예제 #1
0
        public override void Run(IProgress <ICommand> progress = null)
        {
            logger.Info($"Processing CommandRequest_AddFileToMyList: {VideoLocal.Info} - {VideoLocal?.Hash} - {ReadStates}");
            try
            {
                ReportInit(progress);
                if (VideoLocal == null)
                {
                    ReportError(progress, "Videlocal not found");
                    return;
                }

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

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

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

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

                if (isManualLink)
                {
                    foreach (var xref in xrefs)
                    {
                        (lid, newWatchedDate) = ShokoService.AnidbProcessor.AddFileToMyList(xref.AnimeID, xref.GetEpisode().EpisodeNumber, originalWatchedDate, ref state);
                    }
                }
                else
                {
                    (lid, newWatchedDate) = ShokoService.AnidbProcessor.AddFileToMyList(VideoLocal, originalWatchedDate, ref state);
                }
                ReportUpdate(progress, 15);
                // never true for Manual Links, so no worries about the loop overwriting it
                if (lid != null && lid.Value > 0)
                {
                    using (var upd = Repo.Instance.VideoLocal.BeginAddOrUpdate(VideoLocal)) //TODO: Test if this will work{
                    {
                        upd.Entity.MyListID = lid.Value;
                        VideoLocal          = upd.Commit();
                    }
                }

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

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

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

                    ReportUpdate(progress, 45);

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

                    ReportUpdate(progress, 60);
                }

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

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

                // lets also try adding to the users trakt collecion
                if (ServerSettings.Instance.TraktTv.Enabled && !string.IsNullOrEmpty(ServerSettings.Instance.TraktTv.AuthToken))
                {
                    Queue.Instance.AddRange(VideoLocal.GetAnimeEpisodes().Select(aep => new CmdTraktCollectionEpisode(aep.AnimeEpisodeID, TraktSyncAction.Add)));
                }
                ReportFinish(progress);
            }
            catch (Exception ex)
            {
                ReportError(progress, $"Error processing Command AniDB.AddFileToMyList: {VideoLocal?.Hash} - {ex}", ex);
            }
        }
        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        = xref.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.QueueUpdateStats();
                //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();
            }
        }
        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;
            }
        }
