public override void ProcessCommand()
        {
            logger.Info("Processing CommandRequest_TraktShowScrobble: {0}", AnimeEpisodeID);

            try
            {
                if (!ServerSettings.WebCache_Trakt_Send || string.IsNullOrEmpty(ServerSettings.Trakt_Username))
                {
                    return;
                }

                AnimeEpisodeRepository repEpisodes = new AnimeEpisodeRepository();
                AnimeEpisode           ep          = repEpisodes.GetByID(AnimeEpisodeID);
                if (ep != null)
                {
                    // before scrobbling try to ensure the episode is in the users collection by sync'ing the series
                    //TraktTVHelper.SyncCollectionToTrakt_Series(ep.AnimeSeries);

                    TraktTVHelper.MarkEpisodeWatched(ep);
                }
            }
            catch (Exception ex)
            {
                logger.Error("Error processing CommandRequest_TraktShowScrobble: {0} - {1}", AnimeEpisodeID, ex.ToString());
                return;
            }
        }
        public override void ProcessCommand()
        {
            logger.Info("Processing CommandRequest_TraktCollectionEpisode: {0}-{1}", AnimeEpisodeID, Action);

            try
            {
                logger.Info("CommandRequest_TraktCollectionEpisode - DEBUG01");
                if (!ServerSettings.Trakt_IsEnabled || string.IsNullOrEmpty(ServerSettings.Trakt_AuthToken)) return;
                logger.Info("CommandRequest_TraktCollectionEpisode - DEBUG02");

                AnimeEpisodeRepository repEpisodes = new AnimeEpisodeRepository();
                AnimeEpisode ep = repEpisodes.GetByID(AnimeEpisodeID);
                if (ep != null)
                {
                    logger.Info("CommandRequest_TraktCollectionEpisode - DEBUG03");
                    TraktSyncType syncType = TraktSyncType.CollectionAdd;
                    if (ActionEnum == TraktSyncAction.Remove) syncType = TraktSyncType.CollectionRemove;
                    TraktTVHelper.SyncEpisodeToTrakt(ep, syncType);
                }
            }
            catch (Exception ex)
            {
                logger.Error("Error processing CommandRequest_TraktCollectionEpisode: {0} - {1} - {2}", AnimeEpisodeID,
                    Action,
                    ex.ToString());
                return;
            }
        }
        public void ToggleWatchedStatusOnEpisode(string userid, string episodeid, string watchedstatus)
        {
            try
            {
                int  aep     = 0;
                int  usid    = 0;
                bool wstatus = false;
                if (!int.TryParse(episodeid, out aep))
                {
                    return;
                }
                if (!int.TryParse(userid, out usid))
                {
                    return;
                }
                if (!bool.TryParse(watchedstatus, out wstatus))
                {
                    return;
                }

                AnimeEpisodeRepository repEps = new AnimeEpisodeRepository();
                AnimeEpisode           ep     = repEps.GetByID(aep);
                if (ep == null)
                {
                    return;
                }

                ep.ToggleWatchedStatus(wstatus, true, DateTime.Now, false, false, usid, true);
                ep.GetAnimeSeries().UpdateStats(true, false, true);
            }
            catch (Exception ex)
            {
                logger.ErrorException(ex.ToString(), ex);
            }
        }
        public override void ProcessCommand()
        {
            logger.Info("Processing CommandRequest_UpdateMyListFileStatus: {0}", Hash);


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

                // NOTE - we might return more than one VideoLocal record here, if there are duplicates by hash
                VideoLocal vid = repVids.GetByHash(this.Hash);
                if (vid != null)
                {
                    bool isManualLink = false;
                    List <CrossRef_File_Episode> xrefs = vid.EpisodeCrossRefs;
                    if (xrefs.Count > 0)
                    {
                        isManualLink = xrefs[0].CrossRefSource != (int)CrossRefSource.AniDB;
                    }

                    if (isManualLink)
                    {
                        JMMService.AnidbProcessor.UpdateMyListFileStatus(xrefs[0].AnimeID,
                                                                         xrefs[0].Episode.EpisodeNumber, this.Watched);
                        logger.Info("Updating file list status (GENERIC): {0} - {1}", vid.ToString(), this.Watched);
                    }
                    else
                    {
                        if (WatchedDateAsSecs > 0)
                        {
                            DateTime?watchedDate = Utils.GetAniDBDateAsDate(WatchedDateAsSecs);
                            JMMService.AnidbProcessor.UpdateMyListFileStatus(vid, this.Watched, watchedDate);
                        }
                        else
                        {
                            JMMService.AnidbProcessor.UpdateMyListFileStatus(vid, this.Watched, null);
                        }
                        logger.Info("Updating file list status: {0} - {1}", vid.ToString(), this.Watched);
                    }

                    if (UpdateSeriesStats)
                    {
                        // update watched stats
                        List <AnimeEpisode> eps = repEpisodes.GetByHash(vid.ED2KHash);
                        if (eps.Count > 0)
                        {
                            // all the eps should belong to the same anime
                            eps[0].GetAnimeSeries().QueueUpdateStats();
                            //eps[0].AnimeSeries.TopLevelAnimeGroup.UpdateStatsFromTopLevel(true, true, false);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Error("Error processing CommandRequest_UpdateMyListFileStatus: {0} - {1}", Hash, ex.ToString());
                return;
            }
        }
Beispiel #5
0
        public static Video VideoFromAnimeEpisode(IProvider prov, List <Contract_CrossRef_AniDB_TvDBV2> cross,
                                                  KeyValuePair <AnimeEpisode, Contract_AnimeEpisode> e, int userid)
        {
            Video v = (Video)e.Key.PlexContract?.Clone <Video>();

            if (v?.Thumb != null)
            {
                v.Thumb = ReplaceSchemeHost(v.Thumb);
            }
            if (v != null && (v.Medias == null || v.Medias.Count == 0))
            {
                List <VideoLocal> locals = e.Key.GetVideoLocals();
                if (locals.Count > 0)
                {
                    VideoLocalRepository   lrepo = new VideoLocalRepository();
                    AnimeEpisodeRepository erepo = new AnimeEpisodeRepository();
                    foreach (VideoLocal n in locals)
                    {
                        lrepo.Save(n, false);
                    }
                    erepo.Save(e.Key);
                }
                v = (Video)e.Key.PlexContract?.Clone <Video>();
            }
            if (v != null)
            {
                if (e.Value != null)
                {
                    v.ViewCount = e.Value.WatchedCount.ToString();
                    if (e.Value.WatchedDate.HasValue)
                    {
                        v.LastViewedAt = e.Value.WatchedDate.Value.ToUnixTime();
                    }
                }
                v.ParentIndex = "1";
                if (e.Key.EpisodeTypeEnum != enEpisodeType.Episode)
                {
                    v.ParentIndex = null;
                }
                if (cross != null && cross.Count > 0)
                {
                    Contract_CrossRef_AniDB_TvDBV2 c2 =
                        cross.FirstOrDefault(
                            a =>
                            a.AniDBStartEpisodeType == int.Parse(v.EpisodeType) &&
                            a.AniDBStartEpisodeNumber <= int.Parse(v.EpisodeNumber));
                    if (c2?.TvDBSeasonNumber > 0)
                    {
                        v.ParentIndex = c2.TvDBSeasonNumber.ToString();
                    }
                }
                AddLinksToAnimeEpisodeVideo(prov, v, userid);
            }
            return(v);
        }
Beispiel #6
0
        public void CreateAnimeEpisode(ISession session, int animeSeriesID)
        {
            // check if there is an existing episode for this EpisodeID
            AnimeEpisodeRepository repEps     = new AnimeEpisodeRepository();
            AnimeEpisode           existingEp = repEps.GetByAniDBEpisodeID(session, EpisodeID);

            if (existingEp == null)
            {
                AnimeEpisode animeEp = new AnimeEpisode();
                animeEp.Populate(this);
                animeEp.AnimeSeriesID = animeSeriesID;
                repEps.Save(session, animeEp);
            }
        }
        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();
        }
        public override void ProcessCommand()
        {
            logger.Info("Processing CommandRequest_TraktShowEpisodeUnseen: {0}", AnimeEpisodeID);

            try
            {
                AnimeEpisodeRepository repEps = new AnimeEpisodeRepository();
                AnimeEpisode           ep     = repEps.GetByID(AnimeEpisodeID);
                if (ep == null)
                {
                    logger.Error("Could not find anime epiosde: {0}", AnimeEpisodeID);
                    return;
                }

                TraktTVHelper.SyncEpisodeToTrakt(ep, TraktSyncType.HistoryRemove);
            }
            catch (Exception ex)
            {
                logger.Error("Error processing CommandRequest_TraktShowEpisodeUnseen: {0} - {1}", AnimeEpisodeID, ex.ToString());
                return;
            }
        }
Beispiel #9
0
        public List <AnimeEpisode> GetAnimeEpisodes(ISession session)
        {
            AnimeEpisodeRepository repEpisodes = new AnimeEpisodeRepository();

            return(repEpisodes.GetBySeriesID(session, AnimeSeriesID));
        }
        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;
            }
        }
