Exemple #1
0
        public static TraktMovieScrobble CreateMovieScrobbleData(VideoInfo info)
        {
            try
            {
                // create scrobble data
                TraktMovieScrobble scrobbleData = new TraktMovieScrobble
                {
                    Title                = info.Title,
                    Year                 = info.Year,
                    PluginVersion        = TraktSettings.Version,
                    MediaCenter          = "Mediaportal",
                    MediaCenterVersion   = System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString(),
                    MediaCenterBuildDate = String.Empty,
                    UserName             = TraktSettings.Username,
                    Password             = TraktSettings.Password
                };

                return(scrobbleData);
            }
            catch (Exception e)
            {
                TraktLogger.Error("Error creating scrobble data: {0}", e.Message);
                return(null);
            }
        }
        public void AuthorizeUser()
        {
            if (string.IsNullOrEmpty(PinCode) || PinCode.Length != 8)
            {
                TestStatus = "[Trakt.WrongToken]";
                TraktLogger.Error("Wrong pin entered");
                return;
            }

            if (!Login())
            {
                return;
            }

            if (string.IsNullOrEmpty(Username))
            {
                TestStatus = "[Trakt.EmptyUsername]";
                TraktLogger.Error("Username is missing");
                return;
            }
            ISettingsManager settingsManager = ServiceRegistration.Get <ISettingsManager>();
            TraktSettings    settings        = settingsManager.Load <TraktSettings>();

            // temp. fix to disable the authorize button, when the user already is authorized
            IsAuthorized          = true;
            settings.IsAuthorized = IsAuthorized;
            settings.EnableTrakt  = IsEnabled;
            settings.Username     = Username;
            settingsManager.Save(settings);
        }
Exemple #3
0
        /// <summary>
        /// Reads all Skin Settings
        /// </summary>
        /// <param name="filename"></param>
        public static void Load(string filename)
        {
            // Check if File Exist
            if (!System.IO.File.Exists(filename))
            {
                TraktLogger.Warning("Trakt Skin Settings does not exist!");
                return;
            }

            XmlDocument doc = new XmlDocument();

            try
            {
                doc.Load(filename);
            }
            catch (XmlException e)
            {
                TraktLogger.Error("Cannot Load skin settings xml file!: {0}", e.Message);
                return;
            }

            // Read and Import Skin Settings
            GetOverlayPositions(doc);

            // Read Dashboard Skin Setings
            GetDashboardSkinSettings(doc);
        }
Exemple #4
0
        static string LoadFileCache(string filename, string defaultValue)
        {
            string returnValue = defaultValue;

            try
            {
                if (File.Exists(filename))
                {
                    TraktLogger.Debug("Loading file from disk. Filename = '{0}'", filename);
                    returnValue = File.ReadAllText(filename, Encoding.UTF8);
                    if (string.IsNullOrEmpty(returnValue))
                    {
                        TraktLogger.Warning("Unexpected contents in file '{0}', restoring default value", filename);
                        returnValue = defaultValue;
                    }
                }
            }
            catch (Exception e)
            {
                TraktLogger.Error(string.Format("Error loading file from disk. Filename = '{0}', Error = '{1}'", filename, e.Message));
                return(defaultValue);
            }

            return(returnValue);
        }
Exemple #5
0
        private TraktMovieScrobble CreateMovieScrobbleData(ITrackingInfo info)
        {
            try
            {
                // create scrobble data
                TraktMovieScrobble scrobbleData = new TraktMovieScrobble
                {
                    Title                = info.Title,
                    Year                 = info.Year > 1900 ? info.Year.ToString() : null,
                    IMDBID               = info.ID_IMDB,
                    TMDBID               = info.ID_TMDB,
                    PluginVersion        = TraktSettings.Version,
                    MediaCenter          = "Mediaportal",
                    MediaCenterVersion   = Assembly.GetEntryAssembly().GetName().Version.ToString(),
                    MediaCenterBuildDate = String.Empty,
                    UserName             = TraktSettings.Username,
                    Password             = TraktSettings.Password
                };

                return(scrobbleData);
            }
            catch (Exception e)
            {
                TraktLogger.Error("Error creating scrobble data: {0}", e.Message);
                return(null);
            }
        }
Exemple #6
0
        static void BufferTrailer(string url)
        {
            // stop player if currently playing some other video
            if (g_Player.Playing)
            {
                g_Player.Stop();
            }

            // prepare graph must be done on the MP main thread
            TraktLogger.Debug("Preparing graph for playback of '{0}'", url);
            var  factory       = new PlayerFactory(PlayerType.Internal, url);
            bool?prepareResult = ((OnlineVideosPlayer)factory.PreparedPlayer).PrepareGraph();

            TraktLogger.Debug("Preparing graph complete.");

            switch (prepareResult)
            {
            case true:
                GUIBackgroundTask.Instance.ExecuteInBackgroundAndCallback(() =>
                {
                    TraktLogger.Info("OnlineVideo pre-buffering started.");
                    if (((OnlineVideosPlayer)factory.PreparedPlayer).BufferFile())
                    {
                        TraktLogger.Info("OnlineVideo pre-buffering complete.");
                        return(true);
                    }
                    else
                    {
                        TraktLogger.Error("Error pre-buffering trailer.");
                        return(null);
                    }
                },
                                                                          delegate(bool success, object result)
                {
                    PlayTrailer(url, factory, result as bool?);
                },
                                                                          GUI.Translation.BufferingTrailer, false);
                break;

            case false:
                // play without buffering
                PlayTrailer(url, factory, prepareResult);
                break;

            default:
                TraktLogger.Error("Failed to create player graph.");
                GUIUtils.ShowNotifyDialog(GUI.Translation.Error, GUI.Translation.UnableToPlayTrailer);
                break;
            }
        }
        internal static bool Login(string key)
        {
            ISettingsManager settingsManager = ServiceRegistration.Get <ISettingsManager>();
            TraktSettings    settings        = settingsManager.Load <TraktSettings>();

            var response = TraktAuth.GetOAuthToken(key);

            if (response == null || string.IsNullOrEmpty(response.AccessToken))
            {
                TraktLogger.Error("Unable to login to trakt");
                return(false);
            }
            settings.IsAuthorized    = true;
            settings.TraktOAuthToken = response.RefreshToken;
            settingsManager.Save(settings);
            TraktLogger.Info("Successfully logged in");

            return(true);
        }
        private bool Login()
        {
            ISettingsManager settingsManager = ServiceRegistration.Get <ISettingsManager>();
            TraktSettings    settings        = settingsManager.Load <TraktSettings>();

            TraktLogger.Info("Exchanging refresh-token for access-token");
            var response = TraktAuth.GetOAuthToken(settings.TraktOAuthToken);

            if (response == null || string.IsNullOrEmpty(response.AccessToken))
            {
                TraktLogger.Error("Unable to login to trakt");
                return(false);
            }
            settings.TraktOAuthToken = response.RefreshToken;
            settingsManager.Save(settings);
            TraktLogger.Info("Successfully logged in");

            return(true);
        }
Exemple #9
0
        static void SaveFileCache(string filename, string value)
        {
            if (value == null)
            {
                return;
            }

            TraktLogger.Debug("Saving file to disk. Filename = '{0}'", filename);

            try
            {
                Directory.CreateDirectory(Path.GetDirectoryName(filename));
                File.WriteAllText(filename, value, Encoding.UTF8);
            }
            catch (Exception e)
            {
                TraktLogger.Error(string.Format("Error saving file. Filename = '{0}', Error = '{1}'", filename, e.Message));
            }
        }
        static string LoadFileCache(string filename, string defaultValue)
        {
            string returnValue = defaultValue;

            try
            {
                if (File.Exists(filename))
                {
                    TraktLogger.Debug("Loading file from disk. Filename = '{0}'", filename);
                    returnValue = File.ReadAllText(filename, Encoding.UTF8);
                }
            }
            catch (Exception e)
            {
                TraktLogger.Error(string.Format("Error loading file from disk. Filename = '{0}', Error = '{1}'", filename, e.Message));
                return(defaultValue);
            }

            return(returnValue);
        }
