Video enrichment: wire new workers into Manage Workers modal + Settings
- Manage Workers modal: register fanart.tv / OpenSubtitles / YouTube Votes (RYD) / SponsorBlock in the worker rail (cards + animations + pause/resume come free via the shared .em-* design); add the 'video' entity kind. - Settings: fanart.tv + OpenSubtitles API-key fields (with Test buttons) and a no-key 'YouTube Extras' toggle frame (RYD + SponsorBlock on/off). - API /enrichment/config now reads/writes the two keys + the two toggles; a key change rebuilds the engine so the worker turns on immediately.
This commit is contained in:
parent
278ba47519
commit
21a1e5ddbb
4 changed files with 93 additions and 3 deletions
|
|
@ -50,6 +50,11 @@ def register_routes(bp):
|
|||
"tmdb_api_key": db.get_setting("tmdb_api_key") or "",
|
||||
"tvdb_api_key": db.get_setting("tvdb_api_key") or "",
|
||||
"omdb_api_key": db.get_setting("omdb_api_key") or "",
|
||||
# Backfill-worker keys (free, optional) + no-key toggles.
|
||||
"fanart_api_key": db.get_setting("fanart_api_key") or "",
|
||||
"opensubtitles_api_key": db.get_setting("opensubtitles_api_key") or "",
|
||||
"ryd_enabled": (db.get_setting("ryd_enabled") or "1") == "1",
|
||||
"sponsorblock_enabled": (db.get_setting("sponsorblock_enabled") or "1") == "1",
|
||||
"billboard_autoplay": (db.get_setting("billboard_autoplay") or "1") == "1",
|
||||
"watch_region": (db.get_setting("watch_region") or "US").upper(),
|
||||
})
|
||||
|
|
@ -81,6 +86,12 @@ def register_routes(bp):
|
|||
|
||||
put_key("tmdb_api_key")
|
||||
put_key("tvdb_api_key")
|
||||
put_key("fanart_api_key")
|
||||
put_key("opensubtitles_api_key")
|
||||
# No-key worker on/off toggles (read live by the worker — no rebuild needed).
|
||||
for flag in ("ryd_enabled", "sponsorblock_enabled"):
|
||||
if flag in body:
|
||||
db.set_setting(flag, "1" if body.get(flag) else "0")
|
||||
if "billboard_autoplay" in body:
|
||||
db.set_setting("billboard_autoplay", "1" if body.get("billboard_autoplay") else "0")
|
||||
if "watch_region" in body:
|
||||
|
|
|
|||
|
|
@ -5464,6 +5464,62 @@
|
|||
<button class="test-button" type="button" data-video-test-service="omdb">Test OMDb</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="api-service-frame stg-service" data-video-service="fanart">
|
||||
<div class="stg-service-header" onclick="toggleStgService(this)">
|
||||
<span class="stg-service-dot" style="color: #e4509a;"></span>
|
||||
<h4 class="service-title">fanart.tv (Artwork)</h4>
|
||||
<span class="stg-service-chevron">›</span>
|
||||
</div>
|
||||
<div class="stg-service-body">
|
||||
<div class="form-group">
|
||||
<label>API Key:</label>
|
||||
<input type="password" id="fanart-api-key" placeholder="fanart.tv API Key">
|
||||
</div>
|
||||
<div class="callback-info">
|
||||
<div class="callback-help">Get a free key from <a href="https://fanart.tv/get-an-api-key/" target="_blank" style="color: #e4509a;">fanart.tv</a></div>
|
||||
<div class="callback-help">Clear logos, clearart, banners, posters & backgrounds (gap-fills missing art).</div>
|
||||
</div>
|
||||
<button class="test-button" type="button" data-video-test-service="fanart">Test fanart.tv</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="api-service-frame stg-service" data-video-service="opensubtitles">
|
||||
<div class="stg-service-header" onclick="toggleStgService(this)">
|
||||
<span class="stg-service-dot" style="color: #22a079;"></span>
|
||||
<h4 class="service-title">OpenSubtitles (Subtitles)</h4>
|
||||
<span class="stg-service-chevron">›</span>
|
||||
</div>
|
||||
<div class="stg-service-body">
|
||||
<div class="form-group">
|
||||
<label>API Key:</label>
|
||||
<input type="password" id="opensubtitles-api-key" placeholder="OpenSubtitles API Key">
|
||||
</div>
|
||||
<div class="callback-info">
|
||||
<div class="callback-help">Get a free key from <a href="https://www.opensubtitles.com/en/consumers" target="_blank" style="color: #22a079;">OpenSubtitles</a> (register a consumer)</div>
|
||||
<div class="callback-help">Records which subtitle languages exist per title.</div>
|
||||
</div>
|
||||
<button class="test-button" type="button" data-video-test-service="opensubtitles">Test OpenSubtitles</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="api-service-frame stg-service" data-video-service="ytextras">
|
||||
<div class="stg-service-header" onclick="toggleStgService(this)">
|
||||
<span class="stg-service-dot" style="color: #ef4444;"></span>
|
||||
<h4 class="service-title">YouTube Extras (No Key)</h4>
|
||||
<span class="stg-service-chevron">›</span>
|
||||
</div>
|
||||
<div class="stg-service-body">
|
||||
<label class="vid-pref-row">
|
||||
<input type="checkbox" id="video-ryd-enabled" checked>
|
||||
<span>Return YouTube Dislike (like/dislike estimates)</span>
|
||||
</label>
|
||||
<label class="vid-pref-row">
|
||||
<input type="checkbox" id="video-sponsorblock-enabled" checked>
|
||||
<span>SponsorBlock (crowd-sourced segments)</span>
|
||||
</label>
|
||||
<div class="callback-info">
|
||||
<div class="callback-help">Free community APIs — no key needed. Enrich cached YouTube videos in the background.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Server Connection — mirrors the music server picker, scoped
|
||||
to Plex/Jellyfin. The toggle BOTH selects the active video
|
||||
|
|
|
|||
|
|
@ -20,6 +20,11 @@
|
|||
{ 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: '▶' },
|
||||
// Backfill workers — enrich already-identified items by id.
|
||||
{ id: 'fanart', name: 'fanart.tv', color: '#e4509a', rgb: '228, 80, 154', kinds: ['movie', 'show'], glyph: '🎨' },
|
||||
{ id: 'opensubtitles', name: 'OpenSubtitles', color: '#22a079', rgb: '34, 160, 121', kinds: ['movie', 'show'], glyph: '💬' },
|
||||
{ id: 'ryd', name: 'YouTube Votes', color: '#ef4444', rgb: '239, 68, 68', kinds: ['video'], glyph: '👍' },
|
||||
{ id: 'sponsorblock', name: 'SponsorBlock', color: '#00b4a0', rgb: '0, 180, 160', kinds: ['video'], glyph: '⏭' },
|
||||
];
|
||||
|
||||
function workerDef(id) {
|
||||
|
|
@ -34,8 +39,8 @@
|
|||
tmdb: 'https://www.themoviedb.org/assets/2/v4/logos/v2/blue_square_2-d537fb228cf3ded904ef09b136fe3fec72548ebc1fea3fbbd1ad9e36364db38b.svg',
|
||||
tvdb: 'https://www.svgrepo.com/show/443500/brand-tvdb.svg',
|
||||
};
|
||||
var GLYPH = { movie: '🎬', show: '📺', episode: '🎞️' };
|
||||
var KIND_LABEL = { movie: 'Movies', show: 'Shows', episode: 'Episodes' };
|
||||
var GLYPH = { movie: '🎬', show: '📺', episode: '🎞️', video: '▶' };
|
||||
var KIND_LABEL = { movie: 'Movies', show: 'Shows', episode: 'Episodes', video: 'Videos' };
|
||||
|
||||
var state = {
|
||||
open: false, selected: 'tmdb', statuses: {}, breakdown: null,
|
||||
|
|
|
|||
|
|
@ -212,6 +212,14 @@
|
|||
if (t && d.tmdb_api_key != null) t.value = d.tmdb_api_key;
|
||||
if (v && d.tvdb_api_key != null) v.value = d.tvdb_api_key;
|
||||
if (o && d.omdb_api_key != null) o.value = d.omdb_api_key;
|
||||
var fa = document.getElementById('fanart-api-key');
|
||||
if (fa && d.fanart_api_key != null) fa.value = d.fanart_api_key;
|
||||
var sub = document.getElementById('opensubtitles-api-key');
|
||||
if (sub && d.opensubtitles_api_key != null) sub.value = d.opensubtitles_api_key;
|
||||
var ryd = document.getElementById('video-ryd-enabled');
|
||||
if (ryd && d.ryd_enabled != null) ryd.checked = !!d.ryd_enabled;
|
||||
var sb = document.getElementById('video-sponsorblock-enabled');
|
||||
if (sb && d.sponsorblock_enabled != null) sb.checked = !!d.sponsorblock_enabled;
|
||||
var ap = document.getElementById('video-billboard-autoplay');
|
||||
if (ap && d.billboard_autoplay != null) ap.checked = !!d.billboard_autoplay;
|
||||
var wr = document.getElementById('video-watch-region');
|
||||
|
|
@ -237,12 +245,20 @@
|
|||
var t = document.getElementById('tmdb-api-key');
|
||||
var v = document.getElementById('tvdb-api-key');
|
||||
var o = document.getElementById('omdb-api-key');
|
||||
var fa = document.getElementById('fanart-api-key');
|
||||
var sub = document.getElementById('opensubtitles-api-key');
|
||||
var ryd = document.getElementById('video-ryd-enabled');
|
||||
var sb = document.getElementById('video-sponsorblock-enabled');
|
||||
return fetch(CONFIG_URL, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
tmdb_api_key: t ? t.value : '', tvdb_api_key: v ? v.value : '',
|
||||
omdb_api_key: o ? o.value : '',
|
||||
fanart_api_key: fa ? fa.value : '',
|
||||
opensubtitles_api_key: sub ? sub.value : '',
|
||||
ryd_enabled: ryd ? ryd.checked : true,
|
||||
sponsorblock_enabled: sb ? sb.checked : true,
|
||||
})
|
||||
}).then(function () { if (!silent) toast('API keys saved', 'success'); })
|
||||
.catch(function () { /* ignore */ });
|
||||
|
|
@ -284,7 +300,9 @@
|
|||
selects[i].addEventListener('change', function () { save(); });
|
||||
}
|
||||
// Enrichment keys save on blur/change (turns the workers on).
|
||||
['tmdb-api-key', 'tvdb-api-key', 'omdb-api-key'].forEach(function (id) {
|
||||
['tmdb-api-key', 'tvdb-api-key', 'omdb-api-key',
|
||||
'fanart-api-key', 'opensubtitles-api-key',
|
||||
'video-ryd-enabled', 'video-sponsorblock-enabled'].forEach(function (id) {
|
||||
var el = document.getElementById(id);
|
||||
if (el) el.addEventListener('change', function () { saveKeys(); });
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue