Jellyfin rows reload after watching: the Stopped report clears the server's cached lists

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
foxyzandClaude Opus 5.5 committed 2026-10-11 16:24:38 +03:00
1 parent 86eb30f498
commit 1508d2f804
5 files changed
+30 -3

No files matched your search

@@ -543,6 +543,17 @@ class JellyfinAccounts extends ChangeNotifier {
/// Drops cached browse results (refresh button, after a pick).
void invalidate(String serverId) => _clearMemo(serverId);
final _watched = StreamController<String>.broadcast();
/// Server ids whose watched state this app just changed (a stop report):
/// their cached lists are gone, and browse views reload.
Stream<String> get watched => _watched.stream;
void watchedChanged(String serverId) {
_clearMemo(serverId);
_watched.add(serverId);
}
@override
void dispose() {
_disposed = true;
@@ -157,7 +157,14 @@ class BrowseController extends ChangeNotifier {
final JellyfinAccounts accounts;
/// Clock for the Continue row's age cut-off (tests pin it).
final DateTime Function() now;
BrowseController(this.accounts, {this.now = DateTime.now});
BrowseController(this.accounts, {this.now = DateTime.now}) {
// Back from watching: the rows show what was just watched.
_watchedSub = accounts.watched.listen((id) {
if (!_disposed && id == serverId) dataChanged();
});
}
late final StreamSubscription<String> _watchedSub;
String? _serverId;
List<BrowseRoute> _stack = const [HomeRoute()];
@@ -259,6 +266,7 @@ class BrowseController extends ChangeNotifier {
@override
void dispose() {
_disposed = true;
unawaited(_watchedSub.cancel());
super.dispose();
}
}
+6 -1
View File
@@ -56,6 +56,7 @@ class JellyfinProgressReporter {
this.interval = const Duration(seconds: 10),
this.onError,
this.onUnauthorized,
this.onStopped,
DateTime Function()? clock,
}) : _clock = clock ?? DateTime.now,
_keepPlayed = playedBefore,
@@ -67,6 +68,10 @@ class JellyfinProgressReporter {
/// marks an item played past its "max resume" share (90 % by default).
static const _noPositionFrom = 0.85;
/// After Stopped (and a mark played) went out: the item's watched
/// state on the server may differ from what lists show.
final void Function()? onStopped;
Future<void> _chain = Future.value();
bool _playing = false;
bool _dead = false;
@@ -178,7 +183,7 @@ class JellyfinProgressReporter {
itemId: itemId, mediaSourceId: source.id, playSessionId: playSessionId, positionTicks: ticks);
_send('Stopped', () => client.reportPlaybackStopped(report));
if (ticks == null) _send('played', () => client.markPlayed(itemId));
return _chain;
return _chain = _chain.then((_) => onStopped?.call());
}
void _mark(PlayerSnapshot s) {
@@ -1750,6 +1750,7 @@ class SessionCoordinator {
playedBefore: before?.played ?? false,
resumeTicksBefore: before?.playbackPositionTicks ?? 0,
onUnauthorized: () => jellyfin.markExpired(ref.serverId),
onStopped: () => jellyfin.watchedChanged(ref.serverId),
onError: (e) {
if (_jfToastShown) return;
_jfToastShown = true;