Commit Graph
11 Commits
Author SHA1 Message Date
pastilhas 3368f5def9 temporary: log each stream request range, chasing the iOS 28-requests-per-song storm 2026-08-29 01:09:28 +01:00
pastilhasandClaude Opus 5 6310760fda release 2026.08.27.01
first dated version. plugins were all sitting on 1.0.0, which said nothing about
when a build was made or which of two copies is newer — the platform already
uses YYYY.MM.DD.NN and this follows it.

the version lives in manifest.ts because a plugin has no package.json; that is
the field the marketplace publishes and the installer compares.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 07:36:31 +00:00
pastilhas c214f11c2f AGENTS.md, so both harnesses find the same guidance
opencode discovers AGENTS.md and nothing else; claude code discovers CLAUDE.md.
this repo had neither, so an agent sent to change something here arrived with no
guidance at all under either.

it deliberately does NOT repeat README.md. that file says what the plugin is,
for someone deciding whether to install it. this one answers the other question:
i have to change something in here, what will i break.

the facts in it are read from the repository rather than recalled — the panel
keys from web/panels.ts, the tables from db/schema.ts, the permission keys, the
host binaries and the route claims from manifest.ts. presence is the declaration
everywhere in this system, so the file says what the platform will actually
conclude from these files existing.

CLAUDE.md beside it is a pointer, not a copy: two copies drift and the stale one
is the one somebody reads.
2026-08-27 07:24:14 +00:00
pastilhas 60f6864126 say what this plugin is for, in the store's words
tags are how the marketplace is browsed rather than scrolled: a list of them on
the left, the plugins that carry one on the right. a closed vocabulary
(PLUGIN_TAGS in the platform) because free text becomes homelab, home-lab, Home
Lab and selfhosted inside a month, and a filter list of synonyms is worse than
no filter at all.

declared here rather than curated in the catalogue, so a plugin can say what it
is and nobody edits a table when one ships. the marketplace caches it on sync,
exactly as it already does for label and summary.
2026-08-27 06:49:34 +00:00
pastilhasandClaude Opus 5 9f06297c64 reindex-music looked one level too deep and reported the sidecar down
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>
2026-08-21 03:39:01 +00:00
pastilhas efc9581889 restore the three streaming improvements
reverts 0e08aef, b430a70 and 1170e41 — stream-audio.ts and MUSIC_API.md are
now byte-identical to 2a70bc1.

all three were unwound over two days chasing a mobile playback failure that
turned out to have nothing to do with this plugin. the reasoning that undid
them was elimination, not diagnosis: the duration header did not fix it, so
the etag "must" be the cause. the option never considered was that none of it
was mine, which is the one that was true.

nothing here was measured wrong. removing the per-file ffprobe from the path
before the first byte is the speedup, and it is confirmed in real use.

what the mobile client should know, unchanged from MUSIC_API.md: x-audio-duration
is gone, read durationSec from /meta instead — it arrives with the queue,
before the first stream request.
2026-08-19 17:11:26 +00:00
pastilhas 1170e411ac revert the /stream etag, cache-control and 304
playback did not come back when x-audio-duration did, so the duration header
was not the only thing i broke. the range and whole-file branches are
byte-identical to the version that worked, which leaves these three as the
only remaining difference on /stream.

a cache that keeps a validator after evicting the body sends if-none-match,
gets a 304 and has no audio. plausible, unproven, and not worth another round
trip through someone's phone to find out — the etag was an optimisation and
playback is not.

/stream is now byte-identical to the last version known to play, verified by
running both implementations side by side over no-range, closed, open and
invalid ranges and diffing status, every header and body length.

if-none-match is still accepted and ignored. re-introducing this needs a
capture of what the player actually sends.
2026-08-19 15:43:11 +00:00
pastilhas b430a702b4 keep ffprobe as the floor under the meta.json lookup
the previous commit read the duration from meta.json instead of spawning
ffprobe. correct for an indexed album and wrong everywhere else: /stream
serves any home-relative path and never required an index, so a library that
has not been indexed got no header at all. alpha is exactly that case — its
music cache is empty — which is how this was caught rather than shipped.

"always present" replaced with "present if indexed" is the same regression as
removing the header, one layer down.

so both, in order: meta.json when it can answer, ffprobe when it cannot, each
cached. verified on an indexed album (247 from meta, 0.3ms warm) and on the
same file with its index deleted (7.03 from ffprobe, 83ms cold, 0.1ms warm).
2026-08-19 15:28:54 +00:00
pastilhas 0e08aefad9 restore x-audio-duration, without the ffprobe
removing it was wrong: the mobile player stopped playing. nothing in the web
read the header and /meta already carried durationSec, so it looked dead. it
was not — it is a documented part of the contract and something depended on it.

the header is back and the ffprobe is not. the value is read from the album's
meta.json, which is the same number ffprobe produced (the indexer got it from
ffprobe at index time), cached per album and keyed on the meta file's mtime so
a reindex invalidates it. 1.5ms cold, 0.1ms warm, against 50ms warm and 315ms
cold for the process spawn.

first pass looked for meta.json beside the audio; it lives under the sidecar's
own cache root mirroring the relative path. uses metaFilePath now rather than
re-deriving it.

verified against a real file: header present and equal to meta, 304 on
whole-file revalidation, 206 on range with a matching etag.
2026-08-19 15:26:39 +00:00
pastilhasandClaude Opus 5 3f4ee82ab6 cliamp: validate the path before checking the host for the binary
openPlayer checked `findCliamp()` before `resolveInHome(files)`, so a path
escaping the owner's home was answered "cliamp not found on host" on any
machine without the binary — telling the caller about the host in response to
input that should simply have been refused.

It also made the guarantee depend on an unrelated binary being installed,
which is why cliamp-ws.test.ts's "rejects a path that escapes the owner home"
failed on this machine (and every other one without cliamp) since the tests
started running from plugins/ at all. It was being carried as a known-failing
baseline rather than read.

Validate the request, then inspect the host. No behavioural change on a
machine that has cliamp.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 13:49:59 +00:00
pastilhas 5bd27838bd readme: what music does, what it needs, and what it does not do yet 2026-08-16 04:07:20 +00:00