<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/packages/meshbay-node, branch v0.9.0</title>
<subtitle>MeshBay — read-only public mirror</subtitle>
<id>https://git.meshbay.org/meshbay.git/atom?h=v0.9.0</id>
<link rel='self' href='https://git.meshbay.org/meshbay.git/atom?h=v0.9.0'/>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/'/>
<updated>2026-08-31T10:05:24Z</updated>
<entry>
<title>chore: bump version to 0.9.0</title>
<updated>2026-08-31T10:05:24Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-31T10:05:24Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=f4c6628c8e85513d9fd110ead95682368a15a0fd'/>
<id>urn:sha1:f4c6628c8e85513d9fd110ead95682368a15a0fd</id>
<content type='text'>
Packaging system complete and verified on Ubuntu 26.04 and Fedora 44.

Co-Authored-By: Claude Opus 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(ui): configurable ICE interfaces in the Node page</title>
<updated>2026-08-30T20:36:56Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-30T20:36:56Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=2d6c276734fd19f80edf84cdb95f91a929df6365'/>
<id>urn:sha1:2d6c276734fd19f80edf84cdb95f91a929df6365</id>
<content type='text'>
The ice_interfaces setting (auto-exclude vs explicit whitelist) is now
editable from the Node page, persisted via the settings API and roster,
and hot-swapped at runtime by re-installing the aioice filter.

Co-Authored-By: Claude Opus 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat: configurable STUN server fallbacks for WebRTC ICE</title>
<updated>2026-08-30T20:17:30Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-30T20:17:30Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=07e6e4271ea3a45e9cd364eb6ec05801a653d9e8'/>
<id>urn:sha1:07e6e4271ea3a45e9cd364eb6ec05801a653d9e8</id>
<content type='text'>
The WebRTC transport relied on a single Google STUN server — if it was
unreachable, ICE gathering waited the full 4s timeout. Now four public
servers are used by default (Google ×2, Cloudflare, Mozilla), configurable
via node.toml, the Node page UI, and the CLI (meshbay-node stun list|add|
remove|reset). Changes are hot-swapped on the live transport.

Co-Authored-By: Claude Opus 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>chore: scrub copyrighted names from tests, comments and docs</title>
<updated>2026-08-30T15:05:15Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-30T15:05:15Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=d5fc45ff907e618d884a8d2d91c1f2b45e6898d1'/>
<id>urn:sha1:d5fc45ff907e618d884a8d2d91c1f2b45e6898d1</id>
<content type='text'>
Real franchise / show / release-group names had crept back into test
fixtures, code comments, a docstring and docs/mediacenter.md while fixing
the saga-match and misclassification bugs. Replace them all with invented
placeholders ("Some Saga", "A Different Show") and shape descriptions
("a franchise-origin film", "a 3-season show"). Behaviour and assertions
unchanged; 738 node tests still pass.

Record the rule in CLAUDE.md so it stops recurring.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_018BMLQjqFGCize2KtNBT79v
</content>
</entry>
<entry>
<title>fix(node): stop a numbered saga all matching its first film</title>
<updated>2026-08-30T14:31:34Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-30T14:31:34Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=854b76338072979526ce36fbc176c82f6fc5d0bd'/>
<id>urn:sha1:854b76338072979526ce36fbc176c82f6fc5d0bd</id>
<content type='text'>
Every "&lt;Saga&gt; Episode &lt;N&gt; - &lt;subtitle&gt;" file in a numbered franchise
resolved to the series' first entry (a real, older film). `sequel_variants`
stripped "Episode &lt;N&gt;" and offered the bare "&lt;Saga&gt;" as a candidate query;
that matches the first film's original_title at ratio 1.0 and beat PASS 1's
correct-but-lower hit. A franchise's bare name is very often a real,
different film.

When a Part/Episode/Chapitre/… keyword carried the index, sequel_variants
no longer emits the bare base — only "&lt;base&gt; &lt;digit&gt;" and "&lt;base&gt; &lt;roman&gt;".
Without a keyword ("&lt;Franchise&gt; 3") the bare base is still offered, so that
fix is untouched. Verified live against TMDB: the franchise's episodes each
resolve to their own entry; the earlier numbered-sequel, two-part-film and
franchise-subtitle regressions all hold.

docs/mediacenter.md §10.3.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_018BMLQjqFGCize2KtNBT79v
</content>
</entry>
<entry>
<title>Merge remote-tracking branch 'origin/main'</title>
<updated>2026-08-29T16:55:42Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-29T16:55:42Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=a2215bb071c4e1ce11c616d26df8fd4e7a8fdf57'/>
<id>urn:sha1:a2215bb071c4e1ce11c616d26df8fd4e7a8fdf57</id>
<content type='text'>
</content>
</entry>
<entry>
<title>feat(node): editable node settings in the Node page (D5)</title>
<updated>2026-08-29T16:52:53Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-29T16:42:43Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=1f8a52484412b48205e5ff6aac506428e2fb77ed'/>
<id>urn:sha1:1f8a52484412b48205e5ff6aac506428e2fb77ed</id>
<content type='text'>
Expose invite_ttl_hours, pair_ttl_hours, device_request_ttl_minutes,
max_concurrent_streams and transcode_incompatible_video in the Node
management panel. Changes are applied immediately via roster.db and
written back to node.toml so they survive a DB wipe. On startup,
roster overrides take precedence over node.toml defaults.

