public void SyncProgress() { if (!TraktSettings.SyncPlayback || SyncPlaybackInProgress) { return; } SyncPlaybackInProgress = true; TraktLogger.Info("My Videos Starting Playback Sync"); // get playback data from trakt string lastPausedAtMovie; var playbackData = TraktCache.GetPausedMovies(out lastPausedAtMovie); if (playbackData == null) { TraktLogger.Warning("Failed to get resume data from trakt.tv"); SyncPlaybackInProgress = false; return; } DateTime lastPausedItemProcessed; DateTime.TryParse(lastPausedAtMovie, out lastPausedItemProcessed); TraktLogger.Info("Found {0} movies on trakt.tv with resume data, processing paused movies after {1}", playbackData.Where(p => p.Type == "movie").Count(), lastPausedAtMovie); foreach (var item in playbackData.Where(p => p.Type == "movie")) { DateTime itemPausedAt; if (DateTime.TryParse(item.PausedAt, out itemPausedAt)) { // check if we need to process if (itemPausedAt <= lastPausedItemProcessed) { continue; } } // get movie from local database if it exists var movie = GetMovies().FirstOrDefault(m => ((m.IMDBNumber == item.Movie.Ids.Imdb) && !string.IsNullOrEmpty(item.Movie.Ids.Imdb) || m.Title.ToLowerInvariant() == item.Movie.Title.ToLowerInvariant() && m.Year == item.Movie.Year)); if (movie == null) { continue; } // if the local playtime is not known then skip if (movie.Duration <= 0) { TraktLogger.Warning("Skipping item with invalid runtime in database, Title = '{0}', Year = '{1}', IMDb ID = '{2}'", item.Movie.Title, item.Movie.Year, item.Movie.Ids.Imdb); continue; } // update the stop time based on percentage watched // the video database stores duration in seconds (runtime in minutes if duration not available) and stopTime in secs var resumeData = Convert.ToInt32(movie.Duration * (item.Progress / 100.0)) - TraktSettings.SyncResumeDelta; if (resumeData < 0) { resumeData = 0; } if (string.IsNullOrEmpty(movie.VideoFileName)) { TraktLogger.Warning("Skipping item with invalid filename in database, Title = '{0}', Year = '{1}', IMDb ID = '{2}'", item.Movie.Title, item.Movie.Year, item.Movie.Ids.Imdb); continue; } // if we are syncing on plugin entry we could possibly still be sending paused data to trakt // after stopping video (stopping video == re-entry to plugin), prevent possibly reverting stale resumed data // we already have updated resume data when stopping video in real-time if (TraktSettings.SyncPlaybackOnEnterPlugin && LastMovie != null && LastMovie.VideoFileName == movie.VideoFileName) { continue; } // check if movie is restricted if (TraktSettings.BlockedFilenames.Any(f => f == movie.VideoFileName) || TraktSettings.BlockedFolders.Any(f => f == Path.GetDirectoryName(movie.VideoFileName))) { TraktLogger.Info("Ignoring resume data sync for movie, filename/folder is ignored by user. Title = '{0}', Year = '{1}', IMDb ID = '{2}', Filename = '{3}'", item.Movie.Title, item.Movie.Year, item.Movie.Ids.Imdb, movie.VideoFileName); continue; } // Get FileId from filename int fileId = VideoDatabase.GetMovieId(movie.VideoFileName); // get current stop time for movie int currentResumeData = VideoDatabase.GetMovieStopTime(fileId); if (currentResumeData != resumeData) { // Note: will need to be a bit smarter for multi-part files (who the heck still does that!) TraktLogger.Info("Setting resume time '{0}' for movie, Title = '{1}', Year = '{2}', IMDb ID = '{3}'", new TimeSpan(0, 0, 0, resumeData), item.Movie.Title, item.Movie.Year, item.Movie.Ids.Imdb); VideoDatabase.SetMovieStopTime(fileId, resumeData); } } TraktLogger.Info("My Videos Playback Sync Completed"); SyncPlaybackInProgress = false; return; }