예제 #4
0
        private VideoLocal_Place ProcessFile_LocalInfo()
        {
            // hash and read media info for file
            int    nshareID = -1;
            string filePath = "";


            Tuple <ImportFolder, string> tup = VideoLocal_PlaceRepository.GetFromFullPath(FileName);

            if (tup == null)
            {
                logger.Error($"Unable to locate file {FileName} inside the import folders");
                return(null);
            }
            ImportFolder folder = tup.Item1;

            filePath = tup.Item2;
            IFileSystem f = tup.Item1.FileSystem;

            if (f == null)
            {
                logger.Error("Unable to open filesystem for : {0}", FileName);
                return(null);
            }
            long filesize = 0;

            if (folder.CloudID == null) // Local Access
            {
                if (!File.Exists(FileName))
                {
                    logger.Error("File does not exist: {0}", FileName);
                    return(null);
                }

                int numAttempts = 0;

                // Wait 3 minutes seconds before giving up on trying to access the file
                while ((filesize = CanAccessFile(FileName)) == 0 && (numAttempts < 180))
                {
                    numAttempts++;
                    Thread.Sleep(1000);
                    Console.WriteLine("Attempt # " + numAttempts.ToString());
                }

                // if we failed to access the file, get ouuta here
                if (numAttempts == 180)
                {
                    logger.Error("Could not access file: " + FileName);
                    return(null);
                }
            }


            FileSystemResult <IObject> source = f.Resolve(FileName);

            if (source == null || !source.IsOk || (!(source.Result is IFile)))
            {
                logger.Error("Could not access file: " + FileName);
                return(null);
            }
            IFile source_file = (IFile)source.Result;

            if (folder.CloudID.HasValue)
            {
                filesize = source_file.Size;
            }
            nshareID = folder.ImportFolderID;
            // check if we have already processed this file


            VideoLocal_Place vlocalplace = RepoFactory.VideoLocalPlace.GetByFilePathAndShareID(filePath, nshareID);
            VideoLocal       vlocal;

            if (vlocalplace != null)
            {
                vlocal = vlocalplace.VideoLocal;
                logger.Trace("VideoLocal record found in database: {0}", vlocal.VideoLocalID);

                if (ForceHash)
                {
                    vlocal.FileSize        = filesize;
                    vlocal.DateTimeUpdated = DateTime.Now;
                }
            }
            else
            {
                logger.Trace("VideoLocal, creating new record");
                vlocal = new VideoLocal();
                vlocal.DateTimeUpdated       = DateTime.Now;
                vlocal.DateTimeCreated       = vlocal.DateTimeUpdated;
                vlocal.FileName              = Path.GetFileName(filePath);
                vlocal.FileSize              = filesize;
                vlocal.Hash                  = string.Empty;
                vlocal.CRC32                 = string.Empty;
                vlocal.MD5                   = source_file.MD5.ToUpperInvariant() ?? string.Empty;
                vlocal.SHA1                  = source_file.SHA1.ToUpperInvariant() ?? string.Empty;
                vlocal.IsIgnored             = 0;
                vlocal.IsVariation           = 0;
                vlocalplace                  = new VideoLocal_Place();
                vlocalplace.FilePath         = filePath;
                vlocalplace.ImportFolderID   = nshareID;
                vlocalplace.ImportFolderType = folder.ImportFolderType;
            }

            // check if we need to get a hash this file
            Hashes hashes = null;

            if (string.IsNullOrEmpty(vlocal.Hash) || ForceHash)
            {
                // try getting the hash from the CrossRef
                if (!ForceHash)
                {
                    List <CrossRef_File_Episode> crossRefs = RepoFactory.CrossRef_File_Episode.GetByFileNameAndSize(vlocal.FileName, vlocal.FileSize);
                    if (crossRefs.Count == 1)
                    {
                        vlocal.Hash       = crossRefs[0].Hash;
                        vlocal.HashSource = (int)HashSource.DirectHash;
                    }
                }

                // try getting the hash from the LOCAL cache
                if (!ForceHash && string.IsNullOrEmpty(vlocal.Hash))
                {
                    List <FileNameHash> fnhashes = RepoFactory.FileNameHash.GetByFileNameAndSize(vlocal.FileName, vlocal.FileSize);
                    if (fnhashes != null && fnhashes.Count > 1)
                    {
                        // if we have more than one record it probably means there is some sort of corruption
                        // lets delete the local records
                        foreach (FileNameHash fnh in fnhashes)
                        {
                            RepoFactory.FileNameHash.Delete(fnh.FileNameHashID);
                        }
                    }

                    if (fnhashes != null && fnhashes.Count == 1)
                    {
                        logger.Trace("Got hash from LOCAL cache: {0} ({1})", FileName, fnhashes[0].Hash);
                        vlocal.Hash       = fnhashes[0].Hash;
                        vlocal.HashSource = (int)HashSource.WebCacheFileName;
                    }
                }
                if (string.IsNullOrEmpty(vlocal.Hash))
                {
                    FillVideoHashes(vlocal);
                }
                if (string.IsNullOrEmpty(vlocal.Hash) && folder.CloudID.HasValue)
                {
                    //Cloud and no hash, Nothing to do, except maybe Get the mediainfo....

                    RepoFactory.VideoLocal.Save(vlocal, false);
                    vlocalplace.VideoLocalID = vlocal.VideoLocalID;
                    RepoFactory.VideoLocalPlace.Save(vlocalplace);
                    if (vlocalplace.RefreshMediaInfo())
                    {
                        RepoFactory.VideoLocal.Save(vlocalplace.VideoLocal, true);
                    }
                    return(vlocalplace);
                }
                // hash the file
                if (string.IsNullOrEmpty(vlocal.Hash) || ForceHash)
                {
                    DateTime start = DateTime.Now;
                    logger.Trace("Calculating ED2K hashes for: {0}", FileName);
                    // update the VideoLocal record with the Hash, since cloud support we calculate everything
                    hashes = FileHashHelper.GetHashInfo(FileName.Replace("/", "\\"), true, MainWindow.OnHashProgress, false, false, false);
                    TimeSpan ts = DateTime.Now - start;
                    logger.Trace("Hashed file in {0} seconds --- {1} ({2})", ts.TotalSeconds.ToString("#0.0"), FileName, Utils.FormatByteSize(vlocal.FileSize));
                    vlocal.Hash       = hashes.ed2k?.ToUpperInvariant();
                    vlocal.CRC32      = hashes.crc32?.ToUpperInvariant();
                    vlocal.MD5        = hashes.md5?.ToUpperInvariant();
                    vlocal.SHA1       = hashes.sha1?.ToUpperInvariant();
                    vlocal.HashSource = (int)HashSource.DirectHash;
                    FillVideoHashes(vlocal);
                    bool needcrc32 = string.IsNullOrEmpty(vlocal.CRC32);
                    bool needmd5   = string.IsNullOrEmpty(vlocal.MD5);
                    bool needsha1  = string.IsNullOrEmpty(vlocal.SHA1);
                    if (needcrc32 || needmd5 || needsha1)
                    {
                        List <string> tp = new List <string>();
                        if (needsha1)
                        {
                            tp.Add("SHA1");
                        }
                        if (needmd5)
                        {
                            tp.Add("MD5");
                        }
                        if (needcrc32)
                        {
                            tp.Add("CRC32");
                        }
                        logger.Trace("Calculating missing {1} hashes for: {0}", FileName, string.Join(",", tp));
                        // update the VideoLocal record with the Hash, since cloud support we calculate everything
                        hashes = FileHashHelper.GetHashInfo(FileName.Replace("/", "\\"), true, MainWindow.OnHashProgress,
                                                            needcrc32, needmd5, needsha1);
                        ts = DateTime.Now - start;
                        logger.Trace("Hashed file in {0} seconds --- {1} ({2})", ts.TotalSeconds.ToString("#0.0"),
                                     FileName, Utils.FormatByteSize(vlocal.FileSize));
                        if (needsha1)
                        {
                            vlocal.SHA1 = hashes.sha1?.ToUpperInvariant();
                        }
                        if (needmd5)
                        {
                            vlocal.MD5 = hashes.md5?.ToUpperInvariant();
                        }
                        if (needcrc32)
                        {
                            vlocal.CRC32 = hashes.crc32?.ToUpperInvariant();
                        }
                        AzureWebAPI.Send_FileHash(new List <VideoLocal> {
                            vlocal
                        });
                    }
                }

                // We should have a hash by now
                // before we save it, lets make sure there is not any other record with this hash (possible duplicate file)

                VideoLocal tlocal = RepoFactory.VideoLocal.GetByHash(vlocal.Hash);

                bool             intercloudfolder = false;
                VideoLocal_Place prep             = tlocal?.Places.FirstOrDefault(a => a.ImportFolder.CloudID == folder.CloudID && vlocalplace.VideoLocal_Place_ID != a.VideoLocal_Place_ID);
                if (prep != null)
                {
                    // delete the VideoLocal record
                    logger.Warn("Deleting duplicate video file record");
                    logger.Warn("---------------------------------------------");
                    logger.Warn($"Keeping record for: {vlocalplace.FullServerPath}");
                    logger.Warn($"Deleting record for: {prep.FullServerPath}");
                    logger.Warn("---------------------------------------------");

                    // check if we have a record of this in the database, if not create one
                    List <DuplicateFile> dupFiles = RepoFactory.DuplicateFile.GetByFilePathsAndImportFolder(vlocalplace.FilePath,
                                                                                                            prep.FilePath,
                                                                                                            vlocalplace.ImportFolderID, prep.ImportFolderID);
                    if (dupFiles.Count == 0)
                    {
                        dupFiles = RepoFactory.DuplicateFile.GetByFilePathsAndImportFolder(prep.FilePath, vlocalplace.FilePath, prep.ImportFolderID, vlocalplace.ImportFolderID);
                    }

                    if (dupFiles.Count == 0)
                    {
                        DuplicateFile dup = new DuplicateFile();
                        dup.DateTimeUpdated     = DateTime.Now;
                        dup.FilePathFile1       = vlocalplace.FilePath;
                        dup.FilePathFile2       = prep.FilePath;
                        dup.ImportFolderIDFile1 = vlocalplace.ImportFolderID;
                        dup.ImportFolderIDFile2 = prep.ImportFolderID;
                        dup.Hash = vlocal.Hash;
                        RepoFactory.DuplicateFile.Save(dup);
                    }
                    //Notify duplicate, don't delete
                }
                else if (tlocal != null)
                {
                    vlocal           = tlocal;
                    intercloudfolder = true;
                }


                if (!intercloudfolder)
                {
                    RepoFactory.VideoLocal.Save(vlocal, true);
                }

                vlocalplace.VideoLocalID = vlocal.VideoLocalID;
                RepoFactory.VideoLocalPlace.Save(vlocalplace);

                if (intercloudfolder)
                {
                    return(vlocalplace);
                }

                // also save the filename to hash record
                // replace the existing records just in case it was corrupt
                FileNameHash        fnhash    = null;
                List <FileNameHash> fnhashes2 = RepoFactory.FileNameHash.GetByFileNameAndSize(vlocal.FileName, vlocal.FileSize);
                if (fnhashes2 != null && fnhashes2.Count > 1)
                {
                    // if we have more than one record it probably means there is some sort of corruption
                    // lets delete the local records
                    foreach (FileNameHash fnh in fnhashes2)
                    {
                        RepoFactory.FileNameHash.Delete(fnh.FileNameHashID);
                    }
                }

                if (fnhashes2 != null && fnhashes2.Count == 1)
                {
                    fnhash = fnhashes2[0];
                }
                else
                {
                    fnhash = new FileNameHash();
                }

                fnhash.FileName        = vlocal.FileName;
                fnhash.FileSize        = vlocal.FileSize;
                fnhash.Hash            = vlocal.Hash;
                fnhash.DateTimeUpdated = DateTime.Now;
                RepoFactory.FileNameHash.Save(fnhash);
            }


            if ((vlocal.Media == null) || vlocal.MediaVersion < VideoLocal.MEDIA_VERSION || vlocal.Duration == 0)
            {
                if (vlocalplace.RefreshMediaInfo())
                {
                    RepoFactory.VideoLocal.Save(vlocalplace.VideoLocal, true);
                }
            }
            // now add a command to process the file
            CommandRequest_ProcessFile cr_procfile = new CommandRequest_ProcessFile(vlocal.VideoLocalID, false);

            cr_procfile.Save();

            return(vlocalplace);
        }
