From eaae86da8539a486709d8ba6bc2a4a52a336d697 Mon Sep 17 00:00:00 2001 From: J2ghz Date: Mon, 12 Sep 2016 16:10:06 +0200 Subject: [PATCH 1/3] Use expression body --- Trakt/Configuration/TraktConfigurationPage.cs | 15 +++---------- Trakt/Plugin.cs | 22 +++++-------------- 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/Trakt/Configuration/TraktConfigurationPage.cs b/Trakt/Configuration/TraktConfigurationPage.cs index c9312555..a94a407e 100644 --- a/Trakt/Configuration/TraktConfigurationPage.cs +++ b/Trakt/Configuration/TraktConfigurationPage.cs @@ -13,10 +13,7 @@ class TraktConfigurationPage : IPluginConfigurationPage /// Gets the name. /// /// The name. - public string Name - { - get { return "Trakt for MediaBrowser"; } - } + public string Name => "Trakt for MediaBrowser"; /// /// Gets the HTML stream. @@ -31,14 +28,8 @@ public Stream GetHtmlStream() /// Gets the type of the configuration page. /// /// The type of the configuration page. - public ConfigurationPageType ConfigurationPageType - { - get { return ConfigurationPageType.PluginConfiguration; } - } + public ConfigurationPageType ConfigurationPageType => ConfigurationPageType.PluginConfiguration; - public IPlugin Plugin - { - get { return Trakt.Plugin.Instance; } - } + public IPlugin Plugin => Trakt.Plugin.Instance; } } diff --git a/Trakt/Plugin.cs b/Trakt/Plugin.cs index d3e05ef1..f3b204be 100644 --- a/Trakt/Plugin.cs +++ b/Trakt/Plugin.cs @@ -8,7 +8,7 @@ namespace Trakt { public class Plugin : BasePlugin { - public SemaphoreSlim TraktResourcePool = new SemaphoreSlim(2,2); + public SemaphoreSlim TraktResourcePool = new SemaphoreSlim(2, 2); public Plugin(IApplicationPaths appPaths, IXmlSerializer xmlSerializer) : base(appPaths, xmlSerializer) @@ -16,26 +16,14 @@ public Plugin(IApplicationPaths appPaths, IXmlSerializer xmlSerializer) Instance = this; } - public override string Name - { - get { return "Trakt"; } - } - + public override string Name => "Trakt"; public override string Description - { - get - { - return "Watch, rate and discover media using Trakt. The htpc just got more social"; - } - } + => "Watch, rate and discover media using Trakt. The htpc just got more social"; public static Plugin Instance { get; private set; } - - public PluginConfiguration PluginConfiguration - { - get { return Configuration; } - } + + public PluginConfiguration PluginConfiguration => Configuration; } } From 66dce97b8c7410ae28d26d4bb598c85bfa228a74 Mon Sep 17 00:00:00 2001 From: J2ghz Date: Mon, 12 Sep 2016 20:06:48 +0200 Subject: [PATCH 2/3] Clean up and split library syncing task --- Trakt/Api/TraktApi.cs | 13 + Trakt/ScheduledTasks/SyncFromTraktTask.cs | 15 +- Trakt/ScheduledTasks/SyncLibraryTask.cs | 354 ++++++++++++---------- 3 files changed, 217 insertions(+), 165 deletions(-) diff --git a/Trakt/Api/TraktApi.cs b/Trakt/Api/TraktApi.cs index f3a4de2e..3babe34e 100644 --- a/Trakt/Api/TraktApi.cs +++ b/Trakt/Api/TraktApi.cs @@ -53,6 +53,18 @@ public TraktApi(IJsonSerializer jsonSerializer, ILogger logger, IHttpClient http _logger = logger; } + /// + /// Checks whether it's possible/allowed to sync a for a . + /// + /// + /// Item to check. + /// + /// + /// The trakt user to check for. + /// + /// + /// indicates if it's possible/allowed to sync this item. + /// public bool CanSync(BaseItem item, TraktUser traktUser) { if (item.Path == null || item.LocationType == LocationType.Virtual) @@ -85,6 +97,7 @@ public bool CanSync(BaseItem item, TraktUser traktUser) return false; } + /// /// Report to trakt.tv that a movie is being watched, or has been watched. /// diff --git a/Trakt/ScheduledTasks/SyncFromTraktTask.cs b/Trakt/ScheduledTasks/SyncFromTraktTask.cs index 5edbb183..a80992c9 100644 --- a/Trakt/ScheduledTasks/SyncFromTraktTask.cs +++ b/Trakt/ScheduledTasks/SyncFromTraktTask.cs @@ -370,25 +370,16 @@ public IEnumerable GetDefaultTriggers() /// /// /// - public string Name - { - get { return "Import playstates from Trakt.tv"; } - } + public string Name => "Import playstates from Trakt.tv"; /// /// /// - public string Description - { - get { return "Sync Watched/Unwatched status from Trakt.tv for each MB3 user that has a configured Trakt account"; } - } + public string Description => "Sync Watched/Unwatched status from Trakt.tv for each MB3 user that has a configured Trakt account"; /// /// /// - public string Category - { - get { return "Trakt"; } - } + public string Category => "Trakt"; } } \ No newline at end of file diff --git a/Trakt/ScheduledTasks/SyncLibraryTask.cs b/Trakt/ScheduledTasks/SyncLibraryTask.cs index 2a774d9d..978bfbb5 100644 --- a/Trakt/ScheduledTasks/SyncLibraryTask.cs +++ b/Trakt/ScheduledTasks/SyncLibraryTask.cs @@ -1,27 +1,29 @@ -using MediaBrowser.Common.IO; -using MediaBrowser.Common.Net; -using MediaBrowser.Common.ScheduledTasks; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Serialization; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using CommonIO; -using MediaBrowser.Model.Entities; -using Trakt.Api; -using Trakt.Api.DataContracts.Sync; -using Trakt.Helpers; -using Trakt.Model; - -namespace Trakt.ScheduledTasks +namespace Trakt.ScheduledTasks { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading; + using System.Threading.Tasks; + + using CommonIO; + + using MediaBrowser.Common.Net; + using MediaBrowser.Common.ScheduledTasks; + using MediaBrowser.Controller; + using MediaBrowser.Controller.Entities; + using MediaBrowser.Controller.Entities.Movies; + using MediaBrowser.Controller.Entities.TV; + using MediaBrowser.Controller.Library; + using MediaBrowser.Model.Entities; + using MediaBrowser.Model.Logging; + using MediaBrowser.Model.Serialization; + + using Trakt.Api; + using Trakt.Api.DataContracts.Sync; + using Trakt.Helpers; + using Trakt.Model; + /// /// Task that will Sync each users local library with their respective trakt.tv profiles. This task will only include /// titles, watched states will be synced in other tasks. @@ -53,13 +55,7 @@ public IEnumerable GetDefaultTriggers() public async Task Execute(CancellationToken cancellationToken, IProgress progress) { - var users = _userManager.Users.Where(u => - { - var traktUser = UserHelper.GetTraktUser(u); - - return traktUser != null; - - }).ToList(); + var users = _userManager.Users.Where(u => UserHelper.GetTraktUser(u) != null).ToList(); // No point going further if we don't have users. if (users.Count == 0) @@ -77,7 +73,7 @@ public async Task Execute(CancellationToken cancellationToken, IProgress 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)) + if (string.IsNullOrEmpty(traktUser?.LinkedMbUserId)) { _logger.Error("traktUser is either null or has no linked MB account"); continue; @@ -90,61 +86,105 @@ await SyncUserLibrary(user, traktUser, progPercent, percentPerUser, progress, ca } } - private async Task SyncUserLibrary(User user, + private async Task SyncUserLibrary( + User user, TraktUser traktUser, double progPercent, double percentPerUser, IProgress progress, CancellationToken cancellationToken) { - var libraryRoot = user.RootFolder; // 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)); + }) + .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; + var percentPerItem = (float)percentPerUser / mediaItemsCount / 2.0; + + await SyncMovies(user, traktUser, progress, progPercent, percentPerItem, cancellationToken); + await SyncShows(user, traktUser, progress, progPercent, percentPerItem, cancellationToken); + } + + /// + /// Sync watched and collected status of s with trakt. + /// + /// + /// to get (e.g. watched status) from. + /// + /// + /// The to sync with. + /// + /// + /// Progress reporter. + /// + /// + /// Initial progress value. + /// + /// + /// Progress percent per item. + /// + /// + /// The cancellation token. + /// + /// + /// Awaitable . + /// + private async Task SyncMovies( + User user, + TraktUser traktUser, + IProgress progress, + double progPercent, + double percentPerItem, + 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).ConfigureAwait(false); var traktCollectedMovies = await _traktApi.SendGetAllCollectedMoviesRequest(traktUser).ConfigureAwait(false); - var movieItems = _libraryManager.GetItemList(new InternalItemsQuery - { - IncludeItemTypes = new[] { typeof(Movie).Name }, - ExcludeLocationTypes = new[] { LocationType.Virtual } - }) - .Where(x => _traktApi.CanSync(x, traktUser)) - .OrderBy(x => x.Name) - .ToList(); - var movies = new List(); + var libraryMovies = + _libraryManager.GetItemList( + new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(Movie).Name }, + ExcludeLocationTypes = new[] { LocationType.Virtual } + }) + .Where(x => _traktApi.CanSync(x, traktUser)) + .OrderBy(x => x.Name) + .ToList(); + var collectedMovies = new List(); var playedMovies = new List(); - var unPlayedMovies = new List(); + var unplayedMovies = new List(); - foreach (var child in movieItems) + foreach (var child in libraryMovies) { cancellationToken.ThrowIfCancellationRequested(); - var movie = child as Movie; + var libraryMovie = child as Movie; var userData = _userDataManager.GetUserData(user.Id, child); - - var collectedMovies = SyncFromTraktTask.FindMatches(movie, traktCollectedMovies).ToList(); - if (!collectedMovies.Any() || (traktUser.ExportMediaInfo && collectedMovies.All(collectedMovie => collectedMovie.MetadataIsDifferent(movie)))) + + // if movie is not collected, or (export media info setting is enabled and every collected matching movie has different metadata), collect it + var collectedMathingMovies = SyncFromTraktTask.FindMatches(libraryMovie, traktCollectedMovies).ToList(); + if (!collectedMathingMovies.Any() + || (traktUser.ExportMediaInfo + && collectedMathingMovies.All(collectedMovie => collectedMovie.MetadataIsDifferent(libraryMovie)))) { - movies.Add(movie); + collectedMovies.Add(libraryMovie); } - var movieWatched = SyncFromTraktTask.FindMatch(movie, traktWatchedMovies); + var movieWatched = SyncFromTraktTask.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) { @@ -152,37 +192,62 @@ private async Task SyncUserLibrary(User user, { if (traktUser.PostWatchedHistory) { - playedMovies.Add(movie); + playedMovies.Add(libraryMovie); } else { userData.Played = false; - await _userDataManager.SaveUserData(user.Id, movie, userData, UserDataSaveReason.Import, - cancellationToken); + await + _userDataManager.SaveUserData( + user.Id, + libraryMovie, + userData, + UserDataSaveReason.Import, + cancellationToken); } } } - // If the show has not been played locally but is played on trakt.tv then add it to the unplayed list 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(movie); + unplayedMovies.Add(libraryMovie); } } + // purely for progress reporting progPercent += percentPerItem; progress.Report(progPercent); } - _logger.Info("Movies to add to Collection: " + movies.Count); - // send any remaining entries + + // send movies to mark collected + await SendMovieCollectionUpdates(true, traktUser, collectedMovies, progress, progPercent, percentPerItem, cancellationToken); + + // send movies to mark watched + await SendMoviePlaystateUpdates(true, traktUser, playedMovies, progress, progPercent, percentPerItem, cancellationToken); + + // send movies to mark unwatched + await SendMoviePlaystateUpdates(false, traktUser, unplayedMovies, progress, progPercent, percentPerItem, cancellationToken); + } + + private async Task SendMovieCollectionUpdates( + bool collected, + TraktUser traktUser, + List movies, + IProgress progress, + double progPercent, + double percentPerItem, + CancellationToken cancellationToken) + { + _logger.Info("Movies to " + (collected ? "add to" : "remove from") + " Collection: " + movies.Count); if (movies.Count > 0) { try { var dataContracts = await - _traktApi.SendLibraryUpdateAsync(movies, traktUser, cancellationToken, EventType.Add) + _traktApi.SendLibraryUpdateAsync(movies, traktUser, cancellationToken, collected ? EventType.Add : EventType.Remove) .ConfigureAwait(false); if (dataContracts != null) { @@ -200,18 +265,29 @@ await _userDataManager.SaveUserData(user.Id, movie, userData, UserDataSaveReason { _logger.ErrorException("Exception handled sending movies to trakt.tv", e); } + // purely for progress reporting - progPercent += (percentPerItem*movies.Count); + progPercent += percentPerItem * movies.Count; progress.Report(progPercent); } + } - _logger.Info("Movies to set watched: " + playedMovies.Count); + private async Task SendMoviePlaystateUpdates( + bool seen, + TraktUser traktUser, + List playedMovies, + IProgress progress, + double progPercent, + double percentPerItem, + CancellationToken cancellationToken) + { + _logger.Info("Movies to set " + (seen ? string.Empty : "un") + "watched: " + playedMovies.Count); if (playedMovies.Count > 0) { try { var dataContracts = - await _traktApi.SendMoviePlaystateUpdates(playedMovies, traktUser, true, cancellationToken); + await _traktApi.SendMoviePlaystateUpdates(playedMovies, traktUser, seen, cancellationToken); if (dataContracts != null) { foreach (var traktSyncResponse in dataContracts) @@ -224,49 +300,37 @@ await _userDataManager.SaveUserData(user.Id, movie, userData, UserDataSaveReason { _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); + progPercent += percentPerItem * playedMovies.Count; progress.Report(progPercent); } + } + private async Task SyncShows( + User user, + TraktUser traktUser, + IProgress progress, + double progPercent, + double percentPerItem, + 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 is Episode ? (x as Episode).SeriesName : null) - .ToList(); - - var episodes = new List(); + 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(); var playedEpisodes = new List(); - var unPlayedEpisodes = new List(); + var unplayedEpisodes = new List(); foreach (var child in episodeItems) { @@ -276,14 +340,13 @@ await _userDataManager.SaveUserData(user.Id, movie, userData, UserDataSaveReason var isPlayedTraktTv = false; var traktWatchedShow = SyncFromTraktTask.FindMatch(episode.Series, traktWatchedShows); - if (traktWatchedShow != null && traktWatchedShow.Seasons != null && traktWatchedShow.Seasons.Count > 0) + 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)); + 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 @@ -296,23 +359,28 @@ await _userDataManager.SaveUserData(user.Id, movie, userData, UserDataSaveReason else { userData.Played = false; - await _userDataManager.SaveUserData(user.Id, episode, userData, UserDataSaveReason.Import, + await + _userDataManager.SaveUserData( + user.Id, + episode, + userData, + UserDataSaveReason.Import, cancellationToken); } } - // 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); + // 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 == null || - traktCollectedShow.Seasons == null || - traktCollectedShow.Seasons.All(x => x.Number != episode.ParentIndexNumber) || - traktCollectedShow.Seasons.First(x => x.Number == episode.ParentIndexNumber) + 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)) { - episodes.Add(episode); + collectedEpisodes.Add(episode); } // purely for progress reporting @@ -320,15 +388,14 @@ await _userDataManager.SaveUserData(user.Id, episode, userData, UserDataSaveReas progress.Report(progPercent); } - - _logger.Info("Episodes to add to Collection: " + episodes.Count); - if (episodes.Count > 0) + _logger.Info("Episodes to add to Collection: " + collectedEpisodes.Count); + if (collectedEpisodes.Count > 0) { try { var dataContracts = await - _traktApi.SendLibraryUpdateAsync(episodes, traktUser, cancellationToken, EventType.Add) + _traktApi.SendLibraryUpdateAsync(collectedEpisodes, traktUser, cancellationToken, EventType.Add) .ConfigureAwait(false); if (dataContracts != null) { @@ -346,8 +413,9 @@ await _userDataManager.SaveUserData(user.Id, episode, userData, UserDataSaveReas { _logger.ErrorException("Exception handled sending episodes to trakt.tv", e); } + // purely for progress reporting - progPercent += (percentPerItem*episodes.Count); + progPercent += percentPerItem * collectedEpisodes.Count; progress.Report(progPercent); } @@ -358,67 +426,44 @@ await _userDataManager.SaveUserData(user.Id, episode, userData, UserDataSaveReas { var dataContracts = await _traktApi.SendEpisodePlaystateUpdates(playedEpisodes, traktUser, true, cancellationToken); - if (dataContracts != null) - { - foreach (var traktSyncResponse in dataContracts) - LogTraktResponseDataContract(traktSyncResponse); - } + dataContracts?.ForEach(LogTraktResponseDataContract); } catch (Exception e) { _logger.ErrorException("Error updating episode play states", e); } + // purely for progress reporting - progPercent += (percentPerItem*playedEpisodes.Count); + progPercent += percentPerItem * playedEpisodes.Count; progress.Report(progPercent); } - _logger.Info("Episodes to set unwatched: " + unPlayedEpisodes.Count); - if (unPlayedEpisodes.Count > 0) + + _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); - } - } + _traktApi.SendEpisodePlaystateUpdates(unplayedEpisodes, traktUser, false, cancellationToken); + dataContracts?.ForEach(LogTraktResponseDataContract); } catch (Exception e) { _logger.ErrorException("Error updating episode play states", e); } + // purely for progress reporting - progPercent += (percentPerItem*unPlayedEpisodes.Count); + progPercent += percentPerItem * unplayedEpisodes.Count; progress.Report(progPercent); } } + + public string Name => "Sync library to trakt.tv"; - public string Name - { - get { return "Sync library to trakt.tv"; } - } - - public string Category - { - get - { - return "Trakt"; - } - } + public string Category => "Trakt"; - public string Description - { - get - { - return - "Adds any media that is in each users trakt monitored locations to their trakt.tv profile"; - } - } + public string Description => "Adds any media that is in each users trakt monitored locations to their trakt.tv profile"; private void LogTraktResponseDataContract(TraktSyncResponse dataContract) { @@ -430,14 +475,17 @@ private void LogTraktResponseDataContract(TraktSyncResponse dataContract) { _logger.Error("TraktResponse not Found:" + _jsonSerializer.SerializeToString(traktMovie)); } + foreach (var traktShow in dataContract.NotFound.Shows) { _logger.Error("TraktResponse not Found:" + _jsonSerializer.SerializeToString(traktShow)); } + foreach (var traktSeason in dataContract.NotFound.Seasons) { _logger.Error("TraktResponse not Found:" + _jsonSerializer.SerializeToString(traktSeason)); } + foreach (var traktEpisode in dataContract.NotFound.Episodes) { _logger.Error("TraktResponse not Found:" + _jsonSerializer.SerializeToString(traktEpisode)); From 30a595bc6f74250e187a312a27ce41f4a4f407a1 Mon Sep 17 00:00:00 2001 From: J2ghz Date: Sun, 2 Oct 2016 13:04:45 +0200 Subject: [PATCH 3/3] Cleanup and split SyncShows --- Trakt/ScheduledTasks/SyncFromTraktTask.cs | 117 ++++++++++++---------- Trakt/ScheduledTasks/SyncLibraryTask.cs | 82 ++++++++------- 2 files changed, 110 insertions(+), 89 deletions(-) diff --git a/Trakt/ScheduledTasks/SyncFromTraktTask.cs b/Trakt/ScheduledTasks/SyncFromTraktTask.cs index a80992c9..b1854af5 100644 --- a/Trakt/ScheduledTasks/SyncFromTraktTask.cs +++ b/Trakt/ScheduledTasks/SyncFromTraktTask.cs @@ -1,30 +1,30 @@ -using System.Globalization; -using MediaBrowser.Common.IO; -using MediaBrowser.Common.Net; -using MediaBrowser.Common.ScheduledTasks; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Serialization; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using CommonIO; -using Trakt.Api; -using Trakt.Api.DataContracts.BaseModel; -using Trakt.Api.DataContracts.Users.Collection; -using Trakt.Api.DataContracts.Users.Watched; -using Trakt.Helpers; -using Trakt.Model; - -namespace Trakt.ScheduledTasks +namespace Trakt.ScheduledTasks { + using System; + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + using System.Threading; + using System.Threading.Tasks; + + using CommonIO; + + using MediaBrowser.Common.Net; + using MediaBrowser.Common.ScheduledTasks; + using MediaBrowser.Controller; + using MediaBrowser.Controller.Entities; + using MediaBrowser.Controller.Entities.Movies; + using MediaBrowser.Controller.Entities.TV; + using MediaBrowser.Controller.Library; + using MediaBrowser.Model.Entities; + using MediaBrowser.Model.Logging; + using MediaBrowser.Model.Serialization; + + using Trakt.Api; + using Trakt.Api.DataContracts.BaseModel; + using Trakt.Api.DataContracts.Users.Collection; + using Trakt.Api.DataContracts.Users.Watched; + using Trakt.Helpers; /// /// Task that will Sync each users trakt.tv profile with their local library. This task will only include @@ -120,24 +120,24 @@ private async Task SyncTraktDataForUser(User user, double currentProgress, Cance throw; } - _logger.Info("Trakt.tv watched Movies count = " + traktWatchedMovies.Count()); _logger.Info("Trakt.tv watched Shows count = " + traktWatchedShows.Count()); + var mediaItems = + _libraryManager.GetItemList( + new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(Movie).Name, typeof(Episode).Name }, + ExcludeLocationTypes = new[] { LocationType.Virtual } + }) + .Where(i => _traktApi.CanSync(i, traktUser)) + .OrderBy( + i => + { + var episode = i as Episode; - var mediaItems = _libraryManager.GetItemList(new InternalItemsQuery - { - IncludeItemTypes = new[] { typeof(Movie).Name, typeof(Episode).Name }, - ExcludeLocationTypes = new[] { LocationType.Virtual } - }) - .Where(i => _traktApi.CanSync(i, traktUser)) - .OrderBy(i => - { - var episode = i as Episode; - - return episode != null ? episode.Series.Id : i.Id; - }) - .ToList(); + return episode != null ? episode.Series.Id : i.Id; + }).ToList(); // purely for progress reporting var percentPerItem = percentPerUser / mediaItems.Count; @@ -164,6 +164,7 @@ private async Task SyncTraktDataForUser(User user, double currentProgress, Cance // keep the highest play count int playcount = Math.Max(matchedMovie.Plays, userData.PlayCount); + // set movie playcount if (userData.PlayCount != playcount) { @@ -175,9 +176,7 @@ private async Task SyncTraktDataForUser(User user, double currentProgress, Cance if (!string.IsNullOrEmpty(matchedMovie.LastWatchedAt)) { var tLastPlayed = DateTime.Parse(matchedMovie.LastWatchedAt); - var latestPlayed = tLastPlayed > userData.LastPlayedDate - ? tLastPlayed - : userData.LastPlayedDate; + var latestPlayed = tLastPlayed > userData.LastPlayedDate ? tLastPlayed : userData.LastPlayedDate; if (userData.LastPlayedDate != latestPlayed) { userData.LastPlayedDate = latestPlayed; @@ -189,7 +188,11 @@ private async Task SyncTraktDataForUser(User user, double currentProgress, Cance if (changed) { await - _userDataManager.SaveUserData(user.Id, movie, userData, UserDataSaveReason.Import, + _userDataManager.SaveUserData( + user.Id, + movie, + userData, + UserDataSaveReason.Import, cancellationToken); } } @@ -210,8 +213,13 @@ private async Task SyncTraktDataForUser(User user, double currentProgress, Cance if (matchedShow != null) { - var matchedSeason = matchedShow.Seasons - .FirstOrDefault(tSeason => tSeason.Number == (episode.ParentIndexNumber == 0 ? 0 : ((episode.ParentIndexNumber ?? 1) + (episode.Series.AnimeSeriesIndex ?? 1) - 1))); + var matchedSeason = + matchedShow.Seasons.FirstOrDefault( + tSeason => + tSeason.Number + == (episode.ParentIndexNumber == 0 + ? 0 + : ((episode.ParentIndexNumber ?? 1) + (episode.Series.AnimeSeriesIndex ?? 1) - 1))); // if it's not a match then it means trakt doesn't know about the season, leave the watched state alone and move on if (matchedSeason != null) @@ -220,7 +228,8 @@ private async Task SyncTraktDataForUser(User user, double currentProgress, Cance var userData = _userDataManager.GetUserData(user.Id, episode); bool changed = false; - var matchedEpisode = matchedSeason.Episodes.FirstOrDefault(x => x.Number == (episode.IndexNumber ?? -1)); + var matchedEpisode = + matchedSeason.Episodes.FirstOrDefault(x => x.Number == (episode.IndexNumber ?? -1)); if (matchedEpisode != null) { @@ -236,6 +245,7 @@ private async Task SyncTraktDataForUser(User user, double currentProgress, Cance // keep the highest play count int playcount = Math.Max(matchedEpisode.Plays, userData.PlayCount); + // set episode playcount if (userData.PlayCount != playcount) { @@ -255,7 +265,11 @@ private async Task SyncTraktDataForUser(User user, double currentProgress, Cance if (changed) { await - _userDataManager.SaveUserData(user.Id, episode, userData, UserDataSaveReason.Import, + _userDataManager.SaveUserData( + user.Id, + episode, + userData, + UserDataSaveReason.Import, cancellationToken); } } @@ -273,17 +287,18 @@ private async Task SyncTraktDataForUser(User user, double currentProgress, Cance currentProgress += percentPerItem; progress.Report(currentProgress); } - //_logger.Info(syncItemFailures + " items not parsed"); + + // _logger.Info(syncItemFailures + " items not parsed"); } private string GetVerboseEpisodeData(Episode episode) { - string episodeString = ""; + string episodeString = string.Empty; episodeString += "Episode: " + (episode.ParentIndexNumber != null ? episode.ParentIndexNumber.ToString() : "null"); episodeString += "x" + (episode.IndexNumber != null ? episode.IndexNumber.ToString() : "null"); episodeString += " '" + episode.Name + "' "; episodeString += "Series: '" + (episode.Series != null - ? !String.IsNullOrWhiteSpace(episode.Series.Name) + ? !string.IsNullOrWhiteSpace(episode.Series.Name) ? episode.Series.Name : "null property" : "null class"); diff --git a/Trakt/ScheduledTasks/SyncLibraryTask.cs b/Trakt/ScheduledTasks/SyncLibraryTask.cs index 978bfbb5..1c7912df 100644 --- a/Trakt/ScheduledTasks/SyncLibraryTask.cs +++ b/Trakt/ScheduledTasks/SyncLibraryTask.cs @@ -388,44 +388,29 @@ private async Task SyncShows( progress.Report(progPercent); } - _logger.Info("Episodes to add to Collection: " + collectedEpisodes.Count); - if (collectedEpisodes.Count > 0) - { - try - { - var dataContracts = - await - _traktApi.SendLibraryUpdateAsync(collectedEpisodes, 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); - } + await SendEpisodeCollectionUpdates(true, traktUser, collectedEpisodes, progress, progPercent, percentPerItem, cancellationToken); - // purely for progress reporting - progPercent += percentPerItem * collectedEpisodes.Count; - progress.Report(progPercent); - } + await SendEpisodePlaystateUpdates(true, traktUser, playedEpisodes, progress, progPercent, percentPerItem, cancellationToken); - _logger.Info("Episodes to set watched: " + playedEpisodes.Count); + await SendEpisodePlaystateUpdates(false, traktUser, unplayedEpisodes, progress, progPercent, percentPerItem, cancellationToken); + } + + private async Task SendEpisodePlaystateUpdates( + bool seen, + TraktUser traktUser, + List playedEpisodes, + IProgress progress, + double progPercent, + double percentPerItem, + 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, true, cancellationToken); + await _traktApi.SendEpisodePlaystateUpdates(playedEpisodes, traktUser, seen, cancellationToken); dataContracts?.ForEach(LogTraktResponseDataContract); } catch (Exception e) @@ -437,28 +422,49 @@ private async Task SyncShows( progPercent += percentPerItem * playedEpisodes.Count; progress.Report(progPercent); } + } - _logger.Info("Episodes to set unwatched: " + unplayedEpisodes.Count); - if (unplayedEpisodes.Count > 0) + private async Task SendEpisodeCollectionUpdates( + bool collected, + TraktUser traktUser, + List collectedEpisodes, + IProgress progress, + double progPercent, + double percentPerItem, + CancellationToken cancellationToken) + { + _logger.Info("Episodes to add to Collection: " + collectedEpisodes.Count); + if (collectedEpisodes.Count > 0) { try { var dataContracts = await - _traktApi.SendEpisodePlaystateUpdates(unplayedEpisodes, traktUser, false, cancellationToken); - dataContracts?.ForEach(LogTraktResponseDataContract); + _traktApi.SendLibraryUpdateAsync(collectedEpisodes, traktUser, cancellationToken, collected ? EventType.Add : EventType.Remove) + .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("Error updating episode play states", e); + _logger.ErrorException("Exception handled sending episodes to trakt.tv", e); } // purely for progress reporting - progPercent += percentPerItem * unplayedEpisodes.Count; + progPercent += percentPerItem * collectedEpisodes.Count; progress.Report(progPercent); } } - + public string Name => "Sync library to trakt.tv"; public string Category => "Trakt";