private void ProcessFile_LocalInfo() { // hash and read media info for file int nshareID = -1; (SVR_ImportFolder folder, string filePath) = VideoLocal_PlaceRepository.GetFromFullPath(FileName); if (folder == null) { logger.Error($"Unable to locate Import Folder for {FileName}"); return; } IFileSystem f = folder.FileSystem; if (f == null) { logger.Error("Unable to open filesystem for: {0}", FileName); return; } long filesize = 0; if (folder.CloudID == null) // Local Access { if (!File.Exists(FileName)) { logger.Error("File does not exist: {0}", FileName); return; } int numAttempts = 0; // Wait 1 minute before giving up on trying to access the file while ((filesize = CanAccessFile(FileName)) == 0 && (numAttempts < 60)) { numAttempts++; Thread.Sleep(1000); logger.Error($@"Failed to access, (or filesize is 0) Attempt # {numAttempts}, {FileName}"); } // if we failed to access the file, get ouuta here if (numAttempts >= 60) { logger.Error("Could not access file: " + FileName); return; } //For systems with no locking while (FileModified(FileName, 3)) { Thread.Sleep(1000); logger.Error($@"An external process is modifying the file, {FileName}"); } } IObject source = f.Resolve(FileName); if (source == null || source.Status != Status.Ok || !(source is IFile source_file)) { logger.Error("Could not access file: " + FileName); return; } if (folder.CloudID.HasValue) { filesize = source_file.Size; } nshareID = folder.ImportFolderID; // check if we have already processed this file SVR_VideoLocal_Place vlocalplace = Repo.Instance.VideoLocal_Place.GetByFilePathAndImportFolderID(filePath, nshareID); SVR_VideoLocal vlocal = null; var filename = Path.GetFileName(filePath); if (vlocalplace != null) { vlocal = vlocalplace.VideoLocal; if (vlocal != null) { logger.Trace("VideoLocal record found in database: {0}", FileName); // This will only happen with DB corruption, so just clean up the mess. if (vlocalplace.FullServerPath == null) { if (vlocal.Places.Count == 1) { Repo.Instance.VideoLocal.Delete(vlocal); vlocal = null; } Repo.Instance.VideoLocal_Place.Delete(vlocalplace); vlocalplace = null; } if (vlocal != null && ForceHash) { vlocal.FileSize = filesize; vlocal.DateTimeUpdated = DateTime.Now; } } } bool duplicate = false; using (var txn = Repo.Instance.VideoLocal.BeginAddOrUpdate(() => vlocal, () => { logger.Trace("No existing VideoLocal, creating temporary record"); return(new SVR_VideoLocal { DateTimeUpdated = DateTime.Now, DateTimeCreated = DateTimeUpdated, FileName = filename, FileSize = filesize, Hash = string.Empty, CRC32 = string.Empty, MD5 = source_file?.MD5?.ToUpperInvariant() ?? string.Empty, SHA1 = source_file?.SHA1?.ToUpperInvariant() ?? string.Empty, IsIgnored = 0, IsVariation = 0 }); })) { if (vlocalplace == null) { logger.Trace("No existing VideoLocal_Place, creating a new record"); vlocalplace = new SVR_VideoLocal_Place { FilePath = filePath, ImportFolderID = nshareID, ImportFolderType = folder.ImportFolderType }; // Make sure we have an ID vlocalplace = Repo.Instance.VideoLocal_Place.BeginAdd(vlocalplace).Commit(); } using (var txn_vl = Repo.Instance.VideoLocal_Place.BeginAddOrUpdate(() => vlocalplace)) { // check if we need to get a hash this file if (string.IsNullOrEmpty(txn.Entity.Hash) || ForceHash) { logger.Trace("No existing hash in VideoLocal, checking XRefs"); if (!ForceHash) { // try getting the hash from the CrossRef List <CrossRef_File_Episode> crossRefs = Repo.Instance.CrossRef_File_Episode.GetByFileNameAndSize(filename, txn.Entity.FileSize); if (crossRefs.Any()) { txn.Entity.Hash = crossRefs[0].Hash; txn.Entity.HashSource = (int)HashSource.DirectHash; } } // try getting the hash from the LOCAL cache if (!ForceHash && string.IsNullOrEmpty(txn.Entity.Hash)) { List <FileNameHash> fnhashes = Repo.Instance.FileNameHash.GetByFileNameAndSize(filename, txn.Entity.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) { Repo.Instance.FileNameHash.Delete(fnh.FileNameHashID); } } // reinit this to check if we erased them fnhashes = Repo.Instance.FileNameHash.GetByFileNameAndSize(filename, txn.Entity.FileSize); if (fnhashes != null && fnhashes.Count == 1) { logger.Trace("Got hash from LOCAL cache: {0} ({1})", FileName, fnhashes[0].Hash); txn.Entity.Hash = fnhashes[0].Hash; txn.Entity.HashSource = (int)HashSource.WebCacheFileName; } } if (string.IsNullOrEmpty(txn.Entity.Hash)) { FillVideoHashes(txn.Entity); } //Cloud and no hash, Nothing to do, except maybe Get the mediainfo.... if (string.IsNullOrEmpty(txn.Entity.Hash) && folder.CloudID.HasValue) { logger.Trace("No Hash found for cloud " + filename + " putting in videolocal table with empty ED2K"); vlocal = txn.Commit(true); using (var upd = Repo.Instance.VideoLocal_Place.BeginAddOrUpdate(() => vlocalplace)) { upd.Entity.VideoLocalID = vlocal.VideoLocalID; vlocalplace = upd.Commit(); } if (vlocalplace.RefreshMediaInfo()) { txn_vl.Commit(true); } return; } // hash the file if (string.IsNullOrEmpty(txn.Entity.Hash) || ForceHash) { logger.Info("Hashing File: {0}", FileName); ShokoService.CmdProcessorHasher.QueueState = PrettyDescriptionHashing; DateTime start = DateTime.Now; // update the VideoLocal record with the Hash, since cloud support we calculate everything var hashes = FileHashHelper.GetHashInfo(FileName.Replace("/", $"{System.IO.Path.DirectorySeparatorChar}"), true, ShokoServer.OnHashProgress, true, true, true); TimeSpan ts = DateTime.Now - start; logger.Trace("Hashed file in {0:#0.0} seconds --- {1} ({2})", ts.TotalSeconds, FileName, Utils.FormatByteSize(txn.Entity.FileSize)); txn.Entity.Hash = hashes.ED2K?.ToUpperInvariant(); txn.Entity.CRC32 = hashes.CRC32?.ToUpperInvariant(); txn.Entity.MD5 = hashes.MD5?.ToUpperInvariant(); txn.Entity.SHA1 = hashes.SHA1?.ToUpperInvariant(); txn.Entity.HashSource = (int)HashSource.DirectHash; } FillMissingHashes(txn.Entity); // 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) SVR_VideoLocal tlocal = Repo.Instance.VideoLocal.GetByHash(txn.Entity.Hash); bool changed = false; if (tlocal != null) { logger.Trace("Found existing VideoLocal with hash, merging info from it"); // Aid with hashing cloud. Merge hashes and save, regardless of duplicate file changed = tlocal.MergeInfoFrom(txn.Entity); vlocal = tlocal; List <SVR_VideoLocal_Place> preps = vlocal.Places.Where( a => a.ImportFolder.CloudID == folder.CloudID && !vlocalplace.FullServerPath.Equals(a.FullServerPath)).ToList(); foreach (var prep in preps) { if (prep == null) { continue; } // clean up, if there is a 'duplicate file' that is invalid, remove it. if (prep.FullServerPath == null) { Repo.Instance.VideoLocal_Place.Delete(prep); } else { FileSystemResult dupFileSystemResult = (FileSystemResult)prep.ImportFolder?.FileSystem?.Resolve(prep.FullServerPath); if (dupFileSystemResult == null || dupFileSystemResult.Status != Status.Ok) { Repo.Instance.VideoLocal_Place.Delete(prep); } } } var dupPlace = txn.Entity.Places.FirstOrDefault( a => a.ImportFolder.CloudID == folder.CloudID && !vlocalplace.FullServerPath.Equals(a.FullServerPath)); if (dupPlace != null) { logger.Warn("Found Duplicate File"); logger.Warn("---------------------------------------------"); logger.Warn($"New File: {vlocalplace.FullServerPath}"); logger.Warn($"Existing File: {dupPlace.FullServerPath}"); logger.Warn("---------------------------------------------"); // check if we have a record of this in the database, if not create one List <DuplicateFile> dupFiles = Repo.Instance.DuplicateFile.GetByFilePathsAndImportFolder( vlocalplace.FilePath, dupPlace.FilePath, vlocalplace.ImportFolderID, dupPlace.ImportFolderID); if (dupFiles.Count == 0) { dupFiles = Repo.Instance.DuplicateFile.GetByFilePathsAndImportFolder(dupPlace.FilePath, vlocalplace.FilePath, dupPlace.ImportFolderID, vlocalplace.ImportFolderID); } if (dupFiles.Count == 0) { DuplicateFile dup = new DuplicateFile { DateTimeUpdated = DateTime.Now, FilePathFile1 = vlocalplace.FilePath, FilePathFile2 = dupPlace.FilePath, ImportFolderIDFile1 = vlocalplace.ImportFolderID, ImportFolderIDFile2 = dupPlace.ImportFolderID, Hash = txn.Entity.Hash }; Repo.Instance.DuplicateFile.BeginAdd(dup).Commit(); } //Notify duplicate, don't delete duplicate = true; } } if (!duplicate || changed) { vlocal = txn.Commit(); } } } using (var upd = Repo.Instance.VideoLocal_Place.BeginAddOrUpdate(() => vlocalplace)) { upd.Entity.VideoLocalID = vlocal.VideoLocalID; upd.Commit(); } } if (duplicate) { CommandRequest_ProcessFile cr_procfile3 = new CommandRequest_ProcessFile(vlocal.VideoLocalID, false); cr_procfile3.Save(); return; } // also save the filename to hash record // replace the existing records just in case it was corrupt List <FileNameHash> fnhashes2 = Repo.Instance.FileNameHash.GetByFileNameAndSize(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) { Repo.Instance.FileNameHash.Delete(fnh.FileNameHashID); } } using (var upd = Repo.Instance.FileNameHash.BeginAddOrUpdate(() => fnhashes2?.Count == 1 ? fnhashes2[0] : null)) { upd.Entity.FileName = filename; upd.Entity.FileSize = vlocal.FileSize; upd.Entity.Hash = vlocal.Hash; upd.Entity.DateTimeUpdated = DateTime.Now; upd.Commit(); } if ((vlocal.Media == null) || vlocal.MediaVersion < SVR_VideoLocal.MEDIA_VERSION || vlocal.Duration == 0) { if (vlocalplace.RefreshMediaInfo()) { using (var upd = Repo.Instance.VideoLocal.BeginAddOrUpdate(() => vlocalplace.VideoLocal)) upd.Commit(true); } } // now add a command to process the file CommandRequest_ProcessFile cr_procfile = new CommandRequest_ProcessFile(vlocal.VideoLocalID, false); cr_procfile.Save(); }
private SVR_VideoLocal_Place ProcessFile_LocalInfo() { // hash and read media info for file int nshareID = -1; string filePath = ""; Tuple <SVR_ImportFolder, string> tup = VideoLocal_PlaceRepository.GetFromFullPath(FileName); if (tup == null) { logger.Error($"Unable to locate Import Folder for {FileName}"); return(null); } SVR_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 SVR_VideoLocal_Place vlocalplace = RepoFactory.VideoLocalPlace.GetByFilePathAndShareID(filePath, nshareID); SVR_VideoLocal vlocal = null; if (vlocalplace != null) { vlocal = vlocalplace.VideoLocal; logger.Trace("VideoLocal record found in database: {0}", vlocal.VideoLocalID); if (vlocalplace.FullServerPath == null) { if (vlocal.Places.Count == 1) { RepoFactory.VideoLocal.Delete(vlocal); } RepoFactory.VideoLocalPlace.Delete(vlocalplace); vlocalplace = null; vlocal = null; } else if (ForceHash) { vlocal.FileSize = filesize; vlocal.DateTimeUpdated = DateTime.Now; } } if (vlocalplace == null) { logger.Trace("VideoLocal, creating temporary record"); vlocal = new SVR_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 SVR_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); } } // reinit this to check if we erased them fnhashes = RepoFactory.FileNameHash.GetByFileNameAndSize(vlocal.FileName, vlocal.FileSize); 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.... logger.Trace("No Hash found for cloud " + vlocal.FileName + " putting in videolocal table with empty ED2K"); 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) { logger.Info("Hashing File: {0}", FileName); ShokoService.CmdProcessorHasher.QueueState = PrettyDescriptionHashing; 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, ShokoServer.OnHashProgress, true, true, true); 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; } FillMissingHashes(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) SVR_VideoLocal tlocal = RepoFactory.VideoLocal.GetByHash(vlocal.Hash); bool duplicate = false; bool changed = false; if (tlocal != null) { // Aid with hashing cloud. Merge hashes and save, regardless of duplicate file changed = tlocal.MergeInfoFrom(vlocal); vlocal = tlocal; SVR_VideoLocal_Place prep = tlocal.Places.FirstOrDefault( a => a.ImportFolder.CloudID == folder.CloudID && a.ImportFolderID == folder.ImportFolderID && vlocalplace.VideoLocal_Place_ID != a.VideoLocal_Place_ID); // clean up, if there is a 'duplicate file' that is invalid, remove it. if (prep != null && prep.FullServerPath == null) { if (tlocal.Places.Count == 1) { RepoFactory.VideoLocal.Delete(tlocal); } RepoFactory.VideoLocalPlace.Delete(prep); prep = null; } 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("Found Duplicate File"); logger.Warn("---------------------------------------------"); logger.Warn($"New File: {vlocalplace.FullServerPath}"); logger.Warn($"Existing File: {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 duplicate = true; } } if (!duplicate || changed) { RepoFactory.VideoLocal.Save(vlocal, true); } vlocalplace.VideoLocalID = vlocal.VideoLocalID; RepoFactory.VideoLocalPlace.Save(vlocalplace); if (duplicate) { CommandRequest_ProcessFile cr_procfile3 = new CommandRequest_ProcessFile(vlocal.VideoLocalID, false); cr_procfile3.Save(); 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); } else { FillMissingHashes(vlocal); } if ((vlocal.Media == null) || vlocal.MediaVersion < SVR_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); }
// List of Default priorities for commands // Pri 1 //------ // Reserved for commands user manually initiates from UI //------ // Pri 2 //------ // CommandRequest_GetAnimeHTTP //------ // Pri 3 //------ // CommandRequest_ProcessFile // CommandRequest_GetFile //------ // Pri 4 //------ // CommandRequest_GetUpdated // CommandRequest_ReadMediaInfo // CommandRequest_GetEpsode //------ // Pri 5 //------ // CommandRequest_GetReleaseGroupStatus //------ // Pri 6 //------ // CommandRequest_SyncMyList // CommandRequest_SyncMyVotes //------ // Pri 7 //------ // CommandRequest_GetCalendar //------ // Pri 8 //------ // CommandRequest_UpdateMyListFileStatus // CommandRequest_GetCharactersCreators // CommandRequest_TraktSyncCollection // CommandRequest_TvDBUpdateSeriesAndEpisodes // CommandRequest_TvDBDownloadImages // CommandRequest_TvDBSearchAnime // CommandRequest_MovieDBSearchAnime // CommandRequest_TraktSearchAnime // CommandRequest_MALSearchAnime // CommandRequest_LinkFileManually //------ // Pri 9 //------ // CommandRequest_WebCacheSendFileHash // CommandRequest_GetReviews // CommandRequest_GetReleaseGroup // CommandRequest_WebCacheSendXRefFileEpisode // CommandRequest_WebCacheDeleteXRefFileEpisode // CommandRequest_AddFileToMyList // CommandRequest_DeleteFileFromMyList // CommandRequest_VoteAnime // CommandRequest_WebCacheDeleteXRefAniDBTvDB // CommandRequest_WebCacheDeleteXRefAniDBTvDBAll // CommandRequest_WebCacheSendXRefAniDBTvDB // CommandRequest_WebCacheSendXRefAniDBOther // CommandRequest_WebCacheDeleteXRefAniDBOther // CommandRequest_WebCacheDeleteXRefAniDBTrakt // CommandRequest_WebCacheSendXRefAniDBTrakt // CommandRequest_TraktUpdateInfoAndImages // CommandRequest_TraktSyncCollectionSeries // CommandRequest_TraktShowEpisodeUnseen // CommandRequest_DownloadImage // CommandRequest_TraktUpdateAllSeries // CommandRequest_MALUpdatedWatchedStatus // CommandRequest_MALUploadStatusToMAL // CommandRequest_MALDownloadStatusFromMAL // CommandRequest_WebCacheSendAniDB_File // CommandRequest_Azure_SendAnimeFull //------ // Pri 10 //------ // CommandRequest_UpdateMylistStats // CommandRequest_Azure_SendAnimeXML //------ // Pri 11 //------ // CommandRequest_Azure_SendAnimeTitle public static ICommandRequest GetCommand(CommandRequest crdb) { CommandRequestType crt = (CommandRequestType)crdb.CommandType; switch (crt) { case CommandRequestType.Trakt_SyncCollectionSeries: CommandRequest_TraktSyncCollectionSeries cr_CommandRequest_TraktSyncCollectionSeries = new CommandRequest_TraktSyncCollectionSeries(); cr_CommandRequest_TraktSyncCollectionSeries.LoadFromDBCommand(crdb); return((ICommandRequest)cr_CommandRequest_TraktSyncCollectionSeries); case CommandRequestType.AniDB_GetEpisodeUDP: CommandRequest_GetEpisode cr_CommandRequest_GetEpisode = new CommandRequest_GetEpisode(); cr_CommandRequest_GetEpisode.LoadFromDBCommand(crdb); return((ICommandRequest)cr_CommandRequest_GetEpisode); case CommandRequestType.Azure_SendAnimeTitle: CommandRequest_Azure_SendAnimeTitle cr_CommandRequest_Azure_SendAnimeTitle = new CommandRequest_Azure_SendAnimeTitle(); cr_CommandRequest_Azure_SendAnimeTitle.LoadFromDBCommand(crdb); return((ICommandRequest)cr_CommandRequest_Azure_SendAnimeTitle); case CommandRequestType.AniDB_GetTitles: CommandRequest_GetAniDBTitles cr_CommandRequest_GetAniDBTitles = new CommandRequest_GetAniDBTitles(); cr_CommandRequest_GetAniDBTitles.LoadFromDBCommand(crdb); return((ICommandRequest)cr_CommandRequest_GetAniDBTitles); case CommandRequestType.Azure_SendAnimeXML: CommandRequest_Azure_SendAnimeXML cr_CommandRequest_Azure_SendAnimeXML = new CommandRequest_Azure_SendAnimeXML(); cr_CommandRequest_Azure_SendAnimeXML.LoadFromDBCommand(crdb); return((ICommandRequest)cr_CommandRequest_Azure_SendAnimeXML); case CommandRequestType.Azure_SendAnimeFull: CommandRequest_Azure_SendAnimeFull cr_CommandRequest_Azure_SendAnimeFull = new CommandRequest_Azure_SendAnimeFull(); cr_CommandRequest_Azure_SendAnimeFull.LoadFromDBCommand(crdb); return((ICommandRequest)cr_CommandRequest_Azure_SendAnimeFull); case CommandRequestType.Azure_SendUserInfo: CommandRequest_Azure_SendUserInfo cr_CommandRequest_Azure_SendUserInfo = new CommandRequest_Azure_SendUserInfo(); cr_CommandRequest_Azure_SendUserInfo.LoadFromDBCommand(crdb); return((ICommandRequest)cr_CommandRequest_Azure_SendUserInfo); case CommandRequestType.AniDB_UpdateMylistStats: CommandRequest_UpdateMylistStats cr_AniDB_UpdateMylistStats = new CommandRequest_UpdateMylistStats(); cr_AniDB_UpdateMylistStats.LoadFromDBCommand(crdb); return((ICommandRequest)cr_AniDB_UpdateMylistStats); case CommandRequestType.MAL_DownloadWatchedStates: CommandRequest_MALDownloadStatusFromMAL cr_MAL_DownloadWatchedStates = new CommandRequest_MALDownloadStatusFromMAL(); cr_MAL_DownloadWatchedStates.LoadFromDBCommand(crdb); return((ICommandRequest)cr_MAL_DownloadWatchedStates); case CommandRequestType.MAL_UploadWatchedStates: CommandRequest_MALUploadStatusToMAL cr_MAL_UploadWatchedStates = new CommandRequest_MALUploadStatusToMAL(); cr_MAL_UploadWatchedStates.LoadFromDBCommand(crdb); return((ICommandRequest)cr_MAL_UploadWatchedStates); case CommandRequestType.MAL_UpdateStatus: CommandRequest_MALUpdatedWatchedStatus cr_MAL_UpdateStatus = new CommandRequest_MALUpdatedWatchedStatus(); cr_MAL_UpdateStatus.LoadFromDBCommand(crdb); return((ICommandRequest)cr_MAL_UpdateStatus); case CommandRequestType.MAL_SearchAnime: CommandRequest_MALSearchAnime cr_MAL_SearchAnime = new CommandRequest_MALSearchAnime(); cr_MAL_SearchAnime.LoadFromDBCommand(crdb); return((ICommandRequest)cr_MAL_SearchAnime); case CommandRequestType.WebCache_SendXRefAniDBMAL: CommandRequest_WebCacheSendXRefAniDBMAL cr_WebCacheSendXRefAniDBMAL = new CommandRequest_WebCacheSendXRefAniDBMAL(); cr_WebCacheSendXRefAniDBMAL.LoadFromDBCommand(crdb); return((ICommandRequest)cr_WebCacheSendXRefAniDBMAL); case CommandRequestType.WebCache_DeleteXRefAniDBMAL: CommandRequest_WebCacheDeleteXRefAniDBMAL cr_WebCacheDeleteXRefAniDBMAL = new CommandRequest_WebCacheDeleteXRefAniDBMAL(); cr_WebCacheDeleteXRefAniDBMAL.LoadFromDBCommand(crdb); return((ICommandRequest)cr_WebCacheDeleteXRefAniDBMAL); case CommandRequestType.AniDB_GetFileUDP: CommandRequest_GetFile cr_AniDB_GetFileUDP = new CommandRequest_GetFile(); cr_AniDB_GetFileUDP.LoadFromDBCommand(crdb); return((ICommandRequest)cr_AniDB_GetFileUDP); case CommandRequestType.ReadMediaInfo: CommandRequest_ReadMediaInfo cr_ReadMediaInfo = new CommandRequest_ReadMediaInfo(); cr_ReadMediaInfo.LoadFromDBCommand(crdb); return((ICommandRequest)cr_ReadMediaInfo); case CommandRequestType.Trakt_UpdateAllSeries: CommandRequest_TraktUpdateAllSeries cr_Trakt_UpdateAllSeries = new CommandRequest_TraktUpdateAllSeries(); cr_Trakt_UpdateAllSeries.LoadFromDBCommand(crdb); return((ICommandRequest)cr_Trakt_UpdateAllSeries); case CommandRequestType.Trakt_EpisodeCollection: CommandRequest_TraktCollectionEpisode cr_TraktCollectionEpisode = new CommandRequest_TraktCollectionEpisode(); cr_TraktCollectionEpisode.LoadFromDBCommand(crdb); return((ICommandRequest)cr_TraktCollectionEpisode); case CommandRequestType.Trakt_SyncCollection: CommandRequest_TraktSyncCollection cr_Trakt_SyncCollection = new CommandRequest_TraktSyncCollection(); cr_Trakt_SyncCollection.LoadFromDBCommand(crdb); return((ICommandRequest)cr_Trakt_SyncCollection); case CommandRequestType.Trakt_EpisodeHistory: CommandRequest_TraktHistoryEpisode cr_Trakt_EpisodeHistory = new CommandRequest_TraktHistoryEpisode(); cr_Trakt_EpisodeHistory.LoadFromDBCommand(crdb); return((ICommandRequest)cr_Trakt_EpisodeHistory); case CommandRequestType.Trakt_UpdateInfoImages: CommandRequest_TraktUpdateInfoAndImages cr_Trakt_UpdateInfoImages = new CommandRequest_TraktUpdateInfoAndImages(); cr_Trakt_UpdateInfoImages.LoadFromDBCommand(crdb); return((ICommandRequest)cr_Trakt_UpdateInfoImages); case CommandRequestType.WebCache_SendXRefAniDBTrakt: CommandRequest_WebCacheSendXRefAniDBTrakt cr_WebCache_SendXRefAniDBTrakt = new CommandRequest_WebCacheSendXRefAniDBTrakt(); cr_WebCache_SendXRefAniDBTrakt.LoadFromDBCommand(crdb); return((ICommandRequest)cr_WebCache_SendXRefAniDBTrakt); case CommandRequestType.WebCache_DeleteXRefAniDBTrakt: CommandRequest_WebCacheDeleteXRefAniDBTrakt cr_WebCache_DeleteXRefAniDBTrakt = new CommandRequest_WebCacheDeleteXRefAniDBTrakt(); cr_WebCache_DeleteXRefAniDBTrakt.LoadFromDBCommand(crdb); return((ICommandRequest)cr_WebCache_DeleteXRefAniDBTrakt); case CommandRequestType.Trakt_SearchAnime: CommandRequest_TraktSearchAnime cr_Trakt_SearchAnime = new CommandRequest_TraktSearchAnime(); cr_Trakt_SearchAnime.LoadFromDBCommand(crdb); return((ICommandRequest)cr_Trakt_SearchAnime); case CommandRequestType.MovieDB_SearchAnime: CommandRequest_MovieDBSearchAnime cr_MovieDB_SearchAnime = new CommandRequest_MovieDBSearchAnime(); cr_MovieDB_SearchAnime.LoadFromDBCommand(crdb); return((ICommandRequest)cr_MovieDB_SearchAnime); case CommandRequestType.WebCache_DeleteXRefAniDBOther: CommandRequest_WebCacheDeleteXRefAniDBOther cr_SendXRefAniDBOther = new CommandRequest_WebCacheDeleteXRefAniDBOther(); cr_SendXRefAniDBOther.LoadFromDBCommand(crdb); return((ICommandRequest)cr_SendXRefAniDBOther); case CommandRequestType.WebCache_SendXRefAniDBOther: CommandRequest_WebCacheSendXRefAniDBOther cr_WebCacheSendXRefAniDBOther = new CommandRequest_WebCacheSendXRefAniDBOther(); cr_WebCacheSendXRefAniDBOther.LoadFromDBCommand(crdb); return((ICommandRequest)cr_WebCacheSendXRefAniDBOther); case CommandRequestType.AniDB_DeleteFileUDP: CommandRequest_DeleteFileFromMyList cr_AniDB_DeleteFileUDP = new CommandRequest_DeleteFileFromMyList(); cr_AniDB_DeleteFileUDP.LoadFromDBCommand(crdb); return((ICommandRequest)cr_AniDB_DeleteFileUDP); case CommandRequestType.ImageDownload: CommandRequest_DownloadImage cr_ImageDownload = new CommandRequest_DownloadImage(); cr_ImageDownload.LoadFromDBCommand(crdb); return((ICommandRequest)cr_ImageDownload); case CommandRequestType.WebCache_DeleteXRefAniDBTvDB: CommandRequest_WebCacheDeleteXRefAniDBTvDB cr_DeleteXRefAniDBTvDB = new CommandRequest_WebCacheDeleteXRefAniDBTvDB(); cr_DeleteXRefAniDBTvDB.LoadFromDBCommand(crdb); return((ICommandRequest)cr_DeleteXRefAniDBTvDB); case CommandRequestType.WebCache_SendXRefAniDBTvDB: CommandRequest_WebCacheSendXRefAniDBTvDB cr_SendXRefAniDBTvDB = new CommandRequest_WebCacheSendXRefAniDBTvDB(); cr_SendXRefAniDBTvDB.LoadFromDBCommand(crdb); return((ICommandRequest)cr_SendXRefAniDBTvDB); case CommandRequestType.TvDB_SearchAnime: CommandRequest_TvDBSearchAnime cr_TvDB_SearchAnime = new CommandRequest_TvDBSearchAnime(); cr_TvDB_SearchAnime.LoadFromDBCommand(crdb); return((ICommandRequest)cr_TvDB_SearchAnime); case CommandRequestType.TvDB_DownloadImages: CommandRequest_TvDBDownloadImages cr_TvDB_DownloadImages = new CommandRequest_TvDBDownloadImages(); cr_TvDB_DownloadImages.LoadFromDBCommand(crdb); return((ICommandRequest)cr_TvDB_DownloadImages); case CommandRequestType.TvDB_SeriesEpisodes: CommandRequest_TvDBUpdateSeriesAndEpisodes cr_TvDB_Episodes = new CommandRequest_TvDBUpdateSeriesAndEpisodes(); cr_TvDB_Episodes.LoadFromDBCommand(crdb); return((ICommandRequest)cr_TvDB_Episodes); case CommandRequestType.AniDB_SyncVotes: CommandRequest_SyncMyVotes cr_SyncVotes = new CommandRequest_SyncMyVotes(); cr_SyncVotes.LoadFromDBCommand(crdb); return((ICommandRequest)cr_SyncVotes); case CommandRequestType.AniDB_VoteAnime: CommandRequest_VoteAnime cr_VoteAnime = new CommandRequest_VoteAnime(); cr_VoteAnime.LoadFromDBCommand(crdb); return((ICommandRequest)cr_VoteAnime); case CommandRequestType.AniDB_GetCalendar: CommandRequest_GetCalendar cr_GetCalendar = new CommandRequest_GetCalendar(); cr_GetCalendar.LoadFromDBCommand(crdb); return((ICommandRequest)cr_GetCalendar); case CommandRequestType.AniDB_GetReleaseGroup: CommandRequest_GetReleaseGroup cr_GetReleaseGroup = new CommandRequest_GetReleaseGroup(); cr_GetReleaseGroup.LoadFromDBCommand(crdb); return((ICommandRequest)cr_GetReleaseGroup); case CommandRequestType.AniDB_GetAnimeHTTP: CommandRequest_GetAnimeHTTP cr_geth = new CommandRequest_GetAnimeHTTP(); cr_geth.LoadFromDBCommand(crdb); return((ICommandRequest)cr_geth); case CommandRequestType.AniDB_GetReleaseGroupStatus: CommandRequest_GetReleaseGroupStatus cr_GetReleaseGroupStatus = new CommandRequest_GetReleaseGroupStatus(); cr_GetReleaseGroupStatus.LoadFromDBCommand(crdb); return((ICommandRequest)cr_GetReleaseGroupStatus); case CommandRequestType.HashFile: CommandRequest_HashFile cr_HashFile = new CommandRequest_HashFile(); cr_HashFile.LoadFromDBCommand(crdb); return((ICommandRequest)cr_HashFile); case CommandRequestType.ProcessFile: CommandRequest_ProcessFile cr_pf = new CommandRequest_ProcessFile(); cr_pf.LoadFromDBCommand(crdb); return((ICommandRequest)cr_pf); case CommandRequestType.AniDB_AddFileUDP: CommandRequest_AddFileToMyList cr_af = new CommandRequest_AddFileToMyList(); cr_af.LoadFromDBCommand(crdb); return((ICommandRequest)cr_af); case CommandRequestType.AniDB_UpdateWatchedUDP: CommandRequest_UpdateMyListFileStatus cr_umlf = new CommandRequest_UpdateMyListFileStatus(); cr_umlf.LoadFromDBCommand(crdb); return((ICommandRequest)cr_umlf); case CommandRequestType.WebCache_DeleteXRefFileEpisode: CommandRequest_WebCacheDeleteXRefFileEpisode cr_DeleteXRefFileEpisode = new CommandRequest_WebCacheDeleteXRefFileEpisode(); cr_DeleteXRefFileEpisode.LoadFromDBCommand(crdb); return((ICommandRequest)cr_DeleteXRefFileEpisode); case CommandRequestType.WebCache_SendXRefFileEpisode: CommandRequest_WebCacheSendXRefFileEpisode cr_SendXRefFileEpisode = new CommandRequest_WebCacheSendXRefFileEpisode(); cr_SendXRefFileEpisode.LoadFromDBCommand(crdb); return((ICommandRequest)cr_SendXRefFileEpisode); case CommandRequestType.AniDB_GetReviews: CommandRequest_GetReviews cr_GetReviews = new CommandRequest_GetReviews(); cr_GetReviews.LoadFromDBCommand(crdb); return((ICommandRequest)cr_GetReviews); case CommandRequestType.AniDB_GetUpdated: CommandRequest_GetUpdated cr_GetUpdated = new CommandRequest_GetUpdated(); cr_GetUpdated.LoadFromDBCommand(crdb); return((ICommandRequest)cr_GetUpdated); case CommandRequestType.AniDB_SyncMyList: CommandRequest_SyncMyList cr_SyncMyList = new CommandRequest_SyncMyList(); cr_SyncMyList.LoadFromDBCommand(crdb); return((ICommandRequest)cr_SyncMyList); case CommandRequestType.Refresh_AnimeStats: CommandRequest_RefreshAnime cr_refreshAnime = new CommandRequest_RefreshAnime(); cr_refreshAnime.LoadFromDBCommand(crdb); return(cr_refreshAnime); case CommandRequestType.LinkAniDBTvDB: CommandRequest_LinkAniDBTvDB cr_linkAniDBTvDB = new CommandRequest_LinkAniDBTvDB(); cr_linkAniDBTvDB.LoadFromDBCommand(crdb); return(cr_linkAniDBTvDB); case CommandRequestType.Refresh_GroupFilter: CommandRequest_RefreshGroupFilter cr_refreshGroupFilter = new CommandRequest_RefreshGroupFilter(); cr_refreshGroupFilter.LoadFromDBCommand(crdb); return(cr_refreshGroupFilter); case CommandRequestType.Plex_Sync: CommandRequest_PlexSyncWatched cr_PlexSync = new CommandRequest_PlexSyncWatched(); cr_PlexSync.LoadFromDBCommand(crdb); return(cr_PlexSync); case CommandRequestType.LinkFileManually: CommandRequest_LinkFileManually cr_LinkFile = new CommandRequest_LinkFileManually(); cr_LinkFile.LoadFromDBCommand(crdb); return(cr_LinkFile); } return(null); }
private void ProcessFile_LocalInfo() { // hash and read media info for file int nshareID = -1; Tuple <SVR_ImportFolder, string> tup = VideoLocal_PlaceRepository.GetFromFullPath(FileName); if (tup == null) { logger.Error($"Unable to locate Import Folder for {FileName}"); return; } SVR_ImportFolder folder = tup.Item1; string filePath = tup.Item2; long filesize = 0; Exception e = null; if (!File.Exists(FileName)) { logger.Error("File does not exist: {0}", FileName); return; } if (ServerSettings.Instance.Import.FileLockChecking) { int numAttempts = 0; bool writeAccess = folder.IsDropSource == 1; bool aggressive = ServerSettings.Instance.Import.AggressiveFileLockChecking; // At least 1s between to ensure that size has the chance to change int waitTime = ServerSettings.Instance.Import.FileLockWaitTimeMS; if (waitTime < 1000) { waitTime = ServerSettings.Instance.Import.FileLockWaitTimeMS = 4000; ServerSettings.Instance.SaveSettings(); } if (!aggressive) { // Wait 1 minute before giving up on trying to access the file while ((filesize = CanAccessFile(FileName, writeAccess, ref e)) == 0 && (numAttempts < 60)) { numAttempts++; Thread.Sleep(waitTime); logger.Trace($@"Failed to access, (or filesize is 0) Attempt # {numAttempts}, {FileName}"); } } else { // Wait 1 minute before giving up on trying to access the file // first only do read to not get in something's way while ((filesize = CanAccessFile(FileName, false, ref e)) == 0 && (numAttempts < 60)) { numAttempts++; Thread.Sleep(1000); logger.Trace($@"Failed to access, (or filesize is 0) Attempt # {numAttempts}, {FileName}"); } // if we failed to access the file, get ouuta here if (numAttempts >= 60) { logger.Error("Could not access file: " + FileName); logger.Error(e); return; } int seconds = ServerSettings.Instance.Import.AggressiveFileLockWaitTimeSeconds; if (seconds < 0) { seconds = ServerSettings.Instance.Import.AggressiveFileLockWaitTimeSeconds = 8; ServerSettings.Instance.SaveSettings(); } Thread.Sleep(waitTime); numAttempts = 0; //For systems with no locking while (FileModified(FileName, seconds, ref filesize, writeAccess, ref e) && numAttempts < 60) { numAttempts++; Thread.Sleep(waitTime); // Only show if it's more than 'seconds' past if (numAttempts != 0 && numAttempts * 2 % seconds == 0) { logger.Warn( $@"The modified date is too soon. Waiting to ensure that no processes are writing to it. {numAttempts}/60 {FileName}" ); } } } // if we failed to access the file, get ouuta here if (numAttempts >= 60 || filesize == 0) { logger.Error("Could not access file: " + FileName); logger.Error(e); return; } } if (!File.Exists(FileName)) { logger.Error("Could not access file: " + FileName); return; } FileInfo sourceFile = new FileInfo(FileName); nshareID = folder.ImportFolderID; // check if we have already processed this file SVR_VideoLocal_Place vlocalplace = RepoFactory.VideoLocalPlace.GetByFilePathAndImportFolderID(filePath, nshareID); SVR_VideoLocal vlocal = null; var filename = Path.GetFileName(filePath); if (vlocalplace != null) { vlocal = vlocalplace.VideoLocal; if (vlocal != null) { logger.Trace("VideoLocal record found in database: {0}", FileName); // This will only happen with DB corruption, so just clean up the mess. if (vlocalplace.FullServerPath == null) { if (vlocal.Places.Count == 1) { RepoFactory.VideoLocal.Delete(vlocal); vlocal = null; } RepoFactory.VideoLocalPlace.Delete(vlocalplace); vlocalplace = null; } if (vlocal != null && ForceHash) { vlocal.FileSize = filesize; vlocal.DateTimeUpdated = DateTime.Now; } } } if (vlocal == null) { // TODO support reading MD5 and SHA1 from files via the standard way logger.Trace("No existing VideoLocal, creating temporary record"); vlocal = new SVR_VideoLocal { DateTimeUpdated = DateTime.Now, DateTimeCreated = DateTimeUpdated, FileName = filename, FileSize = filesize, Hash = string.Empty, CRC32 = string.Empty, MD5 = string.Empty, SHA1 = string.Empty, IsIgnored = 0, IsVariation = 0 }; } if (vlocalplace == null) { logger.Trace("No existing VideoLocal_Place, creating a new record"); vlocalplace = new SVR_VideoLocal_Place { FilePath = filePath, ImportFolderID = nshareID, ImportFolderType = folder.ImportFolderType }; // Make sure we have an ID RepoFactory.VideoLocalPlace.Save(vlocalplace); } // check if we need to get a hash this file if (string.IsNullOrEmpty(vlocal.Hash) || ForceHash) { logger.Trace("No existing hash in VideoLocal, checking XRefs"); if (!ForceHash) { // try getting the hash from the CrossRef List <CrossRef_File_Episode> crossRefs = RepoFactory.CrossRef_File_Episode.GetByFileNameAndSize(filename, vlocal.FileSize); if (crossRefs.Any()) { 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(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); } } // reinit this to check if we erased them fnhashes = RepoFactory.FileNameHash.GetByFileNameAndSize(filename, vlocal.FileSize); 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); } // hash the file if (string.IsNullOrEmpty(vlocal.Hash) || ForceHash) { logger.Info("Hashing File: {0}", FileName); ShokoService.CmdProcessorHasher.QueueState = PrettyDescriptionHashing; DateTime start = DateTime.Now; // update the VideoLocal record with the Hash, since cloud support we calculate everything var hashes = FileHashHelper.GetHashInfo(FileName.Replace("/", $"{Path.DirectorySeparatorChar}"), true, ShokoServer.OnHashProgress, true, true, true); TimeSpan ts = DateTime.Now - start; logger.Trace("Hashed file in {0:#0.0} seconds --- {1} ({2})", ts.TotalSeconds, 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; } FillMissingHashes(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) SVR_VideoLocal tlocal = RepoFactory.VideoLocal.GetByHash(vlocal.Hash); bool duplicate = false; bool changed = false; if (tlocal != null) { logger.Trace("Found existing VideoLocal with hash, merging info from it"); // Aid with hashing cloud. Merge hashes and save, regardless of duplicate file changed = tlocal.MergeInfoFrom(vlocal); vlocal = tlocal; List <SVR_VideoLocal_Place> preps = vlocal.Places.Where(a => !vlocalplace.FullServerPath.Equals(a.FullServerPath)).ToList(); foreach (var prep in preps) { if (prep == null) { continue; } // clean up, if there is a 'duplicate file' that is invalid, remove it. if (prep.FullServerPath == null) { RepoFactory.VideoLocalPlace.Delete(prep); } else { if (!File.Exists(prep.FullServerPath)) { RepoFactory.VideoLocalPlace.Delete(prep); } } } var dupPlace = vlocal.Places.FirstOrDefault(a => !vlocalplace.FullServerPath.Equals(a.FullServerPath)); if (dupPlace != null) { logger.Warn("Found Duplicate File"); logger.Warn("---------------------------------------------"); logger.Warn($"New File: {vlocalplace.FullServerPath}"); logger.Warn($"Existing File: {dupPlace.FullServerPath}"); logger.Warn("---------------------------------------------"); if (ServerSettings.Instance.Import.AutomaticallyDeleteDuplicatesOnImport) { vlocalplace.RemoveRecordAndDeletePhysicalFile(); return; } // check if we have a record of this in the database, if not create one List <DuplicateFile> dupFiles = RepoFactory.DuplicateFile.GetByFilePathsAndImportFolder( vlocalplace.FilePath, dupPlace.FilePath, vlocalplace.ImportFolderID, dupPlace.ImportFolderID); if (dupFiles.Count == 0) { dupFiles = RepoFactory.DuplicateFile.GetByFilePathsAndImportFolder(dupPlace.FilePath, vlocalplace.FilePath, dupPlace.ImportFolderID, vlocalplace.ImportFolderID); } if (dupFiles.Count == 0) { DuplicateFile dup = new DuplicateFile { DateTimeUpdated = DateTime.Now, FilePathFile1 = vlocalplace.FilePath, FilePathFile2 = dupPlace.FilePath, ImportFolderIDFile1 = vlocalplace.ImportFolderID, ImportFolderIDFile2 = dupPlace.ImportFolderID, Hash = vlocal.Hash }; RepoFactory.DuplicateFile.Save(dup); } //Notify duplicate, don't delete duplicate = true; } } if (!duplicate || changed) { RepoFactory.VideoLocal.Save(vlocal, true); } vlocalplace.VideoLocalID = vlocal.VideoLocalID; RepoFactory.VideoLocalPlace.Save(vlocalplace); if (duplicate) { CommandRequest_ProcessFile cr_procfile3 = new CommandRequest_ProcessFile(vlocal.VideoLocalID, false); cr_procfile3.Save(); return; } // also save the filename to hash record // replace the existing records just in case it was corrupt FileNameHash fnhash; List <FileNameHash> fnhashes2 = RepoFactory.FileNameHash.GetByFileNameAndSize(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 = filename; fnhash.FileSize = vlocal.FileSize; fnhash.Hash = vlocal.Hash; fnhash.DateTimeUpdated = DateTime.Now; RepoFactory.FileNameHash.Save(fnhash); } else { FillMissingHashes(vlocal); } if (((vlocal.Media?.GeneralStream?.Duration ?? 0) == 0) || vlocal.MediaVersion < SVR_VideoLocal.MEDIA_VERSION) { 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, SkipMyList); cr_procfile.Save(); }