private ITraktSyncCollectionPost GetCollectedShowsForSync(IList <MediaItem> localCollectedEpisodes, IEnumerable <EpisodeCollected> traktEpisodesCollected)
        {
            _mediaPortalServices.GetLogger().Info("Trakt: finding local episodes to add to trakt collection");
            TraktSyncCollectionPostBuilder     builder        = new TraktSyncCollectionPostBuilder();
            ILookup <string, EpisodeCollected> onlineEpisodes = traktEpisodesCollected.ToLookup(tce => CreateLookupKey(tce), tce => tce);

            foreach (var episode in localCollectedEpisodes)
            {
                string           tvdbKey      = CreateLookupKey(episode);
                EpisodeCollected traktEpisode = onlineEpisodes[tvdbKey].FirstOrDefault();

                if (traktEpisode == null)
                {
                    TraktShow show = new TraktShow
                    {
                        Title = MediaItemAspectsUtl.GetSeriesTitle(episode),
                        Ids   = new TraktShowIds
                        {
                            Tvdb = MediaItemAspectsUtl.GetTvdbId(episode),
                            Imdb = MediaItemAspectsUtl.GetSeriesImdbId(episode)
                        }
                    };

                    TraktMetadata metadata = new TraktMetadata
                    {
                        Audio            = MediaItemAspectsUtl.GetVideoAudioCodec(episode),
                        AudioChannels    = MediaItemAspectsUtl.GetVideoAudioChannel(episode),
                        MediaResolution  = MediaItemAspectsUtl.GetVideoResolution(episode),
                        MediaType        = MediaItemAspectsUtl.GetVideoMediaType(episode),
                        ThreeDimensional = false
                    };

                    DateTime collectedAt = MediaItemAspectsUtl.GetDateAddedToDb(episode);

                    builder.AddShow(show,
                                    new PostSeasons
                    {
                        {
                            MediaItemAspectsUtl.GetSeasonIndex(episode),
                            new PostEpisodes
                            {
                                { MediaItemAspectsUtl.GetEpisodeIndex(episode), metadata, collectedAt }
                            }
                        }
                    });
                }
            }
            return(builder.Build());
        }
        public TraktSyncMoviesResult SyncMovies()
        {
            _mediaPortalServices.GetLogger().Info("Trakt: start sync movies");

            ValidateAuthorization();

            TraktSyncMoviesResult  syncMoviesResult     = new TraktSyncMoviesResult();
            TraktMovies            traktMovies          = _traktCache.RefreshMoviesCache();
            IList <Movie>          traktUnWatchedMovies = traktMovies.UnWatched;
            IList <MovieWatched>   traktWatchedMovies   = traktMovies.Watched;
            IList <MovieCollected> traktCollectedMovies = traktMovies.Collected;

            Guid[] types =
            {
                MediaAspect.ASPECT_ID,              MovieAspect.ASPECT_ID,            VideoAspect.ASPECT_ID,       ImporterAspect.ASPECT_ID,
                ExternalIdentifierAspect.ASPECT_ID, ProviderResourceAspect.ASPECT_ID, VideoStreamAspect.ASPECT_ID,
                VideoAudioStreamAspect.ASPECT_ID
            };

            IContentDirectory contentDirectory = _mediaPortalServices.GetServerConnectionManager().ContentDirectory;

            if (contentDirectory == null)
            {
                throw new MediaLibraryNotConnectedException("ML not connected");
            }

            Guid?           userProfile = null;
            IUserManagement userProfileDataManagement = _mediaPortalServices.GetUserManagement();

            if (userProfileDataManagement != null && userProfileDataManagement.IsValidUser)
            {
                userProfile = userProfileDataManagement.CurrentUser.ProfileId;
            }

            #region Get local database info

            IList <MediaItem> collectedMovies = contentDirectory.SearchAsync(new MediaItemQuery(types, null, null), true, userProfile, false).Result;

            if (collectedMovies.Any())
            {
                syncMoviesResult.CollectedInLibrary = collectedMovies.Count;
                _mediaPortalServices.GetLogger().Info("Trakt: found {0} collected movies available to sync in media library", collectedMovies.Count);
            }

            List <MediaItem> watchedMovies = collectedMovies.Where(MediaItemAspectsUtl.IsWatched).ToList();

            if (watchedMovies.Any())
            {
                syncMoviesResult.WatchedInLibrary = watchedMovies.Count;
                _mediaPortalServices.GetLogger().Info("Trakt: found {0} watched movies available to sync in media library", watchedMovies.Count);
            }

            #endregion

            #region Mark movies as unwatched in local database

            _mediaPortalServices.GetLogger().Info("Trakt: start marking movies as unwatched in media library");
            if (traktUnWatchedMovies.Any())
            {
                foreach (var movie in traktUnWatchedMovies)
                {
                    var localMovie = watchedMovies.FirstOrDefault(m => MovieMatch(m, movie));
                    if (localMovie == null)
                    {
                        continue;
                    }

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

                    if (_mediaPortalServices.MarkAsUnWatched(localMovie).Result)
                    {
                        syncMoviesResult.MarkedAsUnWatchedInLibrary++;
                    }
                }

                // update watched set
                watchedMovies = collectedMovies.Where(MediaItemAspectsUtl.IsWatched).ToList();
            }

            #endregion

            #region Mark movies as watched in local database

            _mediaPortalServices.GetLogger().Info("Trakt: start marking movies as watched in media library");
            if (traktWatchedMovies.Any())
            {
                foreach (var twm in traktWatchedMovies)
                {
                    var localMovie = collectedMovies.FirstOrDefault(m => MovieMatch(m, twm));
                    if (localMovie == null)
                    {
                        continue;
                    }

                    _mediaPortalServices.GetLogger().Info(
                        "Marking movie as watched in library, movie is watched on trakt. Plays = '{0}', Title = '{1}', Year = '{2}', IMDb ID = '{3}', TMDb ID = '{4}'",
                        twm.Plays, twm.Title, twm.Year.HasValue ? twm.Year.ToString() : "<empty>",
                        twm.Imdb ?? "<empty>", twm.Tmdb.HasValue ? twm.Tmdb.ToString() : "<empty>");

                    if (_mediaPortalServices.MarkAsWatched(localMovie).Result)
                    {
                        syncMoviesResult.MarkedAsWatchedInLibrary++;
                    }
                }
            }

            #endregion

            #region Add movies to watched history at trakt.tv

            _mediaPortalServices.GetLogger().Info("Trakt: finding movies to add to watched history");

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

            if (syncWatchedMovies.Any())
            {
                _mediaPortalServices.GetLogger().Info("Trakt: trying to add {0} watched movies to trakt watched history", syncWatchedMovies.Count);

                ITraktSyncHistoryPostResponse watchedResponse = _traktClient.AddWatchedHistoryItems(new TraktSyncHistoryPost {
                    Movies = syncWatchedMovies
                });
                syncMoviesResult.AddedToTraktWatchedHistory = watchedResponse.Added?.Movies;
                _traktCache.ClearLastActivity(FileName.WatchedMovies.Value);

                if (watchedResponse.Added?.Movies != null)
                {
                    _mediaPortalServices.GetLogger().Info("Trakt: successfully added {0} watched movies to trakt watched history", watchedResponse.Added.Movies.Value);
                }
            }

            #endregion

            #region Add movies to collection at trakt.tv

            _mediaPortalServices.GetLogger().Info("Trakt: finding movies to add to collection");

            List <TraktSyncCollectionPostMovie> syncCollectedMovies = (from movie in collectedMovies
                                                                       where !traktCollectedMovies.ToList().Exists(c => MovieMatch(movie, c))
                                                                       select new TraktSyncCollectionPostMovie
            {
                MediaType = MediaItemAspectsUtl.GetVideoMediaType(movie),
                MediaResolution = MediaItemAspectsUtl.GetVideoResolution(movie),
                Audio = MediaItemAspectsUtl.GetVideoAudioCodec(movie),
                AudioChannels = MediaItemAspectsUtl.GetVideoAudioChannel(movie),
                ThreeDimensional = false,

                Ids = new TraktMovieIds
                {
                    Imdb = MediaItemAspectsUtl.GetMovieImdbId(movie),
                    Tmdb = MediaItemAspectsUtl.GetMovieTmdbId(movie)
                },
                Title = MediaItemAspectsUtl.GetMovieTitle(movie),
                Year = MediaItemAspectsUtl.GetMovieYear(movie),
                CollectedAt = MediaItemAspectsUtl.GetDateAddedToDb(movie)
            }).ToList();

            if (syncCollectedMovies.Any())
            {
                _mediaPortalServices.GetLogger().Info("Trakt: trying to add {0} collected movies to trakt collection", syncCollectedMovies.Count);

                foreach (var traktSyncCollectionPostMovie in syncCollectedMovies)
                {
                    string audio     = traktSyncCollectionPostMovie.Audio?.DisplayName;
                    string channel   = traktSyncCollectionPostMovie.AudioChannels?.DisplayName;
                    string res       = traktSyncCollectionPostMovie.MediaResolution?.DisplayName;
                    string mediatype = traktSyncCollectionPostMovie.MediaType?.DisplayName;
                    string name      = traktSyncCollectionPostMovie.Title;
                    _mediaPortalServices.GetLogger().Info("Trakt: {0}, {1}, {2}, {3}, {4}", audio, channel, res, mediatype, name);
                }
                ITraktSyncCollectionPostResponse collectionResponse = _traktClient.AddCollectionItems(new TraktSyncCollectionPost {
                    Movies = syncCollectedMovies
                });
                syncMoviesResult.AddedToTraktCollection = collectionResponse.Added?.Movies;
                _traktCache.ClearLastActivity(FileName.CollectedMovies.Value);

                if (collectionResponse.Added?.Movies != null)
                {
                    _mediaPortalServices.GetLogger().Info("Trakt: successfully added {0} collected movies to trakt collection", collectionResponse.Added.Movies.Value);
                }
            }
            #endregion

            return(syncMoviesResult);
        }