Beispiel #1
0
        public override void ProcessCommand()
        {
            foreach (int section in ServerSettings.Plex_Libraries)
            {
                var allSeries = PlexHelper.GetForUser(_jmmuser).GetPlexSeries(section);
                foreach (PlexSeries series in allSeries)
                {
                    foreach (PlexEpisode episode in series.Episodes)
                    {
                        var            animeEpisode = episode.AnimeEpisode;
                        var            isWatched    = episode.WatchCount > 0;
                        var            lastWatched  = FromUnixTime(episode.LastWatched);
                        SVR_VideoLocal video        = animeEpisode?.GetVideoLocals()?.FirstOrDefault();
                        if (video == null)
                        {
                            continue;
                        }
                        var alreadyWatched = animeEpisode.GetVideoLocals()
                                             .Where(x => x.GetAniDBFile() != null)
                                             .Any(x => x.GetAniDBFile().IsWatched > 0);

                        if (alreadyWatched && !isWatched)
                        {
                            episode.Scrobble();
                        }
                        if (isWatched && !alreadyWatched)
                        {
                            video.ToggleWatchedStatus(true, true, lastWatched, true, true,
                                                      _jmmuser.JMMUserID, true, true);
                        }
                    }
                }
            }
        }
Beispiel #2
0
        private ActionResult ScrobbleStatusOnFile(SVR_VideoLocal file, bool?watched, long?resumePosition)
        {
            if (!(watched ?? false) && resumePosition != null)
            {
                var safeRP = resumePosition ?? 0;
                if (safeRP < 0)
                {
                    safeRP = 0;
                }

                if (safeRP >= file.Duration)
                {
                    watched = true;
                }
                else
                {
                    file.SetResumePosition(safeRP, User.JMMUserID);
                }
            }

            if (watched != null)
            {
                var safeWatched = watched ?? false;
                file.ToggleWatchedStatus(safeWatched, User.JMMUserID);
                if (safeWatched)
                {
                    file.SetResumePosition(0, User.JMMUserID);
                }
            }

            return(Ok());
        }
Beispiel #3
0
        public override void ProcessCommand()
        {
            logger.Info($"Syncing watched videos for: {_jmmuser.Username}, if nothing happens make sure you have your libraries configured in Shoko.");

            foreach (var section in PlexHelper.GetForUser(_jmmuser).GetDirectories())
            {
                if (!ServerSettings.Instance.Plex.Libraries.Contains(section.Key))
                {
                    continue;
                }

                var allSeries = ((SVR_Directory)section).GetShows();
                foreach (var series in allSeries)
                {
                    var episodes = ((SVR_PlexLibrary)series)?.GetEpisodes()?.Where(s => s != null);
                    if (episodes == null)
                    {
                        continue;
                    }
                    foreach (var ep in episodes)
                    {
                        var episode = (SVR_Episode)ep;

                        var animeEpisode = episode.AnimeEpisode;
                        if (animeEpisode == null)
                        {
                            continue;
                        }
                        var userRecord  = animeEpisode.GetUserRecord(_jmmuser.JMMUserID);
                        var isWatched   = episode.ViewCount != null && episode.ViewCount > 0;
                        var lastWatched = userRecord?.WatchedDate;
                        if (userRecord?.WatchedCount == 0 && isWatched && episode.LastViewedAt != null)
                        {
                            lastWatched = FromUnixTime((long)episode.LastViewedAt);
                        }

                        SVR_VideoLocal video = animeEpisode.GetVideoLocals()?.FirstOrDefault();
                        if (video == null)
                        {
                            continue;
                        }
                        var alreadyWatched = animeEpisode.GetVideoLocals()
                                             .Where(x => x.GetAniDBFile() != null)
                                             .Any(x => x.GetAniDBFile().IsWatched > 0);

                        if (alreadyWatched && !isWatched)
                        {
                            episode.Scrobble();
                        }

                        if (isWatched && !alreadyWatched)
                        {
                            video.ToggleWatchedStatus(true, true, lastWatched, true, _jmmuser.JMMUserID, true, true);
                        }
                    }
                }
            }
        }
