Device capabilities are not persisted #22

Open
opened 2026-09-13 13:33:16 +10:00 by unkin-agent · 0 comments
Member

Context: multi-replica stateless deployment (two 2-replica apps, cheeztv and fafflix, each one PostgreSQL plus valkey, no sticky sessions). Not a 12.0 regression — live in the deployed build. Tracking: #12.

Problem

Jellyfin.Server.Implementations/Devices/DeviceManager.cs keeps _capabilitiesMap in process, so reported capabilities exist only on the pod the client reported them to.

ClientCapabilities.SupportsPersistentIdentifier defaults to true (MediaBrowser.Model/Session/ClientCapabilities.cs:17), so CanAccessDevice fails closed: a restricted user's device is wrongly denied on every pod that never saw the report. The user gets an access error on some requests and not others.

Separately, missing capabilities make MediaInfoHelper fall back to a default device profile, producing a worse transcode decision than the client actually needs.

Proposal

Persist capabilities to a new table keyed by device id, and read them through on CanAccessDevice and in MediaInfoHelper. PR #8 already dropped the device and device-options dictionaries in favour of reading the database per query; this extends the same approach to capabilities.

This needs an EF migration. Any PostgreSQL migration here must be append-only — regenerating the provider's baseline previously broke upgrades of existing databases in production.

Acceptance

  • Two independently constructed instances against real PostgreSQL: capabilities reported to A are visible to B; CanAccessDevice for a restricted user's device returns true on B; MediaInfoHelper on B uses the reported profile rather than the default.
  • A new append-only migration — the existing baseline is not regenerated — and the migration chain applies cleanly to a database created before it.
  • Tests use PostgreSqlTestServer in tests/Jellyfin.Server.Tests and run in the postgres-migration-chain Woodpecker step (JELLYFIN_TEST_POSTGRES). In-memory providers have hidden different semantics and are how three bugs reached production.
Context: multi-replica stateless deployment (two 2-replica apps, `cheeztv` and `fafflix`, each one PostgreSQL plus valkey, no sticky sessions). Not a 12.0 regression — live in the deployed build. Tracking: #12. ## Problem `Jellyfin.Server.Implementations/Devices/DeviceManager.cs` keeps `_capabilitiesMap` in process, so reported capabilities exist only on the pod the client reported them to. `ClientCapabilities.SupportsPersistentIdentifier` defaults to `true` (`MediaBrowser.Model/Session/ClientCapabilities.cs:17`), so `CanAccessDevice` fails **closed**: a restricted user's device is wrongly *denied* on every pod that never saw the report. The user gets an access error on some requests and not others. Separately, missing capabilities make `MediaInfoHelper` fall back to a default device profile, producing a worse transcode decision than the client actually needs. ## Proposal Persist capabilities to a new table keyed by device id, and read them through on `CanAccessDevice` and in `MediaInfoHelper`. PR #8 already dropped the device and device-options dictionaries in favour of reading the database per query; this extends the same approach to capabilities. This needs an EF migration. Any PostgreSQL migration here must be **append-only** — regenerating the provider's baseline previously broke upgrades of existing databases in production. ## Acceptance - Two independently constructed instances against real PostgreSQL: capabilities reported to A are visible to B; `CanAccessDevice` for a restricted user's device returns true on B; `MediaInfoHelper` on B uses the reported profile rather than the default. - A new append-only migration — the existing baseline is not regenerated — and the migration chain applies cleanly to a database created before it. - Tests use `PostgreSqlTestServer` in `tests/Jellyfin.Server.Tests` and run in the `postgres-migration-chain` Woodpecker step (`JELLYFIN_TEST_POSTGRES`). In-memory providers have hidden different semantics and are how three bugs reached production.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unkin/jellyfin-ha-src#22