Пример #1
0
        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);
            }
        }
Пример #2
0
        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;
        }
Пример #3
0
        public CmdServerDeleteFolder(int importFolderId)
        {
            ImportFolderId = importFolderId;
            SVR_ImportFolder fldr = Repo.Instance.ImportFolder.GetByID(ImportFolderId);

            ScanFolderPath = fldr.ImportFolderLocation;
        }
Пример #4
0
        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);
            }
        }
Пример #5
0
        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;
        }
Пример #6
0
 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;
 }
Пример #7
0
        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,
            });
        }
Пример #8
0
        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,
            });
        }
Пример #9
0
        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();
        }
Пример #10
0
 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();
        }
Пример #12
0
        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();
        }
Пример #13
0
        public CmdServerDeleteFolder(string str) : base(str)
        {
            SVR_ImportFolder fldr = Repo.Instance.ImportFolder.GetByID(ImportFolderId);

            ScanFolderPath = fldr.ImportFolderLocation;
        }
Пример #14
0
 public void Init(SVR_ImportFolder acc, string initialpath)
 {
     _account = acc.CloudAccount;
     PopulateMainDir(initialpath);
 }
Пример #15
0
        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);
        }