private void CommandBinding_ScanFolder(object sender, ExecutedRoutedEventArgs e) { object obj = e.Parameter; if (obj == null) { return; } try { if (obj.GetType() == typeof(SVR_ImportFolder)) { SVR_ImportFolder fldr = (SVR_ImportFolder)obj; ShokoServer.ScanFolder(fldr.ImportFolderID); MessageBox.Show(Commons.Properties.Resources.Server_ScanFolder, Commons.Properties.Resources.Success, MessageBoxButton.OK, MessageBoxImage.Information); } } catch (Exception ex) { Utils.ShowErrorMessage(ex); } }
public CmdHashFile(string filename, bool force) { (SVR_ImportFolder folder, string filePath) = VideoLocal_PlaceRepository.GetFromFullPath(filename); if (folder == null) { throw new IOException($"Unable to locate Import Folder for {filename}"); } IFileSystem f = folder.FileSystem; if (f == null) { throw new IOException($"Unable to open filesystem for: {filename}"); } _importFolder = folder; _filePath = filePath; IObject source = f.Resolve(filename); if (source == null || source.Status != NutzCode.CloudFileSystem.Status.Ok || !(source is IFile source_file)) { throw new IOException($"Could not access file: {filename}"); } File = source_file; Force = force; FileSystemName = File.FileSystem.Name; FullName = File.FullName; }
public CmdServerDeleteFolder(int importFolderId) { ImportFolderId = importFolderId; SVR_ImportFolder fldr = Repo.Instance.ImportFolder.GetByID(ImportFolderId); ScanFolderPath = fldr.ImportFolderLocation; }
void btnDeleteImportFolder_Click(object sender, RoutedEventArgs e) { object obj = lbImportFolders.SelectedItem; if (obj == null) { return; } try { if (obj.GetType() == typeof(SVR_ImportFolder)) { SVR_ImportFolder ns = (SVR_ImportFolder)obj; MessageBoxResult res = MessageBox.Show( string.Format(Commons.Properties.Resources.ImportFolders_RemoveFolder, ns.ImportFolderLocation), Commons.Properties.Resources.Confirm, MessageBoxButton.YesNo, MessageBoxImage.Question); if (res == MessageBoxResult.Yes) { Cursor = Cursors.Wait; Importer.DeleteImportFolder(ns.ImportFolderID); Cursor = Cursors.Arrow; } } } catch (Exception ex) { Cursor = Cursors.Arrow; Utils.ShowErrorMessage(ex); } }
public ImportFolder(SVR_ImportFolder folder) { int series = RepoFactory.VideoLocalPlace.GetByImportFolder(folder.ImportFolderID) .Select(a => a?.VideoLocal?.Hash).Where(a => !string.IsNullOrEmpty(a)).Distinct() .SelectMany(RepoFactory.CrossRef_File_Episode.GetByHash).DistinctBy(a => a.AnimeID).Count(); long size = RepoFactory.VideoLocalPlace.GetByImportFolder(folder.ImportFolderID) .Select(a => a.VideoLocal).Where(b => b != null) .Sum(b => b.FileSize); DropFolderType type; if (folder.FolderIsDropDestination) { type = DropFolderType.Destination; } else if (folder.FolderIsDropSource) { type = DropFolderType.Source; } else { type = DropFolderType.None; } ID = folder.ImportFolderID; Name = folder.ImportFolderName; Path = folder.ImportFolderLocation; WatchForNewFiles = folder.FolderIsWatched; DropFolderType = type; Size = series; FileSize = size; }
public CmdHashFile(IFile file, bool force) { File = file; Force = force; FileSystemName = File.FileSystem.Name; FullName = File.FullName; (SVR_ImportFolder folder, string filePath) = VideoLocal_PlaceRepository.GetFromFullPath(File.FullName); _importFolder = folder; _filePath = filePath; }
internal void OnFileHashed(SVR_ImportFolder folder, SVR_VideoLocal_Place vlp) { var path = vlp.FilePath; FileHashed?.Invoke(null, new FileHashedEventArgs { FileInfo = vlp.GetFile(), ImportFolder = folder, RelativePath = path, Hashes = vlp.Hashes, MediaInfo = vlp.MediaInfo, }); }
internal void OnFileDetected(SVR_ImportFolder folder, FileInfo file) { var path = file.FullName.Replace(folder.ImportFolderLocation, ""); if (!path.StartsWith("/")) { path = "/" + path; } FileDetected?.Invoke(null, new FileDetectedEventArgs { FileInfo = file, ImportFolder = folder, RelativePath = path, }); }
void lbImportFolders_MouseDoubleClick(object sender, MouseButtonEventArgs e) { object obj = lbImportFolders.SelectedItem; if (obj == null) { return; } SVR_ImportFolder ns = (SVR_ImportFolder)obj; ImportFolderForm frm = new ImportFolderForm(); frm.Owner = GetTopParent(); frm.Init(ns); bool?result = frm.ShowDialog(); }
public void Init(SVR_ImportFolder ifldr) { try { ServerInfo.Instance.RefreshFolderProviders(); importFldr = new SVR_ImportFolder() { ImportFolderID = ifldr.ImportFolderID, ImportFolderType = ifldr.ImportFolderType, ImportFolderLocation = ifldr.ImportFolderLocation, ImportFolderName = ifldr.ImportFolderName, IsDropSource = ifldr.IsDropSource, IsDropDestination = ifldr.IsDropDestination, CloudID = ifldr.CloudID.HasValue && ifldr.CloudID == 0 ? null : ifldr.CloudID, IsWatched = ifldr.IsWatched }; txtImportFolderLocation.Text = importFldr.ImportFolderLocation; chkDropDestination.IsChecked = importFldr.IsDropDestination == 1; chkDropSource.IsChecked = importFldr.IsDropSource == 1; chkIsWatched.IsChecked = importFldr.IsWatched == 1; if (ifldr.CloudID.HasValue) { comboProvider.SelectedItem = ServerInfo.Instance.FolderProviders.FirstOrDefault(a => a.CloudID == ifldr.CloudID.Value); } else { comboProvider.SelectedIndex = 0; } txtImportFolderLocation.Focus(); } catch (Exception ex) { Utils.ShowErrorMessage(ex); } }
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; IFileSystem f = tup.Item1.FileSystem; if (f == null) { logger.Error("Unable to open filesystem for: {0}", FileName); return; } long filesize = 0; Exception e = null; if (folder.CloudID == null) // Local Access { if (!File.Exists(FileName)) { logger.Error("File does not exist: {0}", FileName); return; } int numAttempts = 0; bool writeAccess = folder.IsDropSource == 1; // 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; } // At least 1s between to ensure that size has the chance to change // TODO make this a setting to allow fine tuning on various configs // TODO Make this able to be disabled. It adds 1.5s to hashing just waiting for the Linux/NAS use case int seconds = 8; int waitTime = seconds * 1000 / 2; Thread.Sleep(waitTime); numAttempts = 0; //For systems with no locking // TODO make this a setting as well 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; } } FileSystemResult <IObject> source = f.Resolve(FileName); if (source == null || !source.IsOk || !(source.Result is IFile)) { logger.Error("Could not access file: " + FileName); return; } 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.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) { 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 = 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 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); } //Cloud and no hash, Nothing to do, except maybe Get the mediainfo.... if (string.IsNullOrEmpty(vlocal.Hash) && folder.CloudID.HasValue) { logger.Trace("No Hash found for cloud " + 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; } // 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("/", $"{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(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 => 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) { RepoFactory.VideoLocalPlace.Delete(prep); } else { FileSystemResult dupFileSystemResult = prep.ImportFolder?.FileSystem?.Resolve(prep.FullServerPath); if (dupFileSystemResult == null || !dupFileSystemResult.IsOk) { RepoFactory.VideoLocalPlace.Delete(prep); } } } var dupPlace = vlocal.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 = 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 == 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(); }
void btnSave_Click(object sender, RoutedEventArgs e) { try { // An import folder cannot be both the drop source and the drop destination if (chkDropDestination.IsChecked.HasValue && chkDropSource.IsChecked.HasValue && chkDropDestination.IsChecked.Value && chkDropSource.IsChecked.Value) { MessageBox.Show(Shoko.Commons.Properties.Resources.ImportFolders_SameFolder, Shoko.Commons.Properties.Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return; } // The import folder location cannot be blank. Enter a valid path on OMM Server if (string.IsNullOrEmpty(txtImportFolderLocation.Text)) { MessageBox.Show(Shoko.Commons.Properties.Resources.ImportFolders_BlankImport, Shoko.Commons.Properties.Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); txtImportFolderLocation.Focus(); return; } ImportFolder contract = new ImportFolder(); contract.ImportFolderID = importFldr.ImportFolderID; contract.ImportFolderType = (int)(importFldr.CloudID.HasValue ? ImportFolderType.Cloud : ImportFolderType.HDD); contract.ImportFolderName = "NA"; contract.ImportFolderLocation = txtImportFolderLocation.Text.Trim(); contract.IsDropDestination = chkDropDestination.IsChecked.Value ? 1 : 0; contract.IsDropSource = chkDropSource.IsChecked.Value ? 1 : 0; contract.IsWatched = chkIsWatched.IsChecked.Value ? 1 : 0; if (comboProvider.SelectedIndex == 0) { contract.CloudID = null; } else { contract.CloudID = ((SVR_CloudAccount)comboProvider.SelectedItem).CloudID; } ShokoServiceImplementation imp = new ShokoServiceImplementation(); CL_Response <ImportFolder> response = imp.SaveImportFolder(contract); if (!string.IsNullOrEmpty(response.ErrorMessage)) { MessageBox.Show(response.ErrorMessage, Shoko.Commons.Properties.Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); } importFldr = null; ServerInfo.Instance.RefreshImportFolders(); } catch (Exception ex) { Utils.ShowErrorMessage(ex); } this.DialogResult = true; this.Close(); }
public CmdServerDeleteFolder(string str) : base(str) { SVR_ImportFolder fldr = Repo.Instance.ImportFolder.GetByID(ImportFolderId); ScanFolderPath = fldr.ImportFolderLocation; }
public void Init(SVR_ImportFolder acc, string initialpath) { _account = acc.CloudAccount; PopulateMainDir(initialpath); }
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); }