Jellyfin end to end: per-viewer playback, progress, episodes, swap browser
- Host/swap send refs only; pasted Jellyfin links become refs; the host hands the relay its own app-obtained credential. - Each viewer resolves with their own account (token in a header) or via the relay, else a clear blocked card with Link account. - Per-account progress reporting (Playing/Progress/Stopped), 401 marks the account expired. - Previous/next episode in the controls (< > / Shift+P/N), floating Next episode pill near the end, auto-advance countdown (one designated swapper), track carry-over per series. - Swap panel uses the shared MediaPicker; browser location remembered per server and opens on the current series. - Fix: states are applied one at a time (a stale pause could land after a newer play). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
773a04369e
commit
ae4edc29e8
33 files changed
+3541
-175
No files matched your search
@@ -23,6 +23,7 @@ const _keyDeviceId = 'deviceId';
|
||||
const _keyAccounts = 'accounts';
|
||||
const _keyDefault = 'defaultServer';
|
||||
const _keyLastPick = 'lastPick';
|
||||
const _keyBrowsePrefix = 'browse:';
|
||||
|
||||
/// One signed-in user on one server.
|
||||
class JellyfinAccount {
|
||||
@@ -124,10 +125,12 @@ abstract class JellyfinStore {
|
||||
}
|
||||
|
||||
class HiveJellyfinStore implements JellyfinStore {
|
||||
HiveJellyfinStore({this.boxName = jellyfinBoxName});
|
||||
final String boxName;
|
||||
Box? _box;
|
||||
|
||||
@override
|
||||
Future<void> open() async => _box ??= await Hive.openBox(jellyfinBoxName);
|
||||
Future<void> open() async => _box ??= await Hive.openBox(boxName);
|
||||
|
||||
@override
|
||||
Object? get(String key) => _box?.get(key);
|
||||
@@ -461,6 +464,26 @@ class JellyfinAccounts extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
/// The browser's last location on [serverId] (encoded route stack, see
|
||||
/// `browse_scope.dart`), restored by every browser and across restarts.
|
||||
Object? browseLocation(String serverId) {
|
||||
try {
|
||||
final v = _store.get('$_keyBrowsePrefix$serverId');
|
||||
return v is String ? _tryJson(v) : null;
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> saveBrowseLocation(String serverId, Object? location) async {
|
||||
try {
|
||||
await _store.put(
|
||||
'$_keyBrowsePrefix$serverId', location == null ? null : jsonEncode(location));
|
||||
} catch (e) {
|
||||
debugPrint('save browse location failed: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------- cache
|
||||
|
||||
/// Short-lived memo for browse calls, so going back does not refetch.
|
||||
|
||||
Reference in new issue
Block a user