diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-08-24 15:57:41 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-08-24 15:57:41 +0200 |
| commit | c5585beab3d6adefaa2ef9444946dd3816960a7c (patch) | |
| tree | a321e540c2db0458716d526e4a045fca123937b2 /packages/meshbay-hub/src/meshbay_hub/static/transport.js | |
| parent | 317f09328ed8bf20148b707470c9b0fe82e59575 (diff) | |
| download | meshbay-c5585beab3d6adefaa2ef9444946dd3816960a7c.tar.gz | |
fix(node,hub): HEVC transcode fallback, live-add progress, per-group TMDB toggle
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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LAmyXtc6dAADsH23ydXQpY
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/transport.js')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/transport.js | 62 |
1 files changed, 44 insertions, 18 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/transport.js b/packages/meshbay-hub/src/meshbay_hub/static/transport.js index b4bfe87..763e279 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/transport.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/transport.js @@ -107,6 +107,7 @@ class MeshBayTransport { set onUploadPolicy(fn) { this._onUploadPolicy = fn; } set onAppsEnabled(fn) { this._onAppsEnabled = fn; } set onTmdbConfig(fn) { this._onTmdbConfig = fn; } + set onTmdbEnabled(fn) { this._onTmdbEnabled = fn; } set onVideoRoot(fn) { this._onVideoRoot = fn; } set onIndexProgress(fn) { this._onIndexProgress = fn; } @@ -536,37 +537,57 @@ class MeshBayTransport { } /** - * Turn TMDB lookups on/off node-wide, optionally set/clear a custom API - * token, and optionally set the language TMDB is queried in (e.g. - * "fr-FR") — one for the whole node, same reasoning as the token: one - * shared cache, not a per-viewer request. Signed like setAppsEnabled/ - * setMemberUpload — an unsigned toggle would let any member turn on - * outbound third-party network traffic the operator never agreed to - * (docs/mediacenter.md §5.5, §8). `token: ''` explicitly clears a - * previously-set custom token; omit it (undefined/null), like + * Set/clear a custom TMDB API token, and/or set the language TMDB is + * queried in (e.g. "fr-FR") — one for the whole node, since both are one + * operator's shared credential/cache, not a per-group concern (see + * setTmdbEnabled below for the per-group on/off switch). Signed like + * setAppsEnabled/setMemberUpload — an unsigned change would let any + * member alter outbound third-party network traffic the operator never + * agreed to (docs/mediacenter.md §5.5, §8). `token: ''` explicitly clears + * a previously-set custom token; omit it (undefined/null), like * `language`, to leave whatever is stored unchanged. */ - async setTmdbConfig(enabled, token, language, signFn) { + async setTmdbConfig(token, language, signFn) { const msg = await this._sendAndWait({ - type: 'tmdb_config', v: '0.5', enabled: Boolean(enabled), + type: 'tmdb_config', v: '0.7', token: token === undefined ? null : token, language: language === undefined ? null : language, }); if (msg.type === 'error') throw new Error(msg.detail); if (msg.type === 'admin_challenge') { // Must match the node's subject byte-for-byte (webrtc_server.py - // _do_tmdb_config): Python's f"{bool}" is "True"/"False", not JS's - // lowercase — and the token itself is never part of the subject + // _do_tmdb_config) — the token itself is never part of the subject // (it would end up in the audit log in plaintext), only whether one // was supplied. The language is not a secret, so it appears as-is. - const subject = `enabled=${enabled ? 'True' : 'False'},` + - `custom_token=${token ? 'yes' : 'no'},language=${language || 'default'}`; + const subject = `custom_token=${token ? 'yes' : 'no'},language=${language || 'default'}`; return this._authorizeAdminOp(msg, 'tmdb_config', subject, signFn); } return msg; } /** + * Whether TMDB lookups run for this group at all — per-group (2026-08-24, + * used to be node-wide): a real media-library group and a test/demo group + * on the same node need not share the decision to spend TMDB quota and + * make outbound requests. Signed like setVideoRoot — it decides whether + * this group's members' Videos tab ever makes outbound TMDB traffic. + */ + async setTmdbEnabled(enabled, signFn) { + const msg = await this._sendAndWait({ + type: 'tmdb_enabled', v: '0.7', enabled: Boolean(enabled), + }); + if (msg.type === 'error') throw new Error(msg.detail); + if (msg.type === 'admin_challenge') { + // Must match the node's subject byte-for-byte (webrtc_server.py + // _do_tmdb_enabled): Python's f"{bool}" is "True"/"False", not JS's + // lowercase. + const subject = enabled ? 'True' : 'False'; + return this._authorizeAdminOp(msg, 'tmdb_enabled', subject, signFn); + } + return msg; + } + + /** * Which folder (possibly a subfolder of a shared root) the Videos app * treats as its entry point for this group. `path: ''` means the whole * group index. Signed like setAppsEnabled — it decides what every @@ -1404,17 +1425,22 @@ class MeshBayTransport { this._onAppsEnabled(msg.apps || []); } - // Node-wide (not per-group) — the operator changed whether TMDB is - // called at all, or supplied/cleared a custom token. `token_customized` - // only says whether one is set, never the token itself. + // Node-wide (not per-group) — the operator supplied/cleared a custom + // token, or changed the query language. `token_customized` only says + // whether one is set, never the token itself. if (msg.type === 'tmdb_config_ack' && this._onTmdbConfig) { this._onTmdbConfig({ - enabled: Boolean(msg.enabled), tokenCustomized: Boolean(msg.token_customized), language: msg.language || '', }); } + // Per-group (2026-08-24, used to be folded into tmdb_config_ack above) — + // the operator turned TMDB on/off for this group specifically. + if (msg.type === 'tmdb_enabled_ack' && this._onTmdbEnabled) { + this._onTmdbEnabled(Boolean(msg.enabled)); + } + // Same shape: an operator corrected a wrong automatic TMDB match, and // everyone connected needs to know their poster grid/detail modal for // this show is now stale — falls through so the operator's own |