private async Task SyncUserLibrary(User user,
                                           TraktUser traktUser,
                                           double progPercent,
                                           double percentPerUser,
                                           IProgress <double> progress,
                                           CancellationToken cancellationToken)
        {
            var libraryRoot = user.RootFolder;
            // purely for progress reporting
            var mediaItemsCount = libraryRoot.GetRecursiveChildren(user).Count(i => _traktApi.CanSync(i, traktUser));

            if (mediaItemsCount == 0)
            {
                _logger.Info("No media found for '" + user.Name + "'.");
                return;
            }
            _logger.Info(mediaItemsCount + " Items found for '" + user.Name + "'.");

            var percentPerItem = (float)percentPerUser / mediaItemsCount / 2.0;

            /*
             * In order to sync watched status to trakt.tv we need to know what's been watched on Trakt already. This
             * will stop us from endlessly incrementing the watched values on the site.
             */
            var traktWatchedMovies = await _traktApi.SendGetAllWatchedMoviesRequest(traktUser).ConfigureAwait(false);

            var traktCollectedMovies = await _traktApi.SendGetAllCollectedMoviesRequest(traktUser).ConfigureAwait(false);

            var movieItems = libraryRoot.GetRecursiveChildren(user)
                             .Where(x => x is Movie)
                             .Where(x => _traktApi.CanSync(x, traktUser))
                             .OrderBy(x => x.Name)
                             .ToList();
            var movies         = new List <Movie>();
            var playedMovies   = new List <Movie>();
            var unPlayedMovies = new List <Movie>();

            foreach (var child in movieItems)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var movie    = child as Movie;
                var userData = _userDataManager.GetUserData(user.Id, child.GetUserDataKey());

                var collectedMovies = SyncFromTraktTask.FindMatches(movie, traktCollectedMovies).ToList();
                if (!collectedMovies.Any() || collectedMovies.All(collectedMovie => collectedMovie.MetadataIsDifferent(movie)))
                {
                    movies.Add(movie);
                }

                var movieWatched = SyncFromTraktTask.FindMatch(movie, traktWatchedMovies);
                if (userData.Played)
                {
                    if (movieWatched == null)
                    {
                        playedMovies.Add(movie);
                    }
                }
                else
                {
                    if (movieWatched != null)
                    {
                        unPlayedMovies.Add(movie);
                    }
                }
                // purely for progress reporting
                progPercent += percentPerItem;
                progress.Report(progPercent);
            }

            _logger.Info("Movies to add to Collection: " + movies.Count);
            // send any remaining entries
            if (movies.Count > 0)
            {
                try
                {
                    var dataContracts =
                        await
                        _traktApi.SendLibraryUpdateAsync(movies, traktUser, cancellationToken, EventType.Add)
                        .ConfigureAwait(false);

                    if (dataContracts != null)
                    {
                        foreach (var traktSyncResponse in dataContracts)
                        {
                            LogTraktResponseDataContract(traktSyncResponse);
                        }
                    }
                }
                catch (ArgumentNullException argNullEx)
                {
                    _logger.ErrorException("ArgumentNullException handled sending movies to trakt.tv", argNullEx);
                }
                catch (Exception e)
                {
                    _logger.ErrorException("Exception handled sending movies to trakt.tv", e);
                }
                // purely for progress reporting
                progPercent += (percentPerItem * movies.Count);
                progress.Report(progPercent);
            }

            _logger.Info("Movies to set watched: " + playedMovies.Count);
            if (playedMovies.Count > 0)
            {
                try
                {
                    var dataContracts =
                        await _traktApi.SendMoviePlaystateUpdates(playedMovies, traktUser, true, cancellationToken);

                    if (dataContracts != null)
                    {
                        foreach (var traktSyncResponse in dataContracts)
                        {
                            LogTraktResponseDataContract(traktSyncResponse);
                        }
                    }
                }
                catch (Exception e)
                {
                    _logger.ErrorException("Error updating movie play states", e);
                }
                // purely for progress reporting
                progPercent += (percentPerItem * playedMovies.Count);
                progress.Report(progPercent);
            }

            _logger.Info("Movies to set unwatched: " + unPlayedMovies.Count);
            if (unPlayedMovies.Count > 0)
            {
                try
                {
                    var dataContracts =
                        await _traktApi.SendMoviePlaystateUpdates(unPlayedMovies, traktUser, false, cancellationToken);

                    if (dataContracts != null)
                    {
                        foreach (var traktSyncResponse in dataContracts)
                        {
                            LogTraktResponseDataContract(traktSyncResponse);
                        }
                    }
                }
                catch (Exception e)
                {
                    _logger.ErrorException("Error updating movie play states", e);
                }
                // purely for progress reporting
                progPercent += (percentPerItem * unPlayedMovies.Count);
                progress.Report(progPercent);
            }

            var traktWatchedShows = await _traktApi.SendGetWatchedShowsRequest(traktUser).ConfigureAwait(false);

            var traktCollectedShows = await _traktApi.SendGetCollectedShowsRequest(traktUser).ConfigureAwait(false);

            var episodeItems = libraryRoot.GetRecursiveChildren(user)
                               .Where(x => x is Episode)
                               .Where(x => _traktApi.CanSync(x, traktUser))
                               .OrderBy(x => x is Episode ? (x as Episode).SeriesName : null)
                               .ToList();

            var episodes         = new List <Episode>();
            var playedEpisodes   = new List <Episode>();
            var unPlayedEpisodes = new List <Episode>();

            foreach (var child in episodeItems)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var episode          = child as Episode;
                var userData         = _userDataManager.GetUserData(user.Id, episode.GetUserDataKey());
                var isPlayedTraktTv  = false;
                var traktWatchedShow = SyncFromTraktTask.FindMatch(episode.Series, traktWatchedShows);

                if (traktWatchedShow != null && traktWatchedShow.Seasons != null && traktWatchedShow.Seasons.Count > 0)
                {
                    isPlayedTraktTv =
                        traktWatchedShow.Seasons.Any(
                            season =>
                            season.Number == episode.GetSeasonNumber() &&
                            season.Episodes != null &&
                            season.Episodes.Any(te => te.Number == episode.IndexNumber && te.Plays > 0));
                }

                // if the show has been played locally and is unplayed on trakt.tv then add it to the list
                if (userData != null && userData.Played && !isPlayedTraktTv)
                {
                    playedEpisodes.Add(episode);
                }
                // If the show has not been played locally but is played on trakt.tv then add it to the unplayed list
                else if (userData != null && !userData.Played && isPlayedTraktTv)
                {
                    unPlayedEpisodes.Add(episode);
                }
                var traktCollectedShow = SyncFromTraktTask.FindMatch(episode.Series, traktCollectedShows);
                if (traktCollectedShow == null ||
                    traktCollectedShow.Seasons == null ||
                    traktCollectedShow.Seasons.All(x => x.Number != episode.ParentIndexNumber) ||
                    traktCollectedShow.Seasons.First(x => x.Number == episode.ParentIndexNumber)
                    .Episodes.All(e => e.Number != episode.IndexNumber))
                {
                    episodes.Add(episode);
                }

                // purely for progress reporting
                progPercent += percentPerItem;
                progress.Report(progPercent);
            }


            _logger.Info("Episodes to add to Collection: " + episodes.Count);
            if (episodes.Count > 0)
            {
                try
                {
                    var dataContracts =
                        await
                        _traktApi.SendLibraryUpdateAsync(episodes, traktUser, cancellationToken, EventType.Add)
                        .ConfigureAwait(false);

                    if (dataContracts != null)
                    {
                        foreach (var traktSyncResponse in dataContracts)
                        {
                            LogTraktResponseDataContract(traktSyncResponse);
                        }
                    }
                }
                catch (ArgumentNullException argNullEx)
                {
                    _logger.ErrorException("ArgumentNullException handled sending episodes to trakt.tv", argNullEx);
                }
                catch (Exception e)
                {
                    _logger.ErrorException("Exception handled sending episodes to trakt.tv", e);
                }
                // purely for progress reporting
                progPercent += (percentPerItem * episodes.Count);
                progress.Report(progPercent);
            }

            _logger.Info("Episodes to set watched: " + playedEpisodes.Count);
            if (playedEpisodes.Count > 0)
            {
                try
                {
                    var dataContracts =
                        await _traktApi.SendEpisodePlaystateUpdates(playedEpisodes, traktUser, true, cancellationToken);

                    if (dataContracts != null)
                    {
                        foreach (var traktSyncResponse in dataContracts)
                        {
                            LogTraktResponseDataContract(traktSyncResponse);
                        }
                    }
                }
                catch (Exception e)
                {
                    _logger.ErrorException("Error updating episode play states", e);
                }
                // purely for progress reporting
                progPercent += (percentPerItem * playedEpisodes.Count);
                progress.Report(progPercent);
            }
            _logger.Info("Episodes to set unwatched: " + unPlayedEpisodes.Count);
            if (unPlayedEpisodes.Count > 0)
            {
                try
                {
                    var dataContracts =
                        await
                        _traktApi.SendEpisodePlaystateUpdates(unPlayedEpisodes, traktUser, false, cancellationToken);

                    if (dataContracts != null)
                    {
                        foreach (var traktSyncResponse in dataContracts)
                        {
                            LogTraktResponseDataContract(traktSyncResponse);
                        }
                    }
                }
                catch (Exception e)
                {
                    _logger.ErrorException("Error updating episode play states", e);
                }
                // purely for progress reporting
                progPercent += (percentPerItem * unPlayedEpisodes.Count);
                progress.Report(progPercent);
            }
        }
