コード例 #1
0
        private static void CreateInitialUsers()
        {
            JMMUserRepository repUsers = new JMMUserRepository();

            if (repUsers.GetAll().Count() > 0)
            {
                return;
            }

            JMMUser defaultUser = new JMMUser();

            defaultUser.CanEditServerSettings = 1;
            defaultUser.HideCategories        = "";
            defaultUser.IsAdmin     = 1;
            defaultUser.IsAniDBUser = 1;
            defaultUser.IsTraktUser = 1;
            defaultUser.Password    = "";
            defaultUser.Username    = "******";
            repUsers.Save(defaultUser);

            JMMUser familyUser = new JMMUser();

            familyUser.CanEditServerSettings = 1;
            familyUser.HideCategories        = "Ecchi,Nudity,Sex,Sexual Abuse,Horror,Erotic Game,Incest,18 Restricted";
            familyUser.IsAdmin     = 1;
            familyUser.IsAniDBUser = 1;
            familyUser.IsTraktUser = 1;
            familyUser.Password    = "";
            familyUser.Username    = "******";
            repUsers.Save(familyUser);
        }
コード例 #2
0
        private static void CreateInitialUsers()
        {
            JMMUserRepository repUsers = new JMMUserRepository();

            if (repUsers.GetAll().Count() > 0)
            {
                return;
            }

            Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(ServerSettings.Culture);

            JMMUser defaultUser = new JMMUser();

            defaultUser.CanEditServerSettings = 1;
            defaultUser.HideCategories        = "";
            defaultUser.IsAdmin     = 1;
            defaultUser.IsAniDBUser = 1;
            defaultUser.IsTraktUser = 1;
            defaultUser.Password    = "";
            defaultUser.Username    = JMMServer.Properties.Resources.Users_Default;
            repUsers.Save(defaultUser, true);

            JMMUser familyUser = new JMMUser();

            familyUser.CanEditServerSettings = 1;
            familyUser.HideCategories        = "ecchi,nudity,sex,sexual abuse,horror,erotic game,incest,18 restricted";
            familyUser.IsAdmin     = 1;
            familyUser.IsAniDBUser = 1;
            familyUser.IsTraktUser = 1;
            familyUser.Password    = "";
            familyUser.Username    = JMMServer.Properties.Resources.Users_FamilyFriendly;
            repUsers.Save(familyUser, true);
        }
コード例 #3
0
        public static JMMUser GetJMMUser(string userid)
        {
            JMMUserRepository repUsers = new JMMUserRepository();
            List <JMMUser>    allusers = repUsers.GetAll();
            int id = 0;

            int.TryParse(userid, out id);
            return(allusers.FirstOrDefault(a => a.JMMUserID == id) ??
                   allusers.FirstOrDefault(a => a.IsAdmin == 1) ??
                   allusers.FirstOrDefault(a => a.Username == "Default") ?? allusers.First());
        }
コード例 #4
0
        public void UpdateGroupFilter(HashSet <GroupFilterConditionType> types)
        {
            AnimeSeriesRepository repo     = new AnimeSeriesRepository();
            JMMUserRepository     repouser = new JMMUserRepository();
            AnimeSeries           ser      = repo.GetByID(AnimeSeriesID);
            JMMUser usr = repouser.GetByID(JMMUserID);

            if (ser != null && usr != null)
            {
                ser.UpdateGroupFilters(types, usr);
            }
        }
コード例 #5
0
ファイル: KodiHelper.cs プロジェクト: Zhardas/jmmserver
        public static JMMUser GetUser(string UserId)
        {
            int userId = -1;

            if (!string.IsNullOrEmpty(UserId))
            {
                int.TryParse(UserId, out userId);
            }
            JMMUserRepository repUsers = new JMMUserRepository();

            return(userId != 0
                ? repUsers.GetByID(userId)
                : repUsers.GetAll().FirstOrDefault(a => a.Username == "Default"));
        }
コード例 #6
0
        public static JMMUser GetUser(string userid)
        {
            JMMUserRepository repUsers = new JMMUserRepository();
            List <JMMUser>    allusers = repUsers.GetAll();

            foreach (JMMUser n in allusers)
            {
                if (userid.FindIn(n?.Contract?.PlexUsers))
                {
                    return(n);
                }
            }
            return(allusers.FirstOrDefault(a => a.IsAdmin == 1) ??
                   allusers.FirstOrDefault(a => a.Username == "Default") ?? allusers.First());
        }
コード例 #7
0
        private static void InitCache(this IDatabase db)
        {
            JMMUserRepository.InitCache();
            AniDB_AnimeRepository.InitCache();
            VideoInfoRepository.InitCache();
            VideoLocalRepository.InitCache();
            VideoLocal_UserRepository.InitCache();
            List <GroupFilter> recalc = GroupFilterRepository.InitCache();

            AnimeEpisodeRepository.InitCache();
            AnimeEpisode_UserRepository.InitCache();
            AnimeSeriesRepository.InitCache();
            AnimeSeries_UserRepository.InitCache();
            AnimeGroupRepository.InitCache();
            AnimeGroup_UserRepository.InitCache();
            GroupFilterRepository.InitCacheSecondPart(recalc);
            DatabaseFixes.ExecuteDatabaseFixes();
            db.CleanUpMemory();
        }
コード例 #8
0
ファイル: PlexHelper.cs プロジェクト: Zhardas/jmmserver
        public static JMMUser GetUser(string UserId)
        {
            JMMUserRepository repUsers = new JMMUserRepository();
            List <JMMUser>    allusers = repUsers.GetAll();

            foreach (JMMUser n in allusers)
            {
                if (!string.IsNullOrEmpty(n.PlexUsers))
                {
                    string[] users = n.PlexUsers.Split(',');
                    foreach (string m in users)
                    {
                        if (m.Trim().ToLower() == UserId.ToLower())
                        {
                            return(n);
                        }
                    }
                }
            }
            return(allusers.FirstOrDefault(a => a.IsAdmin == 1) ?? allusers.FirstOrDefault(a => a.Username == "Default") ?? allusers.First());
        }
