<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/packages/meshbay-hub/src/meshbay_hub/static/music-player.js, branch 0.15</title>
<subtitle>MeshBay — read-only public mirror</subtitle>
<id>https://git.meshbay.org/meshbay.git/atom?h=0.15</id>
<link rel='self' href='https://git.meshbay.org/meshbay.git/atom?h=0.15'/>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/'/>
<updated>2026-09-19T11:45:56Z</updated>
<entry>
<title>fix(node): the node decides which files it will transcode, not the player</title>
<updated>2026-09-19T11:45:56Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-19T11:45:56Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=f8223293a211a87c92b1fed80f5ca53660f6b26c'/>
<id>urn:sha1:f8223293a211a87c92b1fed80f5ca53660f6b26c</id>
<content type='text'>
`BROWSER_INCOMPATIBLE_AUDIO_EXTS` named the two formats no browser decodes and
was read by nothing. The player asked for `.wma` and `.mpc` and no others, and
`music-player.js` called itself "kept in sync with the node's" constant — so the
entire restriction lived in the caller, and a member's own message is not the
caller.

What that let through: this converts a whole file and holds a transcode slot
shared with video streaming while it runs. One message naming a two-hour film
spends minutes of the operator's CPU and a slot every other viewer is queued
behind. `AUDIO_TRANSCODE_MAX_BYTES` catches the result, after the work is done;
only the extension catches the work.

The client comment now says what it is — an optimisation that saves asking for a
refusal — rather than implying it is the rule.

Two tests: a film is refused before ffmpeg is reached, and a WMA still passes,
because a gate that refuses everything is not a gate.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>docs: cite MESHBAY_DESIGN.md and a section instead of the merged notes</title>
<updated>2026-09-19T00:12:47Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-19T00:12:47Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=20a824118c09af15d6c338db4c9480ffe5cbcdb6'/>
<id>urn:sha1:20a824118c09af15d6c338db4c9480ffe5cbcdb6</id>
<content type='text'>
The per-feature design notes were merged into docs/MESHBAY_DESIGN.md and
deleted from the tree on 2026-09-11, but ~230 comments across the three
packages still named them — usually written `docs/musicbay.md §3.2`, as
though the file were still in docs/. A reader had to know §16 existed to
resolve any of them. They now name the section directly.

Every mapping comes from §16, the concordance, which already records where
each old section landed: musicbay -&gt; §9.8, mediacenter -&gt; §9.7 for the
Videos app and §6.5 where the subject is derived data, photos -&gt; §9.9,
auth-confirm -&gt; §3.6, refactoring-search -&gt; §9.11, invite-pairing-v1 -&gt;
§3.4, per-node-identity-v1 -&gt; §3.2, captcha -&gt; §7.7, chat-sender-keys -&gt;
§4.5, apps/refactor-groups -&gt; §9.1–§9.4, desktop-client-v1 per section.
Bare citations of the same documents (`draft-v6 §2.11`, `§4.8`, `§3.4`)
are retargeted too: those collide with real section numbers in the design
document, so leaving them would have been worse than the named form.

Four cases the concordance does not cover, each decided rather than guessed:

  Sub-item references into documents that no longer exist — mediacenter's
  `§3.3 row 4`, `§3.4b/c`, `apps.md §3b` — name rows and sub-items §9.7 and
  §9.2 do not reproduce. The module-level citation stays; the sub-item
  pointer is dropped.

  The V-findings keep their labels but lose the dead `§10.1/` prefix.
  §13.8 lists V1–V13 as per-application open items, which is not what the
  labels mean in these comments, so pointing them at §13.8 would have been
  a false citation.

  `apps.md §5`'s virtualization requirement has no counterpart anywhere in
  the design document. The requirement is stated in the comment itself, so
  the citation is dropped rather than aimed at a section that does not say
  it.

  Comments that attributed a *sentence* to an old note — musicbay's "several
  thousand files" example, its "what got measured" note, its measured
  ~11%/~26% cover-art figures, the "original no root, whole shared tree"
  call — state the fact without attribution now. §9.8 does not contain those
  sentences and citing it for them would have been wrong.

