diff options
Diffstat (limited to 'Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs')
| -rw-r--r-- | Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs b/Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs new file mode 100644 index 000000000..2850c3a61 --- /dev/null +++ b/Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs @@ -0,0 +1,210 @@ +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.FileOrganization; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.FileOrganization; +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.IO; + +namespace Emby.Server.Implementations.FileOrganization +{ + public class TvFolderOrganizer + { + private readonly ILibraryMonitor _libraryMonitor; + private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; + private readonly IFileSystem _fileSystem; + private readonly IFileOrganizationService _organizationService; + private readonly IServerConfigurationManager _config; + private readonly IProviderManager _providerManager; + + public TvFolderOrganizer(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, ILibraryMonitor libraryMonitor, IFileOrganizationService organizationService, IServerConfigurationManager config, IProviderManager providerManager) + { + _libraryManager = libraryManager; + _logger = logger; + _fileSystem = fileSystem; + _libraryMonitor = libraryMonitor; + _organizationService = organizationService; + _config = config; + _providerManager = providerManager; + } + + private bool EnableOrganization(FileSystemMetadata fileInfo, TvFileOrganizationOptions options) + { + var minFileBytes = options.MinFileSizeMb * 1024 * 1024; + + try + { + return _libraryManager.IsVideoFile(fileInfo.FullName) && fileInfo.Length >= minFileBytes; + } + catch (Exception ex) + { + _logger.ErrorException("Error organizing file {0}", ex, fileInfo.Name); + } + + return false; + } + + public async Task Organize(AutoOrganizeOptions options, CancellationToken cancellationToken, IProgress<double> progress) + { + var watchLocations = options.TvOptions.WatchLocations.ToList(); + + var eligibleFiles = watchLocations.SelectMany(GetFilesToOrganize) + .OrderBy(_fileSystem.GetCreationTimeUtc) + .Where(i => EnableOrganization(i, options.TvOptions)) + .ToList(); + + var processedFolders = new HashSet<string>(); + + progress.Report(10); + + if (eligibleFiles.Count > 0) + { + var numComplete = 0; + + foreach (var file in eligibleFiles) + { + var organizer = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager, + _libraryMonitor, _providerManager); + + try + { + var result = await organizer.OrganizeEpisodeFile(file.FullName, options, options.TvOptions.OverwriteExistingEpisodes, cancellationToken).ConfigureAwait(false); + if (result.Status == FileSortingStatus.Success && !processedFolders.Contains(file.DirectoryName, StringComparer.OrdinalIgnoreCase)) + { + processedFolders.Add(file.DirectoryName); + } + } + catch (Exception ex) + { + _logger.ErrorException("Error organizing episode {0}", ex, file.FullName); + } + + numComplete++; + double percent = numComplete; + percent /= eligibleFiles.Count; + + progress.Report(10 + 89 * percent); + } + } + + cancellationToken.ThrowIfCancellationRequested(); + progress.Report(99); + + foreach (var path in processedFolders) + { + var deleteExtensions = options.TvOptions.LeftOverFileExtensionsToDelete + .Select(i => i.Trim().TrimStart('.')) + .Where(i => !string.IsNullOrEmpty(i)) + .Select(i => "." + i) + .ToList(); + + if (deleteExtensions.Count > 0) + { + DeleteLeftOverFiles(path, deleteExtensions); + } + + if (options.TvOptions.DeleteEmptyFolders) + { + if (!IsWatchFolder(path, watchLocations)) + { + DeleteEmptyFolders(path); + } + } + } + + progress.Report(100); + } + + /// <summary> + /// Gets the files to organize. + /// </summary> + /// <param name="path">The path.</param> + /// <returns>IEnumerable{FileInfo}.</returns> + private List<FileSystemMetadata> GetFilesToOrganize(string path) + { + try + { + return _fileSystem.GetFiles(path, true) + .ToList(); + } + catch (IOException ex) + { + _logger.ErrorException("Error getting files from {0}", ex, path); + + return new List<FileSystemMetadata>(); + } + } + + /// <summary> + /// Deletes the left over files. + /// </summary> + /// <param name="path">The path.</param> + /// <param name="extensions">The extensions.</param> + private void DeleteLeftOverFiles(string path, IEnumerable<string> extensions) + { + var eligibleFiles = _fileSystem.GetFiles(path, true) + .Where(i => extensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase)) + .ToList(); + + foreach (var file in eligibleFiles) + { + try + { + _fileSystem.DeleteFile(file.FullName); + } + catch (Exception ex) + { + _logger.ErrorException("Error deleting file {0}", ex, file.FullName); + } + } + } + + /// <summary> + /// Deletes the empty folders. + /// </summary> + /// <param name="path">The path.</param> + private void DeleteEmptyFolders(string path) + { + try + { + foreach (var d in _fileSystem.GetDirectoryPaths(path)) + { + DeleteEmptyFolders(d); + } + + var entries = _fileSystem.GetFileSystemEntryPaths(path); + + if (!entries.Any()) + { + try + { + _logger.Debug("Deleting empty directory {0}", path); + _fileSystem.DeleteDirectory(path, false); + } + catch (UnauthorizedAccessException) { } + catch (IOException) { } + } + } + catch (UnauthorizedAccessException) { } + } + + /// <summary> + /// Determines if a given folder path is contained in a folder list + /// </summary> + /// <param name="path">The folder path to check.</param> + /// <param name="watchLocations">A list of folders.</param> + private bool IsWatchFolder(string path, IEnumerable<string> watchLocations) + { + return watchLocations.Contains(path, StringComparer.OrdinalIgnoreCase); + } + } +}
\ No newline at end of file |
