Scan work

This commit is contained in:
Steven Hildreth 2018-12-14 17:38:48 -06:00
parent e03f01ecb1
commit 304c808acd
16 changed files with 548 additions and 143 deletions

View file

@ -0,0 +1,370 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.MetaData.ID3Tags;
using Roadie.Library.Processors;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Xunit;
namespace Roadie.Library.Tests
{
public class ID3TagsHelperTests
{
private IEventMessageLogger MessageLogger { get; }
private ILogger Logger
{
get
{
return this.MessageLogger as ILogger;
}
}
private ID3TagsHelper TagsHelper { get; }
private IRoadieSettings Configuration { get; }
public DictionaryCacheManager CacheManager { get; }
public ID3TagsHelperTests()
{
this.MessageLogger = new EventMessageLogger();
this.MessageLogger.Messages += MessageLogger_Messages;
var settings = new RoadieSettings();
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddJsonFile("appsettings.test.json");
IConfiguration configuration = configurationBuilder.Build();
configuration.GetSection("RoadieSettings").Bind(settings);
settings.ConnectionString = configuration.GetConnectionString("RoadieDatabaseConnection");
this.Configuration = settings;
this.CacheManager = new DictionaryCacheManager(this.Logger, new CachePolicy(TimeSpan.FromHours(4)));
this.TagsHelper = new ID3TagsHelper(this.Configuration, this.CacheManager, this.Logger);
}
private void MessageLogger_Messages(object sender, EventMessage e)
{
Console.WriteLine($"Log Level [{ e.Level }] Log Message [{ e.Message }] ");
}
[Fact]
public void ReadID3TagsFromFileWithTrackArtists()
{
var file = new FileInfo(@"E:\Roadie_Test_Files\13-anna_kendrick-true_colors-a57e270d\01-justin_timberlake-hair_up-ef53c026.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
Assert.NotNull(metaData.TrackArtist);
Assert.NotEqual(metaData.Artist, metaData.TrackArtist);
Assert.NotNull(metaData.Release);
Assert.NotNull(metaData.Title);
Assert.True(metaData.Year > 0);
Assert.NotNull(metaData.TrackNumber);
Assert.True(metaData.TotalSeconds > 0);
Assert.True(metaData.ValidWeight > 30);
}
else
{
Console.WriteLine($"skipping { file}");
Assert.True(true);
}
}
[Theory]
[InlineData(@"N:\Rita Ora - Phoenix (Deluxe) (2018) Mp3 (320kbps) [Hunter]\Rita Ora - Phoenix (Deluxe) (2018)")]
[InlineData(@"N:\Travis Scott - ASTROWORLD (2018) Mp3 (320kbps) [Hunter]")]
[InlineData(@"N:\Lil Wayne - Tha Carter V (2018) Mp3 (320kbps) [Hunter]")]
[InlineData(@"N:\Beyonce & JAY-Z - EVERYTHING IS LOVE (2018) Mp3 (320kbps) [Hunter]")]
public void ReadFolderTestAllFiles(string folderName)
{
if (!Directory.Exists(folderName))
{
Assert.True(true);
}
else
{
var folderFiles = Directory.GetFiles(folderName, "*.mp3", SearchOption.AllDirectories);
foreach(var file in folderFiles)
{
var tagLib = this.TagsHelper.MetaDataForFile(file);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
Assert.NotNull(metaData.Release);
Assert.NotNull(metaData.Title);
Assert.True(metaData.Year > 0);
Assert.True(metaData.ValidWeight > 30);
}
}
}
[Fact]
public void ReadID3TagsFromFileSoundtrackInTitleNotSoundtrack()
{
var file = new FileInfo(@"E:\Roadie_Test_Files\01 01 Angel Of Death.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
Assert.NotNull(metaData.Release);
Assert.NotNull(metaData.Title);
Assert.True(metaData.Year > 0);
Assert.NotNull(metaData.TrackNumber);
Assert.True(metaData.TotalSeconds > 0);
Assert.False(metaData.IsSoundTrack);
Assert.True(metaData.ValidWeight > 30);
}
else
{
Console.WriteLine($"skipping { file}");
Assert.True(true);
}
}
[Fact]
public void ReadID3TagsFromFileIsSoundtrack()
{
var file = new FileInfo(@"E:\Roadie_Test_Files\06 You'Re Sensational.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
Assert.NotNull(metaData.Release);
Assert.NotNull(metaData.Title);
Assert.True(metaData.Year > 0);
Assert.NotNull(metaData.TrackNumber);
Assert.True(metaData.TotalSeconds > 0);
Assert.True(metaData.IsSoundTrack);
Assert.True(metaData.ValidWeight > 30);
}
else
{
Console.WriteLine($"skipping { file}");
Assert.True(true);
}
}
[Fact]
public void ReadID3TagsFromFileWithAlbumNoTrackSet()
{
var file = new FileInfo(@"Z:\inbound\MEGAPACK ---METAL-DEATH-BLACK---\ebony_tears-evil_as_hell-2001-ss\01-deviation-ss.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
Assert.NotNull(metaData.TrackArtist);
Assert.NotNull(metaData.Release);
Assert.NotNull(metaData.Title);
Assert.True(metaData.Year > 0);
Assert.NotNull(metaData.TrackNumber);
Assert.True(metaData.TotalSeconds > 0);
Assert.True(metaData.ValidWeight > 30);
}
else
{
Console.WriteLine($"skipping { file}");
Assert.True(true);
}
}
[Fact]
public void Read_File_Test_Is_valid()
{
var file = new FileInfo(@"Z:\unknown\2eec19bd-3575-4b7f-84dd-db2a0ec3e2f3~[2009] Dolly - Disc 1 Of 4~06 Nobody But You (Previously Unissued).mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
Assert.Null(metaData.TrackArtist);
Assert.False(metaData.TrackArtists.Any());
Assert.NotNull(metaData.Release);
Assert.NotNull(metaData.Title);
Assert.True(metaData.Year > 0);
Assert.NotNull(metaData.TrackNumber);
Assert.True(metaData.TotalSeconds > 0);
Assert.True(metaData.ValidWeight > 30);
}
else
{
Console.WriteLine($"skipping { file}");
Assert.True(true);
}
}
[Fact]
public void Read_File_Test_Is_valid2()
{
var file = new FileInfo(@"Z:\library_old\Perverse\[2014] Champion Dub\01 Champion Dub (Original Mix).mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
Assert.Null(metaData.TrackArtist);
Assert.False(metaData.TrackArtists.Any());
Assert.NotNull(metaData.Release);
Assert.NotNull(metaData.Title);
Assert.True(metaData.Year > 0);
Assert.NotNull(metaData.TrackNumber);
Assert.True(metaData.TotalSeconds > 0);
Assert.True(metaData.ValidWeight > 30);
}
else
{
Console.WriteLine($"skipping { file}");
Assert.True(true);
}
}
[Fact]
public void ReadID3TagsFromFileWithTrackAndArtistTheSame()
{
var file = new FileInfo(@"Z:\library\Blind Melon\[1992] Blind Melon\01. Blind Melon - Soak The Sin.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
Assert.Null(metaData.TrackArtist);
Assert.False(metaData.TrackArtists.Any());
Assert.NotNull(metaData.Release);
Assert.NotNull(metaData.Title);
Assert.True(metaData.Year > 0);
Assert.NotNull(metaData.TrackNumber);
Assert.True(metaData.TotalSeconds > 0);
Assert.True(metaData.ValidWeight > 30);
}
else
{
Console.WriteLine($"skipping { file}");
Assert.True(true);
}
}
[Fact]
public void ReadID3TagsFromFileWithArtistAndTrackArtist()
{
var file = new FileInfo(@"E:\Roadie_Test_Files\Test.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
Assert.NotNull(metaData.TrackArtist);
Assert.Equal("Da Album Artist", metaData.Artist);
Assert.Equal("Da Artist", metaData.TrackArtist);
Assert.NotNull(metaData.Release);
Assert.NotNull(metaData.Title);
Assert.NotNull(metaData.Genres);
Assert.NotNull(metaData.Genres.First());
Assert.Equal(2011, metaData.Year);
Assert.NotNull(metaData.TrackNumber);
Assert.Equal(6, metaData.TrackNumber.Value);
Assert.Equal(64, metaData.TotalTrackNumbers);
Assert.True(metaData.TotalSeconds > 0);
Assert.True(metaData.ValidWeight > 30);
}
else
{
Console.WriteLine($"skipping { file}");
Assert.True(true);
}
}
[Fact]
public void ReadID3TagsFromFile2()
{
var file = new FileInfo(@"Z:\library\Denver, John\[1972] Aerie\10 Readjustment Blues.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
Assert.NotNull(metaData.Release);
Assert.NotNull(metaData.Title);
Assert.True(metaData.Year > 0);
Assert.NotNull(metaData.TrackNumber);
Assert.Equal(metaData.TrackNumber.Value, 10);
Assert.True(metaData.TotalSeconds > 0);
Assert.True(metaData.ValidWeight > 30);
}
else
{
Console.WriteLine($"skipping { file}");
Assert.True(true);
}
}
[Fact]
public void ReadID3TagsFromFile3()
{
var file = new FileInfo(@"E:\Roadie_Test_Files\01. What's Yesterday.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
Assert.NotNull(metaData.Release);
Assert.NotNull(metaData.Title);
Assert.True(metaData.Year > 0);
Assert.NotNull(metaData.TrackNumber);
Assert.Equal(1, metaData.TrackNumber.Value);
Assert.Equal(10, metaData.TotalTrackNumbers.Value);
Assert.True(metaData.TotalSeconds > 0);
Assert.True(metaData.ValidWeight > 30);
}
else
{
Console.WriteLine($"skipping { file}");
Assert.True(true);
}
}
[Fact]
public void ReadID3TagsFromFile4()
{
var file = new FileInfo(@"Z:\library\Ac Dc\[1975] T.N.T\01 It'S A Long Way To The Top (If You Wanna Rock 'N' Roll).mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
Assert.NotNull(metaData.Release);
Assert.NotNull(metaData.Title);
Assert.True(metaData.Year > 0);
Assert.NotNull(metaData.TrackNumber);
Assert.Equal(metaData.TrackNumber.Value, 10);
Assert.True(metaData.TotalSeconds > 0);
Assert.True(metaData.ValidWeight > 30);
}
else
{
Console.WriteLine($"skipping { file}");
Assert.True(true);
}
}
}
}