Beispiel #11
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);
            }
        }
Beispiel #12
0
        private void ProcessFile_AniDB(VideoLocal vidLocal)
        {
            logger.Trace("Checking for AniDB_File record for: {0} --- {1}", vidLocal.Hash, vidLocal.FilePath);
            // check if we already have this AniDB_File info in the database

            AniDB_FileRepository            repAniFile   = new AniDB_FileRepository();
            AniDB_EpisodeRepository         repAniEps    = new AniDB_EpisodeRepository();
            AniDB_AnimeRepository           repAniAnime  = new AniDB_AnimeRepository();
            AnimeSeriesRepository           repSeries    = new AnimeSeriesRepository();
            VideoLocalRepository            repVidLocals = new VideoLocalRepository();
            AnimeEpisodeRepository          repEps       = new AnimeEpisodeRepository();
            CrossRef_File_EpisodeRepository repXrefFE    = new CrossRef_File_EpisodeRepository();

            AniDB_File aniFile = null;

            if (!ForceAniDB)
            {
                aniFile = repAniFile.GetByHashAndFileSize(vidLocal.Hash, vlocal.FileSize);

                if (aniFile == null)
                {
                    logger.Trace("AniDB_File record not found");
                }
            }

            int animeID = 0;

            if (aniFile == null)
            {
                // get info from AniDB
                logger.Debug("Getting AniDB_File record from AniDB....");
                Raw_AniDB_File fileInfo = JMMService.AnidbProcessor.GetFileInfo(vidLocal);
                if (fileInfo != null)
                {
                    // check if we already have a record
                    aniFile = repAniFile.GetByHashAndFileSize(vidLocal.Hash, vlocal.FileSize);

                    if (aniFile == null)
                    {
                        aniFile = new AniDB_File();
                    }

                    aniFile.Populate(fileInfo);

                    //overwrite with local file name
                    string localFileName = Path.GetFileName(vidLocal.FilePath);
                    aniFile.FileName = localFileName;

                    repAniFile.Save(aniFile, false);
                    aniFile.CreateLanguages();
                    aniFile.CreateCrossEpisodes(localFileName);

                    if (!string.IsNullOrEmpty(fileInfo.OtherEpisodesRAW))
                    {
                        string[] epIDs = fileInfo.OtherEpisodesRAW.Split(',');
                        foreach (string epid in epIDs)
                        {
                            int id = 0;
                            if (int.TryParse(epid, out id))
                            {
                                CommandRequest_GetEpisode cmdEp = new CommandRequest_GetEpisode(id);
                                cmdEp.Save();
                            }
                        }
                    }

                    animeID = aniFile.AnimeID;
                }
            }

            bool missingEpisodes = false;

            // if we still haven't got the AniDB_File Info we try the web cache or local records
            if (aniFile == null)
            {
                // check if we have any records from previous imports
                List <CrossRef_File_Episode> crossRefs = repXrefFE.GetByHash(vidLocal.Hash);
                if (crossRefs == null || crossRefs.Count == 0)
                {
                    // lets see if we can find the episode/anime info from the web cache
                    if (ServerSettings.WebCache_XRefFileEpisode_Get)
                    {
                        List <JMMServer.Providers.Azure.CrossRef_File_Episode> xrefs = JMMServer.Providers.Azure.AzureWebAPI.Get_CrossRefFileEpisode(vidLocal);

                        crossRefs = new List <CrossRef_File_Episode>();
                        if (xrefs == null || xrefs.Count == 0)
                        {
                            logger.Debug("Cannot find AniDB_File record or get cross ref from web cache record so exiting: {0}", vidLocal.ED2KHash);
                            return;
                        }
                        else
                        {
                            foreach (JMMServer.Providers.Azure.CrossRef_File_Episode xref in xrefs)
                            {
                                CrossRef_File_Episode xrefEnt = new CrossRef_File_Episode();
                                xrefEnt.Hash           = vidLocal.ED2KHash;
                                xrefEnt.FileName       = Path.GetFileName(vidLocal.FullServerPath);
                                xrefEnt.FileSize       = vidLocal.FileSize;
                                xrefEnt.CrossRefSource = (int)JMMServer.CrossRefSource.WebCache;
                                xrefEnt.AnimeID        = animeID;
                                xrefEnt.EpisodeID      = xref.EpisodeID;
                                xrefEnt.Percentage     = xref.Percentage;
                                xrefEnt.EpisodeOrder   = xref.EpisodeOrder;

                                crossRefs.Add(xrefEnt);
                                // in this case we need to save the cross refs manually as AniDB did not provide them
                                repXrefFE.Save(xrefEnt);
                            }
                        }
                    }
                    else
                    {
                        logger.Debug("Cannot get AniDB_File record so exiting: {0}", vidLocal.ED2KHash);
                        return;
                    }
                }

                // we assume that all episodes belong to the same anime
                foreach (CrossRef_File_Episode xref in crossRefs)
                {
                    animeID = xref.AnimeID;

                    AniDB_Episode ep = repAniEps.GetByEpisodeID(xref.EpisodeID);
                    if (ep == null)
                    {
                        missingEpisodes = true;
                    }
                }
            }
            else
            {
                // check if we have the episode info
                // if we don't, we will need to re-download the anime info (which also has episode info)

                if (aniFile.EpisodeCrossRefs.Count == 0)
                {
                    animeID = aniFile.AnimeID;

                    // if we have the anidb file, but no cross refs it means something has been broken
                    logger.Debug("Could not find any cross ref records for: {0}", vidLocal.ED2KHash);
                    missingEpisodes = true;
                }
                else
                {
                    foreach (CrossRef_File_Episode xref in aniFile.EpisodeCrossRefs)
                    {
                        AniDB_Episode ep = repAniEps.GetByEpisodeID(xref.EpisodeID);
                        if (ep == null)
                        {
                            missingEpisodes = true;
                        }

                        animeID = xref.AnimeID;
                    }
                }
            }

            // get from DB
            AniDB_Anime anime = repAniAnime.GetByAnimeID(animeID);
            bool        animeRecentlyUpdated = false;

            if (anime != null)
            {
                TimeSpan ts = DateTime.Now - anime.DateTimeUpdated;
                if (ts.TotalHours < 4)
                {
                    animeRecentlyUpdated = true;
                }
            }

            // even if we are missing episode info, don't get data  more than once every 4 hours
            // this is to prevent banning
            if (missingEpisodes && !animeRecentlyUpdated)
            {
                logger.Debug("Getting Anime record from AniDB....");
                anime = JMMService.AnidbProcessor.GetAnimeInfoHTTP(animeID, true, ServerSettings.AutoGroupSeries);
            }

            // create the group/series/episode records if needed
            AnimeSeries ser = null;

            if (anime != null)
            {
                logger.Debug("Creating groups, series and episodes....");
                // check if there is an AnimeSeries Record associated with this AnimeID
                ser = repSeries.GetByAnimeID(animeID);
                if (ser == null)
                {
                    // create a new AnimeSeries record
                    ser = anime.CreateAnimeSeriesAndGroup();
                }


                ser.CreateAnimeEpisodes();

                // check if we have any group status data for this associated anime
                // if not we will download it now
                AniDB_GroupStatusRepository repStatus = new AniDB_GroupStatusRepository();
                if (repStatus.GetByAnimeID(anime.AnimeID).Count == 0)
                {
                    CommandRequest_GetReleaseGroupStatus cmdStatus = new CommandRequest_GetReleaseGroupStatus(anime.AnimeID, false);
                    cmdStatus.Save();
                }

                // update stats
                ser.EpisodeAddedDate = DateTime.Now;
                repSeries.Save(ser);

                AnimeGroupRepository repGroups = new AnimeGroupRepository();
                foreach (AnimeGroup grp in ser.AllGroupsAbove)
                {
                    grp.EpisodeAddedDate = DateTime.Now;
                    repGroups.Save(grp);
                }
            }

            vidLocal.RenameIfRequired();
            vidLocal.MoveFileIfRequired();


            // update stats for groups and series
            if (ser != null)
            {
                // update all the groups above this series in the heirarchy
                ser.UpdateStats(true, true, true);
                StatsCache.Instance.UpdateUsingSeries(ser.AnimeSeriesID);
            }


            // Add this file to the users list
            if (ServerSettings.AniDB_MyList_AddFiles)
            {
                CommandRequest_AddFileToMyList cmd = new CommandRequest_AddFileToMyList(vidLocal.ED2KHash);
                cmd.Save();
            }

            // lets also try adding to the users trakt collecion by sync'ing the series
            if (ser != null)
            {
                if (ServerSettings.WebCache_Trakt_Send && !string.IsNullOrEmpty(ServerSettings.Trakt_Username))
                {
                    CommandRequest_TraktSyncCollectionSeries cmdTrakt = new CommandRequest_TraktSyncCollectionSeries(ser.AnimeSeriesID, ser.GetAnime().MainTitle);
                    cmdTrakt.Save();
                }
            }

            // sync the series on MAL
            if (ser != null)
            {
                CommandRequest_MALUpdatedWatchedStatus cmdMAL = new CommandRequest_MALUpdatedWatchedStatus(ser.AniDB_ID);
                cmdMAL.Save();
            }
        }
