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); } } }
private async Task SyncTraktDataForUser(User user, double currentProgress, CancellationToken cancellationToken, IProgress <double> progress, double percentPerUser) { var libraryRoot = user.RootFolder; var traktUser = UserHelper.GetTraktUser(user); IEnumerable <TraktMovieDataContract> tMovies; IEnumerable <TraktUserLibraryShowDataContract> tShowsCollection; IEnumerable <TraktUserLibraryShowDataContract> tShowsWatched; try { /* * In order to be as accurate as possible. We need to download the users show collection & the users watched shows. * It's unfortunate that trakt.tv doesn't explicitly supply a bulk method to determine shows that have not been watched * like they do for movies. */ tMovies = await _traktApi.SendGetAllMoviesRequest(traktUser).ConfigureAwait(false); tShowsCollection = await _traktApi.SendGetCollectionShowsRequest(traktUser).ConfigureAwait(false); tShowsWatched = await _traktApi.SendGetWatchedShowsRequest(traktUser).ConfigureAwait(false); } catch (Exception ex) { _logger.ErrorException("Exception handled", ex); return; } _logger.Info("Trakt.tv Movies count = " + tMovies.Count()); _logger.Info("Trakt.tv ShowsCollection count = " + tShowsCollection.Count()); _logger.Info("Trakt.tv ShowsWatched count = " + tShowsWatched.Count()); var mediaItems = libraryRoot.GetRecursiveChildren(user) .Where(CanSync) .OrderBy(i => { var episode = i as Episode; return(episode != null ? episode.Series.Id : i.Id); }) .ToList(); // purely for progress reporting var percentPerItem = percentPerUser / mediaItems.Count; foreach (var movie in mediaItems.OfType <Movie>()) { var matchedMovie = FindMatch(movie, tMovies); if (matchedMovie != null) { var userData = _userDataManager.GetUserData(user.Id, movie.GetUserDataKey()); if (matchedMovie.Plays >= 1) { // set movie as watched userData.Played = true; userData.PlayCount = Math.Max(matchedMovie.Plays, userData.PlayCount); // keep the highest play count // Set last played to whichever is most recent, remote or local time... if (matchedMovie.LastPlayed > 0) { var tLastPlayed = matchedMovie.LastPlayed.ConvertEpochToDateTime(); userData.LastPlayedDate = tLastPlayed > userData.LastPlayedDate ? tLastPlayed : userData.LastPlayedDate; } } else { // set as unwatched userData.Played = false; userData.PlayCount = 0; userData.LastPlayedDate = null; } await _userDataManager.SaveUserData(user.Id, movie, userData, UserDataSaveReason.Import, cancellationToken); } else { _logger.Info("Failed to match " + movie.Name); } // purely for progress reporting currentProgress += percentPerItem; progress.Report(currentProgress); } foreach (var episode in mediaItems.OfType <Episode>()) { var matchedShow = FindMatch(episode.Series, tShowsCollection); if (matchedShow != null) { var matchedSeason = matchedShow.Seasons .FirstOrDefault(tSeason => tSeason.Season == (episode.ParentIndexNumber ?? -1)); // if it's not a match then it means trakt doesn't know about the episode, leave the watched state alone and move on if (matchedSeason != null && matchedSeason.Episodes.Contains(episode.IndexNumber ?? -1)) { // episode is in users libary. Now we need to determine if it's watched var userData = _userDataManager.GetUserData(user.Id, episode.GetUserDataKey()); var watchedShowMatch = FindMatch(episode.Series, tShowsWatched); var isWatched = false; if (watchedShowMatch != null) { var watchedSeasonMatch = watchedShowMatch.Seasons .FirstOrDefault(tSeason => tSeason.Season == (episode.ParentIndexNumber ?? -1)); if (watchedSeasonMatch != null) { if (watchedSeasonMatch.Episodes.Contains(episode.IndexNumber ?? -1)) { userData.Played = true; isWatched = true; } else { _logger.Debug("No Episode match in Watched shows list " + GetVerboseEpisodeData(episode)); } } else { _logger.Debug("No Season match in Watched shows list " + GetVerboseEpisodeData(episode)); } } else { _logger.Debug("No Show match in Watched shows list " + GetVerboseEpisodeData(episode)); } if (!isWatched) { userData.Played = false; userData.PlayCount = 0; userData.LastPlayedDate = null; } await _userDataManager.SaveUserData(user.Id, episode, userData, UserDataSaveReason.Import, cancellationToken); } else { _logger.Info("Failed to match episode/season numbers " + GetVerboseEpisodeData(episode)); } } else { _logger.Info("Failed to match show " + GetVerboseEpisodeData(episode)); } // purely for progress reporting currentProgress += percentPerItem; progress.Report(currentProgress); } //_logger.Info(syncItemFailures + " items not parsed"); }
private async Task SyncTraktDataForUser(User user, double currentProgress, CancellationToken cancellationToken, IProgress <double> progress, double percentPerUser) { var libraryRoot = user.RootFolder; var traktUser = UserHelper.GetTraktUser(user); IEnumerable <TraktMovieDataContract> tMovies; IEnumerable <TraktUserLibraryShowDataContract> tShowsCollection; IEnumerable <TraktUserLibraryShowDataContract> tShowsWatched; try { /* * In order to be as accurate as possible. We need to download the users show collection & the users watched shows. * It's unfortunate that trakt.tv doesn't explicitly supply a bulk method to determine shows that have not been watched * like they do for movies. */ tMovies = await _traktApi.SendGetAllMoviesRequest(traktUser).ConfigureAwait(false); tShowsCollection = await _traktApi.SendGetCollectionShowsRequest(traktUser).ConfigureAwait(false); tShowsWatched = await _traktApi.SendGetWatchedShowsRequest(traktUser).ConfigureAwait(false); } catch (Exception ex) { _logger.ErrorException("Exception handled", ex); return; } _logger.Info("tMovies count = " + tMovies.Count()); _logger.Info("tShowsCollection count = " + tShowsCollection.Count()); _logger.Info("tShowsWatched count = " + tShowsWatched.Count()); var mediaItems = libraryRoot.GetRecursiveChildren(user) .Where(i => { var movie = i as Movie; if (movie != null) { var imdbId = movie.GetProviderId(MetadataProviders.Imdb); if (string.IsNullOrEmpty(imdbId)) { return(false); } return(true); } var episode = i as Episode; if (episode != null && episode.Series != null) { var tvdbId = episode.Series.GetProviderId(MetadataProviders.Tvdb); if (string.IsNullOrEmpty(tvdbId)) { return(false); } return(true); } return(false); }) .OrderBy(i => { var episode = i as Episode; return(episode != null ? episode.Series.Id : i.Id); }) .ToList(); // purely for progress reporting var percentPerItem = percentPerUser / mediaItems.Count; // Turn off UserDataManager.UserDataSaved event listener until task completes ServerMediator.Instance.DisableUserDataSavedEventListener(); foreach (var movie in mediaItems.OfType <Movie>()) { /* * First make sure this child is in the users collection. If not, skip it. if it is in the collection then we need * to see if it's in the watched movies list. If it is, mark it watched, otherwise mark it unwatched. */ var imdbId = movie.GetProviderId(MetadataProviders.Imdb); var matchedMovie = tMovies.FirstOrDefault(i => i.ImdbId == imdbId); if (matchedMovie != null) { var userData = _userDataManager.GetUserData(user.Id, movie.GetUserDataKey()); if (matchedMovie.Plays >= 1) { // set movie as watched userData.Played = true; userData.PlayCount = Math.Max(matchedMovie.Plays, userData.PlayCount); // keep the highest play count // Set last played to whichever is most recent, remote or local time... if (matchedMovie.LastPlayed > 0) { var tLastPlayed = matchedMovie.LastPlayed.ConvertEpochToDateTime(); userData.LastPlayedDate = tLastPlayed > userData.LastPlayedDate ? tLastPlayed : userData.LastPlayedDate; } } else { // set as unwatched userData.Played = false; userData.PlayCount = 0; userData.LastPlayedDate = null; } await _userDataManager.SaveUserData(user.Id, movie, userData, UserDataSaveReason.TogglePlayed, cancellationToken); } // purely for progress reporting currentProgress += percentPerItem; progress.Report(currentProgress); } foreach (var episode in mediaItems.OfType <Episode>()) { /* * First make sure this child is in the users collection. If not, skip it. if it is in the collection then we need * to see if it's in the watched shows list. If it is, mark it watched, otherwise mark it unwatched. */ var tvdbId = episode.Series.GetProviderId(MetadataProviders.Tvdb); var matchedShow = tShowsCollection.FirstOrDefault(tShow => tShow.TvdbId == tvdbId); if (matchedShow != null) { var matchedSeason = matchedShow.Seasons.FirstOrDefault(tSeason => tSeason.Season == (episode.ParentIndexNumber ?? -1)); if (matchedSeason != null) { // if it's not a match then it means trakt doesn't know about the episode, leave the watched state alone and move on if (matchedSeason.Episodes.Contains(episode.IndexNumber ?? -1)) { // episode is in users libary. Now we need to determine if it's watched var userData = _userDataManager.GetUserData(user.Id, episode.GetUserDataKey()); var watchedShowMatch = tShowsWatched.SingleOrDefault(tShow => tShow.TvdbId == tvdbId); var isWatched = false; if (watchedShowMatch != null) { var watchedSeasonMatch = watchedShowMatch.Seasons.FirstOrDefault(tSeason => tSeason.Season == (episode.ParentIndexNumber ?? -1)); if (watchedSeasonMatch != null) { if (watchedSeasonMatch.Episodes.Contains(episode.IndexNumber ?? -1)) { userData.Played = true; isWatched = true; } } } if (!isWatched) { userData.Played = false; userData.PlayCount = 0; userData.LastPlayedDate = null; } await _userDataManager.SaveUserData(user.Id, episode, userData, UserDataSaveReason.TogglePlayed, cancellationToken); } } } // purely for progress reporting currentProgress += percentPerItem; progress.Report(currentProgress); } // Turn on UserDataManager.UserDataSaved event listener since task has completed ServerMediator.Instance.EnableUserDataSavedEventListener(); }
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); } } } }