Exemple #11
0
        /// <summary>
        /// Get the date watched for the movie
        /// </summary>
        private static long GetLastDateWatched(IMDBMovie movie)
        {
            long dateLastPlayed = 0;

            if (!string.IsNullOrEmpty(movie.DateWatched) && movie.DateWatched != "0001-01-01 00:00:00")
            {
                try
                {
                    DateTime dateResult;
                    if (DateTime.TryParse(movie.DateWatched, out dateResult))
                    {
                        dateLastPlayed = dateResult.ToUniversalTime().ToEpoch();
                    }
                }
                catch (Exception e)
                {
                    TraktLogger.Error("Failed to get last watched date from movie: '{0}', Error: '{1}'", movie.Title, e.Message);
                }
            }

            return(dateLastPlayed);
        }
Exemple #12
0
        private TraktEpisodeScrobble CreateScrobbleData(FileLocal episode)
        {
            string seriesid   = null;
            int    seasonidx  = 0;
            int    episodeidx = 0;

            if (episode.AnimeEpisodes == null || episode.AnimeEpisodes.Count == 0 || !GetTVDBEpisodeInfo(episode.AnimeEpisodes[0], out seriesid, out seasonidx, out episodeidx))
            {
                TraktLogger.Warning("Unable to scrobble episodes, no AniDb/TVDb reference in database yet. Episode will be manually marked as seen on sync when available.");
                return(null);
            }

            // create scrobble data
            try
            {
                TraktEpisodeScrobble scrobbleData = new TraktEpisodeScrobble
                {
                    Title                = episode.AniDB_File.AnimeSeries.SeriesName,
                    Year                 = GetStartYear(episode.AniDB_File.AnimeSeries),
                    Season               = seasonidx.ToString(),
                    Episode              = episodeidx.ToString(),
                    SeriesID             = seriesid,
                    PluginVersion        = TraktSettings.Version,
                    MediaCenter          = "Mediaportal",
                    MediaCenterVersion   = Assembly.GetEntryAssembly().GetName().Version.ToString(),
                    MediaCenterBuildDate = String.Empty,
                    UserName             = TraktSettings.Username,
                    Password             = TraktSettings.Password
                };

                return(scrobbleData);
            }
            catch
            {
                TraktLogger.Error("Failed to create scrobble data for '{0}'", episode.ToString());
                return(null);
            }
        }
        public void SyncMediaToTrakt()
        {
            if (!IsSynchronizing)
            {
                ISettingsManager settingsManager = ServiceRegistration.Get <ISettingsManager>();
                TraktSettings    settings        = settingsManager.Load <TraktSettings>();

                if (!settings.IsAuthorized)
                {
                    TestStatus = "[Trakt.NotAuthorized]";
                    TraktLogger.Error("Trakt.tv not authorized");
                    return;
                }

                if (!TraktCache.RefreshData())
                {
                    return;
                }

                IsSynchronizing = true;
                IThreadPool threadPool = ServiceRegistration.Get <IThreadPool>();
                threadPool.Add(SyncMediaToTrakt_Async, ThreadPriority.BelowNormal);
            }
        }
        private bool Login()
        {
            ISettingsManager settingsManager = ServiceRegistration.Get <ISettingsManager>();
            TraktSettings    settings        = settingsManager.Load <TraktSettings>();

            TraktLogger.Info("Exchanging {0} for access-token...", PinCode.Length == 8 ? "pin-code" : "refresh-token");
            var response = TraktAuth.GetOAuthToken(PinCode.Length == 8 ? PinCode : settings.TraktOAuthToken);

            if (response == null || string.IsNullOrEmpty(response.AccessToken))
            {
                TestStatus = "[Trakt.CheckPin]";
                TraktLogger.Error("Unable to login to trakt, wrong pin?");
                PinCode = string.Empty;
                return(false);
            }

            TestStatus = "[Trakt.LoggedIn]";
            settings.TraktOAuthToken = response.RefreshToken;
            settingsManager.Save(settings);

            TraktLogger.Info("Successfully logged in!");

            return(true);
        }