예제 #5
0
 private void FillVideoHashes(VideoLocal v)
 {
     using (var session = JMMService.SessionFactory.OpenSession())
     {
         if (!string.IsNullOrEmpty(v.ED2KHash))
         {
             VideoLocal n = RepoFactory.VideoLocal.GetByHash(v.ED2KHash);
             if (n != null)
             {
                 v.CRC32 = n.CRC32.ToUpperInvariant();
                 v.MD5   = n.MD5.ToUpperInvariant();
                 v.SHA1  = n.SHA1.ToUpperInvariant();
                 return;
             }
             AniDB_File f = RepoFactory.AniDB_File.GetByHash(v.ED2KHash);
             if (f != null)
             {
                 v.CRC32 = f.CRC.ToUpperInvariant();
                 v.SHA1  = f.SHA1.ToUpperInvariant();
                 v.MD5   = f.MD5.ToUpperInvariant();
                 return;
             }
             List <FileHash> ls = AzureWebAPI.Get_FileHash(FileHashType.ED2K, v.ED2KHash);
             ls = ls.Where(a => !string.IsNullOrEmpty(a.CRC32) && !string.IsNullOrEmpty(a.MD5) && !string.IsNullOrEmpty(a.SHA1)).ToList();
             if (ls.Count > 0)
             {
                 v.SHA1  = ls[0].SHA1.ToUpperInvariant();
                 v.CRC32 = ls[0].CRC32.ToUpperInvariant();
                 v.MD5   = ls[0].MD5.ToUpperInvariant();
                 return;
             }
         }
         if (!string.IsNullOrEmpty(v.SHA1))
         {
             VideoLocal n = RepoFactory.VideoLocal.GetBySHA1(v.SHA1);
             if (n != null)
             {
                 v.CRC32    = n.CRC32.ToUpperInvariant();
                 v.MD5      = n.MD5.ToUpperInvariant();
                 v.ED2KHash = n.ED2KHash.ToUpperInvariant();
                 return;
             }
             AniDB_File f = RepoFactory.AniDB_File.GetBySHA1(v.SHA1);
             if (f != null)
             {
                 v.CRC32    = f.CRC.ToUpperInvariant();
                 v.ED2KHash = f.Hash.ToUpperInvariant();
                 v.MD5      = f.MD5.ToUpperInvariant();
                 return;
             }
             List <FileHash> ls = AzureWebAPI.Get_FileHash(FileHashType.SHA1, v.SHA1);
             ls = ls.Where(a => !string.IsNullOrEmpty(a.CRC32) && !string.IsNullOrEmpty(a.MD5) && !string.IsNullOrEmpty(a.ED2K)).ToList();
             if (ls.Count > 0)
             {
                 v.ED2KHash = ls[0].ED2K.ToUpperInvariant();
                 v.CRC32    = ls[0].CRC32.ToUpperInvariant();
                 v.MD5      = ls[0].MD5.ToUpperInvariant();
                 return;
             }
         }
         if (!string.IsNullOrEmpty(v.MD5))
         {
             VideoLocal n = RepoFactory.VideoLocal.GetByMD5(v.MD5);
             if (n != null)
             {
                 v.CRC32    = n.CRC32.ToUpperInvariant();
                 v.SHA1     = n.SHA1.ToUpperInvariant();
                 v.ED2KHash = n.ED2KHash.ToUpperInvariant();
                 return;
             }
             AniDB_File f = RepoFactory.AniDB_File.GetByMD5(v.MD5);
             if (f != null)
             {
                 v.CRC32    = f.CRC.ToUpperInvariant();
                 v.ED2KHash = f.Hash.ToUpperInvariant();
                 v.SHA1     = f.SHA1.ToUpperInvariant();
                 return;
             }
             List <FileHash> ls = AzureWebAPI.Get_FileHash(FileHashType.MD5, v.MD5);
             if (ls != null)
             {
                 ls = ls.Where(a => !string.IsNullOrEmpty(a.CRC32) && !string.IsNullOrEmpty(a.SHA1) && !string.IsNullOrEmpty(a.ED2K)).ToList();
                 if (ls.Count > 0)
                 {
                     v.ED2KHash = ls[0].ED2K.ToUpperInvariant();
                     v.CRC32    = ls[0].CRC32.ToUpperInvariant();
                     v.SHA1     = ls[0].SHA1.ToUpperInvariant();
                 }
             }
         }
     }
 }