View file

@ -3,38 +3,28 @@
"SiteName": "Roadie", "SiteName": "Roadie",
"DefaultTimeZone": "US/Central", "DefaultTimeZone": "US/Central",
"DiagnosticsPassword": "RoadieDiagPassword", "DiagnosticsPassword": "RoadieDiagPassword",
"InboundFolder": "Z:/incoming/", "InboundFolder": "C:\\roadie_dev_root\\inbound",
"LibraryFolder": "Z:/library/", "LibraryFolder": "C:\\\\roadie_dev_root\\\\library",
"ThumbnailImageSize": { "Thumbnails": {
"Height": 80, "Height": 80,
"Width": 80 "Width": 80
}, },
"SmallImageSize": { "MediumThumbnails": {
"Height": 160, "Height": 160,
"Width": 160 "Width": 160
}, },
"MediumImageSize": { "LargeThumbnails": {
"Height": 320, "Height": 320,
"Width": 320 "Width": 320
}, },
"LargeImageSize": {
"Height": 500,
"Width": 500
},
"DontDoMetaDataProvidersSearchArtists": [ "Various Artists", "Sound Tracks" ], "DontDoMetaDataProvidersSearchArtists": [ "Various Artists", "Sound Tracks" ],
"FileExtenionsToDelete": [ ".cue", ".db", ".gif", ".html", ".ini", ".jpg", ".jpeg", ".log", ".mpg", ".m3u", ".png", ".nfo", ".nzb", ".sfv", ".srr", ".txt", ".url" ], "FileExtenionsToDelete": [ ".cue", ".db", ".gif", ".html", ".ini", ".jpg", ".jpeg", ".log", ".mpg", ".m3u", ".png", ".nfo", ".nzb", ".sfv", ".srr", ".txt", ".url" ],
"RecordNoResultSearches": true, "RecordNoResultSearches": true,
"SingleArtistHoldingFolder": "Z:/single_holding/", "SingleArtistHoldingFolder": "C:\\roadie_dev_root\\single_holding",
"ArtistNameReplace": { "ArtistNameReplace": {
"AC/DC": [ "AC; DC", "AC;DC", "AC/ DC", "AC DC" ], "AC/DC": [ "AC; DC", "AC;DC", "AC/ DC", "AC DC" ],
"Love/Hate": [ "Love; Hate", "Love;Hate", "Love/ Hate", "Love Hate" ] "Love/Hate": [ "Love; Hate", "Love;Hate", "Love/ Hate", "Love Hate" ]
}, },
"Converting": {
"DoDeleteAfter": true,
"M4AConvertCommand": "ffmpeg -i \"{0}\" -acodec libmp3lame -q:a 0 \"{1}\"",
"OGGConvertCommand": "ffmpeg -i \"{0}\" -acodec libmp3lame -q:a 0 \"{1}\"\"",
"APEConvertCommand": "ffmpeg -i \"{0}\" \"{1}\""
},
"Integrations": { "Integrations": {
"ITunesProviderEnabled": true, "ITunesProviderEnabled": true,
"MusicBrainzProviderEnabled": true, "MusicBrainzProviderEnabled": true,

View file

@ -33,7 +33,7 @@ namespace Roadie.Api.Controllers
[Authorize("Admin")] [Authorize("Admin")]
public async Task<IActionResult> Scan() public async Task<IActionResult> Scan()
{ {
var result = await this.AdminService.ScanInboundFolder(await this.UserManager.GetUserAsync(User)); var result = await this.AdminService.ScanInboundFolder(await this.UserManager.GetUserAsync(User), true);
if (!result.IsSuccess) if (!result.IsSuccess)
{ {
return StatusCode((int)HttpStatusCode.InternalServerError); return StatusCode((int)HttpStatusCode.InternalServerError);

View file

@ -31,6 +31,16 @@ namespace Roadie.Api.Services
{ {
public class AdminService : ServiceBase, IAdminService public class AdminService : ServiceBase, IAdminService
{ {
private IEventMessageLogger EventMessageLogger { get; }
private ILogger MessageLogger
{
get
{
return this.EventMessageLogger as ILogger;
}
}
protected IHubContext<ScanActivityHub> ScanActivityHub { get; } protected IHubContext<ScanActivityHub> ScanActivityHub { get; }
public AdminService(IRoadieSettings configuration, public AdminService(IRoadieSettings configuration,
@ -44,6 +54,13 @@ namespace Roadie.Api.Services
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext) : base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
{ {
this.ScanActivityHub = scanActivityHub; this.ScanActivityHub = scanActivityHub;
this.EventMessageLogger = new EventMessageLogger();
this.EventMessageLogger.Messages += EventMessageLogger_Messages;
}
private void EventMessageLogger_Messages(object sender, EventMessage e)
{
Task.WaitAll(this.LogAndPublish(e.Message, e.Level));
} }
public async Task<OperationResult<bool>> ScanInboundFolder(ApplicationUser user, bool isReadOnly = false) public async Task<OperationResult<bool>> ScanInboundFolder(ApplicationUser user, bool isReadOnly = false)
@ -58,7 +75,7 @@ namespace Roadie.Api.Services
await this.LogAndPublish($"** Processing Folder: [{d.FullName}]"); await this.LogAndPublish($"** Processing Folder: [{d.FullName}]");
long processedFolders = 0; long processedFolders = 0;
var folderProcessor = new FolderProcessor(this.Configuration, this.HttpEncoder, this.Configuration.LibraryFolder, this.DbContext, this.CacheManager, this.Logger); var folderProcessor = new FolderProcessor(this.Configuration, this.HttpEncoder, this.Configuration.LibraryFolder, this.DbContext, this.CacheManager, this.MessageLogger);
foreach (var folder in Directory.EnumerateDirectories(d.FullName).ToArray()) foreach (var folder in Directory.EnumerateDirectories(d.FullName).ToArray())
{ {
await folderProcessor.Process(new DirectoryInfo(folder), isReadOnly); await folderProcessor.Process(new DirectoryInfo(folder), isReadOnly);
@ -78,6 +95,8 @@ namespace Roadie.Api.Services
}; };
} }
private async Task LogAndPublish(string message, LogLevel level = LogLevel.Trace) private async Task LogAndPublish(string message, LogLevel level = LogLevel.Trace)
{ {
switch (level) switch (level)

View file

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Roadie.Library
{
[Serializable]
public class EventMessage
{
public Microsoft.Extensions.Logging.LogLevel Level { get; set; } = Microsoft.Extensions.Logging.LogLevel.Trace;
public string Message { get; set; }
}
}

View file

@ -15,5 +15,14 @@ namespace Roadie.Library.Extensions
} }
return 0; return 0;
} }
public static TimeSpan? ToTimeSpan(this decimal? value)
{
if(!value.HasValue)
{
return null;
}
return TimeSpan.FromSeconds((double)value);
}
} }
} }

View file

@ -1042,7 +1042,7 @@ namespace Roadie.Library.Factories
getParams.Add(new MySqlParameter("@sinAlt", string.Format("%|{0}|%", specialSearchName))); getParams.Add(new MySqlParameter("@sinAlt", string.Format("%|{0}|%", specialSearchName)));
getParams.Add(new MySqlParameter("@sendAlt", string.Format("%|{0}", specialSearchName))); getParams.Add(new MySqlParameter("@sendAlt", string.Format("%|{0}", specialSearchName)));
return this.DbContext.Artists.FromSql(@"SELECT * return this.DbContext.Artists.FromSql(@"SELECT *
FROM `Artist` FROM `artist`
WHERE LCASE(name) = @isName WHERE LCASE(name) = @isName
OR LCASE(sortName) = @isName OR LCASE(sortName) = @isName
OR LCASE(sortName) = @isSortName OR LCASE(sortName) = @isSortName
@ -1053,7 +1053,7 @@ namespace Roadie.Library.Factories
OR alternatenames like @sinAlt OR alternatenames like @sinAlt
OR (alternatenames like @endAlt OR (alternatenames like @endAlt
OR alternatenames like @sendAlt) OR alternatenames like @sendAlt)
LIMIT 1;", getParams.ToArray()).FirstOrDefault(); LIMIT 1", getParams.ToArray()).FirstOrDefault();
} }
catch (Exception ex) catch (Exception ex)
{ {

View file

@ -0,0 +1,34 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;
namespace Roadie.Library.Processors
{
public class EventMessageLogger : ILogger, IEventMessageLogger
{
public event EventHandler<EventMessage> Messages;
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
Messages?.Invoke(this, new EventMessage { Level = logLevel, Message = formatter(state, exception) });
}
private void OnEventMessage(EventMessage message)
{
Messages?.Invoke(this, message);
}
}
}

View file

@ -36,13 +36,14 @@ namespace Roadie.Library.Processors
{ {
if (t.GetInterface("IFilePlugin") != null && !t.IsAbstract && !t.IsInterface) if (t.GetInterface("IFilePlugin") != null && !t.IsAbstract && !t.IsInterface)
{ {
IFilePlugin plugin = Activator.CreateInstance(t, new object[] { this.ArtistFactory, this.ReleaseFactory, this.ImageFactory, this.CacheManager, this.Logger }) as IFilePlugin; IFilePlugin plugin = Activator.CreateInstance(t, new object[] { this.Configuration, this.HttpEncoder, this.ArtistFactory, this.ReleaseFactory, this.ImageFactory, this.CacheManager, this.Logger }) as IFilePlugin;
plugins.Add(plugin); plugins.Add(plugin);
} }
} }
} }
catch catch (Exception ex)
{ {
this.Logger.LogError(ex);
} }
this._plugins = plugins.ToArray(); this._plugins = plugins.ToArray();
} }

