diff --git a/database/video_database.py b/database/video_database.py
index b622b253..c648e01e 100644
--- a/database/video_database.py
+++ b/database/video_database.py
@@ -2055,13 +2055,17 @@ class VideoDatabase:
conn.close()
def channel_dates_enriched_recently(self, channel_id, within_hours=24) -> bool:
- """True if the channel was date-enriched within the window (don't re-sweep)."""
+ """True if the channel was date-enriched within the window (don't re-sweep).
+ Coverage-aware: a run that produced FEW dates (proxies were down) retries
+ soon instead of being locked out for the full window — so the catalog
+ actually fills in once a source works."""
if not channel_id:
return False
conn = self._get_connection()
try:
- row = conn.execute("SELECT enriched_at FROM youtube_channel_enrichment WHERE channel_id=?",
- (str(channel_id),)).fetchone()
+ row = conn.execute(
+ "SELECT enriched_at, date_count FROM youtube_channel_enrichment WHERE channel_id=?",
+ (str(channel_id),)).fetchone()
if not row or not row["enriched_at"]:
return False
try:
@@ -2069,7 +2073,9 @@ class VideoDatabase:
except (ValueError, TypeError):
return False
now = datetime.now(timezone.utc).replace(tzinfo=None) # naive UTC, matches CURRENT_TIMESTAMP
- return (now - when) < timedelta(hours=within_hours)
+ # Good coverage → skip for the full window; thin result → retry in 15 min.
+ window = within_hours if (row["date_count"] or 0) >= 15 else 0.25
+ return (now - when) < timedelta(hours=window)
finally:
conn.close()
diff --git a/webui/static/video/video-enrichment-manager.js b/webui/static/video/video-enrichment-manager.js
index cb48df24..1dabf288 100644
--- a/webui/static/video/video-enrichment-manager.js
+++ b/webui/static/video/video-enrichment-manager.js
@@ -18,6 +18,8 @@
{ id: 'tmdb', name: 'TMDB', color: '#38bdf8', rgb: '56, 189, 248', kinds: ['movie', 'show'] },
{ id: 'tvdb', name: 'TVDB', color: '#a855f7', rgb: '168, 85, 247', kinds: ['show'] },
{ id: 'omdb', name: 'OMDb', color: '#f5c518', rgb: '245, 197, 24', kinds: ['movie', 'show'] },
+ // The YouTube date enricher — no per-kind match queue; its own simple panel.
+ { id: 'youtube', name: 'YouTube Dates', color: '#ff3b3b', rgb: '255, 59, 59', kinds: [], glyph: '▶' },
];
function workerDef(id) {
@@ -64,8 +66,13 @@
}
return t ? Math.round(m / t * 100) : 0;
}
- function railSub(s) {
+ function railSub(s, id) {
if (!s || !s.enabled) return 'Not configured';
+ if (id === 'youtube') {
+ if (s.running && s.current_item && s.current_item.name) return s.current_item.name;
+ if (s.queued) return s.queued + ' queued';
+ return (s.dates_cached || 0) + ' dates cached';
+ }
if (s.idle) return 'All matched';
if (s.running && !s.paused && s.current_item && s.current_item.name) return s.current_item.name;
return (s.stats ? (s.stats.pending || 0) : 0) + ' pending';
@@ -119,11 +126,11 @@
'';
var icon = LOGOS[w.id]
? ''
- : '★';
+ : '' + (w.glyph || '★') + '';
return '';
}).join('');
WORKERS.forEach(function (w) {
@@ -132,6 +139,25 @@
});
}
+ function renderYoutubePanel(panel) {
+ var s = state.statuses.youtube || {};
+ var info = statusInfo(s);
+ var prog = (s.progress && s.progress.channels) || {};
+ var current = (s.current_item && s.current_item.name)
+ ? 'channel: ' + esc(s.current_item.name) + '' : '';
+ panel.innerHTML =
+ '