/// <summary> /// Count media items and call <see cref="SyncMovies"/> and <see cref="SyncShows"/> /// </summary> /// <returns></returns> private async Task SyncUserLibrary( User user, TraktUser traktUser, ISplittableProgress <double> progress, CancellationToken cancellationToken) { // purely for progress reporting var mediaItemsCount = _libraryManager.GetItemList( new InternalItemsQuery { IncludeItemTypes = new[] { typeof(Movie).Name, typeof(Episode).Name }, ExcludeLocationTypes = new[] { LocationType.Virtual } }) .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 + "'."); await SyncMovies(user, traktUser, progress.Split(2), cancellationToken); await SyncShows(user, traktUser, progress.Split(2), cancellationToken); }
/// <summary> /// Count media items and call <see cref="SyncMovies"/> and <see cref="SyncShows"/> /// </summary> /// <returns></returns> private async Task SyncUserLibrary( User user, TraktUser traktUser, ISplittableProgress <double> progress, CancellationToken cancellationToken) { await SyncMovies(user, traktUser, progress.Split(2), cancellationToken).ConfigureAwait(false); await SyncShows(user, traktUser, progress.Split(2), cancellationToken).ConfigureAwait(false); }
/// <summary> /// Sync watched and collected status of <see cref="Movie"/>s with trakt. /// </summary> private async Task SyncShows( User user, TraktUser traktUser, ISplittableProgress <double> progress, CancellationToken cancellationToken) { var traktWatchedShows = await _traktApi.SendGetWatchedShowsRequest(traktUser, cancellationToken).ConfigureAwait(false); var traktCollectedShows = await _traktApi.SendGetCollectedShowsRequest(traktUser, cancellationToken).ConfigureAwait(false); var episodeItems = _libraryManager.GetItemList( new InternalItemsQuery(user) { IncludeItemTypes = new[] { typeof(Episode).Name }, IsVirtualItem = false, OrderBy = new[] { new ValueTuple <string, SortOrder>(ItemSortBy.SeriesSortName, SortOrder.Ascending) } }) .Where(x => _traktApi.CanSync(x, traktUser)) .ToList(); var series = _libraryManager.GetItemList( new InternalItemsQuery(user) { IncludeItemTypes = new[] { typeof(Series).Name }, IsVirtualItem = false }) .Where(x => _traktApi.CanSync(x, traktUser)) .OfType <Series>() .ToList(); var collectedEpisodes = new List <Episode>(); var uncollectedShows = new List <Api.DataContracts.Sync.Collection.TraktShowCollected>(); var playedEpisodes = new List <Episode>(); var unplayedEpisodes = new List <Episode>(); var decisionProgress = progress.Split(4).Split(episodeItems.Count); foreach (var child in episodeItems) { cancellationToken.ThrowIfCancellationRequested(); var episode = child as Episode; var userData = _userDataManager.GetUserData(user, episode); var isPlayedTraktTv = false; var traktWatchedShow = Match.FindMatch(episode.Series, traktWatchedShows); if (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) { if (traktUser.PostWatchedHistory) { playedEpisodes.Add(episode); } else if (!traktUser.SkipUnwatchedImportFromTrakt) { if (userData.Played) { userData.Played = false; _userDataManager.SaveUserData( user.InternalId, episode, userData, UserDataSaveReason.Import, cancellationToken); } } } else if (userData != null && !userData.Played && isPlayedTraktTv) { // If the show has not been played locally but is played on trakt.tv then add it to the unplayed list unplayedEpisodes.Add(episode); } var traktCollectedShow = Match.FindMatch(episode.Series, traktCollectedShows); if (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)) { collectedEpisodes.Add(episode); } decisionProgress.Report(100); } // Check if we have all the collected items, add missing to uncollectedShows foreach (var traktShowCollected in traktCollectedShows) { _logger.Debug(_jsonSerializer.SerializeToString(series)); var seriesMatch = Match.FindMatch(traktShowCollected.show, series); if (seriesMatch != null) { var seriesEpisodes = episodeItems.OfType <Episode>().Where(e => e.Series.Id == seriesMatch.Id); var uncollectedSeasons = new List <TraktShowCollected.TraktSeasonCollected>(); foreach (var traktSeasonCollected in traktShowCollected.seasons) { var uncollectedEpisodes = new List <TraktEpisodeCollected>(); foreach (var traktEpisodeCollected in traktSeasonCollected.episodes) { if (seriesEpisodes.Any(e => e.ParentIndexNumber == traktSeasonCollected.number && e.IndexNumber == traktEpisodeCollected.number)) { } else { _logger.Debug("Could not match S{0}E{1} from {2} to any Emby episode, marking for collection removal", traktSeasonCollected.number, traktEpisodeCollected.number, _jsonSerializer.SerializeToString(traktShowCollected.show)); uncollectedEpisodes.Add(new TraktEpisodeCollected() { number = traktEpisodeCollected.number }); } } if (uncollectedEpisodes.Any()) { uncollectedSeasons.Add(new TraktShowCollected.TraktSeasonCollected() { number = traktSeasonCollected.number, episodes = uncollectedEpisodes }); } } if (uncollectedSeasons.Any()) { uncollectedShows.Add(new TraktShowCollected() { ids = traktShowCollected.show.ids, title = traktShowCollected.show.title, year = traktShowCollected.show.year, seasons = uncollectedSeasons }); } } else { _logger.Debug("Could not match {0} to any Emby show, marking for collection removal", _jsonSerializer.SerializeToString(traktShowCollected.show)); uncollectedShows.Add(new TraktShowCollected() { ids = traktShowCollected.show.ids, title = traktShowCollected.show.title, year = traktShowCollected.show.year }); } } if (traktUser.SyncCollection) { await SendEpisodeCollectionAdds(traktUser, collectedEpisodes, progress.Split(4), cancellationToken) .ConfigureAwait(false); await SendEpisodeCollectionRemovals(traktUser, uncollectedShows, progress.Split(5), cancellationToken) .ConfigureAwait(false); } await SendEpisodePlaystateUpdates(true, traktUser, playedEpisodes, progress.Split(4), cancellationToken).ConfigureAwait(false); await SendEpisodePlaystateUpdates(false, traktUser, unplayedEpisodes, progress.Split(4), cancellationToken).ConfigureAwait(false); }
/// <summary> /// Sync watched and collected status of <see cref="Movie"/>s with trakt. /// </summary> private async Task SyncMovies( User user, TraktUser traktUser, ISplittableProgress <double> progress, CancellationToken cancellationToken) { /* * 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, cancellationToken).ConfigureAwait(false); var traktCollectedMovies = await _traktApi.SendGetAllCollectedMoviesRequest(traktUser, cancellationToken).ConfigureAwait(false); var libraryMovies = _libraryManager.GetItemList( new InternalItemsQuery(user) { IncludeItemTypes = new[] { typeof(Movie).Name }, IsVirtualItem = false, OrderBy = new[] { new ValueTuple <string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending) } }) .Where(x => _traktApi.CanSync(x, traktUser)) .ToList(); var collectedMovies = new List <Movie>(); var uncollectedMovies = new List <TraktMovieCollected>(); var playedMovies = new List <Movie>(); var unplayedMovies = new List <Movie>(); var decisionProgress = progress.Split(4).Split(libraryMovies.Count); foreach (var child in libraryMovies) { cancellationToken.ThrowIfCancellationRequested(); var libraryMovie = child as Movie; var userData = _userDataManager.GetUserData(user, child); // if movie is not collected, or (export media info setting is enabled and every collected matching movie has different metadata), collect it var collectedMathingMovies = Match.FindMatches(libraryMovie, traktCollectedMovies).ToList(); if (!collectedMathingMovies.Any() || (traktUser.ExportMediaInfo && collectedMathingMovies.All( collectedMovie => collectedMovie.MetadataIsDifferent(libraryMovie)))) { collectedMovies.Add(libraryMovie); } var movieWatched = Match.FindMatch(libraryMovie, traktWatchedMovies); // if the movie has been played locally and is unplayed on trakt.tv then add it to the list if (userData.Played) { if (movieWatched == null) { if (traktUser.PostWatchedHistory) { playedMovies.Add(libraryMovie); } else if (!traktUser.SkipUnwatchedImportFromTrakt) { if (userData.Played) { userData.Played = false; _userDataManager.SaveUserData( user.InternalId, libraryMovie, userData, UserDataSaveReason.Import, cancellationToken); } } } } else { // If the show has not been played locally but is played on trakt.tv then add it to the unplayed list if (movieWatched != null) { unplayedMovies.Add(libraryMovie); } } decisionProgress.Report(100); } foreach (var traktCollectedMovie in traktCollectedMovies) { if (!Match.FindMatches(traktCollectedMovie, libraryMovies).Any()) { _logger.Debug("No matches for {0}, will be uncollected on Trakt", _jsonSerializer.SerializeToString(traktCollectedMovie.movie)); uncollectedMovies.Add(traktCollectedMovie); } } if (traktUser.SyncCollection) { // send movies to mark collected await SendMovieCollectionAdds(traktUser, collectedMovies, progress.Split(4), cancellationToken).ConfigureAwait(false); // send movies to mark uncollected await SendMovieCollectionRemoves(traktUser, uncollectedMovies, progress.Split(4), cancellationToken).ConfigureAwait(false); } // send movies to mark watched await SendMoviePlaystateUpdates(true, traktUser, playedMovies, progress.Split(4), cancellationToken).ConfigureAwait(false); // send movies to mark unwatched await SendMoviePlaystateUpdates(false, traktUser, unplayedMovies, progress.Split(4), cancellationToken).ConfigureAwait(false); }
/// <summary> /// Sync watched and collected status of <see cref="Movie"/>s with trakt. /// </summary> private async Task SyncShows( User user, TraktUser traktUser, ISplittableProgress <double> progress, CancellationToken cancellationToken) { var traktWatchedShows = await _traktApi.SendGetWatchedShowsRequest(traktUser).ConfigureAwait(false); var traktCollectedShows = await _traktApi.SendGetCollectedShowsRequest(traktUser).ConfigureAwait(false); var episodeItems = _libraryManager.GetItemList( new InternalItemsQuery { IncludeItemTypes = new[] { typeof(Episode).Name }, ExcludeLocationTypes = new[] { LocationType.Virtual } }) .Where(x => _traktApi.CanSync(x, traktUser)) .OrderBy(x => (x as Episode)?.SeriesName) .ToList(); var collectedEpisodes = new List <Episode>(); var playedEpisodes = new List <Episode>(); var unplayedEpisodes = new List <Episode>(); var decisionProgress = progress.Split(4).Split(episodeItems.Count); foreach (var child in episodeItems) { cancellationToken.ThrowIfCancellationRequested(); var episode = child as Episode; var userData = _userDataManager.GetUserData(user.Id, episode); var isPlayedTraktTv = false; var traktWatchedShow = SyncFromTraktTask.FindMatch(episode.Series, traktWatchedShows); if (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) { if (traktUser.PostWatchedHistory) { playedEpisodes.Add(episode); } else if (!traktUser.SkipUnwatchedImportFromTrakt) { userData.Played = false; await _userDataManager.SaveUserData( user.Id, episode, userData, UserDataSaveReason.Import, cancellationToken); } } else if (userData != null && !userData.Played && isPlayedTraktTv) { // If the show has not been played locally but is played on trakt.tv then add it to the unplayed list unplayedEpisodes.Add(episode); } var traktCollectedShow = SyncFromTraktTask.FindMatch(episode.Series, traktCollectedShows); if (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)) { collectedEpisodes.Add(episode); } decisionProgress.Report(100); } await SendEpisodeCollectionUpdates(true, traktUser, collectedEpisodes, progress.Split(4), cancellationToken); await SendEpisodePlaystateUpdates(true, traktUser, playedEpisodes, progress.Split(4), cancellationToken); await SendEpisodePlaystateUpdates(false, traktUser, unplayedEpisodes, progress.Split(4), cancellationToken); }