コード例 #9
0
        public System.IO.Stream GetUsers()
        {
            KodiContract_Users gfs = new KodiContract_Users();

            try
            {
                gfs.Users = new List <KodiContract_User>();
                JMMUserRepository repUsers = new JMMUserRepository();
                foreach (JMMUser us in repUsers.GetAll())
                {
                    KodiContract_User p = new KodiContract_User();
                    p.id   = us.JMMUserID.ToString();
                    p.name = us.Username;
                    gfs.Users.Add(p);
                }
            }
            catch (Exception ex)
            {
                logger.ErrorException(ex.ToString(), ex);
            }
            return(KodiHelper.GetStreamFromXmlObject(gfs));
        }
コード例 #10
0
        public override void ProcessCommand()
        {
            logger.Info("Processing CommandRequest_AddFileToMyList: {0}", Hash);


            try
            {
                VideoLocalRepository   repVids     = new VideoLocalRepository();
                AnimeEpisodeRepository repEpisodes = new AnimeEpisodeRepository();

                vid = repVids.GetByHash(this.Hash);
                List <AnimeEpisode> animeEpisodes = new List <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 = JMMService.AnidbProcessor.AddFileToMyList(xrefs[0].AnimeID, xrefs[0].Episode.EpisodeNumber, ref watchedDate);
                    }
                    else
                    {
                        newWatchedStatus = JMMService.AnidbProcessor.AddFileToMyList(vid, ref watchedDate);
                    }

                    // do for all AniDB users
                    JMMUserRepository repUsers   = new JMMUserRepository();
                    List <JMMUser>    aniDBUsers = repUsers.GetAniDBUsers();


                    if (aniDBUsers.Count > 0)
                    {
                        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)
                            {
                                AnimeEpisode      ep     = animeEpisodes[0];
                                AnimeEpisode_User epUser = null;

                                foreach (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);
                                }
                            }
                        }
                    }

                    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 (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;
            }
        }
コード例 #11
0
ファイル: AzureWebAPI.cs プロジェクト: pmcleish/jmmserver
        public static UserInfo GetUserInfoData(string dashType = "", string vidPlayer = "")
        {
            try
            {
                if (string.IsNullOrEmpty(ServerSettings.AniDB_Username))
                {
                    return(null);
                }

                UserInfo uinfo = new UserInfo();

                uinfo.DateTimeUpdated    = DateTime.Now;
                uinfo.DateTimeUpdatedUTC = 0;

                // Optional JMM Desktop data
                uinfo.DashboardType = null;
                uinfo.VideoPlayer   = vidPlayer;

                System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly();
                try
                {
                    if (a != null)
                    {
                        uinfo.JMMServerVersion = Utils.GetApplicationVersion(a);
                    }
                }
                catch
                {
                }

                uinfo.UsernameHash   = Utils.GetMd5Hash(ServerSettings.AniDB_Username);
                uinfo.DatabaseType   = ServerSettings.DatabaseType;
                uinfo.WindowsVersion = Utils.GetOSInfo();
                uinfo.TraktEnabled   = ServerSettings.Trakt_IsEnabled ? 1 : 0;
                uinfo.MALEnabled     = string.IsNullOrEmpty(ServerSettings.MAL_Username) ? 0 : 1;

                uinfo.CountryLocation = "";

                // this field is not actually used
                uinfo.LastEpisodeWatchedAsDate = DateTime.Now.AddDays(-5);

                JMMUserRepository repUsers = new JMMUserRepository();
                uinfo.LocalUserCount = (int)repUsers.GetTotalRecordCount();

                VideoLocalRepository repVids = new VideoLocalRepository();
                uinfo.FileCount = repVids.GetTotalRecordCount();

                AnimeEpisode_UserRepository repEps = new AnimeEpisode_UserRepository();
                AnimeEpisode_User           rec    = repEps.GetLastWatchedEpisode();
                uinfo.LastEpisodeWatched = 0;
                if (rec != null)
                {
                    uinfo.LastEpisodeWatched = Utils.GetAniDBDateAsSeconds(rec.WatchedDate);
                }

                return(uinfo);
            }
            catch (Exception ex)
            {
                logger.ErrorException(ex.ToString(), ex);
                return(null);
            }
        }