Exemple #15
0
        public void SyncLibrary()
        {
            TraktLogger.Info("My Anime Starting Sync");

            #region Get online data
            // get all episodes on trakt that are marked as in 'collection'
            IEnumerable <TraktLibraryShow> traktCollectionEpisodes = TraktAPI.TraktAPI.GetLibraryEpisodesForUser(TraktSettings.Username);
            if (traktCollectionEpisodes == null)
            {
                TraktLogger.Error("Error getting show collection from trakt server, cancelling sync.");
                return;
            }
            TraktLogger.Info("{0} tvshows in trakt collection", traktCollectionEpisodes.Count().ToString());

            // get all episodes on trakt that are marked as 'seen' or 'watched'
            IEnumerable <TraktLibraryShow> traktWatchedEpisodes = TraktAPI.TraktAPI.GetWatchedEpisodesForUser(TraktSettings.Username);
            if (traktWatchedEpisodes == null)
            {
                TraktLogger.Error("Error getting shows watched from trakt server, cancelling sync.");
                return;
            }
            TraktLogger.Info("{0} tvshows with watched episodes in trakt library", traktWatchedEpisodes.Count().ToString());

            // get all episodes on trakt that are marked as 'unseen'
            IEnumerable <TraktLibraryShow> traktUnSeenEpisodes = TraktAPI.TraktAPI.GetUnSeenEpisodesForUser(TraktSettings.Username);
            if (traktUnSeenEpisodes == null)
            {
                TraktLogger.Error("Error getting shows unseen from trakt server, cancelling sync.");
                return;
            }
            TraktLogger.Info("{0} tvshows with unseen episodes in trakt library", traktUnSeenEpisodes.Count().ToString());
            #endregion

            #region Get local data
            List <FileLocal> localCollectionEpisodes = new List <FileLocal>();
            List <FileLocal> localWatchedEpisodes    = new List <FileLocal>();

            // Get all local episodes in database
            localCollectionEpisodes = FileLocal.GetAll().Where(f => !string.IsNullOrEmpty(f.FileNameFull) && f.AnimeEpisodes.Count > 0).ToList();

            TraktLogger.Info("{0} episodes with local files in my anime database", localCollectionEpisodes.Count.ToString());

            // Get only Valid Episodes types
            localCollectionEpisodes.RemoveAll(lc => lc.AnimeEpisodes.Where(e => (e.EpisodeTypeEnum != enEpisodeType.Normal && e.EpisodeTypeEnum != enEpisodeType.Special)).Count() > 0);

            TraktLogger.Info("{0} episodes with valid episode types in my anime database", localCollectionEpisodes.Count.ToString());

            // Get watched episodes
            localWatchedEpisodes = localCollectionEpisodes.Where(f => (f.AniDB_File != null && f.AniDB_File.IsWatched > 0) || (f.AnimeEpisodes != null && f.AnimeEpisodes[0].IsWatched > 0)).ToList();

            TraktLogger.Info("{0} episodes watched in my anime database", localWatchedEpisodes.Count.ToString());
            #endregion

            #region Sync collection/library to trakt
            // get list of episodes that we have not already trakt'd
            List <FileLocal> localEpisodesToSync = new List <FileLocal>(localCollectionEpisodes);
            foreach (FileLocal ep in localCollectionEpisodes)
            {
                if (TraktEpisodeExists(traktCollectionEpisodes, ep))
                {
                    // no interest in syncing, remove
                    localEpisodesToSync.Remove(ep);
                }
            }
            // sync unseen episodes
            TraktLogger.Info("{0} episodes need to be added to Library", localEpisodesToSync.Count.ToString());
            SyncLibrary(localEpisodesToSync, TraktSyncModes.library);
            #endregion

            #region Sync seen to trakt
            // get list of episodes that we have not already trakt'd
            // filter out any marked as UnSeen
            List <FileLocal> localWatchedEpisodesToSync = new List <FileLocal>(localWatchedEpisodes);
            foreach (FileLocal ep in localWatchedEpisodes)
            {
                if (TraktEpisodeExists(traktWatchedEpisodes, ep) || TraktEpisodeExists(traktUnSeenEpisodes, ep))
                {
                    // no interest in syncing, remove
                    localWatchedEpisodesToSync.Remove(ep);
                }
            }
            // sync seen episodes
            TraktLogger.Info("{0} episodes need to be added to SeenList", localWatchedEpisodesToSync.Count.ToString());
            SyncLibrary(localWatchedEpisodesToSync, TraktSyncModes.seen);
            #endregion

            #region Sync watched flags from trakt locally
            // Sync watched flags from trakt to local database
            // do not mark as watched locally if UnSeen on trakt
            foreach (FileLocal ep in localCollectionEpisodes.Where(e => e.AnimeEpisodes[0].IsWatched == 0))
            {
                if (TraktEpisodeExists(traktWatchedEpisodes, ep) && !TraktEpisodeExists(traktUnSeenEpisodes, ep))
                {
                    // mark episode as watched
                    TraktLogger.Info("Marking episode '{0}' as watched", ep.ToString());
                    ep.AnimeEpisodes[0].ToggleWatchedStatus(true, false);
                }
            }
            #endregion

            #region Sync unseen flags from trakt locally
            foreach (FileLocal ep in localCollectionEpisodes.Where(e => e.AnimeEpisodes[0].IsWatched > 1))
            {
                if (TraktEpisodeExists(traktUnSeenEpisodes, ep))
                {
                    // mark episode as unwatched
                    TraktLogger.Info("Marking episode '{0}' as unwatched", ep.ToString());
                    ep.AnimeEpisodes[0].ToggleWatchedStatus(false, false);
                }
            }
            #endregion

            #region Clean Library
            if (TraktSettings.KeepTraktLibraryClean && TraktSettings.TvShowPluginCount == 1)
            {
                TraktLogger.Info("Removing shows From Trakt Collection no longer in database");

                // if we no longer have a file reference in database remove from library
                foreach (var series in traktCollectionEpisodes)
                {
                    TraktEpisodeSync syncData = GetEpisodesForTraktRemoval(series, localCollectionEpisodes.Where(e => e.AniDB_File.AnimeSeries.TvDB_ID.ToString() == series.SeriesId).ToList());
                    if (syncData == null)
                    {
                        continue;
                    }
                    TraktResponse response = TraktAPI.TraktAPI.SyncEpisodeLibrary(syncData, TraktSyncModes.unlibrary);
                    TraktAPI.TraktAPI.LogTraktResponse(response);
                    Thread.Sleep(500);
                }
            }
            #endregion

            TraktLogger.Info("My Anime Sync Completed");
        }
        public bool SyncSeries()
        {
            TraktLogger.Info("Series Library Starting Sync");

            // store list of series ids so we can update the episode counts
            // of any series that syncback watched flags
            var seriesToUpdateEpisodeCounts = new HashSet <int>();

            #region Get online data from cache

            #region UnWatched / Watched

            List <TraktCache.EpisodeWatched> traktWatchedEpisodes = null;

            // get all episodes on trakt that are marked as 'unseen'
            var traktUnWatchedEpisodes = TraktCache.GetUnWatchedEpisodesFromTrakt().ToNullableList();
            if (traktUnWatchedEpisodes == null)
            {
                TraktLogger.Error("Error getting tv shows unwatched from trakt.tv server, unwatched and watched sync will be skipped");
            }
            else
            {
                TraktLogger.Info("Found {0} unwatched tv episodes in trakt.tv library", traktUnWatchedEpisodes.Count());

                // now get all episodes on trakt that are marked as 'seen' or 'watched' (this will be cached already when working out unwatched)
                traktWatchedEpisodes = TraktCache.GetWatchedEpisodesFromTrakt().ToNullableList();
                if (traktWatchedEpisodes == null)
                {
                    TraktLogger.Error("Error getting tv shows watched from trakt.tv server, watched sync will be skipped");
                }
                else
                {
                    TraktLogger.Info("Found {0} watched tv episodes in trakt.tv library", traktWatchedEpisodes.Count());
                }
            }

            #endregion

            #region Collection

            // get all episodes on trakt that are marked as in 'collection'
            var traktCollectedEpisodes = TraktCache.GetCollectedEpisodesFromTrakt().ToNullableList();
            if (traktCollectedEpisodes == null)
            {
                TraktLogger.Error("Error getting tv episode collection from trakt.tv server");
            }
            else
            {
                TraktLogger.Info("Found {0} tv episodes in trakt.tv collection", traktCollectedEpisodes.Count());
            }

            #endregion

            #region Ratings

            #region Episodes

            //var traktRatedEpisodes = TraktCache.GetRatedEpisodesFromTrakt().ToNullableList();
            //if (traktRatedEpisodes == null)
            //{
            //  TraktLogger.Error("Error getting rated episodes from trakt.tv server");
            //}
            //else
            //{
            //  TraktLogger.Info("Found {0} rated tv episodes in trakt.tv library", traktRatedEpisodes.Count());
            //}

            #endregion

            #region Shows

            //var traktRatedShows = TraktCache.GetRatedShowsFromTrakt().ToNullableList();
            //if (traktRatedShows == null)
            //{
            //  TraktLogger.Error("Error getting rated shows from trakt.tv server");
            //}
            //else
            //{
            //  TraktLogger.Info("Found {0} rated tv shows in trakt.tv library", traktRatedShows.Count());
            //}

            #endregion

            #region Seasons

            //var traktRatedSeasons = TraktCache.GetRatedSeasonsFromTrakt().ToNullableList();
            //if (traktRatedSeasons == null)
            //{
            //  TraktLogger.Error("Error getting rated seasons from trakt.tv server");
            //}
            //else
            //{
            //  TraktLogger.Info("Found {0} rated tv seasons in trakt.tv library", traktRatedSeasons.Count());
            //}

            #endregion

            #endregion

            #region Watchlist

            #region Shows

            //var traktWatchlistedShows = TraktCache.GetWatchlistedShowsFromTrakt();
            //if (traktWatchlistedShows == null)
            //{
            //  TraktLogger.Error("Error getting watchlisted shows from trakt.tv server");
            //}
            //else
            //{
            //  TraktLogger.Info("Found {0} watchlisted tv shows in trakt.tv library", traktWatchlistedShows.Count());
            //}

            #endregion

            #region Seasons

            //var traktWatchlistedSeasons = TraktCache.GetWatchlistedSeasonsFromTrakt();
            //if (traktWatchlistedSeasons == null)
            //{
            //  TraktLogger.Error("Error getting watchlisted seasons from trakt.tv server");
            //}
            //else
            //{
            //  TraktLogger.Info("Found {0} watchlisted tv seasons in trakt.tv library", traktWatchlistedSeasons.Count());
            //}

            #endregion

            #region Episodes

            //var traktWatchlistedEpisodes = TraktCache.GetWatchlistedEpisodesFromTrakt();
            //if (traktWatchlistedEpisodes == null)
            //{
            //  TraktLogger.Error("Error getting watchlisted episodes from trakt.tv server");
            //}
            //else
            //{
            //  TraktLogger.Info("Found {0} watchlisted tv episodes in trakt.tv library", traktWatchlistedEpisodes.Count());
            //}

            #endregion

            #endregion

            #endregion

            if (traktCollectedEpisodes != null)
            {
                try
                {
                    TestStatus = "[Trakt.SyncSeries]";
                    Guid[]         types            = { MediaAspect.ASPECT_ID, SeriesAspect.ASPECT_ID, VideoAspect.ASPECT_ID, ImporterAspect.ASPECT_ID };
                    MediaItemQuery mediaItemQuery   = new MediaItemQuery(types, null, null);
                    var            contentDirectory = ServiceRegistration.Get <IServerConnectionManager>().ContentDirectory;
                    if (contentDirectory == null)
                    {
                        TestStatus = "[Trakt.MediaLibraryNotConnected]";
                        return(false);
                    }

                    #region Get data from local database

                    var localEpisodes = contentDirectory.Search(mediaItemQuery, true);
                    int episodeCount  = localEpisodes.Count;

                    TraktLogger.Info("Found {0} total episodes in local database", episodeCount);

                    // get the episodes that we have watched
                    var localWatchedEpisodes = localEpisodes.Where(IsWatched).ToList();

                    TraktLogger.Info("Found {0} episodes watched in tvseries database", localWatchedEpisodes.Count);

                    #endregion

                    #region Add episodes to watched history at trakt.tv
                    int showCount    = 0;
                    int iSyncCounter = 0;
                    if (traktWatchedEpisodes != null)
                    {
                        var syncWatchedShows = GetWatchedShowsForSyncEx(localWatchedEpisodes, traktWatchedEpisodes);

                        TraktLogger.Info("Found {0} local tv show(s) with {1} watched episode(s) to add to trakt.tv watched history", syncWatchedShows.Shows.Count, syncWatchedShows.Shows.Sum(sh => sh.Seasons.Sum(se => se.Episodes.Count())));

                        showCount = syncWatchedShows.Shows.Count;
                        foreach (var show in syncWatchedShows.Shows)
                        {
                            int showEpisodeCount = show.Seasons.Sum(s => s.Episodes.Count());
                            TraktLogger.Info("Adding tv show [{0}/{1}] to trakt.tv episode watched history, Episode Count = '{2}', Show Title = '{3}', Show Year = '{4}', Show TVDb ID = '{5}', Show IMDb ID = '{6}'",
                                             ++iSyncCounter, showCount, showEpisodeCount, show.Title, show.Year.HasValue ? show.Year.ToString() : "<empty>", show.Ids.Tvdb, show.Ids.Imdb ?? "<empty>");

                            show.Seasons.ForEach(s => s.Episodes.ForEach(e =>
                            {
                                TraktLogger.Info("Adding episode to trakt.tv watched history, Title = '{0} - {1}x{2}', Watched At = '{3}'", show.Title, s.Number, e.Number, e.WatchedAt.ToLogString());
                            }));

                            // only sync one show at a time regardless of batch size in settings
                            var pagedShows = new List <TraktSyncShowWatchedEx>();
                            pagedShows.Add(show);

                            var response = TraktAPI.AddShowsToWatchedHistoryEx(new TraktSyncShowsWatchedEx {
                                Shows = pagedShows
                            });
                            TraktLogger.LogTraktResponse <TraktSyncResponse>(response);

                            // only add to cache if it was a success
                            // note: we don't get back the same object type so makes it hard to figure out what failed
                            if (response != null && response.Added != null && response.Added.Episodes == showEpisodeCount)
                            {
                                // update local cache
                                TraktCache.AddEpisodesToWatchHistory(show);
                            }
                        }
                    }
                    #endregion

                    #region Add episodes to collection at trakt.tv

                    if (traktCollectedEpisodes != null)
                    {
                        var syncCollectedShows = GetCollectedShowsForSyncEx(localEpisodes, traktCollectedEpisodes);

                        TraktLogger.Info("Found {0} local tv show(s) with {1} collected episode(s) to add to trakt.tv collection", syncCollectedShows.Shows.Count, syncCollectedShows.Shows.Sum(sh => sh.Seasons.Sum(se => se.Episodes.Count())));

                        iSyncCounter = 0;
                        showCount    = syncCollectedShows.Shows.Count;
                        foreach (var show in syncCollectedShows.Shows)
                        {
                            int showEpisodeCount = show.Seasons.Sum(s => s.Episodes.Count());
                            TraktLogger.Info("Adding tv show [{0}/{1}] to trakt.tv episode collection, Episode Count = '{2}', Show Title = '{3}', Show Year = '{4}', Show TVDb ID = '{5}', Show IMDb ID = '{6}'",
                                             ++iSyncCounter, showCount, showEpisodeCount, show.Title, show.Year.HasValue ? show.Year.ToString() : "<empty>", show.Ids.Tvdb, show.Ids.Imdb ?? "<empty>");

                            show.Seasons.ForEach(s => s.Episodes.ForEach(e =>
                            {
                                TraktLogger.Info("Adding episode to trakt.tv collection, Title = '{0} - {1}x{2}', Collected At = '{3}', Audio Channels = '{4}', Audio Codec = '{5}', Resolution = '{6}', Media Type = '{7}', Is 3D = '{8}'", show.Title, s.Number, e.Number, e.CollectedAt.ToLogString(), e.AudioChannels.ToLogString(), e.AudioCodec.ToLogString(), e.Resolution.ToLogString(), e.MediaType.ToLogString(), e.Is3D);
                            }));

                            // only sync one show at a time regardless of batch size in settings
                            var pagedShows = new List <TraktSyncShowCollectedEx>();
                            pagedShows.Add(show);

                            var response = TraktAPI.AddShowsToCollectonEx(new TraktSyncShowsCollectedEx {
                                Shows = pagedShows
                            });
                            TraktLogger.LogTraktResponse <TraktSyncResponse>(response);

                            // only add to cache if it was a success
                            if (response != null && response.Added != null && response.Added.Episodes == showEpisodeCount)
                            {
                                // update local cache
                                TraktCache.AddEpisodesToCollection(show);
                            }
                        }
                    }
                    #endregion
                    return(true);
                }
                catch (Exception ex)
                {
                    ServiceRegistration.Get <ILogger>().Error("Trakt.tv: Exception while synchronizing media library.", ex);
                }
            }
            return(false);
        }