Пример #2
0
        /// <summary>
        /// Sync watched and collected status of <see cref="Movie"/>s with trakt.
        /// </summary>
        private async Task SyncMovies(
            User user,
            TraktUser traktUser,
            ISplittableProgress <double> progress,
            CancellationToken cancellationToken)
        {
            /*
             * In order to sync watched status to trakt.tv we need to know what's been watched on Trakt already. This
             * will stop us from endlessly incrementing the watched values on the site.
             */
            var traktWatchedMovies = await _traktApi.SendGetAllWatchedMoviesRequest(traktUser).ConfigureAwait(false);

            var traktCollectedMovies = await _traktApi.SendGetAllCollectedMoviesRequest(traktUser).ConfigureAwait(false);

            var libraryMovies =
                _libraryManager.GetItemList(
                    new InternalItemsQuery
            {
                IncludeItemTypes     = new[] { typeof(Movie).Name },
                ExcludeLocationTypes = new[] { LocationType.Virtual }
            })
                .Where(x => _traktApi.CanSync(x, traktUser))
                .OrderBy(x => x.Name)
                .ToList();
            var collectedMovies = new List <Movie>();
            var playedMovies    = new List <Movie>();
            var unplayedMovies  = new List <Movie>();

            var decisionProgress = progress.Split(4).Split(libraryMovies.Count);

            foreach (var child in libraryMovies)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var libraryMovie = child as Movie;
                var userData     = _userDataManager.GetUserData(user.Id, child);

                // if movie is not collected, or (export media info setting is enabled and every collected matching movie has different metadata), collect it
                var collectedMathingMovies = SyncFromTraktTask.FindMatches(libraryMovie, traktCollectedMovies).ToList();
                if (!collectedMathingMovies.Any() ||
                    (traktUser.ExportMediaInfo &&
                     collectedMathingMovies.All(
                         collectedMovie => collectedMovie.MetadataIsDifferent(libraryMovie))))
                {
                    collectedMovies.Add(libraryMovie);
                }

                var movieWatched = SyncFromTraktTask.FindMatch(libraryMovie, traktWatchedMovies);

                // if the movie has been played locally and is unplayed on trakt.tv then add it to the list
                if (userData.Played)
                {
                    if (movieWatched == null)
                    {
                        if (traktUser.PostWatchedHistory)
                        {
                            playedMovies.Add(libraryMovie);
                        }
                        else if (!traktUser.SkipUnwatchedImportFromTrakt)
                        {
                            userData.Played = false;
                            await
                            _userDataManager.SaveUserData(
                                user.Id,
                                libraryMovie,
                                userData,
                                UserDataSaveReason.Import,
                                cancellationToken);
                        }
                    }
                }
                else
                {
                    // If the show has not been played locally but is played on trakt.tv then add it to the unplayed list
                    if (movieWatched != null)
                    {
                        unplayedMovies.Add(libraryMovie);
                    }
                }

                decisionProgress.Report(100);
            }

            // send movies to mark collected
            await SendMovieCollectionUpdates(true, traktUser, collectedMovies, progress.Split(4), cancellationToken);

            // send movies to mark watched
            await SendMoviePlaystateUpdates(true, traktUser, playedMovies, progress.Split(4), cancellationToken);

            // send movies to mark unwatched
            await SendMoviePlaystateUpdates(false, traktUser, unplayedMovies, progress.Split(4), cancellationToken);
        }
