mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-07-20 05:04:18 +01:00
#680 - episode organization
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.FileOrganization;
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
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;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.FileOrganization
|
||||
{
|
||||
public class TvFolderOrganizer
|
||||
{
|
||||
private readonly IDirectoryWatchers _directoryWatchers;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IFileOrganizationService _organizationService;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
public TvFolderOrganizer(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, IDirectoryWatchers directoryWatchers, IFileOrganizationService organizationService, IServerConfigurationManager config)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_logger = logger;
|
||||
_fileSystem = fileSystem;
|
||||
_directoryWatchers = directoryWatchers;
|
||||
_organizationService = organizationService;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public async Task Organize(TvFileOrganizationOptions options, CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
var minFileBytes = options.MinFileSizeMb * 1024 * 1024;
|
||||
|
||||
var watchLocations = options.WatchLocations.ToList();
|
||||
|
||||
var eligibleFiles = watchLocations.SelectMany(GetFilesToOrganize)
|
||||
.OrderBy(_fileSystem.GetCreationTimeUtc)
|
||||
.Where(i => EntityResolutionHelper.IsVideoFile(i.FullName) && i.Length >= minFileBytes)
|
||||
.ToList();
|
||||
|
||||
progress.Report(10);
|
||||
|
||||
var scanLibrary = false;
|
||||
|
||||
if (eligibleFiles.Count > 0)
|
||||
{
|
||||
var numComplete = 0;
|
||||
|
||||
foreach (var file in eligibleFiles)
|
||||
{
|
||||
var organizer = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager,
|
||||
_directoryWatchers);
|
||||
|
||||
var result = await organizer.OrganizeEpisodeFile(file.FullName, options, false).ConfigureAwait(false);
|
||||
|
||||
if (result.Status == FileSortingStatus.Success)
|
||||
{
|
||||
scanLibrary = true;
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= eligibleFiles.Count;
|
||||
|
||||
progress.Report(10 + (89 * percent));
|
||||
}
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
progress.Report(99);
|
||||
|
||||
foreach (var path in watchLocations)
|
||||
{
|
||||
if (options.LeftOverFileExtensionsToDelete.Length > 0)
|
||||
{
|
||||
DeleteLeftOverFiles(path, options.LeftOverFileExtensionsToDelete);
|
||||
}
|
||||
|
||||
if (options.DeleteEmptyFolders)
|
||||
{
|
||||
DeleteEmptyFolders(path);
|
||||
}
|
||||
}
|
||||
|
||||
if (scanLibrary)
|
||||
{
|
||||
await _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the files to organize.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns>IEnumerable{FileInfo}.</returns>
|
||||
private IEnumerable<FileInfo> GetFilesToOrganize(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new DirectoryInfo(path)
|
||||
.EnumerateFiles("*", SearchOption.AllDirectories)
|
||||
.ToList();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting files from {0}", ex, path);
|
||||
|
||||
return new List<FileInfo>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 = new DirectoryInfo(path)
|
||||
.EnumerateFiles("*", SearchOption.AllDirectories)
|
||||
.Where(i => extensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
|
||||
foreach (var file in eligibleFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(file.FullName);
|
||||
}
|
||||
catch (IOException 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 Directory.EnumerateDirectories(path))
|
||||
{
|
||||
DeleteEmptyFolders(d);
|
||||
}
|
||||
|
||||
var entries = Directory.EnumerateFileSystemEntries(path);
|
||||
|
||||
if (!entries.Any())
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(path);
|
||||
}
|
||||
catch (UnauthorizedAccessException) { }
|
||||
catch (DirectoryNotFoundException) { }
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user