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