예제 #6
0
        public override void ProcessCommand()
        {
            logger.Info("Get AniDB file info: {0}", VideoLocalID);


            try
            {
                AniDB_FileRepository repAniFile = new AniDB_FileRepository();
                VideoLocalRepository repVids    = new VideoLocalRepository();
                vlocal = repVids.GetByID(VideoLocalID);
                if (vlocal == null)
                {
                    return;
                }

                AniDB_File aniFile = repAniFile.GetByHashAndFileSize(vlocal.Hash, vlocal.FileSize);

                /*// get anidb file info from web cache
                 * if (aniFile == null && ServerSettings.WebCache_AniDB_File_Get)
                 * {
                 *      AniDB_FileRequest fr = XMLService.Get_AniDB_File(vlocal.Hash, vlocal.FileSize);
                 *      if (fr != null)
                 *      {
                 *              aniFile = new AniDB_File();
                 *              aniFile.Populate(fr);
                 *
                 *              //overwrite with local file name
                 *              string localFileName = Path.GetFileName(vlocal.FilePath);
                 *              aniFile.FileName = localFileName;
                 *
                 *              repAniFile.Save(aniFile, false);
                 *              aniFile.CreateLanguages();
                 *              aniFile.CreateCrossEpisodes(localFileName);
                 *
                 *              StatsCache.Instance.UpdateUsingAniDBFile(vlocal.Hash);
                 *      }
                 * }*/

                Raw_AniDB_File fileInfo = null;
                if (aniFile == null || ForceAniDB)
                {
                    fileInfo = JMMService.AnidbProcessor.GetFileInfo(vlocal);
                }

                if (fileInfo != null)
                {
                    // save to the database
                    if (aniFile == null)
                    {
                        aniFile = new AniDB_File();
                    }

                    aniFile.Populate(fileInfo);

                    //overwrite with local file name
                    string localFileName = Path.GetFileName(vlocal.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();
                            }
                        }
                    }

                    StatsCache.Instance.UpdateUsingAniDBFile(vlocal.Hash);
                }
            }
            catch (Exception ex)
            {
                logger.Error("Error processing CommandRequest_GetFile: {0} - {1}", VideoLocalID, ex.ToString());
                return;
            }
        }
