public Media GetMediaFromUser(int userID) { Media n = null; if (Media == null) { SVR_VideoLocal_Place pl = GetBestVideoLocalPlace(); if (pl?.FullServerPath != null) { IFileSystem f = pl.ImportFolder.FileSystem; FileSystemResult <IObject> src = f?.Resolve(pl.FullServerPath); if (src != null && src.IsOk && src.Result is IFile) { if (pl.RefreshMediaInfo()) { RepoFactory.VideoLocal.Save(pl.VideoLocal, true); } } } } if (Media == null) { return(null); } n = Media.DeepClone(); if (n?.Parts == null) { return(n); } foreach (Part p in n.Parts) { string name = UrlSafe.Replace(Path.GetFileName(FileName), " ") .Replace(" ", " ") .Replace(" ", " ") .Trim(); name = UrlSafe2.Replace(name, string.Empty) .Trim() .Replace("..", ".") .Replace("..", ".") .Replace("__", "_") .Replace("__", "_") .Replace(" ", "_") .Replace("_.", "."); while (name.StartsWith("_")) { name = name.Substring(1); } while (name.StartsWith(".")) { name = name.Substring(1); } p.Key = ((IProvider)null).ReplaceSchemeHost( ((IProvider)null).ConstructVideoLocalStream(userID, VideoLocalID.ToString(), name, false)); if (p.Streams == null) { continue; } foreach (Stream s in p.Streams.Where(a => a.File != null && a.StreamType == "3").ToList()) { s.Key = ((IProvider)null).ReplaceSchemeHost( ((IProvider)null).ConstructFileStream(userID, s.File, false)); } } return(n); }
// returns false if we should retry private bool MoveFileIfRequired() { try { logger.Trace("Attempting to MOVE file: {0}", this.FullServerPath); // check if this file is in the drop folder // otherwise we don't need to move it if (ImportFolder.IsDropSource == 0) { logger.Trace("Not moving file as it is NOT in the drop folder: {0}", this.FullServerPath); return(true); } IFileSystem f = this.ImportFolder.FileSystem; if (f == null) { logger.Trace("Unable to MOVE, filesystem not working: {0}", this.FullServerPath); return(true); } FileSystemResult <IObject> fsrresult = f.Resolve(FullServerPath); if (!fsrresult.IsOk) { logger.Error("Could not find or access the file to move: {0}", this.FullServerPath); // this can happen due to file locks, so retry return(false); } IFile source_file = fsrresult.Result as IFile; if (source_file == null) { logger.Error("Could not move the file (it isn't a file): {0}", this.FullServerPath); // this means it isn't a file, but something else, so don't retry return(true); } // find the default destination SVR_ImportFolder destFolder = null; foreach (SVR_ImportFolder fldr in RepoFactory.ImportFolder.GetAll() .Where(a => a != null && a.CloudID == ImportFolder.CloudID).ToList()) { if (!fldr.FolderIsDropDestination) { continue; } if (fldr.FolderIsDropSource) { continue; } IFileSystem fs = fldr.FileSystem; FileSystemResult <IObject> fsresult = fs?.Resolve(fldr.ImportFolderLocation); if (fsresult == null || !fsresult.IsOk) { continue; } string tempNewPath = Path.Combine(fldr.ImportFolderLocation, FilePath); fsresult = fs.Resolve(tempNewPath); if (fsresult.IsOk) { continue; } destFolder = fldr; break; } if (destFolder == null) { logger.Error("Could not find a valid destination: {0}", this.FullServerPath); return(true); } // keep the original drop folder for later (take a copy, not a reference) SVR_ImportFolder dropFolder = this.ImportFolder; // we can only move the file if it has an anime associated with it List <CrossRef_File_Episode> xrefs = this.VideoLocal.EpisodeCrossRefs; if (xrefs.Count == 0) { return(true); } CrossRef_File_Episode xref = xrefs[0]; // find the series associated with this episode SVR_AnimeSeries series = RepoFactory.AnimeSeries.GetByAnimeID(xref.AnimeID); if (series == null) { return(true); } // find where the other files are stored for this series // if there are no other files except for this one, it means we need to create a new location bool foundLocation = false; string newFullPath = ""; // sort the episodes by air date, so that we will move the file to the location of the latest episode List <SVR_AnimeEpisode> allEps = series.GetAnimeEpisodes() .OrderByDescending(a => a.AniDB_Episode.AirDate) .ToList(); IDirectory destination = null; foreach (SVR_AnimeEpisode ep in allEps) { // check if this episode belongs to more than one anime // if it does we will ignore it List <CrossRef_File_Episode> fileEpXrefs = RepoFactory.CrossRef_File_Episode.GetByEpisodeID(ep.AniDB_EpisodeID); int? animeID = null; bool crossOver = false; foreach (CrossRef_File_Episode fileEpXref in fileEpXrefs) { if (!animeID.HasValue) { animeID = fileEpXref.AnimeID; } else { if (animeID.Value != fileEpXref.AnimeID) { crossOver = true; } } } if (crossOver) { continue; } foreach (SVR_VideoLocal vid in ep.GetVideoLocals() .Where(a => a.Places.Any(b => b.ImportFolder.CloudID == destFolder.CloudID && b.ImportFolder.IsDropSource == 0)).ToList()) { if (vid.VideoLocalID == this.VideoLocalID) { continue; } SVR_VideoLocal_Place place = vid.Places.FirstOrDefault(a => a.ImportFolder.CloudID == destFolder.CloudID); string thisFileName = place?.FullServerPath; if (thisFileName == null) { continue; } string folderName = Path.GetDirectoryName(thisFileName); FileSystemResult <IObject> dir = f.Resolve(folderName); if (!dir.IsOk) { continue; } // ensure we aren't moving to the current directory if (folderName.Equals(Path.GetDirectoryName(FullServerPath), StringComparison.InvariantCultureIgnoreCase)) { continue; } destination = dir.Result as IDirectory; // Not a directory if (destination == null) { continue; } newFullPath = folderName; foundLocation = true; break; } if (foundLocation) { break; } } if (!foundLocation) { // we need to create a new folder string newFolderName = Utils.RemoveInvalidFolderNameCharacters(series.GetSeriesName()); newFullPath = Path.Combine(destFolder.ImportFolderLocation, newFolderName); FileSystemResult <IObject> dirn = f.Resolve(newFullPath); if (!dirn.IsOk) { dirn = f.Resolve(destFolder.ImportFolderLocation); if (dirn.IsOk) { IDirectory d = (IDirectory)dirn.Result; FileSystemResult <IDirectory> d2 = Task .Run(async() => await d.CreateDirectoryAsync(newFolderName, null)) .Result; destination = d2.Result; } else { logger.Error("Import folder couldn't be resolved: {0}", destFolder.ImportFolderLocation); newFullPath = null; } } else if (dirn.Result is IFile) { logger.Error("Destination folder is a file: {0}", newFolderName); newFullPath = null; } else { destination = (IDirectory)dirn.Result; } } if (string.IsNullOrEmpty(newFullPath)) { return(true); } // We've already resolved FullServerPath, so it doesn't need to be checked string newFullServerPath = Path.Combine(newFullPath, Path.GetFileName(this.FullServerPath)); Tuple <SVR_ImportFolder, string> tup = VideoLocal_PlaceRepository.GetFromFullPath(newFullServerPath); if (tup == null) { logger.Error($"Unable to LOCATE file {newFullServerPath} inside the import folders"); return(true); } // Last ditch effort to ensure we aren't moving a file unto itself if (newFullServerPath.Equals(FullServerPath, StringComparison.InvariantCultureIgnoreCase)) { logger.Error($"Resolved to move {newFullServerPath} unto itself. NOT MOVING"); return(true); } logger.Info("Moving file from {0} to {1}", this.FullServerPath, newFullServerPath); FileSystemResult <IObject> dst = f.Resolve(newFullServerPath); if (dst.IsOk) { logger.Trace( "Not moving file as it already exists at the new location, deleting source file instead: {0} --- {1}", this.FullServerPath, newFullServerPath); // if the file already exists, we can just delete the source file instead // this is safer than deleting and moving FileSystemResult fr = new FileSystemResult(); try { fr = source_file.Delete(false); if (!fr.IsOk) { logger.Warn("Unable to DELETE file: {0} error {1}", this.FullServerPath, fr?.Error ?? String.Empty); } this.ImportFolderID = tup.Item1.ImportFolderID; this.FilePath = tup.Item2; RepoFactory.VideoLocalPlace.Save(this); // check for any empty folders in drop folder // only for the drop folder if (dropFolder.IsDropSource == 1) { FileSystemResult <IObject> dd = f.Resolve(dropFolder.ImportFolderLocation); if (dd != null && dd.IsOk && dd.Result is IDirectory) { RecursiveDeleteEmptyDirectories((IDirectory)dd.Result, true); } } } catch { logger.Error("Unable to DELETE file: {0} error {1}", this.FullServerPath, fr?.Error ?? String.Empty); } } else { FileSystemResult fr = source_file.Move(destination); if (!fr.IsOk) { logger.Error("Unable to MOVE file: {0} to {1} error {2}", this.FullServerPath, newFullServerPath, fr?.Error ?? "No Error String"); return(false); } string originalFileName = this.FullServerPath; this.ImportFolderID = tup.Item1.ImportFolderID; this.FilePath = tup.Item2; RepoFactory.VideoLocalPlace.Save(this); try { // move any subtitle files foreach (string subtitleFile in Utils.GetPossibleSubtitleFiles(originalFileName)) { FileSystemResult <IObject> src = f.Resolve(subtitleFile); if (src.IsOk && src.Result is IFile) { string newSubPath = Path.Combine(Path.GetDirectoryName(newFullServerPath), ((IFile)src.Result).Name); dst = f.Resolve(newSubPath); if (dst.IsOk && dst.Result is IFile) { FileSystemResult fr2 = src.Result.Delete(false); if (!fr2.IsOk) { logger.Warn("Unable to DELETE file: {0} error {1}", subtitleFile, fr2?.Error ?? String.Empty); } } else { FileSystemResult fr2 = ((IFile)src.Result).Move(destination); if (!fr2.IsOk) { logger.Error("Unable to MOVE file: {0} to {1} error {2)", subtitleFile, newSubPath, fr2?.Error ?? String.Empty); } } } } } catch (Exception ex) { logger.Error(ex, ex.ToString()); } // check for any empty folders in drop folder // only for the drop folder if (dropFolder.IsDropSource == 1) { FileSystemResult <IObject> dd = f.Resolve(dropFolder.ImportFolderLocation); if (dd != null && dd.IsOk && dd.Result is IDirectory) { RecursiveDeleteEmptyDirectories((IDirectory)dd.Result, true); } } } } catch (Exception ex) { string msg = $"Could not MOVE file: {this.FullServerPath} -- {ex.ToString()}"; logger.Error(ex, msg); } return(true); }