Пример #3
0
        /// <summary>
        /// Sync watched and collected status of <see cref="Movie"/>s with trakt.
        /// </summary>
        private async Task SyncShows(
            User user,
            TraktUser traktUser,
            ISplittableProgress <double> progress,
            CancellationToken cancellationToken)
        {
            var traktWatchedShows = await _traktApi.SendGetWatchedShowsRequest(traktUser).ConfigureAwait(false);

            var traktCollectedShows = await _traktApi.SendGetCollectedShowsRequest(traktUser).ConfigureAwait(false);

            var episodeItems =
                _libraryManager.GetItemList(
                    new InternalItemsQuery
            {
                IncludeItemTypes     = new[] { typeof(Episode).Name },
                ExcludeLocationTypes = new[] { LocationType.Virtual }
            })
                .Where(x => _traktApi.CanSync(x, traktUser))
                .OrderBy(x => (x as Episode)?.SeriesName)
                .ToList();

            var collectedEpisodes = new List <Episode>();
            var playedEpisodes    = new List <Episode>();
            var unplayedEpisodes  = new List <Episode>();

            var decisionProgress = progress.Split(4).Split(episodeItems.Count);

            foreach (var child in episodeItems)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var episode          = child as Episode;
                var userData         = _userDataManager.GetUserData(user.Id, episode);
                var isPlayedTraktTv  = false;
                var traktWatchedShow = SyncFromTraktTask.FindMatch(episode.Series, traktWatchedShows);

                if (traktWatchedShow?.Seasons != null && traktWatchedShow.Seasons.Count > 0)
                {
                    isPlayedTraktTv =
                        traktWatchedShow.Seasons.Any(
                            season =>
                            season.Number == episode.GetSeasonNumber() && season.Episodes != null &&
                            season.Episodes.Any(te => te.Number == episode.IndexNumber && te.Plays > 0));
                }

                // if the show has been played locally and is unplayed on trakt.tv then add it to the list
                if (userData != null && userData.Played && !isPlayedTraktTv)
                {
                    if (traktUser.PostWatchedHistory)
                    {
                        playedEpisodes.Add(episode);
                    }
                    else if (!traktUser.SkipUnwatchedImportFromTrakt)
                    {
                        userData.Played = false;
                        await
                        _userDataManager.SaveUserData(
                            user.Id,
                            episode,
                            userData,
                            UserDataSaveReason.Import,
                            cancellationToken);
                    }
                }
                else if (userData != null && !userData.Played && isPlayedTraktTv)
                {
                    // If the show has not been played locally but is played on trakt.tv then add it to the unplayed list
                    unplayedEpisodes.Add(episode);
                }

                var traktCollectedShow = SyncFromTraktTask.FindMatch(episode.Series, traktCollectedShows);
                if (traktCollectedShow?.Seasons == null ||
                    traktCollectedShow.Seasons.All(x => x.Number != episode.ParentIndexNumber) ||
                    traktCollectedShow.Seasons.First(x => x.Number == episode.ParentIndexNumber)
                    .Episodes.All(e => e.Number != episode.IndexNumber))
                {
                    collectedEpisodes.Add(episode);
                }

                decisionProgress.Report(100);
            }

            await SendEpisodeCollectionUpdates(true, traktUser, collectedEpisodes, progress.Split(4), cancellationToken);

            await SendEpisodePlaystateUpdates(true, traktUser, playedEpisodes, progress.Split(4), cancellationToken);

            await SendEpisodePlaystateUpdates(false, traktUser, unplayedEpisodes, progress.Split(4), cancellationToken);
        }
        private async Task SyncUserLibrary(User user,
                                           TraktUser traktUser,
                                           double progPercent,
                                           double percentPerUser,
                                           IProgress <double> progress,
                                           CancellationToken cancellationToken)
        {
            var libraryRoot = user.RootFolder;

            /*
             * In order to sync watched status to trakt.tv we need to know what's been watched on Trakt already. This
             * will stop us from endlessly incrementing the watched values on the site.
             */
            List <TraktMovieDataContract> tMovies = await _traktApi.SendGetAllMoviesRequest(traktUser).ConfigureAwait(false);

            List <TraktUserLibraryShowDataContract> tShowsWatched = await _traktApi.SendGetWatchedShowsRequest(traktUser).ConfigureAwait(false);

            var movies           = new List <Movie>();
            var episodes         = new List <Episode>();
            var playedMovies     = new List <Movie>();
            var playedEpisodes   = new List <Episode>();
            var unPlayedMovies   = new List <Movie>();
            var unPlayedEpisodes = new List <Episode>();
            var currentSeriesId  = Guid.Empty;

            var mediaItems = libraryRoot.GetRecursiveChildren(user)
                             .Where(SyncFromTraktTask.CanSync)
                             .ToList();

            if (mediaItems.Count == 0)
            {
                _logger.Info("No trakt media found for '" + user.Name + "'. Have trakt locations been configured?");
                return;
            }

            // purely for progress reporting
            var percentPerItem = percentPerUser / mediaItems.Count;

            foreach (var child in mediaItems)
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (child.Path == null || child.LocationType == LocationType.Virtual)
                {
                    continue;
                }

                if (child is Movie)
                {
                    var movie = (Movie)child;
                    movies.Add(movie);

                    var userData = _userDataManager.GetUserData(user.Id, child.GetUserDataKey());

                    var traktTvMovie = SyncFromTraktTask.FindMatch(child, tMovies);

                    if (traktTvMovie != null && userData.Played && (traktTvMovie.Watched == false || traktTvMovie.Plays < userData.PlayCount))
                    {
                        playedMovies.Add(movie);
                    }
                    else if (traktTvMovie != null && traktTvMovie.Watched && !userData.Played)
                    {
                        unPlayedMovies.Add(movie);
                    }

                    // publish if the list hits a certain size
                    if (movies.Count >= 120)
                    {
                        // Add movies to library
                        try
                        {
                            var dataContract = await _traktApi.SendLibraryUpdateAsync(movies, traktUser, cancellationToken, EventType.Add).ConfigureAwait(false);

                            if (dataContract != null)
                            {
                                LogTraktResponseDataContract(dataContract);
                            }
                        }
                        catch (ArgumentNullException argNullEx)
                        {
                            _logger.ErrorException("ArgumentNullException handled sending movies to trakt.tv", argNullEx);
                        }
                        catch (Exception e)
                        {
                            _logger.ErrorException("Exception handled sending movies to trakt.tv", e);
                        }
                        movies.Clear();

                        // Mark movies seen
                        if (playedMovies.Count > 0)
                        {
                            try
                            {
                                var dataCotract = await _traktApi.SendMoviePlaystateUpdates(playedMovies, traktUser, true, cancellationToken);

                                if (dataCotract != null)
                                {
                                    LogTraktResponseDataContract(dataCotract);
                                }
                            }
                            catch (Exception e)
                            {
                                _logger.ErrorException("Error updating played state", e);
                            }

                            playedMovies.Clear();
                        }

                        // Mark movies unseen
                        if (unPlayedMovies.Count > 0)
                        {
                            try
                            {
                                var dataContract = await _traktApi.SendMoviePlaystateUpdates(unPlayedMovies, traktUser, false, cancellationToken);

                                if (dataContract != null)
                                {
                                    LogTraktResponseDataContract(dataContract);
                                }
                            }
                            catch (Exception e)
                            {
                                _logger.ErrorException("Error updating played state", e);
                            }

                            unPlayedMovies.Clear();
                        }
                    }
                }
                else if (child is Episode)
                {
                    var ep     = child as Episode;
                    var series = ep.Series;

                    var userData = _userDataManager.GetUserData(user.Id, ep.GetUserDataKey());

                    var isPlayedTraktTv = false;

                    var traktTvShow = SyncFromTraktTask.FindMatch(series, tShowsWatched);

                    if (traktTvShow != null && traktTvShow.Seasons != null && traktTvShow.Seasons.Count > 0)
                    {
                        foreach (var episode in from season in traktTvShow.Seasons where ep.Season != null && season.Season.Equals(ep.Season.IndexNumber) && season.Episodes != null && season.Episodes.Count > 0 from episode in season.Episodes where episode.Equals(ep.IndexNumber) select episode)
                        {
                            isPlayedTraktTv = true;
                        }
                    }

                    if (series != null && currentSeriesId != series.Id && episodes.Count > 0)
                    {
                        // We're starting a new show. Finish up with the old one

                        // Add episodes to trakt.tv library
                        try
                        {
                            var dataContract = await _traktApi.SendLibraryUpdateAsync(episodes, traktUser, cancellationToken, EventType.Add).ConfigureAwait(false);

                            if (dataContract != null)
                            {
                                LogTraktResponseDataContract(dataContract);
                            }
                        }
                        catch (ArgumentNullException argNullEx)
                        {
                            _logger.ErrorException("ArgumentNullException handled sending episodes to trakt.tv", argNullEx);
                        }
                        catch (Exception e)
                        {
                            _logger.ErrorException("Exception handled sending episodes to trakt.tv", e);
                        }

                        // Update played state of these episodes
                        if (playedEpisodes.Count > 0)
                        {
                            try
                            {
                                var dataContracts = await _traktApi.SendEpisodePlaystateUpdates(playedEpisodes, traktUser, true, cancellationToken);

                                if (dataContracts != null)
                                {
                                    foreach (var dataContract in dataContracts)
                                    {
                                        LogTraktResponseDataContract(dataContract);
                                    }
                                }
                            }
                            catch (Exception e)
                            {
                                _logger.ErrorException("Exception handled sending played episodes to trakt.tv", e);
                            }
                        }

                        if (unPlayedEpisodes.Count > 0)
                        {
                            try
                            {
                                var dataContracts = await _traktApi.SendEpisodePlaystateUpdates(unPlayedEpisodes, traktUser, false, cancellationToken);

                                if (dataContracts != null)
                                {
                                    foreach (var dataContract in dataContracts)
                                    {
                                        LogTraktResponseDataContract(dataContract);
                                    }
                                }
                            }
                            catch (Exception e)
                            {
                                _logger.ErrorException("Exception handled sending played episodes to trakt.tv", e);
                            }
                        }

                        episodes.Clear();
                        playedEpisodes.Clear();
                        unPlayedEpisodes.Clear();
                    }

                    if (ep.Series != null)
                    {
                        currentSeriesId = ep.Series.Id;
                        episodes.Add(ep);
                    }

                    // if the show has been played locally and is unplayed on trakt.tv then add it to the list
                    if (userData != null && userData.Played && !isPlayedTraktTv)
                    {
                        playedEpisodes.Add(ep);
                    }
                    // If the show has not been played locally but is played on trakt.tv then add it to the unplayed list
                    else if (userData != null && !userData.Played && isPlayedTraktTv)
                    {
                        unPlayedEpisodes.Add(ep);
                    }
                }

                // purely for progress reporting
                progPercent += percentPerItem;
                progress.Report(progPercent);
            }

            // send any remaining entries
            if (movies.Count > 0)
            {
                try
                {
                    var dataContract = await _traktApi.SendLibraryUpdateAsync(movies, traktUser, cancellationToken, EventType.Add).ConfigureAwait(false);

                    if (dataContract != null)
                    {
                        LogTraktResponseDataContract(dataContract);
                    }
                }
                catch (ArgumentNullException argNullEx)
                {
                    _logger.ErrorException("ArgumentNullException handled sending movies to trakt.tv", argNullEx);
                }
                catch (Exception e)
                {
                    _logger.ErrorException("Exception handled sending movies to trakt.tv", e);
                }
            }

            if (episodes.Count > 0)
            {
                try
                {
                    var dataContract = await _traktApi.SendLibraryUpdateAsync(episodes, traktUser, cancellationToken, EventType.Add).ConfigureAwait(false);

                    if (dataContract != null)
                    {
                        LogTraktResponseDataContract(dataContract);
                    }
                }
                catch (ArgumentNullException argNullEx)
                {
                    _logger.ErrorException("ArgumentNullException handled sending episodes to trakt.tv", argNullEx);
                }
                catch (Exception e)
                {
                    _logger.ErrorException("Exception handled sending episodes to trakt.tv", e);
                }
            }

            if (playedMovies.Count > 0)
            {
                try
                {
                    var dataContract = await _traktApi.SendMoviePlaystateUpdates(playedMovies, traktUser, true, cancellationToken);

                    if (dataContract != null)
                    {
                        LogTraktResponseDataContract(dataContract);
                    }
                }
                catch (Exception e)
                {
                    _logger.ErrorException("Error updating movie play states", e);
                }
            }

            if (playedEpisodes.Count > 0)
            {
                try
                {
                    var dataContracts = await _traktApi.SendEpisodePlaystateUpdates(playedEpisodes, traktUser, true, cancellationToken);

                    if (dataContracts != null)
                    {
                        foreach (var dataContract in dataContracts)
                        {
                            LogTraktResponseDataContract(dataContract);
                        }
                    }
                }
                catch (Exception e)
                {
                    _logger.ErrorException("Error updating episode play states", e);
                }
            }

            if (unPlayedEpisodes.Count > 0)
            {
                try
                {
                    var dataContracts = await _traktApi.SendEpisodePlaystateUpdates(unPlayedEpisodes, traktUser, false, cancellationToken);

                    if (dataContracts != null)
                    {
                        foreach (var dataContract in dataContracts)
                        {
                            LogTraktResponseDataContract(dataContract);
                        }
                    }
                }
                catch (Exception e)
                {
                    _logger.ErrorException("Error updating episode play states", e);
                }
            }
        }