CLAUDE.md's "a reference to a document that no longer exists" row now says
the concordance is for git history and out-of-tree material; the code cites
sections directly.

Verified: 2851 passed, 4 skipped. The 12 errors in the run are the Firefox
leg of test_sticky_header.py's browser harness, which is broken at the
browser level on this machine — headless Firefox (snap) dies with
`[GFX1-]: RenderCompositorSWGL failed mapping default framebuffer`, renders
nothing, and the probe exits `{"error": "no measurement"}` after its full
90s wait. Chrome runs the same 12 assertions in 3.2s and passes. Nothing
here can affect it: every changed line in style.css is inside a comment.
Also checked: ast.parse on every changed .py, `node --check` on every
changed .js, the /* */ balance in style.css, and that no changed line
exceeds the width its file already used.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>music: the playlist menus</title>
<updated>2026-09-16T10:10:25Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-16T10:10:25Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=9cbff21274604e37c0986d57937deef85819c396'/>
<id>urn:sha1:9cbff21274604e37c0986d57937deef85819c396</id>
<content type='text'>
One button in Music's sticky toolbar — load, create, delete, remove a
track, sync now — and "add to playlist" on every cover and row. Both
surfaces share one list, read from the manifest, so they open instantly
with every node offline and no body is fetched until one is wanted.

Submenus expand in place rather than flying out: the account menu's
language list already does this, and a flyout has nowhere to go at 400px.
The tracklist under "remove a track" loads when it is expanded.

A name is typed into a field. Electron has no prompt — it throws.

Also splits the two playback failures: a decode failure belongs to that
file and keeps the bounded counter, a connection failure belongs to the
group and skips all of its queued tracks at once. Six dead tracks are
one more than the bound, which is where a playlist would otherwise stop.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>music: play, play next, add to queue</title>
<updated>2026-09-16T09:01:02Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-16T09:01:02Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=20706fb9a4ec646816b44a10842aa8f58ea0fd75'/>
<id>urn:sha1:20706fb9a4ec646816b44a10842aa8f58ea0fd75</id>
<content type='text'>
The player's queue could only be replaced: every onPlayQueue reset
tracks/order/pos together. It becomes one reducer (queue-ops.js) with
an `op`, because two appends batched into one tick cannot both read the
track count out of separate useStates.

A shared pop-up menu (menu.js) carries the three verbs, on right-click
and on a dots button. A track row is now a div holding two buttons: a
button cannot contain a button.

Found by the browser probe: both music wrappers took two arguments and
forwarded two, so every "add to queue" arrived as a plain play.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(hub): legal information link at the foot of the sidebar</title>
<updated>2026-09-11T11:57:34Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-11T11:57:34Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=4b74ff3fc54f35fbc41d9c0f7d2b4ec89475154a'/>
<id>urn:sha1:4b74ff3fc54f35fbc41d9c0f7d2b4ec89475154a</id>
<content type='text'>
A small link to the hub's legal pages, pinned to the bottom of the
sidebar once signed in. It opens in a new tab: the desktop application
refuses to navigate away from its interface and hands a new window to
the system browser, and in a browser it keeps the session on screen. The
address comes from hubBase(), so it is the legal pages of the hub in use.

The sidebar now sticks under the navigation bar at the window's height;
otherwise, on a long file list, the link would sit at the bottom of the
page. The music bar, pinned to the bottom of the window as well,
publishes its height through useStickyBand as --music-bar-h and the
sidebar stops above it. On a phone the slide-out panel does the same.

test_sidebar_legal_measured.py measures the real stylesheet: the link at
the bottom of the window on a 3000px page, and above the music bar, at
phone and desktop widths. Checked signed in on a local hub in Chrome and
Firefox 155.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01D9MCBBWSm9GhBESmqzJxNy
</content>
</entry>
<entry>
<title>feat(hub): cross-group search with reuse of existing views</title>
<updated>2026-08-28T13:35:58Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-28T13:35:20Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=eba2e6b14484c124f3c87ff95cd7ee640833e5d3'/>
<id>urn:sha1:eba2e6b14484c124f3c87ff95cd7ee640833e5d3</id>
<content type='text'>
Search page fetches indexes from all groups, then renders consolidated
entries through the existing FilesPanel, VideoApp, and MusicApp
components — no reimplemented views. Groups appear as top-level
directories in the file browser; video/music entries use a synthetic
root with per-entry transport refs for thumbnails and metadata across
groups. Music player lifted to app.js with getConnection(groupId) for
cross-group playback. Connection pool (max 3, LRU eviction) manages
lazy WebRTC connections. All 10 locales updated with search keys.

