Files
plezy/lib/media/account_preferences_source.dart
edde746andGitHub ae555ed5d7 feat(settings): account preferences, stored on the server instead of the device (#2112)
Preferences that belong to the media-server account had nowhere to live in Plezy. Jellyfin keeps a user's audio/subtitle language, subtitle mode and several library options in `UserConfiguration`; plex.tv keeps the same language choices plus watched indicators and review visibility on the account. Plezy read four of those fields for auto-track selection and could never show or change any of them.

Adds an Account preferences section under Connections. One account edits in place; several show a picker first, scoped to the active profile's own connections so a managed Plex Home user never edits the owner's record. Every row is gated on what the backend can actually store.

It also moves "rewatching in Next Up" onto the account. There is no `UserConfiguration` field for it, but the per-user `DisplayPreferences` store is keyed `(userId, displayPreferencesId, client)` with no device component, so the switch goes there and follows the account.

`AccountRef` keys by account, not `clientScopeId`: MediaBrowser is `{machineId}/{userId}`, Plex is (account, Home user). Writes are patch-shaped because both backends replace whole objects — Jellyfin's `POST /Users/{id}/Configuration` and its `DisplayPreferences` row both reset omitted fields, so each write re-reads, merges only the patched keys, and posts back. Plex takes its changes as query parameters with an empty body, and its `experience` blob and the PMS `/accounts/1` mirror are deliberately untouched.

`AccountPreferencesController` owns a single repository above the profile session, so changing a language in settings reaches the next playback without a restart. Emby is gated out of rewatching through `MediaBrowserDialect.supportsNextUpRewatching`.

close #1910
2026-08-25 08:42:48 +02:00

27 lines
1.2 KiB
Dart

import 'account_preferences.dart';
import 'account_ref.dart';
/// Read/write access to one account's server-stored preferences.
///
/// One instance per [AccountRef]; implementations own the wire mapping and are
/// created by the repository, never by UI. Both current implementations
/// (`MediaBrowserAccountPreferencesSource`, `PlexAccountPreferencesSource`)
/// throw the canonical [MediaServerException] hierarchy on failure — callers
/// must not flatten those into strings.
abstract class AccountPreferencesSource {
/// What this backend can store. UI hides unsupported rows.
AccountPreferencesCapabilities get capabilities;
/// Fetch the authoritative current values.
Future<AccountPreferences> read();
/// Apply [patch] and return the account's state afterwards.
///
/// Implementations must send only what [patch] names — Jellyfin by merging it
/// into a freshly read `Configuration` before its whole-object POST, Plex by
/// putting exactly those keys in the query string. Writing a key the
/// backend does not support is a programming error; the repository filters
/// against [capabilities] first.
Future<AccountPreferences> write(AccountPreferencesPatch patch);
}