Jump to content

Trakt Plugin NullReferenceException when syncing Library to Trakt


smokey7722

Recommended Posts

smokey7722

 Most of the time the scheduled task to sync my Library to Trakt is failing with the following error.  I did find one other post mentioning this however the poster claimed it was resolved.  The log below is for the task execution and unfortunately I don't see anything that would be able to help me troubleshoot its failure.

2014-08-20 08:53:38.4844 Debug - HttpServer: HTTP POST http://10.0.0.8:8896/mediabrowser/ScheduledTasks/Running/b1a52e63d5fb09335557d4f1e6402299
2014-08-20 08:53:38.4844 Info - App: Executing Sync library to trakt.tv
2014-08-20 08:53:38.4844 Debug - HttpServer: HTTP Response 204 to 10.0.0.200. Response time: 3.906 ms.
	Url: http://10.0.0.8:8896/mediabrowser/ScheduledTasks/Running/b1a52e63d5fb09335557d4f1e6402299
2014-08-20 08:53:38.5001 Debug - HttpServer: HTTP GET http://10.0.0.8:8896/mediabrowser/ScheduledTasks?isHidden=false
2014-08-20 08:53:38.5001 Debug - HttpServer: HTTP Response 200 to 10.0.0.200. Response time: 1.953 ms.
	Url: http://10.0.0.8:8896/mediabrowser/ScheduledTasks?isHidden=false
2014-08-20 08:53:38.5635 Info - App: HttpClientManager POST: http://api.trakt.tv/user/library/movies/all.json/77449c38c9f4f9b3cdb8d3f9ef0566b167a935eb/smokey7722
2014-08-20 08:53:40.2823 Info - App: HttpClientManager POST: http://api.trakt.tv/user/library/shows/watched.json/77449c38c9f4f9b3cdb8d3f9ef0566b167a935eb/smokey7722
2014-08-20 08:53:40.7794 Error - App: Error
	Object reference not set to an instance of an object.
	System.NullReferenceException
	   at Trakt.ScheduledTasks.SyncLibraryTask.<Execute>b__2(BaseItem i)
	   at System.Linq.Enumerable.WhereListIterator`1.MoveNext()
	   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
	   at System.Linq.OrderedEnumerable`1.<GetEnumerator>d__0.MoveNext()
	   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
	   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
	   at Trakt.ScheduledTasks.SyncLibraryTask.<Execute>d__1d.MoveNext()
	--- End of stack trace from previous location where exception was thrown ---
	   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
	   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
	   at MediaBrowser.Common.Implementations.ScheduledTasks.ScheduledTaskWorker.<>c__DisplayClassf.<<ExecuteTask>b__e>d__11.MoveNext()
	--- End of stack trace from previous location where exception was thrown ---
	   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
	   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
	   at MediaBrowser.Common.Implementations.ScheduledTasks.ScheduledTaskWorker.<Execute>d__6.MoveNext()
	
2014-08-20 08:53:40.7794 Info - App: Sync library to trakt.tv Failed after 0 minute(s) and 2 seconds
2014-08-20 08:53:40.7941 Debug - NotificationManager: Sending notification via Dashboard Notifications to user adamz
2014-08-20 08:53:40.7941 Info - ServerManager: Sending web socket message NotificationAdded
2014-08-20 08:53:40.7941 Info - ServerManager: Sending web socket message ScheduledTaskEnded
2014-08-20 08:53:41.5079 Debug - HttpServer: HTTP GET http://10.0.0.8:8896/mediabrowser/Notifications/a5f2e806960a5b38dd074528f14db579/Summary
2014-08-20 08:53:41.5128 Debug - HttpServer: HTTP Response 200 to 10.0.0.200. Response time: 0.9765 ms.
	Url: http://10.0.0.8:8896/mediabrowser/Notifications/a5f2e806960a5b38dd074528f14db579/Summary

The notification list for MB only says the following as well:

Sync library to trakt.tv failed.
a minute ago
Object reference not set to an instance of an object.

Is there any direction I can go in regards to troubleshooting this?

 

Thanks!

Link to comment
Share on other sites

PurposelyCryptic

I'm guessing I was the person you mentioned, in the thread here.

 

Sadly, I'm not entirely sure why it started working again for me but not you - An MBS update came down, and afterwards it just worked. I do know my initial half-baked assumption that it was trying to access the wrong data seems to have been wrong, as the log had the same calls both when successful and not.

 

The only thing I can tell you is that the issue I had seemed to have been related to syncing tv-series, as it would sync properly if I removed them from my MBS library. I had my series in a mixed tv & movies folder type (all anime), so maybe the trakt plug-in has some sort of issue with those? That is honestly just a shot in the dark though.

 

Sorry I couldn't be more helpful, and I hope your issue gets resolved soon.

 

Edit:

The folder type theory could actually be plausible, if the 'Object' in the error message is the TV-Series/Movie to be synced, and it is trying to process is as the wrong type because it is looking at the mixed folder as being composed of a uniform type. Just a thought.

 

