private async Task SendEpisodePlaystateUpdates( bool seen, TraktUser traktUser, List <Episode> playedEpisodes, ISplittableProgress <double> progress, CancellationToken cancellationToken) { _logger.Info("Episodes to set " + (seen ? string.Empty : "un") + "watched: " + playedEpisodes.Count); if (playedEpisodes.Count > 0) { try { var dataContracts = await _traktApi.SendEpisodePlaystateUpdates(playedEpisodes, traktUser, false, seen, cancellationToken).ConfigureAwait(false); if (dataContracts != null) { foreach (var con in dataContracts) { LogTraktResponseDataContract(con); } } } catch (Exception e) { _logger.ErrorException("Error updating episode play states", e); } progress.Report(100); } }
private async Task SyncUserLibrary(User user, TraktUser traktUser, double progPercent, double percentPerUser, IProgress <double> progress, CancellationToken cancellationToken) { var libraryRoot = user.RootFolder; // purely for progress reporting var mediaItemsCount = libraryRoot.GetRecursiveChildren(user).Count(i => _traktApi.CanSync(i, traktUser)); if (mediaItemsCount == 0) { _logger.Info("No media found for '" + user.Name + "'."); return; } _logger.Info(mediaItemsCount + " Items found for '" + user.Name + "'."); var percentPerItem = (float)percentPerUser / mediaItemsCount / 2.0; /* * In order to sync watched status to trakt.tv we need to know what's been watched on Trakt already. This * will stop us from endlessly incrementing the watched values on the site. */ var traktWatchedMovies = await _traktApi.SendGetAllWatchedMoviesRequest(traktUser).ConfigureAwait(false); var traktCollectedMovies = await _traktApi.SendGetAllCollectedMoviesRequest(traktUser).ConfigureAwait(false); var movieItems = libraryRoot.GetRecursiveChildren(user) .Where(x => x is Movie) .Where(x => _traktApi.CanSync(x, traktUser)) .OrderBy(x => x.Name) .ToList(); var movies = new List <Movie>(); var playedMovies = new List <Movie>(); var unPlayedMovies = new List <Movie>(); foreach (var child in movieItems) { cancellationToken.ThrowIfCancellationRequested(); var movie = child as Movie; var userData = _userDataManager.GetUserData(user.Id, child.GetUserDataKey()); var collectedMovies = SyncFromTraktTask.FindMatches(movie, traktCollectedMovies).ToList(); if (!collectedMovies.Any() || collectedMovies.All(collectedMovie => collectedMovie.MetadataIsDifferent(movie))) { movies.Add(movie); } var movieWatched = SyncFromTraktTask.FindMatch(movie, traktWatchedMovies); if (userData.Played) { if (movieWatched == null) { playedMovies.Add(movie); } } else { if (movieWatched != null) { unPlayedMovies.Add(movie); } } // purely for progress reporting progPercent += percentPerItem; progress.Report(progPercent); } _logger.Info("Movies to add to Collection: " + movies.Count); // send any remaining entries if (movies.Count > 0) { try { var dataContracts = await _traktApi.SendLibraryUpdateAsync(movies, traktUser, cancellationToken, EventType.Add) .ConfigureAwait(false); if (dataContracts != null) { foreach (var traktSyncResponse in dataContracts) { LogTraktResponseDataContract(traktSyncResponse); } } } catch (ArgumentNullException argNullEx) { _logger.ErrorException("ArgumentNullException handled sending movies to trakt.tv", argNullEx); } catch (Exception e) { _logger.ErrorException("Exception handled sending movies to trakt.tv", e); } // purely for progress reporting progPercent += (percentPerItem * movies.Count); progress.Report(progPercent); } _logger.Info("Movies to set watched: " + playedMovies.Count); if (playedMovies.Count > 0) { try { var dataContracts = await _traktApi.SendMoviePlaystateUpdates(playedMovies, traktUser, true, cancellationToken); if (dataContracts != null) { foreach (var traktSyncResponse in dataContracts) { LogTraktResponseDataContract(traktSyncResponse); } } } catch (Exception e) { _logger.ErrorException("Error updating movie play states", e); } // purely for progress reporting progPercent += (percentPerItem * playedMovies.Count); progress.Report(progPercent); } _logger.Info("Movies to set unwatched: " + unPlayedMovies.Count); if (unPlayedMovies.Count > 0) { try { var dataContracts = await _traktApi.SendMoviePlaystateUpdates(unPlayedMovies, traktUser, false, cancellationToken); if (dataContracts != null) { foreach (var traktSyncResponse in dataContracts) { LogTraktResponseDataContract(traktSyncResponse); } } } catch (Exception e) { _logger.ErrorException("Error updating movie play states", e); } // purely for progress reporting progPercent += (percentPerItem * unPlayedMovies.Count); progress.Report(progPercent); } var traktWatchedShows = await _traktApi.SendGetWatchedShowsRequest(traktUser).ConfigureAwait(false); var traktCollectedShows = await _traktApi.SendGetCollectedShowsRequest(traktUser).ConfigureAwait(false); var episodeItems = libraryRoot.GetRecursiveChildren(user) .Where(x => x is Episode) .Where(x => _traktApi.CanSync(x, traktUser)) .OrderBy(x => x is Episode ? (x as Episode).SeriesName : null) .ToList(); var episodes = new List <Episode>(); var playedEpisodes = new List <Episode>(); var unPlayedEpisodes = new List <Episode>(); foreach (var child in episodeItems) { cancellationToken.ThrowIfCancellationRequested(); var episode = child as Episode; var userData = _userDataManager.GetUserData(user.Id, episode.GetUserDataKey()); var isPlayedTraktTv = false; var traktWatchedShow = SyncFromTraktTask.FindMatch(episode.Series, traktWatchedShows); if (traktWatchedShow != null && traktWatchedShow.Seasons != null && traktWatchedShow.Seasons.Count > 0) { isPlayedTraktTv = traktWatchedShow.Seasons.Any( season => season.Number == episode.GetSeasonNumber() && season.Episodes != null && season.Episodes.Any(te => te.Number == episode.IndexNumber && te.Plays > 0)); } // if the show has been played locally and is unplayed on trakt.tv then add it to the list if (userData != null && userData.Played && !isPlayedTraktTv) { playedEpisodes.Add(episode); } // If the show has not been played locally but is played on trakt.tv then add it to the unplayed list else if (userData != null && !userData.Played && isPlayedTraktTv) { unPlayedEpisodes.Add(episode); } var traktCollectedShow = SyncFromTraktTask.FindMatch(episode.Series, traktCollectedShows); if (traktCollectedShow == null || traktCollectedShow.Seasons == null || traktCollectedShow.Seasons.All(x => x.Number != episode.ParentIndexNumber) || traktCollectedShow.Seasons.First(x => x.Number == episode.ParentIndexNumber) .Episodes.All(e => e.Number != episode.IndexNumber)) { episodes.Add(episode); } // purely for progress reporting progPercent += percentPerItem; progress.Report(progPercent); } _logger.Info("Episodes to add to Collection: " + episodes.Count); if (episodes.Count > 0) { try { var dataContracts = await _traktApi.SendLibraryUpdateAsync(episodes, traktUser, cancellationToken, EventType.Add) .ConfigureAwait(false); if (dataContracts != null) { foreach (var traktSyncResponse in dataContracts) { LogTraktResponseDataContract(traktSyncResponse); } } } catch (ArgumentNullException argNullEx) { _logger.ErrorException("ArgumentNullException handled sending episodes to trakt.tv", argNullEx); } catch (Exception e) { _logger.ErrorException("Exception handled sending episodes to trakt.tv", e); } // purely for progress reporting progPercent += (percentPerItem * episodes.Count); progress.Report(progPercent); } _logger.Info("Episodes to set watched: " + playedEpisodes.Count); if (playedEpisodes.Count > 0) { try { var dataContracts = await _traktApi.SendEpisodePlaystateUpdates(playedEpisodes, traktUser, true, cancellationToken); if (dataContracts != null) { foreach (var traktSyncResponse in dataContracts) { LogTraktResponseDataContract(traktSyncResponse); } } } catch (Exception e) { _logger.ErrorException("Error updating episode play states", e); } // purely for progress reporting progPercent += (percentPerItem * playedEpisodes.Count); progress.Report(progPercent); } _logger.Info("Episodes to set unwatched: " + unPlayedEpisodes.Count); if (unPlayedEpisodes.Count > 0) { try { var dataContracts = await _traktApi.SendEpisodePlaystateUpdates(unPlayedEpisodes, traktUser, false, cancellationToken); if (dataContracts != null) { foreach (var traktSyncResponse in dataContracts) { LogTraktResponseDataContract(traktSyncResponse); } } } catch (Exception e) { _logger.ErrorException("Error updating episode play states", e); } // purely for progress reporting progPercent += (percentPerItem * unPlayedEpisodes.Count); progress.Report(progPercent); } }
/// <summary> /// /// </summary> /// <param name="userDataSaveEventArgs"></param> /// <param name="traktUser"></param> public async Task ProcessUserDataSaveEventArgs(UserDataSaveEventArgs userDataSaveEventArgs, TraktUser traktUser, CancellationToken cancellationToken) { var userPackage = _userDataPackages.FirstOrDefault(e => e.TraktUser.Equals(traktUser)); if (userPackage == null) { userPackage = new UserDataPackage { TraktUser = traktUser }; _userDataPackages.Add(userPackage); } if (_timer == null) { _timer = new Timer(OnTimerCallback, null, TimeSpan.FromMilliseconds(5000), Timeout.InfiniteTimeSpan); } else { _timer.Change(TimeSpan.FromMilliseconds(5000), Timeout.InfiniteTimeSpan); } var movie = userDataSaveEventArgs.Item as Movie; if (movie != null) { if (userDataSaveEventArgs.UserData.Played) { userPackage.SeenMovies.Add(movie); if (userPackage.SeenMovies.Count >= 100) { await _traktApi.SendMoviePlaystateUpdates(userPackage.SeenMovies, userPackage.TraktUser, true, true, cancellationToken).ConfigureAwait(false); userPackage.SeenMovies = new List <Movie>(); } await MovieStatusUpdate(movie, userPackage.TraktUser, cancellationToken).ConfigureAwait(false); } else { userPackage.UnSeenMovies.Add(movie); if (userPackage.UnSeenMovies.Count >= 100) { await _traktApi.SendMoviePlaystateUpdates(userPackage.UnSeenMovies, userPackage.TraktUser, true, false, cancellationToken).ConfigureAwait(false); userPackage.UnSeenMovies = new List <Movie>(); } } return; } var episode = userDataSaveEventArgs.Item as Episode; if (episode == null) { return; } // If it's not the series we're currently storing, upload our episodes and reset the arrays if (!userPackage.CurrentSeriesId.Equals(episode.Series.Id)) { if (userPackage.SeenEpisodes.Any()) { await _traktApi.SendEpisodePlaystateUpdates(userPackage.SeenEpisodes, userPackage.TraktUser, true, true, cancellationToken).ConfigureAwait(false); userPackage.SeenEpisodes = new List <Episode>(); } if (userPackage.UnSeenEpisodes.Any()) { await _traktApi.SendEpisodePlaystateUpdates(userPackage.UnSeenEpisodes, userPackage.TraktUser, true, false, cancellationToken).ConfigureAwait(false); userPackage.UnSeenEpisodes = new List <Episode>(); } userPackage.CurrentSeriesId = episode.Series.Id; } if (userDataSaveEventArgs.UserData.Played) { userPackage.SeenEpisodes.Add(episode); await EpisodeStatusUpdate(episode, traktUser, cancellationToken).ConfigureAwait(false); } else { userPackage.UnSeenEpisodes.Add(episode); } }
/// <summary> /// /// </summary> /// <param name="userDataSaveEventArgs"></param> /// <param name="traktUser"></param> public void ProcessUserDataSaveEventArgs(UserDataSaveEventArgs userDataSaveEventArgs, TraktUser traktUser) { var userPackage = _userDataPackages.FirstOrDefault(e => e.TraktUser.Equals(traktUser)); if (userPackage == null) { userPackage = new UserDataPackage { TraktUser = traktUser }; _userDataPackages.Add(userPackage); } if (_timer == null) { _timer = new Timer(5000); _timer.Elapsed += TimerElapsed; } if (_timer.Enabled) { _timer.Stop(); _timer.Start(); } else { _timer.Start(); } var movie = userDataSaveEventArgs.Item as Movie; if (movie != null) { if (userDataSaveEventArgs.UserData.Played) { userPackage.SeenMovies.Add(movie); if (userPackage.SeenMovies.Count >= 100) { _traktApi.SendMoviePlaystateUpdates(userPackage.SeenMovies, userPackage.TraktUser, true, CancellationToken.None).ConfigureAwait(false); userPackage.SeenMovies = new List <Movie>(); } } else { userPackage.UnSeenMovies.Add(movie); if (userPackage.UnSeenMovies.Count >= 100) { _traktApi.SendMoviePlaystateUpdates(userPackage.UnSeenMovies, userPackage.TraktUser, false, CancellationToken.None).ConfigureAwait(false); userPackage.UnSeenMovies = new List <Movie>(); } } return; } var episode = userDataSaveEventArgs.Item as Episode; if (episode == null) { return; } // If it's not the series we're currently storing, upload our episodes and reset the arrays if (!userPackage.CurrentSeriesId.Equals(episode.Series.Id)) { if (userPackage.SeenEpisodes.Any()) { _traktApi.SendEpisodePlaystateUpdates(userPackage.SeenEpisodes, userPackage.TraktUser, true, CancellationToken.None).ConfigureAwait(false); userPackage.SeenEpisodes = new List <Episode>(); } if (userPackage.UnSeenEpisodes.Any()) { _traktApi.SendEpisodePlaystateUpdates(userPackage.UnSeenEpisodes, userPackage.TraktUser, false, CancellationToken.None).ConfigureAwait(false); userPackage.SeenEpisodes = new List <Episode>(); } userPackage.CurrentSeriesId = episode.Series.Id; } if (userDataSaveEventArgs.UserData.Played) { userPackage.SeenEpisodes.Add(episode); } else { userPackage.UnSeenEpisodes.Add(episode); } }
private async Task SyncUserLibrary(User user, TraktUser traktUser, double progPercent, double percentPerUser, IProgress <double> progress, CancellationToken cancellationToken) { var libraryRoot = user.RootFolder; /* * In order to sync watched status to trakt.tv we need to know what's been watched on Trakt already. This * will stop us from endlessly incrementing the watched values on the site. */ List <TraktMovieDataContract> tMovies = await _traktApi.SendGetAllMoviesRequest(traktUser).ConfigureAwait(false); List <TraktUserLibraryShowDataContract> tShowsWatched = await _traktApi.SendGetWatchedShowsRequest(traktUser).ConfigureAwait(false); var movies = new List <Movie>(); var episodes = new List <Episode>(); var playedMovies = new List <Movie>(); var playedEpisodes = new List <Episode>(); var unPlayedMovies = new List <Movie>(); var unPlayedEpisodes = new List <Episode>(); var currentSeriesId = Guid.Empty; var mediaItems = libraryRoot.GetRecursiveChildren(user) .Where(SyncFromTraktTask.CanSync) .ToList(); if (mediaItems.Count == 0) { _logger.Info("No trakt media found for '" + user.Name + "'. Have trakt locations been configured?"); return; } // purely for progress reporting var percentPerItem = percentPerUser / mediaItems.Count; foreach (var child in mediaItems) { cancellationToken.ThrowIfCancellationRequested(); if (child.Path == null || child.LocationType == LocationType.Virtual) { continue; } if (child is Movie) { var movie = (Movie)child; movies.Add(movie); var userData = _userDataManager.GetUserData(user.Id, child.GetUserDataKey()); var traktTvMovie = SyncFromTraktTask.FindMatch(child, tMovies); if (traktTvMovie != null && userData.Played && (traktTvMovie.Watched == false || traktTvMovie.Plays < userData.PlayCount)) { playedMovies.Add(movie); } else if (traktTvMovie != null && traktTvMovie.Watched && !userData.Played) { unPlayedMovies.Add(movie); } // publish if the list hits a certain size if (movies.Count >= 120) { // Add movies to library try { var dataContract = await _traktApi.SendLibraryUpdateAsync(movies, traktUser, cancellationToken, EventType.Add).ConfigureAwait(false); if (dataContract != null) { LogTraktResponseDataContract(dataContract); } } catch (ArgumentNullException argNullEx) { _logger.ErrorException("ArgumentNullException handled sending movies to trakt.tv", argNullEx); } catch (Exception e) { _logger.ErrorException("Exception handled sending movies to trakt.tv", e); } movies.Clear(); // Mark movies seen if (playedMovies.Count > 0) { try { var dataCotract = await _traktApi.SendMoviePlaystateUpdates(playedMovies, traktUser, true, cancellationToken); if (dataCotract != null) { LogTraktResponseDataContract(dataCotract); } } catch (Exception e) { _logger.ErrorException("Error updating played state", e); } playedMovies.Clear(); } // Mark movies unseen if (unPlayedMovies.Count > 0) { try { var dataContract = await _traktApi.SendMoviePlaystateUpdates(unPlayedMovies, traktUser, false, cancellationToken); if (dataContract != null) { LogTraktResponseDataContract(dataContract); } } catch (Exception e) { _logger.ErrorException("Error updating played state", e); } unPlayedMovies.Clear(); } } } else if (child is Episode) { var ep = child as Episode; var series = ep.Series; var userData = _userDataManager.GetUserData(user.Id, ep.GetUserDataKey()); var isPlayedTraktTv = false; var traktTvShow = SyncFromTraktTask.FindMatch(series, tShowsWatched); if (traktTvShow != null && traktTvShow.Seasons != null && traktTvShow.Seasons.Count > 0) { foreach (var episode in from season in traktTvShow.Seasons where ep.Season != null && season.Season.Equals(ep.Season.IndexNumber) && season.Episodes != null && season.Episodes.Count > 0 from episode in season.Episodes where episode.Equals(ep.IndexNumber) select episode) { isPlayedTraktTv = true; } } if (series != null && currentSeriesId != series.Id && episodes.Count > 0) { // We're starting a new show. Finish up with the old one // Add episodes to trakt.tv library try { var dataContract = await _traktApi.SendLibraryUpdateAsync(episodes, traktUser, cancellationToken, EventType.Add).ConfigureAwait(false); if (dataContract != null) { LogTraktResponseDataContract(dataContract); } } catch (ArgumentNullException argNullEx) { _logger.ErrorException("ArgumentNullException handled sending episodes to trakt.tv", argNullEx); } catch (Exception e) { _logger.ErrorException("Exception handled sending episodes to trakt.tv", e); } // Update played state of these episodes if (playedEpisodes.Count > 0) { try { var dataContracts = await _traktApi.SendEpisodePlaystateUpdates(playedEpisodes, traktUser, true, cancellationToken); if (dataContracts != null) { foreach (var dataContract in dataContracts) { LogTraktResponseDataContract(dataContract); } } } catch (Exception e) { _logger.ErrorException("Exception handled sending played episodes to trakt.tv", e); } } if (unPlayedEpisodes.Count > 0) { try { var dataContracts = await _traktApi.SendEpisodePlaystateUpdates(unPlayedEpisodes, traktUser, false, cancellationToken); if (dataContracts != null) { foreach (var dataContract in dataContracts) { LogTraktResponseDataContract(dataContract); } } } catch (Exception e) { _logger.ErrorException("Exception handled sending played episodes to trakt.tv", e); } } episodes.Clear(); playedEpisodes.Clear(); unPlayedEpisodes.Clear(); } if (ep.Series != null) { currentSeriesId = ep.Series.Id; episodes.Add(ep); } // if the show has been played locally and is unplayed on trakt.tv then add it to the list if (userData != null && userData.Played && !isPlayedTraktTv) { playedEpisodes.Add(ep); } // If the show has not been played locally but is played on trakt.tv then add it to the unplayed list else if (userData != null && !userData.Played && isPlayedTraktTv) { unPlayedEpisodes.Add(ep); } } // purely for progress reporting progPercent += percentPerItem; progress.Report(progPercent); } // send any remaining entries if (movies.Count > 0) { try { var dataContract = await _traktApi.SendLibraryUpdateAsync(movies, traktUser, cancellationToken, EventType.Add).ConfigureAwait(false); if (dataContract != null) { LogTraktResponseDataContract(dataContract); } } catch (ArgumentNullException argNullEx) { _logger.ErrorException("ArgumentNullException handled sending movies to trakt.tv", argNullEx); } catch (Exception e) { _logger.ErrorException("Exception handled sending movies to trakt.tv", e); } } if (episodes.Count > 0) { try { var dataContract = await _traktApi.SendLibraryUpdateAsync(episodes, traktUser, cancellationToken, EventType.Add).ConfigureAwait(false); if (dataContract != null) { LogTraktResponseDataContract(dataContract); } } catch (ArgumentNullException argNullEx) { _logger.ErrorException("ArgumentNullException handled sending episodes to trakt.tv", argNullEx); } catch (Exception e) { _logger.ErrorException("Exception handled sending episodes to trakt.tv", e); } } if (playedMovies.Count > 0) { try { var dataContract = await _traktApi.SendMoviePlaystateUpdates(playedMovies, traktUser, true, cancellationToken); if (dataContract != null) { LogTraktResponseDataContract(dataContract); } } catch (Exception e) { _logger.ErrorException("Error updating movie play states", e); } } if (playedEpisodes.Count > 0) { try { var dataContracts = await _traktApi.SendEpisodePlaystateUpdates(playedEpisodes, traktUser, true, cancellationToken); if (dataContracts != null) { foreach (var dataContract in dataContracts) { LogTraktResponseDataContract(dataContract); } } } catch (Exception e) { _logger.ErrorException("Error updating episode play states", e); } } if (unPlayedEpisodes.Count > 0) { try { var dataContracts = await _traktApi.SendEpisodePlaystateUpdates(unPlayedEpisodes, traktUser, false, cancellationToken); if (dataContracts != null) { foreach (var dataContract in dataContracts) { LogTraktResponseDataContract(dataContract); } } } catch (Exception e) { _logger.ErrorException("Error updating episode play states", e); } } }
public async Task Execute(CancellationToken cancellationToken, IProgress <double> progress) { var users = _userManager.Users.Where(u => { var traktUser = UserHelper.GetTraktUser(u); return(traktUser != null && traktUser.TraktLocations != null && traktUser.TraktLocations.Length > 0); }).ToList(); // No point going further if we don't have users. if (users.Count == 0) { _logger.Info("No Users returned"); return; } // purely for progress reporting var progPercent = 0.0; var percentPerUser = 100 / users.Count; foreach (var user in users) { var libraryRoot = user.RootFolder; var traktUser = UserHelper.GetTraktUser(user); // I'll leave this in here for now, but in reality this continue should never be reached. if (traktUser == null || String.IsNullOrEmpty(traktUser.LinkedMbUserId)) { _logger.Error("traktUser is either null or has no linked MB account"); continue; } /* * In order to sync watched status to trakt.tv we need to know what's been watched on Trakt already. This * will stop us from endlessly incrementing the watched values on the site. */ IEnumerable <TraktMovieDataContract> tMovies = await _traktApi.SendGetAllMoviesRequest(traktUser).ConfigureAwait(false); IEnumerable <TraktUserLibraryShowDataContract> tShowsWatched = await _traktApi.SendGetWatchedShowsRequest(traktUser).ConfigureAwait(false); var movies = new List <Movie>(); var episodes = new List <Episode>(); var playedMovies = new List <Movie>(); var playedEpisodes = new List <Episode>(); var unPlayedMovies = new List <Movie>(); var unPlayedEpisodes = new List <Episode>(); var currentSeriesId = Guid.Empty; var mediaItems = libraryRoot.GetRecursiveChildren(user) .Where(i => i.Name != null && (i is Episode && ((Episode)i).Series != null && ((Episode)i).Series.ProviderIds.ContainsKey("Tvdb")) || (i is Movie && i.ProviderIds.ContainsKey("Imdb"))) .OrderBy(i => { var episode = i as Episode; return(episode != null ? episode.Series.Id : i.Id); }) .ToList(); if (mediaItems.Count == 0) { _logger.Info("No trakt media found for '" + user.Name + "'. Have trakt locations been configured?"); continue; } // purely for progress reporting var percentPerItem = percentPerUser / (double)mediaItems.Count; foreach (var child in mediaItems) { cancellationToken.ThrowIfCancellationRequested(); if (child.Path == null || child.LocationType == LocationType.Virtual) { continue; } foreach (var s in traktUser.TraktLocations.Where(s => _fileSystem.ContainsSubPath(s, child.Path))) { if (child is Movie) { var movie = child as Movie; movies.Add(movie); var userData = _userDataManager.GetUserData(user.Id, movie.GetUserDataKey()); if (movie.ProviderIds.ContainsKey("Tmdb") && userData != null) { var traktTvMovie = tMovies.FirstOrDefault( tMovie => tMovie.TmdbId.Equals(movie.GetProviderId(MetadataProviders.Tmdb))); if (traktTvMovie != null && userData.Played && (traktTvMovie.Watched == false || traktTvMovie.Plays < userData.PlayCount)) { playedMovies.Add(movie); } else if (traktTvMovie != null && traktTvMovie.Watched && !userData.Played) { unPlayedMovies.Add(movie); } } // publish if the list hits a certain size if (movies.Count >= 120) { // Add movies to library try { var dataContract = await _traktApi.SendLibraryUpdateAsync(movies, traktUser, cancellationToken, EventType.Add).ConfigureAwait(false); if (dataContract != null) { LogTraktResponseDataContract(dataContract); } } catch (ArgumentNullException argNullEx) { _logger.ErrorException("ArgumentNullException handled sending movies to trakt.tv", argNullEx); } catch (Exception e) { _logger.ErrorException("Exception handled sending movies to trakt.tv", e); } movies.Clear(); // Mark movies seen if (playedMovies.Count > 0) { try { var dataCotract = await _traktApi.SendMoviePlaystateUpdates(playedMovies, traktUser, true, cancellationToken); if (dataCotract != null) { LogTraktResponseDataContract(dataCotract); } } catch (Exception e) { _logger.ErrorException("Error updating played state", e); } playedMovies.Clear(); } // Mark movies unseen if (unPlayedMovies.Count > 0) { try { var dataContract = await _traktApi.SendMoviePlaystateUpdates(unPlayedMovies, traktUser, false, cancellationToken); if (dataContract != null) { LogTraktResponseDataContract(dataContract); } } catch (Exception e) { _logger.ErrorException("Error updating played state", e); } unPlayedMovies.Clear(); } } } else if (child is Episode) { var ep = child as Episode; var userData = _userDataManager.GetUserData(user.Id, ep.GetUserDataKey()); var isPlayedTraktTv = false; if (ep.Series != null && ep.Series.ProviderIds.ContainsKey("Tvdb")) { var traktTvShow = tShowsWatched.FirstOrDefault( tShow => tShow.TvdbId.Equals(ep.Series.GetProviderId(MetadataProviders.Tvdb))); if (traktTvShow != null && traktTvShow.Seasons != null && traktTvShow.Seasons.Count > 0) { foreach (var episode in from season in traktTvShow.Seasons where ep.Season != null && season.Season.Equals(ep.Season.IndexNumber) && season.Episodes != null && season.Episodes.Count > 0 from episode in season.Episodes where episode.Equals(ep.IndexNumber) select episode) { isPlayedTraktTv = true; } } } if (ep.Series != null && currentSeriesId != ep.Series.Id && episodes.Count > 0) { // We're starting a new show. Finish up with the old one // Add episodes to trakt.tv library try { var dataContract = await _traktApi.SendLibraryUpdateAsync(episodes, traktUser, cancellationToken, EventType.Add).ConfigureAwait(false); if (dataContract != null) { LogTraktResponseDataContract(dataContract); } } catch (ArgumentNullException argNullEx) { _logger.ErrorException("ArgumentNullException handled sending episodes to trakt.tv", argNullEx); } catch (Exception e) { _logger.ErrorException("Exception handled sending episodes to trakt.tv", e); } // Update played state of these episodes if (playedEpisodes.Count > 0) { try { var dataContracts = await _traktApi.SendEpisodePlaystateUpdates(playedEpisodes, traktUser, true, cancellationToken); if (dataContracts != null) { foreach (var dataContract in dataContracts) { LogTraktResponseDataContract(dataContract); } } } catch (Exception e) { _logger.ErrorException("Exception handled sending played episodes to trakt.tv", e); } } if (unPlayedEpisodes.Count > 0) { try { var dataContracts = await _traktApi.SendEpisodePlaystateUpdates(unPlayedEpisodes, traktUser, false, cancellationToken); if (dataContracts != null) { foreach (var dataContract in dataContracts) { LogTraktResponseDataContract(dataContract); } } } catch (Exception e) { _logger.ErrorException("Exception handled sending played episodes to trakt.tv", e); } } episodes.Clear(); playedEpisodes.Clear(); unPlayedEpisodes.Clear(); } if (ep.Series != null) { currentSeriesId = ep.Series.Id; episodes.Add(ep); } // if the show has been played locally and is unplayed on trakt.tv then add it to the list if (userData != null && userData.Played && !isPlayedTraktTv) { playedEpisodes.Add(ep); } // If the show has not been played locally but is played on trakt.tv then add it to the unplayed list else if (userData != null && !userData.Played && isPlayedTraktTv) { unPlayedEpisodes.Add(ep); } } } // purely for progress reporting progPercent += percentPerItem; progress.Report(progPercent); } // send any remaining entries if (movies.Count > 0) { try { var dataContract = await _traktApi.SendLibraryUpdateAsync(movies, traktUser, cancellationToken, EventType.Add).ConfigureAwait(false); if (dataContract != null) { LogTraktResponseDataContract(dataContract); } } catch (ArgumentNullException argNullEx) { _logger.ErrorException("ArgumentNullException handled sending movies to trakt.tv", argNullEx); } catch (Exception e) { _logger.ErrorException("Exception handled sending movies to trakt.tv", e); } } if (episodes.Count > 0) { try { var dataContract = await _traktApi.SendLibraryUpdateAsync(episodes, traktUser, cancellationToken, EventType.Add).ConfigureAwait(false); if (dataContract != null) { LogTraktResponseDataContract(dataContract); } } catch (ArgumentNullException argNullEx) { _logger.ErrorException("ArgumentNullException handled sending episodes to trakt.tv", argNullEx); } catch (Exception e) { _logger.ErrorException("Exception handled sending episodes to trakt.tv", e); } } if (playedMovies.Count > 0) { try { var dataContract = await _traktApi.SendMoviePlaystateUpdates(playedMovies, traktUser, true, cancellationToken); if (dataContract != null) { LogTraktResponseDataContract(dataContract); } } catch (Exception e) { _logger.ErrorException("Error updating movie play states", e); } } if (playedEpisodes.Count > 0) { try { var dataContracts = await _traktApi.SendEpisodePlaystateUpdates(playedEpisodes, traktUser, true, cancellationToken); if (dataContracts != null) { foreach (var dataContract in dataContracts) { LogTraktResponseDataContract(dataContract); } } } catch (Exception e) { _logger.ErrorException("Error updating episode play states", e); } } if (unPlayedEpisodes.Count > 0) { try { var dataContracts = await _traktApi.SendEpisodePlaystateUpdates(unPlayedEpisodes, traktUser, false, cancellationToken); if (dataContracts != null) { foreach (var dataContract in dataContracts) { LogTraktResponseDataContract(dataContract); } } } catch (Exception e) { _logger.ErrorException("Error updating episode play states", e); } } } }