jellyfin-server/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs
softworkz 66a80ac6b9 EpisodeFileOrganizer: Improve error handling (alternate approach)
Previously some methods were just returning null or empty values in case
of encountered errors; as a consequence, the actual reason for failure
was never written to the auto-organize log.
Instead, only a generic message like "Unable to sort xxx because target
path could not be determined." was displayed.

After this change, the actual reason for failure will be saved to the
auto-organize log or displayed in the UI (when completing the organize
dialog).

This information is very important for the user. Examples are "No
permission", "Target folder not available", "Disk full", etc..
2016-08-18 22:05:54 +02:00

194 lines
6.5 KiB
C#

using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.FileOrganization;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.FileOrganization;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Querying;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
namespace MediaBrowser.Server.Implementations.FileOrganization
{
public class FileOrganizationService : IFileOrganizationService
{
private readonly ITaskManager _taskManager;
private readonly IFileOrganizationRepository _repo;
private readonly ILogger _logger;
private readonly ILibraryMonitor _libraryMonitor;
private readonly ILibraryManager _libraryManager;
private readonly IServerConfigurationManager _config;
private readonly IFileSystem _fileSystem;
private readonly IProviderManager _providerManager;
public FileOrganizationService(ITaskManager taskManager, IFileOrganizationRepository repo, ILogger logger, ILibraryMonitor libraryMonitor, ILibraryManager libraryManager, IServerConfigurationManager config, IFileSystem fileSystem, IProviderManager providerManager)
{
_taskManager = taskManager;
_repo = repo;
_logger = logger;
_libraryMonitor = libraryMonitor;
_libraryManager = libraryManager;
_config = config;
_fileSystem = fileSystem;
_providerManager = providerManager;
}
public void BeginProcessNewFiles()
{
_taskManager.CancelIfRunningAndQueue<OrganizerScheduledTask>();
}
public Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken)
{
if (result == null || string.IsNullOrEmpty(result.OriginalPath))
{
throw new ArgumentNullException("result");
}
result.Id = result.OriginalPath.GetMD5().ToString("N");
return _repo.SaveResult(result, cancellationToken);
}
public QueryResult<FileOrganizationResult> GetResults(FileOrganizationResultQuery query)
{
return _repo.GetResults(query);
}
public FileOrganizationResult GetResult(string id)
{
return _repo.GetResult(id);
}
public FileOrganizationResult GetResultBySourcePath(string path)
{
if (string.IsNullOrEmpty(path))
{
throw new ArgumentNullException("path");
}
var id = path.GetMD5().ToString("N");
return GetResult(id);
}
public Task DeleteOriginalFile(string resultId)
{
var result = _repo.GetResult(resultId);
_logger.Info("Requested to delete {0}", result.OriginalPath);
try
{
_fileSystem.DeleteFile(result.OriginalPath);
}
catch (Exception ex)
{
_logger.ErrorException("Error deleting {0}", ex, result.OriginalPath);
}
return _repo.Delete(resultId);
}
private AutoOrganizeOptions GetAutoOrganizeOptions()
{
return _config.GetAutoOrganizeOptions();
}
public async Task PerformOrganization(string resultId)
{
var result = _repo.GetResult(resultId);
if (string.IsNullOrEmpty(result.TargetPath))
{
throw new ArgumentException("No target path available.");
}
var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
_libraryMonitor, _providerManager);
var organizeResult = await organizer.OrganizeEpisodeFile(result.OriginalPath, GetAutoOrganizeOptions(), true, CancellationToken.None)
.ConfigureAwait(false);
if (organizeResult.Status != FileSortingStatus.Success)
{
throw new Exception(result.StatusMessage);
}
}
public Task ClearLog()
{
return _repo.DeleteAll();
}
public async Task PerformEpisodeOrganization(EpisodeFileOrganizationRequest request)
{
var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
_libraryMonitor, _providerManager);
var result = await organizer.OrganizeWithCorrection(request, GetAutoOrganizeOptions(), CancellationToken.None).ConfigureAwait(false);
if (result.Status != FileSortingStatus.Success)
{
throw new Exception(result.StatusMessage);
}
}
public QueryResult<SmartMatchInfo> GetSmartMatchInfos(FileOrganizationResultQuery query)
{
if (query == null)
{
throw new ArgumentNullException("query");
}
var options = GetAutoOrganizeOptions();
var items = options.SmartMatchInfos.Skip(query.StartIndex ?? 0).Take(query.Limit ?? Int32.MaxValue).ToArray();
return new QueryResult<SmartMatchInfo>()
{
Items = items,
TotalRecordCount = options.SmartMatchInfos.Length
};
}
public void DeleteSmartMatchEntry(string itemName, string matchString)
{
if (string.IsNullOrEmpty(itemName))
{
throw new ArgumentNullException("itemName");
}
if (string.IsNullOrEmpty(matchString))
{
throw new ArgumentNullException("matchString");
}
var options = GetAutoOrganizeOptions();
SmartMatchInfo info = options.SmartMatchInfos.FirstOrDefault(i => string.Equals(i.ItemName, itemName));
if (info != null && info.MatchStrings.Contains(matchString))
{
var list = info.MatchStrings.ToList();
list.Remove(matchString);
info.MatchStrings = list.ToArray();
if (info.MatchStrings.Length == 0)
{
var infos = options.SmartMatchInfos.ToList();
infos.Remove(info);
options.SmartMatchInfos = infos.ToArray();
}
_config.SaveAutoOrganizeOptions(options);
}
}
}
}