summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/src/meshbay_node/musicbrainz.py
Commit message (Collapse)AuthorAgeFilesLines
* fix(node): say so when MusicBrainz lookups are inertChristophe Besson2026-09-041-1/+13
| | | | | | | | | | | | | | Staying inert without a contact is the documented policy (module docstring, musicbay.md §3.1): the usage policy wants a contact in the User-Agent, so an unidentified client is never sent. Staying *silent* about it was not a decision — the operator sees Music tiles with no metadata or cover art and has nothing to search the logs for. Warns once per client rather than once per lookup, since the condition is constant for the client's lifetime. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DtfG7z6wHWj8RKHCvxQtY1
* feat: node workflow redesign — wizard auto-config, reset, MusicBrainz contactChristophe Besson2026-08-291-26/+7
| | | | | | | | | | | | | | | | | | | | | | | | Wizard (Electron): - Auto-provisions node config (hub URL + username) from logged-in user - node:start handles both cold start and restart of misconfigured daemon - Waits for daemon to reach 'running', auto-links node key on hub - probeNode accepts intermediate states for wizard progress feedback Reset (meshbay-node reset): - Unlinks node key from hub (DELETE /me/node_key, best-effort) - Stops and disables daemon (systemctl --user disable --now) - Erases ~/.config/meshbay, ~/.local/share/meshbay, ~/.local/state/meshbay MusicBrainz contact: - Resolved from owner's hub email instead of per-node roster config - Removed musicbrainz_contact UI and WebRTC handshake field - Removed set_musicbrainz_contact/musicbrainz_contact from roster Node pairing: - Added operator pairing banner on NodePage - Added operator_paired flag to list_groups Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(node): fall back to a loose MusicBrainz query when the strict one finds ↵Christophe Besson2026-08-251-11/+63
| | | | | | | | | | | | | | | | | | | | | | nothing search_release() only ever tried a field-scoped exact-phrase Lucene query (artist:"..." AND release:"..."). Verified live against musicbrainz.org: any deviation from MusicBrainz's own spelling (a year suffix, an edition tag, an artist credited under an older/aliased name) drops it to zero results outright rather than a low-scored one, so the confidence check never even ran — this is why well-recognized artists were still getting almost no cover art. Add an unscoped loose-query fallback, escape Lucene special characters in the interpolated tag text, and make the confidence score consider the artist match too (not just the album title) now that the fallback has no field scoping to rely on. Also document MESHBAY_MUSICBRAINZ_CONTACT_DEFAULT in the systemd units and man page, mirroring MESHBAY_TMDB_DEFAULT_TOKEN's precedent — never a literal value in source, configured via node.env. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013XSohfUQQiaE77qyFLgSv3
* feat(node): Music app node-side — indexing, MusicBrainz enrichment, protocolChristophe Besson2026-08-241-0/+168
Implements the node half of docs/musicbay.md against MNP 0.8: - IndexEntry gains artist/album/track_no (reuses duration/thumb_hash/ display_title, already generic). New musicbrainz_config/_enabled and music_meta_req/_resp message pairs, mirroring the TMDB shape. - title_parse.parse_track_filename: track-number-prefix + title parsing, fallback-only (embedded tags are the primary source, unlike Videos). - indexer.enrich_audio.AudioEnricher: mutagen-based tag/embedded-cover extraction through its own bounded pool (asyncio.to_thread, no subprocess — no ffmpeg-shaped deadlock risk). Gated on "music" in a group's enabled_apps rather than a video_root-style scoped folder. - musicbrainz.py: MusicBrainzClient — no API key (unlike TMDB), just a self-imposed ~1 req/s pace and a configurable, non-default User-Agent contact string; inert (no calls at all) when no contact is configured, never sends an unidentified client. - media_cache.py: file_mbid/mbid_meta tables alongside the existing TMDB ones, cover art reusing the thumbs table via a synthetic musicbrainz:{mbid} id, pruned on file deletion. - roster.py/ops.py/webrtc_server.py: musicbrainz_contact (node-wide) and musicbrainz_enabled (per-group, from the start) as signed operator settings, ALLOWED_APPS gains "music", _do_music_meta_request resolves and caches a release-level MusicBrainz match per (artist, album). - daemon.py: AudioEnricher/MusicBrainzClient wired alongside the video ones; a group's existing library is swept when "music" is newly enabled (no video_root equivalent — see musicbay.md §2.1). 41 new tests (musicbrainz.py against a mocked transport, admin-op policy for both new settings, media_cache round-trip/pruning, enrich_audio end-to-end against real ffmpeg-generated MP3s). Full suite (common + node + hub): 1116 passed, no regressions. Client-side (music-app.js, persistent player bar) not started yet. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KBi7ALLGfwcjBXt57yNMcy