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-node/src/meshbay_node/roster.py | |
| 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-node/src/meshbay_node/roster.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/roster.py | 54 |
1 files changed, 37 insertions, 17 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/roster.py b/packages/meshbay-node/src/meshbay_node/roster.py index 701462f..b4efb7c 100644 --- a/packages/meshbay-node/src/meshbay_node/roster.py +++ b/packages/meshbay-node/src/meshbay_node/roster.py @@ -599,13 +599,20 @@ class Roster: json.dumps(sorted(apps)), set_by) return apps - # TMDB is one operator's budget and credential, not a per-group concern - # (docs/mediacenter.md §5.5) — stored under the group_id="" sentinel, - # the same precedent as `roster.get_member("", user_id)` authorizing the - # operator node-wide (desktop-client-v1.md §6.3). Unset means "on, using - # the shipped default token" — the same "absent means the old behaviour" - # discipline member_upload/enabled_apps already follow. - SETTING_TMDB_ENABLED = "tmdb_enabled" + # The TMDB credential and query language are one operator's budget, not a + # per-group concern (docs/mediacenter.md §5.5) — stored under the + # group_id="" sentinel, the same precedent as `roster.get_member("", + # user_id)` authorizing the operator node-wide (desktop-client-v1.md + # §6.3). Unset means "the shipped default token, TMDB's own default + # language" — the same "absent means the old behaviour" discipline + # member_upload/enabled_apps already follow. + # + # Whether TMDB is used *at all*, though, is per-group (moved off the + # node-wide sentinel below, 2026-08-24): an operator running a real media + # library alongside test/demo groups wants outbound TMDB traffic for the + # one group that needs it, not all of them just because one node process + # serves both. See SETTING_TMDB_ENABLED's own per-group methods further + # down, next to video_root. SETTING_TMDB_TOKEN = "tmdb_api_token" # A TMDB language tag (e.g. "fr-FR") — one for the whole node, same # reasoning as the token: one shared cache, not a per-viewer request. @@ -614,18 +621,14 @@ class Roster: SETTING_TMDB_LANGUAGE = "tmdb_language" NODE_WIDE_GROUP_ID = "" - async def tmdb_config(self) -> tuple[bool, str | None, str | None]: - """Returns (enabled, custom_token_or_None, language_or_None).""" - enabled = (await self.get_setting( - self.NODE_WIDE_GROUP_ID, self.SETTING_TMDB_ENABLED, "1")) != "0" + async def tmdb_config(self) -> tuple[str | None, str | None]: + """Returns (custom_token_or_None, language_or_None).""" token = await self.get_setting(self.NODE_WIDE_GROUP_ID, self.SETTING_TMDB_TOKEN) language = await self.get_setting(self.NODE_WIDE_GROUP_ID, self.SETTING_TMDB_LANGUAGE) - return enabled, (token or None), (language or None) + return (token or None), (language or None) - async def set_tmdb_config(self, enabled: bool, token: str | None = None, + async def set_tmdb_config(self, token: str | None = None, language: str | None = None, set_by: str = "") -> None: - await self.set_setting(self.NODE_WIDE_GROUP_ID, self.SETTING_TMDB_ENABLED, - "1" if enabled else "0", set_by) if token is not None: await self.set_setting(self.NODE_WIDE_GROUP_ID, self.SETTING_TMDB_TOKEN, token, set_by) @@ -634,8 +637,9 @@ class Roster: language, set_by) # Which folder is the Videos app's entry point for this group — per-group - # (unlike tmdb_config above), since different groups share different - # trees. Empty/unset means the whole group index, exactly as today. + # (unlike the token/language above), since different groups share + # different trees. Empty/unset means the whole group index, exactly as + # today. SETTING_VIDEO_ROOT = "video_root" async def video_root(self, group_id: str) -> str: @@ -645,6 +649,22 @@ class Roster: await self.set_setting(group_id, self.SETTING_VIDEO_ROOT, path or "", set_by) return path or "" + # Whether TMDB lookups run for this group at all — per-group, unlike the + # token/language above: one node process can share a real media library + # group and several test/demo groups, and outbound TMDB traffic (and API + # quota) for the demo groups is not something turning it on for the real + # one should imply. Unset means on, same "absent means the old + # behaviour" discipline as everything else here — a node that predates + # this setting keeps working exactly as before for every group. + SETTING_TMDB_ENABLED = "tmdb_enabled" + + async def tmdb_enabled(self, group_id: str) -> bool: + return (await self.get_setting(group_id, self.SETTING_TMDB_ENABLED, "1")) != "0" + + async def set_tmdb_enabled(self, group_id: str, enabled: bool, set_by: str = "") -> None: + await self.set_setting(group_id, self.SETTING_TMDB_ENABLED, + "1" if enabled else "0", set_by) + # How often the indexer's reconciliation backstop runs, and how long it # waits after the last change on a file before hashing it. Unset means # the indexer's own defaults — an existing group's behaviour must not |