fix(trackers): respect server completion threshold

close #1194
This commit is contained in:
edde746
2026-05-30 08:30:06 +02:00
parent 139eed9ca9
commit 9e5098f356
3 changed files with 87 additions and 4 deletions
+4 -2
View File
@@ -2,8 +2,10 @@
class TrackerConstants {
TrackerConstants._();
/// Progress percent at which an episode/movie counts as watched and is
/// pushed to each tracker.
/// Fallback watched threshold (percent) used only until the active server's
/// threshold is known. The operative value follows
/// [MediaServerClient.watchedThreshold] (captured per playback in
/// [TrackerCoordinator]); this constant just seeds the field before playback.
static const double watchedThresholdPercent = 80.0;
static const Duration requestTimeout = Duration(seconds: 20);
+15 -2
View File
@@ -42,6 +42,17 @@ class TrackerCoordinator {
Duration _lastPosition = Duration.zero;
bool _thresholdCrossed = false;
/// Seed used before [startPlayback] captures the server's threshold; never
/// actually consulted (a crossing is only evaluated once `_ctx` is set,
/// after the client value is assigned).
static const double _fallbackWatchedThreshold = TrackerConstants.watchedThresholdPercent / 100.0;
/// Captured from the active server client in [startPlayback]; trackers mark
/// watched once progress crosses it (Plex's `LibraryVideoPlayedThreshold`,
/// Jellyfin's fixed 0.9). Mirrors [PlaybackProgressTracker]'s local-marking
/// path so trackers and the server stay in lock-step.
double _watchedThreshold = _fallbackWatchedThreshold;
Future<void> initialize() async {
await Future.wait(_trackers.map((t) => t.initialize()));
}
@@ -71,6 +82,7 @@ class TrackerCoordinator {
}
_reset();
_ctx = ctx;
_watchedThreshold = client.watchedThreshold;
}
bool _anyTrackerNeedsFribb() => _anyTrackerNeedsFribbForLibrary(_activeLibraryGlobalKey);
@@ -332,12 +344,13 @@ class TrackerCoordinator {
_duration = Duration.zero;
_lastPosition = Duration.zero;
_thresholdCrossed = false;
_watchedThreshold = _fallbackWatchedThreshold;
}
static bool _crossed(Duration duration, Duration position) {
bool _crossed(Duration duration, Duration position) {
final dMs = duration.inMilliseconds;
if (dMs == 0) return false;
return position.inMilliseconds * 100 >= dMs * TrackerConstants.watchedThresholdPercent;
return position.inMilliseconds / dMs >= _watchedThreshold;
}
Future<void> _dispatchMarkWatched(TrackerContext ctx) async {