summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-common
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-08-24 21:08:34 +0200
committerChristophe Besson <cbesson@gmail.com>2026-08-24 21:08:34 +0200
commitf4ed927fa873133c5fed73fb7dd60e7747fc3dc2 (patch)
treed126c5e505c342ee6b02aadc1e46b1a026c2a027 /packages/meshbay-common
parent75d1f8b93dfa0bffda3a59a6d143b06dcc3ca67f (diff)
downloadmeshbay-f4ed927fa873133c5fed73fb7dd60e7747fc3dc2.tar.gz
feat(music): transcode WMA/Musepack to AAC so they actually play
Tagging and covers for these two formats landed already, but neither one decodes in any mainstream browser's <audio> element at all — a real library scan turned up 273 such files that would show up correctly in the Music app and then simply fail on click. This closes that gap: the node transcodes to AAC/M4A on request (a one-shot whole-file conversion, not live-piped like video's fMP4 segments — an audio file is small enough that streaming it buys nothing), caches the result under its own content hash the same way a TMDB poster or a MusicBrainz cover is cached, and serves it back through the ordinary file_req/chunk path. That path used to assume anything in the media cache was thumbnail-sized (single chunk, always); generalized it to slice a cached blob the same way a real file on disk gets sliced, since a transcoded track can be several MB. New MNP pair (`audio_transcode_req`/`_resp`, version bump to 0.9), shares its concurrency cap with video's transcode pool rather than getting its own — both are real ffmpeg processes on the same node. Every other audio format is untouched: this only fires for .wma/.mpc, the two extensions that need it.
Diffstat (limited to 'packages/meshbay-common')
-rw-r--r--packages/meshbay-common/src/meshbay_common/__init__.py8
-rw-r--r--packages/meshbay-common/src/meshbay_common/protocol.py6
2 files changed, 13 insertions, 1 deletions
diff --git a/packages/meshbay-common/src/meshbay_common/__init__.py b/packages/meshbay-common/src/meshbay_common/__init__.py
index 3ed1ed2..ecf51fd 100644
--- a/packages/meshbay-common/src/meshbay_common/__init__.py
+++ b/packages/meshbay-common/src/meshbay_common/__init__.py
@@ -31,5 +31,11 @@ __version__ = "0.7.0"
# `thumb_hash`/`display_title` rather than declaring new ones. Additive:
# an older client simply doesn't render the new fields or send the new
# messages.
-MNP_VERSION = "0.8"
+# 0.9: added `audio_transcode_req`/`_resp` — WMA and Musepack tag/cover
+# fine but decode in no mainstream browser's <audio> element at all, so
+# the node transcodes to AAC/M4A on request and caches the result the same
+# way a TMDB poster or MusicBrainz cover is cached. Additive: an older
+# client never sends the request, and simply can't play those two formats,
+# same as before this existed.
+MNP_VERSION = "0.9"
MHP_VERSION = "0.1"
diff --git a/packages/meshbay-common/src/meshbay_common/protocol.py b/packages/meshbay-common/src/meshbay_common/protocol.py
index 3b5d428..8f29c38 100644
--- a/packages/meshbay-common/src/meshbay_common/protocol.py
+++ b/packages/meshbay-common/src/meshbay_common/protocol.py
@@ -113,6 +113,12 @@ class MNP:
MUSICBRAINZ_ENABLED_ACK = "musicbrainz_enabled_ack" # node → this group: new enabled state
MUSIC_META_REQ = "music_meta_req" # client → node: metadata for a path
MUSIC_META_RESP = "music_meta_resp" # node → client: metadata (or none)
+ # A file whose format the browser's own <audio> element cannot decode at
+ # all (WMA, Musepack) — resolved to a cached, browser-playable AAC/M4A
+ # copy on request, the same "computed once, reused forever" shape as a
+ # TMDB poster or a MusicBrainz cover.
+ AUDIO_TRANSCODE_REQ = "audio_transcode_req" # client → node: transcode this file id
+ AUDIO_TRANSCODE_RESP = "audio_transcode_resp" # node → client: cache hash/size/mime
# Device linking. A new device files a request bound to a code it displays;
# an already-pinned device of the same account approves it. Neither the hub
# nor the node can produce the countersignature.