/// <summary> /// Saves any movies that return as 'already_exists' from library sync calls /// </summary> /// <param name="response">Trakt Sync Movie Response</param> public static void InsertAlreadyExistMovies(TraktSyncResponse response) { if (response == null || response.AlreadyExistMovies == null) { return; } foreach (var movie in response.AlreadyExistMovies) { if (TraktSettings.AlreadyExistMovies == null) { TraktSettings.AlreadyExistMovies = new SyncMovieCheck(); } TraktLogger.Info("Inserting movie into already-exist list: Title: {0}, Year: {1}, IMDb: {2}", movie.Title, movie.Year, movie.IMDBID); if (TraktSettings.AlreadyExistMovies.Movies != null) { if (!TraktSettings.AlreadyExistMovies.Movies.Contains(movie)) { TraktSettings.AlreadyExistMovies.Movies.Add(movie); } } else { TraktSettings.AlreadyExistMovies.Movies = new List <TraktMovieSync.Movie>(); TraktSettings.AlreadyExistMovies.Movies.Add(movie); } } }
private void LogTraktResponseDataContract(TraktSyncResponse dataContract) { _logger.LogDebug("TraktResponse Added Movies: " + dataContract.added.movies); _logger.LogDebug("TraktResponse Added Shows: " + dataContract.added.shows); _logger.LogDebug("TraktResponse Added Seasons: " + dataContract.added.seasons); _logger.LogDebug("TraktResponse Added Episodes: " + dataContract.added.episodes); foreach (var traktMovie in dataContract.not_found.movies) { _logger.LogError("TraktResponse not Found: {TraktMovie}", _jsonSerializer.SerializeToString(traktMovie)); } foreach (var traktShow in dataContract.not_found.shows) { _logger.LogError("TraktResponse not Found: {TraktShow}", _jsonSerializer.SerializeToString(traktShow)); } foreach (var traktSeason in dataContract.not_found.seasons) { _logger.LogError("TraktResponse not Found: {TraktSeason}", _jsonSerializer.SerializeToString(traktSeason)); } foreach (var traktEpisode in dataContract.not_found.episodes) { _logger.LogError("TraktResponse not Found: {TraktEpisode}", _jsonSerializer.SerializeToString(traktEpisode)); } }
private void LogTraktResponseDataContract(TraktSyncResponse dataContract) { _logger.Debug("TraktResponse Added Movies: " + dataContract.Added.Movies); _logger.Debug("TraktResponse Added Shows: " + dataContract.Added.Shows); _logger.Debug("TraktResponse Added Seasons: " + dataContract.Added.Seasons); _logger.Debug("TraktResponse Added Episodes: " + dataContract.Added.Episodes); foreach (var traktMovie in dataContract.NotFound.Movies) { _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)); } }
/// <summary> /// Saves any movies that return as 'already_exists' from library sync calls /// </summary> /// <param name="response">Trakt Sync Movie Response</param> internal static void InsertAlreadyExistMovies(TraktSyncResponse response) { //TODO //if (response == null || response.AlreadyExistMovies == null) return; //foreach (var movie in response.AlreadyExistMovies) //{ // if (TraktSettings.AlreadyExistMovies == null) // TraktSettings.AlreadyExistMovies = new SyncMovieCheck(); // TraktLogger.Info("Inserting movie into already-exist list: Title: {0}, Year: {1}, IMDb: {2}", movie.Title, movie.Year, movie.IMDBID); // if (TraktSettings.AlreadyExistMovies.Movies != null) // { // if (!TraktSettings.AlreadyExistMovies.Movies.Contains(movie)) // TraktSettings.AlreadyExistMovies.Movies.Add(movie); // } // else // { // TraktSettings.AlreadyExistMovies.Movies = new List<TraktMovieSync.Movie>(); // TraktSettings.AlreadyExistMovies.Movies.Add(movie); // } //} }
private void HandleMovieResponse(TraktSyncResponse response) { if (response == null) { UIUtils.UpdateStatus("Error importing Criticker movie list to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus("Unable to process {0} movies as they're not found on trakt.tv!", response.NotFound.Movies.Count); foreach (var movie in response.NotFound.Movies) { UIUtils.UpdateStatus("Unable to process movie: Title = {0}, Year = {1}, IMDb = {2}", movie.Title, movie.Year, movie.Ids.ImdbId); } Thread.Sleep(1000); } }
private void HandleShowResponse(TraktSyncResponse response) { if (response == null) { UIUtils.UpdateStatus("Error importing Criticker tv show list to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Shows.Count > 0) { UIUtils.UpdateStatus("Unable to process {0} tv shows as they're not found on trakt.tv!", response.NotFound.Shows.Count); foreach (var show in response.NotFound.Shows) { UIUtils.UpdateStatus("Unable to process tv show: Title = {0}, Year = {1}, IMDb = {2}", show.Title, show.Year, show.Ids.ImdbId); } Thread.Sleep(1000); } }
private void LogTraktResponseDataContract(TraktSyncResponse dataContract) { try { _logger.Debug("TraktResponse Added Movies: " + dataContract?.added?.movies); _logger.Debug("TraktResponse Added Shows: " + dataContract?.added?.shows); _logger.Debug("TraktResponse Added Seasons: " + dataContract?.added?.seasons); _logger.Debug("TraktResponse Added Episodes: " + dataContract?.added?.episodes); _logger.Debug("TraktResponse Deleted Movies: " + dataContract?.deleted?.movies); _logger.Debug("TraktResponse Deleted Shows: " + dataContract?.deleted?.shows); _logger.Debug("TraktResponse Deleted Seasons: " + dataContract?.deleted?.seasons); _logger.Debug("TraktResponse Deleted Episodes: " + dataContract?.deleted?.episodes); _logger.Debug("TraktResponse Existing Movies: " + dataContract?.existing?.movies); _logger.Debug("TraktResponse Existing Shows: " + dataContract?.existing?.shows); _logger.Debug("TraktResponse Existing Seasons: " + dataContract?.existing?.seasons); _logger.Debug("TraktResponse Existing Episodes: " + dataContract?.existing?.episodes); foreach (var traktMovie in dataContract.not_found.movies) { _logger.Error("TraktResponse not Found:" + _jsonSerializer.SerializeToString(traktMovie)); } foreach (var traktShow in dataContract.not_found.shows) { _logger.Error("TraktResponse not Found:" + _jsonSerializer.SerializeToString(traktShow)); } foreach (var traktSeason in dataContract.not_found.seasons) { _logger.Error("TraktResponse not Found:" + _jsonSerializer.SerializeToString(traktSeason)); } foreach (var traktEpisode in dataContract.not_found.episodes) { _logger.Error("TraktResponse not Found:" + _jsonSerializer.SerializeToString(traktEpisode)); } } catch (NullReferenceException e) { _logger.ErrorException("Couldn't decode trakt response", e); _logger.Debug("Response object: {0}", _jsonSerializer.SerializeToString(dataContract)); } }
/// <summary> /// Logs the result of Trakt api call /// </summary> /// <typeparam name="T">Response Type of message</typeparam> /// <param name="response">The response object holding the message to log</param> internal static bool LogTraktResponse <T>(T response) { try { TraktResponse traktResponse = (response as TraktResponse); if (traktResponse == null || traktResponse.Status == null) { // server is probably temporarily unavailable // return true even though it failed, so we can try again // currently the return value is only being used in livetv/recordings Error("Response from server was unexpected."); return(true); } // check response error status if (traktResponse.Status != "success") { Error(traktResponse.Error == "The remote server returned an error: (401) Unauthorized." ? "401 Unauthorized, Please check your Username and Password" : traktResponse.Error); return(false); } // success if (!string.IsNullOrEmpty(traktResponse.Message)) { Info("Response: {0}", traktResponse.Message); } else { // no message returned on movie sync success TraktSyncResponse traktSyncResponse = (response as TraktSyncResponse); if (traktSyncResponse != null) { string message = "Response: Items Inserted: {0}, Items Already Exist: {1}, Items Skipped: {2}"; Info(message, traktSyncResponse.Inserted, traktSyncResponse.AlreadyExist, traktSyncResponse.Skipped); } } return(true); } catch (Exception) { Info("Response: {0}", "Failed to interpret response from server"); return(false); } }
private List <Episode> FindNotFoundEpisodes(IEnumerable <Episode> episodeChunk, TraktSyncResponse traktSyncResponse) { // episodes not found. if using IDs, try again without them List <Episode> episodes = new List <Episode>(); // build a list of unfound episodes with ids foreach (TraktEpisode traktEpisode in traktSyncResponse.NotFound.Episodes.Where(i => HasAnyProviderTvIds(i.Ids))) { // find matching episode in JF based on ids provide var notFoundEpisode = episodeChunk.First(e => e.GetProviderId(MetadataProvider.Imdb) == traktEpisode.Ids.Imdb || e.GetProviderId(MetadataProvider.Tmdb) == traktEpisode.Ids.Tmdb?.ToString(CultureInfo.InvariantCulture) || e.GetProviderId(MetadataProvider.Tvdb) == traktEpisode.Ids.Tvdb?.ToString(CultureInfo.InvariantCulture) || e.GetProviderId(MetadataProvider.TvRage) == traktEpisode.Ids.Tvrage?.ToString(CultureInfo.InvariantCulture)); if (notFoundEpisode != null) { episodes.Add(notFoundEpisode); } } return(episodes); }
internal static void AddRemoveItemInList(List <string> slugs, List <TraktListItem> items, bool remove) { Thread listThread = new Thread(delegate(object obj) { foreach (var slug in slugs) { TraktList list = new TraktList { UserName = TraktSettings.Username, Password = TraktSettings.Password, Slug = slug, Items = items }; TraktSyncResponse response = null; if (!remove) { response = TraktAPI.TraktAPI.ListAddItems(list); } else { response = TraktAPI.TraktAPI.ListDeleteItems(list); } TraktAPI.TraktAPI.LogTraktResponse <TraktSyncResponse>(response); if (response.Status == "success") { // clear current items in any lists // list items will be refreshed online if we try to request them TraktLists.ClearItemsInList(TraktSettings.Username, slug); } } }) { Name = remove ? "RemoveList" : "AddList", IsBackground = true }; listThread.Start(); }
internal static void AddRemoveItemInList(List <string> listnames, List <TraktListItem> items, bool remove) { Thread listThread = new Thread(delegate(object obj) { foreach (var listname in listnames) { TraktList list = new TraktList { UserName = TraktSettings.Username, Password = TraktSettings.Password, Slug = listname, Items = items }; TraktSyncResponse response = null; if (!remove) { response = SendListAddItems(list); } else { response = SendListDeleteItems(list); } if (response.Status == "success") { // all fine! } } }) { Name = remove ? "RemoveList" : "AddList", IsBackground = true }; listThread.Start(); }
public static void RemoveMovieFromWatchList(string title, string year, string imdbid, bool updateMovingPicturesFilters) { if (!GUICommon.CheckLogin(false)) { return; } TraktMovieSync syncObject = BasicHandler.CreateMovieSyncData(title, year, imdbid); if (syncObject == null) { return; } Thread syncThread = new Thread(delegate(object obj) { TraktSyncResponse response = TraktAPI.TraktAPI.SyncMovieLibrary(obj as TraktMovieSync, TraktSyncModes.unwatchlist); if (response == null || response.Status != "success") { return; } if (updateMovingPicturesFilters && IsMovingPicturesAvailableAndEnabled) { // Update Categories & Filters MovingPictures.ClearWatchListCache(); MovingPictures.UpdateCategoriesAndFilters(); } GUI.GUIWatchListMovies.ClearCache(TraktSettings.Username); }) { IsBackground = true, Name = "RemoveWatchList" }; syncThread.Start(syncObject); }
/// <summary> /// Shows a Trakt Rate Dialog /// </summary> /// <param name="rateObject">Type of object being rated</param> public static int ShowRateDialog <T>(T rateObject) { if (!GUICommon.CheckLogin(false)) { return(-1); } if (GUIGraphicsContext.form.InvokeRequired) { ShowRateDialogDelegate <T> d = ShowRateDialog <T>; return((int)GUIGraphicsContext.form.Invoke(d, rateObject)); } TraktRateValue currentRating = TraktRateValue.unrate; var ratingDlg = (GUIRateDialog)GUIWindowManager.GetWindow(GUIRateDialog.ID); ratingDlg.Reset(); ratingDlg.SetHeading(Translation.RateHeading); // if item is not rated, it will default to seven if (rateObject is TraktSyncEpisodeRated) { var item = rateObject as TraktSyncEpisodeRated; ratingDlg.SetLine(1, string.Format("{0}x{1} - {2}", item.Season, item.Number, item.Title)); ratingDlg.Rated = item.Rating == 0 ? TraktRateValue.seven : (TraktRateValue)Convert.ToInt32(item.Rating); } else if (rateObject is TraktSyncShowRatedEx) { // for when episode ids are not available we need to sync with both episode and show details var item = rateObject as TraktSyncShowRatedEx; ratingDlg.SetLine(1, string.Format("{0} - {1}x{2}", item.Title, item.Seasons[0].Number, item.Seasons[0].Episodes[0].Number)); ratingDlg.Rated = item.Seasons[0].Episodes[0].Rating == 0 ? TraktRateValue.seven : (TraktRateValue)Convert.ToInt32(item.Seasons[0].Episodes[0].Rating); } else if (rateObject is TraktSyncShowRated) { var item = rateObject as TraktSyncShowRated; ratingDlg.SetLine(1, item.Title); ratingDlg.Rated = item.Rating == 0 ? TraktRateValue.seven : (TraktRateValue)Convert.ToInt32(item.Rating); } else if (rateObject is TraktSyncSeasonRatedEx) { // for when season ids are not available we need to sync with both season and show details var item = rateObject as TraktSyncSeasonRatedEx; ratingDlg.SetLine(1, string.Format("{0} - {1} {2}", item.Title, Translation.Season, item.Seasons[0].Number)); ratingDlg.Rated = item.Seasons[0].Rating == 0 ? TraktRateValue.seven : (TraktRateValue)Convert.ToInt32(item.Seasons[0].Rating); } else { var item = rateObject as TraktSyncMovieRated; ratingDlg.SetLine(1, item.Title); ratingDlg.Rated = item.Rating == 0 ? TraktRateValue.seven : (TraktRateValue)Convert.ToInt32(item.Rating); } // show dialog ratingDlg.DoModal(ratingDlg.GetID); if (!ratingDlg.IsSubmitted) { return(-1); } TraktSyncResponse response = null; if (rateObject is TraktSyncEpisodeRated) { var item = rateObject as TraktSyncEpisodeRated; currentRating = ratingDlg.Rated; item.Rating = (int)currentRating; var rateThread = new Thread((obj) => { if ((obj as TraktSyncEpisodeRated).Rating > 0) { response = TraktAPI.TraktAPI.AddEpisodeToRatings(obj as TraktSyncEpisodeRated); } else { response = TraktAPI.TraktAPI.RemoveEpisodeFromRatings(obj as TraktEpisode); } TraktLogger.LogTraktResponse(response); }) { IsBackground = true, Name = "Rate" }; rateThread.Start(item); } else if (rateObject is TraktSyncShowRatedEx) { // for when episode ids are not available we need to sync with both episode and show details var item = rateObject as TraktSyncShowRatedEx; currentRating = ratingDlg.Rated; item.Seasons[0].Episodes[0].Rating = (int)currentRating; var rateThread = new Thread((obj) => { if ((obj as TraktSyncShowRatedEx).Seasons[0].Episodes[0].Rating > 0) { response = TraktAPI.TraktAPI.AddEpisodeToRatingsEx(obj as TraktSyncShowRatedEx); } else { response = TraktAPI.TraktAPI.RemoveEpisodeFromRatingsEx(obj as TraktSyncShowRatedEx); } TraktLogger.LogTraktResponse(response); }) { IsBackground = true, Name = "Rate" }; rateThread.Start(item); } else if (rateObject is TraktSyncShowRated) { var item = rateObject as TraktSyncShowRated; currentRating = ratingDlg.Rated; item.Rating = (int)currentRating; var rateThread = new Thread((obj) => { if ((obj as TraktSyncShowRated).Rating > 0) { response = TraktAPI.TraktAPI.AddShowToRatings(obj as TraktSyncShowRated); } else { response = TraktAPI.TraktAPI.RemoveShowFromRatings(obj as TraktShow); } TraktLogger.LogTraktResponse(response); }) { IsBackground = true, Name = "Rate" }; rateThread.Start(item); } else if (rateObject is TraktSyncSeasonRatedEx) { // for when season ids are not available we need to sync with both season and show details var item = rateObject as TraktSyncSeasonRatedEx; currentRating = ratingDlg.Rated; item.Seasons[0].Rating = (int)currentRating; var rateThread = new Thread((obj) => { if ((obj as TraktSyncSeasonRatedEx).Seasons[0].Rating > 0) { response = TraktAPI.TraktAPI.AddSeasonToRatingsEx(obj as TraktSyncSeasonRatedEx); } else { response = TraktAPI.TraktAPI.RemoveSeasonFromRatingsEx(obj as TraktSyncSeasonRatedEx); } TraktLogger.LogTraktResponse(response); }) { IsBackground = true, Name = "Rate" }; rateThread.Start(item); } else { var item = rateObject as TraktSyncMovieRated; currentRating = ratingDlg.Rated; item.Rating = (int)currentRating; var rateThread = new Thread((obj) => { if ((obj as TraktSyncMovieRated).Rating > 0) { response = TraktAPI.TraktAPI.AddMovieToRatings(obj as TraktSyncMovieRated); } else { response = TraktAPI.TraktAPI.RemoveMovieFromRatings(obj as TraktMovie); } TraktLogger.LogTraktResponse(response); }) { IsBackground = true, Name = "Rate" }; rateThread.Start(item); } return((int)currentRating); }
public void ImportRatings() { mImportCancelled = false; var lRatedCsvItems = new List <IMDbRateItem>(); var lWatchlistCsvItems = new List <IMDbListItem>(); var lCustomLists = new Dictionary <string, List <IMDbListItem> >(); #region Parse Ratings CSV UIUtils.UpdateStatus("Reading IMDb ratings export..."); if (mImportCsvRatings) { mCsvConfiguration.RegisterClassMap <IMDbRatingCsvMap>(); lRatedCsvItems = ParseCsvFile <IMDbRateItem>(mRatingsFileCsv); if (lRatedCsvItems == null) { UIUtils.UpdateStatus("Failed to parse IMDb ratings file!", true); Thread.Sleep(2000); return; } mCsvConfiguration.UnregisterClassMap <IMDbRatingCsvMap>(); } if (mImportCancelled) { return; } #endregion #region Parse Watchlist CSV UIUtils.UpdateStatus("Reading IMDb watchlist export..."); if (mImportCsvWatchlist) { mCsvConfiguration.RegisterClassMap <IMDbListCsvMap>(); lWatchlistCsvItems = ParseCsvFile <IMDbListItem>(mWatchlistFileCsv); if (lWatchlistCsvItems == null) { UIUtils.UpdateStatus("Failed to parse IMDb watchlist file!", true); Thread.Sleep(2000); return; } mCsvConfiguration.UnregisterClassMap <IMDbListCsvMap>(); } if (mImportCancelled) { return; } #endregion #region Parse Custom List CSVs UIUtils.UpdateStatus("Reading IMDb custom lists export..."); if (mImportCsvCustomLists) { mCsvConfiguration.RegisterClassMap <IMDbListCsvMap>(); foreach (var list in mCustomListsCsvs) { UIUtils.UpdateStatus($"Reading IMDb custom list '{list}'"); var lListCsvItems = ParseCsvFile <IMDbListItem>(list); if (lListCsvItems == null) { UIUtils.UpdateStatus("Failed to parse IMDb custom list file!", true); Thread.Sleep(2000); continue; } lCustomLists.Add(list, lListCsvItems); } mCsvConfiguration.UnregisterClassMap <IMDbListCsvMap>(); } if (mImportCancelled) { return; } #endregion #region Import Rated Movies var lRatedCsvMovies = lRatedCsvItems.Where(r => r.Type.ItemType() == IMDbType.Movie && r.MyRating != null) .Select(s => s.ToTraktRatedMovie()).ToList(); FileLog.Info($"Found {lRatedCsvMovies.Count} movie ratings in CSV file"); if (lRatedCsvMovies.Any()) { UIUtils.UpdateStatus("Retrieving existing movie ratings from trakt.tv"); var lCurrentUserMovieRatings = TraktAPI.GetRatedMovies(); if (lCurrentUserMovieRatings != null) { UIUtils.UpdateStatus($"Found {lCurrentUserMovieRatings.Count()} user movie ratings on trakt.tv"); // Filter out movies to rate from existing ratings online lRatedCsvMovies.RemoveAll(m => lCurrentUserMovieRatings.Any(c => c.Movie.Ids.ImdbId == m.Ids.ImdbId)); } UIUtils.UpdateStatus($"Importing {lRatedCsvMovies.Count()} new movie ratings to trakt.tv"); if (lRatedCsvMovies.Count > 0) { int lPageSize = AppSettings.BatchSize; int lPages = (int)Math.Ceiling((double)lRatedCsvMovies.Count / lPageSize); for (int i = 0; i < lPages; i++) { UIUtils.UpdateStatus($"Importing page {i + 1}/{lPages} IMDb rated movies..."); var lRatingsToSync = new TraktMovieRatingSync() { movies = lRatedCsvMovies.Skip(i * lPageSize).Take(lPageSize).ToList() }; TraktSyncResponse lResponse = TraktAPI.AddMoviesToRatings(lRatingsToSync); if (lResponse == null) { UIUtils.UpdateStatus("Error importing IMDb movie ratings to trakt.tv", true); Thread.Sleep(2000); } else if (lResponse.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus($"Unable to sync ratings for {lResponse.NotFound.Movies.Count} movies as they're not found on trakt.tv!"); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } if (mImportCancelled) { return; } #endregion #region Import Rated TV Shows var lRatedCsvShows = lRatedCsvItems.Where(r => r.Type.ItemType() == IMDbType.Show && r.MyRating != null) .Select(s => s.ToTraktRatedShow()).ToList(); FileLog.Info($"Found {lRatedCsvShows.Count} tv show ratings in CSV file"); if (lRatedCsvShows.Any()) { UIUtils.UpdateStatus("Retrieving existing tv show ratings from trakt.tv"); var lCurrentUserShowRatings = TraktAPI.GetRatedShows(); if (lCurrentUserShowRatings != null) { UIUtils.UpdateStatus($"Found {lCurrentUserShowRatings.Count()} user tv show ratings on trakt.tv"); // Filter out shows to rate from existing ratings online lRatedCsvShows.RemoveAll(s => lCurrentUserShowRatings.Any(c => (c.Show.Ids.ImdbId == s.Ids.ImdbId) || (c.Show.Title.ToLowerInvariant() == s.Title.ToLowerInvariant() && c.Show.Year == s.Year))); } UIUtils.UpdateStatus($"Importing {lRatedCsvShows.Count()} tv show ratings to trakt.tv"); if (lRatedCsvShows.Count > 0) { int lPageSize = AppSettings.BatchSize; int lPages = (int)Math.Ceiling((double)lRatedCsvShows.Count / lPageSize); for (int i = 0; i < lPages; i++) { UIUtils.UpdateStatus($"Importing page {i + 1}/{lPages} IMDb rated shows..."); var lRatingsToSync = new TraktShowRatingSync() { shows = lRatedCsvShows.Skip(i * lPageSize).Take(lPageSize).ToList() }; TraktSyncResponse lResponse = TraktAPI.AddShowsToRatings(lRatingsToSync); if (lResponse == null) { UIUtils.UpdateStatus("Error importing IMDb tv show ratings to trakt.tv", true); Thread.Sleep(2000); } else if (lResponse.NotFound.Shows.Count > 0) { UIUtils.UpdateStatus($"Unable to sync ratings for {lResponse.NotFound.Shows.Count} shows as they're not found on trakt.tv!"); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } if (mImportCancelled) { return; } #endregion #region Import Rated Episodes var lImdbRatedEpisodes = new List <IMDbEpisode>(); var lImdbRatedCsvEpisodes = lRatedCsvItems.Where(r => r.Type.ItemType() == IMDbType.Episode).ToList(); FileLog.Info($"Found {lImdbRatedCsvEpisodes.Count} tv episode ratings in CSV file"); if (lImdbRatedCsvEpisodes.Any()) { // we can't rely on the episode imdb id as trakt most likely wont have that info at the episode level lImdbRatedEpisodes.AddRange(lImdbRatedCsvEpisodes.Select(Helper.GetIMDbEpisodeFromTrakt).Where(imdbEpisode => imdbEpisode != null)); if (mImportCancelled) { return; } UIUtils.UpdateStatus("Retrieving existing tv episode ratings from trakt.tv"); var lCurrentUserEpisodeRatings = TraktAPI.GetRatedEpisodes(); if (lCurrentUserEpisodeRatings != null) { UIUtils.UpdateStatus($"Found {lCurrentUserEpisodeRatings.Count()} user tv episode ratings on trakt.tv"); // Filter out episodes to rate from existing ratings online lImdbRatedEpisodes.RemoveAll(e => lCurrentUserEpisodeRatings.Any(c => c.Episode.Ids.Trakt == e.TraktId)); } UIUtils.UpdateStatus($"Importing {lImdbRatedEpisodes.Count()} episode ratings to trakt.tv"); if (lImdbRatedEpisodes.Count > 0) { int lPageSize = AppSettings.BatchSize; int lPages = (int)Math.Ceiling((double)lImdbRatedEpisodes.Count / lPageSize); for (int i = 0; i < lPages; i++) { var lEpisodesRated = Helper.GetTraktEpisodeRateData(lImdbRatedEpisodes.Skip(i * lPageSize).Take(lPageSize)); UIUtils.UpdateStatus($"Importing page {i + 1}/{lPages} IMDb rated episodes..."); var lResponse = TraktAPI.AddsEpisodesToRatings(lEpisodesRated); if (lResponse == null) { UIUtils.UpdateStatus("Error importing IMDb episodes ratings to trakt.tv", true); Thread.Sleep(2000); } else if (lResponse.NotFound.Episodes.Count > 0) { UIUtils.UpdateStatus($"Unable to sync ratings for {lResponse.NotFound.Episodes.Count} IMDb episodes as they're not found on trakt.tv!"); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } if (mImportCancelled) { return; } #endregion #region Mark Rated Items as Watched IEnumerable <TraktMoviePlays> lWatchedTraktMovies = null; if (AppSettings.MarkAsWatched) { #region Movies var lWatchedCsvMovies = lRatedCsvItems.Where(r => r.Type.ItemType() == IMDbType.Movie) .Select(s => s.ToTraktWatchedMovie()).ToList(); FileLog.Info("Found {0} movies in CSV file", lWatchedCsvMovies.Count); // compare all movies rated against what's not watched on trakt if (lWatchedCsvMovies.Count > 0) { // get watched movies from trakt.tv UIUtils.UpdateStatus("Requesting watched movies from trakt..."); lWatchedTraktMovies = TraktAPI.GetWatchedMovies(); if (lWatchedTraktMovies == null) { UIUtils.UpdateStatus("Failed to get watched movies from trakt.tv, skipping watched movie import", true); Thread.Sleep(2000); } else { if (mImportCancelled) { return; } UIUtils.UpdateStatus($"Found {lWatchedTraktMovies.Count()} watched movies on trakt"); UIUtils.UpdateStatus("Filtering out watched movies that are already watched on trakt.tv"); lWatchedCsvMovies.RemoveAll(w => lWatchedTraktMovies.FirstOrDefault(t => t.Movie.Ids.ImdbId == w.Ids.ImdbId || (t.Movie.Title.ToLowerInvariant() == w.Title.ToLowerInvariant() && t.Movie.Year == w.Year)) != null); // mark all rated movies as watched UIUtils.UpdateStatus($"Importing {lWatchedCsvMovies.Count} IMDb movies as watched..."); int lPageSize = AppSettings.BatchSize; int lPages = (int)Math.Ceiling((double)lRatedCsvMovies.Count / lPageSize); for (int i = 0; i < lPages; i++) { UIUtils.UpdateStatus($"Importing page {i + 1}/{lPages} IMDb movies as watched..."); var lMoviesToSync = new TraktMovieWatchedSync() { Movies = lWatchedCsvMovies.Skip(i * lPageSize).Take(lPageSize).ToList() }; var lResponse = TraktAPI.AddMoviesToWatchedHistory(lMoviesToSync); if (lResponse == null) { UIUtils.UpdateStatus("Failed to send watched status for IMDb movies to trakt.tv", true); Thread.Sleep(2000); } else if (lResponse.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus($"Unable to sync watched states for {lResponse.NotFound.Movies.Count} movies as they're not found on trakt.tv!"); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } #endregion #region Episodes if (lImdbRatedEpisodes != null && lImdbRatedEpisodes.Any()) { int lPageSize = AppSettings.BatchSize; int lPages = (int)Math.Ceiling((double)lImdbRatedEpisodes.Count / lPageSize); for (int i = 0; i < lPages; i++) { var lEpisodesWatched = Helper.GetTraktEpisodeWatchedData(lImdbRatedEpisodes.Skip(i * lPageSize).Take(lPageSize)); UIUtils.UpdateStatus($"Importing page {i + 1}/{lPages} IMDb watched episodes..."); var lResponse = TraktAPI.AddEpisodesToWatchedHistory(lEpisodesWatched); if (lResponse == null) { UIUtils.UpdateStatus("Error importing IMDb episodes as watched to trakt.tv", true); Thread.Sleep(2000); } else if (lResponse.NotFound.Episodes.Count > 0) { UIUtils.UpdateStatus($"Unable to sync {lResponse.NotFound.Episodes.Count} IMDb episodes as watched, as they're not found on trakt.tv!"); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } #endregion } #endregion #region Import Watchlist Movies var lWatchlistedCsvMovies = lWatchlistCsvItems.Where(r => r.Type.ItemType() == IMDbType.Movie) .Select(s => s.ToTraktMovie()).ToList(); FileLog.Info($"Found {lWatchlistedCsvMovies.Count} movies watchlisted in CSV file"); if (lWatchlistedCsvMovies.Any()) { UIUtils.UpdateStatus("Requesting existing watchlisted movies from trakt..."); var lWatchlistTraktMovies = TraktAPI.GetWatchlistMovies(); if (lWatchlistTraktMovies != null) { UIUtils.UpdateStatus($"Found {lWatchlistTraktMovies.Count()} watchlist movies on trakt"); UIUtils.UpdateStatus("Filtering out watchlist movies that are already in watchlist on trakt.tv"); lWatchlistedCsvMovies.RemoveAll(w => lWatchlistTraktMovies.FirstOrDefault(t => t.Movie.Ids.ImdbId == w.Ids.ImdbId || (t.Movie.Title.ToLowerInvariant() == w.Title.ToLowerInvariant() && t.Movie.Year == w.Year)) != null); } if (AppSettings.IgnoreWatchedForWatchlist && lWatchlistedCsvMovies.Count > 0) { // get watched movies from trakt so we don't import movies into watchlist that are already watched // we may already have this if we imported rated items as watched if (lWatchedTraktMovies != null) { UIUtils.UpdateStatus("Requesting watched movies from trakt..."); lWatchedTraktMovies = TraktAPI.GetWatchedMovies(); if (lWatchedTraktMovies == null) { UIUtils.UpdateStatus("Failed to get watched movies from trakt.tv", true); Thread.Sleep(2000); } } if (lWatchedTraktMovies != null) { UIUtils.UpdateStatus($"Found {lWatchedTraktMovies.Count()} watched movies on trakt"); UIUtils.UpdateStatus("Filtering out watchlist movies that are watched on trakt.tv"); // remove movies from sync list which are watched already lWatchlistedCsvMovies.RemoveAll(w => lWatchedTraktMovies.FirstOrDefault(t => t.Movie.Ids.ImdbId == w.Ids.ImdbId || (t.Movie.Title.ToLowerInvariant() == w.Title.ToLowerInvariant() && t.Movie.Year == w.Year)) != null); } } // add movies to watchlist UIUtils.UpdateStatus($"Importing {lWatchlistedCsvMovies.Count()} IMDb watchlist movies to trakt.tv..."); int lPageSize = AppSettings.BatchSize; int lPages = (int)Math.Ceiling((double)lWatchlistedCsvMovies.Count / lPageSize); for (int i = 0; i < lPages; i++) { UIUtils.UpdateStatus($"Importing page {i + 1}/{lPages} IMDb watchlist movies..."); var lWatchlistedToSync = new TraktMovieSync() { Movies = lWatchlistedCsvMovies.Skip(i * lPageSize).Take(lPageSize).ToList() }; var lResponse = TraktAPI.AddMoviesToWatchlist(lWatchlistedToSync); if (lResponse == null) { UIUtils.UpdateStatus("Failed to send watchlist for IMDb movies", true); Thread.Sleep(2000); } else if (lResponse.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus($"Unable to sync watchlist for {lResponse.NotFound.Movies.Count} movies as they're not found on trakt.tv!"); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } if (mImportCancelled) { return; } #endregion #region Import Watchlist TV Shows IEnumerable <TraktShowPlays> lWatchedTraktShows = null; var lWatchlistedCsvShows = lWatchlistCsvItems.Where(r => r.Type.ItemType() == IMDbType.Show) .Select(s => s.ToTraktShow()).ToList(); FileLog.Info($"Found {lWatchlistedCsvShows.Count} tv shows watchlisted in CSV file"); if (lWatchlistedCsvShows.Any()) { UIUtils.UpdateStatus("Requesting existing watchlisted shows from trakt..."); var lWatchlistTraktShows = TraktAPI.GetWatchlistShows(); if (lWatchlistTraktShows != null) { UIUtils.UpdateStatus($"Found {lWatchlistTraktShows.Count()} watchlist shows on trakt"); UIUtils.UpdateStatus("Filtering out watchlist shows that are already in watchlist on trakt.tv"); lWatchlistedCsvShows.RemoveAll(w => lWatchlistTraktShows.FirstOrDefault(t => t.Show.Ids.ImdbId == w.Ids.ImdbId || (t.Show.Title.ToLowerInvariant() == w.Title.ToLowerInvariant() && t.Show.Year == w.Year)) != null); } if (AppSettings.IgnoreWatchedForWatchlist && lWatchlistedCsvShows.Count > 0) { UIUtils.UpdateStatus("Requesting watched shows from trakt..."); // get watched movies from trakt so we don't import shows into watchlist that are already watched lWatchedTraktShows = TraktAPI.GetWatchedShows(); if (lWatchedTraktShows != null) { UIUtils.UpdateStatus($"Found {lWatchedTraktShows.Count()} watched shows on trakt"); UIUtils.UpdateStatus("Filtering out watchlist shows containing watched episodes on trakt.tv."); // remove shows from sync list which are watched already lWatchlistedCsvShows.RemoveAll(w => lWatchedTraktShows.FirstOrDefault(t => (t.Show.Ids.ImdbId == w.Ids.ImdbId) || (t.Show.Title.ToLowerInvariant() == w.Title.ToLowerInvariant() && t.Show.Year == w.Year)) != null); } } // add shows to watchlist UIUtils.UpdateStatus($"Importing {lWatchlistedCsvShows.Count()} IMDb watchlist shows to trakt.tv..."); int lPageSize = AppSettings.BatchSize; int lPages = (int)Math.Ceiling((double)lWatchlistedCsvShows.Count / lPageSize); for (int i = 0; i < lPages; i++) { UIUtils.UpdateStatus($"Importing page {i + 1}/{lPages} IMDb watchlist shows..."); var lWatchlistShowsToSync = new TraktShowSync { Shows = lWatchlistedCsvShows.Skip(i * lPageSize).Take(lPageSize).ToList() }; var lResponse = TraktAPI.AddShowsToWatchlist(lWatchlistShowsToSync); if (lResponse == null) { UIUtils.UpdateStatus("Failed to send watchlist for IMDb tv shows", true); Thread.Sleep(2000); } else if (lResponse.NotFound.Shows.Count > 0) { UIUtils.UpdateStatus($"Unable to sync watchlist for {lResponse.NotFound.Shows.Count} shows as they're not found on trakt.tv!"); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } if (mImportCancelled) { return; } #endregion #region Import Watchlist Episodes var lImdbWatchlistedEpisodes = new List <IMDbEpisode>(); var lImdbWatchlistedCsvEpisodes = lWatchlistCsvItems.Where(r => r.Type.ItemType() == IMDbType.Episode).ToList(); FileLog.Info($"Found {lImdbWatchlistedCsvEpisodes.Count} tv episodes watchlisted in CSV file"); if (lImdbWatchlistedCsvEpisodes.Any()) { UIUtils.UpdateStatus($"Found {lImdbWatchlistedCsvEpisodes.Count()} IMDb watchlisted episodes"); lImdbWatchlistedEpisodes.AddRange(lImdbWatchlistedCsvEpisodes.Select(Helper.GetIMDbEpisodeFromTrakt).Where(imdbEpisode => imdbEpisode != null)); if (mImportCancelled) { return; } // filter out existing watchlist episodes UIUtils.UpdateStatus("Requesting existing watchlist episodes from trakt..."); var lWatchlistedTraktEpisodes = TraktAPI.GetWatchlistEpisodes(); if (lWatchlistedTraktEpisodes != null) { UIUtils.UpdateStatus($"Found {lWatchlistedTraktEpisodes.Count()} watchlist episodes on trakt"); UIUtils.UpdateStatus("Filtering out watchlist episodes that are already in watchlist on trakt.tv"); lImdbWatchlistedEpisodes.RemoveAll(e => lWatchlistedTraktEpisodes.FirstOrDefault(w => w.Episode.Ids.Trakt == e.TraktId) != null); } if (AppSettings.IgnoreWatchedForWatchlist && lImdbWatchlistedEpisodes.Count > 0) { // we already might have it from the shows sync if (lWatchedTraktShows == null) { UIUtils.UpdateStatus("Requesting watched episodes from trakt..."); // get watched episodes from trakt so we don't import episodes into watchlist that are already watched lWatchedTraktShows = TraktAPI.GetWatchedShows(); } if (lWatchedTraktShows != null) { UIUtils.UpdateStatus("Filtering out watchlist episodes containing watched episodes on trakt.tv"); // this wont work atm due to show IMDb ID not being set in the IMDbEpisode object lImdbWatchlistedEpisodes.RemoveAll(e => lWatchedTraktShows.Where(s => s.Show.Ids.ImdbId == e.ShowImdbId) .Any(s => s.Seasons.Exists(se => se.Number == e.SeasonNumber && se.Episodes.Exists(ep => ep.Number == e.EpisodeNumber)))); } } UIUtils.UpdateStatus($"Importing {lImdbWatchlistedEpisodes.Count()} episodes in watchlist to trakt.tv"); if (lImdbWatchlistedEpisodes.Count > 0) { int lPageSize = AppSettings.BatchSize; int lPages = (int)Math.Ceiling((double)lImdbWatchlistedEpisodes.Count / lPageSize); for (int i = 0; i < lPages; i++) { UIUtils.UpdateStatus($"Importing page {i + 1}/{lPages} IMDb watchlisted episodes..."); var lResponse = TraktAPI.AddEpisodesToWatchlist(Helper.GetTraktEpisodeData(lImdbWatchlistedEpisodes.Skip(i * lPageSize).Take(lPageSize))); if (lResponse == null) { UIUtils.UpdateStatus("Error importing IMDb episode watchlist to trakt.tv", true); Thread.Sleep(2000); } else if (lResponse.NotFound.Episodes.Count > 0) { UIUtils.UpdateStatus("Unable to sync watchlist for {0} IMDb episodes as they're not found on trakt.tv!", lResponse.NotFound.Episodes.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } #endregion #region Import Custom Lists if (lCustomLists.Count > 0) { UIUtils.UpdateStatus("Requesting custom lists from trakt..."); var lTraktCustomLists = TraktAPI.GetCustomLists(); if (lTraktCustomLists == null) { UIUtils.UpdateStatus("Error requesting custom lists from trakt.tv", true); Thread.Sleep(2000); return; } UIUtils.UpdateStatus($"Found {lTraktCustomLists.Count()} custom lists on trakt.tv"); foreach (var list in lCustomLists) { bool lListCreated = false; string lListName = Path.GetFileNameWithoutExtension(list.Key); // create the list if we don't have it TraktListDetail lTraktCustomList = lTraktCustomLists.FirstOrDefault(l => l.Name == lListName); if (lTraktCustomList == null) { UIUtils.UpdateStatus($"Creating new custom list '{lListName}' on trakt.tv"); var lTraktList = new TraktList { Name = lListName, DisplayNumbers = true, }; lTraktCustomList = TraktAPI.CreateCustomList(lTraktList); if (lTraktCustomList == null) { UIUtils.UpdateStatus("Error creating custom list on trakt.tv, skipping list creation", true); Thread.Sleep(2000); continue; } lListCreated = true; } // get the CSV list items parsed var lIMDbCsvListItems = list.Value; var lImdbCsvListMovies = lIMDbCsvListItems.Where(l => l.Type.ItemType() == IMDbType.Movie).Select(m => m.ToTraktMovie()).ToList(); var lImdbCsvListShows = lIMDbCsvListItems.Where(l => l.Type.ItemType() == IMDbType.Show).Select(m => m.ToTraktShow()).ToList(); FileLog.Info($"Found {lIMDbCsvListItems.Count} movies and {lImdbCsvListShows.Count} shows in IMDb {lListName} list", lListName); // if the list already exists, get current items for list if (!lListCreated) { lTraktCustomList = lTraktCustomLists.FirstOrDefault(l => l.Name == lListName); UIUtils.UpdateStatus($"Requesting existing custom list '{lListName}' items from trakt..."); var lTraktListItems = TraktAPI.GetCustomListItems(lTraktCustomList.Ids.Trakt.ToString()); if (lTraktListItems == null) { UIUtils.UpdateStatus("Error requesting custom list items from trakt.tv, skipping list creation", true); Thread.Sleep(2000); continue; } // filter out existing items from CSV so we don't send again FileLog.Info($"Filtering out existing items from IMDb list '{lListName}' so we don't send again to trakt.tv"); lImdbCsvListMovies.RemoveAll(i => lTraktListItems.FirstOrDefault(l => l.Movie.Ids.ImdbId == i.Ids.ImdbId) != null); lImdbCsvListShows.RemoveAll(i => lTraktListItems.FirstOrDefault(l => l.Show.Ids.ImdbId == i.Ids.ImdbId) != null); } #region Movies UIUtils.UpdateStatus($"Importing {lImdbCsvListMovies.Count} new movies into {lListName} custom list..."); int lPageSize = AppSettings.BatchSize; int lPages = (int)Math.Ceiling((double)lImdbCsvListMovies.Count / lPageSize); for (int i = 0; i < lPages; i++) { UIUtils.UpdateStatus($"Importing page {i + 1}/{lPages} IMDb custom list movies..."); // create list sync object to hold list items var lTraktMovieSync = new TraktSyncAll { Movies = lImdbCsvListMovies.Skip(i * lPageSize).Take(lPageSize).ToList() }; var lResponse = TraktAPI.AddItemsToList(lTraktCustomList.Ids.Trakt.ToString(), lTraktMovieSync); if (lResponse == null) { UIUtils.UpdateStatus("Failed to send custom list items for IMDb movies", true); Thread.Sleep(2000); } else if (lResponse.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus($"Unable to sync custom list items for {lResponse.NotFound.Movies.Count} movies as they're not found on trakt.tv!"); Thread.Sleep(1000); } if (mImportCancelled) { return; } } #endregion #region Shows UIUtils.UpdateStatus("Importing {0} new shows into {1} custom list...", lImdbCsvListShows.Count(), lListName); lPageSize = AppSettings.BatchSize; lPages = (int)Math.Ceiling((double)lImdbCsvListShows.Count / lPageSize); for (int i = 0; i < lPages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb custom list shows...", i + 1, lPages); // create list sync object to hold list items var lTraktShowSync = new TraktSyncAll { Shows = lImdbCsvListShows.Skip(i * lPageSize).Take(lPageSize).ToList() }; var lResponse = TraktAPI.AddItemsToList(lTraktCustomList.Ids.Trakt.ToString(), lTraktShowSync); if (lResponse == null) { UIUtils.UpdateStatus("Failed to send custom list items for IMDb shows", true); Thread.Sleep(2000); } else if (lResponse.NotFound.Shows.Count > 0) { UIUtils.UpdateStatus("Unable to sync custom list items for {0} shows as they're not found on trakt.tv!", lResponse.NotFound.Shows.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } #endregion } } #endregion }
public void ImportRatings() { mImportCancelled = false; var lRateItems = new List <Dictionary <string, string> >(); var lWatchlistItems = new List <Dictionary <string, string> >(); var lCustomLists = new Dictionary <string, List <Dictionary <string, string> > >(); #region Parse Ratings CSV UIUtils.UpdateStatus("Reading IMDb ratings export..."); if (mImportCsvRatings && !ParseCSVFile(mRatingsFileCsv, out lRateItems)) { UIUtils.UpdateStatus("Failed to parse IMDb ratings file!", true); Thread.Sleep(2000); return; } if (mImportCancelled) { return; } #endregion #region Parse Watchlist CSV UIUtils.UpdateStatus("Reading IMDb watchlist export..."); if (mImportCsvWatchlist && !ParseCSVFile(mWatchlistFileCsv, out lWatchlistItems)) { UIUtils.UpdateStatus("Failed to parse IMDb watchlist file!", true); Thread.Sleep(2000); return; } if (mImportCancelled) { return; } #endregion #region Parse Custom List CSVs UIUtils.UpdateStatus("Reading IMDb custom lists export..."); if (mImportCsvCustomLists) { foreach (var list in mCustomListsCsvs) { UIUtils.UpdateStatus("Reading IMDb custom list '{0}' export...", list); var lCustomList = new List <Dictionary <string, string> >(); if (!ParseCSVFile(list, out lCustomList)) { UIUtils.UpdateStatus("Failed to parse IMDb custom list file!", true); Thread.Sleep(2000); return; } lCustomLists.Add(list, lCustomList); } } if (mImportCancelled) { return; } #endregion #region Import Rated Movies var lMovies = lRateItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Movie && !string.IsNullOrEmpty(r[IMDbFieldMapping.cRating])).ToList(); FileLog.Info("Found {0} movie ratings in CSV file", lMovies.Count); if (lMovies.Any()) { UIUtils.UpdateStatus("Retrieving existing movie ratings from trakt.tv"); var lCurrentUserMovieRatings = TraktAPI.GetRatedMovies(); if (lCurrentUserMovieRatings != null) { UIUtils.UpdateStatus("Found {0} user movie ratings on trakt.tv", lCurrentUserMovieRatings.Count()); // Filter out movies to rate from existing ratings online lMovies.RemoveAll(m => lCurrentUserMovieRatings.Any(c => c.Movie.Ids.ImdbId == m[IMDbFieldMapping.cIMDbID])); } UIUtils.UpdateStatus("Importing {0} new movie ratings to trakt.tv", lMovies.Count()); if (lMovies.Count > 0) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)lMovies.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb rated movies...", i + 1, pages); TraktSyncResponse response = TraktAPI.AddMoviesToRatings(Helper.GetRateMoviesData(lMovies.Skip(i * pageSize).Take(pageSize))); if (response == null) { UIUtils.UpdateStatus("Error importing IMDb movie ratings to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus("Unable to sync ratings for {0} movies as they're not found on trakt.tv!", response.NotFound.Movies.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } if (mImportCancelled) { return; } #endregion #region Import Rated TV Shows var lShows = lRateItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Show && !string.IsNullOrEmpty(r[IMDbFieldMapping.cRating])).ToList(); FileLog.Info("Found {0} tv show ratings in CSV file", lShows.Count); if (lShows.Any()) { UIUtils.UpdateStatus("Retrieving existing tv show ratings from trakt.tv"); var currentUserShowRatings = TraktAPI.GetRatedShows(); if (currentUserShowRatings != null) { UIUtils.UpdateStatus("Found {0} user tv show ratings on trakt.tv", currentUserShowRatings.Count()); // Filter out shows to rate from existing ratings online lShows.RemoveAll(s => currentUserShowRatings.Any(c => (c.Show.Ids.ImdbId == s[IMDbFieldMapping.cIMDbID]) || (c.Show.Title == s[IMDbFieldMapping.cTitle] && c.Show.Year.ToString() == s[IMDbFieldMapping.cYear]))); } UIUtils.UpdateStatus("Importing {0} tv show ratings to trakt.tv", lShows.Count()); if (lShows.Count > 0) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)lShows.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb rated shows...", i + 1, pages); TraktSyncResponse response = TraktAPI.AddShowsToRatings(Helper.GetRateShowsData(lShows.Skip(i * pageSize).Take(pageSize))); if (response == null) { UIUtils.UpdateStatus("Error importing IMDb tv show ratings to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Shows.Count > 0) { UIUtils.UpdateStatus("Unable to sync ratings for {0} shows as they're not found on trakt.tv!", response.NotFound.Shows.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } if (mImportCancelled) { return; } #endregion #region Import Rated Episodes var lImdbEpisodes = new List <IMDbEpisode>(); var lImdbCsvEpisodes = lRateItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Episode).ToList(); FileLog.Info("Found {0} tv episode ratings in CSV file", lImdbCsvEpisodes.Count); if (lImdbCsvEpisodes.Any()) { // we can't rely on the imdb id as trakt most likely wont have the info for episodes // search and cache all series info needed for syncing // use the tvdb API to first search for each unique series name // then GetSeries by TVDb ID to get a list of all episodes // each episode will have TVDb ID which we can use for syncing. lImdbEpisodes.AddRange(lImdbCsvEpisodes.Select(Helper.GetIMDbEpisodeFromTVDb).Where(imdbEpisode => imdbEpisode != null)); UIUtils.UpdateStatus("Retrieving existing tv episode ratings from trakt.tv"); var currentUserEpisodeRatings = TraktAPI.GetRatedEpisodes(); if (currentUserEpisodeRatings != null) { UIUtils.UpdateStatus("Found {0} user tv episode ratings on trakt.tv", currentUserEpisodeRatings.Count()); // Filter out episodes to rate from existing ratings online lImdbEpisodes.RemoveAll(e => currentUserEpisodeRatings.Any(c => c.Episode.Ids.TvdbId == e.TvdbId || c.Episode.Ids.ImdbId == e.ImdbId)); } UIUtils.UpdateStatus("Importing {0} episode ratings to trakt.tv", lImdbEpisodes.Count()); if (lImdbEpisodes.Count > 0) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)lImdbEpisodes.Count / pageSize); for (int i = 0; i < pages; i++) { var episodesRated = Helper.GetTraktEpisodeRateData(lImdbEpisodes.Skip(i * pageSize).Take(pageSize)); UIUtils.UpdateStatus("Importing page {0}/{1} IMDb rated episodes...", i + 1, pages); var response = TraktAPI.AddsEpisodesToRatings(episodesRated); if (response == null) { UIUtils.UpdateStatus("Error importing IMDb episodes ratings to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Episodes.Count > 0) { UIUtils.UpdateStatus("Unable to sync ratings for {0} IMDb episodes as they're not found on trakt.tv!", response.NotFound.Episodes.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } if (mImportCancelled) { return; } #endregion #region Mark Rated Items as Watched IEnumerable <TraktMoviePlays> lWatchedTraktMovies = null; if (AppSettings.MarkAsWatched) { #region Movies // compare all movies rated against what's not watched on trakt lMovies = lRateItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Movie).ToList(); FileLog.Info("Found {0} movies in CSV file", lMovies.Count); if (lMovies.Count > 0) { // get watched movies from trakt.tv UIUtils.UpdateStatus("Requesting watched movies from trakt..."); lWatchedTraktMovies = TraktAPI.GetWatchedMovies(); if (lWatchedTraktMovies == null) { UIUtils.UpdateStatus("Failed to get watched movies from trakt.tv, skipping watched movie import", true); Thread.Sleep(2000); } else { if (mImportCancelled) { return; } UIUtils.UpdateStatus("Found {0} watched movies on trakt", lWatchedTraktMovies.Count()); UIUtils.UpdateStatus("Filtering out watched movies that are already watched on trakt.tv"); lMovies.RemoveAll(w => lWatchedTraktMovies.FirstOrDefault(t => t.Movie.Ids.ImdbId == w[IMDbFieldMapping.cIMDbID] || (t.Movie.Title.ToLowerInvariant() == w[IMDbFieldMapping.cTitle] && t.Movie.Year.ToString() == w[IMDbFieldMapping.cYear])) != null); // mark all rated movies as watched UIUtils.UpdateStatus("Importing {0} IMDb movies as watched...", lMovies.Count); int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)lMovies.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb movies as watched...", i + 1, pages); var response = TraktAPI.AddMoviesToWatchedHistory(Helper.GetSyncWatchedMoviesData(lMovies.Skip(i * pageSize).Take(pageSize).ToList())); if (response == null) { UIUtils.UpdateStatus("Failed to send watched status for IMDb movies to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus("Unable to sync watched states for {0} movies as they're not found on trakt.tv!", response.NotFound.Movies.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } #endregion #region Episodes if (lImdbEpisodes != null && lImdbEpisodes.Any()) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)lImdbEpisodes.Count / pageSize); for (int i = 0; i < pages; i++) { var episodesWatched = Helper.GetTraktEpisodeWatchedData(lImdbEpisodes.Skip(i * pageSize).Take(pageSize)); UIUtils.UpdateStatus("Importing page {0}/{1} IMDb watched episodes...", i + 1, pages); var response = TraktAPI.AddEpisodesToWatchedHistory(episodesWatched); if (response == null) { UIUtils.UpdateStatus("Error importing IMDb episodes as watched to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Episodes.Count > 0) { UIUtils.UpdateStatus("Unable to sync {0} IMDb episodes as watched, as they're not found on trakt.tv!", response.NotFound.Episodes.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } #endregion } #endregion #region Import Watchlist Movies lMovies = lWatchlistItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Movie).ToList(); FileLog.Info("Found {0} movies watchlisted in CSV file", lMovies.Count); if (lMovies.Any()) { UIUtils.UpdateStatus("Requesting existing watchlist movies from trakt..."); var watchlistTraktMovies = TraktAPI.GetWatchlistMovies(); if (watchlistTraktMovies != null) { UIUtils.UpdateStatus("Found {0} watchlist movies on trakt", watchlistTraktMovies.Count()); UIUtils.UpdateStatus("Filtering out watchlist movies that are already in watchlist on trakt.tv"); lMovies.RemoveAll(w => watchlistTraktMovies.FirstOrDefault(t => t.Movie.Ids.ImdbId == w[IMDbFieldMapping.cIMDbID] || (t.Movie.Title.ToLowerInvariant() == w[IMDbFieldMapping.cTitle] && t.Movie.Year.ToString() == w[IMDbFieldMapping.cYear])) != null); } if (AppSettings.IgnoreWatchedForWatchlist && lMovies.Count > 0) { UIUtils.UpdateStatus("Requesting watched movies from trakt..."); // get watched movies from trakt so we don't import movies into watchlist that are already watched if (lWatchedTraktMovies != null) { lWatchedTraktMovies = TraktAPI.GetWatchedMovies(); if (lWatchedTraktMovies == null) { UIUtils.UpdateStatus("Failed to get watched movies from trakt.tv", true); Thread.Sleep(2000); } } if (lWatchedTraktMovies != null) { UIUtils.UpdateStatus("Found {0} watched movies on trakt", lWatchedTraktMovies.Count()); UIUtils.UpdateStatus("Filtering out watchlist movies that are watched on trakt.tv"); // remove movies from sync list which are watched already lMovies.RemoveAll(w => lWatchedTraktMovies.FirstOrDefault(t => t.Movie.Ids.ImdbId == w[IMDbFieldMapping.cIMDbID] || (t.Movie.Title.ToLowerInvariant() == w[IMDbFieldMapping.cTitle] && t.Movie.Year.ToString() == w[IMDbFieldMapping.cYear])) != null); } } // add movies to watchlist UIUtils.UpdateStatus("Importing {0} IMDb watchlist movies to trakt.tv...", lMovies.Count()); int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)lMovies.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb watchlist movies...", i + 1, pages); var response = TraktAPI.AddMoviesToWatchlist(Helper.GetSyncMoviesData(lMovies.Skip(i * pageSize).Take(pageSize).ToList())); if (response == null) { UIUtils.UpdateStatus("Failed to send watchlist for IMDb movies", true); Thread.Sleep(2000); } else if (response.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus("Unable to sync watchlist for {0} movies as they're not found on trakt.tv!", response.NotFound.Movies.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } if (mImportCancelled) { return; } #endregion #region Import Watchlist TV Shows IEnumerable <TraktShowPlays> watchedTraktShows = null; lShows = lWatchlistItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Show).ToList(); FileLog.Info("Found {0} tv shows watchlisted in CSV file", lShows.Count); if (lShows.Any()) { UIUtils.UpdateStatus("Requesting existing watchlist shows from trakt..."); var watchlistTraktShows = TraktAPI.GetWatchlistShows(); if (watchlistTraktShows != null) { UIUtils.UpdateStatus("Found {0} watchlist shows on trakt", watchlistTraktShows.Count()); UIUtils.UpdateStatus("Filtering out watchlist shows that are already in watchlist on trakt.tv"); lShows.RemoveAll(w => watchlistTraktShows.FirstOrDefault(t => t.Show.Ids.ImdbId == w[IMDbFieldMapping.cIMDbID] || (t.Show.Title.ToLowerInvariant() == w[IMDbFieldMapping.cTitle].ToLowerInvariant() && t.Show.Year.ToString() == w[IMDbFieldMapping.cYear])) != null); } if (AppSettings.IgnoreWatchedForWatchlist && lShows.Count > 0) { UIUtils.UpdateStatus("Requesting watched shows from trakt..."); // get watched movies from trakt so we don't import shows into watchlist that are already watched watchedTraktShows = TraktAPI.GetWatchedShows(); if (watchedTraktShows != null) { UIUtils.UpdateStatus("Found {0} watched shows on trakt", watchedTraktShows.Count()); UIUtils.UpdateStatus("Filtering out watchlist shows containing watched episodes on trakt.tv."); // remove shows from sync list which are watched already lShows.RemoveAll(w => watchedTraktShows.FirstOrDefault(t => (t.Show.Ids.ImdbId == w[IMDbFieldMapping.cIMDbID]) || (t.Show.Title.ToLowerInvariant() == w[IMDbFieldMapping.cTitle].ToLowerInvariant() && t.Show.Year.ToString() == w[IMDbFieldMapping.cYear])) != null); } } // add shows to watchlist UIUtils.UpdateStatus("Importing {0} IMDb watchlist shows to trakt.tv...", lShows.Count()); int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)lShows.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb watchlist shows...", i + 1, pages); var response = TraktAPI.AddShowsToWatchlist(Helper.GetSyncShowsData(lShows.Skip(i * pageSize).Take(pageSize))); if (response == null) { UIUtils.UpdateStatus("Failed to send watchlist for IMDb tv shows", true); Thread.Sleep(2000); } else if (response.NotFound.Shows.Count > 0) { UIUtils.UpdateStatus("Unable to sync watchlist for {0} shows as they're not found on trakt.tv!", response.NotFound.Shows.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } if (mImportCancelled) { return; } #endregion #region Import Watchlist Episodes lImdbEpisodes.Clear(); lImdbCsvEpisodes = lWatchlistItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Episode).ToList(); FileLog.Info("Found {0} tv episodes watchlisted in CSV file", lImdbCsvEpisodes.Count); if (lImdbCsvEpisodes.Any()) { UIUtils.UpdateStatus("Found {0} IMDb watchlist episodes", lImdbCsvEpisodes.Count()); lImdbEpisodes.AddRange(lImdbCsvEpisodes.Select(Helper.GetIMDbEpisodeFromTVDb).Where(imdbEpisode => imdbEpisode != null)); // filter out existing watchlist episodes UIUtils.UpdateStatus("Requesting existing watchlist episodes from trakt..."); var watchlistTraktEpisodes = TraktAPI.GetWatchlistEpisodes(); if (watchlistTraktEpisodes != null) { UIUtils.UpdateStatus("Found {0} watchlist episodes on trakt", watchlistTraktEpisodes.Count()); UIUtils.UpdateStatus("Filtering out watchlist episodes that are already in watchlist on trakt.tv"); lImdbEpisodes.RemoveAll(e => watchlistTraktEpisodes.FirstOrDefault(w => w.Episode.Ids.ImdbId == e.ImdbId || w.Episode.Ids.TvdbId == e.TvdbId) != null); } if (AppSettings.IgnoreWatchedForWatchlist && lImdbEpisodes.Count > 0) { // we already might have it from the shows sync if (watchedTraktShows == null) { UIUtils.UpdateStatus("Requesting watched episodes from trakt..."); // get watched episodes from trakt so we don't import episodes into watchlist that are already watched watchedTraktShows = TraktAPI.GetWatchedShows(); } if (watchedTraktShows != null) { UIUtils.UpdateStatus("Filtering out watchlist episodes containing watched episodes on trakt.tv"); lImdbEpisodes.RemoveAll(e => watchedTraktShows.Where(s => s.Show.Ids.ImdbId == e.ImdbId) .Any(s => s.Seasons.Exists(se => se.Number == e.SeasonNumber && se.Episodes.Exists(ep => ep.Number == e.EpisodeNumber)))); } } UIUtils.UpdateStatus("Importing {0} episodes in watchlist to trakt.tv", lImdbEpisodes.Count()); if (lImdbEpisodes.Count > 0) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)lImdbEpisodes.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb watchlist episodes...", i + 1, pages); var response = TraktAPI.AddEpisodesToWatchlist(Helper.GetTraktEpisodeData(lImdbEpisodes.Skip(i * pageSize).Take(pageSize))); if (response == null) { UIUtils.UpdateStatus("Error importing IMDb episode watchlist to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Episodes.Count > 0) { UIUtils.UpdateStatus("Unable to sync watchlist for {0} IMDb episodes as they're not found on trakt.tv!", response.NotFound.Episodes.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } #endregion #region Import Custom Lists if (lCustomLists.Count > 0) { UIUtils.UpdateStatus("Requesting custom lists from trakt..."); var lTraktCustomLists = TraktAPI.GetCustomLists(); if (lTraktCustomLists == null) { UIUtils.UpdateStatus("Error requesting custom lists from trakt.tv", true); Thread.Sleep(2000); return; } UIUtils.UpdateStatus("Found {0} custom lists on trakt.tv", lTraktCustomLists.Count()); foreach (var list in lCustomLists) { bool lListCreated = false; string lListName = Path.GetFileNameWithoutExtension(list.Key); // create the list if we don't have it TraktListDetail lTraktCustomList = lTraktCustomLists.FirstOrDefault(l => l.Name == lListName); if (lTraktCustomList == null) { UIUtils.UpdateStatus("Creating new custom list '{0}' on trakt.tv", lListName); var lTraktList = new TraktList { Name = lListName, DisplayNumbers = true, }; lTraktCustomList = TraktAPI.CreateCustomList(lTraktList); if (lTraktCustomList == null) { UIUtils.UpdateStatus("Error creating custom list on trakt.tv, skipping list creation", true); Thread.Sleep(2000); continue; } lListCreated = true; } // get the CSV list items parsed var lIMDbListItems = list.Value; var lImdbListMovies = lIMDbListItems.Where(l => l.ItemType() == IMDbType.Movie).ToList(); var lImdbListShows = lIMDbListItems.Where(l => l.ItemType() == IMDbType.Show).ToList(); // if the list already exists, get current items for list if (!lListCreated) { lTraktCustomList = lTraktCustomLists.FirstOrDefault(l => l.Name == lListName); UIUtils.UpdateStatus("Requesting existing custom list '{0}' items from trakt...", lListName); var lTraktListItems = TraktAPI.GetCustomListItems(lTraktCustomList.Ids.Trakt.ToString()); if (lTraktListItems == null) { UIUtils.UpdateStatus("Error requesting custom list items on trakt.tv, skipping list creation", true); Thread.Sleep(2000); continue; } // filter out existing items from CSV so we don't send again FileLog.Info("Filtering out existing items from IMDb list '{0}' so we don't send again to trakt.tv", lListName); lImdbListMovies.RemoveAll(d => d.ItemType() == IMDbType.Movie && lTraktListItems.FirstOrDefault(l => l.Movie.Ids.ImdbId == d[IMDbFieldMapping.cIMDbID]) != null); lImdbListShows.RemoveAll(d => d.ItemType() == IMDbType.Show && lTraktListItems.FirstOrDefault(l => l.Show.Ids.ImdbId == d[IMDbFieldMapping.cIMDbID]) != null); } #region Movies UIUtils.UpdateStatus("Importing {0} movies into {1} custom list...", lImdbListMovies.Count(), lListName); int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)lImdbListMovies.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb custom list movies...", i + 1, pages); // create list sync object to hold list items var lTraktMovieSync = new TraktSyncAll { Movies = Helper.GetSyncMoviesData(lImdbListMovies.Skip(i * pageSize).Take(pageSize).ToList()).Movies }; var response = TraktAPI.AddItemsToList(lTraktCustomList.Ids.Trakt.ToString(), lTraktMovieSync); if (response == null) { UIUtils.UpdateStatus("Failed to send custom list items for IMDb movies", true); Thread.Sleep(2000); } else if (response.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus("Unable to sync custom list items for {0} movies as they're not found on trakt.tv!", response.NotFound.Movies.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } #endregion #region Shows UIUtils.UpdateStatus("Importing {0} shows into {1} custom list...", lImdbListShows.Count(), lListName); pageSize = AppSettings.BatchSize; pages = (int)Math.Ceiling((double)lImdbListShows.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb custom list shows...", i + 1, pages); // create list sync object to hold list items var lTraktShowSync = new TraktSyncAll { Shows = Helper.GetSyncShowsData(lImdbListShows.Skip(i * pageSize).Take(pageSize).ToList()).Shows }; var response = TraktAPI.AddItemsToList(lTraktCustomList.Ids.Trakt.ToString(), lTraktShowSync); if (response == null) { UIUtils.UpdateStatus("Failed to send custom list items for IMDb shows", true); Thread.Sleep(2000); } else if (response.NotFound.Shows.Count > 0) { UIUtils.UpdateStatus("Unable to sync custom list items for {0} shows as they're not found on trakt.tv!", response.NotFound.Shows.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } #endregion } } #endregion }
public void ImportRatings() { importCancelled = false; List <Dictionary <string, string> > watchlistMovies = new List <Dictionary <string, string> >(); List <Dictionary <string, string> > watchlistShows = new List <Dictionary <string, string> >(); List <Dictionary <string, string> > ratedItems = new List <Dictionary <string, string> >(); List <Dictionary <string, string> > watchlistItems = new List <Dictionary <string, string> >(); List <IMDbListItem> lWatchlistItems = new List <IMDbListItem>(); #region Download Data UIUtils.UpdateStatus("Requesting ratings from IMDb.com..."); int movieIndex = 0; int movieIncrement = 100; string paginationKey = string.Empty; Regex reg; Match find; #region Ratings do { UIUtils.UpdateStatus("Requesting ratings {0} - {1}, Total Results: {2}", movieIndex + 1, (movieIncrement + movieIndex), ratedItems.Count); string url = "http://www.imdb.com/user/" + username + "/ratings?sort=date_added%2Cdesc&mode=detail&lastPosition=" + movieIndex + (string.IsNullOrEmpty(paginationKey) ? string.Empty : "&paginationKey=" + paginationKey); string response = TraktWeb.Transmit(url, null, false); if (response == null) { break; } int begin = 0; // only log response when set to trace as it's very verbose in this case if (AppSettings.LogSeverityLevel >= AppSettings.LoggingSeverity.Trace) { FileLog.Trace("Response: {0}", response); } while ((begin = response.IndexOf("lister-item-content", begin)) > 0) { var rateItem = new Dictionary <string, string>(); string sub = response.Substring(begin, response.IndexOf("class=\"clear\"", begin) - begin); reg = new Regex("<a href=\"/title/(?<cIMDbID>tt\\d+)/[^\"]*\"\n>(?<cTitle>[^<]*)</a>(?:[.\\s\\S]*Episode:</small>\\s*<a href=\"/title/(?<cEpisodeID>tt\\d+)/[^\"]*\"\n*>(?<cEpisodeTitle>[^<]+)</a>){0,1}"); // Get IMDb ID find = reg.Match(sub); rateItem.Add(IMDbFieldMapping.cIMDbID, find.Groups["cIMDbID"].ToString()); // Get Title // If it's a TV Episode then include both show and episode title if (!string.IsNullOrEmpty(find.Groups["cEpisodeTitle"].ToString())) { rateItem.Add(IMDbFieldMapping.cTitle, string.Format("{0}: {1}", find.Groups["cTitle"], find.Groups["cEpisodeTitle"])); } else { rateItem.Add(IMDbFieldMapping.cTitle, find.Groups["cTitle"].ToString()); } // Get User Rating reg = new Regex("<span class=\"ipl-rating-star__rating\">([1-9][0-9]{0,1})</span>"); find = reg.Match(sub); rateItem.Add(IMDbFieldMapping.cRating, find.Groups[1].ToString()); // Get Year reg = new Regex("<span class=\"lister-item-year text-muted unbold\">\\(([1-2][0-9]{3}).*\\)</span>"); find = reg.Match(sub); rateItem.Add(IMDbFieldMapping.cYear, find.Groups[1].ToString()); // Get Type reg = new Regex("<span class=\"lister-item-year text-muted unbold\">\\(([1-2][0-9]{3}–).*\\)</span>"); find = reg.Match(sub); if (find.Groups[1].ToString() == string.Empty) { rateItem.Add(IMDbFieldMapping.cType, "Feature Film"); } else { rateItem.Add(IMDbFieldMapping.cType, "tvseries"); } // Set provider to web or csv rateItem.Add(IMDbFieldMapping.cProvider, "web"); ratedItems.Add(rateItem); begin += 10; } // fetch next page movieIndex += movieIncrement; reg = new Regex("<a class=\"flat-button lister-page-next next-page\" href=.*&paginationKey=(?<cPaginationKey>.*)&"); find = reg.Match(response); paginationKey = find.Groups["cPaginationKey"].ToString(); }while (movieIndex == ratedItems.Count); #endregion #region Watchlist if (AppSettings.IMDbSyncWatchlist) { UIUtils.UpdateStatus("Reading IMDb watchlist from web..."); string url = "http://www.imdb.com/user/" + username + "/watchlist"; string response = TraktWeb.Transmit(url, null, false); if (response != null) { var sub = response.Substring(0, response.IndexOf("</head>", 0)); reg = new Regex("ls\\d+"); // Get IMDb Watchlist ID find = reg.Match(sub); url = "http://www.imdb.com/list/" + find.Value + "/export"; using (StreamReader reader = TraktWeb.GetCsvStream(url)) { if (reader == null) { UIUtils.UpdateStatus("Failed to download watchlist from IMDb.", true); Thread.Sleep(2000); } else { lWatchlistItems = ParseCsvFile <IMDbListItem>(reader); if (lWatchlistItems == null) { UIUtils.UpdateStatus("Failed to parse IMDb watchlist file!", true); Thread.Sleep(2000); } } } } // only log response when set to trace as it's very verbose in this case if (AppSettings.LogSeverityLevel >= AppSettings.LoggingSeverity.Trace) { FileLog.Trace("Response: {0}", response); } } #endregion #endregion if (importCancelled) { return; } #region Sync Ratings #region Movies var movies = ratedItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Movie && !string.IsNullOrEmpty(r[IMDbFieldMapping.cRating])).ToList(); if (movies.Any()) { UIUtils.UpdateStatus("Retrieving existing movie ratings from trakt.tv"); var currentUserMovieRatings = TraktAPI.GetRatedMovies(); if (currentUserMovieRatings != null) { UIUtils.UpdateStatus(string.Format("Found {0} user movie ratings on trakt.tv", currentUserMovieRatings.Count())); // Filter out movies to rate from existing ratings online movies.RemoveAll(m => currentUserMovieRatings.Any(c => c.Movie.Ids.ImdbId == m[IMDbFieldMapping.cIMDbID])); } UIUtils.UpdateStatus("Importing {0} new IMDb movie ratings to trakt.tv", movies.Count()); if (movies.Count > 0) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)movies.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb rated movies...", i + 1, pages); TraktSyncResponse response = TraktAPI.AddMoviesToRatings(Helper.GetRateMoviesData(movies.Skip(i * pageSize).Take(pageSize))); if (response == null) { UIUtils.UpdateStatus("Error importing IMDb movie ratings to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus("Unable to sync ratings for {0} IMDb movies as they're not found on trakt.tv!", response.NotFound.Movies.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } } if (importCancelled) { return; } #endregion #region TV Shows var shows = ratedItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Show && !string.IsNullOrEmpty(r[IMDbFieldMapping.cRating])).ToList(); if (shows.Any()) { UIUtils.UpdateStatus("Retrieving existing tv show ratings from trakt.tv"); var currentUserShowRatings = TraktAPI.GetRatedShows(); if (currentUserShowRatings != null) { UIUtils.UpdateStatus("Found {0} user tv show ratings on trakt.tv", currentUserShowRatings.Count()); // Filter out shows to rate from existing ratings online shows.RemoveAll(s => currentUserShowRatings.Any(c => (c.Show.Ids.ImdbId == s[IMDbFieldMapping.cIMDbID]) || (c.Show.Title == s[IMDbFieldMapping.cTitle] && c.Show.Year.ToString() == s[IMDbFieldMapping.cYear]))); } if (shows.Count > 0) { UIUtils.UpdateStatus("Importing {0} new IMDb tv show ratings to trakt.tv", shows.Count()); int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)shows.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb rated shows...", i + 1, pages); TraktSyncResponse response = TraktAPI.AddShowsToRatings(Helper.GetRateShowsData(shows.Skip(i * pageSize).Take(pageSize))); if (response == null) { UIUtils.UpdateStatus("Error importing IMDb show ratings to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Shows.Count > 0) { UIUtils.UpdateStatus("Unable to sync ratings for {0} IMDb shows as they're not found on trakt.tv!", response.NotFound.Shows.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } } if (importCancelled) { return; } #endregion #region Episodes var imdbEpisodes = new List <IMDbEpisode>(); var episodes = ratedItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Episode).ToList(); if (episodes.Any()) { // we can't rely on the imdb id as trakt most likely wont have the info for episodes // search and cache all series info needed for syncing // use the tvdb API to first search for each unique series name // then GetSeries by TVDb ID to get a list of all episodes // each episode will have TVDb ID which we can use for syncing. imdbEpisodes.AddRange(episodes.Select(Helper.GetIMDbEpisodeFromTrakt).Where(imdbEpisode => imdbEpisode != null)); UIUtils.UpdateStatus("Retrieving existing tv episode ratings from trakt.tv"); var currentUserEpisodeRatings = TraktAPI.GetRatedEpisodes(); if (currentUserEpisodeRatings != null) { UIUtils.UpdateStatus("Found {0} user tv episode ratings on trakt.tv", currentUserEpisodeRatings.Count()); // Filter out episodes to rate from existing ratings online imdbEpisodes.RemoveAll(e => currentUserEpisodeRatings.Any(c => c.Episode.Ids.Trakt == e.TraktId)); } UIUtils.UpdateStatus("Importing {0} episode ratings to trakt.tv", imdbEpisodes.Count()); if (imdbEpisodes.Count > 0) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)imdbEpisodes.Count / pageSize); for (int i = 0; i < pages; i++) { var episodesRated = Helper.GetTraktEpisodeRateData(imdbEpisodes.Skip(i * pageSize).Take(pageSize)); UIUtils.UpdateStatus("Importing page {0}/{1} IMDb rated episodes...", i + 1, pages); var response = TraktAPI.AddsEpisodesToRatings(episodesRated); if (response == null) { UIUtils.UpdateStatus("Error importing IMDb episodes ratings to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Episodes.Count > 0) { UIUtils.UpdateStatus("Unable to sync ratings for {0} IMDb episodes as they're not found on trakt.tv!", response.NotFound.Episodes.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } } if (importCancelled) { return; } #endregion #endregion #region Mark as Watched IEnumerable <TraktMoviePlays> watchedTraktMovies = null; if (AppSettings.MarkAsWatched) { #region Movies // compare all movies rated against what's not watched on trakt movies = ratedItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Movie && !string.IsNullOrEmpty(r[IMDbFieldMapping.cRating])).ToList(); if (movies.Count > 0) { // get watched movies from trakt.tv UIUtils.UpdateStatus("Requesting watched movies from trakt..."); watchedTraktMovies = TraktAPI.GetWatchedMovies(); if (watchedTraktMovies == null) { UIUtils.UpdateStatus("Failed to get watched movies from trakt.tv, skipping watched movie import", true); Thread.Sleep(2000); } else { if (importCancelled) { return; } UIUtils.UpdateStatus("Found {0} watched movies on trakt", watchedTraktMovies.Count()); UIUtils.UpdateStatus("Filtering out watched movies that are already watched on trakt.tv"); movies.RemoveAll(w => watchedTraktMovies.FirstOrDefault(t => t.Movie.Ids.ImdbId == w[IMDbFieldMapping.cIMDbID] || (t.Movie.Title.ToLowerInvariant() == w[IMDbFieldMapping.cTitle] && t.Movie.Year.ToString() == w[IMDbFieldMapping.cYear])) != null); // mark all rated movies as watched UIUtils.UpdateStatus("Importing {0} IMDb movies as watched...", movies.Count); int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)movies.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb movies as watched...", i + 1, pages); var response = TraktAPI.AddMoviesToWatchedHistory(Helper.GetSyncWatchedMoviesData(movies.Skip(i * pageSize).Take(pageSize).ToList())); if (response == null) { UIUtils.UpdateStatus("Failed to send watched status for IMDb movies", true); Thread.Sleep(2000); } else if (response.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus("Unable to sync watched state for {0} IMDb movies as they're not found on trakt.tv!", response.NotFound.Movies.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } } #endregion #region Episodes if (imdbEpisodes != null && imdbEpisodes.Any()) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)imdbEpisodes.Count / pageSize); for (int i = 0; i < pages; i++) { var episodesWatched = Helper.GetTraktEpisodeWatchedData(imdbEpisodes.Skip(i * pageSize).Take(pageSize)); UIUtils.UpdateStatus("Importing page {0}/{1} IMDb watched episodes...", i + 1, pages); var response = TraktAPI.AddEpisodesToWatchedHistory(episodesWatched); if (response == null) { UIUtils.UpdateStatus("Error importing IMDb episodes as watched to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Episodes.Count > 0) { UIUtils.UpdateStatus("Unable to sync {0} IMDb episodes as watched, as they're not found on trakt.tv!", response.NotFound.Episodes.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } #endregion } #endregion #region Sync Watchlist if (AppSettings.IMDbSyncWatchlist) { #region Movies var lWatchlistedMovies = lWatchlistItems.Where(r => r.Type.ItemType() == IMDbType.Movie) .Select(s => s.ToTraktMovie()).ToList(); if (lWatchlistedMovies.Any()) { UIUtils.UpdateStatus("Requesting existing watchlist movies from trakt..."); var lWatchlistTraktMovies = TraktAPI.GetWatchlistMovies(); if (lWatchlistTraktMovies != null) { UIUtils.UpdateStatus($"Found {0} watchlist movies on trakt", lWatchlistTraktMovies.Count()); UIUtils.UpdateStatus("Filtering out watchlist movies that are already in watchlist on trakt.tv"); lWatchlistedMovies.RemoveAll(w => lWatchlistTraktMovies.FirstOrDefault(t => t.Movie.Ids.ImdbId == w.Ids.ImdbId || (t.Movie.Title.ToLowerInvariant() == w.Title.ToLowerInvariant() && t.Movie.Year == w.Year)) != null); } if (AppSettings.IgnoreWatchedForWatchlist && lWatchlistedMovies.Count > 0) { // get watched movies from trakt so we don't import movies into watchlist that are already watched // we may already have this if we imported rated items as watched if (watchedTraktMovies == null) { UIUtils.UpdateStatus("Requesting watched movies from trakt..."); watchedTraktMovies = TraktAPI.GetWatchedMovies(); if (watchedTraktMovies == null) { UIUtils.UpdateStatus("Failed to get watched movies from trakt.tv", true); Thread.Sleep(2000); } } if (watchedTraktMovies != null) { UIUtils.UpdateStatus($"Found {0} watched movies on trakt", watchedTraktMovies.Count()); UIUtils.UpdateStatus("Filtering out watchlist movies that are watched on trakt.tv"); // remove movies from sync list which are watched already lWatchlistedMovies.RemoveAll(w => watchedTraktMovies.FirstOrDefault(t => t.Movie.Ids.ImdbId == w.Ids.ImdbId || (t.Movie.Title.ToLowerInvariant() == w.Title.ToLowerInvariant() && t.Movie.Year == w.Year)) != null); } } // add movies to watchlist UIUtils.UpdateStatus($"Importing {0} IMDb watchlist movies to trakt.tv...", lWatchlistedMovies.Count()); int lPageSize = AppSettings.BatchSize; int lPages = (int)Math.Ceiling((double)lWatchlistedMovies.Count / lPageSize); for (int i = 0; i < lPages; i++) { UIUtils.UpdateStatus($"Importing page {0}/{1} IMDb watchlist movies...", i + 1, lPages); var lWatchlistedToSync = new TraktMovieSync() { Movies = lWatchlistedMovies.Skip(i * lPageSize).Take(lPageSize).ToList() }; var lResponse = TraktAPI.AddMoviesToWatchlist(lWatchlistedToSync); if (lResponse == null) { UIUtils.UpdateStatus("Failed to send watchlist for IMDb movies", true); Thread.Sleep(2000); } else if (lResponse.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus($"Unable to sync watchlist for {0} movies as they're not found on trakt.tv!", lResponse.NotFound.Movies.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } if (importCancelled) { return; } #endregion #region TV Shows IEnumerable <TraktShowPlays> lWatchedTraktShows = null; var lWatchlistedShows = lWatchlistItems.Where(r => r.Type.ItemType() == IMDbType.Show) .Select(s => s.ToTraktShow()).ToList(); if (lWatchlistedShows.Any()) { UIUtils.UpdateStatus("Requesting existing watchlisted shows from trakt..."); var lWatchlistTraktShows = TraktAPI.GetWatchlistShows(); if (lWatchlistTraktShows != null) { UIUtils.UpdateStatus($"Found {0} watchlist shows on trakt", lWatchlistTraktShows.Count()); UIUtils.UpdateStatus("Filtering out watchlist shows that are already in watchlist on trakt.tv"); lWatchlistedShows.RemoveAll(w => lWatchlistTraktShows.FirstOrDefault(t => t.Show.Ids.ImdbId == w.Ids.ImdbId || (t.Show.Title.ToLowerInvariant() == w.Title.ToLowerInvariant() && t.Show.Year == w.Year)) != null); } if (AppSettings.IgnoreWatchedForWatchlist && lWatchlistedShows.Count > 0) { UIUtils.UpdateStatus("Requesting watched shows from trakt..."); // get watched movies from trakt so we don't import shows into watchlist that are already watched lWatchedTraktShows = TraktAPI.GetWatchedShows(); if (lWatchedTraktShows != null) { UIUtils.UpdateStatus($"Found {0} watched shows on trakt", lWatchedTraktShows.Count()); UIUtils.UpdateStatus("Filtering out watchlist shows containing watched episodes on trakt.tv."); // remove shows from sync list which are watched already lWatchlistedShows.RemoveAll(w => lWatchedTraktShows.FirstOrDefault(t => (t.Show.Ids.ImdbId == w.Ids.ImdbId) || (t.Show.Title.ToLowerInvariant() == w.Title.ToLowerInvariant() && t.Show.Year == w.Year)) != null); } } // add shows to watchlist UIUtils.UpdateStatus($"Importing {0} IMDb watchlist shows to trakt.tv...", lWatchlistedShows.Count()); int lPageSize = AppSettings.BatchSize; int lPages = (int)Math.Ceiling((double)lWatchlistedShows.Count / lPageSize); for (int i = 0; i < lPages; i++) { UIUtils.UpdateStatus($"Importing page {0}/{1} IMDb watchlist shows...", i + 1, lPages); var lWatchlistShowsToSync = new TraktShowSync { Shows = lWatchlistedShows.Skip(i * lPageSize).Take(lPageSize).ToList() }; var lResponse = TraktAPI.AddShowsToWatchlist(lWatchlistShowsToSync); if (lResponse == null) { UIUtils.UpdateStatus("Failed to send watchlist for IMDb tv shows", true); Thread.Sleep(2000); } else if (lResponse.NotFound.Shows.Count > 0) { UIUtils.UpdateStatus($"Unable to sync watchlist for {0} shows as they're not found on trakt.tv!", lResponse.NotFound.Shows.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } if (importCancelled) { return; } #endregion #region Episodes var lImdbEpisodes = new List <IMDbEpisode>(); var lImdbWatchlistedEpisodes = lWatchlistItems.Where(r => r.Type.ItemType() == IMDbType.Episode).ToList(); if (lImdbWatchlistedEpisodes.Any()) { UIUtils.UpdateStatus($"Found {0} IMDb watchlisted episodes", lImdbWatchlistedEpisodes.Count()); lImdbEpisodes.AddRange(lImdbWatchlistedEpisodes.Select(Helper.GetIMDbEpisodeFromTrakt).Where(imdbEpisode => imdbEpisode != null)); if (importCancelled) { return; } // filter out existing watchlist episodes UIUtils.UpdateStatus("Requesting existing watchlist episodes from trakt..."); var lWatchlistedTraktEpisodes = TraktAPI.GetWatchlistEpisodes(); if (lWatchlistedTraktEpisodes != null) { UIUtils.UpdateStatus($"Found {0} watchlist episodes on trakt", lWatchlistedTraktEpisodes.Count()); UIUtils.UpdateStatus("Filtering out watchlist episodes that are already in watchlist on trakt.tv"); lImdbEpisodes.RemoveAll(e => lWatchlistedTraktEpisodes.FirstOrDefault(w => w.Episode.Ids.Trakt == e.TraktId) != null); } if (AppSettings.IgnoreWatchedForWatchlist && lImdbEpisodes.Count > 0) { // we already might have it from the shows sync if (lWatchedTraktShows == null) { UIUtils.UpdateStatus("Requesting watched episodes from trakt..."); // get watched episodes from trakt so we don't import episodes into watchlist that are already watched lWatchedTraktShows = TraktAPI.GetWatchedShows(); } if (lWatchedTraktShows != null) { UIUtils.UpdateStatus("Filtering out watchlist episodes containing watched episodes on trakt.tv"); // this wont work atm due to show IMDb ID not being set in the IMDbEpisode object lImdbEpisodes.RemoveAll(e => lWatchedTraktShows.Where(s => s.Show.Ids.ImdbId == e.ShowImdbId) .Any(s => s.Seasons.Exists(se => se.Number == e.SeasonNumber && se.Episodes.Exists(ep => ep.Number == e.EpisodeNumber)))); } } UIUtils.UpdateStatus($"Importing {0} episodes in watchlist to trakt.tv", lImdbEpisodes.Count()); if (lImdbEpisodes.Count > 0) { int lPageSize = AppSettings.BatchSize; int lPages = (int)Math.Ceiling((double)lImdbEpisodes.Count / lPageSize); for (int i = 0; i < lPages; i++) { UIUtils.UpdateStatus($"Importing page {0}/{1} IMDb watchlisted episodes...", i + 1, lPages); var lResponse = TraktAPI.AddEpisodesToWatchlist(Helper.GetTraktEpisodeData(lImdbEpisodes.Skip(i * lPageSize).Take(lPageSize))); if (lResponse == null) { UIUtils.UpdateStatus("Error importing IMDb episode watchlist to trakt.tv", true); Thread.Sleep(2000); } else if (lResponse.NotFound.Episodes.Count > 0) { UIUtils.UpdateStatus("Unable to sync watchlist for {0} IMDb episodes as they're not found on trakt.tv!", lResponse.NotFound.Episodes.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } } #endregion } #endregion }
public void ImportRatings() { importCancelled = false; List <Dictionary <string, string> > watchlistMovies = new List <Dictionary <string, string> >(); List <Dictionary <string, string> > watchlistShows = new List <Dictionary <string, string> >(); List <Dictionary <string, string> > ratedItems = new List <Dictionary <string, string> >(); List <Dictionary <string, string> > watchlistItems = new List <Dictionary <string, string> >(); #region Download Data UIUtils.UpdateStatus("Requesting ratings from IMDb.com..."); int count; int movieIndex = 1; int movieIncrement = 250; #region Ratings do { count = ratedItems.Count; UIUtils.UpdateStatus("Requesting ratings {0} - {1}, Total Results: {2}", movieIndex, (movieIncrement + movieIndex - 1), count); string url = "http://www.imdb.com/user/" + username + "/ratings?start=" + movieIndex + "&view=compact"; string response = TraktWeb.Transmit(url, null, false); if (response == null) { break; } int begin = 0; // only log response when set to trace as it's very verbose in this case if (AppSettings.LogSeverityLevel >= AppSettings.LoggingSeverity.Trace) { FileLog.Trace("Response: {0}", response); } while ((begin = response.IndexOf("<tr data-item-id", begin)) > 0) { var rateItem = new Dictionary <string, string>(); string sub = response.Substring(begin, response.IndexOf("</tr>", begin) - begin); Regex reg = new Regex("<td class=\"title[^\"]*\"><a href=\"/title/(?<cIMDbID>tt\\d+)/[^\"]*\">(?<cTitle>[^<]+)</a>(?:\\s*<br>\\s*Episode:\\s*<a href=\"/title/(?<cEpisodeID>tt\\d+)/[^\"]*\">(?<cEpisodeTitle>[^<]+)</a>)?</td>"); // Get IMDb ID var find = reg.Match(sub); rateItem.Add(IMDbFieldMapping.cIMDbID, find.Groups["cIMDbID"].ToString()); // Get Title // If it's a TV Episode then include both show and episode title if (!string.IsNullOrEmpty(find.Groups["cEpisodeTitle"].ToString())) { rateItem.Add(IMDbFieldMapping.cTitle, string.Format("{0}: {1}", find.Groups["cTitle"], find.Groups["cEpisodeTitle"])); } else { rateItem.Add(IMDbFieldMapping.cTitle, find.Groups["cTitle"].ToString()); } // Get User Rating reg = new Regex("<td class=\"your_ratings\">\\n <a>([1-9][0-9]{0,1})</a>\\n</td>"); find = reg.Match(sub); rateItem.Add(IMDbFieldMapping.cRating, find.Groups[1].ToString()); // Get Year reg = new Regex("<td class=\"year\">([1-2][0-9]{3})</td>"); find = reg.Match(sub); rateItem.Add(IMDbFieldMapping.cYear, find.Groups[1].ToString()); // Get Type reg = new Regex("<td class=\"title_type\"> (.*)</td>"); find = reg.Match(sub); if (find.Groups[1].ToString() == string.Empty) { rateItem.Add(IMDbFieldMapping.cType, "Feature Film"); } else { rateItem.Add(IMDbFieldMapping.cType, find.Groups[1].ToString()); } // Set provider to web or csv rateItem.Add(IMDbFieldMapping.cProvider, "web"); ratedItems.Add(rateItem); begin += 10; } // fetch next page movieIndex += movieIncrement; }while (count < ratedItems.Count); #endregion #region Watchlist if (AppSettings.IMDbSyncWatchlist) { UIUtils.UpdateStatus("Reading IMDb watchlist from web..."); movieIndex = 1; movieIncrement = 100; do { count = watchlistItems.Count; UIUtils.UpdateStatus("Requesting watchlist items {0} - {1}, Total Results: {2}", movieIndex, (movieIncrement + movieIndex - 1), count); string url = "http://www.imdb.com/user/" + username + "/watchlist?start=" + movieIndex + "&view=compact"; string response = TraktWeb.Transmit(url, null, false); if (response == null) { break; } int begin = 0; // only log response when set to trace as it's very verbose in this case if (AppSettings.LogSeverityLevel >= AppSettings.LoggingSeverity.Trace) { FileLog.Trace("Response: {0}", response); } if (response == null) { continue; } while ((begin = response.IndexOf("<tr data-item-id", begin)) > 0) { var watchListItem = new Dictionary <string, string>(); var sub = response.Substring(begin, response.IndexOf("</tr>", begin) - begin); Regex reg = new Regex("<td class=\"title[^\"]*\"><a href=\"/title/(?<cIMDbID>tt\\d+)/[^\"]*\">(?<cTitle>[^<]+)</a>(?:\\s*<br>\\s*Episode:\\s*<a href=\"/title/(?<cEpisodeID>tt\\d+)/[^\"]*\">(?<cEpisodeTitle>[^<]+)</a>)?</td>"); // Get IMDb ID var find = reg.Match(sub); watchListItem.Add(IMDbFieldMapping.cIMDbID, find.Groups["cIMDbID"].ToString()); // Get Title // If it's a TV Episode then include both show and episode title if (!string.IsNullOrEmpty(find.Groups["cEpisodeTitle"].ToString())) { watchListItem.Add(IMDbFieldMapping.cTitle, string.Format("{0}: {1}", find.Groups["cTitle"], find.Groups["cEpisodeTitle"])); } else { watchListItem.Add(IMDbFieldMapping.cTitle, find.Groups["cTitle"].ToString()); } // Get Year reg = new Regex("<td class=\"year\">([1-2][0-9]{3})</td>"); find = reg.Match(sub); watchListItem.Add(IMDbFieldMapping.cYear, find.Groups[1].ToString()); // Get Type reg = new Regex("<td class=\"title_type\"> (.*)</td>"); find = reg.Match(sub); if (find.Groups[1].ToString() == string.Empty) { watchListItem.Add(IMDbFieldMapping.cType, "Feature Film"); } else { watchListItem.Add(IMDbFieldMapping.cType, find.Groups[1].ToString()); } // Set provider to web or csv watchListItem.Add(IMDbFieldMapping.cProvider, "web"); watchlistItems.Add(watchListItem); begin += 10; } // fetch next page movieIndex += movieIncrement; }while (count < watchlistItems.Count); } #endregion #endregion if (importCancelled) { return; } #region Sync Ratings #region Movies var movies = ratedItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Movie && !string.IsNullOrEmpty(r[IMDbFieldMapping.cRating])).ToList(); if (movies.Any()) { UIUtils.UpdateStatus("Retrieving existing movie ratings from trakt.tv"); var currentUserMovieRatings = TraktAPI.GetRatedMovies(); if (currentUserMovieRatings != null) { UIUtils.UpdateStatus(string.Format("Found {0} user movie ratings on trakt.tv", currentUserMovieRatings.Count())); // Filter out movies to rate from existing ratings online movies.RemoveAll(m => currentUserMovieRatings.Any(c => c.Movie.Ids.ImdbId == m[IMDbFieldMapping.cIMDbID])); } UIUtils.UpdateStatus("Importing {0} new IMDb movie ratings to trakt.tv", movies.Count()); if (movies.Count > 0) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)movies.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb rated movies...", i + 1, pages); TraktSyncResponse response = TraktAPI.AddMoviesToRatings(Helper.GetRateMoviesData(movies.Skip(i * pageSize).Take(pageSize))); if (response == null) { UIUtils.UpdateStatus("Error importing IMDb movie ratings to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus("Unable to sync ratings for {0} IMDb movies as they're not found on trakt.tv!", response.NotFound.Movies.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } } if (importCancelled) { return; } #endregion #region TV Shows var shows = ratedItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Show && !string.IsNullOrEmpty(r[IMDbFieldMapping.cRating])).ToList(); if (shows.Any()) { UIUtils.UpdateStatus("Retrieving existing tv show ratings from trakt.tv"); var currentUserShowRatings = TraktAPI.GetRatedShows(); if (currentUserShowRatings != null) { UIUtils.UpdateStatus("Found {0} user tv show ratings on trakt.tv", currentUserShowRatings.Count()); // Filter out shows to rate from existing ratings online shows.RemoveAll(s => currentUserShowRatings.Any(c => (c.Show.Ids.ImdbId == s[IMDbFieldMapping.cIMDbID]) || (c.Show.Title == s[IMDbFieldMapping.cTitle] && c.Show.Year.ToString() == s[IMDbFieldMapping.cYear]))); } if (shows.Count > 0) { UIUtils.UpdateStatus("Importing {0} new IMDb tv show ratings to trakt.tv", shows.Count()); int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)shows.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb rated shows...", i + 1, pages); TraktSyncResponse response = TraktAPI.AddShowsToRatings(Helper.GetRateShowsData(shows.Skip(i * pageSize).Take(pageSize))); if (response == null) { UIUtils.UpdateStatus("Error importing IMDb show ratings to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Shows.Count > 0) { UIUtils.UpdateStatus("Unable to sync ratings for {0} IMDb shows as they're not found on trakt.tv!", response.NotFound.Shows.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } } if (importCancelled) { return; } #endregion #region Episodes var imdbEpisodes = new List <IMDbEpisode>(); var episodes = ratedItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Episode).ToList(); if (episodes.Any()) { // we can't rely on the imdb id as trakt most likely wont have the info for episodes // search and cache all series info needed for syncing // use the tvdb API to first search for each unique series name // then GetSeries by TVDb ID to get a list of all episodes // each episode will have TVDb ID which we can use for syncing. imdbEpisodes.AddRange(episodes.Select(Helper.GetIMDbEpisodeFromTVDb).Where(imdbEpisode => imdbEpisode != null)); UIUtils.UpdateStatus("Retrieving existing tv episode ratings from trakt.tv"); var currentUserEpisodeRatings = TraktAPI.GetRatedEpisodes(); if (currentUserEpisodeRatings != null) { UIUtils.UpdateStatus("Found {0} user tv episode ratings on trakt.tv", currentUserEpisodeRatings.Count()); // Filter out episodes to rate from existing ratings online imdbEpisodes.RemoveAll(e => currentUserEpisodeRatings.Any(c => c.Episode.Ids.TvdbId == e.TvdbId)); } UIUtils.UpdateStatus("Importing {0} episode ratings to trakt.tv", imdbEpisodes.Count()); if (imdbEpisodes.Count > 0) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)imdbEpisodes.Count / pageSize); for (int i = 0; i < pages; i++) { var episodesRated = Helper.GetTraktEpisodeRateData(imdbEpisodes.Skip(i * pageSize).Take(pageSize)); UIUtils.UpdateStatus("Importing page {0}/{1} IMDb rated episodes...", i + 1, pages); var response = TraktAPI.AddsEpisodesToRatings(episodesRated); if (response == null) { UIUtils.UpdateStatus("Error importing IMDb episodes ratings to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Episodes.Count > 0) { UIUtils.UpdateStatus("Unable to sync ratings for {0} IMDb episodes as they're not found on trakt.tv!", response.NotFound.Episodes.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } } if (importCancelled) { return; } #endregion #endregion #region Mark as Watched IEnumerable <TraktMoviePlays> watchedTraktMovies = null; if (AppSettings.MarkAsWatched) { #region Movies // compare all movies rated against what's not watched on trakt movies = ratedItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Movie && !string.IsNullOrEmpty(r[IMDbFieldMapping.cRating])).ToList(); if (movies.Count > 0) { // get watched movies from trakt.tv UIUtils.UpdateStatus("Requesting watched movies from trakt..."); watchedTraktMovies = TraktAPI.GetWatchedMovies(); if (watchedTraktMovies == null) { UIUtils.UpdateStatus("Failed to get watched movies from trakt.tv, skipping watched movie import", true); Thread.Sleep(2000); } else { if (importCancelled) { return; } UIUtils.UpdateStatus("Found {0} watched movies on trakt", watchedTraktMovies.Count()); UIUtils.UpdateStatus("Filtering out watched movies that are already watched on trakt.tv"); movies.RemoveAll(w => watchedTraktMovies.FirstOrDefault(t => t.Movie.Ids.ImdbId == w[IMDbFieldMapping.cIMDbID] || (t.Movie.Title.ToLowerInvariant() == w[IMDbFieldMapping.cTitle] && t.Movie.Year.ToString() == w[IMDbFieldMapping.cYear])) != null); // mark all rated movies as watched UIUtils.UpdateStatus("Importing {0} IMDb movies as watched...", movies.Count); int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)movies.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb movies as watched...", i + 1, pages); var response = TraktAPI.AddMoviesToWatchedHistory(Helper.GetSyncWatchedMoviesData(movies.Skip(i * pageSize).Take(pageSize).ToList())); if (response == null) { UIUtils.UpdateStatus("Failed to send watched status for IMDb movies", true); Thread.Sleep(2000); } else if (response.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus("Unable to sync watched state for {0} IMDb movies as they're not found on trakt.tv!", response.NotFound.Movies.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } } #endregion #region Episodes if (imdbEpisodes != null && imdbEpisodes.Any()) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)imdbEpisodes.Count / pageSize); for (int i = 0; i < pages; i++) { var episodesWatched = Helper.GetTraktEpisodeWatchedData(imdbEpisodes.Skip(i * pageSize).Take(pageSize)); UIUtils.UpdateStatus("Importing page {0}/{1} IMDb watched episodes...", i + 1, pages); var response = TraktAPI.AddEpisodesToWatchedHistory(episodesWatched); if (response == null) { UIUtils.UpdateStatus("Error importing IMDb episodes as watched to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Episodes.Count > 0) { UIUtils.UpdateStatus("Unable to sync {0} IMDb episodes as watched, as they're not found on trakt.tv!", response.NotFound.Episodes.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } #endregion } #endregion #region Sync Watchlist if (AppSettings.IMDbSyncWatchlist) { #region Movies watchlistMovies.AddRange(watchlistItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Movie)); if (watchlistMovies.Any()) { UIUtils.UpdateStatus("Requesting existing watchlist movies from trakt..."); var watchlistTraktMovies = TraktAPI.GetWatchlistMovies(); if (watchlistTraktMovies != null) { UIUtils.UpdateStatus("Found {0} watchlist movies on trakt", watchlistTraktMovies.Count()); UIUtils.UpdateStatus("Filtering out watchlist movies that are already in watchlist on trakt.tv"); watchlistMovies.RemoveAll(w => watchlistTraktMovies.FirstOrDefault(t => t.Movie.Ids.ImdbId == w[IMDbFieldMapping.cIMDbID] || (t.Movie.Title.ToLowerInvariant() == w[IMDbFieldMapping.cTitle] && t.Movie.Year.ToString() == w[IMDbFieldMapping.cYear])) != null); } if (AppSettings.IgnoreWatchedForWatchlist && movies.Count > 0) { UIUtils.UpdateStatus("Requesting watched movies from trakt..."); // get watched movies from trakt so we don't import movies into watchlist that are already watched if (watchedTraktMovies != null) { watchedTraktMovies = TraktAPI.GetWatchedMovies(); if (watchedTraktMovies == null) { UIUtils.UpdateStatus("Failed to get watched movies from trakt.tv", true); Thread.Sleep(2000); } else { UIUtils.UpdateStatus("Found {0} watched movies on trakt", watchedTraktMovies.Count()); UIUtils.UpdateStatus("Filtering out watchlist movies that are watched on trakt.tv"); // remove movies from sync list which are watched already watchlistMovies.RemoveAll(w => watchedTraktMovies.FirstOrDefault(t => t.Movie.Ids.ImdbId == w[IMDbFieldMapping.cIMDbID] || (t.Movie.Title.ToLowerInvariant() == w[IMDbFieldMapping.cTitle] && t.Movie.Year.ToString() == w[IMDbFieldMapping.cYear])) != null); } } } // add all movies to watchlist UIUtils.UpdateStatus("Importing {0} IMDb watchlist movies to trakt.tv ...", watchlistMovies.Count()); int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)watchlistMovies.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb movies into watchlist...", i + 1, pages); var response = TraktAPI.AddMoviesToWatchlist(Helper.GetSyncMoviesData(watchlistMovies.Skip(i * pageSize).Take(pageSize).ToList())); if (response == null) { UIUtils.UpdateStatus("Failed to send watchlist for IMDb movies.", true); Thread.Sleep(2000); } else if (response.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus("Unable to sync watchlist for {0} IMDb movies as they're not found on trakt.tv!", response.NotFound.Movies.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } #endregion #region TV Shows IEnumerable <TraktShowPlays> watchedTraktShows = null; watchlistShows.AddRange(watchlistItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Show)); if (watchlistShows.Any()) { UIUtils.UpdateStatus("Requesting existing watchlist shows from trakt..."); var watchlistTraktShows = TraktAPI.GetWatchlistShows(); if (watchlistTraktShows != null) { UIUtils.UpdateStatus("Found {0} watchlist shows on trakt", watchlistTraktShows.Count()); UIUtils.UpdateStatus("Filtering out watchlist shows that are already in watchlist on trakt.tv"); watchlistShows.RemoveAll(w => watchlistTraktShows.FirstOrDefault(t => t.Show.Ids.ImdbId == w[IMDbFieldMapping.cIMDbID] || (t.Show.Title.ToLowerInvariant() == w[IMDbFieldMapping.cTitle].ToLowerInvariant() && t.Show.Year.ToString() == w[IMDbFieldMapping.cYear])) != null); } if (AppSettings.IgnoreWatchedForWatchlist && shows.Count > 0) { UIUtils.UpdateStatus("Requesting watched shows from trakt..."); // get watched movies from trakt so we don't import shows into watchlist that are already watched watchedTraktShows = TraktAPI.GetWatchedShows(); if (watchedTraktShows != null) { UIUtils.UpdateStatus("Found {0} watched shows on trakt", watchedTraktShows.Count()); UIUtils.UpdateStatus("Filtering out watchlist shows containing watched episodes on trakt.tv"); // remove shows from sync list which are watched already watchlistShows.RemoveAll(w => watchedTraktShows.Count(t => (t.Show.Ids.ImdbId == w[IMDbFieldMapping.cIMDbID]) || (t.Show.Title.ToLowerInvariant() == w[IMDbFieldMapping.cTitle].ToLowerInvariant() && t.Show.Year.ToString() == w[IMDbFieldMapping.cYear])) != 0); } } //add all shows to watchlist UIUtils.UpdateStatus("Importing {0} IMDb watchlist shows to trakt.tv...", watchlistShows.Count()); int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)watchlistShows.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} IMDb shows into watchlist...", i + 1, pages); var response = TraktAPI.AddShowsToWatchlist(Helper.GetSyncShowsData(watchlistShows.Skip(i * pageSize).Take(pageSize))); if (response == null) { UIUtils.UpdateStatus("Failed to send watchlist for IMDb tv shows", true); Thread.Sleep(2000); } else if (response.NotFound.Shows.Count > 0) { UIUtils.UpdateStatus("Unable to sync watchlist for {0} IMDb shows as they're not found on trakt.tv!", response.NotFound.Shows.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } #endregion #region Episodes imdbEpisodes.Clear(); episodes = watchlistItems.Where(r => r[IMDbFieldMapping.cType].ItemType() == IMDbType.Episode).ToList(); if (episodes.Any()) { UIUtils.UpdateStatus("Found {0} IMDb watchlist episodes", episodes.Count()); imdbEpisodes.AddRange(episodes.Select(Helper.GetIMDbEpisodeFromTVDb).Where(imdbEpisode => imdbEpisode != null)); // filter out existing watchlist episodes UIUtils.UpdateStatus("Requesting existing watchlist episodes from trakt..."); var watchlistTraktEpisodes = TraktAPI.GetWatchlistEpisodes(); if (watchlistTraktEpisodes != null) { UIUtils.UpdateStatus("Found {0} watchlist episodes on trakt", watchlistTraktEpisodes.Count()); UIUtils.UpdateStatus("Filtering out watchlist episodes that are already in watchlist on trakt.tv"); imdbEpisodes.RemoveAll(e => watchlistTraktEpisodes.FirstOrDefault(w => w.Episode.Ids.ImdbId == e.ImdbId || w.Episode.Ids.TvdbId == e.TvdbId) != null); } if (AppSettings.IgnoreWatchedForWatchlist && episodes.Count > 0) { // we already might have it from the shows sync if (watchedTraktShows == null) { UIUtils.UpdateStatus("Requesting watched episodes from trakt..."); // get watched episodes from trakt so we don't import episodes into watchlist that are already watched watchedTraktShows = TraktAPI.GetWatchedShows(); } if (watchedTraktShows != null) { UIUtils.UpdateStatus("Filtering out watchlist episodes containing watched episodes on trakt.tv."); imdbEpisodes.RemoveAll(e => watchedTraktShows.Where(s => s.Show.Ids.ImdbId == e.ImdbId) .Any(s => s.Seasons.Exists(se => se.Number == e.SeasonNumber && se.Episodes.Exists(ep => ep.Number == e.EpisodeNumber)))); } } UIUtils.UpdateStatus("Importing {0} episodes in watchlist to trakt.tv", imdbEpisodes.Count()); if (imdbEpisodes.Count > 0) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)imdbEpisodes.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus(string.Format("Importing page {0}/{1} IMDb watchlist episodes...", i + 1, pages)); var response = TraktAPI.AddEpisodesToWatchlist(Helper.GetTraktEpisodeData(imdbEpisodes.Skip(i * pageSize).Take(pageSize))); if (response == null) { UIUtils.UpdateStatus("Error importing IMDb episode watchlist to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Episodes.Count > 0) { UIUtils.UpdateStatus("Unable to sync watchlist for {0} IMDb episodes as they're not found on trakt.tv!", response.NotFound.Episodes.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } } #endregion } #endregion }
public void ImportRatings() { mImportCancelled = false; var lAllMovies = new List <FlixsterMovieRating>(); var lAllMovieRatings = new List <FlixsterMovieRating>(); var lAllMoviesWatchlist = new List <FlixsterMovieRating>(); #region Get Rated Movies int lPageSize = 50; UIUtils.UpdateStatus("Getting page 1 of Flixster rated movies..."); var lPagedMovieRatings = FlixsterAPI.GetRatedMovies(mUserId.ToString(), 1, lPageSize); if (mImportCancelled) { return; } if (lPagedMovieRatings == null) { UIUtils.UpdateStatus("Failed to get movie ratings from Flixster", true); Thread.Sleep(2000); return; } // see if there are any more movie ratings to request // we don't get back a number of pages so need to manually work it out if (lPagedMovieRatings.Count() >= lPageSize) { lAllMovies.AddRange(lPagedMovieRatings); int lPage = 2; bool lRequestMore = true; while (lRequestMore) { UIUtils.UpdateStatus("Getting page {0} of Flixster rated movies...", lPage); lPagedMovieRatings = FlixsterAPI.GetRatedMovies(mUserId.ToString(), lPage++, lPageSize); if (lPagedMovieRatings == null) { lRequestMore = false; UIUtils.UpdateStatus(string.Format("Failed to get movie ratings on page {0} from Flixster", lPage - 1), true); Thread.Sleep(2000); } else if (lPagedMovieRatings.Count() > 0) { // when we request another page, if there are no more movies, it *sometimes* returns the same ones again // we can just check if the first movie returned already exists in our collection if (lAllMovies.Exists(r => r.Movie.Title == lPagedMovieRatings.First().Movie.Title&& r.Movie.Year == lPagedMovieRatings.First().Movie.Year)) { lRequestMore = false; } else { lAllMovies.AddRange(lPagedMovieRatings); // check if there is any more pages worth requesting based on size returned in last batch if (lPagedMovieRatings.Count() < lPageSize) { lRequestMore = false; } } } else { lRequestMore = false; } } } #endregion #region Import Rated Movies lAllMovieRatings.AddRange(lAllMovies.Where(m => m.UserScore.IsFloat())); FileLog.Info("Found {0} movie ratings on Flixster", lAllMovieRatings.Count); if (lAllMovieRatings.Any()) { var lMovieRatings = new List <FlixsterMovieRating>(lAllMovieRatings); UIUtils.UpdateStatus("Retrieving existing movie ratings from trakt.tv"); var lCurrentUserMovieRatings = TraktAPI.GetRatedMovies(); if (lCurrentUserMovieRatings != null) { UIUtils.UpdateStatus("Found {0} user movie ratings on trakt.tv", lCurrentUserMovieRatings.Count()); lMovieRatings.RemoveAll(r => lCurrentUserMovieRatings.Any(c => c.Movie.Title.ToLowerInvariant() == r.Movie.Title.ToLowerInvariant() && c.Movie.Year == r.Movie.Year.ToYear())); } UIUtils.UpdateStatus("Importing {0} new movie ratings to trakt.tv", lMovieRatings.Count()); if (lMovieRatings.Count > 0) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)lMovieRatings.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} Flixster rated movies...", i + 1, pages); TraktSyncResponse response = TraktAPI.AddMoviesToRatings(GetSyncRateMoviesData(lMovieRatings.Skip(i * pageSize).Take(pageSize).ToList())); if (response == null) { UIUtils.UpdateStatus("Error importing Flixster movie ratings to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus("Unable to sync ratings for {0} movies as they're not found on trakt.tv!", response.NotFound.Movies.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } if (mImportCancelled) { return; } #endregion #region Mark Rated Items as Watched IEnumerable <TraktMoviePlays> lWatchedTraktMovies = null; if (AppSettings.MarkAsWatched && lAllMovieRatings.Count > 0) { if (mImportCancelled) { return; } var lMoviesWatched = new List <FlixsterMovieRating>(lAllMovieRatings); // get watched movies from trakt.tv UIUtils.UpdateStatus("Requesting watched movies from trakt.tv..."); lWatchedTraktMovies = TraktAPI.GetWatchedMovies(); if (lWatchedTraktMovies == null) { UIUtils.UpdateStatus("Failed to get watched movies from trakt.tv, skipping watched movie import", true); Thread.Sleep(2000); } else { if (mImportCancelled) { return; } UIUtils.UpdateStatus("Found {0} watched movies on trakt", lWatchedTraktMovies.Count()); UIUtils.UpdateStatus("Filtering out watched movies that are already watched on trakt.tv"); lMoviesWatched.RemoveAll(w => lWatchedTraktMovies.Any(t => t.Movie.Title.ToLowerInvariant() == w.Movie.Title.ToLowerInvariant() && t.Movie.Year == w.Movie.Year.ToYear())); // mark all rated movies as watched UIUtils.UpdateStatus("Importing {0} Flixster movies as watched...", lMoviesWatched.Count); int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)lMoviesWatched.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} Flixster movies as watched...", i + 1, pages); var response = TraktAPI.AddMoviesToWatchedHistory(GetSyncWatchedMoviesData(lMoviesWatched.Skip(i * pageSize).Take(pageSize).ToList())); if (response == null) { UIUtils.UpdateStatus("Failed to send watched status for Flixster movies to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus("Unable to sync watched states for {0} movies as they're not found on trakt.tv!", response.NotFound.Movies.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } #endregion #region Sync Watchlist if (mSyncWantToSee) { if (mImportCancelled) { return; } lAllMoviesWatchlist.AddRange(lAllMovies.Where(m => m.UserScore == "+")); if (lAllMoviesWatchlist.Count > 0) { UIUtils.UpdateStatus("Requesting existing watchlist movies from trakt..."); var lWatchlistTraktMovies = TraktAPI.GetWatchlistMovies(); if (lWatchlistTraktMovies != null) { UIUtils.UpdateStatus("Found {0} watchlist movies on trakt", lWatchlistTraktMovies.Count()); UIUtils.UpdateStatus("Filtering out watchlist movies that are already in watchlist on trakt.tv"); lAllMoviesWatchlist.RemoveAll(w => lWatchlistTraktMovies.Any(t => t.Movie.Title.ToLowerInvariant() == w.Movie.Title.ToLowerInvariant() && t.Movie.Year == w.Movie.Year.ToYear())); } if (mImportCancelled) { return; } if (AppSettings.IgnoreWatchedForWatchlist) { UIUtils.UpdateStatus("Requesting watched movies from trakt..."); // get watched movies from trakt so we don't import movies into watchlist that are already watched if (lWatchedTraktMovies == null) { lWatchedTraktMovies = TraktAPI.GetWatchedMovies(); if (lWatchedTraktMovies != null) { UIUtils.UpdateStatus("Found {0} watched movies on trakt", lWatchedTraktMovies.Count()); // remove movies from sync list which are watched already lAllMoviesWatchlist.RemoveAll(w => lWatchedTraktMovies.Any(t => t.Movie.Title.ToLowerInvariant() == w.Movie.Title.ToLowerInvariant() && t.Movie.Year == w.Movie.Year.ToYear())); } } if (mImportCancelled) { return; } } // add all movies to watchlist UIUtils.UpdateStatus("Importing {0} Flixster wanttosee movies to trakt.tv watchlist...", lAllMoviesWatchlist.Count()); if (lAllMoviesWatchlist.Count > 0) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)lAllMoviesWatchlist.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} Flixster wantlist movies to trakt.tv watchlist...", i + 1, pages); var watchlistMoviesResponse = TraktAPI.AddMoviesToWatchlist(GetSyncMoviesData(lAllMoviesWatchlist.Skip(i * pageSize).Take(pageSize).ToList())); if (watchlistMoviesResponse == null) { UIUtils.UpdateStatus("Failed to send watchlist for Flixster movies", true); Thread.Sleep(2000); } if (mImportCancelled) { return; } } } } } #endregion }
/// <summary> /// Shows a Trakt Rate Dialog /// </summary> /// <param name="rateObject">Type of object being rated</param> public static int ShowRateDialog <T>(T rateObject) { // Wait playback is fully stopped to avoid loop on stop while (g_Player.FullScreen || GUIGraphicsContext.Vmr9Active) { Thread.Sleep(10); } if (!GUICommon.CheckLogin(false)) { return(-1); } if (GUIGraphicsContext.form.InvokeRequired) { ShowRateDialogDelegate <T> d = ShowRateDialog <T>; return((int)GUIGraphicsContext.form.Invoke(d, rateObject)); } // The WiFi Remote is using an older version of the API which causes a conflict after recent refactoring // This check is put in place so it does not cripple users experience when rate dialog is invoked if (!TraktHelper.IsWifiRemotePluginCompatible) { GUIUtils.ShowOKDialog(Translation.Error, Translation.WifiRemotePluginInCompatible); return(-1); } TraktRateValue currentRating = TraktRateValue.unrate; var ratingDlg = (GUIRateDialog)GUIWindowManager.GetWindow(GUIRateDialog.ID); ratingDlg.Reset(); ratingDlg.SetHeading(Translation.RateHeading); // if item is not rated, it will default to seven if (rateObject is TraktSyncEpisodeRated) { var item = rateObject as TraktSyncEpisodeRated; ratingDlg.SetLine(1, string.Format("{0}x{1} - {2}", item.Season, item.Number, item.Title)); ratingDlg.Rated = item.Rating == 0 ? TraktRateValue.seven : (TraktRateValue)Convert.ToInt32(item.Rating); } else if (rateObject is TraktSyncShowRatedEx) { // for when episode ids are not available we need to sync with both episode and show details var item = rateObject as TraktSyncShowRatedEx; ratingDlg.SetLine(1, string.Format("{0} - {1}x{2}", item.Title, item.Seasons[0].Number, item.Seasons[0].Episodes[0].Number)); ratingDlg.Rated = item.Seasons[0].Episodes[0].Rating == 0 ? TraktRateValue.seven : (TraktRateValue)Convert.ToInt32(item.Seasons[0].Episodes[0].Rating); } else if (rateObject is TraktSyncShowRated) { var item = rateObject as TraktSyncShowRated; ratingDlg.SetLine(1, item.Title); ratingDlg.Rated = item.Rating == 0 ? TraktRateValue.seven : (TraktRateValue)Convert.ToInt32(item.Rating); } else if (rateObject is TraktSyncSeasonRatedEx) { // for when season ids are not available we need to sync with both season and show details var item = rateObject as TraktSyncSeasonRatedEx; ratingDlg.SetLine(1, string.Format("{0} - {1} {2}", item.Title, Translation.Season, item.Seasons[0].Number)); ratingDlg.Rated = item.Seasons[0].Rating == 0 ? TraktRateValue.seven : (TraktRateValue)Convert.ToInt32(item.Seasons[0].Rating); } else { var item = rateObject as TraktSyncMovieRated; ratingDlg.SetLine(1, item.Title); ratingDlg.Rated = item.Rating == 0 ? TraktRateValue.seven : (TraktRateValue)Convert.ToInt32(item.Rating); } // show dialog ratingDlg.DoModal(ratingDlg.GetID); if (!ratingDlg.IsSubmitted) { return(-1); } TraktSyncResponse response = null; if (rateObject is TraktSyncEpisodeRated) { var item = rateObject as TraktSyncEpisodeRated; currentRating = ratingDlg.Rated; item.Rating = (int)currentRating; var rateThread = new Thread((obj) => { if ((obj as TraktSyncEpisodeRated).Rating > 0) { response = TraktAPI.TraktAPI.AddEpisodeToRatings(obj as TraktSyncEpisodeRated); } else { response = TraktAPI.TraktAPI.RemoveEpisodeFromRatings(obj as TraktEpisode); } TraktLogger.LogTraktResponse(response); }) { IsBackground = true, Name = "Rate" }; rateThread.Start(item); } else if (rateObject is TraktSyncShowRatedEx) { // for when episode ids are not available we need to sync with both episode and show details var item = rateObject as TraktSyncShowRatedEx; currentRating = ratingDlg.Rated; item.Seasons[0].Episodes[0].Rating = (int)currentRating; var rateThread = new Thread((obj) => { if ((obj as TraktSyncShowRatedEx).Seasons[0].Episodes[0].Rating > 0) { response = TraktAPI.TraktAPI.AddEpisodeToRatingsEx(obj as TraktSyncShowRatedEx); } else { response = TraktAPI.TraktAPI.RemoveEpisodeFromRatingsEx(obj as TraktSyncShowRatedEx); } TraktLogger.LogTraktResponse(response); }) { IsBackground = true, Name = "Rate" }; rateThread.Start(item); } else if (rateObject is TraktSyncShowRated) { var item = rateObject as TraktSyncShowRated; currentRating = ratingDlg.Rated; item.Rating = (int)currentRating; var rateThread = new Thread((obj) => { if ((obj as TraktSyncShowRated).Rating > 0) { response = TraktAPI.TraktAPI.AddShowToRatings(obj as TraktSyncShowRated); } else { response = TraktAPI.TraktAPI.RemoveShowFromRatings(obj as TraktShow); } TraktLogger.LogTraktResponse(response); }) { IsBackground = true, Name = "Rate" }; rateThread.Start(item); } else if (rateObject is TraktSyncSeasonRatedEx) { // for when season ids are not available we need to sync with both season and show details var item = rateObject as TraktSyncSeasonRatedEx; currentRating = ratingDlg.Rated; item.Seasons[0].Rating = (int)currentRating; var rateThread = new Thread((obj) => { if ((obj as TraktSyncSeasonRatedEx).Seasons[0].Rating > 0) { response = TraktAPI.TraktAPI.AddSeasonToRatingsEx(obj as TraktSyncSeasonRatedEx); } else { response = TraktAPI.TraktAPI.RemoveSeasonFromRatingsEx(obj as TraktSyncSeasonRatedEx); } TraktLogger.LogTraktResponse(response); }) { IsBackground = true, Name = "Rate" }; rateThread.Start(item); } else { var item = rateObject as TraktSyncMovieRated; currentRating = ratingDlg.Rated; item.Rating = (int)currentRating; var rateThread = new Thread((obj) => { if ((obj as TraktSyncMovieRated).Rating > 0) { response = TraktAPI.TraktAPI.AddMovieToRatings(obj as TraktSyncMovieRated); } else { response = TraktAPI.TraktAPI.RemoveMovieFromRatings(obj as TraktMovie); } TraktLogger.LogTraktResponse(response); }) { IsBackground = true, Name = "Rate" }; rateThread.Start(item); } return((int)currentRating); }
public void ImportRatings() { importCancelled = false; // get show userratings from theTVDb.com first UIUtils.UpdateStatus("Getting show ratings from theTVDb.com"); TVDbShowRatings showRatings = TVDbAPI.GetShowRatings(accountId); // if there are no show ratings quit if (showRatings == null || showRatings.Shows.Count == 0) { UIUtils.UpdateStatus("Unable to get list of shows from thetvdb.com, NOTE: episode ratings can not be retreived from theTVDb.com unless the Show has also been rated!", true); return; } #region Import Show Ratings if (importCancelled) { return; } UIUtils.UpdateStatus("Retrieving existing tv show ratings from trakt.tv"); var currentUserShowRatings = TraktAPI.GetRatedShows(); var filteredShows = new TVDbShowRatings(); filteredShows.Shows.AddRange(showRatings.Shows); if (currentUserShowRatings != null) { UIUtils.UpdateStatus("Found {0} user tv show ratings on trakt.tv", currentUserShowRatings.Count()); UIUtils.UpdateStatus("Filtering out tvdb show ratings that already exist at trakt.tv"); // Filter out shows to rate from existing ratings online filteredShows.Shows.RemoveAll(s => currentUserShowRatings.Any(c => c.Show.Ids.TvdbId == s.Id)); } UIUtils.UpdateStatus("Importing {0} show ratings to trakt.tv", filteredShows.Shows.Count); if (filteredShows.Shows.Count > 0) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)filteredShows.Shows.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} TVDb rated shows...", i + 1, pages); TraktSyncResponse response = TraktAPI.AddShowsToRatings(GetRateShowsData(filteredShows.Shows.Skip(i * pageSize).Take(pageSize).ToList())); if (response == null) { UIUtils.UpdateStatus("Error importing show ratings to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Shows.Count > 0) { UIUtils.UpdateStatus("Unable to sync ratings of {0} shows as they're not found on trakt.tv!", response.NotFound.Shows.Count); Thread.Sleep(1000); } if (importCancelled) { return; } } } #endregion #region Import Episode Ratings int iCounter = 0; var episodesRated = new Dictionary <string, List <TraktEpisodeRating> >(); // get all existing user ratings from trakt.tv UIUtils.UpdateStatus("Retrieving existing episode ratings from trakt.tv"); var currentUserEpisodeRatings = TraktAPI.GetRatedEpisodes(); if (currentUserEpisodeRatings != null) { UIUtils.UpdateStatus("Found {0} user tv episode ratings on trakt.tv", currentUserEpisodeRatings.Count()); } foreach (var show in showRatings.Shows) { if (importCancelled) { return; } iCounter++; UIUtils.UpdateStatus("[{0}/{1}] Getting show info for tvdb series id {2}", iCounter, showRatings.Shows.Count, show.Id); // we need to get the episode/season numbers as trakt api requires this // tvdb only returns episode ids, so user series info call to this info TVDbShow showInfo = TVDbAPI.GetShowInfo(show.Id.ToString()); if (showInfo == null) { UIUtils.UpdateStatus(string.Format("Unable to get show info for tvdb series id: {0}", show.Id), true); Thread.Sleep(2000); continue; } if (importCancelled) { return; } UIUtils.UpdateStatus("[{0}/{1}] Requesting episode ratings for {2} from theTVDb.com", iCounter, showRatings.Shows.Count, showInfo.Show.Name); // get episode ratings for each show in showratings TVDbEpisodeRatings episodeRatings = TVDbAPI.GetEpisodeRatings(accountId, show.Id.ToString()); if (episodeRatings == null) { UIUtils.UpdateStatus(string.Format("Unable to get episode ratings for {0} [{1}] from theTVDb.com", showInfo.Show.Name, show.Id), true); Thread.Sleep(2000); continue; } if (importCancelled) { return; } UIUtils.UpdateStatus("Found {0} episode ratings for {1} on theTVDb.com", episodeRatings.Episodes.Count, showInfo.Show.Name); if (currentUserEpisodeRatings != null) { UIUtils.UpdateStatus("Filtering out {0} tvdb episode ratings that already exist at trakt.tv", showInfo.Show.Name); // Filter out episodes to rate from existing ratings online, using tvdb episode id's episodeRatings.Episodes.RemoveAll(e => currentUserEpisodeRatings.Any(c => ((c.Episode.Ids.TvdbId == e.Id)))); } UIUtils.UpdateStatus("[{0}/{1}] Importing {2} episode ratings for {3}", iCounter, showRatings.Shows.Count, episodeRatings.Episodes.Count, showInfo.Show.Name); if (episodeRatings.Episodes.Count == 0) { continue; } // submit one series at a time var episodesToRate = GetRateEpisodeData(episodeRatings); var response = TraktAPI.AddsEpisodesToRatings(episodesToRate); if (response == null) { UIUtils.UpdateStatus(string.Format("Error importing {0} episode ratings to trakt.tv", showInfo.Show.Name), true); Thread.Sleep(2000); continue; } else if (response.NotFound.Episodes.Count > 0) { UIUtils.UpdateStatus("[{0}/{1}] Unable to sync ratings for {2} episodes of {3} as they're not found on trakt.tv!", iCounter, showRatings.Shows.Count, response.NotFound.Episodes.Count, showInfo.Show.Name); Thread.Sleep(1000); } episodesRated.Add(showInfo.Show.Name, episodesToRate.Episodes); } #endregion #region Mark As Watched if (AppSettings.MarkAsWatched && episodesRated.Any()) { int i = 0; foreach (var show in episodesRated) { if (importCancelled) { return; } // mark all episodes as watched if rated UIUtils.UpdateStatus("[{0}/{1}] Importing {2} TVDb episodes of {3} as watched to trakt.tv...", ++i, episodesRated.Count, show.Value.Count, show.Key); var watchedEpisodes = GetWatchedEpisodeData(show.Value); var response = TraktAPI.AddEpisodesToWatchedHistory(watchedEpisodes); if (response == null) { UIUtils.UpdateStatus(string.Format("Failed to send watched status for TVDb '{0}' episodes", show.Key), true); Thread.Sleep(2000); } else if (response.NotFound.Episodes.Count > 0) { UIUtils.UpdateStatus("[{0}/{1}] Unable to sync {2} TVDb episodes of {3} as watched as they're not found on trakt.tv!", i, episodesRated.Count, response.NotFound.Episodes.Count, show.Key); Thread.Sleep(1000); } } } #endregion }
public void ImportRatings() { var lRateItems = new List <Dictionary <string, string> >(); var lWatchedItems = new List <Dictionary <string, string> >(); var lDiaryItems = new List <Dictionary <string, string> >(); mImportCancelled = false; #region Parse Ratings CSV UIUtils.UpdateStatus("Reading Letterboxd ratings export..."); if (mImportRatings && !ParseCSVFile(mLetterboxdRatingsFile, out lRateItems)) { UIUtils.UpdateStatus("Failed to parse Letterboxd ratings file!", true); Thread.Sleep(2000); return; } if (mImportCancelled) { return; } #endregion #region Parse Watched CSV UIUtils.UpdateStatus("Reading Letterboxd watched export..."); if (mImportWatched && !ParseCSVFile(mLetterboxdWatchedFile, out lWatchedItems)) { UIUtils.UpdateStatus("Failed to parse Letterboxd watched file!", true); Thread.Sleep(2000); return; } if (mImportCancelled) { return; } #endregion #region Parse Diary CSV UIUtils.UpdateStatus("Reading Letterboxd diary export..."); if (mImportDiary && !ParseCSVFile(mLetterboxdDiaryFile, out lDiaryItems)) { UIUtils.UpdateStatus("Failed to parse Letterboxd diary file!", true); Thread.Sleep(2000); return; } if (mImportCancelled) { return; } #endregion #region Import Rated Movies FileLog.Info("Found {0} movie ratings in CSV file", lRateItems.Count); if (lRateItems.Any()) { UIUtils.UpdateStatus("Retrieving existing movie ratings from trakt.tv"); var currentUserMovieRatings = TraktAPI.GetRatedMovies(); if (currentUserMovieRatings != null) { UIUtils.UpdateStatus("Found {0} user movie ratings on trakt.tv", currentUserMovieRatings.Count()); // Filter out movies to rate from existing ratings online lRateItems.RemoveAll(m => currentUserMovieRatings.Any(c => c.Movie.Title == m[LetterboxdFieldMapping.cTitle] && c.Movie.Year.ToString() == m[LetterboxdFieldMapping.cYear])); } UIUtils.UpdateStatus("Importing {0} new movie ratings to trakt.tv", lRateItems.Count()); if (lRateItems.Count > 0) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)lRateItems.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} Letterboxd rated movies...", i + 1, pages); TraktSyncResponse response = TraktAPI.AddMoviesToRatings(GetRateMoviesData(lRateItems.Skip(i * pageSize).Take(pageSize))); if (response == null) { UIUtils.UpdateStatus("Error importing Letterboxd movie ratings to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus("Unable to sync Letterboxd ratings for {0} movies as they're not found on trakt.tv!", response.NotFound.Movies.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } if (mImportCancelled) { return; } #endregion #region Import Watched Movies // The Dairy can can include rated and watched items, it also has a watched date // if the watched movie exists in the diary use that as a watched date otherwise use date from watched file // add to diary any watched films that have been back filled foreach (var movie in lWatchedItems) { if (!lDiaryItems.Exists(d => d[LetterboxdFieldMapping.cTitle] == movie[LetterboxdFieldMapping.cTitle] && d[LetterboxdFieldMapping.cYear] == movie[LetterboxdFieldMapping.cYear])) { lDiaryItems.Add(movie); } } if (lDiaryItems.Count > 0) { // get watched movies from trakt.tv UIUtils.UpdateStatus("Requesting watched movies from trakt..."); var watchedTraktMovies = TraktAPI.GetWatchedMovies(); if (watchedTraktMovies == null) { UIUtils.UpdateStatus("Failed to get watched movies from trakt.tv, skipping watched movie import", true); Thread.Sleep(2000); } else { if (mImportCancelled) { return; } UIUtils.UpdateStatus("Found {0} watched movies on trakt", watchedTraktMovies.Count()); UIUtils.UpdateStatus("Filtering out watched movies that are already watched on trakt.tv"); lDiaryItems.RemoveAll(d => watchedTraktMovies.FirstOrDefault(t => t.Movie.Title == d[LetterboxdFieldMapping.cTitle] && t.Movie.Year.ToString() == d[LetterboxdFieldMapping.cYear]) != null); UIUtils.UpdateStatus("Importing {0} Letterboxd movies as watched...", lDiaryItems.Count); int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)lDiaryItems.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} Letterboxd movies as watched...", i + 1, pages); var response = TraktAPI.AddMoviesToWatchedHistory(GetSyncWatchedMoviesData(lDiaryItems.Skip(i * pageSize).Take(pageSize).ToList())); if (response == null) { UIUtils.UpdateStatus("Failed to send watched status for Letterboxd movies to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus("Unable to sync Letterboxd watched states for {0} movies as they're not found on trakt.tv!", response.NotFound.Movies.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } #endregion return; }
public void SyncLibrary() { TraktLogger.Info("My Videos Starting Sync"); if (TraktSettings.SyncLibrary) { // get all movies ArrayList myvideos = new ArrayList(); VideoDatabase.GetMovies(ref myvideos); List <IMDBMovie> MovieList = (from IMDBMovie movie in myvideos select movie).ToList(); #region Remove Blocked Movies MovieList.RemoveAll(m => TraktSettings.BlockedFolders.Any(f => m.Path.ToLowerInvariant().Contains(f.ToLowerInvariant()))); List <int> blockedMovieIds = new List <int>(); foreach (string file in TraktSettings.BlockedFilenames) { int pathId = 0; int movieId = 0; // get a list of ids for blocked filenames // filename seems to always be empty for an IMDBMovie object! if (VideoDatabase.GetFile(file, out pathId, out movieId, false) > 0) { blockedMovieIds.Add(movieId); } } MovieList.RemoveAll(m => blockedMovieIds.Contains(m.ID)); #endregion #region Skipped Movies Check // Remove Skipped Movies from previous Sync if (TraktSettings.SkippedMovies != null) { // allow movies to re-sync again after 7-days in the case user has addressed issue ie. edited movie or added to themoviedb.org if (TraktSettings.SkippedMovies.LastSkippedSync.FromEpoch() > DateTime.UtcNow.Subtract(new TimeSpan(7, 0, 0, 0))) { if (TraktSettings.SkippedMovies.Movies != null && TraktSettings.SkippedMovies.Movies.Count > 0) { TraktLogger.Info("Skipping {0} movies due to invalid data or movies don't exist on http://themoviedb.org. Next check will be {1}.", TraktSettings.SkippedMovies.Movies.Count, TraktSettings.SkippedMovies.LastSkippedSync.FromEpoch().Add(new TimeSpan(7, 0, 0, 0))); foreach (var movie in TraktSettings.SkippedMovies.Movies) { TraktLogger.Info("Skipping movie, Title: {0}, Year: {1}, IMDb: {2}", movie.Title, movie.Year, movie.IMDBID); MovieList.RemoveAll(m => (m.Title == movie.Title) && (m.Year.ToString() == movie.Year) && (m.IMDBNumber == movie.IMDBID)); } } } else { if (TraktSettings.SkippedMovies.Movies != null) { TraktSettings.SkippedMovies.Movies.Clear(); } TraktSettings.SkippedMovies.LastSkippedSync = DateTime.UtcNow.ToEpoch(); } } #endregion #region Already Exists Movie Check // Remove Already-Exists Movies, these are typically movies that are using aka names and no IMDb/TMDb set // When we compare our local collection with trakt collection we have english only titles, so if no imdb/tmdb exists // we need to fallback to title matching. When we sync aka names are sometimes accepted if defined on themoviedb.org so we need to // do this to revent syncing these movies every sync interval. if (TraktSettings.AlreadyExistMovies != null && TraktSettings.AlreadyExistMovies.Movies != null && TraktSettings.AlreadyExistMovies.Movies.Count > 0) { TraktLogger.Debug("Skipping {0} movies as they already exist in trakt library but failed local match previously.", TraktSettings.AlreadyExistMovies.Movies.Count.ToString()); var movies = new List <TraktMovieSync.Movie>(TraktSettings.AlreadyExistMovies.Movies); foreach (var movie in movies) { Predicate <IMDBMovie> criteria = m => (m.Title == movie.Title) && (m.Year.ToString() == movie.Year) && (m.IMDBNumber == movie.IMDBID); if (MovieList.Exists(criteria)) { TraktLogger.Debug("Skipping movie, Title: {0}, Year: {1}, IMDb: {2}", movie.Title, movie.Year, movie.IMDBID); MovieList.RemoveAll(criteria); } else { // remove as we have now removed from our local collection or updated movie signature if (TraktSettings.MoviePluginCount == 1) { TraktLogger.Debug("Removing 'AlreadyExists' movie, Title: {0}, Year: {1}, IMDb: {2}", movie.Title, movie.Year, movie.IMDBID); TraktSettings.AlreadyExistMovies.Movies.Remove(movie); } } } } #endregion TraktLogger.Info("{0} movies available to sync in My Videos database", MovieList.Count.ToString()); // get the movies that we have watched List <IMDBMovie> SeenList = MovieList.Where(m => m.Watched > 0).ToList(); TraktLogger.Info("{0} watched movies available to sync in My Videos database", SeenList.Count.ToString()); // get the movies that we have yet to watch TraktLogger.Info("Getting user {0}'s movies from trakt", TraktSettings.Username); IEnumerable <TraktLibraryMovies> traktMoviesAll = TraktAPI.TraktAPI.GetAllMoviesForUser(TraktSettings.Username); if (traktMoviesAll == null) { TraktLogger.Error("Error getting movies from trakt server, cancelling sync."); return; } TraktLogger.Info("{0} movies in trakt library", traktMoviesAll.Count().ToString()); #region Movies to Sync to Collection List <IMDBMovie> moviesToSync = new List <IMDBMovie>(MovieList); List <TraktLibraryMovies> NoLongerInOurCollection = new List <TraktLibraryMovies>(); //Filter out a list of movies we have already sync'd in our collection foreach (TraktLibraryMovies tlm in traktMoviesAll) { bool notInLocalCollection = true; // if it is in both libraries foreach (IMDBMovie libraryMovie in MovieList.Where(m => MovieMatch(m, tlm))) { // If the users IMDb Id is empty/invalid and we have matched one then set it if (BasicHandler.IsValidImdb(tlm.IMDBID) && !BasicHandler.IsValidImdb(libraryMovie.IMDBNumber)) { TraktLogger.Info("Movie '{0}' inserted IMDb Id '{1}'", libraryMovie.Title, tlm.IMDBID); libraryMovie.IMDBNumber = tlm.IMDBID; IMDBMovie details = libraryMovie; VideoDatabase.SetMovieInfoById(libraryMovie.ID, ref details); } // if it is watched in Trakt but not My Videos update // skip if movie is watched but user wishes to have synced as unseen locally if (tlm.Plays > 0 && !tlm.UnSeen && libraryMovie.Watched == 0) { TraktLogger.Info("Movie '{0}' is watched on Trakt updating Database", libraryMovie.Title); libraryMovie.Watched = 1; if (libraryMovie.DateWatched == "0001-01-01 00:00:00") { libraryMovie.DateWatched = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); } IMDBMovie details = libraryMovie; VideoDatabase.SetMovieInfoById(libraryMovie.ID, ref details); if (libraryMovie.WatchedCount == 0) { VideoDatabase.SetMovieWatchedCount(libraryMovie.ID, tlm.Plays); VideoDatabase.SetMovieWatchedStatus(libraryMovie.ID, true, 0); } } // mark movies as unseen if watched locally if (tlm.UnSeen && libraryMovie.Watched > 0) { TraktLogger.Info("Movie '{0}' is unseen on Trakt, updating database", libraryMovie.Title); libraryMovie.Watched = 0; IMDBMovie details = libraryMovie; VideoDatabase.SetMovieInfoById(libraryMovie.ID, ref details); VideoDatabase.SetMovieWatchedStatus(libraryMovie.ID, false, 0); } notInLocalCollection = false; //filter out if its already in collection if (tlm.InCollection) { moviesToSync.RemoveAll(m => MovieMatch(m, tlm)); } break; } if (notInLocalCollection && tlm.InCollection) { NoLongerInOurCollection.Add(tlm); } } #endregion #region Movies to Sync to Seen Collection // filter out a list of movies already marked as watched on trakt // also filter out movie marked as unseen so we dont reset the unseen cache online List <IMDBMovie> watchedMoviesToSync = new List <IMDBMovie>(SeenList); foreach (TraktLibraryMovies tlm in traktMoviesAll.Where(t => t.Plays > 0 || t.UnSeen)) { foreach (IMDBMovie watchedMovie in SeenList.Where(m => MovieMatch(m, tlm))) { //filter out watchedMoviesToSync.Remove(watchedMovie); } } #endregion #region Sync Collection to trakt //Send Library/Collection TraktLogger.Info("{0} movies need to be added to Library", moviesToSync.Count.ToString()); foreach (IMDBMovie m in moviesToSync) { TraktLogger.Info("Sending movie to trakt library, Title: {0}, Year: {1}, IMDb: {2}", m.Title, m.Year.ToString(), m.IMDBNumber); } if (moviesToSync.Count > 0) { TraktSyncResponse response = TraktAPI.TraktAPI.SyncMovieLibrary(CreateSyncData(moviesToSync), TraktSyncModes.library); BasicHandler.InsertSkippedMovies(response); BasicHandler.InsertAlreadyExistMovies(response); TraktLogger.LogTraktResponse(response); } #endregion #region Sync Seen to trakt //Send Seen TraktLogger.Info("{0} movies need to be added to SeenList", watchedMoviesToSync.Count.ToString()); foreach (IMDBMovie m in watchedMoviesToSync) { TraktLogger.Info("Sending movie to trakt as seen, Title: {0}, Year: {1}, IMDb: {2}", m.Title, m.Year.ToString(), m.IMDBNumber); } if (watchedMoviesToSync.Count > 0) { TraktSyncResponse response = TraktAPI.TraktAPI.SyncMovieLibrary(CreateSyncData(watchedMoviesToSync), TraktSyncModes.seen); BasicHandler.InsertSkippedMovies(response); BasicHandler.InsertAlreadyExistMovies(response); TraktLogger.LogTraktResponse(response); } #endregion #region Clean Library //Dont clean library if more than one movie plugin installed if (TraktSettings.KeepTraktLibraryClean && TraktSettings.MoviePluginCount == 1) { //Remove movies we no longer have in our local database from Trakt foreach (var m in NoLongerInOurCollection) { TraktLogger.Info("Removing from Trakt Collection {0}", m.Title); } TraktLogger.Info("{0} movies need to be removed from Trakt Collection", NoLongerInOurCollection.Count.ToString()); if (NoLongerInOurCollection.Count > 0) { if (TraktSettings.AlreadyExistMovies != null && TraktSettings.AlreadyExistMovies.Movies != null && TraktSettings.AlreadyExistMovies.Movies.Count > 0) { TraktLogger.Warning("DISABLING CLEAN LIBRARY!!!, there are trakt library movies that can't be determined to be local in collection."); TraktLogger.Warning("To fix this, check the 'already exist' entries in log, then check movies in local collection against this list and ensure IMDb id is set then run sync again."); } else { //Then remove from library TraktSyncResponse response = TraktAPI.TraktAPI.SyncMovieLibrary(BasicHandler.CreateMovieSyncData(NoLongerInOurCollection), TraktSyncModes.unlibrary); TraktLogger.LogTraktResponse(response); } } } #endregion } TraktLogger.Info("My Videos Sync Completed"); }
public void SyncLibrary() { TraktLogger.Info("My Films Starting Sync"); SyncInProgress = true; // get all movies ArrayList myvideos = new ArrayList(); BaseMesFilms.GetMovies(ref myvideos); TraktLogger.Info("BaseMesFilms.GetMovies: returning " + myvideos.Count + " movies"); List <MFMovie> MovieList = (from MFMovie movie in myvideos select movie).ToList(); // Remove any blocked movies MovieList.RemoveAll(movie => TraktSettings.BlockedFolders.Any(f => movie.File.ToLowerInvariant().Contains(f.ToLowerInvariant()))); MovieList.RemoveAll(movie => TraktSettings.BlockedFilenames.Contains(movie.File)); #region Skipped Movies Check // Remove Skipped Movies from previous Sync if (TraktSettings.SkippedMovies != null) { // allow movies to re-sync again after 7-days in the case user has addressed issue ie. edited movie or added to themoviedb.org if (TraktSettings.SkippedMovies.LastSkippedSync.FromEpoch() > DateTime.UtcNow.Subtract(new TimeSpan(7, 0, 0, 0))) { if (TraktSettings.SkippedMovies.Movies != null && TraktSettings.SkippedMovies.Movies.Count > 0) { TraktLogger.Info("Skipping {0} movies due to invalid data or movies don't exist on http://themoviedb.org. Next check will be {1}.", TraktSettings.SkippedMovies.Movies.Count, TraktSettings.SkippedMovies.LastSkippedSync.FromEpoch().Add(new TimeSpan(7, 0, 0, 0))); foreach (var movie in TraktSettings.SkippedMovies.Movies) { TraktLogger.Info("Skipping movie, Title: {0}, Year: {1}, IMDb: {2}", movie.Title, movie.Year, movie.IMDBID); MovieList.RemoveAll(m => (m.Title == movie.Title) && (m.Year.ToString() == movie.Year) && (m.IMDBNumber == movie.IMDBID)); } } } else { if (TraktSettings.SkippedMovies.Movies != null) { TraktSettings.SkippedMovies.Movies.Clear(); } TraktSettings.SkippedMovies.LastSkippedSync = DateTime.UtcNow.ToEpoch(); } } #endregion #region Already Exists Movie Check // Remove Already-Exists Movies, these are typically movies that are using aka names and no IMDb/TMDb set // When we compare our local collection with trakt collection we have english only titles, so if no imdb/tmdb exists // we need to fallback to title matching. When we sync aka names are sometimes accepted if defined on themoviedb.org so we need to // do this to revent syncing these movies every sync interval. if (TraktSettings.AlreadyExistMovies != null && TraktSettings.AlreadyExistMovies.Movies != null && TraktSettings.AlreadyExistMovies.Movies.Count > 0) { TraktLogger.Debug("Skipping {0} movies as they already exist in trakt library but failed local match previously.", TraktSettings.AlreadyExistMovies.Movies.Count.ToString()); var movies = new List <TraktMovieSync.Movie>(TraktSettings.AlreadyExistMovies.Movies); foreach (var movie in movies) { Predicate <MFMovie> criteria = m => (m.Title == movie.Title) && (m.Year.ToString() == movie.Year) && (m.IMDBNumber == movie.IMDBID); if (MovieList.Exists(criteria)) { TraktLogger.Debug("Skipping movie, Title: {0}, Year: {1}, IMDb: {2}", movie.Title, movie.Year, movie.IMDBID); MovieList.RemoveAll(criteria); } else { // remove as we have now removed from our local collection or updated movie signature if (TraktSettings.MoviePluginCount == 1) { TraktLogger.Debug("Removing 'AlreadyExists' movie, Title: {0}, Year: {1}, IMDb: {2}", movie.Title, movie.Year, movie.IMDBID); TraktSettings.AlreadyExistMovies.Movies.Remove(movie); } } } } #endregion TraktLogger.Info("{0} movies available to sync in MyFilms database(s)", MovieList.Count.ToString()); // get the movies that we have watched List <MFMovie> SeenList = MovieList.Where(m => m.Watched == true).ToList(); TraktLogger.Info("{0} watched movies available to sync in MyFilms database(s)", SeenList.Count.ToString()); // get the movies that we have yet to watch IEnumerable <TraktLibraryMovies> traktMoviesAll = TraktAPI.TraktAPI.GetAllMoviesForUser(TraktSettings.Username); if (traktMoviesAll == null) { SyncInProgress = false; TraktLogger.Error("Error getting movies from trakt server, cancelling sync."); return; } TraktLogger.Info("{0} movies in trakt library", traktMoviesAll.Count().ToString()); #region Movies to Sync to Collection List <MFMovie> moviesToSync = new List <MFMovie>(MovieList); List <TraktLibraryMovies> NoLongerInOurCollection = new List <TraktLibraryMovies>(); //Filter out a list of movies we have already sync'd in our collection foreach (TraktLibraryMovies tlm in traktMoviesAll) { bool notInLocalCollection = true; // if it is in both libraries foreach (MFMovie libraryMovie in MovieList.Where(m => MovieMatch(m, tlm))) { // If the users IMDb Id is empty/invalid and we have matched one then set it if (BasicHandler.IsValidImdb(tlm.IMDBID) && !BasicHandler.IsValidImdb(libraryMovie.IMDBNumber)) { TraktLogger.Info("Movie '{0}' inserted IMDb Id '{1}'", libraryMovie.Title, tlm.IMDBID); libraryMovie.IMDBNumber = tlm.IMDBID; libraryMovie.Username = TraktSettings.Username; libraryMovie.Commit(); } // If the users TMDb Id is empty/invalid and we have one then set it if (string.IsNullOrEmpty(libraryMovie.TMDBNumber) && !string.IsNullOrEmpty(tlm.TMDBID)) { TraktLogger.Info("Movie '{0}' inserted TMDb Id '{1}'", libraryMovie.Title, tlm.TMDBID); libraryMovie.TMDBNumber = tlm.TMDBID; libraryMovie.Username = TraktSettings.Username; libraryMovie.Commit(); } // if it is watched in Trakt but not My Films update // skip if movie is watched but user wishes to have synced as unseen locally if (tlm.Plays > 0 && !tlm.UnSeen && libraryMovie.Watched == false) { TraktLogger.Info("Movie '{0}' is watched on Trakt updating Database", libraryMovie.Title); libraryMovie.Watched = true; libraryMovie.WatchedCount = tlm.Plays; libraryMovie.Username = TraktSettings.Username; libraryMovie.Commit(); } // mark movies as unseen if watched locally if (tlm.UnSeen && libraryMovie.Watched == true) { TraktLogger.Info("Movie '{0}' is unseen on Trakt, updating database", libraryMovie.Title); libraryMovie.Watched = false; libraryMovie.WatchedCount = tlm.Plays; libraryMovie.Username = TraktSettings.Username; libraryMovie.Commit(); } notInLocalCollection = false; //filter out if its already in collection if (tlm.InCollection) { moviesToSync.RemoveAll(m => MovieMatch(m, tlm)); } break; } if (notInLocalCollection && tlm.InCollection) { NoLongerInOurCollection.Add(tlm); } } #endregion #region Movies to Sync to Seen Collection // filter out a list of movies already marked as watched on trakt // also filter out movie marked as unseen so we dont reset the unseen cache online List <MFMovie> watchedMoviesToSync = new List <MFMovie>(SeenList); foreach (TraktLibraryMovies tlm in traktMoviesAll.Where(t => t.Plays > 0 || t.UnSeen)) { foreach (MFMovie watchedMovie in SeenList.Where(m => MovieMatch(m, tlm))) { //filter out watchedMoviesToSync.Remove(watchedMovie); } } #endregion #region Send Library/Collection TraktLogger.Info("{0} movies need to be added to Library", moviesToSync.Count.ToString()); foreach (MFMovie m in moviesToSync) { TraktLogger.Info("Sending movie to trakt library, Title: {0}, Year: {1}, IMDb: {2}, TMDb: {3}", m.Title, m.Year.ToString(), m.IMDBNumber, m.TMDBNumber); } if (moviesToSync.Count > 0) { TraktSyncResponse response = TraktAPI.TraktAPI.SyncMovieLibrary(CreateSyncData(moviesToSync), TraktSyncModes.library); BasicHandler.InsertSkippedMovies(response); BasicHandler.InsertAlreadyExistMovies(response); TraktAPI.TraktAPI.LogTraktResponse(response); } #endregion #region Send Seen TraktLogger.Info("{0} movies need to be added to SeenList", watchedMoviesToSync.Count.ToString()); foreach (MFMovie m in watchedMoviesToSync) { TraktLogger.Info("Sending movie to trakt as seen, Title: {0}, Year: {1}, IMDb: {2}, TMDb: {3}", m.Title, m.Year.ToString(), m.IMDBNumber, m.TMDBNumber); } if (watchedMoviesToSync.Count > 0) { TraktSyncResponse response = TraktAPI.TraktAPI.SyncMovieLibrary(CreateSyncData(watchedMoviesToSync), TraktSyncModes.seen); BasicHandler.InsertSkippedMovies(response); BasicHandler.InsertAlreadyExistMovies(response); TraktAPI.TraktAPI.LogTraktResponse(response); } #endregion #region Ratings Sync // only sync ratings if we are using Advanced Ratings if (TraktSettings.SyncRatings) { var traktRatedMovies = TraktAPI.TraktAPI.GetUserRatedMovies(TraktSettings.Username); if (traktRatedMovies == null) { TraktLogger.Error("Error getting rated movies from trakt server."); } else { TraktLogger.Info("{0} rated movies in trakt library", traktRatedMovies.Count().ToString()); } if (traktRatedMovies != null) { // get the movies that we have rated/unrated var RatedList = MovieList.Where(m => m.RatingUser > 0.0).ToList(); var UnRatedList = MovieList.Except(RatedList).ToList(); TraktLogger.Info("{0} rated movies available to sync in MyFilms database", RatedList.Count.ToString()); List <MFMovie> ratedMoviesToSync = new List <MFMovie>(RatedList); foreach (var trm in traktRatedMovies) { foreach (var movie in UnRatedList.Where(m => MovieMatch(m, trm))) { // update local collection rating TraktLogger.Info("Inserting rating '{0}/10' for movie '{1} ({2})'", trm.RatingAdvanced, movie.Title, movie.Year); movie.RatingUser = trm.RatingAdvanced; movie.Username = TraktSettings.Username; movie.Commit(); } foreach (var movie in RatedList.Where(m => MovieMatch(m, trm))) { // if rating is not synced, update local collection rating to get in sync if ((int)movie.RatingUser != trm.RatingAdvanced) { TraktLogger.Info("Updating rating '{0}/10' for movie '{1} ({2})'", trm.RatingAdvanced, movie.Title, movie.Year); movie.RatingUser = trm.RatingAdvanced; movie.Username = TraktSettings.Username; movie.Commit(); } // already rated on trakt, so remove from sync collection ratedMoviesToSync.Remove(movie); } } TraktLogger.Info("{0} rated movies to sync to trakt", ratedMoviesToSync.Count); if (ratedMoviesToSync.Count > 0) { ratedMoviesToSync.ForEach(a => TraktLogger.Info("Importing rating '{0}/10' for movie '{1} ({2})'", a.RatingUser, a.Title, a.Year)); TraktResponse response = TraktAPI.TraktAPI.RateMovies(CreateRatingMoviesData(ratedMoviesToSync)); TraktAPI.TraktAPI.LogTraktResponse(response); } } } #endregion #region Clean Library //Dont clean library if more than one movie plugin installed if (TraktSettings.KeepTraktLibraryClean && TraktSettings.MoviePluginCount == 1) { //Remove movies we no longer have in our local database from Trakt foreach (var m in NoLongerInOurCollection) { TraktLogger.Info("Removing from Trakt Collection {0}", m.Title); } TraktLogger.Info("{0} movies need to be removed from Trakt Collection", NoLongerInOurCollection.Count.ToString()); if (NoLongerInOurCollection.Count > 0) { if (TraktSettings.AlreadyExistMovies != null && TraktSettings.AlreadyExistMovies.Movies != null && TraktSettings.AlreadyExistMovies.Movies.Count > 0) { TraktLogger.Warning("DISABLING CLEAN LIBRARY!!!, there are trakt library movies that can't be determined to be local in collection."); TraktLogger.Warning("To fix this, check the 'already exist' entries in log, then check movies in local collection against this list and ensure IMDb id is set then run sync again."); } else { //Then remove from library TraktSyncResponse response = TraktAPI.TraktAPI.SyncMovieLibrary(BasicHandler.CreateMovieSyncData(NoLongerInOurCollection), TraktSyncModes.unlibrary); TraktAPI.TraktAPI.LogTraktResponse(response); } } } #endregion #region Trakt Category Tags List <MFMovie> movieListAll = (from MFMovie movie in myvideos select movie).ToList(); // Add tags also to blocked movies, as it is only local // get the movies that locally have trakt categories var categoryTraktList = movieListAll.Where(m => m.CategoryTrakt.Count > 0).ToList(); if (TraktSettings.MyFilmsCategories) { TraktLogger.Info("{0} trakt-categorized movies available in MyFilms database", categoryTraktList.Count.ToString()); #region update watchlist tags IEnumerable <TraktWatchListMovie> traktWatchListMovies = null; string Watchlist = Translation.WatchList; TraktLogger.Info("Retrieving watchlist from trakt"); traktWatchListMovies = TraktAPI.TraktAPI.GetWatchListMovies(TraktSettings.Username); if (traktWatchListMovies != null) { TraktLogger.Info("Retrieved {0} watchlist items from trakt", traktWatchListMovies.Count()); var cleanupList = movieListAll.Where(m => m.CategoryTrakt.Contains(Watchlist)).ToList(); foreach (var trm in traktWatchListMovies) { TraktLogger.Debug("Processing trakt watchlist movie - Title '{0}', Year '{1}' Imdb '{2}'", trm.Title ?? "null", trm.Year, trm.IMDBID ?? "null"); foreach (var movie in movieListAll.Where(m => MovieMatch(m, trm))) { if (!movie.CategoryTrakt.Contains(Watchlist)) { TraktLogger.Info("Inserting trakt category '{0}' for movie '{1} ({2})'", Watchlist, movie.Title, movie.Year); movie.CategoryTrakt.Add(Watchlist); movie.Username = TraktSettings.Username; movie.Commit(); } cleanupList.Remove(movie); } } // remove tag from remaining films foreach (var movie in cleanupList) { TraktLogger.Info("Removing trakt category '{0}' for movie '{1} ({2})'", Watchlist, movie.Title, movie.Year); movie.CategoryTrakt.Remove(Watchlist); movie.Username = TraktSettings.Username; movie.Commit(); } } #endregion #region update user list tags IEnumerable <TraktUserList> traktUserLists = null; string Userlist = Translation.List; TraktLogger.Info("Retrieving user lists from trakt"); traktUserLists = TraktAPI.TraktAPI.GetUserLists(TraktSettings.Username); if (traktUserLists != null) { TraktLogger.Info("Retrieved {0} user lists from trakt", traktUserLists.Count()); foreach (TraktUserList traktUserList in traktUserLists) { TraktUserList traktUserListMovies = TraktAPI.TraktAPI.GetUserList(TraktSettings.Username, traktUserList.Slug); if (traktUserListMovies == null) { continue; } string userListName = Userlist + ": " + traktUserList.Name; var cleanupList = movieListAll.Where(m => m.CategoryTrakt.Contains(userListName)).ToList(); TraktLogger.Info("Processing trakt user list '{0}' as tag '{1}' with '{2}' items", traktUserList.Name, userListName, traktUserListMovies.Items.Count); // process 'movies' only foreach (var trm in traktUserListMovies.Items.Where(m => m.Type == "movie")) { TraktLogger.Debug("Processing trakt user list movie - Title '{0}', Year '{1}' ImdbId '{2}'", trm.Title ?? "null", trm.Year ?? "null", trm.ImdbId ?? "null"); foreach (var movie in movieListAll.Where(m => MovieMatch(m, trm.Movie))) { if (!movie.CategoryTrakt.Contains(userListName)) { // update local trakt category TraktLogger.Info("Inserting trakt user list '{0}' for movie '{1} ({2})'", userListName, movie.Title, movie.Year); movie.CategoryTrakt.Add(userListName); movie.Username = TraktSettings.Username; movie.Commit(); } cleanupList.Remove(movie); } } // remove tag from remaining films foreach (var movie in cleanupList) { TraktLogger.Info("Removing trakt user list '{0}' for movie '{1} ({2})'", userListName, movie.Title, movie.Year); movie.CategoryTrakt.Remove(userListName); movie.Username = TraktSettings.Username; movie.Commit(); } } } #endregion #region update recommendation tags IEnumerable <TraktMovie> traktRecommendationMovies = null; string Recommendations = Translation.Recommendations; TraktLogger.Info("Retrieving recommendations from trakt"); traktRecommendationMovies = TraktAPI.TraktAPI.GetRecommendedMovies(); if (traktRecommendationMovies != null) { TraktLogger.Info("Retrieved {0} recommendations items from trakt", traktRecommendationMovies.Count()); var cleanupList = movieListAll.Where(m => m.CategoryTrakt.Contains(Recommendations)).ToList(); foreach (var trm in traktRecommendationMovies) { TraktLogger.Debug("Processing trakt recommendations movie - Title '{0}', Year '{1}' Imdb '{2}'", trm.Title ?? "null", trm.Year ?? "null", trm.IMDBID ?? "null"); foreach (var movie in movieListAll.Where(m => MovieMatch(m, trm))) { if (!movie.CategoryTrakt.Contains(Recommendations)) { // update local trakt category TraktLogger.Info("Inserting trakt category '{0}' for movie '{1} ({2})'", Recommendations, movie.Title, movie.Year); movie.CategoryTrakt.Add(Recommendations); movie.Username = TraktSettings.Username; movie.Commit(); } cleanupList.Remove(movie); } } // remove tag from remaining films foreach (var movie in cleanupList) { // update local trakt category TraktLogger.Info("Removing trakt category '{0}' for movie '{1} ({2})'", Recommendations, movie.Title, movie.Year); movie.CategoryTrakt.Remove(Recommendations); movie.Username = TraktSettings.Username; movie.Commit(); } } #endregion #region update trending tags /*IEnumerable<TraktTrendingMovie> traktTrendingMovies = null; * string Trending = Translation.Trending; * TraktLogger.Info("Retrieving trending movies from trakt"); * traktTrendingMovies = TraktAPI.TraktAPI.GetTrendingMovies(); * * if (traktTrendingMovies != null) * { * TraktLogger.Info("Retrieved {0} trending items from trakt", traktTrendingMovies.Count()); * * var cleanupList = movieListAll.Where(m => m.CategoryTrakt.Contains(Trending)).ToList(); * foreach (var trm in traktTrendingMovies) * { * TraktLogger.Debug("Processing trakt user list movie trm.Title '{0}', trm.Year '{1}' trm.Imdb '{2}'", trm.Title ?? "null", trm.Year ?? "null", trm.Imdb ?? "null"); * foreach (var movie in movieListAll.Where(m => MovieMatch(m, trm))) * { * if (!movie.CategoryTrakt.Contains(Trending)) * { * // update local trakt category * TraktLogger.Info("Inserting trakt category '{0}' for movie '{1} ({2})'", Trending, movie.Title, movie.Year); * movie.CategoryTrakt.Add(Trending); * movie.Username = TraktSettings.Username; * movie.Commit(); * } * cleanupList.Remove(movie); * } * } * // remove tag from remaining films * foreach (var movie in cleanupList) * { * // update local trakt category * TraktLogger.Info("Removing trakt category '{0}' for movie '{1} ({2})'", Trending, movie.Title, movie.Year); * movie.CategoryTrakt.Remove(Trending); * movie.Username = TraktSettings.Username; * movie.Commit(); * } * }*/ #endregion } else { if (categoryTraktList.Count > 0) { TraktLogger.Info("clearing trakt-categorized movies from MyFilms database", categoryTraktList.Count.ToString()); foreach (var movie in categoryTraktList) { movie.CategoryTrakt.Clear(); movie.Commit(); } } } #endregion myvideos.Clear(); SyncInProgress = false; TraktLogger.Info("My Films Sync Completed"); }
public void ImportRatings() { var lRateItems = new List <Dictionary <string, string> >(); var lWatchedItems = new List <Dictionary <string, string> >(); var lDiaryItems = new List <Dictionary <string, string> >(); var lCustomLists = new Dictionary <string, List <LetterboxdListItem> >(); mImportCancelled = false; #region Parse Ratings CSV UIUtils.UpdateStatus("Reading Letterboxd ratings export..."); if (mImportRatings && !ParseCSVFile(mLetterboxdRatingsFile, out lRateItems)) { UIUtils.UpdateStatus("Failed to parse Letterboxd ratings file!", true); Thread.Sleep(2000); return; } if (mImportCancelled) { return; } #endregion #region Parse Watched CSV UIUtils.UpdateStatus("Reading Letterboxd watched export..."); if (mImportWatched && !ParseCSVFile(mLetterboxdWatchedFile, out lWatchedItems)) { UIUtils.UpdateStatus("Failed to parse Letterboxd watched file!", true); Thread.Sleep(2000); return; } if (mImportCancelled) { return; } #endregion #region Parse Diary CSV UIUtils.UpdateStatus("Reading Letterboxd diary export..."); if (mImportDiary && !ParseCSVFile(mLetterboxdDiaryFile, out lDiaryItems)) { UIUtils.UpdateStatus("Failed to parse Letterboxd diary file!", true); Thread.Sleep(2000); return; } if (mImportCancelled) { return; } #endregion #region Parse Custom List CSVs UIUtils.UpdateStatus("Reading Letterboxd custom lists export..."); if (mImportCustomLists) { mCsvConfiguration.RegisterClassMap <LetterboxdListCsvMap>(); foreach (var list in mCustomListsCsvs) { UIUtils.UpdateStatus($"Reading Letterboxd custom list '{list}'"); var lListCsvItems = ParseCsvFile <LetterboxdListItem>(list); if (lListCsvItems == null) { UIUtils.UpdateStatus("Failed to parse Letterboxd custom list file!", true); Thread.Sleep(2000); continue; } lCustomLists.Add(list, lListCsvItems); } mCsvConfiguration.UnregisterClassMap <LetterboxdListCsvMap>(); } if (mImportCancelled) { return; } #endregion #region Import Rated Movies FileLog.Info("Found {0} movie ratings in CSV file", lRateItems.Count); if (lRateItems.Any()) { UIUtils.UpdateStatus("Retrieving existing movie ratings from trakt.tv"); var currentUserMovieRatings = TraktAPI.GetRatedMovies(); if (currentUserMovieRatings != null) { UIUtils.UpdateStatus("Found {0} user movie ratings on trakt.tv", currentUserMovieRatings.Count()); // Filter out movies to rate from existing ratings online lRateItems.RemoveAll(m => currentUserMovieRatings.Any(c => c.Movie.Title == m[LetterboxdFieldMapping.cTitle] && c.Movie.Year.ToString() == m[LetterboxdFieldMapping.cYear])); } UIUtils.UpdateStatus("Importing {0} new movie ratings to trakt.tv", lRateItems.Count()); if (lRateItems.Count > 0) { int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)lRateItems.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} Letterboxd rated movies...", i + 1, pages); TraktSyncResponse response = TraktAPI.AddMoviesToRatings(GetRateMoviesData(lRateItems.Skip(i * pageSize).Take(pageSize))); if (response == null) { UIUtils.UpdateStatus("Error importing Letterboxd movie ratings to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus("Unable to sync Letterboxd ratings for {0} movies as they're not found on trakt.tv!", response.NotFound.Movies.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } if (mImportCancelled) { return; } #endregion #region Import Watched Movies // The Dairy can can include rated and watched items, it also has a watched date // if the watched movie exists in the diary use that as a watched date otherwise use date from watched file // add to diary any watched films that have been back filled foreach (var movie in lWatchedItems) { if (!lDiaryItems.Exists(d => d[LetterboxdFieldMapping.cTitle] == movie[LetterboxdFieldMapping.cTitle] && d[LetterboxdFieldMapping.cYear] == movie[LetterboxdFieldMapping.cYear])) { lDiaryItems.Add(movie); } } if (lDiaryItems.Count > 0) { // get watched movies from trakt.tv UIUtils.UpdateStatus("Requesting watched movies from trakt..."); var watchedTraktMovies = TraktAPI.GetWatchedMovies(); if (watchedTraktMovies == null) { UIUtils.UpdateStatus("Failed to get watched movies from trakt.tv, skipping watched movie import", true); Thread.Sleep(2000); } else { if (mImportCancelled) { return; } UIUtils.UpdateStatus("Found {0} watched movies on trakt", watchedTraktMovies.Count()); UIUtils.UpdateStatus("Filtering out watched movies that are already watched on trakt.tv"); lDiaryItems.RemoveAll(d => watchedTraktMovies.FirstOrDefault(t => t.Movie.Title == d[LetterboxdFieldMapping.cTitle] && t.Movie.Year.ToString() == d[LetterboxdFieldMapping.cYear]) != null); UIUtils.UpdateStatus("Importing {0} Letterboxd movies as watched...", lDiaryItems.Count); int pageSize = AppSettings.BatchSize; int pages = (int)Math.Ceiling((double)lDiaryItems.Count / pageSize); for (int i = 0; i < pages; i++) { UIUtils.UpdateStatus("Importing page {0}/{1} Letterboxd movies as watched...", i + 1, pages); var response = TraktAPI.AddMoviesToWatchedHistory(GetSyncWatchedMoviesData(lDiaryItems.Skip(i * pageSize).Take(pageSize).ToList())); if (response == null) { UIUtils.UpdateStatus("Failed to send watched status for Letterboxd movies to trakt.tv", true); Thread.Sleep(2000); } else if (response.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus("Unable to sync Letterboxd watched states for {0} movies as they're not found on trakt.tv!", response.NotFound.Movies.Count); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } #endregion #region Import Custom Lists if (lCustomLists.Count > 0) { UIUtils.UpdateStatus("Requesting custom lists from trakt..."); var lTraktCustomLists = TraktAPI.GetCustomLists(); if (lTraktCustomLists == null) { UIUtils.UpdateStatus("Error requesting custom lists from trakt.tv", true); Thread.Sleep(2000); return; } UIUtils.UpdateStatus($"Found {lTraktCustomLists.Count()} custom lists on trakt.tv"); foreach (var list in lCustomLists) { bool lListCreated = false; string lListName = Path.GetFileNameWithoutExtension(list.Key); // create the list if we don't have it TraktListDetail lTraktCustomList = lTraktCustomLists.FirstOrDefault(l => l.Name == lListName); if (lTraktCustomList == null) { UIUtils.UpdateStatus($"Creating new custom list '{lListName}' on trakt.tv"); var lTraktList = new TraktList { Name = lListName, DisplayNumbers = true, }; lTraktCustomList = TraktAPI.CreateCustomList(lTraktList); if (lTraktCustomList == null) { UIUtils.UpdateStatus("Error creating custom list on trakt.tv, skipping list creation", true); Thread.Sleep(2000); continue; } lListCreated = true; } FileLog.Info($"Found {list.Value.Count} movies in Letterboxd {lListName} list"); // if the list already exists, get current items for list if (!lListCreated) { lTraktCustomList = lTraktCustomLists.FirstOrDefault(l => l.Name == lListName); UIUtils.UpdateStatus($"Requesting existing custom list '{lListName}' items from trakt..."); var lTraktListItems = TraktAPI.GetCustomListItems(lTraktCustomList.Ids.Trakt.ToString()); if (lTraktListItems == null) { UIUtils.UpdateStatus("Error requesting custom list items from trakt.tv, skipping list creation", true); Thread.Sleep(2000); continue; } // filter out existing items from CSV so we don't send again FileLog.Info($"Filtering out existing items from Letterboxd list '{lListName}' so we don't send again to trakt.tv"); list.Value.RemoveAll(i => lTraktListItems.FirstOrDefault(l => l.Movie.Title.ToLowerInvariant() == i.Title.ToLowerInvariant() && l.Movie.Year == i.Year) != null); } UIUtils.UpdateStatus($"Importing {list.Value.Count} new movies into {lListName} custom list..."); var lLetterboxdCsvListMovies = list.Value.Select(m => m.ToTraktMovie()); int lPageSize = AppSettings.BatchSize; int lPages = ( int )Math.Ceiling(( double )list.Value.Count / lPageSize); for (int i = 0; i < lPages; i++) { UIUtils.UpdateStatus($"Importing page {i + 1}/{lPages} Letterboxd custom list movies..."); // create list sync object to hold list items var lTraktMovieSync = new TraktSyncAll { Movies = lLetterboxdCsvListMovies.Skip(i * lPageSize).Take(lPageSize).ToList() }; var lResponse = TraktAPI.AddItemsToList(lTraktCustomList.Ids.Trakt.ToString(), lTraktMovieSync); if (lResponse == null) { UIUtils.UpdateStatus("Failed to send custom list items for Letterboxd movies", true); Thread.Sleep(2000); } else if (lResponse.NotFound.Movies.Count > 0) { UIUtils.UpdateStatus($"Unable to sync custom list items for {lResponse.NotFound.Movies.Count} movies as they're not found on trakt.tv!"); Thread.Sleep(1000); } if (mImportCancelled) { return; } } } } #endregion }