chore(jellyfin): update id-family notes for uniform canonical ids

This commit is contained in:
Deluan 2026-07-19 22:29:30 -04:00
parent d62bc7b4b2
commit 0328a732cf
3 changed files with 10 additions and 11 deletions

View File

@ -90,9 +90,9 @@ skipped, so it doesn't create a nameless player.
Navidrome item ids are **hex-encoded at the API boundary** (`dto.EncodeID`/`DecodeID`): every id
is hex-encoded on the way out and hex-decoded on the way in. This is required because some clients
parse ids as radix-16 — Finamp's queue `packIds`, for instance, does `int.parse(chunk, radix:16)`,
which chokes on Navidrome's base-62 nanoids (e.g. `5QFKvMsJrd57QE2Le2dKKo`). Because a raw MD5 id
from an old migrated library is itself valid hex, correctness depends on every emit path encoding
and every receive path decoding — see `dto/ids.go`.
which chokes on Navidrome's base62 ids (e.g. `5QFKvMsJrd57QE2Le2dKKo`). Because a base62 id can
itself be valid hex, correctness depends on every emit path encoding and every receive path
decoding — see `dto/ids.go`.
## Multi-library behavior
@ -184,13 +184,13 @@ their Navidrome `ArtworkID`.
Real Jellyfin item ids are GUIDs — 128-bit values, always 32 hex characters. Finamp relies on that
when persisting its play queue across restarts: `packIds()` bit-packs every id into exactly 16
bytes. Navidrome ids are longer (nanoid ids can exceed 128 bits, so they cannot be mapped into
GUIDs), which means Finamp silently stores only the first 16 characters of each id and asks for
those **truncated ids** back when restoring the queue — item lookups, then streaming, images,
favorites and playback reports for the restored tracks.
bytes. Navidrome ids are 22-character base62 strings, not 32-hex GUIDs, which means Finamp silently
stores only the first 16 characters of each id and asks for those **truncated ids** back when
restoring the queue — item lookups, then streaming, images, favorites and playback reports for the
restored tracks.
This API compensates server-side (`truncated_ids.go`): a 16-character id — a length no Navidrome
id family uses — is resolved to the full id by unique-prefix lookup (an indexed range scan;
id uses — is resolved to the full id by unique-prefix lookup (an indexed range scan;
ambiguity is detected and fails safe). The `/Items?ids=` batch response echoes the id **as
requested**, because Finamp matches restored items back to its stored ids, and the other item
endpoints accept truncated ids transparently.

View File

@ -3,7 +3,7 @@ package dto
import "encoding/hex"
// EncodeID renders a Navidrome id as lowercase hex; Jellyfin clients parse ids as radix-16 (e.g.
// Finamp's queue packing) and crash on Navidrome's base62 nanoids if emitted as-is.
// Finamp's queue packing) and crash on Navidrome's base62 ids if emitted as-is.
func EncodeID(id string) string {
if id == "" {
return ""

View File

@ -11,8 +11,7 @@ import (
)
// truncatedIDLen is what Finamp's saved-queue persistence cuts item ids to (16 bytes, assuming
// Jellyfin GUIDs). No Navidrome id family is 16 chars (nanoid=22, legacy MD5=32, playlist
// UUID=36), so the length alone identifies a truncated id. See README.
// Jellyfin GUIDs). All Navidrome ids are 22 chars (share ids 10), so length alone flags a truncated id. See README.
//
// Handlers taking an item id resolve it via resolveItemID/resolveItemIDs; playlist-write handlers
// and ParentId scoping don't (a restored queue never edits playlists or browses by container id).