コード例 #12
0
        public override void ProcessCommand()
        {
            logger.Info("Processing CommandRequest_MALDownloadStatusFromMAL");

            try
            {
                if (string.IsNullOrEmpty(ServerSettings.MAL_Username) || string.IsNullOrEmpty(ServerSettings.MAL_Password))
                {
                    return;
                }

                // find the latest eps to update
                AniDB_AnimeRepository repAnime = new AniDB_AnimeRepository();

                myanimelist mal = MALHelper.GetMALAnimeList();
                if (mal == null)
                {
                    return;
                }
                if (mal.anime == null)
                {
                    return;
                }

                CrossRef_AniDB_MALRepository repCrossRef = new CrossRef_AniDB_MALRepository();
                AniDB_EpisodeRepository      repAniEps   = new AniDB_EpisodeRepository();
                AnimeEpisodeRepository       repEp       = new AnimeEpisodeRepository();

                // find the anidb user
                JMMUserRepository repUsers   = new JMMUserRepository();
                List <JMMUser>    aniDBUsers = repUsers.GetAniDBUsers();
                if (aniDBUsers.Count == 0)
                {
                    return;
                }

                JMMUser user = aniDBUsers[0];


                foreach (myanimelistAnime malAnime in mal.anime)
                {
                    // look up the anime
                    CrossRef_AniDB_MAL xref = repCrossRef.GetByMALID(malAnime.series_animedb_id);
                    if (xref == null)
                    {
                        continue;
                    }

                    if (malAnime.series_animedb_id == 8107 || malAnime.series_animedb_id == 10737)
                    {
                        Console.Write("");
                    }

                    // check if this anime has any other links
                    List <CrossRef_AniDB_MAL> allXrefs = repCrossRef.GetByAnimeID(xref.AnimeID);
                    if (allXrefs.Count == 0)
                    {
                        continue;
                    }

                    // find the range of watched episodes that this applies to
                    int startEpNumber = xref.StartEpisodeNumber;
                    int endEpNumber   = GetUpperEpisodeLimit(allXrefs, xref);

                    List <AniDB_Episode> aniEps = repAniEps.GetByAnimeID(xref.AnimeID);
                    foreach (AniDB_Episode aniep in aniEps)
                    {
                        if (aniep.EpisodeType != xref.StartEpisodeType)
                        {
                            continue;
                        }

                        AnimeEpisode ep = repEp.GetByAniDBEpisodeID(aniep.EpisodeID);
                        if (ep == null)
                        {
                            continue;
                        }

                        int adjustedWatchedEps = malAnime.my_watched_episodes + xref.StartEpisodeNumber - 1;
                        int epNum = aniep.EpisodeNumber;

                        if (epNum < startEpNumber || epNum > endEpNumber)
                        {
                            continue;
                        }

                        AnimeEpisode_User usrRec = ep.GetUserRecord(user.JMMUserID);

                        if (epNum <= adjustedWatchedEps)
                        {
                            // update if the user doesn't have a record (means not watched)
                            // or it is currently un-watched
                            bool update = false;
                            if (usrRec == null)
                            {
                                update = true;
                            }
                            else
                            {
                                if (!usrRec.WatchedDate.HasValue)
                                {
                                    update = true;
                                }
                            }

                            if (update)
                            {
                                ep.ToggleWatchedStatus(true, true, DateTime.Now, user.JMMUserID, false);
                            }
                        }
                        else
                        {
                            bool update = false;
                            if (usrRec != null)
                            {
                                if (usrRec.WatchedDate.HasValue)
                                {
                                    update = true;
                                }
                            }

                            if (update)
                            {
                                ep.ToggleWatchedStatus(false, true, DateTime.Now, user.JMMUserID, false);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Error("Error processing CommandRequest_MALDownloadStatusFromMAL: {0}", ex.ToString());
                return;
            }
        }
コード例 #13
0
        /// <summary>
        /// Update the stats for this group based on the child series
        /// Assumes that all the AnimeSeries have had their stats updated already
        /// </summary>
        public void UpdateStats(bool watchedStats, bool missingEpsStats)
        {
            List <AnimeSeries> seriesList = GetAllSeries();

            JMMUserRepository repUsers = new JMMUserRepository();
            List <JMMUser>    allUsers = repUsers.GetAll();

            if (watchedStats)
            {
                foreach (JMMUser juser in allUsers)
                {
                    AnimeGroup_User userRecord = GetUserRecord(juser.JMMUserID);
                    if (userRecord == null)
                    {
                        userRecord = new AnimeGroup_User(juser.JMMUserID, this.AnimeGroupID);
                    }

                    // reset stats
                    userRecord.WatchedCount          = 0;
                    userRecord.UnwatchedEpisodeCount = 0;
                    userRecord.PlayedCount           = 0;
                    userRecord.StoppedCount          = 0;
                    userRecord.WatchedEpisodeCount   = 0;
                    userRecord.WatchedDate           = null;

                    foreach (AnimeSeries ser in seriesList)
                    {
                        AnimeSeries_User serUserRecord = ser.GetUserRecord(juser.JMMUserID);
                        if (serUserRecord != null)
                        {
                            userRecord.WatchedCount          += serUserRecord.WatchedCount;
                            userRecord.UnwatchedEpisodeCount += serUserRecord.UnwatchedEpisodeCount;
                            userRecord.PlayedCount           += serUserRecord.PlayedCount;
                            userRecord.StoppedCount          += serUserRecord.StoppedCount;
                            userRecord.WatchedEpisodeCount   += serUserRecord.WatchedEpisodeCount;

                            if (serUserRecord.WatchedDate.HasValue)
                            {
                                if (userRecord.WatchedDate.HasValue)
                                {
                                    if (serUserRecord.WatchedDate > userRecord.WatchedDate)
                                    {
                                        userRecord.WatchedDate = serUserRecord.WatchedDate;
                                    }
                                }
                                else
                                {
                                    userRecord.WatchedDate = serUserRecord.WatchedDate;
                                }
                            }
                        }
                    }

                    // now update the stats for the groups
                    logger.Trace("Updating stats for {0}", this.ToString());
                    AnimeGroup_UserRepository rep = new AnimeGroup_UserRepository();
                    rep.Save(userRecord);
                }
            }

            if (missingEpsStats)
            {
                this.MissingEpisodeCount       = 0;
                this.MissingEpisodeCountGroups = 0;

                foreach (AnimeSeries ser in seriesList)
                {
                    this.MissingEpisodeCount       += ser.MissingEpisodeCount;
                    this.MissingEpisodeCountGroups += ser.MissingEpisodeCountGroups;
                }

                AnimeGroupRepository repGrp = new AnimeGroupRepository();
                repGrp.Save(this);
            }
        }
コード例 #14
0
ファイル: VideoLocal.cs プロジェクト: ewelike23/jmm
        public void ToggleWatchedStatus(bool watched, bool updateOnline, DateTime?watchedDate, bool updateStats, bool updateStatsCache, int userID,
                                        bool scrobbleTrakt, bool updateWatchedDate)
        {
            VideoLocalRepository            repVids     = new VideoLocalRepository();
            AnimeEpisodeRepository          repEpisodes = new AnimeEpisodeRepository();
            AniDB_FileRepository            repAniFile  = new AniDB_FileRepository();
            CrossRef_File_EpisodeRepository repCross    = new CrossRef_File_EpisodeRepository();
            VideoLocal_UserRepository       repVidUsers = new VideoLocal_UserRepository();
            JMMUserRepository           repUsers        = new JMMUserRepository();
            AnimeEpisode_UserRepository repEpisodeUsers = new AnimeEpisode_UserRepository();

            JMMUser user = repUsers.GetByID(userID);

            if (user == null)
            {
                return;
            }

            List <JMMUser> aniDBUsers = repUsers.GetAniDBUsers();

            // update the video file to watched
            int mywatched = watched ? 1 : 0;

            if (user.IsAniDBUser == 0)
            {
                SaveWatchedStatus(watched, userID, watchedDate, updateWatchedDate);
            }
            else
            {
                // if the user is AniDB user we also want to update any other AniDB
                // users to keep them in sync
                foreach (JMMUser juser in aniDBUsers)
                {
                    if (juser.IsAniDBUser == 1)
                    {
                        SaveWatchedStatus(watched, juser.JMMUserID, watchedDate, updateWatchedDate);
                    }
                }
            }


            // now lets find all the associated AniDB_File record if there is one
            if (user.IsAniDBUser == 1)
            {
                AniDB_File aniFile = repAniFile.GetByHash(this.Hash);
                if (aniFile != null)
                {
                    aniFile.IsWatched = mywatched;

                    if (watched)
                    {
                        if (watchedDate.HasValue)
                        {
                            aniFile.WatchedDate = watchedDate;
                        }
                        else
                        {
                            aniFile.WatchedDate = DateTime.Now;
                        }
                    }
                    else
                    {
                        aniFile.WatchedDate = null;
                    }


                    repAniFile.Save(aniFile, false);
                }

                if (updateOnline)
                {
                    if ((watched && ServerSettings.AniDB_MyList_SetWatched) || (!watched && ServerSettings.AniDB_MyList_SetUnwatched))
                    {
                        CommandRequest_UpdateMyListFileStatus cmd = new CommandRequest_UpdateMyListFileStatus(this.Hash, watched, false,
                                                                                                              watchedDate.HasValue ? Utils.GetAniDBDateAsSeconds(watchedDate) : 0);
                        cmd.Save();
                    }
                }
            }

            // now find all the episode records associated with this video file
            // but we also need to check if theer are any other files attached to this episode with a watched
            // status,


            AnimeSeries ser = null;
            // get all files associated with this episode
            List <CrossRef_File_Episode> xrefs = repCross.GetByHash(this.Hash);

            if (watched)
            {
                // find the total watched percentage
                // eg one file can have a % = 100
                // or if 2 files make up one episodes they will each have a % = 50

                foreach (CrossRef_File_Episode xref in xrefs)
                {
                    // get the episode for this file
                    AnimeEpisode ep = repEpisodes.GetByAniDBEpisodeID(xref.EpisodeID);
                    if (ep == null)
                    {
                        continue;
                    }

                    // get all the files for this episode
                    int epPercentWatched = 0;
                    foreach (CrossRef_File_Episode filexref in ep.FileCrossRefs)
                    {
                        VideoLocal_User vidUser = filexref.GetVideoLocalUserRecord(userID);
                        if (vidUser != null)
                        {
                            // if not null means it is watched
                            epPercentWatched += filexref.Percentage;
                        }

                        if (epPercentWatched > 95)
                        {
                            break;
                        }
                    }

                    if (epPercentWatched > 95)
                    {
                        ser = ep.GetAnimeSeries();

                        if (user.IsAniDBUser == 0)
                        {
                            ep.SaveWatchedStatus(true, userID, watchedDate, updateWatchedDate);
                        }
                        else
                        {
                            // if the user is AniDB user we also want to update any other AniDB
                            // users to keep them in sync
                            foreach (JMMUser juser in aniDBUsers)
                            {
                                if (juser.IsAniDBUser == 1)
                                {
                                    ep.SaveWatchedStatus(true, juser.JMMUserID, watchedDate, updateWatchedDate);
                                }
                            }
                        }

                        if (scrobbleTrakt && !string.IsNullOrEmpty(ServerSettings.Trakt_Username) && !string.IsNullOrEmpty(ServerSettings.Trakt_Password))
                        {
                            CommandRequest_TraktShowScrobble cmdScrobble = new CommandRequest_TraktShowScrobble(ep.AnimeEpisodeID);
                            cmdScrobble.Save();
                        }

                        if (!string.IsNullOrEmpty(ServerSettings.MAL_Username) && !string.IsNullOrEmpty(ServerSettings.MAL_Password))
                        {
                            CommandRequest_MALUpdatedWatchedStatus cmdMAL = new CommandRequest_MALUpdatedWatchedStatus(ser.AniDB_ID);
                            cmdMAL.Save();
                        }
                    }
                }
            }
            else
            {
                // if setting a file to unwatched only set the episode unwatched, if ALL the files are unwatched
                foreach (CrossRef_File_Episode xrefEp in xrefs)
                {
                    AnimeEpisode ep = repEpisodes.GetByAniDBEpisodeID(xrefEp.EpisodeID);
                    if (ep == null)
                    {
                        continue;
                    }
                    ser = ep.GetAnimeSeries();

                    // get all the files for this episode
                    int epPercentWatched = 0;
                    foreach (CrossRef_File_Episode filexref in ep.FileCrossRefs)
                    {
                        VideoLocal_User vidUser = filexref.GetVideoLocalUserRecord(userID);
                        if (vidUser != null)
                        {
                            epPercentWatched += filexref.Percentage;
                        }

                        if (epPercentWatched > 95)
                        {
                            break;
                        }
                    }

                    if (epPercentWatched < 95)
                    {
                        if (user.IsAniDBUser == 0)
                        {
                            ep.SaveWatchedStatus(false, userID, watchedDate, true);
                        }
                        else
                        {
                            // if the user is AniDB user we also want to update any other AniDB
                            // users to keep them in sync
                            foreach (JMMUser juser in aniDBUsers)
                            {
                                if (juser.IsAniDBUser == 1)
                                {
                                    ep.SaveWatchedStatus(false, juser.JMMUserID, watchedDate, true);
                                }
                            }
                        }

                        CommandRequest_TraktShowEpisodeUnseen cmdUnseen = new CommandRequest_TraktShowEpisodeUnseen(ep.AnimeEpisodeID);
                        cmdUnseen.Save();
                    }
                }

                if (!string.IsNullOrEmpty(ServerSettings.MAL_Username) && !string.IsNullOrEmpty(ServerSettings.MAL_Password))
                {
                    CommandRequest_MALUpdatedWatchedStatus cmdMAL = new CommandRequest_MALUpdatedWatchedStatus(ser.AniDB_ID);
                    cmdMAL.Save();
                }
            }


            // update stats for groups and series
            if (ser != null && updateStats)
            {
                // update all the groups above this series in the heirarchy
                ser.UpdateStats(true, true, true);
                //ser.TopLevelAnimeGroup.UpdateStatsFromTopLevel(true, true, true);
            }

            if (ser != null && updateStatsCache)
            {
                StatsCache.Instance.UpdateUsingSeries(ser.AnimeSeriesID);
            }
        }
コード例 #15
0
        public override void ProcessCommand()
        {
            logger.Info("Processing CommandRequest_SyncMyList");

            try
            {
                // we will always assume that an anime was downloaded via http first
                ScheduledUpdateRepository repSched     = new ScheduledUpdateRepository();
                AniDB_FileRepository      repAniFile   = new AniDB_FileRepository();
                VideoLocalRepository      repVidLocals = new VideoLocalRepository();

                ScheduledUpdate sched = repSched.GetByUpdateType((int)ScheduledUpdateType.AniDBMyListSync);
                if (sched == null)
                {
                    sched               = new ScheduledUpdate();
                    sched.UpdateType    = (int)ScheduledUpdateType.AniDBMyListSync;
                    sched.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)
                {
                    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, AniDB_File> dictAniFiles = new Dictionary <string, AniDB_File>();
                    List <AniDB_File> allAniFiles = repAniFile.GetAll();
                    foreach (AniDB_File anifile in allAniFiles)
                    {
                        dictAniFiles[anifile.Hash] = anifile;
                    }

                    int missingFiles = 0;
                    foreach (VideoLocal vid in repVidLocals.GetAll())
                    {
                        if (!dictAniFiles.ContainsKey(vid.Hash))
                        {
                            continue;
                        }

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

                        if (!onlineFiles.ContainsKey(fileID))
                        {
                            // 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(string.Format("MYLIST Missing Files: {0} Added to queue for inclusion", missingFiles));

                    JMMUserRepository repUsers   = new JMMUserRepository();
                    List <JMMUser>    aniDBUsers = repUsers.GetAniDBUsers();

                    VideoLocal_UserRepository       repVidUsers = new VideoLocal_UserRepository();
                    CrossRef_File_EpisodeRepository repFileEp   = new CrossRef_File_EpisodeRepository();

                    // 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 = (double)totalItems / (double)cmd.MyListItems.Count * (double)100;
                        string spct = pct.ToString("#0.0");

                        string hash = string.Empty;

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


                        if (!string.IsNullOrEmpty(hash))
                        {
                            // find the video associated with this record
                            VideoLocal vl = repVidLocals.GetByHash(hash);
                            if (vl == null)
                            {
                                continue;
                            }

                            foreach (JMMUser juser in aniDBUsers)
                            {
                                bool localStatus = false;
                                int? jmmUserID   = null;

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

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

                                    string msg =
                                        string.Format(
                                            "MYLISTDIFF:: File {0} - Local Status = {1}, AniDB Status = {2} --- {3}",
                                            vl.FullServerPath, localStatus, 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;
                    repSched.Save(sched);
                }
            }
            catch (Exception ex)
            {
                logger.Error("Error processing CommandRequest_SyncMyList: {0} ", ex.ToString());
                return;
            }
        }
コード例 #16
0
        /*public static void UpdateWatchedStatus(int animeID, enEpisodeType epType, int lastWatchedEpNumber)
         *      {
         *              try
         *              {
         *                      if (string.IsNullOrEmpty(ServerSettings.MAL_Username) || string.IsNullOrEmpty(ServerSettings.MAL_Password))
         *                              return;
         *
         *                      AniDB_EpisodeRepository repAniEps = new AniDB_EpisodeRepository();
         *                      List<AniDB_Episode> aniEps = repAniEps.GetByAnimeIDAndEpisodeTypeNumber(animeID, epType, lastWatchedEpNumber);
         *                      if (aniEps.Count == 0) return;
         *
         *                      AnimeEpisodeRepository repEp = new AnimeEpisodeRepository();
         *                      AnimeEpisode ep = repEp.GetByAniDBEpisodeID(aniEps[0].EpisodeID);
         *                      if (ep == null) return;
         *
         *                      MALHelper.UpdateMAL(ep);
         *              }
         *              catch (Exception ex)
         *              {
         *                      logger.ErrorException(ex.ToString(), ex);
         *              }
         *      }*/

        public static void UpdateMALSeries(AnimeSeries ser)
        {
            try
            {
                if (string.IsNullOrEmpty(ServerSettings.MAL_Username) ||
                    string.IsNullOrEmpty(ServerSettings.MAL_Password))
                {
                    return;
                }

                // Populate MAL animelist hashtable if isNeverDecreaseWatched set
                Hashtable animeListHashtable = new Hashtable();
                if (ServerSettings.MAL_NeverDecreaseWatchedNums)
                //if set, check watched number before update: take some time, as user anime list must be loaded
                {
                    myanimelist malAnimeList = GetMALAnimeList();
                    if (malAnimeList != null && malAnimeList.anime != null)
                    {
                        for (int i = 0; i < malAnimeList.anime.Length; i++)
                        {
                            animeListHashtable.Add(malAnimeList.anime[i].series_animedb_id, malAnimeList.anime[i]);
                        }
                    }
                }

                // look for MAL Links
                List <CrossRef_AniDB_MAL> crossRefs = ser.GetAnime().GetCrossRefMAL();
                if (crossRefs == null || crossRefs.Count == 0)
                {
                    logger.Warn("Could not find MAL link for : {0} ({1})", ser.GetAnime().GetFormattedTitle(),
                                ser.GetAnime().AnimeID);
                    return;
                }

                AnimeEpisodeRepository repEps   = new AnimeEpisodeRepository();
                AniDB_FileRepository   repFiles = new AniDB_FileRepository();

                List <AnimeEpisode> eps = ser.GetAnimeEpisodes();

                // find the anidb user
                JMMUserRepository repUsers   = new JMMUserRepository();
                List <JMMUser>    aniDBUsers = repUsers.GetAniDBUsers();
                if (aniDBUsers.Count == 0)
                {
                    return;
                }

                JMMUser user = aniDBUsers[0];

                int score = 0;
                if (ser.GetAnime().UserVote != null)
                {
                    score = (int)(ser.GetAnime().UserVote.VoteValue / 100);
                }

                // e.g.
                // AniDB - Code Geass R2
                // MAL Equivalent = AniDB Normal Eps 1 - 25 / Code Geass: Hangyaku no Lelouch R2 / hxxp://myanimelist.net/anime/2904/Code_Geass:_Hangyaku_no_Lelouch_R2
                // MAL Equivalent = AniDB Special Eps 1 - 9 / Code Geass: Hangyaku no Lelouch R2 Picture Drama / hxxp://myanimelist.net/anime/5163/Code_Geass:_Hangyaku_no_Lelouch_R2_Picture_Drama
                // MAL Equivalent = AniDB Special Eps 9 - 18 / Code Geass: Hangyaku no Lelouch R2: Flash Specials / hxxp://myanimelist.net/anime/9591/Code_Geass:_Hangyaku_no_Lelouch_R2:_Flash_Specials
                // MAL Equivalent = AniDB Special Eps 20 / Code Geass: Hangyaku no Lelouch - Kiseki no Birthday Picture Drama / hxxp://myanimelist.net/anime/8728/Code_Geass:_Hangyaku_no_Lelouch_-_Kiseki_no_Birthday_Picture_Drama

                foreach (CrossRef_AniDB_MAL xref in crossRefs)
                {
                    // look for the right MAL id
                    int malID        = -1;
                    int epNumber     = -1;
                    int totalEpCount = -1;

                    List <string> fanSubGroups = new List <string>();

                    // for each cross ref (which is a series on MAL) we need to update the data
                    // so find all the episodes which apply to this cross ref
                    int lastWatchedEpNumber = 0;
                    int downloadedEps       = 0;

                    foreach (AnimeEpisode ep in eps)
                    {
                        int epNum = ep.AniDB_Episode.EpisodeNumber;
                        if (xref.StartEpisodeType == (int)ep.EpisodeTypeEnum && epNum >= xref.StartEpisodeNumber &&
                            epNum <= GetUpperEpisodeLimit(crossRefs, xref))
                        {
                            malID    = xref.MALID;
                            epNumber = epNum - xref.StartEpisodeNumber + 1;

                            // find the total episode count
                            if (totalEpCount < 0)
                            {
                                if (ep.EpisodeTypeEnum == AniDBAPI.enEpisodeType.Episode)
                                {
                                    totalEpCount = ser.GetAnime().EpisodeCountNormal;
                                }
                                if (ep.EpisodeTypeEnum == AniDBAPI.enEpisodeType.Special)
                                {
                                    totalEpCount = ser.GetAnime().EpisodeCountSpecial;
                                }
                                totalEpCount = totalEpCount - xref.StartEpisodeNumber + 1;
                            }

                            // any episodes here belong to the MAL series
                            // find the latest watched episod enumber
                            AnimeEpisode_User usrRecord = ep.GetUserRecord(user.JMMUserID);
                            if (usrRecord != null && usrRecord.WatchedDate.HasValue && epNum > lastWatchedEpNumber)
                            {
                                lastWatchedEpNumber = epNum;
                            }

                            List <Contract_VideoDetailed> contracts = ep.GetVideoDetailedContracts(user.JMMUserID);

                            // find the latest episode number in the collection
                            if (contracts.Count > 0)
                            {
                                downloadedEps++;
                            }

                            foreach (Contract_VideoDetailed contract in contracts)
                            {
                                if (!string.IsNullOrEmpty(contract.AniDB_Anime_GroupNameShort) &&
                                    !fanSubGroups.Contains(contract.AniDB_Anime_GroupNameShort))
                                {
                                    fanSubGroups.Add(contract.AniDB_Anime_GroupNameShort);
                                }
                            }
                        }
                    }

                    string fanSubs = "";
                    foreach (string fgrp in fanSubGroups)
                    {
                        if (!string.IsNullOrEmpty(fanSubs))
                        {
                            fanSubs += ",";
                        }
                        fanSubs += fgrp;
                    }

                    // determine status
                    int status = 1; //watching
                    if (animeListHashtable.ContainsKey(malID))
                    {
                        myanimelistAnime animeInList = (myanimelistAnime)animeListHashtable[malID];
                        status = animeInList.my_status;
                    }

                    // over-ride is user has watched an episode
                    // don't override on hold (3) or dropped (4) but do override plan to watch (6)
                    if (status == 6 && lastWatchedEpNumber > 0)
                    {
                        status = 1;                                         //watching
                    }
                    if (lastWatchedEpNumber == totalEpCount)
                    {
                        status = 2;                                      //completed
                    }
                    if (lastWatchedEpNumber > totalEpCount)
                    {
                        logger.Error("updateMAL, episode number > matching anime episode total : {0} ({1}) / {2}",
                                     ser.GetAnime().GetFormattedTitle(), ser.GetAnime().AnimeID, epNumber);
                        continue;
                    }

                    if (malID <= 0 || totalEpCount <= 0)
                    {
                        logger.Warn("Could not find MAL link for : {0} ({1})", ser.GetAnime().GetFormattedTitle(),
                                    ser.GetAnime().AnimeID);
                        continue;
                    }
                    else
                    {
                        bool res = UpdateAnime(malID, lastWatchedEpNumber, status, score, downloadedEps, fanSubs);

                        string confirmationMessage =
                            string.Format("MAL successfully updated, mal id: {0}, ep: {1}, score: {2}", malID,
                                          lastWatchedEpNumber, score);
                        if (res)
                        {
                            logger.Trace(confirmationMessage);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                logger.ErrorException(ex.ToString(), ex);
            }
        }
コード例 #17
0
        public void UpdateStats(bool watchedStats, bool missingEpsStats, bool updateAllGroupsAbove)
        {
            DateTime start        = DateTime.Now;
            DateTime startOverall = DateTime.Now;

            logger.Info("Starting Updating STATS for SERIES {0} ({1} - {2} - {3})", this.ToString(), watchedStats, missingEpsStats, updateAllGroupsAbove);

            AnimeSeries_UserRepository      repSeriesUser  = new AnimeSeries_UserRepository();
            AnimeEpisode_UserRepository     repEpisodeUser = new AnimeEpisode_UserRepository();
            VideoLocalRepository            repVids        = new VideoLocalRepository();
            CrossRef_File_EpisodeRepository repXrefs       = new CrossRef_File_EpisodeRepository();

            JMMUserRepository repUsers = new JMMUserRepository();
            List <JMMUser>    allUsers = repUsers.GetAll();

            DateTime            startEps = DateTime.Now;
            List <AnimeEpisode> eps      = GetAnimeEpisodes();
            TimeSpan            tsEps    = DateTime.Now - startEps;

            logger.Trace("Got episodes for SERIES {0} in {1}ms", this.ToString(), tsEps.TotalMilliseconds);

            DateTime                     startVids = DateTime.Now;
            List <VideoLocal>            vidsTemp  = repVids.GetByAniDBAnimeID(this.AniDB_ID);
            List <CrossRef_File_Episode> crossRefs = repXrefs.GetByAnimeID(this.AniDB_ID);

            Dictionary <int, List <CrossRef_File_Episode> > dictCrossRefs = new Dictionary <int, List <CrossRef_File_Episode> >();

            foreach (CrossRef_File_Episode xref in crossRefs)
            {
                if (!dictCrossRefs.ContainsKey(xref.EpisodeID))
                {
                    dictCrossRefs[xref.EpisodeID] = new List <CrossRef_File_Episode>();
                }
                dictCrossRefs[xref.EpisodeID].Add(xref);
            }

            Dictionary <string, VideoLocal> dictVids = new Dictionary <string, VideoLocal>();

            foreach (VideoLocal vid in vidsTemp)
            {
                dictVids[vid.Hash] = vid;
            }

            TimeSpan tsVids = DateTime.Now - startVids;

            logger.Trace("Got video locals for SERIES {0} in {1}ms", this.ToString(), tsVids.TotalMilliseconds);


            if (watchedStats)
            {
                foreach (JMMUser juser in allUsers)
                {
                    //this.WatchedCount = 0;
                    AnimeSeries_User userRecord = GetUserRecord(juser.JMMUserID);
                    if (userRecord == null)
                    {
                        userRecord = new AnimeSeries_User(juser.JMMUserID, this.AnimeSeriesID);
                    }

                    // reset stats
                    userRecord.UnwatchedEpisodeCount = 0;
                    userRecord.WatchedEpisodeCount   = 0;
                    userRecord.WatchedCount          = 0;
                    userRecord.WatchedDate           = null;

                    DateTime startUser = DateTime.Now;
                    List <AnimeEpisode_User>            epUserRecords   = repEpisodeUser.GetByUserID(juser.JMMUserID);
                    Dictionary <int, AnimeEpisode_User> dictUserRecords = new Dictionary <int, AnimeEpisode_User>();
                    foreach (AnimeEpisode_User usrec in epUserRecords)
                    {
                        dictUserRecords[usrec.AnimeEpisodeID] = usrec;
                    }
                    TimeSpan tsUser = DateTime.Now - startUser;
                    logger.Trace("Got user records for SERIES {0}/{1} in {2}ms", this.ToString(), juser.Username, tsUser.TotalMilliseconds);

                    foreach (AnimeEpisode ep in eps)
                    {
                        // if the episode doesn't have any files then it won't count towards watched/unwatched counts
                        List <VideoLocal> epVids = new List <VideoLocal>();

                        if (dictCrossRefs.ContainsKey(ep.AniDB_EpisodeID))
                        {
                            foreach (CrossRef_File_Episode xref in dictCrossRefs[ep.AniDB_EpisodeID])
                            {
                                if (xref.EpisodeID == ep.AniDB_EpisodeID)
                                {
                                    if (dictVids.ContainsKey(xref.Hash))
                                    {
                                        epVids.Add(dictVids[xref.Hash]);
                                    }
                                }
                            }
                        }
                        if (epVids.Count == 0)
                        {
                            continue;
                        }

                        if (ep.EpisodeTypeEnum == AniDBAPI.enEpisodeType.Episode || ep.EpisodeTypeEnum == AniDBAPI.enEpisodeType.Special)
                        {
                            AnimeEpisode_User epUserRecord = null;
                            if (dictUserRecords.ContainsKey(ep.AnimeEpisodeID))
                            {
                                epUserRecord = dictUserRecords[ep.AnimeEpisodeID];
                            }

                            if (epUserRecord != null && epUserRecord.WatchedDate.HasValue)
                            {
                                userRecord.WatchedEpisodeCount++;
                            }
                            else
                            {
                                userRecord.UnwatchedEpisodeCount++;
                            }

                            if (epUserRecord != null)
                            {
                                if (userRecord.WatchedDate.HasValue)
                                {
                                    if (epUserRecord.WatchedDate > userRecord.WatchedDate)
                                    {
                                        userRecord.WatchedDate = epUserRecord.WatchedDate;
                                    }
                                }
                                else
                                {
                                    userRecord.WatchedDate = epUserRecord.WatchedDate;
                                }

                                userRecord.WatchedCount += epUserRecord.WatchedCount;
                            }
                        }
                    }
                    repSeriesUser.Save(userRecord);
                }
            }

            TimeSpan ts = DateTime.Now - start;

            logger.Trace("Updated WATCHED stats for SERIES {0} in {1}ms", this.ToString(), ts.TotalMilliseconds);
            start = DateTime.Now;



            if (missingEpsStats)
            {
                enAnimeType animeType   = enAnimeType.TVSeries;
                AniDB_Anime aniDB_Anime = this.GetAnime();
                if (aniDB_Anime != null)
                {
                    animeType = aniDB_Anime.AnimeTypeEnum;
                }

                MissingEpisodeCount       = 0;
                MissingEpisodeCountGroups = 0;

                // get all the group status records
                AniDB_GroupStatusRepository repGrpStat  = new AniDB_GroupStatusRepository();
                List <AniDB_GroupStatus>    grpStatuses = repGrpStat.GetByAnimeID(this.AniDB_ID);

                // find all the episodes for which the user has a file
                // from this we can determine what their latest episode number is
                // find out which groups the user is collecting

                List <int> userReleaseGroups = new List <int>();
                foreach (AnimeEpisode ep in eps)
                {
                    List <VideoLocal> vids = new List <VideoLocal>();
                    if (dictCrossRefs.ContainsKey(ep.AniDB_EpisodeID))
                    {
                        foreach (CrossRef_File_Episode xref in dictCrossRefs[ep.AniDB_EpisodeID])
                        {
                            if (xref.EpisodeID == ep.AniDB_EpisodeID)
                            {
                                if (dictVids.ContainsKey(xref.Hash))
                                {
                                    vids.Add(dictVids[xref.Hash]);
                                }
                            }
                        }
                    }

                    //List<VideoLocal> vids = ep.VideoLocals;
                    foreach (VideoLocal vid in vids)
                    {
                        AniDB_File anifile = vid.GetAniDBFile();
                        if (anifile != null)
                        {
                            if (!userReleaseGroups.Contains(anifile.GroupID))
                            {
                                userReleaseGroups.Add(anifile.GroupID);
                            }
                        }
                    }
                }

                int         latestLocalEpNumber = 0;
                EpisodeList epReleasedList      = new EpisodeList(animeType);
                EpisodeList epGroupReleasedList = new EpisodeList(animeType);

                foreach (AnimeEpisode ep in eps)
                {
                    //List<VideoLocal> vids = ep.VideoLocals;
                    if (ep.EpisodeTypeEnum != AniDBAPI.enEpisodeType.Episode)
                    {
                        continue;
                    }

                    List <VideoLocal> vids = new List <VideoLocal>();
                    if (dictCrossRefs.ContainsKey(ep.AniDB_EpisodeID))
                    {
                        foreach (CrossRef_File_Episode xref in dictCrossRefs[ep.AniDB_EpisodeID])
                        {
                            if (xref.EpisodeID == ep.AniDB_EpisodeID)
                            {
                                if (dictVids.ContainsKey(xref.Hash))
                                {
                                    vids.Add(dictVids[xref.Hash]);
                                }
                            }
                        }
                    }



                    AniDB_Episode aniEp     = ep.AniDB_Episode;
                    int           thisEpNum = aniEp.EpisodeNumber;

                    if (thisEpNum > latestLocalEpNumber && vids.Count > 0)
                    {
                        latestLocalEpNumber = thisEpNum;
                    }

                    // does this episode have a file released
                    // does this episode have a file released by the group the user is collecting
                    bool epReleased      = false;
                    bool epReleasedGroup = false;
                    foreach (AniDB_GroupStatus gs in grpStatuses)
                    {
                        if (gs.LastEpisodeNumber >= thisEpNum)
                        {
                            epReleased = true;
                        }
                        if (userReleaseGroups.Contains(gs.GroupID) && gs.HasGroupReleasedEpisode(thisEpNum))
                        {
                            epReleasedGroup = true;
                        }
                    }


                    try
                    {
                        epReleasedList.Add(ep, (!epReleased || vids.Count != 0));
                        epGroupReleasedList.Add(ep, (!epReleasedGroup || vids.Count != 0));
                    }
                    catch (Exception e)
                    {
                        logger.Trace("Error {0}", e.ToString());
                        throw;
                    }
                }
                foreach (EpisodeList.StatEpisodes eplst in epReleasedList)
                {
                    if (!eplst.Available)
                    {
                        MissingEpisodeCount++;
                    }
                }
                foreach (EpisodeList.StatEpisodes eplst in epGroupReleasedList)
                {
                    if (!eplst.Available)
                    {
                        MissingEpisodeCountGroups++;
                    }
                }

                this.LatestLocalEpisodeNumber = latestLocalEpNumber;
            }

            ts = DateTime.Now - start;
            logger.Trace("Updated MISSING EPS stats for SERIES {0} in {1}ms", this.ToString(), ts.TotalMilliseconds);
            start = DateTime.Now;

            AnimeSeriesRepository rep = new AnimeSeriesRepository();

            rep.Save(this);

            if (updateAllGroupsAbove)
            {
                foreach (AnimeGroup grp in AllGroupsAbove)
                {
                    grp.UpdateStats(watchedStats, missingEpsStats);
                }
            }

            ts = DateTime.Now - start;
            logger.Trace("Updated GROUPS ABOVE stats for SERIES {0} in {1}ms", this.ToString(), ts.TotalMilliseconds);
            start = DateTime.Now;

            TimeSpan tsOverall = DateTime.Now - startOverall;

            logger.Info("Finished Updating STATS for SERIES {0} in {1}ms ({2} - {3} - {4})", this.ToString(), tsOverall.TotalMilliseconds,
                        watchedStats, missingEpsStats, updateAllGroupsAbove);
        }