From 16bc07acf053d7d14f8182f5523da1d179154a15 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Mon, 24 Aug 2026 16:43:18 +0200 Subject: docs: plan the Music group app (musicbay.md) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Proposal only, not implemented. Same plug-in mechanism as Videos (apps.md), but no new streaming path — a track is downloaded and decrypted like any other file, not transcoded/remuxed like a film. Metadata: local tags first (mutagen), MusicBrainz/Cover Art Archive as node-side fallback enrichment, no API key needed (unlike TMDB) — just a rate-limited, self-identifying client. Player state (queue, shuffle, repeat) moves up into the group-page shell so playback survives a tab switch, mirroring how the video/preview modal is already shell-owned. --- docs/musicbay.md | 414 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 414 insertions(+) create mode 100644 docs/musicbay.md (limited to 'docs/musicbay.md') diff --git a/docs/musicbay.md b/docs/musicbay.md new file mode 100644 index 0000000..2524948 --- /dev/null +++ b/docs/musicbay.md @@ -0,0 +1,414 @@ +# MeshBay — Music application (plan) + +> Status: **proposal**, not implemented. Follows the plug-in mechanism in +> `docs/apps.md` — read that first, and `docs/mediacenter.md` second: Music +> reuses its node-side pattern (metadata fetched and cached by the node, +> never by a client) wherever the same shape applies, and this document only +> states where Music differs and why. +> +> Follows the project convention: every claim names the adversary it holds +> against (§7). + +--- + +## 0. What was asked, in one paragraph + +A group "application" with exactly the same principles as Videos — a view +over the existing file index, no catalogue, node-side metadata enrichment, +enable/disable per group on the same signed-op mechanism — but for audio, +styled after a mainstream streaming-music player rather than a poster grid: +album art browsing, a persistent transport (play/pause, previous/next within +the current album or queue, shuffle, repeat), and no cast/DLNA surface (out +of scope, unlike a possible future addition to Videos). + +--- + +## 1. What this design does not reopen + +Everything Videos already established stands, and this plan fits inside it: + +- **Views over the index, never a catalogue** (`desktop-client-v1.md` §6.10, + draft-v6 §2.7, `mediacenter.md` §1). A file stays tied to its filesystem + representation; nothing here adds a second identity for a file, and + nothing reaches the hub. +- **The apps plug-in mechanism** (`apps.md`): a new `music-app.js`, one + registry entry, one node-side `ALLOWED_APPS` entry, i18n keys, the asset + list, the two file-set tests. Enablement is a per-group, operator-signed + setting, same shape as `member_upload`/`apps_enabled`. +- **Group-related server state lives on the node** (E9). Nothing in this + design puts a row on the hub. +- **Node-side derived-data caching, never in a shared root** + (`mediacenter.md` §2, §9). Same reasoning applies unchanged: a cache + belongs in the node's own `data_dir`, never beside the audio files. +- **The node already classifies audio** — `indexer.py`'s `MEDIA_EXTENSIONS` + already has an `"audio"` set (`.mp3`, `.flac`, `.ogg`, `.wav`, `.aac`, + `.m4a`, `.opus`), and `IndexEntry.duration`/`.thumb_hash`/`.display_title` + are already generic fields, not video-specific ones, per their own + docstrings. No MNP change is needed to know a file is a track. + +## 2. Where Music genuinely differs from Videos + +### 2.1 Metadata mostly already exists in the files themselves + +A video file's name is usually all there is to go on; an MP3 collection — +especially one assembled over many years — routinely carries **ID3 tags** +(artist, album, title, track/disc number, year, genre) and often an +**embedded cover image** (the `APIC` frame). Unlike Videos, where `guessit` +had to do all the work, here the filename parser is the *fallback*, not the +primary source. Order of trust, each one filling gaps the previous left: + +1. **Embedded tags** (ID3v2 for MP3, Vorbis comments for OGG/FLAC, etc.), + read with `mutagen` (pure Python, MIT, no native extension — same + licensing shape as `guessit`, trivially addable to + `packages/meshbay-node/pyproject.toml`). Also the source of an embedded + cover image when present. +2. **Filename/folder parsing** for whatever tags don't supply — the existing + `title_parse.py` pattern extended with a small audio-specific ruleset + (`Track - Title.mp3`, a leading `NN - `/`NN. ` track-number prefix, the + parent folder as a fallback album name, the grandparent as a fallback + artist name for an `Artist/Album/track.mp3` layout). +3. **MusicBrainz**, node-side, fetched and cached exactly like TMDB — for + canonical spelling, a missing field, or cover art when the file has none + embedded. Read the whole of §3 before assuming this needs the same + credential story as TMDB: it does not. + +A quick, honest read of a real personal MP3 library (several thousand +files, classic P2P-era rips, folder-per-artist/album) during planning showed +embedded tags present and broadly usable on the large majority of files, with +gaps concentrated in older VBR rips and remix/compilation folders — exactly +where the folder-name fallback already has something to say (the folder is +named after the artist or the release). The library itself is not committed +anywhere in this repo, the same discipline `mediacenter.md` §3.1 already +follows for its own test corpus; a real accuracy figure belongs in an +acceptance step (§8), not asserted here from a first look. + +### 2.2 No playback protocol change is needed at all — the big simplification + +Videos needed MSE, live ffmpeg remuxing, seek-by-restart, and a whole flow +control mechanism (`video-player.js`) because a film is gigabytes and has to +start playing before it is fully downloaded. A track is a few megabytes. +**Music does not need any of that.** Playback reuses the download/decrypt +pipeline `Files` and `Chat` attachments already use — +`pipelinedDownload`/`downloadEntry` in `file-utils.js` — fetching and +decrypting a whole track into a blob, then handing a `blob:` URL to an +`