navidrome/server/subsonic
Deluan Quintão 16567f147b
fix(jellyfin): match Jellyfin on login SessionInfo, item types and universal streams (#6161)
* fix(jellyfin): send SessionInfo on login so JellyBox gets past sign-in

JellyBox parses AuthenticateByName's SessionInfo as a required object and
fails silently when it is missing, leaving the user on the login screen.
Real Jellyfin always sends it (SessionManager.AuthenticateNewSessionInternal,
10.10.7 and master), so the login response now carries a full SessionInfo
built from the user and the MediaBrowser auth header. It includes every field
JellyBox (Id, PlayState) and Finamp (UserId, LastActivityDate, the activity
and control bools, PlayState's CanSeek/IsPaused/IsMuted) require once the
object is present. The session Id is derived from client and device id, so
repeated logins from one install share it.

* fix(jellyfin): ignore IncludeItemTypes names that aren't Jellyfin kinds

JellyBox opens an album with ParentId=<album>&IncludeItemTypes=music. Music
is not a BaseItemKind, and Jellyfin's comma-delimited binder drops values it
cannot parse, so real Jellyfin treats the request as having no type filter and
lists the album's tracks. Navidrome returned an empty list, so every album
opened empty. Entries that aren't BaseItemKind names are now dropped before
type resolution, so an all-unknown list behaves like an absent one. Real kinds
Navidrome doesn't serve, such as Boxset, still return nothing.

* fix(jellyfin): treat universal Container as the direct-play list

On /Audio/{id}/universal, Container lists the "container|codec" entries the
client can direct play, and TranscodingContainer/AudioCodec name the target
when it can't (UniversalAudioController builds DirectPlayProfiles from it).
Navidrome passed the whole list to the decider as one target format, which
matched nothing and fell back to DefaultDownsamplingFormat, so JellyBox got
every MP3 transcoded to Opus. /universal now has its own handler: a source
matching an entry keeps its format (still downsampled under a bitrate cap),
anything else is transcoded to TranscodingContainer, then AudioCodec. The
/stream routes keep treating Container as the target format.

* refactor(jellyfin): let the stream decider resolve universal requests

streamUniversal matched the Container list itself with plain string equality
and then asked the legacy resolver for the source format. That skipped the
decider's container and codec aliases (mp4 vs m4a, ogg vs opus), and a
direct-playable source over the bitrate cap was transcoded to its own format
instead of the client's TranscodingContainer.

The shared part of ResolveRequest (server-side player override, player
MaxBitRate cap, decision to Request mapping) moves to a resolve helper, and a
new ResolveClientRequest exposes it for callers that build their own
ClientInfo. streamUniversal now turns Container into DirectPlayProfiles and
TranscodingContainer/AudioCodec into a transcoding profile, so the decision
uses the same rules as the Subsonic getTranscodeDecision path. streamFile and
the /stream routes share a serveStream helper, NewSessionInfo reads the clock
itself, and duplicate comments and tests are trimmed.
2026-09-17 23:48:39 -04:00
..
e2e fix(server): return 404 instead of 500 for missing native API resources (#6131) 2026-09-14 22:46:21 -04:00
responses feat(subsonic): add OpenSubsonic work and movement attributes (#5659) 2026-06-24 09:10:00 -04:00
album_lists.go perf(genre): index genre filtering via join tables across all APIs (#5940) 2026-08-11 08:00:50 -04:00
album_lists_test.go feat(subsonic): add sonicSimilarity extension as plugin capability (#5419) 2026-04-27 17:50:09 -04:00
api.go fix(server): return 404 instead of 500 for missing native API resources (#6131) 2026-09-14 22:46:21 -04:00
api_suite_test.go refactor(lyrics): single ParseLyrics entry point + all-format plugin lyrics (#5632) 2026-06-19 18:25:35 -04:00
api_test.go fix(share): enforce per-user ownership on share reads 2026-06-05 15:50:59 -04:00
bookmarks.go refactor(server): drop redundant error return from req.Strings parsing (#5812) 2026-07-18 19:30:04 -04:00
browsing.go fix(plugins): build public URLs on the caller's address instead of localhost (#6059) 2026-08-31 21:27:43 -04:00
browsing_test.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
helpers.go fix(plugins): build public URLs on the caller's address instead of localhost (#6059) 2026-08-31 21:27:43 -04:00
helpers_test.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
jukebox.go refactor(server): drop redundant error return from req.Strings parsing (#5812) 2026-07-18 19:30:04 -04:00
library_scanning.go refactor(server): drop redundant error return from req.Strings parsing (#5812) 2026-07-18 19:30:04 -04:00
library_scanning_test.go fix(subsonic): require admin access for Subsonic management endpoints (#5510) 2026-05-19 14:23:38 -03:00
lyrics.go fix(subsonic): emit agent-specific cueLine values (#5679) 2026-06-28 18:14:18 -04:00
lyrics_test.go fix(scanner): stop logging expected lyrics sniff misses as warnings (#5702) 2026-07-02 09:46:57 -04:00
media_annotation.go refactor(server): drop redundant error return from req.Strings parsing (#5812) 2026-07-18 19:30:04 -04:00
media_annotation_test.go feat(playlists): per-user starred/rating annotations (backend) (#5749) 2026-07-14 07:38:25 -04:00
media_retrieval.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
media_retrieval_test.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
middlewares.go feat(jellyfin): non-expiring, audience-scoped tokens revocable by password change (#6013) 2026-08-22 20:36:24 -04:00
middlewares_test.go feat(jellyfin): non-expiring, audience-scoped tokens revocable by password change (#6013) 2026-08-22 20:36:24 -04:00
opensubsonic.go feat(subsonic): Implement OpenSubsonic topSongsByArtistId extension (#5853) 2026-08-02 12:39:51 -04:00
opensubsonic_test.go feat(subsonic): Implement OpenSubsonic topSongsByArtistId extension (#5853) 2026-08-02 12:39:51 -04:00
playlists.go fix(subsonic): update the playlist changed timestamp when renaming a smart playlist (#6082) 2026-09-03 16:07:53 -04:00
playlists_test.go fix(subsonic): update the playlist changed timestamp when renaming a smart playlist (#6082) 2026-09-03 16:07:53 -04:00
radio.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
radio_test.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
searching.go fix(plugins): build public URLs on the caller's address instead of localhost (#6059) 2026-08-31 21:27:43 -04:00
searching_test.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
sharing.go fix(subsonic): honor DefaultDownloadableShare in createShare (#6121) 2026-09-09 20:29:00 -04:00
sonic_similarity.go feat(subsonic): add sonicSimilarity extension as plugin capability (#5419) 2026-04-27 17:50:09 -04:00
stream.go fix(transcoding): cap concurrent transcodes to prevent ffmpeg DoS (#5522) 2026-05-24 00:24:30 -03:00
system.go Some cleanup, adding missing context handling 2022-12-06 19:57:47 -05:00
transcode.go fix(subsonic): don't re-encode a source already in the player's forced format 2026-09-07 14:56:41 -04:00
transcode_test.go fix(jellyfin): match Jellyfin on login SessionInfo, item types and universal streams (#6161) 2026-09-17 23:48:39 -04:00
users.go refactor: multiple syntax updates for Go 1.26 2026-05-19 18:02:36 -03:00
users_test.go refactor: rename EnableCoverArtUpload to EnableArtworkUpload 2026-03-27 19:33:46 -04:00