Exemple #17
0
        public void SyncLibrary()
        {
            TraktLogger.Info("My Videos Starting Library Sync");

            #region Get online data from cache

            #region Get unwatched / watched movies from trakt.tv
            IEnumerable <TraktMovieWatched> traktWatchedMovies = null;

            var traktUnWatchedMovies = TraktCache.GetUnWatchedMoviesFromTrakt();
            if (traktUnWatchedMovies == null)
            {
                TraktLogger.Error("Error getting unwatched movies from trakt server, unwatched and watched sync will be skipped");
            }
            else
            {
                TraktLogger.Info("There are {0} unwatched movies since the last sync with trakt.tv", traktUnWatchedMovies.Count());

                traktWatchedMovies = TraktCache.GetWatchedMoviesFromTrakt();
                if (traktWatchedMovies == null)
                {
                    TraktLogger.Error("Error getting watched movies from trakt server, watched sync will be skipped");
                }
                else
                {
                    TraktLogger.Info("There are {0} watched movies in trakt.tv library", traktWatchedMovies.Count());
                }
            }
            #endregion

            #region Get collected movies from trakt.tv
            var traktCollectedMovies = TraktCache.GetCollectedMoviesFromTrakt();
            if (traktCollectedMovies == null)
            {
                TraktLogger.Error("Error getting collected movies from trakt server");
            }
            else
            {
                TraktLogger.Info("There are {0} collected movies in trakt.tv library", traktCollectedMovies.Count());
            }
            #endregion

            #endregion

            // optionally do library sync
            if (TraktSettings.SyncLibrary)
            {
                var collectedMovies = GetMovies();

                #region Remove Blocked Movies
                collectedMovies.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);
                    }
                }
                collectedMovies.RemoveAll(m => blockedMovieIds.Contains(m.ID));
                #endregion

                #region Remove Movies with No IDs
                // Remove any movies that don't have any valid online ID's e.g. IMDb ID or TMDb ID.
                if (TraktSettings.SkipMoviesWithNoIdsOnSync)
                {
                    TraktLogger.Info("Removing movies that contain no valid online ID from sync movie list");
                    collectedMovies.RemoveAll(m => !BasicHandler.IsValidImdb(m.IMDBNumber));
                }
                #endregion

                #region Skipped Movies Check
                // Remove Skipped Movies from previous Sync
                //TODO
                //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.
                //TODO
                //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("Found {0} movies available to sync in My Videos database", collectedMovies.Count);

                // get the movies that we have watched
                var watchedMovies = collectedMovies.Where(m => m.Watched > 0).ToList();

                TraktLogger.Info("Found {0} watched movies available to sync in My Videos database", watchedMovies.Count);

                #region Mark movies as unwatched in local database
                if (traktUnWatchedMovies != null && traktUnWatchedMovies.Count() > 0)
                {
                    foreach (var movie in traktUnWatchedMovies)
                    {
                        var localMovie = watchedMovies.FirstOrDefault(m => MovieMatch(m, movie));
                        if (localMovie == null)
                        {
                            continue;
                        }

                        TraktLogger.Info("Marking movie as unwatched in local database, movie is not watched on trakt.tv. Title = '{0}', Year = '{1}', IMDb ID = '{2}', TMDb ID = '{3}'",
                                         movie.Title, movie.Year.HasValue ? movie.Year.ToString() : "<empty>", movie.Ids.Imdb ?? "<empty>", movie.Ids.Tmdb.HasValue ? movie.Ids.Tmdb.ToString() : "<empty>");

                        localMovie.Watched = 0;
                        IMDBMovie details = localMovie;
                        VideoDatabase.SetMovieInfoById(localMovie.ID, ref details);
                        VideoDatabase.SetMovieWatchedStatus(localMovie.ID, false, 0);
                    }

                    // update watched set
                    watchedMovies = collectedMovies.Where(m => m.Watched > 0).ToList();
                }
                #endregion

                #region Mark movies as watched in local database
                if (traktWatchedMovies != null && traktWatchedMovies.Count() > 0)
                {
                    foreach (var twm in traktWatchedMovies)
                    {
                        var localMovie = collectedMovies.FirstOrDefault(m => MovieMatch(m, twm.Movie));
                        if (localMovie == null)
                        {
                            continue;
                        }

                        int  iPercent;
                        int  iWatchedCount;
                        bool localIsWatched = VideoDatabase.GetmovieWatchedStatus(localMovie.ID, out iPercent, out iWatchedCount);

                        if (!localIsWatched || iWatchedCount < twm.Plays)
                        {
                            TraktLogger.Info("Updating local movie watched state / play count to match trakt.tv. Plays = '{0}', Title = '{1}', Year = '{2}', IMDb ID = '{3}', TMDb ID = '{4}'",
                                             twm.Plays, twm.Movie.Title, twm.Movie.Year.HasValue ? twm.Movie.Year.ToString() : "<empty>", twm.Movie.Ids.Imdb ?? "<empty>", twm.Movie.Ids.Tmdb.HasValue ? twm.Movie.Ids.Tmdb.ToString() : "<empty>");

                            if (localMovie.DateWatched == "0001-01-01 00:00:00")
                            {
                                DateTime dateWatched;
                                if (DateTime.TryParse(twm.LastWatchedAt, out dateWatched))
                                {
                                    localMovie.DateWatched = dateWatched.ToString("yyyy-MM-dd HH:mm:ss");
                                }
                            }

                            localMovie.Watched        = 1;
                            localMovie.WatchedCount   = twm.Plays;
                            localMovie.WatchedPercent = iPercent;

                            VideoDatabase.SetMovieWatchedCount(localMovie.ID, twm.Plays);
                            VideoDatabase.SetMovieWatchedStatus(localMovie.ID, true, iPercent);

                            IMDBMovie details = localMovie;
                            VideoDatabase.SetMovieInfoById(localMovie.ID, ref details);
                        }
                    }
                }
                #endregion

                #region Add movies to watched history at trakt.tv
                if (traktWatchedMovies != null)
                {
                    var syncWatchedMovies = new List <TraktSyncMovieWatched>();
                    TraktLogger.Info("Finding movies to add to trakt.tv watched history");

                    syncWatchedMovies = (from movie in watchedMovies
                                         where !traktWatchedMovies.ToList().Exists(c => MovieMatch(movie, c.Movie))
                                         select new TraktSyncMovieWatched
                    {
                        Ids = new TraktMovieId {
                            Imdb = movie.IMDBNumber.ToNullIfEmpty()
                        },
                        Title = movie.Title,
                        Year = movie.Year,
                        WatchedAt = GetLastDateWatched(movie),
                    }).ToList();

                    TraktLogger.Info("Adding {0} movies to trakt.tv watched history", syncWatchedMovies.Count);

                    if (syncWatchedMovies.Count > 0)
                    {
                        // update local cache
                        TraktCache.AddMoviesToWatchHistory(syncWatchedMovies);

                        int pageSize = TraktSettings.SyncBatchSize;
                        int pages    = (int)Math.Ceiling((double)syncWatchedMovies.Count / pageSize);
                        for (int i = 0; i < pages; i++)
                        {
                            TraktLogger.Info("Adding movies [{0}/{1}] to trakt.tv watched history", i + 1, pages);

                            var pagedMovies = syncWatchedMovies.Skip(i * pageSize).Take(pageSize).ToList();

                            pagedMovies.ForEach(s => TraktLogger.Info("Adding movie to trakt.tv watched history. Title = '{0}', Year = '{1}', IMDb ID = '{2}', TMDb ID = '{3}', Date Watched = '{4}'",
                                                                      s.Title, s.Year.HasValue ? s.Year.ToString() : "<empty>", s.Ids.Imdb ?? "<empty>", s.Ids.Tmdb.HasValue ? s.Ids.Tmdb.ToString() : "<empty>", s.WatchedAt));

                            // remove title/year such that match against online ID only
                            if (TraktSettings.SkipMoviesWithNoIdsOnSync)
                            {
                                pagedMovies.ForEach(m => { m.Title = null; m.Year = null; });
                            }

                            var response = TraktAPI.TraktAPI.AddMoviesToWatchedHistory(new TraktSyncMoviesWatched {
                                Movies = pagedMovies
                            });
                            TraktLogger.LogTraktResponse <TraktSyncResponse>(response);

                            // remove movies from cache which didn't succeed
                            if (response != null && response.NotFound != null && response.NotFound.Movies.Count > 0)
                            {
                                TraktCache.RemoveMoviesFromWatchHistory(response.NotFound.Movies);
                            }
                        }
                    }
                }
                #endregion

                #region Add movies to collection at trakt.tv
                if (traktCollectedMovies != null)
                {
                    var syncCollectedMovies = new List <TraktSyncMovieCollected>();
                    TraktLogger.Info("Finding movies to add to trakt.tv collection");

                    syncCollectedMovies = (from movie in collectedMovies
                                           where !traktCollectedMovies.ToList().Exists(c => MovieMatch(movie, c.Movie))
                                           select new TraktSyncMovieCollected
                    {
                        Ids = new TraktMovieId {
                            Imdb = movie.IMDBNumber.ToNullIfEmpty()
                        },
                        Title = movie.Title,
                        Year = movie.Year,
                        CollectedAt = movie.DateAdded.ToISO8601(),
                        MediaType = GetMovieMediaType(movie),
                        Resolution = GetMovieResolution(movie),
                        AudioCodec = GetMovieAudioCodec(movie),
                        AudioChannels = GetMovieAudioChannels(movie),
                        Is3D = IsMovie3D(movie)
                    }).ToList();

                    TraktLogger.Info("Adding {0} movies to trakt.tv collection", syncCollectedMovies.Count);

                    if (syncCollectedMovies.Count > 0)
                    {
                        // update internal cache
                        TraktCache.AddMoviesToCollection(syncCollectedMovies);

                        int pageSize = TraktSettings.SyncBatchSize;
                        int pages    = (int)Math.Ceiling((double)syncCollectedMovies.Count / pageSize);
                        for (int i = 0; i < pages; i++)
                        {
                            TraktLogger.Info("Adding movies [{0}/{1}] to trakt.tv collection", i + 1, pages);

                            var pagedMovies = syncCollectedMovies.Skip(i * pageSize).Take(pageSize).ToList();

                            pagedMovies.ForEach(s => TraktLogger.Info("Adding movie to trakt.tv collection. Title = '{0}', Year = '{1}', IMDb ID = '{2}', TMDb ID = '{3}', Date Added = '{4}', MediaType = '{5}', Resolution = '{6}', Audio Codec = '{7}', Audio Channels = '{8}'",
                                                                      s.Title, s.Year.HasValue ? s.Year.ToString() : "<empty>", s.Ids.Imdb ?? "<empty>", s.Ids.Tmdb.HasValue ? s.Ids.Tmdb.ToString() : "<empty>",
                                                                      s.CollectedAt, s.MediaType ?? "<empty>", s.Resolution ?? "<empty>", s.AudioCodec ?? "<empty>", s.AudioChannels ?? "<empty>"));

                            // remove title/year such that match against online ID only
                            if (TraktSettings.SkipMoviesWithNoIdsOnSync)
                            {
                                pagedMovies.ForEach(m => { m.Title = null; m.Year = null; });
                            }

                            var response = TraktAPI.TraktAPI.AddMoviesToCollecton(new TraktSyncMoviesCollected {
                                Movies = pagedMovies
                            });
                            TraktLogger.LogTraktResponse(response);

                            // remove movies from cache which didn't succeed
                            if (response != null && response.NotFound != null && response.NotFound.Movies.Count > 0)
                            {
                                TraktCache.RemoveMoviesFromCollection(response.NotFound.Movies);
                            }
                        }
                    }
                }
                #endregion

                #region Remove movies no longer in collection from trakt.tv
                if (TraktSettings.KeepTraktLibraryClean && TraktSettings.MoviePluginCount == 1 && traktCollectedMovies != null)
                {
                    var syncUnCollectedMovies = new List <TraktMovie>();
                    TraktLogger.Info("Finding movies to remove from trakt.tv collection");

                    // workout what movies that are in trakt collection that are not in local collection
                    syncUnCollectedMovies = (from tcm in traktCollectedMovies
                                             where !collectedMovies.Exists(c => MovieMatch(c, tcm.Movie))
                                             select new TraktMovie
                    {
                        Ids = tcm.Movie.Ids,
                        Title = tcm.Movie.Title,
                        Year = tcm.Movie.Year
                    }).ToList();

                    TraktLogger.Info("Removing {0} movies from trakt.tv collection", syncUnCollectedMovies.Count);

                    if (syncUnCollectedMovies.Count > 0)
                    {
                        // update local cache
                        TraktCache.RemoveMoviesFromCollection(syncUnCollectedMovies);

                        int pageSize = TraktSettings.SyncBatchSize;
                        int pages    = (int)Math.Ceiling((double)syncUnCollectedMovies.Count / pageSize);
                        for (int i = 0; i < pages; i++)
                        {
                            TraktLogger.Info("Removing movies [{0}/{1}] from trakt.tv collection", i + 1, pages);

                            var pagedMovies = syncUnCollectedMovies.Skip(i * pageSize).Take(pageSize).ToList();

                            pagedMovies.ForEach(s => TraktLogger.Info("Removing movie from trakt.tv collection, movie no longer exists locally. Title = '{0}', Year = '{1}', IMDb ID = '{2}', TMDb ID = '{3}'",
                                                                      s.Title, s.Year.HasValue ? s.Year.ToString() : "<empty>", s.Ids.Imdb ?? "<empty>", s.Ids.Tmdb.HasValue ? s.Ids.Tmdb.ToString() : "<empty>"));

                            // remove title/year such that match against online ID only
                            if (TraktSettings.SkipMoviesWithNoIdsOnSync)
                            {
                                pagedMovies.ForEach(m => { m.Title = null; m.Year = null; });
                            }

                            var response = TraktAPI.TraktAPI.RemoveMoviesFromCollecton(new TraktSyncMovies {
                                Movies = pagedMovies
                            });
                            TraktLogger.LogTraktResponse(response);
                        }
                    }
                }
                #endregion
            }

            TraktLogger.Info("My Videos Library Sync Completed");
        }
