Some checks failed
Deploy / deploy (push) Has been cancelled
Unraid's stats were already fetched live on every page load (no server-side cache), so this doesn't bypass anything — it just lets the section be re-fetched without a full page reload, for confirming it's current without waiting on a reload. Array section moves into its own partial (_array_section.html) so a new /api/array/refresh route can re-render just that fragment and swap it into #array-section, rather than duplicating the table/bar/disk-row markup in JS. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LPJxtE9tPURsaWDZ6rC4Dt
120 lines
6.2 KiB
HTML
120 lines
6.2 KiB
HTML
{% extends "_shell.html" %}
|
|
{% from "_macros.html" import service_error, bar, trend %}
|
|
{% block title %}P105 System{% endblock %}
|
|
|
|
{% block content %}
|
|
<h1 class="tt-dh bloom tt-masthead">SYSTEM</h1>
|
|
|
|
{#- ── Service transmission status ───────────────────────────────
|
|
Six services, one row each, colour carrying up or down. This is
|
|
what the old header pills were, given room to say something. Each
|
|
row opens that service's own instance, via the reverse proxy. -#}
|
|
<div class="tt-field"><span>Transmission</span></div>
|
|
<div class="tt-rows">
|
|
{% for name, key, svc in [('Sonarr', 'sonarr', sonarr), ('Radarr', 'radarr', radarr), ('SABnzbd', 'sabnzbd', sabnzbd),
|
|
('Tautulli', 'tautulli', tautulli), ('Prowlarr', 'prowlarr', prowlarr), ('Ombi', 'ombi', ombi)] %}
|
|
<a class="tt-row" href="{{ service_urls[key] }}" target="_blank" rel="noopener">
|
|
<span class="tt-row-name">{{ name }} <span class="tt-row-ext" aria-hidden="true">↗</span></span>
|
|
<span class="tt-row-body"></span>
|
|
<span class="tt-row-val {{ 'ok' if svc.status == 'ok' else 'alert' }}">
|
|
{{- 'ON AIR' if svc.status == 'ok' else 'OFF AIR' -}}
|
|
</span>
|
|
</a>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<div id="array-section">
|
|
{% include "_array_section.html" %}
|
|
</div>
|
|
|
|
{#- ── Downloads ─────────────────────────────────────────────────
|
|
The one place the service holds real history, so the one place a
|
|
trend arrow is honest: current speed against the 7-day average. -#}
|
|
{% if sabnzbd.status == 'ok' %}
|
|
<div class="tt-field"><span>Downloads</span><span class="tt-field-meta">{{ sabnzbd.sab_status | default('') }}</span></div>
|
|
<div class="tt-figs">
|
|
<div class="tt-fig">
|
|
<div class="tt-dh tt-fig-v"><span id="sab-queue">{{ sabnzbd.queue_count }}</span></div>
|
|
<div class="tt-fig-l">In queue</div>
|
|
</div>
|
|
<div class="tt-fig">
|
|
<div class="tt-dh tt-fig-v"><span id="sab-speed">{{ sabnzbd.speed | default('0') }}</span> {{ trend(sabnzbd.speed_kbps, sabnzbd.avg_speed_kbps) }}</div>
|
|
<div class="tt-fig-l">Speed vs 7-day avg</div>
|
|
</div>
|
|
<div class="tt-fig">
|
|
<div class="tt-dh tt-fig-v"><span id="sab-remaining">{{ sabnzbd.sizeleft | default('—') }}</span></div>
|
|
<div class="tt-fig-l">Remaining</div>
|
|
</div>
|
|
<div class="tt-fig">
|
|
<div class="tt-dh tt-fig-v">{{ sabnzbd.week_size | default('—') }}</div>
|
|
<div class="tt-fig-l">This week</div>
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<div class="tt-field crit"><span>Downloads</span><span class="tt-field-meta">off air</span></div>
|
|
{{ service_error('SABnzbd', sabnzbd.error) }}
|
|
{% endif %}
|
|
|
|
{#- ── Indexers ────────────────────────────────────────────────── -#}
|
|
{% if prowlarr.status == 'ok' %}
|
|
<div class="tt-field">
|
|
<span>Indexers</span>
|
|
<span class="tt-field-meta">{{ prowlarr.up_count }} of {{ prowlarr.total }} up</span>
|
|
</div>
|
|
<div class="tt-rows">
|
|
{% for idx in prowlarr.indexers %}
|
|
<div class="tt-row">
|
|
<span class="tt-row-name">{{ idx.protocol | default('') }}</span>
|
|
<span class="tt-row-body">
|
|
<span class="tt-row-title">{{ idx.name }}</span>
|
|
{% if prowlarr.has_stats %}<span class="tt-row-sub">{{ idx.grabs | default(0) }} grabs · {{ idx.queries | default(0) }} queries</span>{% endif %}
|
|
</span>
|
|
{% if prowlarr.has_stats %}{{ bar(idx.grab_share | default(0), 'ok' if idx.up else 'alert') }}{% endif %}
|
|
<span class="tt-row-val {{ 'ok' if idx.up else 'alert' }}">{{ 'UP' if idx.up else 'DOWN' }}</span>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<div class="tt-field crit"><span>Indexers</span><span class="tt-field-meta">off air</span></div>
|
|
{{ service_error('Prowlarr', prowlarr.error) }}
|
|
{% endif %}
|
|
|
|
{#- ── Admin ─────────────────────────────────────────────────────
|
|
Shows Sonarr is holding, sized, that nobody has ever played in
|
|
Tautulli and that have sat untouched for longer than the
|
|
neglect window — largest first, since the point is reclaiming
|
|
space. Delete removes the series from Sonarr with its episode
|
|
files and folder; that's permanent, so it shares the site's
|
|
two-tap arming rather than a native confirm(). -#}
|
|
{% if admin_unwatched.status != 'ok' %}
|
|
<div class="tt-field crit"><span>Admin</span><span class="tt-field-meta">off air</span></div>
|
|
{{ service_error('Sonarr/Tautulli', admin_unwatched.error) }}
|
|
{% else %}
|
|
<div class="tt-field">
|
|
<span>Admin</span>
|
|
<span class="tt-field-meta" id="admin-meta">
|
|
{{ admin_unwatched.shows | length }} unwatched · {{ admin_unwatched.total_display }} reclaimable
|
|
</span>
|
|
</div>
|
|
{% if admin_unwatched.shows %}
|
|
<div class="tt-rows" id="admin-rows">
|
|
{% for show in admin_unwatched.shows %}
|
|
<div class="tt-row" data-bytes="{{ show.size }}">
|
|
<span class="tt-row-name">{{ show.ep_count }} EP</span>
|
|
<span class="tt-row-body">
|
|
<span class="tt-row-title">{{ show.title }}</span>
|
|
<span class="tt-row-sub">{% if show.year %}{{ show.year }} · {% endif %}Downloaded {{ show.added[:10] if show.added else 'unknown' }} · {% if show.requested_by %}Requested by {{ show.requested_by }}{% else %}Requester unknown{% endif %} · Never watched</span>
|
|
</span>
|
|
<span class="tt-row-val">{{ show.size_display }}</span>
|
|
<span class="tt-row-acts">
|
|
<button class="tt-btn tt-btn-no tt-btn-sm" data-id="{{ show.sonarr_id }}"
|
|
onclick="armDelete(this)" aria-label="Delete {{ show.title }}">Delete</button>
|
|
</span>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<p class="tt-empty" id="admin-empty">Nothing unwatched and older than {{ admin_unwatched.months }} months is taking up meaningful space.</p>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% endblock %}
|