View file

@ -49,16 +49,18 @@ namespace Roadie.Library.Processors
return result; return result;
} }
public async Task<OperationResult<bool>> Process(DirectoryInfo inboundFolder, bool doJustInfo, int? submissionId = null) public async Task<OperationResult<bool>> Process(DirectoryInfo folder, bool doJustInfo, int? submissionId = null)
{ {
var sw = new Stopwatch(); var sw = new Stopwatch();
sw.Start(); sw.Start();
this.PrePrecessFolder(inboundFolder, doJustInfo); await this.PreProcessFolder(folder, doJustInfo);
int processedFiles = 0; int processedFiles = 0;
var pluginResultInfos = new List<PluginResultInfo>(); var pluginResultInfos = new List<PluginResultInfo>();
var errors = new List<string>(); var errors = new List<string>();
this.FileProcessor.SubmissionId = submissionId; this.FileProcessor.SubmissionId = submissionId;
foreach (var file in Directory.EnumerateFiles(inboundFolder.FullName, "*.*", SearchOption.AllDirectories).ToArray())
foreach (var file in Directory.EnumerateFiles(folder.FullName, "*.*", SearchOption.AllDirectories).ToArray())
{ {
var operation = await this.FileProcessor.Process(file, doJustInfo); var operation = await this.FileProcessor.Process(file, doJustInfo);
if (operation != null && operation.AdditionalData != null && operation.AdditionalData.ContainsKey(PluginResultInfo.AdditionalDataKeyPluginResultInfo)) if (operation != null && operation.AdditionalData != null && operation.AdditionalData.ContainsKey(PluginResultInfo.AdditionalDataKeyPluginResultInfo))
@ -67,7 +69,7 @@ namespace Roadie.Library.Processors
} }
if (operation == null) if (operation == null)
{ {
var fileExtensionsToDelete = this.Configuration.FileExtensionsToDelete; var fileExtensionsToDelete = this.Configuration.FileExtensionsToDelete ?? new string[0];
if (fileExtensionsToDelete.Any(x => x.Equals(Path.GetExtension(file), StringComparison.OrdinalIgnoreCase))) if (fileExtensionsToDelete.Any(x => x.Equals(Path.GetExtension(file), StringComparison.OrdinalIgnoreCase)))
{ {
if (!doJustInfo) if (!doJustInfo)
@ -86,9 +88,9 @@ namespace Roadie.Library.Processors
break; break;
} }
} }
await this.PostProcessFolder(inboundFolder, pluginResultInfos, doJustInfo); await this.PostProcessFolder(folder, pluginResultInfos, doJustInfo);
sw.Stop(); sw.Stop();
this.Logger.LogInformation("** Completed! Processed Folder [{0}]: Processed Files [{1}] : Elapsed Time [{2}]", inboundFolder.FullName.ToString(), processedFiles, sw.Elapsed); this.Logger.LogInformation("** Completed! Processed Folder [{0}]: Processed Files [{1}] : Elapsed Time [{2}]", folder.FullName.ToString(), processedFiles, sw.Elapsed);
return new OperationResult<bool> return new OperationResult<bool>
{ {
IsSuccess = !errors.Any(), IsSuccess = !errors.Any(),
@ -98,7 +100,6 @@ namespace Roadie.Library.Processors
{ "newReleases", this.ReleaseFactory.AddedReleaseIds.Count() }, { "newReleases", this.ReleaseFactory.AddedReleaseIds.Count() },
{ "newTracks", this.ReleaseFactory.AddedTrackIds.Count() } { "newTracks", this.ReleaseFactory.AddedTrackIds.Count() }
}, },
OperationTime = sw.ElapsedMilliseconds OperationTime = sw.ElapsedMilliseconds
}; };
} }
@ -131,29 +132,8 @@ namespace Roadie.Library.Processors
/// <summary> /// <summary>
/// Perform any operations to the given folder before processing /// Perform any operations to the given folder before processing
/// </summary> /// </summary>
private bool PrePrecessFolder(DirectoryInfo inboundFolder, bool doJustInfo = false) private async Task<bool> PreProcessFolder(DirectoryInfo inboundFolder, bool doJustInfo = false)
{ {
// If Folder name starts with "~" then remove the tilde and set all files in the folder artist to the folder name
if (this.Configuration.Processing.DoFolderArtistNameSet && inboundFolder.Name.StartsWith("~"))
{
var artist = inboundFolder.Name.Replace("~", "");
this.Logger.LogInformation("Setting Folder File Tags To [{0}]", artist);
if (!doJustInfo)
{
foreach (var file in inboundFolder.GetFiles("*.*", SearchOption.AllDirectories))
{
var extension = file.Extension.ToLower();
if (extension.Equals(".mp3") || extension.Equals(".flac"))
{
// TODO
//var tagFile = TagLib.File.Create(file.FullName);
//tagFile.Tag.Performers = null;
//tagFile.Tag.Performers = new[] { artist };
//tagFile.Save();
}
}
}
}
return true; return true;
} }
} }

