private object GetMediaFiles() { var pathQuery = Request.Query.path; var path = (string)pathQuery.Value; if (!_diskProvider.FolderExists(path)) { return(new string[0]); } return(_diskScanService.GetBookFiles(path).Select(f => new { Path = f.FullName, Name = f.Name })); }
private Response GetMediaFiles() { var pathQuery = Request.Query.path; var path = (string)pathQuery.Value; if (!_diskProvider.FolderExists(path)) { return(new string[0].AsResponse()); } return(_diskScanService.GetVideoFiles(path).Select(f => new { Path = f, RelativePath = path.GetRelativePath(f), Name = Path.GetFileName(f) }).AsResponse()); }
public TrackFileMoveResult UpgradeTrackFile(TrackFile trackFile, LocalTrack localTrack, bool copyOnly = false) { var moveFileResult = new TrackFileMoveResult(); var existingFiles = localTrack.Tracks .Where(e => e.TrackFileId > 0) .Select(e => e.TrackFile.Value) .Where(e => e != null) .GroupBy(e => e.Id) .ToList(); var rootFolder = _diskProvider.GetParentFolder(localTrack.Artist.Path); // If there are existing track files and the root folder is missing, throw, so the old file isn't left behind during the import process. if (existingFiles.Any() && !_diskProvider.FolderExists(rootFolder)) { throw new RootFolderNotFoundException($"Root folder '{rootFolder}' was not found."); } foreach (var existingFile in existingFiles) { var file = existingFile.First(); var trackFilePath = file.Path; var subfolder = rootFolder.GetRelativePath(_diskProvider.GetParentFolder(trackFilePath)); if (_diskProvider.FileExists(trackFilePath)) { _logger.Debug("Removing existing track file: {0}", file); _recycleBinProvider.DeleteFile(trackFilePath, subfolder); } moveFileResult.OldFiles.Add(file); _mediaFileService.Delete(file, DeleteMediaFileReason.Upgrade); } if (copyOnly) { moveFileResult.TrackFile = _trackFileMover.CopyTrackFile(trackFile, localTrack); } else { moveFileResult.TrackFile = _trackFileMover.MoveTrackFile(trackFile, localTrack); } _audioTagService.WriteTags(trackFile, true); return(moveFileResult); }
private void Scan(Series series) { _logger.ProgressInfo("Scanning disk for {0}", series.Title); _commandExecutor.PublishCommand(new CleanMediaFileDb(series.Id)); if (!_diskProvider.FolderExists(series.Path)) { _logger.Debug("Series folder doesn't exist: {0}", series.Path); return; } var mediaFileList = GetVideoFiles(series.Path); var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, series, false); _importApprovedEpisodes.Import(decisions); }
private object GetMediaFiles() { var pathQuery = Request.Query.path; var path = (string)pathQuery.Value; if (!_diskProvider.FolderExists(path)) { return(Array.Empty <string>()); } return(_diskScanService.GetVideoFiles(path).Select(f => new { Path = f, RelativePath = path.GetRelativePath(f), Name = Path.GetFileName(f) })); }
public EpisodeFileMoveResult UpgradeEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode, bool copyOnly = false) { var moveFileResult = new EpisodeFileMoveResult(); var existingFiles = localEpisode.Episodes .Where(e => e.EpisodeFileId > 0) .Select(e => e.EpisodeFile.Value) .Where(e => e != null) .GroupBy(e => e.Id) .ToList(); var rootFolder = _diskProvider.GetParentFolder(localEpisode.Series.Path); // If there are existing episode files and the root folder is missing, throw, so the old file isn't left behind during the import process. if (existingFiles.Any() && !_diskProvider.FolderExists(rootFolder)) { throw new RootFolderNotFoundException($"Root folder '{rootFolder}' was not found."); } foreach (var existingFile in existingFiles) { var file = existingFile.First(); var episodeFilePath = Path.Combine(localEpisode.Series.Path, file.RelativePath); var subfolder = rootFolder.GetRelativePath(_diskProvider.GetParentFolder(episodeFilePath)); if (_diskProvider.FileExists(episodeFilePath)) { _logger.Debug("Removing existing episode file: {0}", file); _recycleBinProvider.DeleteFile(episodeFilePath, subfolder); } moveFileResult.OldFiles.Add(file); _mediaFileService.Delete(file, DeleteMediaFileReason.Upgrade); } if (copyOnly) { moveFileResult.EpisodeFile = _episodeFileMover.CopyEpisodeFile(episodeFile, localEpisode); } else { moveFileResult.EpisodeFile = _episodeFileMover.MoveEpisodeFile(episodeFile, localEpisode); } return(moveFileResult); }
public List <ImportResult> ProcessPath(string path, Series series = null, DownloadClientItem downloadClientItem = null) { if (_diskProvider.FolderExists(path)) { if (series == null) { return(ProcessFolder(new DirectoryInfo(path), downloadClientItem)); } return(ProcessFolder(new DirectoryInfo(path), series, downloadClientItem)); } if (series == null) { return(ProcessFile(new FileInfo(path), downloadClientItem)); } return(ProcessFile(new FileInfo(path), series, downloadClientItem)); }
public override HealthCheck Check() { var rootFolders = _seriesService.GetAllSeriesPaths().Select(s => _rootFolderService.GetBestRootFolderPath(s)).Distinct(); var missingRootFolders = rootFolders.Where(s => !_diskProvider.FolderExists(s)) .ToList(); if (missingRootFolders.Any()) { if (missingRootFolders.Count == 1) { return(new HealthCheck(GetType(), HealthCheckResult.Error, "Missing root folder: " + missingRootFolders.First(), "#missing-root-folder")); } var message = string.Format("Multiple root folders are missing: {0}", string.Join(" | ", missingRootFolders)); return(new HealthCheck(GetType(), HealthCheckResult.Error, message, "#missing-root-folder")); } return(new HealthCheck(GetType())); }
public override IEnumerable <ExtraFile> CreateAfterArtistScan(Artist artist, List <TrackFile> trackFiles) { var metadataFiles = _metadataFileService.GetFilesByArtist(artist.Id); _cleanMetadataService.Clean(artist); if (!_diskProvider.FolderExists(artist.Path)) { _logger.Info("Artist folder does not exist, skipping metadata creation"); return(Enumerable.Empty <MetadataFile>()); } var files = new List <MetadataFile>(); foreach (var consumer in _metadataFactory.Enabled()) { var consumerFiles = GetMetadataFilesForConsumer(consumer, metadataFiles); files.AddIfNotNull(ProcessArtistMetadata(consumer, artist, consumerFiles)); files.AddRange(ProcessArtistImages(consumer, artist, consumerFiles)); var albumGroups = trackFiles.GroupBy(s => Path.GetDirectoryName(s.Path)).ToList(); foreach (var group in albumGroups) { var album = _albumService.GetAlbum(group.First().AlbumId); var albumFolder = group.Key; files.AddIfNotNull(ProcessAlbumMetadata(consumer, artist, album, albumFolder, consumerFiles)); files.AddRange(ProcessAlbumImages(consumer, artist, album, albumFolder, consumerFiles)); foreach (var trackFile in group) { files.AddIfNotNull(ProcessTrackMetadata(consumer, artist, trackFile, consumerFiles)); } } } _metadataFileService.Upsert(files); return(files); }
public MovieFileMoveResult UpgradeMovieFile(MovieFile movieFile, LocalMovie localMovie, bool copyOnly = false) { _logger.Trace("Upgrading existing movie file."); var moveFileResult = new MovieFileMoveResult(); var existingFile = localMovie.Movie.MovieFileId > 0 ? localMovie.Movie.MovieFile : null; var rootFolder = _diskProvider.GetParentFolder(localMovie.Movie.Path); // If there are existing movie files and the root folder is missing, throw, so the old file isn't left behind during the import process. if (existingFile != null && !_diskProvider.FolderExists(rootFolder)) { throw new RootFolderNotFoundException($"Root folder '{rootFolder}' was not found."); } if (existingFile != null) { var movieFilePath = Path.Combine(localMovie.Movie.Path, existingFile.RelativePath); var subfolder = rootFolder.GetRelativePath(_diskProvider.GetParentFolder(movieFilePath)); if (_diskProvider.FileExists(movieFilePath)) { _logger.Debug("Removing existing movie file: {0}", existingFile); _recycleBinProvider.DeleteFile(movieFilePath, subfolder); } moveFileResult.OldFiles.Add(existingFile); _mediaFileService.Delete(existingFile, DeleteMediaFileReason.Upgrade); } if (copyOnly) { moveFileResult.MovieFile = _movieFileMover.CopyMovieFile(movieFile, localMovie); } else { moveFileResult.MovieFile = _movieFileMover.MoveMovieFile(movieFile, localMovie); } return(moveFileResult); }
protected ValidationFailure TestFolder(string folder, string propertyName, bool mustBeWritable = true) { if (!_diskProvider.FolderExists(folder)) { return(new NzbDroneValidationFailure(propertyName, "Folder does not exist") { DetailedDescription = string.Format("The folder you specified does not exist or is inaccessible. Please verify the folder permissions for the user account '{0}', which is used to execute Prowlarr.", Environment.UserName) }); } if (mustBeWritable && !_diskProvider.FolderWritable(folder)) { _logger.Error("Folder '{0}' is not writable.", folder); return(new NzbDroneValidationFailure(propertyName, "Unable to write to folder") { DetailedDescription = string.Format("The folder you specified is not writable. Please verify the folder permissions for the user account '{0}', which is used to execute Prowlarr.", Environment.UserName) }); } return(null); }
private void MoveSingleArtist(Artist artist, string sourcePath, string destinationPath, bool moveFiles, int?index = null, int?total = null) { if (!_diskProvider.FolderExists(sourcePath)) { _logger.Debug("Folder '{0}' for '{1}' does not exist, not moving.", sourcePath, artist.Name); return; } if (index != null && total != null) { _logger.ProgressInfo("Moving {0} from '{1}' to '{2}' ({3}/{4})", artist.Name, sourcePath, destinationPath, index + 1, total); } else { _logger.ProgressInfo("Moving {0} from '{1}' to '{2}'", artist.Name, sourcePath, destinationPath); } try { if (moveFiles) { _rootFolderWatchingService.ReportFileSystemChangeBeginning(sourcePath, destinationPath); // Ensure the parent of the artist folder exists, this will often just be the root folder, but // in cases where people are using subfolders for first letter (etc) it may not yet exist. _diskProvider.CreateFolder(new DirectoryInfo(destinationPath).Parent.FullName); _diskTransferService.TransferFolder(sourcePath, destinationPath, TransferMode.Move); _logger.ProgressInfo("{0} moved successfully to {1}", artist.Name, artist.Path); } _eventAggregator.PublishEvent(new ArtistMovedEvent(artist, sourcePath, destinationPath)); } catch (IOException ex) { _logger.Error(ex, "Unable to move artist from '{0}' to '{1}'. Try moving files manually", sourcePath, destinationPath); RevertPath(artist.Id, sourcePath); } }
public override HealthCheck Check() { var rootFolders = _movieService.AllMoviePaths() .Select(s => _rootFolderService.GetBestRootFolderPath(s.Value)) .Distinct(); var missingRootFolders = rootFolders.Where(s => !_diskProvider.FolderExists(s)) .ToList(); if (missingRootFolders.Any()) { if (missingRootFolders.Count == 1) { return(new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RootFolderCheckSingleMessage"), missingRootFolders.First()), "#missing-root-folder")); } var message = string.Format(_localizationService.GetLocalizedString("RootFolderCheckMultipleMessage"), string.Join(" | ", missingRootFolders)); return(new HealthCheck(GetType(), HealthCheckResult.Error, message, "#missing-root-folder")); } return(new HealthCheck(GetType())); }
public override HealthCheck Check() { var importLists = _importListFactory.All(); var missingRootFolders = new Dictionary <string, List <ImportListDefinition> >(); foreach (var importList in importLists) { var rootFolderPath = importList.RootFolderPath; if (missingRootFolders.ContainsKey(rootFolderPath)) { missingRootFolders[rootFolderPath].Add(importList); continue; } if (rootFolderPath.IsNullOrWhiteSpace() || !_diskProvider.FolderExists(rootFolderPath)) { missingRootFolders.Add(rootFolderPath, new List <ImportListDefinition> { importList }); } } if (missingRootFolders.Any()) { if (missingRootFolders.Count == 1) { var missingRootFolder = missingRootFolders.First(); return(new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("ImportListMissingRoot"), FormatRootFolder(missingRootFolder.Key, missingRootFolder.Value)), "#import-list-missing-root-folder")); } var message = string.Format(_localizationService.GetLocalizedString("ImportListMultipleMissingRoots"), string.Join(" | ", missingRootFolders.Select(m => FormatRootFolder(m.Key, m.Value)))); return(new HealthCheck(GetType(), HealthCheckResult.Error, message, "#import-list-missing-root-folder")); } return(new HealthCheck(GetType())); }
public override HealthCheck Check() { var importLists = _importListFactory.All(); var missingRootFolders = new Dictionary <string, List <ImportListDefinition> >(); foreach (var importList in importLists) { var rootFolderPath = importList.RootFolderPath; if (missingRootFolders.ContainsKey(rootFolderPath)) { missingRootFolders[rootFolderPath].Add(importList); continue; } if (!_diskProvider.FolderExists(rootFolderPath)) { missingRootFolders.Add(rootFolderPath, new List <ImportListDefinition> { importList }); } } if (missingRootFolders.Any()) { if (missingRootFolders.Count == 1) { var missingRootFolder = missingRootFolders.First(); return(new HealthCheck(GetType(), HealthCheckResult.Error, $"Missing root folder for import list(s): {FormatRootFolder(missingRootFolder.Key, missingRootFolder.Value)}", "#import-list-missing-root-folder")); } var message = string.Format("Multiple root folders are missing for import lists: {0}", string.Join(" | ", missingRootFolders.Select(m => FormatRootFolder(m.Key, m.Value)))); return(new HealthCheck(GetType(), HealthCheckResult.Error, message, "#import-list-missing-root-folder")); } return(new HealthCheck(GetType())); }
public override HealthCheck Check() { var droneFactoryFolder = _configService.DownloadedEpisodesFolder; if (droneFactoryFolder.IsNullOrWhiteSpace()) { return(new HealthCheck(GetType())); } if (!_diskProvider.FolderExists(droneFactoryFolder)) { return(new HealthCheck(GetType(), HealthCheckResult.Error, "Drone factory folder does not exist")); } if (!_diskProvider.FolderWritable(droneFactoryFolder)) { return(new HealthCheck(GetType(), HealthCheckResult.Error, "Unable to write to drone factory folder")); } //Todo: Unable to import one or more files/folders from return(new HealthCheck(GetType())); }
private void InstallUpdate(UpdatePackage updatePackage) { try { var updateSandboxFolder = _appFolderInfo.GetUpdateSandboxFolder(); var packageDestination = Path.Combine(updateSandboxFolder, updatePackage.FileName); if (_diskProvider.FolderExists(updateSandboxFolder)) { _logger.Info("Deleting old update files"); _diskProvider.DeleteFolder(updateSandboxFolder, true); } _logger.ProgressInfo("Downloading update {0} [{1}]", updatePackage.Version, updatePackage.Branch); _logger.Debug("Downloading update package from [{0}] to [{1}]", updatePackage.Url, packageDestination); _httpProvider.DownloadFile(updatePackage.Url, packageDestination); _logger.ProgressInfo("Extracting Update package"); _archiveService.Extract(packageDestination, updateSandboxFolder); _logger.Info("Update package extracted successfully"); _logger.Info("Preparing client"); _diskProvider.MoveFolder(_appFolderInfo.GetUpdateClientFolder(), updateSandboxFolder); _logger.Info("Starting update client {0}", _appFolderInfo.GetUpdateClientExePath()); _logger.ProgressInfo("NzbDrone will restart shortly."); _processProvider.Start(_appFolderInfo.GetUpdateClientExePath(), _processProvider.GetCurrentProcess().Id.ToString()); } catch (Exception ex) { _logger.ErrorException("Update process failed", ex); } }
public OsVersionModel Read() { var version = "10.0"; if (!_diskProvider.FolderExists(PLIST_DIR)) { _logger.Debug("Directory {0} doesn't exist", PLIST_DIR); return(null); } var allFiles = _diskProvider.GetFiles(PLIST_DIR, SearchOption.TopDirectoryOnly); var versionFile = allFiles.SingleOrDefault(c => c.EndsWith("SystemVersion.plist") || c.EndsWith("ServerVersion.plist") ); if (string.IsNullOrWhiteSpace(versionFile)) { _logger.Debug("Couldn't find version plist file in {0}", PLIST_DIR); return(null); } var text = _diskProvider.ReadAllText(versionFile); var match = DarwinVersionRegex.Match(text); if (match.Success) { version = match.Groups["version"].Value; } var name = versionFile.Contains("Server") ? "macOS Server" : "macOS"; return(new OsVersionModel(name, version)); }
public TransferMode TransferFolder(string sourcePath, string targetPath, TransferMode mode, bool verified = true) { Ensure.That(sourcePath, () => sourcePath).IsValidPath(); Ensure.That(targetPath, () => targetPath).IsValidPath(); if (VerificationMode != DiskTransferVerificationMode.Transactional) { verified = false; } if (!_diskProvider.FolderExists(targetPath)) { _diskProvider.CreateFolder(targetPath); } var result = mode; foreach (var subDir in _diskProvider.GetDirectoryInfos(sourcePath)) { result &= TransferFolder(subDir.FullName, Path.Combine(targetPath, subDir.Name), mode, verified); } foreach (var sourceFile in _diskProvider.GetFileInfos(sourcePath)) { var destFile = Path.Combine(targetPath, sourceFile.Name); result &= TransferFile(sourceFile.FullName, destFile, mode, true, verified); } if (mode.HasFlag(TransferMode.Move)) { _diskProvider.DeleteFolder(sourcePath, true); } return(result); }
public void Backup() { _logger.Info("Backing up appdata (database/config)"); var backupFolderAppData = _appFolderInfo.GetUpdateBackUpAppDataFolder(); if (_diskProvider.FolderExists(backupFolderAppData)) { _diskProvider.EmptyFolder(backupFolderAppData); } else { _diskProvider.CreateFolder(backupFolderAppData); } try { _diskTransferService.TransferFile(_appFolderInfo.GetConfigPath(), _appFolderInfo.GetUpdateBackupConfigFile(), TransferMode.Copy); _diskTransferService.TransferFile(_appFolderInfo.GetDatabase(), _appFolderInfo.GetUpdateBackupDatabase(), TransferMode.Copy); } catch (Exception e) { _logger.Error(e, "Couldn't create a data backup"); } }
private bool InstallUpdate(UpdatePackage updatePackage) { EnsureAppDataSafety(); if (OsInfo.IsWindows || _configFileProvider.UpdateMechanism != UpdateMechanism.Script) { var startupFolder = _appFolderInfo.StartUpFolder; var uiFolder = Path.Combine(startupFolder, "UI"); if (!_diskProvider.FolderWritable(startupFolder)) { throw new UpdateFolderNotWritableException("Cannot install update because startup folder '{0}' is not writable by the user '{1}'.", startupFolder, Environment.UserName); } if (!_diskProvider.FolderWritable(uiFolder)) { throw new UpdateFolderNotWritableException("Cannot install update because UI folder '{0}' is not writable by the user '{1}'.", uiFolder, Environment.UserName); } } if (_appFolderInfo.StartUpFolder.EndsWith("_output")) { _logger.ProgressDebug("Running in developer environment, not updating."); return(false); } var updateSandboxFolder = _appFolderInfo.GetUpdateSandboxFolder(); var packageDestination = Path.Combine(updateSandboxFolder, updatePackage.FileName); if (_diskProvider.FolderExists(updateSandboxFolder)) { _logger.Info("Deleting old update files"); _diskProvider.DeleteFolder(updateSandboxFolder, true); } _logger.ProgressInfo("Downloading update {0}", updatePackage.Version); _logger.Debug("Downloading update package from [{0}] to [{1}]", updatePackage.Url, packageDestination); _httpClient.DownloadFile(updatePackage.Url, packageDestination); _logger.ProgressInfo("Verifying update package"); if (!_updateVerifier.Verify(updatePackage, packageDestination)) { _logger.Error("Update package is invalid"); throw new UpdateVerificationFailedException("Update file '{0}' is invalid", packageDestination); } _logger.Info("Update package verified successfully"); _logger.ProgressInfo("Extracting Update package"); _archiveService.Extract(packageDestination, updateSandboxFolder); _logger.Info("Update package extracted successfully"); EnsureValidBranch(updatePackage); _backupService.Backup(BackupType.Update); if (OsInfo.IsNotWindows && _configFileProvider.UpdateMechanism == UpdateMechanism.Script) { InstallUpdateWithScript(updateSandboxFolder); return(true); } _logger.Info("Preparing client"); _diskTransferService.TransferFolder(_appFolderInfo.GetUpdateClientFolder(), updateSandboxFolder, TransferMode.Move); _logger.Info("Starting update client {0}", _appFolderInfo.GetUpdateClientExePath()); _logger.ProgressInfo("Sonarr will restart shortly."); _processProvider.Start(_appFolderInfo.GetUpdateClientExePath(), GetUpdaterArgs(updateSandboxFolder)); return(true); }
public void Handle(SeriesScannedEvent message) { if (!_diskProvider.FolderExists(message.Series.Path)) { return; } _logger.Debug("Looking for existing metadata in {0}", message.Series.Path); var filesOnDisk = _diskProvider.GetFiles(message.Series.Path, SearchOption.AllDirectories); var possibleMetadataFiles = filesOnDisk.Where(c => !MediaFileExtensions.Extensions.Contains(Path.GetExtension(c).ToLower()) && !c.StartsWith(Path.Combine(message.Series.Path, "EXTRAS"))).ToList(); var filteredFiles = _metadataFileService.FilterExistingFiles(possibleMetadataFiles, message.Series); var metadataFiles = new List <MetadataFile>(); foreach (var possibleMetadataFile in filteredFiles) { foreach (var consumer in _consumers) { var metadata = consumer.FindMetadataFile(message.Series, possibleMetadataFile); if (metadata == null) { continue; } if (metadata.Type == MetadataType.EpisodeImage || metadata.Type == MetadataType.EpisodeMetadata) { try { var localEpisode = _parsingService.GetLocalEpisode(possibleMetadataFile, message.Series, false); if (localEpisode == null) { _logger.Debug("Unable to parse meta data file: {0}", possibleMetadataFile); break; } if (localEpisode.Episodes.DistinctBy(e => e.EpisodeFileId).Count() > 1) { _logger.Debug("Metadata file: {0} does not match existing files.", possibleMetadataFile); break; } metadata.EpisodeFileId = localEpisode.Episodes.First().EpisodeFileId; } catch (EpisodeNotFoundException e) { _logger.Debug("Cannot find related episodes for: {0}", possibleMetadataFile); continue; } } metadataFiles.Add(metadata); } } _metadataFileService.Upsert(metadataFiles); }
private MovieFile TransferFile(MovieFile movieFile, Movie movie, string destinationFilePath, TransferMode mode) { Ensure.That(movieFile, () => movieFile).IsNotNull(); Ensure.That(movie, () => movie).IsNotNull(); Ensure.That(destinationFilePath, () => destinationFilePath).IsValidPath(); var movieFilePath = movieFile.Path ?? Path.Combine(movie.Path, movieFile.RelativePath); if (!_diskProvider.FileExists(movieFilePath)) { throw new FileNotFoundException("Movie file path does not exist", movieFilePath); } if (movieFilePath == destinationFilePath) { throw new SameFilenameException("File not moved, source and destination are the same", movieFilePath); } _diskTransferService.TransferFile(movieFilePath, destinationFilePath, mode); var oldMoviePath = movie.Path; var newMoviePath = new OsPath(destinationFilePath).Directory.FullPath.TrimEnd(Path.DirectorySeparatorChar); movie.Path = newMoviePath; //We update it when everything went well! movieFile.RelativePath = movie.Path.GetRelativePath(destinationFilePath); _updateMovieFileService.ChangeFileDateForFile(movieFile, movie); try { _mediaFileAttributeService.SetFolderLastWriteTime(movie.Path, movieFile.DateAdded); } catch (Exception ex) { _logger.Warn(ex, "Unable to set last write time"); } _mediaFileAttributeService.SetFilePermissions(destinationFilePath); if (oldMoviePath != newMoviePath && _diskProvider.FolderExists(oldMoviePath)) { //Let's move the old files before deleting the old folder. We could just do move folder, but the main file (movie file) is already moved, so eh. var files = _diskProvider.GetFiles(oldMoviePath, SearchOption.AllDirectories); foreach (var file in files) { try { var destFile = Path.Combine(newMoviePath, oldMoviePath.GetRelativePath(file)); _diskProvider.EnsureFolder(Path.GetDirectoryName(destFile)); _diskProvider.MoveFile(file, destFile); } catch (Exception e) { _logger.Warn(e, "Error while trying to move extra file {0} to new folder. Maybe it already exists? (Manual cleanup necessary!).", oldMoviePath.GetRelativePath(file)); } } if (_diskProvider.GetFiles(oldMoviePath, SearchOption.AllDirectories).Count() == 0) { _recycleBinProvider.DeleteFolder(oldMoviePath); } } //Only update the movie path if we were successfull! if (oldMoviePath != newMoviePath) { _movieService.UpdateMovie(movie); } return(movieFile); }
public void Execute(ManualImportCommand message) { _logger.ProgressTrace("Manually importing {0} files using mode {1}", message.Files.Count, message.ImportMode); var imported = new List<ImportResult>(); var importedTrackedDownload = new List<ManuallyImportedFile>(); for (int i = 0; i < message.Files.Count; i++) { _logger.ProgressTrace("Processing file {0} of {1}", i + 1, message.Files.Count); var file = message.Files[i]; var movie = _movieService.GetMovie(file.MovieId); var fileMovieInfo = Parser.Parser.ParseMoviePath(file.Path) ?? new ParsedMovieInfo(); var existingFile = movie.Path.IsParentPath(file.Path); TrackedDownload trackedDownload = null; var localMovie = new LocalMovie { ExistingFile = false, FileMovieInfo = fileMovieInfo, Path = file.Path, Quality = file.Quality, Languages = file.Languages, Movie = movie, Size = 0 }; if (file.DownloadId.IsNotNullOrWhiteSpace()) { trackedDownload = _trackedDownloadService.Find(file.DownloadId); localMovie.DownloadClientMovieInfo = trackedDownload?.RemoteMovie?.ParsedMovieInfo; } if (file.FolderName.IsNotNullOrWhiteSpace()) { localMovie.FolderMovieInfo = Parser.Parser.ParseMovieTitle(file.FolderName); localMovie.SceneSource = !existingFile; } localMovie = _aggregationService.Augment(localMovie, trackedDownload?.DownloadItem, false); // Apply the user-chosen values. localMovie.Movie = movie; localMovie.Quality = file.Quality; localMovie.Languages = file.Languages; //TODO: Cleanup non-tracked downloads var importDecision = new ImportDecision(localMovie); if (trackedDownload == null) { imported.AddRange(_importApprovedMovie.Import(new List<ImportDecision> { importDecision }, !existingFile, null, message.ImportMode)); } else { var importResult = _importApprovedMovie.Import(new List<ImportDecision> { importDecision }, true, trackedDownload.DownloadItem, message.ImportMode).First(); imported.Add(importResult); importedTrackedDownload.Add(new ManuallyImportedFile { TrackedDownload = trackedDownload, ImportResult = importResult }); } } _logger.ProgressTrace("Manually imported {0} files", imported.Count); foreach (var groupedTrackedDownload in importedTrackedDownload.GroupBy(i => i.TrackedDownload.DownloadItem.DownloadId).ToList()) { var trackedDownload = groupedTrackedDownload.First().TrackedDownload; var importMovie = groupedTrackedDownload.First().ImportResult.ImportDecision.LocalMovie.Movie; var outputPath = trackedDownload.ImportItem.OutputPath.FullPath; if (_diskProvider.FolderExists(outputPath)) { if (_downloadedMovieImportService.ShouldDeleteFolder( new DirectoryInfo(outputPath), importMovie) && trackedDownload.DownloadItem.CanMoveFiles) { _diskProvider.DeleteFolder(outputPath, true); } } if (groupedTrackedDownload.Select(c => c.ImportResult).Any(c => c.Result == ImportResultType.Imported)) { trackedDownload.State = TrackedDownloadState.Imported; _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, importMovie.Id)); } } }
public void Scan(Series series) { var rootFolder = _rootFolderService.GetBestRootFolderPath(series.Path); var seriesFolderExists = _diskProvider.FolderExists(series.Path); if (!seriesFolderExists) { if (!_diskProvider.FolderExists(rootFolder)) { _logger.Warn("Series' root folder ({0}) doesn't exist.", rootFolder); _eventAggregator.PublishEvent(new SeriesScanSkippedEvent(series, SeriesScanSkippedReason.RootFolderDoesNotExist)); return; } if (_diskProvider.FolderEmpty(rootFolder)) { _logger.Warn("Series' root folder ({0}) is empty.", rootFolder); _eventAggregator.PublishEvent(new SeriesScanSkippedEvent(series, SeriesScanSkippedReason.RootFolderIsEmpty)); return; } } _logger.ProgressInfo("Scanning {0}", series.Title); if (!seriesFolderExists) { if (_configService.CreateEmptySeriesFolders) { if (_configService.DeleteEmptyFolders) { _logger.Debug("Not creating missing series folder: {0} because delete empty series folders is enabled", series.Path); } else { _logger.Debug("Creating missing series folder: {0}", series.Path); _diskProvider.CreateFolder(series.Path); SetPermissions(series.Path); } } else { _logger.Debug("Series folder doesn't exist: {0}", series.Path); } CleanMediaFiles(series, new List <string>()); CompletedScanning(series); return; } var videoFilesStopwatch = Stopwatch.StartNew(); var mediaFileList = FilterPaths(series.Path, GetVideoFiles(series.Path)).ToList(); videoFilesStopwatch.Stop(); _logger.Trace("Finished getting episode files for: {0} [{1}]", series, videoFilesStopwatch.Elapsed); CleanMediaFiles(series, mediaFileList); var decisionsStopwatch = Stopwatch.StartNew(); var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, series); decisionsStopwatch.Stop(); _logger.Trace("Import decisions complete for: {0} [{1}]", series, decisionsStopwatch.Elapsed); _importApprovedEpisodes.Import(decisions, false); RemoveEmptySeriesFolder(series.Path); CompletedScanning(series); }
public void Scan(Artist artist, FilterFilesType filter = FilterFilesType.Known) { var rootFolder = _rootFolderService.GetBestRootFolderPath(artist.Path); if (!_diskProvider.FolderExists(rootFolder)) { _logger.Warn("Artist' root folder ({0}) doesn't exist.", rootFolder); _eventAggregator.PublishEvent(new ArtistScanSkippedEvent(artist, ArtistScanSkippedReason.RootFolderDoesNotExist)); return; } if (_diskProvider.GetDirectories(rootFolder).Empty()) { _logger.Warn("Artist' root folder ({0}) is empty.", rootFolder); _eventAggregator.PublishEvent(new ArtistScanSkippedEvent(artist, ArtistScanSkippedReason.RootFolderIsEmpty)); return; } _logger.ProgressInfo("Scanning {0}", artist.Name); if (!_diskProvider.FolderExists(artist.Path)) { if (_configService.CreateEmptyArtistFolders) { _logger.Debug("Creating missing artist folder: {0}", artist.Path); _diskProvider.CreateFolder(artist.Path); SetPermissions(artist.Path); } else { _logger.Debug("Artist folder doesn't exist: {0}", artist.Path); } CleanMediaFiles(artist, new List <string>()); CompletedScanning(artist); return; } var musicFilesStopwatch = Stopwatch.StartNew(); var mediaFileList = FilterFiles(artist.Path, GetAudioFiles(artist.Path)).ToList(); musicFilesStopwatch.Stop(); _logger.Trace("Finished getting track files for: {0} [{1}]", artist, musicFilesStopwatch.Elapsed); CleanMediaFiles(artist, mediaFileList.Select(x => x.FullName).ToList()); var decisionsStopwatch = Stopwatch.StartNew(); var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, artist, filter, true); decisionsStopwatch.Stop(); _logger.Debug("Import decisions complete for: {0} [{1}]", artist, decisionsStopwatch.Elapsed); var importStopwatch = Stopwatch.StartNew(); _importApprovedTracks.Import(decisions, false); // decisions may have been filtered to just new files. Anything new and approved will have been inserted. // Now we need to make sure anything new but not approved gets inserted // Note that knownFiles will include anything imported just now var knownFiles = _mediaFileService.GetFilesWithBasePath(artist.Path); var newFiles = decisions .ExceptBy(x => x.Item.Path, knownFiles, x => x.Path, PathEqualityComparer.Instance) .Select(decision => new TrackFile { Path = decision.Item.Path, Size = decision.Item.Size, Modified = decision.Item.Modified, DateAdded = DateTime.UtcNow, Quality = decision.Item.Quality, MediaInfo = decision.Item.FileTrackInfo.MediaInfo }) .ToList(); _mediaFileService.AddMany(newFiles); _logger.Debug($"Inserted {newFiles.Count} new unmatched trackfiles"); // finally update info on size/modified for existing files var updatedFiles = knownFiles .Join(decisions, x => x.Path, x => x.Item.Path, (file, decision) => new { File = file, Item = decision.Item }, PathEqualityComparer.Instance) .Where(x => x.File.Size != x.Item.Size || Math.Abs((x.File.Modified - x.Item.Modified).TotalSeconds) > 1) .Select(x => { x.File.Size = x.Item.Size; x.File.Modified = x.Item.Modified; x.File.MediaInfo = x.Item.FileTrackInfo.MediaInfo; x.File.Quality = x.Item.Quality; return(x.File); }) .ToList(); _mediaFileService.Update(updatedFiles); _logger.Debug($"Updated info for {updatedFiles.Count} known files"); RemoveEmptyArtistFolder(artist.Path); CompletedScanning(artist); importStopwatch.Stop(); _logger.Debug("Track import complete for: {0} [{1}]", artist, importStopwatch.Elapsed); }
public override HealthCheck Check() { // We don't care about client folders if we are not handling completed files if (!_configService.EnableCompletedDownloadHandling) { return(new HealthCheck(GetType())); } var clients = _downloadClientProvider.GetDownloadClients(); foreach (var client in clients) { try { var status = client.GetStatus(); var folders = status.OutputRootFolders; foreach (var folder in folders) { if (!folder.IsValid) { if (!status.IsLocalhost) { return(new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckWrongOSPath"), client.Definition.Name, folder.FullPath, _osInfo.Name), "#bad_remote_path_mapping")); } else if (_osInfo.IsDocker) { return(new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckBadDockerPath"), client.Definition.Name, folder.FullPath, _osInfo.Name), "#docker_bad_remote_path_mapping")); } else { return(new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckLocalWrongOSPath"), client.Definition.Name, folder.FullPath, _osInfo.Name), "#bad_download_client_settings")); } } if (!_diskProvider.FolderExists(folder.FullPath)) { if (_osInfo.IsDocker) { return(new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckDockerFolderMissing"), client.Definition.Name, folder.FullPath), "#docker_bad_remote_path_mapping")); } else if (!status.IsLocalhost) { return(new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckLocalFolderMissing"), client.Definition.Name, folder.FullPath), "#bad_remote_path_mapping")); } else { return(new HealthCheck(GetType(), HealthCheckResult.Error, string.Format(_localizationService.GetLocalizedString("RemotePathMappingCheckGenericPermissions"), client.Definition.Name, folder.FullPath), "#permissions_error")); } } } } catch (DownloadClientException ex) { _logger.Debug(ex, "Unable to communicate with {0}", client.Definition.Name); } catch (Exception ex) { _logger.Error(ex, "Unknown error occured in RemotePathMapping HealthCheck"); } } return(new HealthCheck(GetType())); }
public void Scan(List <string> folders = null, FilterFilesType filter = FilterFilesType.Known, bool addNewAuthors = false, List <int> authorIds = null) { if (folders == null) { folders = _rootFolderService.All().Select(x => x.Path).ToList(); } if (authorIds == null) { authorIds = new List <int>(); } var mediaFileList = new List <IFileInfo>(); var musicFilesStopwatch = Stopwatch.StartNew(); foreach (var folder in folders) { // We could be scanning a root folder or a subset of a root folder. If it's a subset, // check if the root folder exists before cleaning. var rootFolder = _rootFolderService.GetBestRootFolder(folder); if (rootFolder == null) { _logger.Error("Not scanning {0}, it's not a subdirectory of a defined root folder", folder); return; } var folderExists = _diskProvider.FolderExists(folder); if (!folderExists) { if (!_diskProvider.FolderExists(rootFolder.Path)) { _logger.Warn("Authors' root folder ({0}) doesn't exist.", rootFolder); var skippedAuthors = _authorService.GetAuthors(authorIds); skippedAuthors.ForEach(x => _eventAggregator.PublishEvent(new AuthorScanSkippedEvent(x, AuthorScanSkippedReason.RootFolderDoesNotExist))); return; } if (_diskProvider.FolderEmpty(rootFolder.Path)) { _logger.Warn("Authors' root folder ({0}) is empty.", rootFolder); var skippedAuthors = _authorService.GetAuthors(authorIds); skippedAuthors.ForEach(x => _eventAggregator.PublishEvent(new AuthorScanSkippedEvent(x, AuthorScanSkippedReason.RootFolderIsEmpty))); return; } } if (!folderExists) { _logger.Debug("Specified scan folder ({0}) doesn't exist.", folder); CleanMediaFiles(folder, new List <string>()); continue; } _logger.ProgressInfo("Scanning {0}", folder); var files = FilterFiles(folder, GetBookFiles(folder)); if (!files.Any()) { _logger.Warn("Scan folder {0} is empty.", folder); continue; } CleanMediaFiles(folder, files.Select(x => x.FullName).ToList()); mediaFileList.AddRange(files); } musicFilesStopwatch.Stop(); _logger.Trace("Finished getting track files for:\n{0} [{1}]", folders.ConcatToString("\n"), musicFilesStopwatch.Elapsed); var decisionsStopwatch = Stopwatch.StartNew(); var config = new ImportDecisionMakerConfig { Filter = filter, IncludeExisting = true, AddNewAuthors = addNewAuthors }; var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, null, null, config); decisionsStopwatch.Stop(); _logger.Debug("Import decisions complete [{0}]", decisionsStopwatch.Elapsed); var importStopwatch = Stopwatch.StartNew(); _importApprovedTracks.Import(decisions, false); // decisions may have been filtered to just new files. Anything new and approved will have been inserted. // Now we need to make sure anything new but not approved gets inserted // Note that knownFiles will include anything imported just now var knownFiles = new List <BookFile>(); folders.ForEach(x => knownFiles.AddRange(_mediaFileService.GetFilesWithBasePath(x))); var newFiles = decisions .ExceptBy(x => x.Item.Path, knownFiles, x => x.Path, PathEqualityComparer.Instance) .Select(decision => new BookFile { Path = decision.Item.Path, CalibreId = decision.Item.Path.ParseCalibreId(), Size = decision.Item.Size, Modified = decision.Item.Modified, DateAdded = DateTime.UtcNow, Quality = decision.Item.Quality, MediaInfo = decision.Item.FileTrackInfo.MediaInfo, Edition = decision.Item.Edition }) .ToList(); _mediaFileService.AddMany(newFiles); _logger.Debug($"Inserted {newFiles.Count} new unmatched trackfiles"); // finally update info on size/modified for existing files var updatedFiles = knownFiles .Join(decisions, x => x.Path, x => x.Item.Path, (file, decision) => new { File = file, Item = decision.Item }, PathEqualityComparer.Instance) .Where(x => x.File.Size != x.Item.Size || Math.Abs((x.File.Modified - x.Item.Modified).TotalSeconds) > 1) .Select(x => { x.File.Size = x.Item.Size; x.File.Modified = x.Item.Modified; x.File.MediaInfo = x.Item.FileTrackInfo.MediaInfo; x.File.Quality = x.Item.Quality; return(x.File); }) .ToList(); _mediaFileService.Update(updatedFiles); _logger.Debug($"Updated info for {updatedFiles.Count} known files"); var authors = _authorService.GetAuthors(authorIds); foreach (var author in authors) { CompletedScanning(author); } importStopwatch.Stop(); _logger.Debug("Book import complete for:\n{0} [{1}]", folders.ConcatToString("\n"), importStopwatch.Elapsed); }
public override HealthCheck Check() { // We don't care about client folders if we are not handling completed files if (!_configService.EnableCompletedDownloadHandling) { return(new HealthCheck(GetType())); } var clients = _downloadClientProvider.GetDownloadClients(); foreach (var client in clients) { try { var status = client.GetStatus(); var folders = status.OutputRootFolders; if (folders != null) { foreach (var folder in folders) { if (!folder.IsValid) { if (!status.IsLocalhost) { return(new HealthCheck(GetType(), HealthCheckResult.Error, $"Remote download client {client.Definition.Name} places downloads in {folder.FullPath} but this is not a valid {_osInfo.Name} path. Review your remote path mappings and download client settings.", "#bad_remote_path_mapping")); } else if (_osInfo.IsDocker) { return(new HealthCheck(GetType(), HealthCheckResult.Error, $"You are using docker; download client {client.Definition.Name} places downloads in {folder.FullPath} but this is not a valid {_osInfo.Name} path. Review your remote path mappings and download client settings.", "#docker_bad_remote_path_mapping")); } else { return(new HealthCheck(GetType(), HealthCheckResult.Error, $"Local download client {client.Definition.Name} places downloads in {folder.FullPath} but this is not a valid {_osInfo.Name} path. Review your download client settings.", "#bad_download_client_settings")); } } if (!_diskProvider.FolderExists(folder.FullPath)) { if (_osInfo.IsDocker) { return(new HealthCheck(GetType(), HealthCheckResult.Error, $"You are using docker; download client {client.Definition.Name} places downloads in {folder.FullPath} but this directory does not appear to exist inside the container. Review your remote path mappings and container volume settings.", "#docker_bad_remote_path_mapping")); } else if (!status.IsLocalhost) { return(new HealthCheck(GetType(), HealthCheckResult.Error, $"Remote download client {client.Definition.Name} places downloads in {folder.FullPath} but this directory does not appear to exist. Likely missing or incorrect remote path mapping.", "#bad_remote_path_mapping")); } else { return(new HealthCheck(GetType(), HealthCheckResult.Error, $"Download client {client.Definition.Name} places downloads in {folder.FullPath} but Lidarr cannot see this directory. You may need to adjust the folder's permissions.", "#permissions_error")); } } } } } catch (DownloadClientException ex) { _logger.Debug(ex, "Unable to communicate with {0}", client.Definition.Name); } catch (Exception ex) { _logger.Error(ex, "Unknown error occured in RemotePathMapping HealthCheck"); } } return(new HealthCheck(GetType())); }
private EpisodeFile TransferFile(EpisodeFile episodeFile, Series series, List <Episode> episodes, String destinationFilename, Boolean copyOnly) { Ensure.That(episodeFile, () => episodeFile).IsNotNull(); Ensure.That(series, () => series).IsNotNull(); Ensure.That(destinationFilename, () => destinationFilename).IsValidPath(); var episodeFilePath = episodeFile.Path ?? Path.Combine(series.Path, episodeFile.RelativePath); if (!_diskProvider.FileExists(episodeFilePath)) { throw new FileNotFoundException("Episode file path does not exist", episodeFilePath); } if (episodeFilePath.PathEquals(destinationFilename)) { throw new SameFilenameException("File not moved, source and destination are the same", episodeFilePath); } var directoryName = new FileInfo(destinationFilename).DirectoryName; if (!_diskProvider.FolderExists(directoryName)) { try { _diskProvider.CreateFolder(directoryName); } catch (IOException ex) { _logger.ErrorException("Unable to create directory: " + directoryName, ex); } SetFolderPermissions(directoryName); if (!directoryName.PathEquals(series.Path)) { SetFolderPermissions(series.Path); } } if (copyOnly) { _logger.Debug("Copying [{0}] > [{1}]", episodeFilePath, destinationFilename); _diskProvider.CopyFile(episodeFilePath, destinationFilename); } else { _logger.Debug("Moving [{0}] > [{1}]", episodeFilePath, destinationFilename); _diskProvider.MoveFile(episodeFilePath, destinationFilename); } episodeFile.RelativePath = series.Path.GetRelativePath(destinationFilename); _updateEpisodeFileService.ChangeFileDateForFile(episodeFile, series, episodes); try { SetFolderLastWriteTime(series.Path, episodeFile.DateAdded); if (series.SeasonFolder) { var seasonFolder = Path.GetDirectoryName(destinationFilename); SetFolderLastWriteTime(seasonFolder, episodeFile.DateAdded); } } catch (Exception ex) { _logger.WarnException("Unable to set last write time", ex); } //We should only run this on Windows if (OsInfo.IsWindows) { //Wrapped in Try/Catch to prevent this from causing issues with remote NAS boxes, the move worked, which is more important. try { _diskProvider.InheritFolderPermissions(destinationFilename); } catch (Exception ex) { if (ex is UnauthorizedAccessException || ex is InvalidOperationException) { _logger.Debug("Unable to apply folder permissions to: ", destinationFilename); _logger.DebugException(ex.Message, ex); } else { throw; } } } else { SetPermissions(destinationFilename, _configService.FileChmod); } return(episodeFile); }