Skip to main content
Rockbox can act as a Jellyfin server for native Jellyfin clients on your LAN. Internally it’s a thin actix-web shim over the same rockbox-library SQLite database the Subsonic API reads from — there’s no separate scan, no separate user store, and no extra daemon to manage.

Enabling

Set jellyfin_port in ~/.config/rockbox.org/settings.toml:
subsonic_username = "admin"
subsonic_password = "changeme"
jellyfin_port     = 8096      # conventional Jellyfin port; pick any free port
Then rockbox restart. The server is disabled when jellyfin_port is missing or when subsonic_password is empty — credentials are shared with the Subsonic side.

Discovery

When enabled, two discovery mechanisms run alongside the HTTP server:
  • mDNS: _jellyfin._tcp.local. is advertised on the configured port, with a ID=… TXT record matching the server’s stable Jellyfin id.
  • UDP 7359: the server binds the standard Jellyfin client-discovery port and answers the literal probe "Who is JellyfinServer?" with a JSON response containing the server’s LAN URL.
Both run automatically; nothing to configure.

Tested clients

ClientPlatformNotes
FinampAndroid/iOSBest-tested music client. Full browse + stream + scrobble.
SymfoniumAndroidPaid. Works against the Jellyfin API.
Amcfy MusicAndroidTriggers library refresh on ScheduledTasks/Running.
FindroidAndroidVideo-focused; will show empty libraries because Rockbox is audio-only.
StreamyfinAndroidPolls /Sessions; works.
Official appAndroidNot supported — the official app is a WebView around the Jellyfin web UI, which Rockbox doesn’t ship.
For music, use Finamp (or Amcfy / Symfonium).

Endpoint surface

The server implements enough of the Jellyfin OpenAPI to satisfy the native music clients above. All authenticated routes accept the token via X-Emby-Token header, Authorization: MediaBrowser Token="…", or ?api_key=… on streaming URLs. Query parameters work in both camelCase (?parentId=…) and PascalCase (?ParentId=…); repeated keys (?includeItemTypes=Audio&includeItemTypes=MusicAlbum) are concatenated.
GroupEndpoints
SystemGET /System/Info, GET /System/Info/Public, GET /System/Endpoint
AuthPOST /Users/AuthenticateByName (+ authenticatebyname lowercase alias)
UsersGET /Users, GET /Users/Public, GET /Users/Me, GET /Users/{id}
ViewsGET /Users/{id}/Views, GET /UserViews, GET /Library/MediaFolders
ItemsGET /Items, GET /Users/{id}/Items, GET /Items/{id}, GET /Items/Latest, GET /Items/Suggestions, GET /Items/{id}/File, GET /Items/{id}/Download, GET /Items/{id}/Images/{kind}
AudioGET /Audio/{id}/stream, /stream.{ext}, /universal (Range-aware)
ArtistsGET /Artists, GET /Artists/AlbumArtists, GET /Artists/{name}
SearchGET /Search/Hints, GET /Items?searchTerm=…
PlaybackGET POST /Items/{id}/PlaybackInfo
SessionsGET /Sessions, POST /Sessions/Capabilities/Full, POST /Sessions/Playing{,/Progress,/Stopped}
TasksPOST /ScheduledTasks/Running/{id}, POST /Library/Refresh
DiscoveryUDP 7359 probe responder, mDNS _jellyfin._tcp.local. advertisement
Item IDs are deterministic dashed UUIDs derived from the native Artist/Album/Track ids, and round-tripped via a jf_guids lookup table so subsequent requests resolve back to the right row.

Quick test

# Discover the server (or just `curl http://<host>:8096/System/Info/Public`)
echo -n 'Who is JellyfinServer?' | nc -u -w1 -b 255.255.255.255 7359

# Authenticate
TOKEN=$(curl -s -X POST http://localhost:8096/Users/AuthenticateByName \
  -H 'Content-Type: application/json' \
  -H 'Authorization: MediaBrowser Client="curl", Device="d", DeviceId="i", Version="0.1"' \
  -d '{"Username":"admin","Pw":"changeme"}' \
  | jq -r .AccessToken)

# List libraries (returns the synthetic "Music" CollectionFolder)
curl -s -H "X-Emby-Token: $TOKEN" "http://localhost:8096/Users/me/Views" | jq

# List all artists
curl -s -H "X-Emby-Token: $TOKEN" \
  "http://localhost:8096/Items?includeItemTypes=MusicArtist" | jq '.Items[].Name'

What’s not supported

  • Video — Rockbox is an audio-only player. Video libraries and the /Videos/{id}/stream endpoint family are not implemented.
  • Transcoding — only direct play. MediaSource.SupportsTranscoding is false; clients must support the container natively.
  • WebSocket notifications (/socket) — clients fall back to polling /Sessions, which is supported.
  • Multi-user — there is a single synthetic user matching subsonic_username. Token storage is real (persisted in jellyfin_tokens), but every token belongs to the same user.
  • Playlists, lyrics, parental ratings, sync, live TV — out of scope.