Skip to content

Download tracks and albums (#35) - #254

Merged
benders merged 1 commit into
mainfrom
feature/35-downloads
Jul 13, 2026
Merged

Download tracks and albums (#35)#254
benders merged 1 commit into
mainfrom
feature/35-downloads

Conversation

@benders

@benders benders commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

Implements #35 — download buttons for tracks and whole albums, matching Navidrome's download semantics. Closes #35.

Backend

  • /rest/download is no longer an alias for stream (hub/src/routes/subsonic/download.ts). Per the Subsonic spec it now returns the original media bytesformat/maxBitRate are ignored — with Content-Disposition: attachment.
  • Track id (t…) → single file, named Artist - Title.ext (RFC 6266 ASCII fallback + UTF-8 filename*; extension from the preferred source's format, content-type fallback).
  • Album id (al…) → streaming ZIP named Artist - Album.zip with NN - Title.ext entries (D-NN when multi-disc). Entries are stored, not deflated (audio doesn't compress; keeps the response streaming). Upstream fetches are sequential — one open connection to Navidrome/a peer at a time. Tracks whose source fails are skipped with a warning so the ZIP stays valid.
  • Peer-sourced tracks proxy raw through /federation/stream with the same merge-time preferred-source selection as streaming. No federation contract change.
  • Cast tokens are not accepted (auth path-gates them to /rest/stream only, Phase 4: eliminate stream-relay; Player hands devices Hub Subsonic stream URLs #218).
  • New dependency: yazl (+ types).

Frontend

  • downloadUrl() helper in lib/subsonic.ts (authed URL, no transcode params).
  • Album header: Download pill (ZIP of the album).
  • Track rows: hover download icon next to Add-to-queue.

Tests

  • hub/test/download.test.ts: filename-helper units, 400/404 cases, track download (attachment header, raw upstream fetch asserted via capturing fake Navidrome), album ZIP (signatures, entry names, stored bytes).
  • Peer-path download test added to the two-hub harness in stream.test.ts.
  • Frontend: downloadUrl unit tests + ReleaseGroupPage button/link tests.
  • pnpm verify ✅, pnpm lint ✅ (zero output), pnpm test:federation ✅ (84 compat tests, all hubs).

Docs

  • docs/opensubsonic.md download row updated.

🤖 Generated with Claude Code

https://claude.ai/code/session_011Q3riZ78G26ohMgPDh8F7u

…album ZIP (refs #35)

/rest/download is no longer a stream alias. Per Navidrome/Subsonic spec it
returns original bytes (transcode params ignored) with Content-Disposition:
attachment. Track id (t…) → single file named from metadata; album id (al…)
→ streaming ZIP (yazl, stored entries, sequential upstream fetches) of the
best release's tracks. Peer-sourced tracks proxy raw via /federation/stream.
SPA: album-header Download pill + per-track hover download link (#35).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Q3riZ78G26ohMgPDh8F7u
@benders
benders marked this pull request as ready for review July 13, 2026 14:24
@benders
benders merged commit 57c9671 into main Jul 13, 2026
2 checks passed
@benders
benders deleted the feature/35-downloads branch July 13, 2026 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow downloading of a track or entire album

2 participants