<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/packages/meshbay-hub/src/meshbay_hub/static/video-player.js, branch 0.14</title>
<subtitle>MeshBay — read-only public mirror</subtitle>
<id>https://git.meshbay.org/meshbay.git/atom?h=0.14</id>
<link rel='self' href='https://git.meshbay.org/meshbay.git/atom?h=0.14'/>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/'/>
<updated>2026-09-06T01:40:16Z</updated>
<entry>
<title>fix(node): inline @owner next to group name, fix buffering layout shift</title>
<updated>2026-09-06T01:40:16Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-06T01:40:16Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=37473b29c02f2dc70eb9ba46d596f503a01c5845'/>
<id>urn:sha1:37473b29c02f2dc70eb9ba46d596f503a01c5845</id>
<content type='text'>
Put the @owner handle on the same line as the group name (flex baseline)
to save a row on mobile. Move the video buffering indicator inside the
video-container as an absolute overlay so it no longer pushes the video
down when it appears briefly during seeks.

Co-Authored-By: Claude Opus 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(video): hold a Screen Wake Lock while a video is open</title>
<updated>2026-08-26T09:35:31Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-26T09:35:31Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=ab96d5821fe9cda4f31b3389e1c6fb3e6010682d'/>
<id>urn:sha1:ab96d5821fe9cda4f31b3389e1c6fb3e6010682d</id>
<content type='text'>
Purely additive and isolated from the streaming/transport code: touches no
DataChannel, SourceBuffer, or playback state, so it cannot itself cause a
stall or regress existing playback (PC/Electron included) — feature-detected
and try/caught, a no-op wherever unsupported or refused.

Sidesteps the commonest real-world trigger for the WebRTC-drop recovery
(the phone auto-locking on its own idle timer while someone just watches).
Does nothing for a deliberate power-button lock or backgrounding the tab —
released automatically in both cases per spec — so the reconnect path is
still what handles those.
</content>
</entry>
<entry>
<title>fix(transport): auto-reconnect after WebRTC failure, without dropping in-flight streams/downloads</title>
<updated>2026-08-26T09:17:37Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-26T09:17:37Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=27d59cbb2d11d863273e2282257d81ac9911ab97'/>
<id>urn:sha1:27d59cbb2d11d863273e2282257d81ac9911ab97</id>
<content type='text'>
Confirmed live (client trace + node logs, mobile screen-lock ~5min): ICE
goes disconnected -&gt; failed within ~10s on both ends, but the DataChannel's
readyState stays "open" throughout, so nothing failed fast — every request
just sat out its own 8s/30s timeout, matching the reported symptom (poster
spinners, blocked chat, dead new streams).

transport.js: on connectionState "failed", reject pending requests
immediately (TransportLostError) and start a self-contained reconnect loop
(capped exponential backoff, redoes the full signaling handshake — the node
already discards the old session on its own "failed"/"closed", so there is
nothing lower-level to resume). New hooks: onNeedToken (fetch a fresh JWT,
since the captured one may have expired during the outage) and
onReconnected (let a consumer resume something that was mid-flight).

file-utils.js: pipelinedDownload retries a lost chunk instead of aborting
the whole transfer — covers Files downloads, poster/thumbnail fetches, and
music-player.js's blob-based track download, all of which go through it.

video-player.js: onReconnected reissues the existing seek-to-current-time
path, which already knows how to land a new stream_init on the live
SourceBuffer without resetting playback.

Playing audio is unaffected either way — musicbay.md's design downloads a
track to a blob before playing it, so a dead transport was never a network
dependency for what is already playing.

Stays on this branch until confirmed by real-device testing.
</content>
</entry>
<entry>
<title>fix(node,hub): always transcode video audio to stereo AAC, never copy</title>
<updated>2026-08-23T20:43:35Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-23T20:43:35Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=b6e2dcea65124673da047f9b3c92bc5e25980d63'/>
<id>urn:sha1:b6e2dcea65124673da047f9b3c92bc5e25980d63</id>
<content type='text'>
MSE only decodes AAC/Opus, so copying a source's real audio codec left
non-AAC files silently unplayable in-browser (E-AC-3 additionally made
ffmpeg itself refuse to write the fragmented MP4 header). Audio is now
always transcoded to AAC and downmixed to stereo — multichannel AAC is
accepted by ffprobe/VLC but silently rejected by some browsers' MSE
decoder once real fragments are appended, which forces the SourceBuffer
out of its MediaSource with no explicit error. Video stays copy-only.

Also: report a clear client-side error instead of a bare STREAM_END when
ffmpeg exits nonzero before producing any output, add video-element/
MediaSource error logging on the client for the next time this class of
bug needs diagnosing, and fix a hub test that had grown too broad a scan
window after an earlier, unrelated transport.js change.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_016SF6RKNBKg9qejmoMJ9ybA
</content>
</entry>
<entry>
<title>feat(hub): split the group UI into a pluggable "applications" architecture</title>
<updated>2026-08-23T13:15:35Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-23T13:15:35Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=9f02ee2c09652abf1308bdfa4a3eec4e9ca9ac83'/>
<id>urn:sha1:9f02ee2c09652abf1308bdfa4a3eec4e9ca9ac83</id>
<content type='text'>
GroupPage's 6620-line app.js carried Chat and Files wedged in directly, with
no way to add another group-level app without touching the shell itself. It
is now app.js (routing, non-group pages) plus nine focused files — apps.js
(the registry), chat-app.js, files-app.js, video-player.js, group-page.js
(the shell), group-settings.js, hub-client.js, icon.js and file-utils.js —
with docs/apps.md as the checklist for adding one (Videos/Music/Photos are
sketched there, not built).

Node side gained the matching enablement mechanism, mirroring
member_upload exactly: a roster setting, a signed apps_enabled op enforced
by _has_admin_authority, exposed in the handshake ack. Operators toggle
applications per group from Settings, which also gained a small reorder:
Invite, Pairing, Applications, Shared directories, Uploads, danger zone,
Your devices, Members.

Two bugs surfaced during the split, both missing an import across the new
file boundary and invisible to node --check or a module-load probe since
they only throw when the code path actually runs:

- group-page.js called onRefreshAuth on a stale-token handshake rejection,
  but app.js never imported refreshAccessToken from hub-client.js — so a
  brand new member (including a group's own creator) hit "Not a member of
  this group" and the retry silently failed, throwing before it could
  refresh the token.
- chat-app.js called getLocale() for message timestamps without importing
  it from i18n.js. Opening Chat on a group with real messages threw mid-
  render; uncaught, that appears to wedge Preact's render scheduler, so
  every button on the page stopped responding until reload.

Caught the second class of bug with a proper no-undef audit across all
split files (a temporarily installed ESLint 9, since the system one is too
old to parse this codebase's syntax) rather than trusting grep. 827 tests
pass; 6 new ones cover the apps_enabled policy.

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