aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/static/music-app.js
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-08-24 22:44:27 +0200
committerChristophe Besson <cbesson@gmail.com>2026-08-24 22:44:27 +0200
commitdf7eb105dda550989dccd3ba2bf22a50e919b19b (patch)
treeafc5de8f43d8fe188a5fdb41ffc504c211e07ccc /packages/meshbay-hub/src/meshbay_hub/static/music-app.js
parent665fb2004e55b72ea483aa50fea81f6a6fd9c322 (diff)
downloadmeshbay-df7eb105dda550989dccd3ba2bf22a50e919b19b.tar.gz
feat(hub): audio_root wiring, mutually-exclusive players, Settings rework
Five related pieces of polish against the Music app and Settings, all from the same conversation: - Music app now requires audio_root, same as Videos requires video_root: an empty-state message until one is set, and grouping filtered to only what's under it (underAudioRoot, mirroring video-app.js's underVideoRoot). Wires the new audio_root/audio_root_ack pair through transport.js and group-page.js state the same way video_root already flows. - Starting one player now stops the other — opening a film closes the music queue, starting a track closes the video modal. Both used to run at once, found live. - Group Settings reworked: every section but a bare form (invite, pair-operator, approve-device) is now collapsible (CollapsibleSection); the uploads on/off button is a real toggle switch (ToggleSwitch, reused for TMDB/MusicBrainz's enabled switches too, each now with an icon + status badge in its header instead of a plain checkbox row); and shared directories, the Videos root picker, and the new Music root picker are merged into one "Directories" section (RootFolderRow) instead of three separate ones scattered down the page — the root pickers only show once their app is actually enabled.
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/music-app.js')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/music-app.js24
1 files changed, 20 insertions, 4 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/music-app.js b/packages/meshbay-hub/src/meshbay_hub/static/music-app.js
index cb14fb4..298e259 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/music-app.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/music-app.js
@@ -46,12 +46,24 @@ function foldKey(s) {
.replace(/\s*&\s*/g, ' and ').replace(/\s+/g, ' ').trim();
}
-function groupMusicEntries(entries) {
+// Same shape as video-app.js's underVideoRoot: an unset root means "show
+// nothing" (docs/musicbay.md's amended §2.1 — the node itself runs no
+// tag/cover enrichment for this group before a root is chosen either,
+// daemon.py's _enrich_new_audio_entries), not "the whole shared tree" —
+// falling back to that would just show files nothing has enriched.
+function underAudioRoot(entry, audioRoot) {
+ if (!audioRoot) return false;
+ const p = entry.path || '';
+ return p === audioRoot || p.startsWith(audioRoot + '/');
+}
+
+function groupMusicEntries(entries, audioRoot) {
const tracks = []; // no artist at all, even after the folder fallback -- rare, but real
const byArtistKey = new Map(); // foldKey(artist) -> { artist, albumsByKey: Map, loose: [] }
for (const e of entries) {
if (e.type !== 'audio') continue;
+ if (!underAudioRoot(e, audioRoot)) continue;
const artistRaw = (e.artist || '').trim();
if (!artistRaw) { tracks.push(e); continue; }
const artistKey = foldKey(artistRaw);
@@ -381,7 +393,7 @@ function FlatList({ tracks, artists, onPlayQueue }) {
// -- shell --------------------------------------------------------------------
function MusicApp({
- groupId, transportRef, gekRef, status, entries, musicbrainzConfig, onPlayQueue,
+ groupId, transportRef, gekRef, status, entries, audioRoot, musicbrainzConfig, onPlayQueue,
}) {
const [mode, setMode] = useState(loadViewMode);
const [filter, setFilter] = useState('');
@@ -392,7 +404,8 @@ function MusicApp({
const setModeAndSave = (m) => { setMode(m); saveViewMode(m); };
- const { tracks, artists, albums } = useMemo(() => groupMusicEntries(entries), [entries]);
+ const { tracks, artists, albums } = useMemo(
+ () => groupMusicEntries(entries, audioRoot), [entries, audioRoot]);
const needle = filter.trim().toLowerCase();
const filteredArtists = useMemo(() => {
@@ -418,7 +431,10 @@ function MusicApp({
${status === 'offline' && html`
<p class="page-message">${t('group.offline_title')} ${t('group.offline_hint')}</p>
`}
- ${status === 'connected' && html`
+ ${status === 'connected' && !audioRoot && html`
+ <p class="page-message">${t('music.no_root_configured')}</p>
+ `}
+ ${status === 'connected' && audioRoot && html`
<div class="video-toolbar">
<button class="tb-btn ${mode === 'grid' ? 'active' : ''}"
onClick=${() => setModeAndSave('grid')}>