Although if that was the case, it shouldn't be working for me either... 

Argh, these error messages need more detail...

 

 

Edit 2:

 

I took a look through the code, but it all looks like it should work to my amateur eyes.

Maybe you can see something I missed:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using Trakt.Api;
using Trakt.Api.DataContracts;
using Trakt.Helpers;

namespace Trakt.ScheduledTasks
{
    /// <summary>
    /// Task that will Sync each users local library with their respective trakt.tv profiles. This task will only include 
    /// titles, watched states will be synced in other tasks.
    /// </summary>
    public class SyncLibraryTask : IScheduledTask
    {
        //private readonly IHttpClient _httpClient;
        private readonly IUserManager _userManager;
        private readonly ILogger _logger;
        private readonly IFileSystem _fileSystem;
        private readonly TraktApi _traktApi;
        private readonly IUserDataManager _userDataManager;

        public SyncLibraryTask(ILogManager logger, IJsonSerializer jsonSerializer, IUserManager userManager, IUserDataManager userDataManager, IHttpClient httpClient, IFileSystem fileSystem)
        {
            _userManager = userManager;
            _userDataManager = userDataManager;
            _logger = logger.GetLogger("Trakt");
            _fileSystem = fileSystem;
            _traktApi = new TraktApi(jsonSerializer, _logger, httpClient);
        }

        public IEnumerable<ITaskTrigger> GetDefaultTriggers()
        {
            return new List<ITaskTrigger>();
        }

        public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
        {
            var users = _userManager.Users.Where(u =>
            {
                var traktUser = UserHelper.GetTraktUser(u);

                return traktUser != null && traktUser.TraktLocations != null && traktUser.TraktLocations.Length > 0;

            }).ToList();

            // No point going further if we don't have users.
            if (users.Count == 0)
            {
                _logger.Info("No Users returned");
                return;
            }
            
            // purely for progress reporting
            var progPercent = 0.0;
            var percentPerUser = 100 / users.Count;

            foreach (var user in users)
            {
                var libraryRoot = user.RootFolder;
                var traktUser = UserHelper.GetTraktUser(user);

                // I'll leave this in here for now, but in reality this continue should never be reached.
                if (traktUser == null || String.IsNullOrEmpty(traktUser.LinkedMbUserId))
                {
                    _logger.Error("traktUser is either null or has no linked MB account");
                    continue;
                }

                /*
                 * 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.
                 */
                IEnumerable<TraktMovieDataContract> tMovies = await _traktApi.SendGetAllMoviesRequest(traktUser).ConfigureAwait(false);
                IEnumerable<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(i => i.Name != null &&
                        (i is Episode && ((Episode)i).Series != null && ((Episode)i).Series.ProviderIds.ContainsKey("Tvdb")) || 
                        (i is Movie && i.ProviderIds.ContainsKey("Imdb")))
                    .OrderBy(i =>
                    {
                        var episode = i as Episode;

                        return episode != null ? episode.Series.Id : i.Id;
                    })
                    .ToList();

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

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

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

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

                    foreach (var s in traktUser.TraktLocations.Where(s => _fileSystem.ContainsSubPath(s, child.Path)))
                    {
                        if (child is Movie)
                        {
                            var movie = child as Movie;
                            movies.Add(movie);

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

                            if (movie.ProviderIds.ContainsKey("Tmdb") && userData != null)
                            {
                                var traktTvMovie =
                                    tMovies.FirstOrDefault(
                                        tMovie => tMovie.TmdbId.Equals(movie.GetProviderId(MetadataProviders.Tmdb)));

                                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 userData = _userDataManager.GetUserData(user.Id, ep.GetUserDataKey());
                            
                            var isPlayedTraktTv = false;
                            
                            if (ep.Series != null && ep.Series.ProviderIds.ContainsKey("Tvdb"))
                            {
                                var traktTvShow =
                                    tShowsWatched.FirstOrDefault(
                                        tShow => tShow.TvdbId.Equals(ep.Series.GetProviderId(MetadataProviders.Tvdb)));
                                
                                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 (ep.Series != null && currentSeriesId != ep.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);
                    }
                }
            }
        }

        public string Name
        {
            get { return "Sync library to trakt.tv"; }
        }

        public string Category
        {
            get
            {
                return "Trakt";
            }
        }

        public string Description
        {
            get
            {
                return
                    "Adds any media that is in each users trakt monitored locations to their trakt.tv profile";
            }
        }

        private void LogTraktResponseDataContract(TraktResponseDataContract dataContract)
        {
            _logger.Debug("TraktResponse status: " + dataContract.Status);
            if (dataContract.Status.Equals("failure", StringComparison.OrdinalIgnoreCase))
                _logger.Error("TraktResponse error: " + dataContract.Error);
            _logger.Debug("TraktResponse message: " + dataContract.Message);
        }
    }
}
Edited by PurposelyCryptic
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...