Video enrichment: add the 4 new workers to the dashboard header

- Dashboard header now shows fanart.tv / OpenSubtitles / YouTube Votes / SponsorBlock
  buttons alongside TMDB/TVDB/OMDb/YouTube (same chip + spinner + tooltip + click
  pause/resume + worker-orb animation).
- Socket status loop now iterates ALL engine workers (matchers + backfill) instead
  of a hardcoded 3, so new buttons get live 2s status with no extra wiring.
- video-enrichment.js SERVICES + video-worker-orbs.js WORKER_DEFS extended.
  header-actions already flex-wraps, so 8 buttons reflow cleanly.
This commit is contained in:
BoulderBadgeDad 2026-06-18 08:04:53 -07:00
parent 6f14f15dd6
commit 530d6f181f
4 changed files with 74 additions and 6 deletions

View file

@ -37257,17 +37257,16 @@ def _emit_video_enrichment_status_loop():
the access log). No-op until the video engine is actually running, so this
never spins it up on the music side."""
from core.video.enrichment.engine import peek_video_enrichment_engine
services = ('tmdb', 'tvdb', 'omdb')
while not globals().get('IS_SHUTTING_DOWN', False):
socketio.sleep(2)
eng = peek_video_enrichment_engine()
if eng is None:
continue
for svc in services:
# Emit for EVERY registered worker (matchers + backfill: fanart / opensubtitles
# / ryd / sponsorblock) so new dashboard buttons get live status with no extra
# wiring here.
for svc, w in (eng.workers or {}).items():
try:
w = eng.worker(svc)
if w is None:
continue
socketio.emit(f'enrichment:{svc}', w.get_stats())
except Exception as e:
logger.debug(f"Error emitting video {svc} status: {e}")

View file

@ -504,6 +504,70 @@
</div>
</div>
</div>
<div class="video-enrich-container" style="--ve-accent: 228, 80, 154;">
<button class="video-enrich-button" type="button" data-video-enrich="fanart" title="fanart.tv Artwork">
<span class="video-enrich-glyph" aria-hidden="true">&#127912;</span>
<span class="video-enrich-spinner" aria-hidden="true"></span>
</button>
<div class="video-enrich-tooltip" data-video-enrich-tooltip="fanart">
<div class="tooltip-content">
<div class="tooltip-header">fanart.tv Artwork</div>
<div class="tooltip-body">
<div class="tooltip-status">Status: <span data-video-enrich-status>Idle</span></div>
<div class="tooltip-current" data-video-enrich-current>No active matches</div>
<div class="tooltip-progress" data-video-enrich-progress>Progress: 0 / 0</div>
</div>
</div>
</div>
</div>
<div class="video-enrich-container" style="--ve-accent: 34, 160, 121;">
<button class="video-enrich-button" type="button" data-video-enrich="opensubtitles" title="OpenSubtitles">
<span class="video-enrich-glyph" aria-hidden="true">&#128172;</span>
<span class="video-enrich-spinner" aria-hidden="true"></span>
</button>
<div class="video-enrich-tooltip" data-video-enrich-tooltip="opensubtitles">
<div class="tooltip-content">
<div class="tooltip-header">OpenSubtitles</div>
<div class="tooltip-body">
<div class="tooltip-status">Status: <span data-video-enrich-status>Idle</span></div>
<div class="tooltip-current" data-video-enrich-current>No active matches</div>
<div class="tooltip-progress" data-video-enrich-progress>Progress: 0 / 0</div>
</div>
</div>
</div>
</div>
<div class="video-enrich-container" style="--ve-accent: 239, 68, 68;">
<button class="video-enrich-button" type="button" data-video-enrich="ryd" title="YouTube Votes (Return YouTube Dislike)">
<span class="video-enrich-glyph" aria-hidden="true">&#128077;</span>
<span class="video-enrich-spinner" aria-hidden="true"></span>
</button>
<div class="video-enrich-tooltip" data-video-enrich-tooltip="ryd">
<div class="tooltip-content">
<div class="tooltip-header">YouTube Votes</div>
<div class="tooltip-body">
<div class="tooltip-status">Status: <span data-video-enrich-status>Idle</span></div>
<div class="tooltip-current" data-video-enrich-current>No active matches</div>
<div class="tooltip-progress" data-video-enrich-progress>Progress: 0 / 0</div>
</div>
</div>
</div>
</div>
<div class="video-enrich-container" style="--ve-accent: 0, 180, 160;">
<button class="video-enrich-button" type="button" data-video-enrich="sponsorblock" title="SponsorBlock">
<span class="video-enrich-glyph" aria-hidden="true">&#9197;</span>
<span class="video-enrich-spinner" aria-hidden="true"></span>
</button>
<div class="video-enrich-tooltip" data-video-enrich-tooltip="sponsorblock">
<div class="tooltip-content">
<div class="tooltip-header">SponsorBlock</div>
<div class="tooltip-body">
<div class="tooltip-status">Status: <span data-video-enrich-status>Idle</span></div>
<div class="tooltip-current" data-video-enrich-current>No active matches</div>
<div class="tooltip-progress" data-video-enrich-progress>Progress: 0 / 0</div>
</div>
</div>
</div>
</div>
<!-- Reuses music's .em-manage-btn* classes verbatim so it's
pixel-identical; wired by data-attribute (no inline
handler) via video-enrichment.js, never music's. -->

View file

@ -17,7 +17,8 @@
// All four push status over the shared socket every 2s (server emits
// 'enrichment:<svc>') — including the standalone YouTube date enricher — so the
// browser never polls /api/video/enrichment/<svc>/status.
var SERVICES = ['tmdb', 'tvdb', 'omdb', 'youtube'];
var SERVICES = ['tmdb', 'tvdb', 'omdb', 'youtube',
'fanart', 'opensubtitles', 'ryd', 'sponsorblock'];
function onVideoSide() {
return document.body.getAttribute('data-side') === 'video';

View file

@ -24,6 +24,10 @@
{ sel: '[data-video-enrich="tvdb"]', color: [168, 85, 247], id: 'tvdb' },
{ sel: '[data-video-enrich="omdb"]', color: [245, 197, 24], id: 'omdb' },
{ sel: '[data-video-enrich="youtube"]', color: [255, 59, 59], id: 'youtube' },
{ sel: '[data-video-enrich="fanart"]', color: [228, 80, 154], id: 'fanart' },
{ sel: '[data-video-enrich="opensubtitles"]', color: [34, 160, 121], id: 'opensubtitles' },
{ sel: '[data-video-enrich="ryd"]', color: [239, 68, 68], id: 'ryd' },
{ sel: '[data-video-enrich="sponsorblock"]', color: [0, 180, 160], id: 'sponsorblock' },
{ sel: '[data-video-manage-workers]', color: [168, 85, 247], hub: true },
];