Beispiel #13
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;
            }
        }
        public System.IO.Stream VoteAnime(string userid, string objectid, string votevalue, string votetype)
        {
            Respond rsp = new Respond();

            rsp.code = 500;

            int    objid  = 0;
            int    usid   = 0;
            int    vt     = 0;
            double vvalue = 0;

            if (!int.TryParse(objectid, out objid))
            {
                return(KodiHelper.GetStreamFromXmlObject(rsp));
            }
            if (!int.TryParse(userid, out usid))
            {
                return(KodiHelper.GetStreamFromXmlObject(rsp));
            }
            if (!int.TryParse(votetype, out vt))
            {
                return(KodiHelper.GetStreamFromXmlObject(rsp));
            }
            if (!double.TryParse(votevalue, NumberStyles.Any, CultureInfo.InvariantCulture, out vvalue))
            {
                return(KodiHelper.GetStreamFromXmlObject(rsp));
            }
            using (var session = JMMService.SessionFactory.OpenSession())
            {
                if (vt == (int)enAniDBVoteType.Episode)
                {
                    AnimeEpisodeRepository repEpisodes = new AnimeEpisodeRepository();
                    AnimeEpisode           ep          = repEpisodes.GetByID(session, objid);
                    AniDB_Anime            anime       = ep.GetAnimeSeries().GetAnime();
                    if (anime == null)
                    {
                        rsp.code = 404;
                        return(KodiHelper.GetStreamFromXmlObject(rsp));
                    }
                    string msg = string.Format("Voting for anime episode: {0} - Value: {1}", ep.AnimeEpisodeID, vvalue);
                    logger.Info(msg);

                    // lets save to the database and assume it will work
                    AniDB_VoteRepository repVotes = new AniDB_VoteRepository();
                    List <AniDB_Vote>    dbVotes  = repVotes.GetByEntity(ep.AnimeEpisodeID);
                    AniDB_Vote           thisVote = null;
                    foreach (AniDB_Vote dbVote in dbVotes)
                    {
                        if (dbVote.VoteType == (int)enAniDBVoteType.Episode)
                        {
                            thisVote = dbVote;
                        }
                    }

                    if (thisVote == null)
                    {
                        thisVote          = new AniDB_Vote();
                        thisVote.EntityID = ep.AnimeEpisodeID;
                    }
                    thisVote.VoteType = vt;

                    int iVoteValue = 0;
                    if (vvalue > 0)
                    {
                        iVoteValue = (int)(vvalue * 100);
                    }
                    else
                    {
                        iVoteValue = (int)vvalue;
                    }

                    msg = string.Format("Voting for anime episode Formatted: {0} - Value: {1}", ep.AnimeEpisodeID, iVoteValue);
                    logger.Info(msg);
                    thisVote.VoteValue = iVoteValue;
                    repVotes.Save(thisVote);
                    CommandRequest_VoteAnime cmdVote = new CommandRequest_VoteAnime(anime.AnimeID, vt, Convert.ToDecimal(vvalue));
                    cmdVote.Save();
                }

                if (vt == (int)enAniDBVoteType.Anime)
                {
                    AnimeSeriesRepository repSeries = new AnimeSeriesRepository();
                    AnimeSeries           ser       = repSeries.GetByID(session, objid);
                    AniDB_Anime           anime     = ser.GetAnime();
                    if (anime == null)
                    {
                        rsp.code = 404;
                        return(KodiHelper.GetStreamFromXmlObject(rsp));
                    }
                    string msg = string.Format("Voting for anime: {0} - Value: {1}", anime.AnimeID, vvalue);
                    logger.Info(msg);

                    // lets save to the database and assume it will work
                    AniDB_VoteRepository repVotes = new AniDB_VoteRepository();
                    List <AniDB_Vote>    dbVotes  = repVotes.GetByEntity(anime.AnimeID);
                    AniDB_Vote           thisVote = null;
                    foreach (AniDB_Vote dbVote in dbVotes)
                    {
                        // we can only have anime permanent or anime temp but not both
                        if (vt == (int)enAniDBVoteType.Anime || vt == (int)enAniDBVoteType.AnimeTemp)
                        {
                            if (dbVote.VoteType == (int)enAniDBVoteType.Anime ||
                                dbVote.VoteType == (int)enAniDBVoteType.AnimeTemp)
                            {
                                thisVote = dbVote;
                            }
                        }
                        else
                        {
                            thisVote = dbVote;
                        }
                    }

                    if (thisVote == null)
                    {
                        thisVote          = new AniDB_Vote();
                        thisVote.EntityID = anime.AnimeID;
                    }
                    thisVote.VoteType = vt;

                    int iVoteValue = 0;
                    if (vvalue > 0)
                    {
                        iVoteValue = (int)(vvalue * 100);
                    }
                    else
                    {
                        iVoteValue = (int)vvalue;
                    }

                    msg = string.Format("Voting for anime Formatted: {0} - Value: {1}", anime.AnimeID, iVoteValue);
                    logger.Info(msg);
                    thisVote.VoteValue = iVoteValue;
                    repVotes.Save(thisVote);
                    CommandRequest_VoteAnime cmdVote = new CommandRequest_VoteAnime(anime.AnimeID, vt, Convert.ToDecimal(vvalue));
                    cmdVote.Save();
                }
                rsp.code = 200;
                return(KodiHelper.GetStreamFromXmlObject(rsp));
            }
        }
