2019-07-07 03:16:33 +00:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
using Roadie.Library;
|
|
|
|
|
using Roadie.Library.Caching;
|
|
|
|
|
using Roadie.Library.Configuration;
|
2019-11-17 14:10:17 +00:00
|
|
|
|
using Roadie.Library.Data.Context;
|
2019-07-07 03:16:33 +00:00
|
|
|
|
using Roadie.Library.Encoding;
|
|
|
|
|
using Roadie.Library.Engines;
|
|
|
|
|
using Roadie.Library.Extensions;
|
|
|
|
|
using Roadie.Library.FilePlugins;
|
|
|
|
|
using Roadie.Library.Identity;
|
|
|
|
|
using Roadie.Library.MetaData.Audio;
|
|
|
|
|
using Roadie.Library.Processors;
|
|
|
|
|
using Roadie.Library.Utility;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Linq.Dynamic.Core;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace Roadie.Api.Services
|
|
|
|
|
{
|
|
|
|
|
public class FileDirectoryProcessorService : ServiceBase, IFileDirectoryProcessorService
|
|
|
|
|
{
|
2020-06-07 22:46:24 +00:00
|
|
|
|
|
|
|
|
|
private IArtistLookupEngine ArtistLookupEngine { get; }
|
|
|
|
|
|
|
|
|
|
private IAudioMetaDataHelper AudioMetaDataHelper { get; }
|
|
|
|
|
|
|
|
|
|
private IFileProcessor FileProcessor { get; }
|
|
|
|
|
private IReleaseLookupEngine ReleaseLookupEngine { get; }
|
|
|
|
|
private IReleaseService ReleaseService { get; }
|
|
|
|
|
|
2019-07-07 03:16:33 +00:00
|
|
|
|
private List<int> _addedArtistIds = new List<int>();
|
|
|
|
|
private List<int> _addedReleaseIds = new List<int>();
|
|
|
|
|
private List<int> _addedTrackIds = new List<int>();
|
|
|
|
|
|
|
|
|
|
public IEnumerable<int> AddedArtistIds => _addedArtistIds.Distinct();
|
|
|
|
|
public IEnumerable<int> AddedReleaseIds => _addedReleaseIds.Distinct();
|
|
|
|
|
public IEnumerable<int> AddedTrackIds => _addedTrackIds.Distinct();
|
|
|
|
|
|
|
|
|
|
public int? ProcessLimit { get; set; }
|
|
|
|
|
|
|
|
|
|
public FileDirectoryProcessorService(IRoadieSettings configuration,
|
|
|
|
|
IHttpEncoder httpEncoder,
|
|
|
|
|
IHttpContext httpContext,
|
2019-11-17 14:10:17 +00:00
|
|
|
|
IRoadieDbContext context,
|
2019-07-07 03:16:33 +00:00
|
|
|
|
ICacheManager cacheManager,
|
|
|
|
|
ILogger<FileDirectoryProcessorService> logger,
|
|
|
|
|
IArtistLookupEngine artistLookupEngine,
|
|
|
|
|
IFileProcessor fileProcessor,
|
|
|
|
|
IReleaseLookupEngine releaseLookupEngine,
|
|
|
|
|
IAudioMetaDataHelper audioMetaDataHelper,
|
|
|
|
|
IReleaseService releaseService)
|
|
|
|
|
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
|
|
|
|
|
{
|
|
|
|
|
ArtistLookupEngine = artistLookupEngine;
|
|
|
|
|
AudioMetaDataHelper = audioMetaDataHelper;
|
|
|
|
|
ReleaseLookupEngine = releaseLookupEngine;
|
|
|
|
|
ReleaseService = releaseService;
|
|
|
|
|
FileProcessor = fileProcessor;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-07 22:46:24 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Perform any operations to the given folder and the plugin results after processing
|
|
|
|
|
/// </summary>
|
|
|
|
|
private async Task<bool> PostProcessFolderAsync(User user, DirectoryInfo inboundFolder, IEnumerable<PluginResultInfo> pluginResults, bool doJustInfo, bool doDeleteFiles = true)
|
|
|
|
|
{
|
|
|
|
|
SimpleContract.Requires<ArgumentNullException>(inboundFolder != null, "Invalid InboundFolder");
|
|
|
|
|
if (pluginResults != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var releasesInfo in pluginResults.GroupBy(x => x.ReleaseId).Select(x => x.First()))
|
|
|
|
|
{
|
|
|
|
|
await ReleaseService.ScanReleaseFolderAsync(user, releasesInfo.ReleaseId, doJustInfo).ConfigureAwait(false);
|
|
|
|
|
_addedTrackIds.AddRange(ReleaseService.AddedTrackIds);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!doJustInfo && doDeleteFiles)
|
|
|
|
|
{
|
|
|
|
|
var fileExtensionsToDelete = Configuration.FileExtensionsToDelete ?? new string[0];
|
|
|
|
|
if (fileExtensionsToDelete.Any())
|
|
|
|
|
{
|
|
|
|
|
foreach (var fileInFolder in inboundFolder.GetFiles("*.*", SearchOption.AllDirectories))
|
|
|
|
|
{
|
|
|
|
|
if (fileExtensionsToDelete.Any(x => x.Equals(fileInFolder.Extension, StringComparison.OrdinalIgnoreCase)))
|
|
|
|
|
{
|
|
|
|
|
if (!doJustInfo)
|
|
|
|
|
{
|
|
|
|
|
fileInFolder.Delete();
|
|
|
|
|
Logger.LogTrace("Deleted File [{0}], Was found in in FileExtensionsToDelete",
|
|
|
|
|
fileInFolder.Name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DeleteEmptyFolders(inboundFolder, Logger);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Perform any operations to the given folder before processing
|
|
|
|
|
/// </summary>
|
|
|
|
|
private Task<bool> PreProcessFolderAsync(DirectoryInfo inboundFolder, bool doJustInfo = false)
|
|
|
|
|
{
|
|
|
|
|
return Task.FromResult(true);
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-07 03:16:33 +00:00
|
|
|
|
public static OperationResult<bool> DeleteEmptyFolders(DirectoryInfo processingFolder, ILogger logger)
|
|
|
|
|
{
|
|
|
|
|
var result = new OperationResult<bool>();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
result.IsSuccess = FolderPathHelper.DeleteEmptyFolders(processingFolder);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2020-06-07 22:46:24 +00:00
|
|
|
|
logger.LogError(ex, $"Error Deleting Empty Folder [{processingFolder.FullName}] Error [{ex.Serialize()}]");
|
2019-07-07 03:16:33 +00:00
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-07 22:46:24 +00:00
|
|
|
|
public async Task<OperationResult<bool>> ProcessAsync(User user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null, bool doDeleteFiles = true)
|
2019-07-07 03:16:33 +00:00
|
|
|
|
{
|
|
|
|
|
var sw = new Stopwatch();
|
|
|
|
|
sw.Start();
|
2020-06-07 22:46:24 +00:00
|
|
|
|
await PreProcessFolderAsync(folder, doJustInfo).ConfigureAwait(false);
|
2019-07-07 03:16:33 +00:00
|
|
|
|
var processedFiles = 0;
|
|
|
|
|
var pluginResultInfos = new List<PluginResultInfo>();
|
|
|
|
|
var errors = new List<string>();
|
|
|
|
|
|
|
|
|
|
_addedArtistIds.Clear();
|
|
|
|
|
_addedReleaseIds.Clear();
|
|
|
|
|
_addedTrackIds.Clear();
|
|
|
|
|
|
|
|
|
|
FileProcessor.SubmissionId = submissionId;
|
|
|
|
|
|
2020-06-07 22:46:24 +00:00
|
|
|
|
foreach (var file in Directory.EnumerateFiles(folder.FullName, "*.*", SearchOption.AllDirectories) .ToArray())
|
2019-07-07 03:16:33 +00:00
|
|
|
|
{
|
2020-06-07 22:46:24 +00:00
|
|
|
|
var operation = await FileProcessor.Process(file, doJustInfo).ConfigureAwait(false);
|
2019-07-07 03:16:33 +00:00
|
|
|
|
if (operation != null && operation.AdditionalData != null &&
|
|
|
|
|
operation.AdditionalData.ContainsKey(PluginResultInfo.AdditionalDataKeyPluginResultInfo))
|
|
|
|
|
{
|
|
|
|
|
pluginResultInfos.Add(operation.AdditionalData[PluginResultInfo.AdditionalDataKeyPluginResultInfo] as PluginResultInfo);
|
|
|
|
|
processedFiles++;
|
|
|
|
|
}
|
2020-06-07 22:46:24 +00:00
|
|
|
|
if (ProcessLimit.HasValue && processedFiles > ProcessLimit.Value)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-07-07 03:16:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-07 22:46:24 +00:00
|
|
|
|
await PostProcessFolderAsync(user, folder, pluginResultInfos, doJustInfo, doDeleteFiles).ConfigureAwait(false);
|
2019-07-07 03:16:33 +00:00
|
|
|
|
sw.Stop();
|
|
|
|
|
_addedArtistIds.AddRange(ArtistLookupEngine.AddedArtistIds);
|
|
|
|
|
_addedReleaseIds.AddRange(ReleaseLookupEngine.AddedReleaseIds);
|
|
|
|
|
_addedTrackIds.AddRange(ReleaseLookupEngine.AddedTrackIds);
|
2019-08-03 22:59:20 +00:00
|
|
|
|
Logger.LogInformation("Completed! Processed Folder [{0}]: Processed Files [{1}] : Elapsed Time [{2}]", folder.FullName, processedFiles, sw.Elapsed);
|
2019-07-07 03:16:33 +00:00
|
|
|
|
return new OperationResult<bool>
|
|
|
|
|
{
|
|
|
|
|
IsSuccess = !errors.Any(),
|
2019-07-28 21:32:20 +00:00
|
|
|
|
AdditionalData = new Dictionary<string, object> { { "ProcessedFiles", processedFiles } },
|
2019-07-07 03:16:33 +00:00
|
|
|
|
OperationTime = sw.ElapsedMilliseconds
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|