From 93496849ec5fdd586ef2de317ecce485c47a6205 Mon Sep 17 00:00:00 2001 From: Jordan Koehn Date: Sun, 5 Apr 2026 11:41:55 -0400 Subject: [PATCH 1/2] fix: Live TV uses wrong begins at time --- lib/screens/video_player_screen.dart | 4 ++- lib/services/plex_client.dart | 37 +++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/lib/screens/video_player_screen.dart b/lib/screens/video_player_screen.dart index a8b6698a..c932c9a5 100644 --- a/lib/screens/video_player_screen.dart +++ b/lib/screens/video_player_screen.dart @@ -1127,7 +1127,9 @@ class VideoPlayerScreenState extends State with WidgetsBindin final watchFromStart = await _showWatchFromStartDialog(effectiveStart, nowEpoch); if (!mounted) return; if (watchFromStart == true) { - offsetSeconds = max(_programBeginsAt! - _captureBuffer!.startedAt.round(), 0); + final _programBeginsAtOffset = _programBeginsAt! - _captureBuffer!.startedAt.round(); + appLogger.d('Watch from start: _programBeginsAtOffset=${_programBeginsAtOffset}, _captureBuffer!.seekStartSeconds.round()=${_captureBuffer!.seekStartSeconds.round()}'); + offsetSeconds = max(_programBeginsAtOffset, _captureBuffer!.seekStartSeconds.round()); } } } diff --git a/lib/services/plex_client.dart b/lib/services/plex_client.dart index dd502b64..94860cb9 100644 --- a/lib/services/plex_client.dart +++ b/lib/services/plex_client.dart @@ -2575,14 +2575,34 @@ class PlexClient { final subList = subscriptions is List ? subscriptions : subscriptions is Map ? [subscriptions] : null; if (subList != null && subList.isNotEmpty) { final sub = subList.first as Map; + + final timeline = sub['Timeline']; + + // Safely extract the first element if it's a list, or the map itself + final op = timeline is List + ? (timeline.isNotEmpty ? timeline.first : null) + : (timeline is Map ? timeline : null); + + if (op is Map) { + if (op['Metadata'] case [Map firstMetadata, ...]) { + if (firstMetadata['Media'] case [Map firstMedia, ...]) { + final rawBeginsAt = firstMedia['beginsAt']; + + beginsAt = switch (rawBeginsAt) { + num n => n.toInt(), + String s => int.tryParse(s), + _ => null, + }; + + appLogger.d('beginsAt=$beginsAt'); + } + } + } + final ops = sub['MediaGrabOperation']; final opList = ops is List ? ops : ops is Map ? [ops] : null; if (opList != null && opList.isNotEmpty) { final op = opList.first as Map; - final rawBeginsAt = op['beginsAt']; - beginsAt = rawBeginsAt is num - ? rawBeginsAt.toInt() - : rawBeginsAt is String ? int.tryParse(rawBeginsAt) : null; final nested = op['Metadata']; if (nested is Map) { metadataJson = nested; @@ -2629,13 +2649,18 @@ class PlexClient { } // beginsAt may also be on the Media items (not just the GrabOperation) + // This value is the start of the requested stream, not the current program. So it will effectively be the current time if (beginsAt == null) { final media = metadataJson['Media']; if (media is List && media.isNotEmpty) { final firstMedia = media.first; if (firstMedia is Map) { - final raw = firstMedia['beginsAt']; - beginsAt = raw is num ? raw.toInt() : raw is String ? int.tryParse(raw) : null; + final rawBeginsAt = firstMedia['beginsAt']; + beginsAt = switch (rawBeginsAt) { + num n => n.toInt(), + String s => int.tryParse(s), + _ => null, + }; } } } From 29ab2ddad3c0e6a4310f13583619e88d47b97b33 Mon Sep 17 00:00:00 2001 From: edde746 <86283021+edde746@users.noreply.github.com> Date: Mon, 6 Apr 2026 04:12:16 +0200 Subject: [PATCH 2/2] refactor: fix variable naming, indentation, remove debug log --- lib/screens/video_player_screen.dart | 5 ++--- lib/services/plex_client.dart | 10 +++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/screens/video_player_screen.dart b/lib/screens/video_player_screen.dart index c932c9a5..b221d5e3 100644 --- a/lib/screens/video_player_screen.dart +++ b/lib/screens/video_player_screen.dart @@ -1127,9 +1127,8 @@ class VideoPlayerScreenState extends State with WidgetsBindin final watchFromStart = await _showWatchFromStartDialog(effectiveStart, nowEpoch); if (!mounted) return; if (watchFromStart == true) { - final _programBeginsAtOffset = _programBeginsAt! - _captureBuffer!.startedAt.round(); - appLogger.d('Watch from start: _programBeginsAtOffset=${_programBeginsAtOffset}, _captureBuffer!.seekStartSeconds.round()=${_captureBuffer!.seekStartSeconds.round()}'); - offsetSeconds = max(_programBeginsAtOffset, _captureBuffer!.seekStartSeconds.round()); + final programBeginsAtOffset = _programBeginsAt! - _captureBuffer!.startedAt.round(); + offsetSeconds = max(programBeginsAtOffset, _captureBuffer!.seekStartSeconds.round()); } } } diff --git a/lib/services/plex_client.dart b/lib/services/plex_client.dart index 94860cb9..16d0ee33 100644 --- a/lib/services/plex_client.dart +++ b/lib/services/plex_client.dart @@ -2656,11 +2656,11 @@ class PlexClient { final firstMedia = media.first; if (firstMedia is Map) { final rawBeginsAt = firstMedia['beginsAt']; - beginsAt = switch (rawBeginsAt) { - num n => n.toInt(), - String s => int.tryParse(s), - _ => null, - }; + beginsAt = switch (rawBeginsAt) { + num n => n.toInt(), + String s => int.tryParse(s), + _ => null, + }; } } }