Beispiel #15
0
        public List <AnimeEpisode> GetAnimeEpisodes(ISession session)
        {
            AnimeEpisodeRepository repEps = new AnimeEpisodeRepository();

            return(repEps.GetByHash(session, Hash));
        }
        private System.IO.Stream GetItemsFromPlaylist(int userid, string id, HistoryInfo info)
        {
            var PlaylistID = -1;

            int.TryParse(id, out PlaylistID);
            var playlistRepository = new PlaylistRepository();
            var repo = new AnimeEpisodeRepository();

            if (PlaylistID == 0)
            {
                using (var session = JMMService.SessionFactory.OpenSession())
                {
                    var ret = new PlexObject(PlexHelper.NewMediaContainer(MediaContainerTypes.Show, info, false));
                    if (!ret.Init())
                    {
                        return(new MemoryStream());
                    }
                    var retPlaylists = new List <Video>();
                    var playlists    = playlistRepository.GetAll();
                    foreach (var playlist in playlists)
                    {
                        var dir = new Directory();
                        dir.Key   = PlexHelper.ConstructPlaylistIdUrl(userid, playlist.PlaylistID);
                        dir.Title = playlist.PlaylistName;
                        var episodeID = -1;
                        if (int.TryParse(playlist.PlaylistItems.Split('|')[0].Split(';')[1], out episodeID))
                        {
                            var anime = repo.GetByID(session, episodeID).GetAnimeSeries(session).GetAnime(session);
                            dir.Thumb = anime.GetDefaultPosterDetailsNoBlanks(session).GenPoster();
                            dir.Art   = anime.GetDefaultFanartDetailsNoBlanks(session).GenArt();
                        }
                        else
                        {
                            dir.Thumb = PlexHelper.ConstructSupportImageLink("plex_404V.png");
                        }
                        dir.LeafCount       = playlist.PlaylistItems.Split('|').Count().ToString();
                        dir.ViewedLeafCount = "0";
                        retPlaylists.Add(dir, info);
                    }
                    retPlaylists  = retPlaylists.OrderBy(a => a.Title).ToList();
                    ret.Childrens = retPlaylists;
                    return(ret.GetStream());
                }
            }
            if (PlaylistID > 0)
            {
                //iOS Hack, since it uses the previous thumb, as overlay image on the episodes
                bool iosHack = false;
                if (WebOperationContext.Current != null && WebOperationContext.Current.IncomingRequest.Headers.AllKeys.Contains("X-Plex-Product"))
                {
                    string kh = WebOperationContext.Current.IncomingRequest.Headers.Get("X-Plex-Product").ToUpper();
                    if (kh.Contains(" IOS"))
                    {
                        iosHack = true;
                    }
                }

                var playlist      = playlistRepository.GetByID(PlaylistID);
                var playlistItems = playlist.PlaylistItems.Split('|');
                var vids          = new List <Video>();
                var ret           = new PlexObject(PlexHelper.NewMediaContainer(MediaContainerTypes.Episode, info, true));
                if (!ret.Init())
                {
                    return(new MemoryStream());
                }
                using (var session = JMMService.SessionFactory.OpenSession())
                {
                    foreach (var item in playlistItems)
                    {
                        var episodeID = -1;
                        int.TryParse(item.Split(';')[1], out episodeID);
                        if (episodeID < 0)
                        {
                            return(new MemoryStream());
                        }
                        var ep     = repo.GetByID(session, episodeID);
                        var v      = new Video();
                        var locals = ep.GetVideoLocals(session);
                        if ((locals == null) || (locals.Count == 0))
                        {
                            continue;
                        }
                        var current = locals[0];
                        try
                        {
                            PlexHelper.PopulateVideo(v, current, JMMType.File, userid);
                            if (!string.IsNullOrEmpty(v.Duration))
                            {
                                vids.Add(v, info);
                                if (iosHack)
                                {
                                    v.Art   = v.Thumb;
                                    v.Thumb = ret.MediaContainer.ParentThumb;
                                }
                            }
                        }
                        catch (Exception e)
                        {
                            //Fast fix if file do not exist, and still is in db. (Xml Serialization of video info will fail on null)
                        }
                    }
                    ret.Childrens = vids;
                    return(ret.GetStream());
                }
            }
            return(new MemoryStream());
        }
Beispiel #17
0
        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);
            }
        }