OpenSubsonic Compatibility

Scope

This document defines the /rest compatibility contract implemented in this fork and captures the readiness evidence behind it.

Contract authority / OpenAPI exemption. This document is the authoritative contract for the Subsonic-compatible /rest surface (backend/src/routes/subsonic/index.ts). Those endpoints follow the published OpenSubsonic/Subsonic API rather than soundspan's own REST shape, so they are intentionally exempt from per-endpoint OpenAPI (@openapi) annotation — see the Documentation-coverage rule in AGENTS.md. Keep the endpoint surface below current when /rest behavior changes; that is the substitute for OpenAPI coverage on this prefix.

Coverage

Client-Facing Companion

The per-client compatibility matrix, connection quickstart, and extension roadmap live in SUBSONIC_CLIENTS.md. Update that matrix when this contract changes.

Client Connection URL

Supported Auth Modes

Create app passwords under Settings > Sign-in & Security. Each generated secret starts with ssap_, is shown once, is limited to /rest, and can be revoked independently. Use the soundspan username with the app password. For token authentication, calculate t from the complete ssap_ secret and the client-provided salt.

Advertised OpenSubsonic Extensions

getOpenSubsonicExtensions advertises these extensions at version 1:

transcodeOffset is supported through the stream endpoint's integer-second timeOffset parameter. Positive offsets apply only when the resolved quality is a transcode tier. Offset transcodes use ffmpeg input seeking and bypass the track-and-quality disk cache, but share the same global ffmpeg concurrency cap as cached transcodes. Temporary offset output lives under the configured transcode cache volume in offset-tmp/; request aborts kill ffmpeg, every response path removes its temporary output, and a process-wide 15-minute gate limits stale-file sweeps. Each bounded sweep removes orphaned files older than one hour while excluding files owned by active responses. Raw/original streams ignore the offset. Federated stream proxy requests ignore timeOffset because the peer stream API forwards quality and Range metadata rather than arbitrary Subsonic parameters. This extension is distinct from the missing getTranscodeDecision and getTranscodeStream endpoint extensions.

formPost is honored across the surface: /rest accepts form-encoded POST requests (validated with Music Assistant). Mutating endpoints serve POST through their existing routes; read endpoints route POST through an explicit read-only allowlist. Form-body parameters never override same-named URL query parameters, and credentials submitted in the body are never copied into the request URL (so they cannot reach URL-based logging).

replayGain gains are computed against the server's configurable LOUDNESS_TARGET_LUFS (default -18 LUFS, the ReplayGain 2 reference). Tracks the analyzer has not measured yet omit the object until the background measurement reaches them. Peaks are linear true-peak amplitudes.

Implemented Endpoint Surface

Tier A foundation and browse/search/media:

Tier B mutation/readiness:

getPlaylists omits generated radio-station playlists. Direct getPlaylist access by ID remains available for compatible clients.

Soft-removed local tracks are omitted from browse, search, album, playlist, similar-song, and random-song responses. stream and download return not-found responses for soft-removed track IDs.

The /rest contract exposes visible local and federated library content with the same local-wins deduplication used by the web library. Search, album, artist, playlist, and state responses include peer-owned tracks. stream and download proxy federated audio through the owning peer and preserve Range requests; complete responses may be served from the consumer transcode cache. getCoverArt falls back to the peer cover proxy when local cover metadata is absent. An unavailable peer produces Subsonic error code 0 (GENERIC) with the message Federation peer is offline. Embedded-file lyrics remain local-only, while federated tracks may use metadata-based LRCLIB lookup.

Alias support:

ID Policy

Protocol-facing IDs are deterministic and typed:

Legacy/raw ID fallback remains supported where endpoint type context is sufficient.

Readiness Evidence (manual validation)

Environment:

Key outcomes:

  1. Auth handshake
  1. Stream seek/range behavior
  1. Cover-art retrieval
  1. Tier B mutation/readiness flows

DB side-effect checkpoints:

Third-Party Client Profile Matrix

Environment:

Matrix outcomes:

  1. symfonium profile
  1. dsub profile
  1. ultrasonic profile
  1. amperfy profile
  1. substreamer profile

Automation support:

Automated run evidence:

Known Gaps / Non-Goals for Current Milestone

Known-Gap Backlog (Carry Forward)

High-value gaps to revisit first if future compatibility demand appears:

  1. Streaming-profile parity gaps:
    • hls
    • OpenSubsonic transcoding extensions (getTranscodeDecision, getTranscodeStream)
  2. Sharing feature gaps:
    • getShares, createShare, updateShare, deleteShare
  3. Certification gap:
    • Full GUI-client validation passes (current matrix is non-GUI request-profile validation)

Current non-goal domains unless product scope changes:

  1. Video endpoints (getVideos, getVideoInfo)
  2. Podcast endpoints (Subsonic-format podcast domain)
  3. Chat domain
  4. Jukebox / internet-radio management domain
  5. Subsonic user-administration endpoints (getUsers, createUser, updateUser, deleteUser, changePassword)

Revisit Triggers

Promote a deferred gap to in-scope when at least one of these is true:

  1. A target real client fails a core workflow due to a specific missing endpoint/domain.
  2. soundspan product scope expands into the corresponding domain (for example podcasts/video/share).
  3. A deployment/operator requirement explicitly depends on a missing Subsonic/OpenSubsonic contract surface.

Implementation Gaps Inside Already-Implemented Endpoints

Missing Subsonic/OpenSubsonic API Surface (Exhaustive)

Spec coverage snapshot (current):

System (missing)

Browsing (missing)

Lists (missing)

Searching (missing)

Media Retrieval (missing)

Media Annotation (missing)

Sharing (missing)

Podcast (missing)

getPodcasts and getNewestPodcasts are implemented as empty-response compatibility stubs (see Implementation Gaps above). Still missing:

Jukebox (missing)

Internet Radio (missing)

Chat (missing)

User Management (missing)

Bookmarks and Play Queue (missing)

Library Scan (missing)

OpenSubsonic Transcoding Extensions (missing)

Which Missing Endpoints Are Required For This Project?

Decision basis:

Required (P0) to move toward practical client completeness

None in this category remain from the current P0 list.

Recommended (P1) for broader ecosystem compatibility

Not required for soundspan's current Subsonic-track scope (non-goal unless strategy changes)

Reference Catalogs Used For Gap Audit