View file

@ -0,0 +1,14 @@
using System;
using Microsoft.Extensions.Logging;
namespace Roadie.Library.Processors
{
public interface IEventMessageLogger
{
event EventHandler<EventMessage> Messages;
IDisposable BeginScope<TState>(TState state);
bool IsEnabled(LogLevel logLevel);
void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter);
}
}

View file

@ -9,8 +9,8 @@
<PackageReference Include="CsvHelper" Version="12.0.1" /> <PackageReference Include="CsvHelper" Version="12.0.1" />
<PackageReference Include="FluentFTP" Version="19.2.2" /> <PackageReference Include="FluentFTP" Version="19.2.2" />
<PackageReference Include="HtmlAgilityPack" Version="1.8.10" /> <PackageReference Include="HtmlAgilityPack" Version="1.8.10" />
<PackageReference Include="ID3" Version="0.5.0-beta.1" /> <PackageReference Include="IdSharp.Common" Version="1.0.1" />
<PackageReference Include="ID3Tag.Core" Version="0.1.3" /> <PackageReference Include="IdSharp.Tagging" Version="1.0.0-rc3" />
<PackageReference Include="Inflatable.Lastfm" Version="1.1.0.339" /> <PackageReference Include="Inflatable.Lastfm" Version="1.1.0.339" />
<PackageReference Include="Mapster" Version="3.2.0" /> <PackageReference Include="Mapster" Version="3.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.1.6" /> <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.1.6" />
@ -30,8 +30,13 @@
<Folder Include="Factories\" /> <Folder Include="Factories\" />
<Folder Include="FilePlugins\" /> <Folder Include="FilePlugins\" />
<Folder Include="Models\Subsonic\" /> <Folder Include="Models\Subsonic\" />
<Folder Include="Processors\" />
<Folder Include="SearchEngines\MetaData\Audio\" /> <Folder Include="SearchEngines\MetaData\Audio\" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Reference Include="IdSharp.AudioInfo-core">
<HintPath>..\libraries\IdSharp.AudioInfo-core.dll</HintPath>
</Reference>
</ItemGroup>
</Project> </Project>