예제 #7
0
        public override void ProcessCommand()
        {
            logger.Info("Processing CommandRequest_SyncMyList");

            try
            {
                // we will always assume that an anime was downloaded via http first



                ScheduledUpdate sched = RepoFactory.ScheduledUpdate.GetByUpdateType((int)ScheduledUpdateType.AniDBMyListSync);
                if (sched == null)
                {
                    sched               = new ScheduledUpdate();
                    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>();
                    IReadOnlyList <AniDB_File>      allAniFiles  = RepoFactory.AniDB_File.GetAll();
                    foreach (AniDB_File anifile in allAniFiles)
                    {
                        dictAniFiles[anifile.Hash] = anifile;
                    }

                    int missingFiles = 0;
                    foreach (VideoLocal vid in RepoFactory.VideoLocal.GetAll().Where(a => !string.IsNullOrEmpty(a.Hash)))
                    {
                        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));

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


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

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

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

                        string hash = string.Empty;

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


                        if (!string.IsNullOrEmpty(hash))
                        {
                            // find the video associated with this record
                            VideoLocal vl = RepoFactory.VideoLocal.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 = userRecord.WatchedDate.HasValue;
                                }

                                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 = $"MYLISTDIFF:: File {vl.FileName} - Local Status = {localStatus}, AniDB Status = {myitem.IsWatched} --- {action}";
                                    logger.Info(msg);
                                }
                            }


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


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

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

                    sched.LastUpdate = DateTime.Now;
                    RepoFactory.ScheduledUpdate.Save(sched);
                }
            }
            catch (Exception ex)
            {
                logger.Error("Error processing CommandRequest_SyncMyList: {0} ", ex.ToString());
                return;
            }
        }