Exemple #18
0
        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");
        }
        private void CopyList(TraktListDetail sourceList, TraktList newList)
        {
            var copyList = new CopyList {
                Username    = CurrentUser,
                Source      = sourceList,
                Destination = newList
            };

            var copyThread = new Thread((obj) =>
            {
                var copyParams = obj as CopyList;

                // first create new list
                TraktLogger.Info("Creating new list online. Privacy = '{0}', Name = '{1}'", copyParams.Destination.Privacy, copyParams.Destination.Name);
                var response = TraktAPI.TraktAPI.CreateCustomList(copyParams.Destination);
                if (response == null || response.Ids == null)
                {
                    TraktLogger.Error("Failed to create user list. List Name = '{0}'", copyParams.Destination.Name);
                    return;
                }

                // get items from other list
                var userListItems = TraktAPI.TraktAPI.GetUserListItems(copyParams.Source.User.Ids.Slug, copyParams.Source.Ids.Trakt.ToString(), "min");
                if (userListItems == null)
                {
                    TraktLogger.Error("Failed to get user list items. List Name = '{0}', ID = '{1}'", copyParams.Destination.Name, copyParams.Source.Ids.Trakt);
                    return;
                }

                // copy items to new list
                var itemsToAdd = new TraktSyncAll();
                foreach (var item in userListItems)
                {
                    var listItem  = new TraktListItem();
                    listItem.Type = item.Type;

                    switch (item.Type)
                    {
                    case "movie":
                        if (itemsToAdd.Movies == null)
                        {
                            itemsToAdd.Movies = new List <TraktMovie>();
                        }

                        itemsToAdd.Movies.Add(new TraktMovie {
                            Ids = item.Movie.Ids
                        });
                        break;

                    case "show":
                        if (itemsToAdd.Shows == null)
                        {
                            itemsToAdd.Shows = new List <TraktShow>();
                        }

                        itemsToAdd.Shows.Add(new TraktShow {
                            Ids = item.Show.Ids
                        });
                        break;

                    case "season":
                        if (itemsToAdd.Seasons == null)
                        {
                            itemsToAdd.Seasons = new List <TraktSeason>();
                        }

                        itemsToAdd.Seasons.Add(new TraktSeason {
                            Ids = item.Season.Ids
                        });
                        break;

                    case "episode":
                        if (itemsToAdd.Episodes == null)
                        {
                            itemsToAdd.Episodes = new List <TraktEpisode>();
                        }

                        itemsToAdd.Episodes.Add(new TraktEpisode {
                            Ids = item.Episode.Ids
                        });
                        break;

                    case "person":
                        if (itemsToAdd.People == null)
                        {
                            itemsToAdd.People = new List <TraktPerson>();
                        }

                        itemsToAdd.People.Add(new TraktPerson {
                            Ids = item.Person.Ids
                        });
                        break;
                    }
                }

                // add items to the list
                var ItemsAddedResponse = TraktAPI.TraktAPI.AddItemsToList("me", response.Ids.Trakt.ToString(), itemsToAdd);

                if (ItemsAddedResponse != null)
                {
                    TraktLists.ClearListCache(TraktSettings.Username);
                    TraktCache.ClearCustomListCache();

                    // updated MovingPictures categories and filters menu
                    if (TraktHelper.IsMovingPicturesAvailableAndEnabled)
                    {
                        MovingPictures.UpdateCategoriesMenu(SyncListType.CustomList);
                        MovingPictures.UpdateFiltersMenu(SyncListType.CustomList);
                    }
                }
            })
            {
                Name         = "CopyList",
                IsBackground = true
            };

            copyThread.Start(copyList);
        }
        public bool SyncMovies()
        {
            ISettingsManager settingsManager = ServiceRegistration.Get <ISettingsManager>();
            TraktSettings    settings        = settingsManager.Load <TraktSettings>();

            #region Get online data from cache

            #region Get unwatched / watched movies from trakt.tv
            IEnumerable <TraktMovieWatched> traktWatchedMovies = null;

            var traktUnWatchedMovies = TraktCache.GetUnWatchedMoviesFromTrakt();
            if (traktUnWatchedMovies == null)
            {
                TraktLogger.Error("Error getting unwatched movies from trakt server, unwatched and watched sync will be skipped");
            }
            else
            {
                TraktLogger.Info("There are {0} unwatched movies since the last sync with trakt.tv", traktUnWatchedMovies.Count());

                traktWatchedMovies = TraktCache.GetWatchedMoviesFromTrakt();
                if (traktWatchedMovies == null)
                {
                    TraktLogger.Error("Error getting watched movies from trakt server, watched sync will be skipped");
                }
                else
                {
                    TraktLogger.Info("There are {0} watched movies in trakt.tv library", traktWatchedMovies.Count().ToString());
                }
            }
            #endregion

            #region Get collected movies from trakt.tv
            var traktCollectedMovies = TraktCache.GetCollectedMoviesFromTrakt();
            if (traktCollectedMovies == null)
            {
                TraktLogger.Error("Error getting collected movies from trakt server");
            }
            else
            {
                TraktLogger.Info("There are {0} collected movies in trakt.tv library", traktCollectedMovies.Count());
            }
            #endregion

            #region Get rated movies from trakt.tv
            //var traktRatedMovies = TraktCache.GetRatedMoviesFromTrakt();
            //if (traktRatedMovies == null)
            //{
            //  TraktLogger.Error("Error getting rated movies from trakt server");
            //}
            //else
            //{
            //  TraktLogger.Info("There are {0} rated movies in trakt.tv library", traktRatedMovies.Count());
            //}
            #endregion

            #region Get watchlisted movies from trakt.tv
            //var traktWatchlistedMovies = TraktCache.GetWatchlistedMoviesFromTrakt();
            //if (traktWatchlistedMovies == null)
            //{
            //  TraktLogger.Error("Error getting watchlisted movies from trakt server");
            //}
            //else
            //{
            //  TraktLogger.Info("There are {0} watchlisted movies in trakt.tv library", traktWatchlistedMovies.Count());
            //}
            #endregion

            #region Get custom lists from trakt.tv
            //var traktCustomLists = TraktCache.GetCustomLists();
            //if (traktCustomLists == null)
            //{
            //  TraktLogger.Error("Error getting custom lists from trakt server");
            //}
            //else
            //{
            //  TraktLogger.Info("There are {0} custom lists in trakt.tv library", traktCustomLists.Count());
            //}
            #endregion
            #endregion

            try
            {
                TestStatus = "[Trakt.SyncMovies]";
                Guid[] types            = { MediaAspect.ASPECT_ID, MovieAspect.ASPECT_ID, VideoAspect.ASPECT_ID, ImporterAspect.ASPECT_ID };
                var    contentDirectory = ServiceRegistration.Get <IServerConnectionManager>().ContentDirectory;
                if (contentDirectory == null)
                {
                    TestStatus = "[Trakt.MediaLibraryNotConnected]";
                    return(false);
                }

                #region Get local database info

                var collectedMovies = contentDirectory.Search(new MediaItemQuery(types, null, null), true);

                TraktLogger.Info("Found {0} movies available to sync in local database", collectedMovies.Count);

                // get the movies that we have watched
                var watchedMovies = collectedMovies.Where(IsWatched).ToList();
                TraktLogger.Info("Found {0} watched movies available to sync in local database", watchedMovies.Count);

                #endregion

                #region Add movies to watched history at trakt.tv
                if (traktWatchedMovies != null)
                {
                    var syncWatchedMovies = new List <TraktSyncMovieWatched>();
                    TraktLogger.Info("Finding movies to add to trakt.tv watched history");

                    syncWatchedMovies = (from movie in watchedMovies
                                         where !traktWatchedMovies.ToList().Exists(c => MovieMatch(movie, c.Movie))
                                         select new TraktSyncMovieWatched
                    {
                        Ids = new TraktMovieId {
                            Imdb = GetMovieImdbId(movie), Tmdb = GetMovieTmdbId(movie)
                        },
                        Title = GetMovieTitle(movie),
                        Year = GetMovieYear(movie),
                        WatchedAt = GetLastPlayedDate(movie),
                    }).ToList();

                    TraktLogger.Info("Adding {0} movies to trakt.tv watched history", syncWatchedMovies.Count);

                    if (syncWatchedMovies.Count > 0)
                    {
                        // update internal cache
                        TraktCache.AddMoviesToWatchHistory(syncWatchedMovies);

                        int pageSize = settings.SyncBatchSize;
                        int pages    = (int)Math.Ceiling((double)syncWatchedMovies.Count / pageSize);
                        for (int i = 0; i < pages; i++)
                        {
                            TraktLogger.Info("Adding movies [{0}/{1}] to trakt.tv watched history", i + 1, pages);

                            var pagedMovies = syncWatchedMovies.Skip(i * pageSize).Take(pageSize).ToList();

                            pagedMovies.ForEach(s => TraktLogger.Info("Adding movie to trakt.tv watched history. Title = '{0}', Year = '{1}', IMDb ID = '{2}', TMDb ID = '{3}', Date Watched = '{4}'",
                                                                      s.Title, s.Year.HasValue ? s.Year.ToString() : "<empty>", s.Ids.Imdb ?? "<empty>", s.Ids.Tmdb.HasValue ? s.Ids.Tmdb.ToString() : "<empty>", s.WatchedAt));

                            // remove title/year such that match against online ID only
                            if (settings.SkipMoviesWithNoIdsOnSync)
                            {
                                pagedMovies.ForEach(m => { m.Title = null; m.Year = null; });
                            }

                            var response = TraktAPI.AddMoviesToWatchedHistory(new TraktSyncMoviesWatched {
                                Movies = pagedMovies
                            });
                            TraktLogger.LogTraktResponse <TraktSyncResponse>(response);

                            // remove movies from cache which didn't succeed
                            if (response != null && response.NotFound != null && response.NotFound.Movies.Count > 0)
                            {
                                TraktCache.RemoveMoviesFromWatchHistory(response.NotFound.Movies);
                            }
                        }
                    }
                }
                #endregion

                #region Add movies to collection at trakt.tv
                if (traktCollectedMovies != null)
                {
                    var syncCollectedMovies = new List <TraktSyncMovieCollected>();
                    TraktLogger.Info("Finding movies to add to trakt.tv collection");

                    syncCollectedMovies = (from movie in collectedMovies
                                           where !traktCollectedMovies.ToList().Exists(c => MovieMatch(movie, c.Movie))
                                           select new TraktSyncMovieCollected
                    {
                        Ids = new TraktMovieId {
                            Imdb = GetMovieImdbId(movie), Tmdb = GetMovieTmdbId(movie)
                        },
                        Title = GetMovieTitle(movie),
                        Year = GetMovieYear(movie),
                        CollectedAt = GetDateAddedToDb(movie),
                        MediaType = GetVideoMediaType(movie),
                        Resolution = GetVideoResolution(movie),
                        AudioCodec = GetVideoAudioCodec(movie),
                        AudioChannels = "",
                        Is3D = false
                    }).ToList();

                    TraktLogger.Info("Adding {0} movies to trakt.tv watched history", syncCollectedMovies.Count);

                    if (syncCollectedMovies.Count > 0)
                    {
                        //update internal cache
                        TraktCache.AddMoviesToCollection(syncCollectedMovies);
                        int pageSize = settings.SyncBatchSize;
                        int pages    = (int)Math.Ceiling((double)syncCollectedMovies.Count / pageSize);
                        for (int i = 0; i < pages; i++)
                        {
                            TraktLogger.Info("Adding movies [{0}/{1}] to trakt.tv collection", i + 1, pages);

                            var pagedMovies = syncCollectedMovies.Skip(i * pageSize).Take(pageSize).ToList();

                            pagedMovies.ForEach(s => TraktLogger.Info("Adding movie to trakt.tv collection. Title = '{0}', Year = '{1}', IMDb ID = '{2}', TMDb ID = '{3}', Date Added = '{4}', MediaType = '{5}', Resolution = '{6}', Audio Codec = '{7}', Audio Channels = '{8}'",
                                                                      s.Title, s.Year.HasValue ? s.Year.ToString() : "<empty>", s.Ids.Imdb ?? "<empty>", s.Ids.Tmdb.HasValue ? s.Ids.Tmdb.ToString() : "<empty>",
                                                                      s.CollectedAt, s.MediaType ?? "<empty>", s.Resolution ?? "<empty>", s.AudioCodec ?? "<empty>", s.AudioChannels ?? "<empty>"));

                            //// remove title/year such that match against online ID only
                            if (settings.SkipMoviesWithNoIdsOnSync)
                            {
                                pagedMovies.ForEach(m =>
                                {
                                    m.Title = null;
                                    m.Year  = null;
                                });
                            }

                            var response = TraktAPI.AddMoviesToCollecton(new TraktSyncMoviesCollected {
                                Movies = pagedMovies
                            });
                            TraktLogger.LogTraktResponse(response);

                            // remove movies from cache which didn't succeed
                            if (response != null && response.NotFound != null && response.NotFound.Movies.Count > 0)
                            {
                                TraktCache.RemoveMoviesFromCollection(response.NotFound.Movies);
                            }
                        }
                    }
                }
                #endregion
                return(true);
            }
            catch (Exception ex)
            {
                ServiceRegistration.Get <ILogger>().Error("Trakt.tv: Exception while synchronizing media library.", ex);
            }
            return(false);
        }
        public bool Scrobble(string filename)
        {
            StopScrobble();

            if (!g_Player.IsTV)
            {
                return(false);
            }

            try
            {
                CurrentProgram = GetCurrentProgram();
            }
            catch (Exception e)
            {
                TraktLogger.Error(e.Message);
                return(false);
            }
            if (CurrentProgram == null)
            {
                return(false);
            }
            CurrentProgram.IsScrobbling = true;

            if (CurrentProgram.Type == VideoType.Series)
            {
                TraktLogger.Info("Detected tv-series '{0}' playing in 4TR TV Live", CurrentProgram.ToString());
            }
            else
            {
                TraktLogger.Info("Detected movie '{0}' playing in 4TR TV Live", CurrentProgram.ToString());
            }

            #region scrobble timer
            TraktTimer = new Timer(new TimerCallback((stateInfo) =>
            {
                Thread.CurrentThread.Name = "Scrobble";

                // get the current program airing on tv now
                // this may have changed since last status update on trakt
                VideoInfo videoInfo = GetCurrentProgram();

                if (videoInfo != null)
                {
                    // if we are watching something different,
                    // check if we should mark previous as watched
                    if (!videoInfo.Equals(CurrentProgram))
                    {
                        TraktLogger.Info("Detected new tv program has started '{0}' -> '{1}'", CurrentProgram.ToString(), videoInfo.ToString());
                        if (IsProgramWatched(CurrentProgram) && CurrentProgram.IsScrobbling)
                        {
                            ScrobbleProgram(CurrentProgram);
                        }
                        CurrentProgram.IsScrobbling = true;
                    }

                    // continue watching new program
                    // dont try to scrobble if previous attempt failed
                    if (CurrentProgram.IsScrobbling)
                    {
                        if (videoInfo.Type == VideoType.Series)
                        {
                            videoInfo.IsScrobbling = BasicHandler.ScrobbleEpisode(videoInfo, TraktScrobbleStates.watching);
                        }
                        else
                        {
                            videoInfo.IsScrobbling = BasicHandler.ScrobbleMovie(videoInfo, TraktScrobbleStates.watching);
                        }

                        // set current program to new program
                        CurrentProgram = videoInfo;
                    }
                }
            }), null, 1000, 300000);
            #endregion

            return(true);
        }
        public static int LoadTranslations(string lang)
        {
            XmlDocument doc = new XmlDocument();
            Dictionary <string, string> TranslatedStrings = new Dictionary <string, string>();
            string langPath = string.Empty;

            try
            {
                langPath = Path.Combine(path, lang + ".xml");
                doc.Load(langPath);
            }
            catch (Exception e)
            {
                if (lang == "en")
                {
                    return(0); // otherwise we are in an endless loop!
                }
                if (e.GetType() == typeof(FileNotFoundException))
                {
                    TraktLogger.Warning("Cannot find translation file {0}. Falling back to English", langPath);
                }
                else
                {
                    TraktLogger.Error("Error in translation xml file: {0}. Falling back to English", lang);
                }

                return(LoadTranslations("en"));
            }
            foreach (XmlNode stringEntry in doc.DocumentElement.ChildNodes)
            {
                if (stringEntry.NodeType == XmlNodeType.Element)
                {
                    try
                    {
                        string key = stringEntry.Attributes.GetNamedItem("name").Value;
                        if (!TranslatedStrings.ContainsKey(key))
                        {
                            TranslatedStrings.Add(key, stringEntry.InnerText.NormalizeTranslation());
                        }
                        else
                        {
                            TraktLogger.Error("Error in Translation Engine, the translation key '{0}' already exists.", key);
                        }
                    }
                    catch (Exception ex)
                    {
                        TraktLogger.Error("Error in Translation Engine: {0}", ex.Message);
                    }
                }
            }

            Type TransType = typeof(Translation);

            FieldInfo[] fieldInfos = TransType.GetFields(BindingFlags.Public | BindingFlags.Static);
            foreach (FieldInfo fi in fieldInfos)
            {
                if (TranslatedStrings != null && TranslatedStrings.ContainsKey(fi.Name))
                {
                    TransType.InvokeMember(fi.Name, BindingFlags.SetField, null, TransType, new object[] { TranslatedStrings[fi.Name] });
                }
                else
                {
                    TraktLogger.Info("Translation not found for field: {0}. Using hard-coded English default.", fi.Name);
                }
            }
            return(TranslatedStrings.Count);
        }
        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");
        }