View file

@ -9,6 +9,11 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using IdSharp.AudioInfo;
using IdSharp.Common.Utils;
using IdSharp.Tagging.ID3v1;
using IdSharp.Tagging.ID3v2;
using Newtonsoft.Json;
namespace Roadie.Library.MetaData.ID3Tags namespace Roadie.Library.MetaData.ID3Tags
{ {
@ -21,12 +26,7 @@ namespace Roadie.Library.MetaData.ID3Tags
public OperationResult<AudioMetaData> MetaDataForFile(string fileName) public OperationResult<AudioMetaData> MetaDataForFile(string fileName)
{ {
var result = this.MetaDataForFileFromTagLib(fileName); var result = this.MetaDataForFileFromIdSharp(fileName);
if (result.IsSuccess)
{
return result;
}
result = this.MetaDataForFileFromNTagLite(fileName);
if (result.IsSuccess) if (result.IsSuccess)
{ {
return result; return result;
@ -39,19 +39,11 @@ namespace Roadie.Library.MetaData.ID3Tags
var result = new List<AudioMetaData>(); var result = new List<AudioMetaData>();
foreach (var fileName in fileNames) foreach (var fileName in fileNames)
{ {
var r = this.MetaDataForFileFromTagLib(fileName); var r = this.MetaDataForFileFromIdSharp(fileName);
if (r.IsSuccess) if (r.IsSuccess)
{ {
result.Add(r.Data); result.Add(r.Data);
} }
else
{
r = this.MetaDataForFileFromNTagLite(fileName);
if (r.IsSuccess)
{
result.Add(r.Data);
}
}
} }
return new OperationResult<IEnumerable<AudioMetaData>> return new OperationResult<IEnumerable<AudioMetaData>>
{ {
@ -102,7 +94,8 @@ namespace Roadie.Library.MetaData.ID3Tags
return false; return false;
} }
private OperationResult<AudioMetaData> MetaDataForFileFromNTagLite(string fileName)
private OperationResult<AudioMetaData> MetaDataForFileFromIdSharp(string fileName)
{ {
var sw = new Stopwatch(); var sw = new Stopwatch();
sw.Start(); sw.Start();
@ -110,81 +103,57 @@ namespace Roadie.Library.MetaData.ID3Tags
var isSuccess = false; var isSuccess = false;
try try
{ {
// TODO IAudioFile audioFile = AudioFile.Create(fileName, true);
if (ID3v2Tag.DoesTagExist(fileName))
{
IID3v2Tag id3v2 = new ID3v2Tag(fileName);
result.Release = id3v2.Album;
result.Artist = id3v2.AlbumArtist ?? id3v2.Artist;
result.ArtistRaw = id3v2.AlbumArtist ?? id3v2.Artist;
result.Genres = id3v2.Genre?.Split(new char[] { ',', '\\' });
result.TrackArtist = id3v2.OriginalArtist ?? id3v2.Artist ?? id3v2.AlbumArtist;
result.TrackArtistRaw = id3v2.OriginalArtist;
result.AudioBitrate = (int?)audioFile.Bitrate;
result.AudioChannels = audioFile.Channels;
result.AudioSampleRate = (int)audioFile.Bitrate;
result.Disk = SafeParser.ToNumber<int?>(id3v2.DiscNumber);
result.Images = id3v2.PictureList?.Select(x => new AudioMetaDataImage
{
Data = x.PictureData,
Description = x.Description,
MimeType = x.MimeType,
Type = (AudioMetaDataImageType)x.PictureType
}).ToArray();
result.Time = (int)audioFile.TotalSeconds > 0 ? ((decimal?)audioFile.TotalSeconds).ToTimeSpan() : null;
result.Title = id3v2.Title.ToTitleCase(false);
//var file = LiteFile.LoadFromFile(fileName); var trackparts = id3v2.TrackNumber?.Split('/');
//var tpos = file.Tag.FindFirstFrameById(FrameId.TPOS); result.TrackNumber = SafeParser.ToNumber<short?>(trackparts[0]);
//Picture[] pics = file.Tag.FindFramesById(FrameId.APIC).Select(f => f.GetPicture()).ToArray(); result.TotalTrackNumbers = trackparts.Length > 1 ? SafeParser.ToNumber<short?>(trackparts[1]) : 0;
//result.Release = file.Tag.Album; result.Year = SafeParser.ToNumber<int?>(id3v2.Year);
//result.Artist = file.Tag.Artist;
//result.ArtistRaw = file.Tag.Artist;
//result.Genres = (file.Tag.Genre ?? string.Empty).Split(';');
//result.TrackArtist = file.Tag.OriginalArtist;
//result.TrackArtistRaw = file.Tag.OriginalArtist;
//result.AudioBitrate = file.Bitrate;
//result.AudioChannels = file.AudioMode.HasValue ? (int?)file.AudioMode.Value : null;
//result.AudioSampleRate = file.Frequency;
//result.Disk = tpos != null ? SafeParser.ToNumber<int?>(tpos.Text) : null;
//result.Images = pics.Select(x => new AudioMetaDataImage
//{
// Data = x.Data,
// Description = x.Description,
// MimeType = x.MimeType,
// Type = (AudioMetaDataImageType)x.PictureType
//}).ToArray();
//result.Time = file.Duration;
//result.Title = file.Tag.Title.ToTitleCase(false);
//result.TotalTrackNumbers = file.Tag.TrackCount;
//result.TrackNumber = file.Tag.TrackNumber;
//result.Year = file.Tag.Year;
isSuccess = true; isSuccess = true;
} }
catch (Exception ex)
if (!isSuccess)
{ {
this.Logger.LogError(ex, "MetaDataForFileFromTagLib Filename [" + fileName + "] Error [" + ex.Serialize() + "]"); if (ID3v1Tag.DoesTagExist(fileName))
{
IID3v1Tag id3v1 = new ID3v1Tag(fileName);
result.Release = id3v1.Album;
result.Artist = id3v1.Artist;
result.ArtistRaw = id3v1.Artist;
result.AudioBitrate = (int?)audioFile.Bitrate;
result.AudioChannels = audioFile.Channels;
result.AudioSampleRate = (int)audioFile.Bitrate;
result.Time = (int)audioFile.TotalSeconds > 0 ? ((decimal?)audioFile.TotalSeconds).ToTimeSpan() : null;
result.Title = id3v1.Title.ToTitleCase(false);
result.TrackNumber = (short?)id3v1.TrackNumber;
result.Year = SafeParser.ToNumber<int?>(id3v1.Year);
isSuccess = true;
} }
sw.Stop();
return new OperationResult<AudioMetaData>
{
IsSuccess = isSuccess,
OperationTime = sw.ElapsedMilliseconds,
Data = result
};
} }
private OperationResult<AudioMetaData> MetaDataForFileFromTagLib(string fileName)
{
var sw = new Stopwatch();
sw.Start();
AudioMetaData result = new AudioMetaData();
var isSuccess = false;
try
{
// TODO
//var tagFile = TagLib.File.Create(fileName);
//result.Release = tagFile.Tag.Album;
//result.Artist = !string.IsNullOrEmpty(tagFile.Tag.JoinedAlbumArtists) ? tagFile.Tag.JoinedAlbumArtists : tagFile.Tag.JoinedPerformers;
//result.ArtistRaw = !string.IsNullOrEmpty(tagFile.Tag.JoinedAlbumArtists) ? tagFile.Tag.JoinedAlbumArtists : tagFile.Tag.JoinedPerformers;
//result.Genres = tagFile.Tag.Genres != null ? tagFile.Tag.Genres : new string[0];
//result.TrackArtist = tagFile.Tag.JoinedPerformers;
//result.TrackArtistRaw = tagFile.Tag.JoinedPerformers;
//result.AudioBitrate = (tagFile.Properties.AudioBitrate > 0 ? (int?)tagFile.Properties.AudioBitrate : null);
//result.AudioChannels = (tagFile.Properties.AudioChannels > 0 ? (int?)tagFile.Properties.AudioChannels : null);
//result.AudioSampleRate = (tagFile.Properties.AudioSampleRate > 0 ? (int?)tagFile.Properties.AudioSampleRate : null);
//result.Disk = (tagFile.Tag.Disc > 0 ? (int?)tagFile.Tag.Disc : null);
//result.Images = (tagFile.Tag.Pictures != null ? tagFile.Tag.Pictures.Select(x => new AudioMetaDataImage
//{
// Data = x.Data.Data,
// Description = x.Description,
// MimeType = x.MimeType,
// Type = (AudioMetaDataImageType)x.Type
//}).ToArray() : null);
//result.Time = (tagFile.Properties.Duration.TotalMinutes > 0 ? (TimeSpan?)tagFile.Properties.Duration : null);
//result.Title = tagFile.Tag.Title.ToTitleCase(false);
//result.TotalTrackNumbers = (tagFile.Tag.TrackCount > 0 ? (int?)tagFile.Tag.TrackCount : null);
//result.TrackNumber = (tagFile.Tag.Track > 0 ? (short?)tagFile.Tag.Track : null);
//result.Year = (tagFile.Tag.Year > 0 ? (int?)tagFile.Tag.Year : null);
isSuccess = true;
} }
catch (Exception ex) catch (Exception ex)
{ {

Binary file not shown.

Binary file not shown.

Binary file not shown.