Co-Authored-By: Claude Opus 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(music): network-adaptive prefetch depth, opt-in keep-screen-on toggle</title>
<updated>2026-08-26T12:43:16Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-26T12:43:16Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=59d9f50bf41b2b38b7c95f8da52b698dff923c2d'/>
<id>urn:sha1:59d9f50bf41b2b38b7c95f8da52b698dff923c2d</id>
<content type='text'>
Prefetch depth (music-player.js): 5 tracks ahead on Wi-Fi, 3 on cellular —
more runway through a screen-lock network gap when the connection is cheap
and fast, less when it's metered. navigator.connection is Chromium-only;
Firefox/Safari (where it's undefined) get the same conservative tier as an
unrecognized connection type, never assumed fast. MAX_CACHED_BLOBS raised
to 6 to hold the largest case (current + 5).

Keep-screen-on-during-audio (new user preference, off by default): a
Settings toggle, backed by a new whitelisted key on
/v1/users/me/preferences (music_keep_screen_on). music-player.js holds a
Screen Wake Lock only while a track is playing and only when the user has
opted in — unlike the video player's unconditional lock, this must not
fight the ordinary expectation (matching Spotify/Deezer) that the phone
locks on its own while listening.
</content>
</entry>
<entry>
<title>feat(music): prefetch 2 tracks ahead instead of 1</title>
<updated>2026-08-26T11:38:04Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-26T11:38:04Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=5ebebb8748453323709136d86f3b027cee309d4d'/>
<id>urn:sha1:5ebebb8748453323709136d86f3b027cee309d4d</id>
<content type='text'>
Complements the WebRTC auto-reconnect: a track already sitting in
blobCacheRef needs no live connection to play, so whatever was fetched
before a screen lock started plays through it regardless of what the
transport is doing during the lock. One track of runway was often shorter
than the lock itself; two buys more of it. MAX_CACHED_BLOBS (3) already
covers the currently-playing track plus these two, so no cache-size change
needed.
</content>
</entry>
<entry>
<title>fix(music): don't throw "Transport not connected" while a reconnect is landing</title>
<updated>2026-08-26T09:44:23Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-26T09:44:23Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=6e0d2b9a477f1e9f1dec646c0de15440106ed7ed'/>
<id>urn:sha1:6e0d2b9a477f1e9f1dec646c0de15440106ed7ed</id>
<content type='text'>
Found live: &gt;5min screen lock while music played, then "Transport not
connected" at the 2nd track's end (~8min in) despite the auto-reconnect
from the previous commit. Root cause: fetchTrackBlob's own
`!transport.connected` pre-flight check ran and threw before the
already-in-progress reconnect got the few seconds it needed — it never
reached _sendAndWait, which is the only place the previous fix taught the
transport to wait.

Adds transport.waitForReconnect(), factored out of _sendAndWait's existing
gate, and calls it from fetchTrackBlob before giving up. No-op when nothing
is being reconnected, so the ordinary path is unchanged.
</content>
</entry>
<entry>
<title>fix(hub): show what's actually playing in the queue panel</title>
<updated>2026-08-24T19:24:30Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-24T19:24:30Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=54dd95884b04ee5a1ffe4a40260e37784f023583'/>
<id>urn:sha1:54dd95884b04ee5a1ffe4a40260e37784f023583</id>
<content type='text'>
The panel's header said "Playing now" but only the panel itself was named
that — the current track was just a highlighted row you had to spot in
the list, easy to miss on a long queue and often scrolled out of view
entirely on open. Now shows the track's own title/artist right under the
header and scrolls the highlighted row into view when the panel opens.
</content>
</entry>
</feed>