Draft v6 §2.11 documents the design; MNP gains node_settings_set /
node_settings_set_ack for the browser path.

Co-Authored-By: Claude Opus 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix(node): stop a movie with a mangled quality tag being shelved as a series</title>
<updated>2026-08-29T16:45:37Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-29T16:45:37Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=00880fd8b9d362ad391c784f1ee31bd62aa18d62'/>
<id>urn:sha1:00880fd8b9d362ad391c784f1ee31bd62aa18d62</id>
<content type='text'>
Found on demo35: "Some.Film.2017.MULTI.108.grp.mkv" — the release name's
"1080p" truncated to "108" — makes guessit read S01E08, so enrich.py's
flat-library branch (elif ep.episode is not None) filed a standalone film
as a series. "Fix match" then only offered TV results for the phantom
show, so there was no way out from the UI.

- title_parse.has_episode_marker(): true only for an explicit SxxExx /
  1x08 / "Episode N" / "Season N" token, not a bare 3-4 digit run.
- enrich.py: the flat-library branch now needs ep.season AND ep.episode,
  plus either a real marker or the absence of a "(2019)"-style year.
  Every genuine flat-dumped episode in the corpus carries a marker, so
  real shows are untouched; the same misparse on "1280" ("...2013.1280...")
  is covered too.

docs/mediacenter.md §10.2. Known gap left open: no operator control over
the movie/show kind itself — a "this is a movie / a show" toggle would.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_018BMLQjqFGCize2KtNBT79v
</content>
</entry>
<entry>
<title>fix: on restart, serve a video's cached TMDB match instead of re-searching</title>
<updated>2026-08-29T15:57:01Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-29T14:42:18Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=32318a64b12c83429c156a36c228769492e41d4e'/>
<id>urn:sha1:32318a64b12c83429c156a36c228769492e41d4e</id>
<content type='text'>
Root of the 2026-08-29 demo35 storms. `_do_media_meta_request` could not
tell "this is a movie" from "this video isn't enriched yet" — both have
season/episode None — so during a slow initial scan with a browser on the
Videos tab, every show episode requested was run through the *movie*
search path with its raw filename as the query
(`search/movie?query=Show S01E01 1080p WEB DL ...`), hundreds per second,
until TMDB rate-limited and posters stopped loading. Worse, an
un-enriched show episode's own valid cached "tv" match was treated as
stale (its provisional kind was "movie"), so a file already resolved got
re-queried anyway.

- While a video is un-enriched (no display_title — enrich.py always sets
  one), never run a TMDB *search*. Serve the cached match if the content
  hash has one, honouring the cached kind ("tv"/"movie") rather than the
  provisional split; otherwise answer confidence 0.
- Once enriched, the strict `cached_media_type == media_type` check is
  unchanged: an enrichment fix that reclassifies a folder movie-&gt;tv still
  drops the stale match and re-resolves.
- video-app.js: `useMediaMeta` gains an `enrichSig` dependency
  (`entry.display_title`) so the client refetches once the enriched fields
  arrive on an index delta — the fileId is a content hash and never
  changes, so nothing else would retrigger it.

Not caused by the V8-V13 work; it raised the per-file call count so the
pre-existing race became a visible storm.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_018BMLQjqFGCize2KtNBT79v
</content>
</entry>
<entry>
<title>feat: V13 — per-card "re-match this one file" (MNP 0.13)</title>
<updated>2026-08-29T13:57:06Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-29T13:57:06Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=4d167e9f958d26c1db920274974ae446426928e3'/>
<id>urn:sha1:4d167e9f958d26c1db920274974ae446426928e3</id>
<content type='text'>
A one-click alternative to the full "Fix match" search-and-pick flow, and
reachable without SSH (`meshbay-node video rematch` clears a whole group).

- MNP 0.13: tmdb_rematch / tmdb_rematch_ack (additive — an older node
  logs "unknown type", the button just does nothing). OP_TMDB_REMATCH,
  signed like tmdb_override (media_cache is shared node-wide).
- media_cache.drop_tmdb_match(file_id): forgets the match AND the
  override marker — deliberately stronger than clear_file_tmdb, since the
  operator is explicitly asking for a fresh resolution.
- webrtc_server: _do_tmdb_rematch / _admin_exec_tmdb_rematch, dispatch +
  admin-response routing, broadcasts tmdb_rematch_ack.
- transport.js: rematchTmdbMatch(fileId, signFn); 'tmdb_rematch' in the
  admin-op allowlist; tmdb_rematch_ack handled like tmdb_override_ack.
- video-app.js: a "Re-match" button beside "Fix match" in the detail
  modal (isNodeAdmin), then bumpMediaMetaGeneration(). video.rematch_one
  key in all ten locales.

docs/mediacenter.md §10.1: V8–V13 marked done.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_018BMLQjqFGCize2KtNBT79v
</content>
</entry>
</feed>
