private static EpisodeSyncDetails ReconSyncTraktEpisode(AnimeSeries ser, AnimeEpisode ep, TraktSummaryContainer traktSummary, List<JMMUser> traktUsers, List<TraktV2ShowCollectedResult> collected, List<TraktV2ShowWatchedResult> watched, bool sendNow) { try { // get the Trakt Show ID for this episode string traktShowID = string.Empty; int season = -1; int epNumber = -1; GetTraktEpisodeIdV2(ep, ref traktShowID, ref season, ref epNumber); if (string.IsNullOrEmpty(traktShowID) || season < 0 || epNumber < 0) return null; // get the current collected records for this series on Trakt TraktV2CollectedEpisode epTraktCol = null; TraktV2ShowCollectedResult col = collected.FirstOrDefault(x => x.show.ids.slug == traktShowID); if (col != null) { TraktV2CollectedSeason sea = col.seasons.FirstOrDefault(x => x.number == season); if (sea != null) { epTraktCol = sea.episodes.FirstOrDefault(x => x.number == epNumber); } } bool onlineCollection = epTraktCol != null; // get the current watched records for this series on Trakt TraktV2WatchedEpisode epTraktWatched = null; TraktV2ShowWatchedResult wtc = watched.FirstOrDefault(x => x.show.ids.slug == traktShowID); if (wtc != null) { TraktV2WatchedSeason sea = wtc.seasons.FirstOrDefault(x => x.number == season); if (sea != null) { epTraktWatched = sea.episodes.FirstOrDefault(x => x.number == epNumber); } } bool onlineWatched = epTraktWatched != null; bool localCollection = false; bool localWatched = false; if (ep.GetVideoLocals().Count > 0) { // let's check if this episode has a user record against it // if it does, it means a user has watched it localCollection = true; AnimeEpisode_User userRecord = null; foreach (JMMUser juser in traktUsers) { userRecord = ep.GetUserRecord(juser.JMMUserID); if (userRecord != null) break; } if (userRecord != null) localWatched = true; } string msg1 = string.Format("Sync Check Status: AniDB: {0} - {1} - {2} - Collection: {3} - Watched: {4}", ser.AniDB_ID, ep.EpisodeTypeEnum, ep.AniDB_EpisodeID, localCollection, localWatched); string msg2 = string.Format("Sync Check Status: Trakt: {0} - S:{1} - EP:{2} - Collection: {3} - Watched: {4}", traktShowID, season, epNumber, onlineCollection, onlineWatched); logger.Trace(msg1); logger.Trace(msg2); // sync the collection status if (localCollection) { // is in the local collection, but not Trakt, so let's ADD it if (!onlineCollection) { string msg = string.Format("SYNC LOCAL: Adding to Trakt Collection: Slug: {0} - S:{1} - EP:{2}", traktShowID, season, epNumber); logger.Trace(msg); DateTime epDate = GetEpisodeDateForSync(ep, TraktSyncType.CollectionAdd); if (sendNow) SyncEpisodeToTrakt(TraktSyncType.CollectionAdd, traktShowID, season, epNumber, epDate, false); else return new EpisodeSyncDetails(TraktSyncType.CollectionAdd, traktShowID, season, epNumber, epDate); } } else { // is in the trakt collection, but not local, so let's REMOVE it if (onlineCollection) { string msg = string.Format("SYNC LOCAL: Removing from Trakt Collection: Slug: {0} - S:{1} - EP:{2}", traktShowID, season, epNumber); logger.Trace(msg); DateTime epDate = GetEpisodeDateForSync(ep, TraktSyncType.CollectionRemove); if (sendNow) SyncEpisodeToTrakt(TraktSyncType.CollectionRemove, traktShowID, season, epNumber, epDate, false); else return new EpisodeSyncDetails(TraktSyncType.CollectionRemove, traktShowID, season, epNumber, epDate); } } // sync the watched status if (localWatched) { // is watched locally, but not Trakt, so let's ADD it if (!onlineWatched) { string msg = string.Format("SYNC LOCAL: Adding to Trakt History: Slug: {0} - S:{1} - EP:{2}", traktShowID, season, epNumber); logger.Trace(msg); DateTime epDate = GetEpisodeDateForSync(ep, TraktSyncType.HistoryAdd); if (sendNow) SyncEpisodeToTrakt(TraktSyncType.HistoryAdd, traktShowID, season, epNumber, epDate, false); else return new EpisodeSyncDetails(TraktSyncType.HistoryAdd, traktShowID, season, epNumber, epDate); } } else { // is watched on trakt, but not locally, so let's REMOVE it if (onlineWatched) { string msg = string.Format("SYNC LOCAL: Removing from Trakt History: Slug: {0} - S:{1} - EP:{2}", traktShowID, season, epNumber); logger.Trace(msg); DateTime epDate = GetEpisodeDateForSync(ep, TraktSyncType.HistoryRemove); if (sendNow) SyncEpisodeToTrakt(TraktSyncType.HistoryRemove, traktShowID, season, epNumber, epDate, false); else return new EpisodeSyncDetails(TraktSyncType.HistoryRemove, traktShowID, season, epNumber, epDate); } } return null; } catch (Exception ex) { logger.ErrorException("Error in TraktTVHelper.SyncTraktEpisode: " + ex.ToString(), ex); return null; } }
private static int? GetTraktEpisodeIdV2(TraktSummaryContainer traktSummary, AniDB_Anime anime, AniDB_Episode ep, ref string traktID, ref int season, ref int epNumber) { try { int? traktEpId = null; #region normal episodes // now do stuff to improve performance if (ep.EpisodeTypeEnum == enEpisodeType.Episode) { if (traktSummary != null && traktSummary.CrossRefTraktV2 != null && traktSummary.CrossRefTraktV2.Count > 0) { // find the xref that is right // relies on the xref's being sorted by season number and then episode number (desc) List<SortPropOrFieldAndDirection> sortCriteria = new List<SortPropOrFieldAndDirection>(); sortCriteria.Add(new SortPropOrFieldAndDirection("AniDBStartEpisodeNumber", true, SortType.eInteger)); List<CrossRef_AniDB_TraktV2> traktCrossRef = Sorting.MultiSort<CrossRef_AniDB_TraktV2>(traktSummary.CrossRefTraktV2, sortCriteria); bool foundStartingPoint = false; CrossRef_AniDB_TraktV2 xrefBase = null; foreach (CrossRef_AniDB_TraktV2 xrefTrakt in traktCrossRef) { if (xrefTrakt.AniDBStartEpisodeType != (int)enEpisodeType.Episode) continue; if (ep.EpisodeNumber >= xrefTrakt.AniDBStartEpisodeNumber) { foundStartingPoint = true; xrefBase = xrefTrakt; break; } } // we have found the starting epiosde numbder from AniDB // now let's check that the Trakt Season and Episode Number exist if (foundStartingPoint) { Dictionary<int, int> dictTraktSeasons = null; Dictionary<int, Trakt_Episode> dictTraktEpisodes = null; foreach (TraktDetailsContainer det in traktSummary.TraktDetails.Values) { if (det.TraktID == xrefBase.TraktID) { dictTraktSeasons = det.DictTraktSeasons; dictTraktEpisodes = det.DictTraktEpisodes; break; } } if (dictTraktSeasons.ContainsKey(xrefBase.TraktSeasonNumber)) { int episodeNumber = dictTraktSeasons[xrefBase.TraktSeasonNumber] + (ep.EpisodeNumber + xrefBase.TraktStartEpisodeNumber - 2) - (xrefBase.AniDBStartEpisodeNumber - 1); if (dictTraktEpisodes.ContainsKey(episodeNumber)) { Trakt_Episode traktep = dictTraktEpisodes[episodeNumber]; traktID = xrefBase.TraktID; season = traktep.Season; epNumber = traktep.EpisodeNumber; traktEpId = traktep.TraktID; } } } } } #endregion #region special episodes if (ep.EpisodeTypeEnum == enEpisodeType.Special) { // find the xref that is right // relies on the xref's being sorted by season number and then episode number (desc) List<SortPropOrFieldAndDirection> sortCriteria = new List<SortPropOrFieldAndDirection>(); sortCriteria.Add(new SortPropOrFieldAndDirection("AniDBStartEpisodeNumber", true, SortType.eInteger)); List<CrossRef_AniDB_TraktV2> traktCrossRef = Sorting.MultiSort<CrossRef_AniDB_TraktV2>(traktSummary.CrossRefTraktV2, sortCriteria); bool foundStartingPoint = false; CrossRef_AniDB_TraktV2 xrefBase = null; foreach (CrossRef_AniDB_TraktV2 xrefTrakt in traktCrossRef) { if (xrefTrakt.AniDBStartEpisodeType != (int)enEpisodeType.Special) continue; if (ep.EpisodeNumber >= xrefTrakt.AniDBStartEpisodeNumber) { foundStartingPoint = true; xrefBase = xrefTrakt; break; } } if (traktSummary != null && traktSummary.CrossRefTraktV2 != null && traktSummary.CrossRefTraktV2.Count > 0) { // we have found the starting epiosde numbder from AniDB // now let's check that the Trakt Season and Episode Number exist if (foundStartingPoint) { Dictionary<int, int> dictTraktSeasons = null; Dictionary<int, Trakt_Episode> dictTraktEpisodes = null; foreach (TraktDetailsContainer det in traktSummary.TraktDetails.Values) { if (det.TraktID == xrefBase.TraktID) { dictTraktSeasons = det.DictTraktSeasons; dictTraktEpisodes = det.DictTraktEpisodes; break; } } if (dictTraktSeasons.ContainsKey(xrefBase.TraktSeasonNumber)) { int episodeNumber = dictTraktSeasons[xrefBase.TraktSeasonNumber] + (ep.EpisodeNumber + xrefBase.TraktStartEpisodeNumber - 2) - (xrefBase.AniDBStartEpisodeNumber - 1); if (dictTraktEpisodes.ContainsKey(episodeNumber)) { Trakt_Episode traktep = dictTraktEpisodes[episodeNumber]; traktID = xrefBase.TraktID; season = traktep.Season; epNumber = traktep.EpisodeNumber; traktEpId = traktep.TraktID; } } } } } #endregion return traktEpId; } catch (Exception ex) { logger.ErrorException(ex.ToString(), ex); return null; } }
public static void SyncCollectionToTrakt_Series(AnimeSeries series) { try { // check that we have at least one user nominated for Trakt JMMUserRepository repUsers = new JMMUserRepository(); List<JMMUser> traktUsers = repUsers.GetTraktUsers(); if (traktUsers.Count == 0) return; AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); AniDB_Anime anime = repAnime.GetByAnimeID(series.AniDB_ID); if (anime == null) return; TraktSummaryContainer traktSummary = new TraktSummaryContainer(); traktSummary.Populate(series.AniDB_ID); if (traktSummary.CrossRefTraktV2 == null || traktSummary.CrossRefTraktV2.Count == 0) return; // now get the full users collection from Trakt List<TraktV2ShowCollectedResult> collected = new List<TraktV2ShowCollectedResult>(); List<TraktV2ShowWatchedResult> watched = new List<TraktV2ShowWatchedResult>(); if (!GetTraktCollectionInfo(ref collected, ref watched)) return; foreach (AnimeEpisode ep in series.GetAnimeEpisodes()) { if (ep.EpisodeTypeEnum == enEpisodeType.Episode || ep.EpisodeTypeEnum == enEpisodeType.Special) { ReconSyncTraktEpisode(series, ep, traktSummary, traktUsers, collected, watched, true); } } } catch (Exception ex) { logger.ErrorException("Error in TraktTVHelper.SyncCollectionToTrakt_Series: " + ex.ToString(), ex); } }
private static int? GetTraktEpisodeIdV2(AniDB_Anime anime, AniDB_Episode ep, ref string traktID, ref int season, ref int epNumber) { TraktSummaryContainer traktSummary = new TraktSummaryContainer(); traktSummary.Populate(anime.AnimeID); return GetTraktEpisodeIdV2(traktSummary, anime, ep, ref traktID, ref season, ref epNumber); }
public static void SyncCollectionToTrakt() { try { if (!ServerSettings.Trakt_IsEnabled || string.IsNullOrEmpty(ServerSettings.Trakt_AuthToken)) return; // check that we have at least one user nominated for Trakt JMMUserRepository repUsers = new JMMUserRepository(); List<JMMUser> traktUsers = repUsers.GetTraktUsers(); if (traktUsers.Count == 0) return; AnimeSeriesRepository repSeries = new AnimeSeriesRepository(); List<AnimeSeries> allSeries = repSeries.GetAll(); // now get the full users collection from Trakt List<TraktV2ShowCollectedResult> collected = new List<TraktV2ShowCollectedResult>(); List<TraktV2ShowWatchedResult> watched = new List<TraktV2ShowWatchedResult>(); if (!GetTraktCollectionInfo(ref collected, ref watched)) return; TraktV2SyncCollectionEpisodesByNumber syncCollectionAdd = new TraktV2SyncCollectionEpisodesByNumber(); TraktV2SyncCollectionEpisodesByNumber syncCollectionRemove = new TraktV2SyncCollectionEpisodesByNumber(); TraktV2SyncWatchedEpisodesByNumber syncHistoryAdd = new TraktV2SyncWatchedEpisodesByNumber(); TraktV2SyncWatchedEpisodesByNumber syncHistoryRemove = new TraktV2SyncWatchedEpisodesByNumber(); #region Local Collection Sync /////////////////////////////////////////////////////////////////////////////////////// // First take a look at our local collection and update on Trakt /////////////////////////////////////////////////////////////////////////////////////// AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository(); int counter = 0; foreach (AnimeSeries series in allSeries) { counter++; logger.Trace("Syncing check - local collection: {0} / {1} - {2}", counter, allSeries.Count, series.GetSeriesName()); AniDB_Anime anime = repAnime.GetByAnimeID(series.AniDB_ID); if (anime == null) continue; //if (anime.AnimeID != 3427) continue; TraktSummaryContainer traktSummary = new TraktSummaryContainer(); traktSummary.Populate(series.AniDB_ID); if (traktSummary.CrossRefTraktV2 == null || traktSummary.CrossRefTraktV2.Count == 0) continue; // get the current watched records for this series on Trakt foreach (AnimeEpisode ep in series.GetAnimeEpisodes()) { if (ep.EpisodeTypeEnum == enEpisodeType.Episode || ep.EpisodeTypeEnum == enEpisodeType.Special) { EpisodeSyncDetails epsync = ReconSyncTraktEpisode(series, ep, traktSummary, traktUsers, collected, watched, false); if (epsync != null) { switch (epsync.SyncType) { case TraktSyncType.CollectionAdd: syncCollectionAdd.AddEpisode(epsync.Slug, epsync.Season, epsync.EpNumber, epsync.EpDate); break; case TraktSyncType.CollectionRemove: syncCollectionRemove.AddEpisode(epsync.Slug, epsync.Season, epsync.EpNumber, epsync.EpDate); break; case TraktSyncType.HistoryAdd: syncHistoryAdd.AddEpisode(epsync.Slug, epsync.Season, epsync.EpNumber, epsync.EpDate); break; case TraktSyncType.HistoryRemove: syncHistoryRemove.AddEpisode(epsync.Slug, epsync.Season, epsync.EpNumber, epsync.EpDate); break; } } } } } #endregion // refresh online info, just in case it was chnaged by the last operations if (!GetTraktCollectionInfo(ref collected, ref watched)) return; #region Online Collection Sync /////////////////////////////////////////////////////////////////////////////////////// // Now look at the collection according to Trakt, and remove it if we don't have it locally /////////////////////////////////////////////////////////////////////////////////////// CrossRef_AniDB_TraktV2Repository repCrossRef = new CrossRef_AniDB_TraktV2Repository(); counter = 0; foreach (TraktV2ShowCollectedResult col in collected) { counter++; logger.Trace("Syncing check - Online collection: {0} / {1} - {2}", counter, collected.Count, col.show.Title); //continue; // check if we have this series locally List<CrossRef_AniDB_TraktV2> xrefs = repCrossRef.GetByTraktID(col.show.ids.slug); if (xrefs.Count > 0) { foreach (CrossRef_AniDB_TraktV2 xref in xrefs) { AnimeSeries locSeries = repSeries.GetByAnimeID(xref.AnimeID); if (locSeries == null) continue; TraktSummaryContainer traktSummary = new TraktSummaryContainer(); traktSummary.Populate(locSeries.AniDB_ID); if (traktSummary.CrossRefTraktV2 == null || traktSummary.CrossRefTraktV2.Count == 0) continue; // if we have this series locSeries, let's sync the whole series foreach (AnimeEpisode ep in locSeries.GetAnimeEpisodes()) { if (ep.EpisodeTypeEnum == enEpisodeType.Episode || ep.EpisodeTypeEnum == enEpisodeType.Special) { EpisodeSyncDetails epsync = ReconSyncTraktEpisode(locSeries, ep, traktSummary, traktUsers, collected, watched, false); if (epsync != null) { switch (epsync.SyncType) { case TraktSyncType.CollectionAdd: syncCollectionAdd.AddEpisode(epsync.Slug, epsync.Season, epsync.EpNumber, epsync.EpDate); break; case TraktSyncType.CollectionRemove: syncCollectionRemove.AddEpisode(epsync.Slug, epsync.Season, epsync.EpNumber, epsync.EpDate); break; case TraktSyncType.HistoryAdd: syncHistoryAdd.AddEpisode(epsync.Slug, epsync.Season, epsync.EpNumber, epsync.EpDate); break; case TraktSyncType.HistoryRemove: syncHistoryRemove.AddEpisode(epsync.Slug, epsync.Season, epsync.EpNumber, epsync.EpDate); break; } } } } } } else { // Actually we can't do this, because the user may have other non Anime series and Movies /* // series doesn't exist locally at all, so let's completely remove it from Trakt foreach (TraktV2CollectedSeason colSeason in col.seasons) { foreach (TraktV2CollectedEpisode colEp in colSeason.episodes) { string msg = string.Format("SYNC ONLINE: Removing from Trakt Collection: Slug: {0} - S:{1} - EP:{2}", col.show.ids.slug, colSeason.number, colEp.number); logger.Trace(msg); SyncEpisodeToTrakt(TraktSyncType.CollectionRemove, col.show.ids.slug, colSeason.number, colEp.number, DateTime.Now, false); } }*/ } } #endregion // refresh online info, just in case it was chnaged by the last operations if (!GetTraktCollectionInfo(ref collected, ref watched)) return; #region Online History (Watched/Unwatched) Sync /////////////////////////////////////////////////////////////////////////////////////// // Now look at the history according to Trakt, and remove it if we don't have it locally /////////////////////////////////////////////////////////////////////////////////////// counter = 0; foreach (TraktV2ShowWatchedResult wtch in watched) { counter++; logger.Trace("Syncing check - Online History: {0} / {1} - {2}", counter, watched.Count, wtch.show.Title); //continue; // check if we have this series locally List<CrossRef_AniDB_TraktV2> xrefs = repCrossRef.GetByTraktID(wtch.show.ids.slug); if (xrefs.Count > 0) { foreach (CrossRef_AniDB_TraktV2 xref in xrefs) { AnimeSeries locSeries = repSeries.GetByAnimeID(xref.AnimeID); if (locSeries == null) continue; TraktSummaryContainer traktSummary = new TraktSummaryContainer(); traktSummary.Populate(locSeries.AniDB_ID); if (traktSummary.CrossRefTraktV2 == null || traktSummary.CrossRefTraktV2.Count == 0) continue; // if we have this series locSeries, let's sync the whole series foreach (AnimeEpisode ep in locSeries.GetAnimeEpisodes()) { if (ep.EpisodeTypeEnum == enEpisodeType.Episode || ep.EpisodeTypeEnum == enEpisodeType.Special) { EpisodeSyncDetails epsync = ReconSyncTraktEpisode(locSeries, ep, traktSummary, traktUsers, collected, watched, false); if (epsync != null) { switch (epsync.SyncType) { case TraktSyncType.CollectionAdd: syncCollectionAdd.AddEpisode(epsync.Slug, epsync.Season, epsync.EpNumber, epsync.EpDate); break; case TraktSyncType.CollectionRemove: syncCollectionRemove.AddEpisode(epsync.Slug, epsync.Season, epsync.EpNumber, epsync.EpDate); break; case TraktSyncType.HistoryAdd: syncHistoryAdd.AddEpisode(epsync.Slug, epsync.Season, epsync.EpNumber, epsync.EpDate); break; case TraktSyncType.HistoryRemove: syncHistoryRemove.AddEpisode(epsync.Slug, epsync.Season, epsync.EpNumber, epsync.EpDate); break; } } } } } } else { // Actually we can't do this, because the user may have other non Anime series and Movies /* // series doesn't exist locally at all, so let's completely remove it from Trakt foreach (TraktV2WatchedSeason wtchSeason in wtch.seasons) { foreach (TraktV2WatchedEpisode wtchEp in wtchSeason.episodes) { string msg = string.Format("SYNC ONLINE: Removing from Trakt History: Slug: {0} - S:{1} - EP:{2}", wtch.show.ids.slug, wtchSeason.number, wtchEp.number); logger.Trace(msg); SyncEpisodeToTrakt(TraktSyncType.HistoryRemove, wtch.show.ids.slug, wtchSeason.number, wtchEp.number, DateTime.Now, false); } }*/ } } #endregion // send the data to Trakt string json = string.Empty; string url = TraktURIs.SyncCollectionAdd; string retData = string.Empty; if (syncCollectionAdd.shows != null && syncCollectionAdd.shows.Count > 0) { json = JSONHelper.Serialize<TraktV2SyncCollectionEpisodesByNumber>(syncCollectionAdd); url = TraktURIs.SyncCollectionAdd; retData = string.Empty; SendData(url, json, "POST", BuildRequestHeaders(), ref retData); } if (syncCollectionRemove.shows != null && syncCollectionRemove.shows.Count > 0) { json = JSONHelper.Serialize<TraktV2SyncCollectionEpisodesByNumber>(syncCollectionRemove); url = TraktURIs.SyncCollectionRemove; retData = string.Empty; SendData(url, json, "POST", BuildRequestHeaders(), ref retData); } if (syncHistoryAdd.shows != null && syncHistoryAdd.shows.Count > 0) { json = JSONHelper.Serialize<TraktV2SyncWatchedEpisodesByNumber>(syncHistoryAdd); url = TraktURIs.SyncHistoryAdd; retData = string.Empty; SendData(url, json, "POST", BuildRequestHeaders(), ref retData); } if (syncHistoryRemove.shows != null && syncHistoryRemove.shows.Count > 0) { json = JSONHelper.Serialize<TraktV2SyncWatchedEpisodesByNumber>(syncHistoryRemove); url = TraktURIs.SyncHistoryRemove; retData = string.Empty; SendData(url, json, "POST", BuildRequestHeaders(), ref retData); } logger.Trace("Test"); } catch (Exception ex) { logger.ErrorException("Error in TraktTVHelper.SyncCollectionToTrakt: " + ex.ToString(), ex); } }