aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/static/transport.js
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-08-24 15:57:41 +0200
committerChristophe Besson <cbesson@gmail.com>2026-08-24 15:57:41 +0200
commitc5585beab3d6adefaa2ef9444946dd3816960a7c (patch)
treea321e540c2db0458716d526e4a045fca123937b2 /packages/meshbay-hub/src/meshbay_hub/static/transport.js
parent317f09328ed8bf20148b707470c9b0fe82e59575 (diff)
downloadmeshbay-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.js62
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