public bool SyncSeries() { TraktLogger.Info("Series Library Starting Sync"); // store list of series ids so we can update the episode counts // of any series that syncback watched flags var seriesToUpdateEpisodeCounts = new HashSet <int>(); #region Get online data from cache #region UnWatched / Watched List <TraktCache.EpisodeWatched> traktWatchedEpisodes = null; // get all episodes on trakt that are marked as 'unseen' var traktUnWatchedEpisodes = TraktCache.GetUnWatchedEpisodesFromTrakt().ToNullableList(); if (traktUnWatchedEpisodes == null) { TraktLogger.Error("Error getting tv shows unwatched from trakt.tv server, unwatched and watched sync will be skipped"); } else { TraktLogger.Info("Found {0} unwatched tv episodes in trakt.tv library", traktUnWatchedEpisodes.Count()); // now get all episodes on trakt that are marked as 'seen' or 'watched' (this will be cached already when working out unwatched) traktWatchedEpisodes = TraktCache.GetWatchedEpisodesFromTrakt().ToNullableList(); if (traktWatchedEpisodes == null) { TraktLogger.Error("Error getting tv shows watched from trakt.tv server, watched sync will be skipped"); } else { TraktLogger.Info("Found {0} watched tv episodes in trakt.tv library", traktWatchedEpisodes.Count()); } } #endregion #region Collection // get all episodes on trakt that are marked as in 'collection' var traktCollectedEpisodes = TraktCache.GetCollectedEpisodesFromTrakt().ToNullableList(); if (traktCollectedEpisodes == null) { TraktLogger.Error("Error getting tv episode collection from trakt.tv server"); } else { TraktLogger.Info("Found {0} tv episodes in trakt.tv collection", traktCollectedEpisodes.Count()); } #endregion #region Ratings #region Episodes //var traktRatedEpisodes = TraktCache.GetRatedEpisodesFromTrakt().ToNullableList(); //if (traktRatedEpisodes == null) //{ // TraktLogger.Error("Error getting rated episodes from trakt.tv server"); //} //else //{ // TraktLogger.Info("Found {0} rated tv episodes in trakt.tv library", traktRatedEpisodes.Count()); //} #endregion #region Shows //var traktRatedShows = TraktCache.GetRatedShowsFromTrakt().ToNullableList(); //if (traktRatedShows == null) //{ // TraktLogger.Error("Error getting rated shows from trakt.tv server"); //} //else //{ // TraktLogger.Info("Found {0} rated tv shows in trakt.tv library", traktRatedShows.Count()); //} #endregion #region Seasons //var traktRatedSeasons = TraktCache.GetRatedSeasonsFromTrakt().ToNullableList(); //if (traktRatedSeasons == null) //{ // TraktLogger.Error("Error getting rated seasons from trakt.tv server"); //} //else //{ // TraktLogger.Info("Found {0} rated tv seasons in trakt.tv library", traktRatedSeasons.Count()); //} #endregion #endregion #region Watchlist #region Shows //var traktWatchlistedShows = TraktCache.GetWatchlistedShowsFromTrakt(); //if (traktWatchlistedShows == null) //{ // TraktLogger.Error("Error getting watchlisted shows from trakt.tv server"); //} //else //{ // TraktLogger.Info("Found {0} watchlisted tv shows in trakt.tv library", traktWatchlistedShows.Count()); //} #endregion #region Seasons //var traktWatchlistedSeasons = TraktCache.GetWatchlistedSeasonsFromTrakt(); //if (traktWatchlistedSeasons == null) //{ // TraktLogger.Error("Error getting watchlisted seasons from trakt.tv server"); //} //else //{ // TraktLogger.Info("Found {0} watchlisted tv seasons in trakt.tv library", traktWatchlistedSeasons.Count()); //} #endregion #region Episodes //var traktWatchlistedEpisodes = TraktCache.GetWatchlistedEpisodesFromTrakt(); //if (traktWatchlistedEpisodes == null) //{ // TraktLogger.Error("Error getting watchlisted episodes from trakt.tv server"); //} //else //{ // TraktLogger.Info("Found {0} watchlisted tv episodes in trakt.tv library", traktWatchlistedEpisodes.Count()); //} #endregion #endregion #endregion if (traktCollectedEpisodes != null) { try { TestStatus = "[Trakt.SyncSeries]"; Guid[] types = { MediaAspect.ASPECT_ID, SeriesAspect.ASPECT_ID, VideoAspect.ASPECT_ID, ImporterAspect.ASPECT_ID }; MediaItemQuery mediaItemQuery = new MediaItemQuery(types, null, null); var contentDirectory = ServiceRegistration.Get <IServerConnectionManager>().ContentDirectory; if (contentDirectory == null) { TestStatus = "[Trakt.MediaLibraryNotConnected]"; return(false); } #region Get data from local database var localEpisodes = contentDirectory.Search(mediaItemQuery, true); int episodeCount = localEpisodes.Count; TraktLogger.Info("Found {0} total episodes in local database", episodeCount); // get the episodes that we have watched var localWatchedEpisodes = localEpisodes.Where(IsWatched).ToList(); TraktLogger.Info("Found {0} episodes watched in tvseries database", localWatchedEpisodes.Count); #endregion #region Add episodes to watched history at trakt.tv int showCount = 0; int iSyncCounter = 0; if (traktWatchedEpisodes != null) { var syncWatchedShows = GetWatchedShowsForSyncEx(localWatchedEpisodes, traktWatchedEpisodes); TraktLogger.Info("Found {0} local tv show(s) with {1} watched episode(s) to add to trakt.tv watched history", syncWatchedShows.Shows.Count, syncWatchedShows.Shows.Sum(sh => sh.Seasons.Sum(se => se.Episodes.Count()))); showCount = syncWatchedShows.Shows.Count; foreach (var show in syncWatchedShows.Shows) { int showEpisodeCount = show.Seasons.Sum(s => s.Episodes.Count()); TraktLogger.Info("Adding tv show [{0}/{1}] to trakt.tv episode watched history, Episode Count = '{2}', Show Title = '{3}', Show Year = '{4}', Show TVDb ID = '{5}', Show IMDb ID = '{6}'", ++iSyncCounter, showCount, showEpisodeCount, show.Title, show.Year.HasValue ? show.Year.ToString() : "<empty>", show.Ids.Tvdb, show.Ids.Imdb ?? "<empty>"); show.Seasons.ForEach(s => s.Episodes.ForEach(e => { TraktLogger.Info("Adding episode to trakt.tv watched history, Title = '{0} - {1}x{2}', Watched At = '{3}'", show.Title, s.Number, e.Number, e.WatchedAt.ToLogString()); })); // only sync one show at a time regardless of batch size in settings var pagedShows = new List <TraktSyncShowWatchedEx>(); pagedShows.Add(show); var response = TraktAPI.AddShowsToWatchedHistoryEx(new TraktSyncShowsWatchedEx { Shows = pagedShows }); TraktLogger.LogTraktResponse <TraktSyncResponse>(response); // only add to cache if it was a success // note: we don't get back the same object type so makes it hard to figure out what failed if (response != null && response.Added != null && response.Added.Episodes == showEpisodeCount) { // update local cache TraktCache.AddEpisodesToWatchHistory(show); } } } #endregion #region Add episodes to collection at trakt.tv if (traktCollectedEpisodes != null) { var syncCollectedShows = GetCollectedShowsForSyncEx(localEpisodes, traktCollectedEpisodes); TraktLogger.Info("Found {0} local tv show(s) with {1} collected episode(s) to add to trakt.tv collection", syncCollectedShows.Shows.Count, syncCollectedShows.Shows.Sum(sh => sh.Seasons.Sum(se => se.Episodes.Count()))); iSyncCounter = 0; showCount = syncCollectedShows.Shows.Count; foreach (var show in syncCollectedShows.Shows) { int showEpisodeCount = show.Seasons.Sum(s => s.Episodes.Count()); TraktLogger.Info("Adding tv show [{0}/{1}] to trakt.tv episode collection, Episode Count = '{2}', Show Title = '{3}', Show Year = '{4}', Show TVDb ID = '{5}', Show IMDb ID = '{6}'", ++iSyncCounter, showCount, showEpisodeCount, show.Title, show.Year.HasValue ? show.Year.ToString() : "<empty>", show.Ids.Tvdb, show.Ids.Imdb ?? "<empty>"); show.Seasons.ForEach(s => s.Episodes.ForEach(e => { TraktLogger.Info("Adding episode to trakt.tv collection, Title = '{0} - {1}x{2}', Collected At = '{3}', Audio Channels = '{4}', Audio Codec = '{5}', Resolution = '{6}', Media Type = '{7}', Is 3D = '{8}'", show.Title, s.Number, e.Number, e.CollectedAt.ToLogString(), e.AudioChannels.ToLogString(), e.AudioCodec.ToLogString(), e.Resolution.ToLogString(), e.MediaType.ToLogString(), e.Is3D); })); // only sync one show at a time regardless of batch size in settings var pagedShows = new List <TraktSyncShowCollectedEx>(); pagedShows.Add(show); var response = TraktAPI.AddShowsToCollectonEx(new TraktSyncShowsCollectedEx { Shows = pagedShows }); TraktLogger.LogTraktResponse <TraktSyncResponse>(response); // only add to cache if it was a success if (response != null && response.Added != null && response.Added.Episodes == showEpisodeCount) { // update local cache TraktCache.AddEpisodesToCollection(show); } } } #endregion return(true); } catch (Exception ex) { ServiceRegistration.Get <ILogger>().Error("Trakt.tv: Exception while synchronizing media library.", ex); } } return(false); }