From c5585beab3d6adefaa2ef9444946dd3816960a7c Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Mon, 24 Aug 2026 15:57:41 +0200 Subject: fix(node,hub): HEVC transcode fallback, live-add progress, per-group TMDB toggle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three bugs found live testing the Videos app against a real HEVC/EAC3 show, plus a design change requested afterward: - Streaming always did "-c:v copy", which faithfully reports a source's real hev1 codec string but is unplayable in a browser with no HEVC decoder (most Chrome/Linux builds). The node now transcodes to H264 whenever the probed codec is browser-incompatible (media_probe.py's new BROWSER_INCOMPATIBLE_VIDEO_CODECS), with a `transcode_incompatible_video` node.toml opt-out for operators who know their viewers already decode it. - Dropping a whole season into an already-watched folder gave no scanning indicator and no progress bar: IndexProgress was only ever updated by the two bulk scan paths, never by the real-time per-file watchdog path (_schedule_update/_debounce/_update_entry). That path now accounts a "burst" the same way, without double-counting a file rewritten mid-debounce. - A stray literal "0" rendered in the video detail modal when there was no TMDB match (`meta.confidence` is 0, and `0 && x` renders "0" in JSX/htm, not nothing) — `confident` is now a real boolean. - Whether TMDB is used at all moves from a node-wide setting to per-group (OP_TMDB_ENABLED/tmdb_enabled/tmdb_enabled_ack, scoped like OP_VIDEO_ROOT): an operator running a real media-library group alongside test/demo groups on one node wants outbound TMDB traffic for the one that needs it, not all of them. The custom API token and query language stay node-wide, one shared credential/cache (tmdb_config/OP_TMDB_CONFIG, unchanged reasoning). MNP_VERSION 0.6 -> 0.7, additive. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01LAmyXtc6dAADsH23ydXQpY --- .../src/meshbay_hub/static/group-settings.js | 71 ++++++++++++++++------ 1 file changed, 51 insertions(+), 20 deletions(-) (limited to 'packages/meshbay-hub/src/meshbay_hub/static/group-settings.js') diff --git a/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js b/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js index 22532fa..88ab68e 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js @@ -33,7 +33,7 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, memberUpload, onMemberUpload, enabledApps, onEnabledApps, scanSettings, onScanSettings, - tmdbConfig, onTmdbConfig, + tmdbConfig, onTmdbConfig, onTmdbEnabled, entries, nodeDirs, videoRoot, onVideoRoot, onPaired, onLeft }) { const [members, setMembers] = useState([]); @@ -259,6 +259,7 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, const [tmdbBusy, setTmdbBusy] = useState(false); const [tmdbMsg, setTmdbMsg] = useState(''); const [tmdbTokenDraft, setTmdbTokenDraft] = useState(''); + const [tmdbEnabledBusy, setTmdbEnabledBusy] = useState(false); const tmdbEnabled = tmdbConfig ? tmdbConfig.enabled : true; // Pre-filled from the operator's own current UI language the first time // this renders with nothing configured yet — a sensible default, not a @@ -271,15 +272,44 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, }, [tmdbConfig && tmdbConfig.language]); /** - * TMDB on/off, an optional custom API token, and the language TMDB is - * queried in — node-wide, not per-group (docs/mediacenter.md §5.5). Same - * shape as saveScanSettings: signed, and the toggle does not claim - * success until the node confirms it. The token field is cleared after a - * save either way: it is never echoed back by the node (tmdb_config_ack - * carries only whether one is set, never the value), so there is - * nothing to keep showing. + * Whether TMDB is used at all — per-group (2026-08-24, used to be bundled + * into the same signed op as the token/language below): a real + * media-library group and a test/demo group on the same node need not + * share this decision. Saves immediately on toggle, same as an ordinary + * checkbox-style setting elsewhere — there is nothing else on the form to + * batch it with any more. */ - const saveTmdbConfig = useCallback(async (nextEnabled) => { + const saveTmdbEnabled = useCallback(async (nextEnabled) => { + const transport = transportRef && transportRef.current; + setTmdbMsg(''); + setTmdbEnabledBusy(true); + try { + if (!transport || !transport.connected) { + throw new Error('Not connected to the node'); + } + const sk = transport.sessionKeys && transport.sessionKeys.skEdB64; + const signFn = (sk && window.MeshBayKeys) + ? (transcript) => window.MeshBayKeys.signBytes(sk, transcript) + : null; + await transport.setTmdbEnabled(nextEnabled, signFn); + if (onTmdbEnabled) onTmdbEnabled(nextEnabled); + } catch (err) { + setTmdbMsg(err.message); + } finally { + setTmdbEnabledBusy(false); + } + }, [transportRef, onTmdbEnabled]); + + /** + * An optional custom API token, and the language TMDB is queried in — + * node-wide, not per-group (docs/mediacenter.md §5.5): one shared + * credential and cache. Same shape as saveScanSettings: signed, and the + * button does not claim success until the node confirms it. The token + * field is cleared after a save either way: it is never echoed back by + * the node (tmdb_config_ack carries only whether one is set, never the + * value), so there is nothing to keep showing. + */ + const saveTmdbConfig = useCallback(async () => { const transport = transportRef && transportRef.current; setTmdbMsg(''); setTmdbBusy(true); @@ -292,11 +322,10 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, ? (transcript) => window.MeshBayKeys.signBytes(sk, transcript) : null; const token = tmdbTokenDraft.trim(); - await transport.setTmdbConfig(nextEnabled, token || undefined, tmdbLanguage, signFn); + await transport.setTmdbConfig(token || undefined, tmdbLanguage, signFn); setTmdbTokenDraft(''); if (onTmdbConfig) { onTmdbConfig({ - enabled: nextEnabled, tokenCustomized: token ? true : (tmdbConfig ? tmdbConfig.tokenCustomized : false), @@ -326,8 +355,8 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, if (!isNodeAdmin || !connected || !tmdbConfig || tmdbConfig.language) return; if (autoLanguageSetRef.current) return; autoLanguageSetRef.current = true; - saveTmdbConfig(tmdbEnabled); - }, [isNodeAdmin, connected, tmdbConfig, tmdbEnabled, saveTmdbConfig]); + saveTmdbConfig(); + }, [isNodeAdmin, connected, tmdbConfig, saveTmdbConfig]); // Every folder anywhere in the group's shared index, deepest included — // `entries[].path` is each file's containing directory (files-app.js's own @@ -607,18 +636,20 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, `} - ${/* TMDB on/off + custom token, node-wide (docs/mediacenter.md §5.5) — - new outbound third-party traffic the node did not have before - the Videos app, so it is a signed operator setting like the - rest, not a display preference. */ + ${/* The on/off switch is per-group (2026-08-24); the custom token and + query language stay node-wide, one shared credential/cache + (docs/mediacenter.md §5.5). Both are new outbound third-party + traffic the node did not have before the Videos app, so both are + signed operator settings, not display preferences — but two + independent ones now, saved separately. */ isNodeAdmin && connected && html`

${t('settings_node.tmdb_title')}

${t('settings_node.tmdb_hint')}

@@ -650,7 +681,7 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef,

${t('settings_node.tmdb_language_hint')}

${tmdbMsg && html`

${tmdbMsg}

`} -- cgit v1.2.3