Beispiel #4
0
        public override void ProcessCommand()
        {
            foreach (var section in PlexHelper.GetForUser(_jmmuser).GetDirectories().Where(d => ServerSettings.Plex_Libraries.Contains(d.Key)))
            {
                var allSeries = ((SVR_Directory)section).GetShows();
                foreach (var series in allSeries)
                {
                    var episodes = ((SVR_PlexLibrary)series)?.GetEpisodes();
                    if (episodes == null)
                    {
                        continue;
                    }
                    foreach (var ep in episodes)
                    {
                        var episode = (SVR_Episode)ep;

                        var animeEpisode = episode.AnimeEpisode;
                        if (animeEpisode == null)
                        {
                            continue;
                        }
                        var userRecord  = animeEpisode.GetUserRecord(_jmmuser.JMMUserID);
                        var isWatched   = episode.ViewCount > 0;
                        var lastWatched = userRecord.WatchedDate;
                        if (userRecord.WatchedCount == 0 && isWatched && episode.LastViewedAt != null)
                        {
                            lastWatched = FromUnixTime((long)episode.LastViewedAt);
                        }
                        SVR_VideoLocal video = animeEpisode.GetVideoLocals()?.FirstOrDefault();
                        if (video == null)
                        {
                            continue;
                        }
                        var alreadyWatched = animeEpisode.GetVideoLocals()
                                             .Where(x => x.GetAniDBFile() != null)
                                             .Any(x => x.GetAniDBFile().IsWatched > 0);

                        if (alreadyWatched && !isWatched)
                        {
                            episode.Scrobble();
                        }

                        if (isWatched && !alreadyWatched)
                        {
                            video.ToggleWatchedStatus(true, true, lastWatched, true,
                                                      _jmmuser.JMMUserID, true, true);
                        }
                    }
                }
            }
        }
        public override void ProcessCommand()
        {
            logger.Info($"Processing CommandRequest_AddFileToMyList: {vid?.FileName} - {Hash} - {ReadStates}");

            try
            {
                if (vid == null)
                {
                    return;
                }

                // when adding a file via the API, newWatchedStatus will return with current watched status on AniDB
                // if the file is already on the user's list

                bool isManualLink = false;
                List <CrossRef_File_Episode> xrefs = vid.EpisodeCrossRefs.DistinctBy(a => Tuple.Create(a.AnimeID, a.EpisodeID)).ToList();
                if (xrefs.Count > 0)
                {
                    isManualLink = xrefs[0].CrossRefSource != (int)CrossRefSource.AniDB;
                }

                // mark the video file as watched
                List <SVR_JMMUser> aniDBUsers          = RepoFactory.JMMUser.GetAniDBUsers();
                SVR_JMMUser        juser               = aniDBUsers.FirstOrDefault();
                DateTime?          originalWatchedDate = null;
                if (juser != null)
                {
                    originalWatchedDate = vid.GetUserRecord(juser.JMMUserID)?.WatchedDate?.ToUniversalTime();
                }

                DateTime?newWatchedDate = null;
                int?     lid            = null;
                // this only gets overwritten if the response is File Already in MyList
                AniDBFile_State?state = ServerSettings.Instance.AniDb.MyList_StorageState;

                if (isManualLink)
                {
                    foreach (var xref in xrefs)
                    {
                        (lid, newWatchedDate) = ShokoService.AnidbProcessor.AddFileToMyList(xref.AnimeID,
                                                                                            xref.GetEpisode().EpisodeNumber, originalWatchedDate, ref state);
                    }
                }
                else
                {
                    (lid, newWatchedDate) =
                        ShokoService.AnidbProcessor.AddFileToMyList(vid, originalWatchedDate, ref state);
                }

                // never true for Manual Links, so no worries about the loop overwriting it
                if (lid != null && lid.Value > 0)
                {
                    vid.MyListID = lid.Value;
                    RepoFactory.VideoLocal.Save(vid);
                }

                logger.Info($"Added File to MyList. File: {vid.FileName}  Manual Link: {isManualLink}  Watched Locally: {originalWatchedDate != null}  Watched AniDB: {newWatchedDate != null}  Local State: {ServerSettings.Instance.AniDb.MyList_StorageState}  AniDB State: {state}  ReadStates: {ReadStates}  ReadWatched Setting: {ServerSettings.Instance.AniDb.MyList_ReadWatched}  ReadUnwatched Setting: {ServerSettings.Instance.AniDb.MyList_ReadUnwatched}");
                if (juser != null)
                {
                    bool watched = newWatchedDate != null;

                    bool watchedLocally = originalWatchedDate != null;
                    bool watchedChanged = watched != watchedLocally;

                    if (ReadStates)
                    {
                        // handle import watched settings. Don't update AniDB in either case, we'll do that with the storage state
                        if (ServerSettings.Instance.AniDb.MyList_ReadWatched && watched && !watchedLocally)
                        {
                            vid.ToggleWatchedStatus(true, false, newWatchedDate, false, juser.JMMUserID,
                                                    false, false);
                        }
                        else if (ServerSettings.Instance.AniDb.MyList_ReadUnwatched && !watched && watchedLocally)
                        {
                            vid.ToggleWatchedStatus(false, false, null, false, juser.JMMUserID,
                                                    false, false);
                        }
                    }

                    // We should have a MyListID at this point, so hopefully this will prevent looping
                    if (watchedChanged || state != ServerSettings.Instance.AniDb.MyList_StorageState)
                    {
                        // if vid.MyListID > 0, isManualLink _should_ always be false, but _should_ isn't good enough
                        if (vid.MyListID > 0 && !isManualLink)
                        {
                            if (ServerSettings.Instance.AniDb.MyList_SetWatched && watchedLocally)
                            {
                                ShokoService.AnidbProcessor.UpdateMyListFileStatus(vid, true, originalWatchedDate);
                            }
                            else if (ServerSettings.Instance.AniDb.MyList_SetUnwatched && !watchedLocally)
                            {
                                ShokoService.AnidbProcessor.UpdateMyListFileStatus(vid, false);
                            }
                        }
                        else if (isManualLink)
                        {
                            foreach (var xref in xrefs)
                            {
                                if (ServerSettings.Instance.AniDb.MyList_SetWatched && watchedLocally)
                                {
                                    ShokoService.AnidbProcessor.UpdateMyListFileStatus(vid, xref.AnimeID, xref.GetEpisode().EpisodeNumber, true, originalWatchedDate);
                                }
                                else if (ServerSettings.Instance.AniDb.MyList_SetUnwatched && !watchedLocally)
                                {
                                    ShokoService.AnidbProcessor.UpdateMyListFileStatus(vid, xref.AnimeID, xref.GetEpisode().EpisodeNumber, false);
                                }
                            }
                        }
                    }
                }

                // if we don't have xrefs, then no series or eps.
                if (xrefs.Count <= 0)
                {
                    return;
                }

                SVR_AnimeSeries ser = RepoFactory.AnimeSeries.GetByAnimeID(xrefs[0].AnimeID);
                // all the eps should belong to the same anime
                ser.QueueUpdateStats();
                //StatsCache.Instance.UpdateUsingSeries(ser.AnimeSeriesID);

                // lets also try adding to the users trakt collecion
                if (ServerSettings.Instance.TraktTv.Enabled &&
                    !string.IsNullOrEmpty(ServerSettings.Instance.TraktTv.AuthToken))
                {
                    foreach (SVR_AnimeEpisode aep in vid.GetAnimeEpisodes())
                    {
                        CommandRequest_TraktCollectionEpisode cmdSyncTrakt =
                            new CommandRequest_TraktCollectionEpisode(aep.AnimeEpisodeID, TraktSyncAction.Add);
                        cmdSyncTrakt.Save();
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Error($"Error processing CommandRequest_AddFileToMyList: {Hash} - {ex}");
            }
        }
        public override void ProcessCommand()
        {
            logger.Info("Processing CommandRequest_SyncMyList");

            try
            {
                // we will always assume that an anime was downloaded via http first
                ScheduledUpdate sched =
                    RepoFactory.ScheduledUpdate.GetByUpdateType((int)ScheduledUpdateType.AniDBMyListSync);
                if (sched == null)
                {
                    sched = new ScheduledUpdate
                    {
                        UpdateType    = (int)ScheduledUpdateType.AniDBMyListSync,
                        UpdateDetails = string.Empty
                    };
                }
                else
                {
                    int freqHours = Utils.GetScheduledHours(ServerSettings.Instance.AniDb.MyList_UpdateFrequency);

                    // if we have run this in the last 24 hours and are not forcing it, then exit
                    TimeSpan tsLastRun = DateTime.Now - sched.LastUpdate;
                    if (tsLastRun.TotalHours < freqHours)
                    {
                        if (!ForceRefresh)
                        {
                            return;
                        }
                    }
                }

                // Get the list from AniDB
                AniDBHTTPCommand_GetMyList cmd = new AniDBHTTPCommand_GetMyList();
                cmd.Init(ServerSettings.Instance.AniDb.Username, ServerSettings.Instance.AniDb.Password);
                AniDBUDPResponseCode ev = cmd.Process();
                if (ev != AniDBUDPResponseCode.GotMyListHTTP)
                {
                    logger.Warn("AniDB did not return a successful code: " + ev);
                    return;
                }

                int totalItems    = 0;
                int watchedItems  = 0;
                int modifiedItems = 0;

                // Add missing files on AniDB
                var onlineFiles  = cmd.MyListItems.ToLookup(a => a.FileID);
                var dictAniFiles = RepoFactory.AniDB_File.GetAll().ToLookup(a => a.Hash);

                int missingFiles = 0;
                foreach (SVR_VideoLocal vid in RepoFactory.VideoLocal.GetAll()
                         .Where(a => !string.IsNullOrEmpty(a.Hash)).ToList())
                {
                    // Does it have a linked AniFile
                    if (!dictAniFiles.Contains(vid.Hash))
                    {
                        continue;
                    }

                    int fileID = dictAniFiles[vid.Hash].FirstOrDefault()?.FileID ?? 0;
                    if (fileID == 0)
                    {
                        continue;
                    }
                    // Is it in MyList
                    if (onlineFiles.Contains(fileID))
                    {
                        Raw_AniDB_MyListFile file = onlineFiles[fileID].FirstOrDefault(a => a != null);

                        if (file != null)
                        {
                            if (vid.MyListID == 0)
                            {
                                vid.MyListID = file.ListID;
                                RepoFactory.VideoLocal.Save(vid);
                            }

                            // Update file state if deleted
                            if (file.State != (int)ServerSettings.Instance.AniDb.MyList_StorageState)
                            {
                                int seconds = Commons.Utils.AniDB.GetAniDBDateAsSeconds(file.WatchedDate);
                                CommandRequest_UpdateMyListFileStatus cmdUpdateFile =
                                    new CommandRequest_UpdateMyListFileStatus(vid.Hash, file.WatchedDate.HasValue,
                                                                              false,
                                                                              seconds);
                                cmdUpdateFile.Save();
                            }

                            continue;
                        }
                    }

                    // means we have found a file in our local collection, which is not recorded online
                    if (ServerSettings.Instance.AniDb.MyList_AddFiles)
                    {
                        CommandRequest_AddFileToMyList cmdAddFile = new CommandRequest_AddFileToMyList(vid.Hash);
                        cmdAddFile.Save();
                    }
                    missingFiles++;
                }
                logger.Info($"MYLIST Missing Files: {missingFiles} Added to queue for inclusion");

                List <SVR_JMMUser> aniDBUsers = RepoFactory.JMMUser.GetAniDBUsers();
                LinkedHashSet <SVR_AnimeSeries> modifiedSeries = new LinkedHashSet <SVR_AnimeSeries>();

                // Remove Missing Files and update watched states (single loop)
                List <int> filesToRemove = new List <int>();
                foreach (Raw_AniDB_MyListFile myitem in cmd.MyListItems)
                {
                    try
                    {
                        totalItems++;
                        if (myitem.IsWatched)
                        {
                            watchedItems++;
                        }

                        string hash = string.Empty;

                        SVR_AniDB_File anifile = RepoFactory.AniDB_File.GetByFileID(myitem.FileID);
                        if (anifile != null)
                        {
                            hash = anifile.Hash;
                        }
                        else
                        {
                            // look for manually linked files
                            List <CrossRef_File_Episode> xrefs =
                                RepoFactory.CrossRef_File_Episode.GetByEpisodeID(myitem.EpisodeID);
                            foreach (CrossRef_File_Episode xref in xrefs)
                            {
                                if (xref.CrossRefSource == (int)CrossRefSource.AniDB)
                                {
                                    continue;
                                }
                                hash = xref.Hash;
                                break;
                            }
                        }

                        // We couldn't evem find a hash, so remove it
                        if (string.IsNullOrEmpty(hash))
                        {
                            filesToRemove.Add(myitem.ListID);
                            continue;
                        }

                        // If there's no video local, we don't have it
                        SVR_VideoLocal vl = RepoFactory.VideoLocal.GetByHash(hash);
                        if (vl == null)
                        {
                            filesToRemove.Add(myitem.ListID);
                            continue;
                        }

                        foreach (SVR_JMMUser juser in aniDBUsers)
                        {
                            bool localStatus = false;

                            // doesn't matter which anidb user we use
                            int             jmmUserID  = juser.JMMUserID;
                            VideoLocal_User userRecord = vl.GetUserRecord(juser.JMMUserID);
                            if (userRecord != null)
                            {
                                localStatus = userRecord.WatchedDate.HasValue;
                            }

                            string action = string.Empty;
                            if (localStatus == myitem.IsWatched)
                            {
                                continue;
                            }

                            // localStatus and AniDB Status are different
                            DateTime?watchedDate = myitem.WatchedDate ?? DateTime.Now;
                            if (localStatus)
                            {
                                // local = watched, anidb = unwatched
                                if (ServerSettings.Instance.AniDb.MyList_ReadUnwatched)
                                {
                                    modifiedItems++;
                                    vl.ToggleWatchedStatus(false, false, watchedDate,
                                                           false, jmmUserID, false,
                                                           true);
                                    action = "Used AniDB Status";
                                }
                                else if (ServerSettings.Instance.AniDb.MyList_SetWatched)
                                {
                                    vl.ToggleWatchedStatus(true, true, userRecord.WatchedDate, false, jmmUserID,
                                                           false, true);
                                }
                            }
                            else
                            {
                                // means local is un-watched, and anidb is watched
                                if (ServerSettings.Instance.AniDb.MyList_ReadWatched)
                                {
                                    modifiedItems++;
                                    vl.ToggleWatchedStatus(true, false, watchedDate, false,
                                                           jmmUserID, false, true);
                                    action = "Updated Local record to Watched";
                                }
                                else if (ServerSettings.Instance.AniDb.MyList_SetUnwatched)
                                {
                                    vl.ToggleWatchedStatus(false, true, watchedDate, false, jmmUserID,
                                                           false, true);
                                }
                            }

                            vl.GetAnimeEpisodes().Select(a => a.GetAnimeSeries()).Where(a => a != null)
                            .DistinctBy(a => a.AnimeSeriesID).ForEach(a => modifiedSeries.Add(a));
                            logger.Info(
                                $"MYLISTDIFF:: File {vl.FileName} - Local Status = {localStatus}, AniDB Status = {myitem.IsWatched} --- {action}");
                        }
                    }
                    catch (Exception ex)
                    {
                        logger.Error($"A MyList Item threw an error while syncing: {ex}");
                    }
                }

                // Actually remove the files
                if (filesToRemove.Count > 0)
                {
                    foreach (int listID in filesToRemove)
                    {
                        CommandRequest_DeleteFileFromMyList deleteCommand =
                            new CommandRequest_DeleteFileFromMyList(listID);
                        deleteCommand.Save();
                    }
                    logger.Info($"MYLIST Missing Files: {filesToRemove.Count} Added to queue for deletion");
                }

                modifiedSeries.ForEach(a => a.QueueUpdateStats());

                logger.Info($"Process MyList: {totalItems} Items, {missingFiles} Added, {filesToRemove.Count} Deleted, {watchedItems} Watched, {modifiedItems} Modified");

                sched.LastUpdate = DateTime.Now;
                RepoFactory.ScheduledUpdate.Save(sched);
            }
            catch (Exception ex)
            {
                logger.Error(ex, "Error processing CommandRequest_SyncMyList: {0} ", ex);
            }
        }
Beispiel #7
0
        public override void ProcessCommand()
        {
            logger.Info("Processing CommandRequest_SyncMyList");

            try
            {
                // we will always assume that an anime was downloaded via http first
                ScheduledUpdate sched =
                    RepoFactory.ScheduledUpdate.GetByUpdateType((int)ScheduledUpdateType.AniDBMyListSync);
                if (sched == null)
                {
                    sched = new ScheduledUpdate
                    {
                        UpdateType    = (int)ScheduledUpdateType.AniDBMyListSync,
                        UpdateDetails = ""
                    };
                }
                else
                {
                    int freqHours = Utils.GetScheduledHours(ServerSettings.AniDB_MyList_UpdateFrequency);

                    // if we have run this in the last 24 hours and are not forcing it, then exit
                    TimeSpan tsLastRun = DateTime.Now - sched.LastUpdate;
                    if (tsLastRun.TotalHours < freqHours)
                    {
                        if (!ForceRefresh)
                        {
                            return;
                        }
                    }
                }

                AniDBHTTPCommand_GetMyList cmd = new AniDBHTTPCommand_GetMyList();
                cmd.Init(ServerSettings.AniDB_Username, ServerSettings.AniDB_Password);
                enHelperActivityType ev = cmd.Process();
                if (ev != enHelperActivityType.GotMyListHTTP || cmd.MyListItems.Count <= 1)
                {
                    return;
                }


                int    totalItems    = 0;
                int    watchedItems  = 0;
                int    modifiedItems = 0;
                double pct           = 0;

                // 2. find files locally for the user, which are not recorded on anidb
                //    and then add them to anidb
                Dictionary <int, Raw_AniDB_MyListFile> onlineFiles = new Dictionary <int, Raw_AniDB_MyListFile>();
                foreach (Raw_AniDB_MyListFile myitem in cmd.MyListItems)
                {
                    onlineFiles[myitem.FileID] = myitem;
                }

                Dictionary <string, SVR_AniDB_File> dictAniFiles = new Dictionary <string, SVR_AniDB_File>();
                IReadOnlyList <SVR_AniDB_File>      allAniFiles  = RepoFactory.AniDB_File.GetAll();
                foreach (SVR_AniDB_File anifile in allAniFiles)
                {
                    dictAniFiles[anifile.Hash] = anifile;
                }

                int missingFiles = 0;
                foreach (SVR_VideoLocal vid in RepoFactory.VideoLocal.GetAll()
                         .Where(a => !string.IsNullOrEmpty(a.Hash)).ToList())
                {
                    if (!dictAniFiles.ContainsKey(vid.Hash))
                    {
                        continue;
                    }

                    int fileID = dictAniFiles[vid.Hash].FileID;

                    if (onlineFiles.ContainsKey(fileID))
                    {
                        continue;
                    }

                    // means we have found a file in our local collection, which is not recorded online
                    CommandRequest_AddFileToMyList cmdAddFile = new CommandRequest_AddFileToMyList(vid.Hash);
                    cmdAddFile.Save();
                    missingFiles++;
                }
                logger.Info($"MYLIST Missing Files: {missingFiles} Added to queue for inclusion");

                List <SVR_JMMUser> aniDBUsers = RepoFactory.JMMUser.GetAniDBUsers();


                // 1 . sync mylist items
                foreach (Raw_AniDB_MyListFile myitem in cmd.MyListItems)
                {
                    // ignore files mark as deleted by the user
                    if (myitem.State == (int)AniDBFileStatus.Deleted)
                    {
                        continue;
                    }

                    totalItems++;
                    if (myitem.IsWatched)
                    {
                        watchedItems++;
                    }

                    //calculate percentage
                    pct = totalItems / (double)cmd.MyListItems.Count * 100;
                    string spct = pct.ToString("#0.0");

                    string hash = string.Empty;

                    SVR_AniDB_File anifile = RepoFactory.AniDB_File.GetByFileID(myitem.FileID);
                    if (anifile != null)
                    {
                        hash = anifile.Hash;
                    }
                    else
                    {
                        // look for manually linked files
                        List <CrossRef_File_Episode> xrefs =
                            RepoFactory.CrossRef_File_Episode.GetByEpisodeID(myitem.EpisodeID);
                        foreach (CrossRef_File_Episode xref in xrefs)
                        {
                            if (xref.CrossRefSource == (int)CrossRefSource.AniDB)
                            {
                                continue;
                            }
                            hash = xref.Hash;
                            break;
                        }
                    }


                    if (string.IsNullOrEmpty(hash))
                    {
                        continue;
                    }

                    // find the video associated with this record
                    SVR_VideoLocal vl = RepoFactory.VideoLocal.GetByHash(hash);
                    if (vl == null)
                    {
                        continue;
                    }

                    foreach (SVR_JMMUser juser in aniDBUsers)
                    {
                        bool localStatus = false;

                        // doesn't matter which anidb user we use
                        int             jmmUserID  = juser.JMMUserID;
                        VideoLocal_User userRecord = vl.GetUserRecord(juser.JMMUserID);
                        if (userRecord != null)
                        {
                            localStatus = userRecord.WatchedDate.HasValue;
                        }

                        string action = "";
                        if (localStatus == myitem.IsWatched)
                        {
                            continue;
                        }

                        if (localStatus)
                        {
                            // local = watched, anidb = unwatched
                            if (ServerSettings.AniDB_MyList_ReadUnwatched)
                            {
                                modifiedItems++;
                                vl.ToggleWatchedStatus(myitem.IsWatched, false, myitem.WatchedDate,
                                                       false, false, jmmUserID, false,
                                                       true);
                                action = "Used AniDB Status";
                            }
                        }
                        else
                        {
                            // means local is un-watched, and anidb is watched
                            if (ServerSettings.AniDB_MyList_ReadWatched)
                            {
                                modifiedItems++;
                                vl.ToggleWatchedStatus(true, false, myitem.WatchedDate, false, false,
                                                       jmmUserID, false, true);
                                action = "Updated Local record to Watched";
                            }
                        }

                        string msg =
                            $"MYLISTDIFF:: File {vl.FileName} - Local Status = {localStatus}, AniDB Status = {myitem.IsWatched} --- {action}";
                        logger.Info(msg);
                    }


                    //string msg = string.Format("MYLIST:: File {0} - Local Status = {1}, AniDB Status = {2} --- {3}",
                    //    vl.FullServerPath, localStatus, myitem.IsWatched, action);
                    //logger.Info(msg);
                }


                // now update all stats
                Importer.UpdateAllStats();

                logger.Info("Process MyList: {0} Items, {1} Watched, {2} Modified", totalItems, watchedItems,
                            modifiedItems);

                sched.LastUpdate = DateTime.Now;
                RepoFactory.ScheduledUpdate.Save(sched);
            }
            catch (Exception ex)
            {
                logger.Error(ex, "Error processing CommandRequest_SyncMyList: {0} ", ex.Message);
            }
        }
        public override void ProcessCommand()
        {
            logger.Info("Processing CommandRequest_AddFileToMyList: {0}", Hash);


            try
            {
                vid = RepoFactory.VideoLocal.GetByHash(this.Hash);
                List <SVR_AnimeEpisode> animeEpisodes = new List <SVR_AnimeEpisode>();
                if (vid != null)
                {
                    animeEpisodes = vid.GetAnimeEpisodes();
                }

                if (vid != null)
                {
                    // when adding a file via the API, newWatchedStatus will return with current watched status on AniDB
                    // if the file is already on the user's list

                    bool isManualLink = false;
                    List <CrossRef_File_Episode> xrefs = vid.EpisodeCrossRefs;
                    if (xrefs.Count > 0)
                    {
                        isManualLink = xrefs[0].CrossRefSource != (int)CrossRefSource.AniDB;
                    }

                    // mark the video file as watched
                    DateTime?watchedDate      = null;
                    bool     newWatchedStatus = false;

                    if (isManualLink)
                    {
                        newWatchedStatus = ShokoService.AnidbProcessor.AddFileToMyList(xrefs[0].AnimeID,
                                                                                       xrefs[0].GetEpisode().EpisodeNumber,
                                                                                       ref watchedDate);
                    }
                    else
                    {
                        newWatchedStatus = ShokoService.AnidbProcessor.AddFileToMyList(vid, ref watchedDate);
                    }

                    // do for all AniDB users
                    List <SVR_JMMUser> aniDBUsers = RepoFactory.JMMUser.GetAniDBUsers();


                    if (aniDBUsers.Count > 0)
                    {
                        SVR_JMMUser juser = aniDBUsers[0];
                        vid.ToggleWatchedStatus(newWatchedStatus, false, watchedDate, false, false, juser.JMMUserID,
                                                false, true);
                        logger.Info("Adding file to list: {0} - {1}", vid.ToString(), watchedDate);

                        // if the the episode is watched we may want to set the file to watched as well
                        if (ServerSettings.Import_UseExistingFileWatchedStatus && !newWatchedStatus)
                        {
                            if (animeEpisodes.Count > 0)
                            {
                                SVR_AnimeEpisode      ep     = animeEpisodes[0];
                                SVR_AnimeEpisode_User epUser = null;

                                foreach (SVR_JMMUser tempuser in aniDBUsers)
                                {
                                    // only find the first user who watched this
                                    if (epUser == null)
                                    {
                                        epUser = ep.GetUserRecord(tempuser.JMMUserID);
                                    }
                                }

                                if (epUser != null)
                                {
                                    logger.Info(
                                        "Setting file as watched, because episode was already watched: {0} - user: {1}",
                                        vid.ToString(),
                                        juser.Username);
                                    vid.ToggleWatchedStatus(true, true, epUser.WatchedDate, false, false,
                                                            epUser.JMMUserID, false, true);
                                }
                            }
                        }
                    }

                    SVR_AnimeSeries ser = animeEpisodes[0].GetAnimeSeries();
                    // all the eps should belong to the same anime
                    ser.QueueUpdateStats();
                    //StatsCache.Instance.UpdateUsingSeries(ser.AnimeSeriesID);

                    // lets also try adding to the users trakt collecion
                    if (ser != null && ServerSettings.Trakt_IsEnabled &&
                        !string.IsNullOrEmpty(ServerSettings.Trakt_AuthToken))
                    {
                        foreach (SVR_AnimeEpisode aep in animeEpisodes)
                        {
                            CommandRequest_TraktCollectionEpisode cmdSyncTrakt =
                                new CommandRequest_TraktCollectionEpisode
                                (
                                    aep.AnimeEpisodeID, TraktSyncAction.Add);
                            cmdSyncTrakt.Save();
                        }
                    }

                    // sync the series on MAL
                    if (ser != null && !string.IsNullOrEmpty(ServerSettings.MAL_Username) &&
                        !string.IsNullOrEmpty(ServerSettings.MAL_Password))
                    {
                        CommandRequest_MALUpdatedWatchedStatus cmdMAL =
                            new CommandRequest_MALUpdatedWatchedStatus(ser.AniDB_ID);
                        cmdMAL.Save();
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Error("Error processing CommandRequest_AddFileToMyList: {0} - {1}", Hash, ex.ToString());
                return;
            }
        }
Beispiel #9
0
        public override void ProcessCommand()
        {
            logger.Info($"Processing CommandRequest_AddFileToMyList: {vid.FileName} - {vid.Hash}");


            try
            {
                if (vid == null)
                {
                    return;
                }

                List <SVR_AnimeEpisode> animeEpisodes = vid.GetAnimeEpisodes();
                // when adding a file via the API, newWatchedStatus will return with current watched status on AniDB
                // if the file is already on the user's list

                bool isManualLink = false;
                List <CrossRef_File_Episode> xrefs = vid.EpisodeCrossRefs;
                if (xrefs.Count > 0)
                {
                    isManualLink = xrefs[0].CrossRefSource != (int)CrossRefSource.AniDB;
                }

                // mark the video file as watched
                DateTime?       watchedDate = null;
                bool?           newWatchedStatus;
                AniDBFile_State?state = null;

                if (isManualLink)
                {
                    newWatchedStatus = ShokoService.AnidbProcessor.AddFileToMyList(xrefs[0].AnimeID,
                                                                                   xrefs[0].GetEpisode().EpisodeNumber,
                                                                                   ref watchedDate);
                }
                else
                {
                    newWatchedStatus = ShokoService.AnidbProcessor.AddFileToMyList(vid, ref watchedDate, ref state);
                }

                // do for all AniDB users
                List <SVR_JMMUser> aniDBUsers = RepoFactory.JMMUser.GetAniDBUsers();


                if (aniDBUsers.Count > 0)
                {
                    string datemessage = watchedDate?.ToShortDateString() ?? "Not Watched";
                    if (watchedDate?.Equals(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime()) ?? false)
                    {
                        datemessage = "No Watch Date Specified";
                    }
                    logger.Info($"Adding file to list: {vid.FileName} - {datemessage}");
                    bool watched = watchedDate != null;
                    if (newWatchedStatus != null)
                    {
                        watched = newWatchedStatus.Value;
                    }

                    SVR_JMMUser juser          = aniDBUsers[0];
                    bool        watchedLocally = vid.GetUserRecord(juser.JMMUserID)?.WatchedDate != null;
                    bool        watchedChanged = watched != watchedLocally;

                    // handle import watched settings. Don't update AniDB in either case, we'll do that with the storage state
                    if (ServerSettings.AniDB_MyList_ReadWatched && watched && !watchedLocally)
                    {
                        vid.ToggleWatchedStatus(true, false, watchedDate, false, juser.JMMUserID,
                                                false, false);
                    }
                    else if (ServerSettings.AniDB_MyList_ReadUnwatched && !watched && watchedLocally)
                    {
                        vid.ToggleWatchedStatus(false, false, watchedDate, false, juser.JMMUserID,
                                                false, false);
                    }

                    if (watchedChanged || state != ServerSettings.AniDB_MyList_StorageState)
                    {
                        int watchedDateSec = Commons.Utils.AniDB.GetAniDBDateAsSeconds(watchedDate);
                        var cmdUpdate      = new CommandRequest_UpdateMyListFileStatus(Hash, watched, false, watchedDateSec);
                        cmdUpdate.Save();
                    }
                }

                SVR_AnimeSeries ser = animeEpisodes[0].GetAnimeSeries();
                // all the eps should belong to the same anime
                ser.QueueUpdateStats();
                //StatsCache.Instance.UpdateUsingSeries(ser.AnimeSeriesID);

                // lets also try adding to the users trakt collecion
                if (ServerSettings.Trakt_IsEnabled &&
                    !string.IsNullOrEmpty(ServerSettings.Trakt_AuthToken))
                {
                    foreach (SVR_AnimeEpisode aep in animeEpisodes)
                    {
                        CommandRequest_TraktCollectionEpisode cmdSyncTrakt =
                            new CommandRequest_TraktCollectionEpisode
                            (
                                aep.AnimeEpisodeID, TraktSyncAction.Add);
                        cmdSyncTrakt.Save();
                    }
                }

                // sync the series on MAL
                if (!string.IsNullOrEmpty(ServerSettings.MAL_Username) &&
                    !string.IsNullOrEmpty(ServerSettings.MAL_Password))
                {
                    CommandRequest_MALUpdatedWatchedStatus cmdMAL =
                        new CommandRequest_MALUpdatedWatchedStatus(ser.AniDB_ID);
                    cmdMAL.Save();
                }
            }
            catch (Exception ex)
            {
                logger.Error($"Error processing CommandRequest_AddFileToMyList: {Hash} - {ex}");
            }
        }
Beispiel #10
0
        public override void Run(IProgress <ICommand> progress = null)
        {
            logger.Info($"Syncing watched videos for: {_jmmuser.Username}, if nothing happens make sure you have your libraries configured in Shoko.");
            try
            {
                List <Directory> dirs = PlexHelper.GetForUser(_jmmuser).GetDirectories().Where(a => ServerSettings.Instance.Plex.Libraries.Contains(a.Key)).ToList();
                double           add  = 100D / dirs.Count;

                for (int x = 0; x < dirs.Count; x++)
                {
                    Directory section   = dirs[x];
                    var       allSeries = ((SVR_Directory)section).GetShows();
                    for (int y = 0; y < allSeries.Length; y++)
                    {
                        PlexLibrary series = allSeries[y];
                        double      pos    = x * add + (y + 1) * add / allSeries.Length;

                        var episodes = ((SVR_PlexLibrary)series)?.GetEpisodes()?.Where(s => s != null);
                        if (episodes == null)
                        {
                            continue;
                        }
                        foreach (var ep in episodes)
                        {
                            var episode = (SVR_Episode)ep;

                            var animeEpisode = episode.AnimeEpisode;
                            if (animeEpisode == null)
                            {
                                continue;
                            }
                            var userRecord  = animeEpisode.GetUserRecord(_jmmuser.JMMUserID);
                            var isWatched   = episode.ViewCount != null && episode.ViewCount > 0;
                            var lastWatched = userRecord?.WatchedDate;
                            if (userRecord?.WatchedCount == 0 && isWatched && episode.LastViewedAt != null)
                            {
                                lastWatched = FromUnixTime((long)episode.LastViewedAt);
                            }

                            SVR_VideoLocal video = animeEpisode.GetVideoLocals()?.FirstOrDefault();
                            if (video == null)
                            {
                                continue;
                            }
                            var alreadyWatched = animeEpisode.GetVideoLocals()
                                                 .Where(a => a.GetAniDBFile() != null)
                                                 .Any(a => a.GetAniDBFile().IsWatched > 0);

                            if (alreadyWatched && !isWatched)
                            {
                                episode.Scrobble();
                            }

                            if (isWatched && !alreadyWatched)
                            {
                                video.ToggleWatchedStatus(true, true, lastWatched, true, _jmmuser.JMMUserID, true, true);
                            }
                            ReportUpdate(progress, pos);
                        }
                    }
                }

                ReportFinish(progress);
            }
            catch (Exception e)
            {
                ReportError(progress, $"Error processing Plex.PlexSyncWatched: {UserId} - {e}", e);
            }
        }
        public override void ProcessCommand()
        {
            logger.Info($"Processing CommandRequest_AddFileToMyList: {vid?.FileName} - {Hash} - {ReadStates}");

            try
            {
                if (vid == null)
                {
                    return;
                }

                // when adding a file via the API, newWatchedStatus will return with current watched status on AniDB
                // if the file is already on the user's list

                bool isManualLink = false;
                List <CrossRef_File_Episode> xrefs = vid.EpisodeCrossRefs;
                if (xrefs.Count > 0)
                {
                    isManualLink = xrefs[0].CrossRefSource != (int)CrossRefSource.AniDB;
                }

                // mark the video file as watched
                List <SVR_JMMUser> aniDBUsers          = RepoFactory.JMMUser.GetAniDBUsers();
                SVR_JMMUser        juser               = aniDBUsers.FirstOrDefault();
                DateTime?          originalWatchedDate = null;
                if (juser != null)
                {
                    originalWatchedDate = vid.GetUserRecord(juser.JMMUserID)?.WatchedDate;
                }

                DateTime?       newWatchedDate;
                int?            lid;
                AniDBFile_State?state = null;

                if (isManualLink)
                {
                    (lid, newWatchedDate) = ShokoService.AnidbProcessor.AddFileToMyList(xrefs[0].AnimeID,
                                                                                        xrefs[0].GetEpisode().EpisodeNumber, originalWatchedDate);
                }
                else
                {
                    (lid, newWatchedDate) =
                        ShokoService.AnidbProcessor.AddFileToMyList(vid, originalWatchedDate, ref state);
                }

                if (lid != null && lid.Value > 0)
                {
                    vid.MyListID = lid.Value;
                    RepoFactory.VideoLocal.Save(vid);
                }

                if (juser != null)
                {
                    string datemessage = newWatchedDate?.ToShortDateString() ?? "Not Watched";
                    if (newWatchedDate?.Equals(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime()) ?? false)
                    {
                        datemessage = "No Watch Date Specified";
                    }
                    logger.Info($"Adding file to list: {vid.FileName} - {datemessage}");
                    bool watched = newWatchedDate != null;

                    bool watchedLocally = originalWatchedDate != null;
                    bool watchedChanged = watched != watchedLocally;

                    if (ReadStates)
                    {
                        // handle import watched settings. Don't update AniDB in either case, we'll do that with the storage state
                        if (ServerSettings.AniDB_MyList_ReadWatched && watched && !watchedLocally)
                        {
                            vid.ToggleWatchedStatus(true, false, newWatchedDate, false, juser.JMMUserID,
                                                    false, false);
                        }
                        else if (ServerSettings.AniDB_MyList_ReadUnwatched && !watched && watchedLocally)
                        {
                            vid.ToggleWatchedStatus(false, false, null, false, juser.JMMUserID,
                                                    false, false);
                        }
                    }

                    // We should have a MyListID at this point, so hopefully this will prevent looping
                    if (vid.MyListID > 0 && (watchedChanged || state != ServerSettings.AniDB_MyList_StorageState))
                    {
                        if (ServerSettings.AniDB_MyList_SetWatched && watchedLocally)
                        {
                            ShokoService.AnidbProcessor.UpdateMyListFileStatus(vid, true, originalWatchedDate);
                        }
                        else if (ServerSettings.AniDB_MyList_SetUnwatched && !watchedLocally)
                        {
                            ShokoService.AnidbProcessor.UpdateMyListFileStatus(vid, false);
                        }
                    }
                }

                // if we don't have xrefs, then no series or eps.
                if (xrefs.Count <= 0)
                {
                    return;
                }

                SVR_AnimeSeries ser = RepoFactory.AnimeSeries.GetByAnimeID(xrefs[0].AnimeID);
                // all the eps should belong to the same anime
                ser.QueueUpdateStats();
                //StatsCache.Instance.UpdateUsingSeries(ser.AnimeSeriesID);

                // lets also try adding to the users trakt collecion
                if (ServerSettings.Trakt_IsEnabled &&
                    !string.IsNullOrEmpty(ServerSettings.Trakt_AuthToken))
                {
                    foreach (SVR_AnimeEpisode aep in vid.GetAnimeEpisodes())
                    {
                        CommandRequest_TraktCollectionEpisode cmdSyncTrakt =
                            new CommandRequest_TraktCollectionEpisode(aep.AnimeEpisodeID, TraktSyncAction.Add);
                        cmdSyncTrakt.Save();
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Error($"Error processing CommandRequest_AddFileToMyList: {Hash} - {ex}");
            }
        }