The 49 files the art pass left behind were fat with USLT, not APIC -
the worst held the complete text of Angela's Ashes (1.5 MB of Frank
McCourt) in an Eels track, some tagger malfunction. AVPlayer pages
through the whole tag before the first audio frame regardless of what
fills it, so absurd lyrics cost the same silence as absurd art. No
song has 50 KB of lyrics; anything past it is junk and is removed.
Redundant with the v2 frames, 128 bytes of legacy, and the thing whose
sync update tripped the audio guard. Applies to files being rewritten;
files already slimmed before this keep their synced v1.
mutagen updates an existing v1 tag on save - it normalised the genre
byte 0xFF to 0x0F on Shamrocks and Shenanigans and the guard refused a
whole album of good rewrites over one metadata byte. The v1 block is
metadata, not audio; the guard now hashes strictly the frames between
the v2 tag and any trailing TAG block.
A tagger that writes a non-standard size field puts the header claim and
the real tag end in different places. mutagen preserves audio from where
it parsed the tag to end; the guard hashed from where the header claimed,
and refused good rewrites across a whole album. Both hashes now use the
same authority. Failed files stay untouched and a re-run picks them up.
iOS AVPlayer reads a streamed file head in ~32 KB range requests and cannot
reach audio until it is past the ID3 tag - a 955 KB embedded JPEG cost ~30
sequential round trips, a two-second silence Android never feels. 28% of the
library (20,487 files, 1,488 albums) carries art that size.
Keeps an embedded front cover (other users of these files see it) but at
600px/JPEG stepped to fit 80 KB, ~3 chunks. Audio region is hashed before
and after; any mismatch keeps the original. Rescues art to cover.jpg first
when the folder has none.
It read `process.env.DATA_PATH ?? cwd/data`. DATA_PATH stopped being an env var on 2026-08-13, when
the install layout became something derived from the working directory rather than configured — so run
from the repo this looked for platform/data/music/.server, which is one level too deep, found nothing,
and said the sidecar was not running.
Imports DATA_PATH from the platform instead, so there is one derivation rather than a copy that fell
behind. Verified it resolves to /home/pastilhas/officer-dev/data.
Also corrects the usage line: the script moved into this plugin and the header still said
`bun scripts/reindex-music.ts` from the platform repo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Everything the plugin is, moved out of officerdev/platform on 2026-08-15 —
41 files, unchanged from the tree they left.
manifest.ts identity, one permission, ffmpeg/ffprobe declared
api/ the sidecar proxy; the prefix comes from mountPrefix()
sidecar/ the whole /api/music contract — indexing, streaming, per-user state
db/ music_favorites, _playlists, _playlist_items, _now_playing
web/ panels, layout, and the player: engine, bar, lyrics, favourites
cliamp/ the second playback path, parked — not working, kept deliberately
widgets/ the dashboard widget, parked — plugins cannot contribute widgets
assets/ icon.png, the dock tile
scripts/ the reindex CLI
PLUGIN.md is the design record: what moved, what stayed, what broke, and why.
MUSIC_API.md is the contract the phone and tablet apps speak, and the reason
the sidecar's HTTP shape is not free to change.
── It does not build here, and that is the point ──
The platform resolves `hooks/useClient`, `officerdev`, `officerdb/db` and `@@/*`
through the workspace links in its own node_modules. Measured from this
directory, outside the platform checkout, every one of them fails to resolve —
7 imports in the backend, ~29 in the frontend.
So this repository is the source of truth, not yet a buildable unit. Making it
one means the host API becoming something a plugin can depend on rather than
something it reaches into. That is the next problem, and having the code here
is what makes it unavoidable rather than theoretical.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>