From 2be343b2760ef5f34d8d5f834993e76b732c9991 Mon Sep 17 00:00:00 2001 From: omkar Date: Tue, 14 Jan 2025 18:42:59 +0530 Subject: [PATCH] fix: trakt integration and multiple episode thing --- .../stremio/stremio_season_selector.dart | 7 +- .../doc_viewer/container/video_viewer.dart | 84 +++++++++++++++---- .../video_viewer/video_viewer_mobile_ui.dart | 11 ++- lib/features/trakt/service/trakt.service.dart | 6 ++ 4 files changed, 90 insertions(+), 18 deletions(-) diff --git a/lib/features/connections/widget/stremio/stremio_season_selector.dart b/lib/features/connections/widget/stremio/stremio_season_selector.dart index 957e130..dd7c46b 100644 --- a/lib/features/connections/widget/stremio/stremio_season_selector.dart +++ b/lib/features/connections/widget/stremio/stremio_season_selector.dart @@ -52,10 +52,15 @@ class _StremioItemSeasonSelectorState extends State return; } + final index = getSelectedSeason(); + _tabController = TabController( length: seasonMap.keys.length, vsync: this, - initialIndex: getSelectedSeason(), + initialIndex: index.clamp( + 0, + seasonMap.keys.isNotEmpty ? seasonMap.keys.length - 1 : 0, + ), ); // This is for rendering the component again for the selection of another tab diff --git a/lib/features/doc_viewer/container/video_viewer.dart b/lib/features/doc_viewer/container/video_viewer.dart index 3b383c3..1cddbdf 100644 --- a/lib/features/doc_viewer/container/video_viewer.dart +++ b/lib/features/doc_viewer/container/video_viewer.dart @@ -59,6 +59,8 @@ class _VideoViewerState extends State { Future? traktProgress; Future saveWatchHistory() async { + _logger.info('Starting to save watch history...'); + final duration = player.state.duration.inSeconds; if (duration <= 30) { @@ -68,7 +70,7 @@ class _VideoViewerState extends State { if (gotFromTraktDuration == false) { _logger.info( - "did not start the scrobbing because initially time is not retrieved from the api", + "Did not start the scrobbling because initially time is not retrieved from the API.", ); return; } @@ -113,6 +115,8 @@ class _VideoViewerState extends State { season: _source.season, ), ); + + _logger.info('Watch history saved successfully.'); } late final controller = VideoController( @@ -128,26 +132,36 @@ class _VideoViewerState extends State { int? traktId; - Future setDurationFromTrakt() async { + Future setDurationFromTrakt({ + Future? traktProgress, + }) async { + _logger.info('Setting duration from Trakt...'); + try { if (player.state.duration.inSeconds < 2) { + _logger.info('Duration is too short to set from Trakt.'); return; } if (gotFromTraktDuration) { + _logger.info('Duration already set from Trakt.'); return; } gotFromTraktDuration = true; - if (!TraktService.isEnabled() || traktProgress == null) { + if (!TraktService.isEnabled() || + (traktProgress ?? this.traktProgress) == null) { + _logger.info( + 'Trakt service is not enabled or progress is null. Playing video.'); player.play(); return; } - final progress = await traktProgress; + final progress = await (traktProgress ?? this.traktProgress); if (this.meta is! types.Meta) { + _logger.info('Meta is not of type types.Meta.'); return; } @@ -161,11 +175,14 @@ class _VideoViewerState extends State { ); if (duration.inSeconds > 10) { + _logger.info('Seeking to duration: $duration'); await player.seek(duration); } await player.play(); + _logger.info('Video started playing.'); } catch (e) { + _logger.severe('Error setting duration from Trakt: $e'); await player.play(); } } @@ -175,24 +192,43 @@ class _VideoViewerState extends State { PlaybackConfig config = getPlaybackConfig(); Future setupVideoThings() async { + _logger.info('Setting up video things...'); + + traktProgress = null; + traktProgress = TraktService.instance!.getProgress( + meta as types.Meta, + bypassCache: true, + ); + _duration = player.stream.duration.listen((item) async { + if (meta is types.Meta) { + setDurationFromTrakt(traktProgress: traktProgress); + } + if (item.inSeconds != 0) { + _logger.info('Duration updated: $item'); await saveWatchHistory(); } }); _timer = Timer.periodic(const Duration(seconds: 30), (timer) { + _logger.info('Periodic save watch history triggered.'); saveWatchHistory(); }); _streamListen = player.stream.playing.listen((playing) { + _logger.info('Playing state changed: $playing'); saveWatchHistory(); }); + _logger.info('Loading file...'); + return loadFile(); } destroyVideoThing() async { + _logger.info('Destroying video things...'); + timeLoaded = false; gotFromTraktDuration = false; traktProgress = null; @@ -200,11 +236,13 @@ class _VideoViewerState extends State { for (final item in listener) { item.cancel(); } + listener = []; _timer?.cancel(); _streamListen?.cancel(); _duration?.cancel(); if (meta is types.Meta && player.state.duration.inSeconds > 30) { + _logger.info('Stopping scrobbling and clearing cache...'); await TraktService.instance!.stopScrobbling( meta: meta as types.Meta, progress: currentProgressInPercentage, @@ -212,11 +250,14 @@ class _VideoViewerState extends State { traktId: traktId, ); } + + _logger.info('Video things destroyed.'); } GlobalKey videoKey = GlobalKey(); generateNewKey() { + _logger.info('Generating new key...'); videoKey = GlobalKey(); setState(() {}); @@ -225,6 +266,8 @@ class _VideoViewerState extends State { @override void initState() { super.initState(); + _logger.info('Initializing VideoViewer...'); + _source = widget.source; SystemChrome.setEnabledSystemUIMode( @@ -234,6 +277,7 @@ class _VideoViewerState extends State { if (player.platform is NativePlayer && !kIsWeb) { Future.microtask(() async { + _logger.info('Setting network timeout...'); await (player.platform as dynamic).setProperty('network-timeout', '60'); }); } @@ -242,17 +286,17 @@ class _VideoViewerState extends State { _source, widget.meta!, ); + + _logger.info('VideoViewer initialized.'); } Future loadFile() async { + _logger.info('Loading file...'); + Duration duration = const Duration(seconds: 0); if (meta is types.Meta && TraktService.isEnabled()) { _logger.info("Playing video ${(meta as types.Meta).selectedVideoIndex}"); - - traktProgress = TraktService.instance!.getProgress( - meta as types.Meta, - ); } else { final item = await zeeeWatchHistory!.getItemWatchHistory( ids: [ @@ -279,6 +323,7 @@ class _VideoViewerState extends State { switch (_source.runtimeType) { case const (FileSource): if (kIsWeb) { + _logger.info('FileSource is not supported on web.'); return; } player.open( @@ -300,10 +345,12 @@ class _VideoViewerState extends State { play: false, ); } + + _logger.info('File loaded successfully.'); } - late StreamSubscription? _streamListen; - late StreamSubscription? _duration; + StreamSubscription? _streamListen; + StreamSubscription? _duration; @override void dispose() { @@ -315,27 +362,34 @@ class _VideoViewerState extends State { DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight, ]); + SystemChrome.setEnabledSystemUIMode( SystemUiMode.edgeToEdge, overlays: [], ); + destroyVideoThing(); player.dispose(); + super.dispose(); + + _logger.info('VideoViewer disposed.'); } onVideoChange(DocSource source, LibraryItem item) async { - _source = source; - meta = item; - setState(() {}); await destroyVideoThing(); + + _logger.info('Changing video source...'); + + _source = source; + meta = item; setState(() {}); - traktProgress = null; await setupVideoThings(); - await setDurationFromTrakt(); setState(() {}); generateNewKey(); + + _logger.info('Video source changed successfully.'); } @override diff --git a/lib/features/doc_viewer/container/video_viewer/video_viewer_mobile_ui.dart b/lib/features/doc_viewer/container/video_viewer/video_viewer_mobile_ui.dart index 087a3dd..4d3464f 100644 --- a/lib/features/doc_viewer/container/video_viewer/video_viewer_mobile_ui.dart +++ b/lib/features/doc_viewer/container/video_viewer/video_viewer_mobile_ui.dart @@ -102,7 +102,7 @@ class _VideoViewerMobileState extends State { key: widget.videoKey, onExitFullscreen: () async { await defaultExitNativeFullscreen(); - if (context.mounted) Navigator.of(context).pop(); + Navigator.of(context).pop(); }, controller: widget.controller, controls: MaterialVideoControls, @@ -126,7 +126,14 @@ class _VideoViewerMobileState extends State { topButtonBar: [ MaterialCustomButton( onPressed: () { - Navigator.of(context).pop(); + Navigator.of( + context, + rootNavigator: true, + ).pop(); + Navigator.of( + context, + rootNavigator: true, + ).pop(); }, icon: const Icon( Icons.arrow_back, diff --git a/lib/features/trakt/service/trakt.service.dart b/lib/features/trakt/service/trakt.service.dart index b66729f..4eb3856 100644 --- a/lib/features/trakt/service/trakt.service.dart +++ b/lib/features/trakt/service/trakt.service.dart @@ -992,6 +992,8 @@ class TraktService { continue; } + meta.videos = meta.videos ?? []; + final result = meta.videos?.firstWhereOrNull((video) { if (video.tvdbId != null && item['episode']['ids']['tvdb'] != null) { @@ -1009,6 +1011,10 @@ class TraktService { final videoIndex = meta.videos!.indexOf(result); meta.videos![videoIndex].progress = item['progress']; + + _logger.info( + "Setting progress for ${meta.videos![videoIndex].name} to ${item['progress']}", + ); } return meta; } else {