mirror of
https://github.com/sphildreth/roadie
synced 2024-11-10 06:44:12 +00:00
Beta v20180216.1
This commit is contained in:
parent
f404a41cfe
commit
48bb25106f
25 changed files with 1397 additions and 44 deletions
28
Inspector/Inspector.csproj
Normal file
28
Inspector/Inspector.csproj
Normal file
|
@ -0,0 +1,28 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="appsettings.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="appsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.3.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Roadie.Api.Library\Roadie.Library.csproj" />
|
||||
<ProjectReference Include="..\Roadie.Api.Services\Roadie.Api.Services.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
29
Inspector/Program.cs
Normal file
29
Inspector/Program.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using McMaster.Extensions.CommandLineUtils;
|
||||
|
||||
namespace Inspector
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
=> CommandLineApplication.Execute<Program>(args);
|
||||
|
||||
[Option(ShortName = "f", Description = "Folder To Inspect")]
|
||||
[Required]
|
||||
public string Folder { get; }
|
||||
|
||||
[Option(ShortName = "d", Description = "Destination Folder")]
|
||||
public string Destination { get; }
|
||||
|
||||
[Option("-c", "Copy Dont Move Originals", CommandOptionType.NoValue)]
|
||||
public bool DoCopy { get; }
|
||||
|
||||
private void OnExecute()
|
||||
{
|
||||
var inspector = new Roadie.Library.Inspect.Inspector();
|
||||
inspector.Inspect(this.DoCopy, this.Folder, this.Destination ?? this.Folder);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
8
Inspector/Properties/launchSettings.json
Normal file
8
Inspector/Properties/launchSettings.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profiles": {
|
||||
"Inspector": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "-f \"C:\\roadie_dev_root\\inbound\""
|
||||
}
|
||||
}
|
||||
}
|
104
Inspector/appsettings.json
Normal file
104
Inspector/appsettings.json
Normal file
|
@ -0,0 +1,104 @@
|
|||
{
|
||||
"RoadieSettings": {
|
||||
"SiteName": "Roadie",
|
||||
"DefaultTimeZone": "US/Central",
|
||||
"DiagnosticsPassword": "RoadieDiagPassword",
|
||||
"InboundFolder": "C:\\roadie_dev_root\\inbound",
|
||||
"LibraryFolder": "C:\\\\roadie_dev_root\\\\library",
|
||||
"Thumbnails": {
|
||||
"Height": 80,
|
||||
"Width": 80
|
||||
},
|
||||
"MediumThumbnails": {
|
||||
"Height": 160,
|
||||
"Width": 160
|
||||
},
|
||||
"LargeThumbnails": {
|
||||
"Height": 320,
|
||||
"Width": 320
|
||||
},
|
||||
"DontDoMetaDataProvidersSearchArtists": [ "Various Artists", "Sound Tracks" ],
|
||||
"FileExtenionsToDelete": [ ".cue", ".db", ".gif", ".html", ".ini", ".jpg", ".jpeg", ".log", ".mpg", ".m3u", ".png", ".nfo", ".nzb", ".sfv", ".srr", ".txt", ".url" ],
|
||||
"RecordNoResultSearches": true,
|
||||
"SingleArtistHoldingFolder": "C:\\roadie_dev_root\\single_holding",
|
||||
"ArtistNameReplace": {
|
||||
"AC/DC": [ "AC; DC", "AC;DC", "AC/ DC", "AC DC" ],
|
||||
"Love/Hate": [ "Love; Hate", "Love;Hate", "Love/ Hate", "Love Hate" ]
|
||||
},
|
||||
"Integrations": {
|
||||
"ITunesProviderEnabled": true,
|
||||
"MusicBrainzProviderEnabled": true,
|
||||
"SpotifyProviderEnabled": true,
|
||||
"ApiKeys": [
|
||||
{
|
||||
"ApiName": "BingImageSearch",
|
||||
"Key": "<KEY HERE>"
|
||||
},
|
||||
{
|
||||
"ApiName": "LastFMApiKey",
|
||||
"Key": "<KEY HERE>",
|
||||
"KeySecret": "<SECRET HERE>"
|
||||
},
|
||||
{
|
||||
"ApiName": "DiscogsConsumerKey",
|
||||
"Key": "<KEY HERE>",
|
||||
"KeySecret": "<SECRET HERE>"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Processing": {
|
||||
"DoAudioCleanup": true,
|
||||
"DoSaveEditsToTags": true,
|
||||
"DoClearComments": true,
|
||||
"DoParseFromFileName": true,
|
||||
"DoParseFromDiscogsDBFindingTrackForArtist": true,
|
||||
"DoParseFromDiscogsDB": true,
|
||||
"DoParseFromMusicBrainz": true,
|
||||
"DoParseFromLastFM": true,
|
||||
"MaximumArtistImagesToAdd": 12,
|
||||
"MaximumReleaseImagesToAdd": 12,
|
||||
"MaxImageWidth": 2048,
|
||||
"ReleaseRemoveStringsRegex": "(\\s*(-\\s)*((CD[0-9][0-9]*)))|((\\(|\\[)+([0-9]|,|self|bonus|released|th|anniversary|re|release|cd|disc|deluxe|digipack|vinyl|japanese|asian|remastered|limited|expanded|edition|\\s)+(]|\\)))",
|
||||
"TrackRemoveStringsRegex": "^([0-9]+)(\\.|-|\\s)*",
|
||||
"ReplaceStrings": [
|
||||
{
|
||||
"order": 1,
|
||||
"key": "-OBSERVER",
|
||||
"replaceWith": ""
|
||||
},
|
||||
{
|
||||
"order": 2,
|
||||
"key": "[Torrent Tatty]",
|
||||
"replaceWith": ""
|
||||
},
|
||||
{
|
||||
"order": 3,
|
||||
"key": "_",
|
||||
"replaceWith": " "
|
||||
},
|
||||
{
|
||||
"order": 4,
|
||||
"key": "-",
|
||||
"replaceWith": " "
|
||||
},
|
||||
{
|
||||
"order": 5,
|
||||
"key": "~",
|
||||
"replaceWith": " "
|
||||
},
|
||||
{
|
||||
"order": 6,
|
||||
"key": "^",
|
||||
"replaceWith": " "
|
||||
},
|
||||
{
|
||||
"order": 7,
|
||||
"key": "#",
|
||||
"replaceWith": " "
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -179,6 +179,158 @@ namespace Roadie.Library.Tests
|
|||
Assert.Null(dn);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTotalTrackNumbersFromCue_Should_Be_Five()
|
||||
{
|
||||
var cuesDir = @"C:\roadie_dev_root\test_cue_and_playlists\cues1";
|
||||
var directory = new DirectoryInfo(cuesDir);
|
||||
if(directory.Exists)
|
||||
{
|
||||
foreach(var file in Directory.GetFiles(cuesDir))
|
||||
{
|
||||
var t = ID3TagsHelper.DetermineTotalTrackNumbers(file);
|
||||
Assert.Equal(5, t.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTotalTrackNumbersFromCue_Should_Be_Eight()
|
||||
{
|
||||
var cuesDir = @"C:\roadie_dev_root\test_cue_and_playlists\cues2";
|
||||
var directory = new DirectoryInfo(cuesDir);
|
||||
if (directory.Exists)
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(cuesDir))
|
||||
{
|
||||
var t = ID3TagsHelper.DetermineTotalTrackNumbers(file);
|
||||
Assert.Equal(8, t.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTotalTrackNumbersFromCue_Should_Be_Six()
|
||||
{
|
||||
var cuesDir = @"C:\roadie_dev_root\test_cue_and_playlists\cues3";
|
||||
var directory = new DirectoryInfo(cuesDir);
|
||||
if (directory.Exists)
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(cuesDir))
|
||||
{
|
||||
var t = ID3TagsHelper.DetermineTotalTrackNumbers(file);
|
||||
Assert.Equal(6, t.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTotalTrackNumbersFromCue_Should_Be_Nine()
|
||||
{
|
||||
var cuesDir = @"C:\roadie_dev_root\test_cue_and_playlists\cues4";
|
||||
var directory = new DirectoryInfo(cuesDir);
|
||||
if (directory.Exists)
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(cuesDir))
|
||||
{
|
||||
var t = ID3TagsHelper.DetermineTotalTrackNumbers(file);
|
||||
Assert.Equal(9, t.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTotalTrackNumbersFromM3u_Should_Be_Eleven()
|
||||
{
|
||||
var cuesDir = @"C:\roadie_dev_root\test_cue_and_playlists\m3u1";
|
||||
var directory = new DirectoryInfo(cuesDir);
|
||||
if (directory.Exists)
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(cuesDir))
|
||||
{
|
||||
var t = ID3TagsHelper.DetermineTotalTrackNumbers(file);
|
||||
Assert.Equal(11, t.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTotalTrackNumbersFromM3u_Should_Be_Four()
|
||||
{
|
||||
var cuesDir = @"C:\roadie_dev_root\test_cue_and_playlists\m3u2";
|
||||
var directory = new DirectoryInfo(cuesDir);
|
||||
if (directory.Exists)
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(cuesDir))
|
||||
{
|
||||
var t = ID3TagsHelper.DetermineTotalTrackNumbers(file);
|
||||
Assert.Equal(4, t.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTotalTrackNumbersFromM3u_Should_Be_Eight()
|
||||
{
|
||||
var cuesDir = @"C:\roadie_dev_root\test_cue_and_playlists\m3u3";
|
||||
var directory = new DirectoryInfo(cuesDir);
|
||||
if (directory.Exists)
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(cuesDir))
|
||||
{
|
||||
var t = ID3TagsHelper.DetermineTotalTrackNumbers(file);
|
||||
Assert.Equal(8, t.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTotalTrackNumbersFromM3u_Should_Be_Fourteen()
|
||||
{
|
||||
var cuesDir = @"C:\roadie_dev_root\test_cue_and_playlists\m3u4";
|
||||
var directory = new DirectoryInfo(cuesDir);
|
||||
if (directory.Exists)
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(cuesDir))
|
||||
{
|
||||
var t = ID3TagsHelper.DetermineTotalTrackNumbers(file);
|
||||
Assert.Equal(14, t.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void ReadID3TagsMultipleMediasWithMax()
|
||||
|
@ -481,6 +633,40 @@ namespace Roadie.Library.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Write_Tags()
|
||||
{
|
||||
var file = new FileInfo(@"C:\roadie_dev_root\inbound\temp\01. Re1nstall 0verture.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
short trackNumber = 15;
|
||||
var numberOfTracks = 25;
|
||||
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
metaData.TrackNumber = trackNumber;
|
||||
metaData.TotalTrackNumbers = numberOfTracks;
|
||||
this.TagsHelper.WriteTags(metaData, file.FullName);
|
||||
|
||||
var tagLibAfterWrite = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
Assert.Equal(metaData.Artist, tagLibAfterWrite.Data.Artist);
|
||||
Assert.Equal(metaData.Release, tagLibAfterWrite.Data.Release);
|
||||
Assert.Equal(metaData.Title, tagLibAfterWrite.Data.Title);
|
||||
Assert.Equal(trackNumber, tagLibAfterWrite.Data.TrackNumber);
|
||||
Assert.Equal(numberOfTracks, tagLibAfterWrite.Data.TotalTrackNumbers);
|
||||
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"skipping { file}");
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadID3TagsFromFile2()
|
||||
{
|
||||
|
@ -613,5 +799,83 @@ namespace Roadie.Library.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadID3TagsFromFile7()
|
||||
{
|
||||
var file = new FileInfo(@"C:\roadie_dev_root\1985 - Sacred Heart\Dio - Sacred Heart (1).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.True(metaData.TotalSeconds > 0);
|
||||
Assert.True(metaData.ValidWeight > 30);
|
||||
Assert.True(metaData.IsValid);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"skipping { file}");
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadID3TagsFromFile8()
|
||||
{
|
||||
var file = new FileInfo(@"C:\roadie_dev_root\Grift\2017 Arvet\01 - Flyktfast.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.True(metaData.TotalSeconds > 0);
|
||||
Assert.True(metaData.ValidWeight > 30);
|
||||
Assert.True(metaData.IsValid);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"skipping { file}");
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadID3TagsFromFile9()
|
||||
{
|
||||
var file = new FileInfo(@"C:\roadie_dev_root\Distorted Harmony - A Way Out - 2018\kWlZr0N_o72dwo0_CD001_0001.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.True(metaData.TotalSeconds > 0);
|
||||
Assert.True(metaData.ValidWeight > 30);
|
||||
Assert.True(metaData.IsValid);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"skipping { file}");
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
53
Roadie.Api.Library.Tests/InspectorTests.cs
Normal file
53
Roadie.Api.Library.Tests/InspectorTests.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using Roadie.Library.Inspect;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Xunit;
|
||||
|
||||
namespace Roadie.Library.Tests
|
||||
{
|
||||
public class InspectorTests
|
||||
{
|
||||
|
||||
[Theory]
|
||||
[InlineData("Bob Jones")]
|
||||
[InlineData("Nancy Jones")]
|
||||
public void Generate_Inspector_Artist_Token(string artist)
|
||||
{
|
||||
var token = Inspector.ArtistInspectorToken(new MetaData.Audio.AudioMetaData { Artist = artist });
|
||||
Assert.NotNull(token);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Generate_Same_Token_Value()
|
||||
{
|
||||
var md = new MetaData.Audio.AudioMetaData { Artist = "Omniversum Fractum", Release = "Paradigm Of The Elementals Essence" };
|
||||
var artistToken = Inspector.ArtistInspectorToken(md);
|
||||
Assert.NotNull(artistToken);
|
||||
|
||||
var releaseToken = Inspector.ReleaseInspectorToken(md);
|
||||
Assert.NotNull(releaseToken);
|
||||
Assert.NotEqual(artistToken, releaseToken);
|
||||
|
||||
var secondReleaseToken = Inspector.ReleaseInspectorToken(md);
|
||||
Assert.NotNull(releaseToken);
|
||||
Assert.NotEqual(artistToken, releaseToken);
|
||||
Assert.Equal(secondReleaseToken, releaseToken);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Generate_Inspector_Tokens_Artist_And_Release_Unique()
|
||||
{
|
||||
var md = new MetaData.Audio.AudioMetaData { Artist = "Bob Jones", Release = "Bob's First Release" };
|
||||
var artistToken = Inspector.ArtistInspectorToken(md);
|
||||
Assert.NotNull(artistToken);
|
||||
|
||||
var releaseToken = Inspector.ReleaseInspectorToken(md);
|
||||
Assert.NotNull(releaseToken);
|
||||
|
||||
Assert.NotEqual(artistToken, releaseToken);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
204
Roadie.Api.Library.Tests/RenumberTests.cs
Normal file
204
Roadie.Api.Library.Tests/RenumberTests.cs
Normal file
|
@ -0,0 +1,204 @@
|
|||
using Roadie.Library.MetaData.Audio;
|
||||
using Roadie.Library.MetaData.ID3Tags;
|
||||
using System.Collections.Generic;
|
||||
using Xunit;
|
||||
|
||||
namespace Roadie.Library.Tests
|
||||
{
|
||||
public class RenumberTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(@"2003 - Accelerated Evolution\01 - Depth Charge.mp3")]
|
||||
[InlineData(@"01 - Depth Charge.mp3")]
|
||||
[InlineData(@"2003 - Accelerated Evolution\CD1\01 - Depth Charge.mp3")]
|
||||
[InlineData(@"2003 - Accelerated Evolution\CD01\01 - Depth Charge.mp3")]
|
||||
[InlineData(@"2003 - Accelerated Evolution\CD001\01 - Depth Charge.mp3")]
|
||||
[InlineData(@"CD 1\01 - Depth Charge.mp3")]
|
||||
[InlineData(@"2003 - Accelerated Evolution\CD 01\01 - Depth Charge.mp3")]
|
||||
[InlineData(@"2003 - Accelerated Evolution\CD 001\01 - Depth Charge.mp3")]
|
||||
[InlineData(@"Accelerated Evolution CD01\22 - Depth Charge.mp3")]
|
||||
[InlineData(@"Accelerated Evolution CD1\22 - Depth Charge.mp3")]
|
||||
public void Find_Disc_Number_Should_Be_One(string filename)
|
||||
{
|
||||
var n = ID3TagsHelper.DetermineDiscNumber(new AudioMetaData { Filename = filename });
|
||||
Assert.Equal(1, n);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"2003 - Accelerated Evolution\CD2\01 - Depth Charge.mp3")]
|
||||
[InlineData(@"2003 - Accelerated Evolution\CD02\01 - Depth Charge.mp3")]
|
||||
[InlineData(@"2003 - Accelerated Evolution\CD002\01 - Depth Charge.mp3")]
|
||||
[InlineData(@"2003 - Accelerated Evolution\CD 2\02 - Depth Charge.mp3")]
|
||||
[InlineData(@"2003 - Accelerated Evolution\CD 02\01 - Depth Charge.mp3")]
|
||||
[InlineData(@"2003 - Accelerated Evolution\CD 002\22 - Depth Charge.mp3")]
|
||||
[InlineData(@"Accelerated Evolution CD2\22 - Depth Charge.mp3")]
|
||||
[InlineData(@"Accelerated Evolution CD02\22 - Depth Charge.mp3")]
|
||||
public void Find_Disc_Number_Should_Be_Two(string filename)
|
||||
{
|
||||
var n = ID3TagsHelper.DetermineDiscNumber(new AudioMetaData { Filename = filename });
|
||||
Assert.Equal(2, n);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Find_Total_Discs_Should_Be_One()
|
||||
{
|
||||
var three = new List<AudioMetaData>
|
||||
{
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\01 - Depth Charge.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\02 - Not A Depth Charge.mp3"
|
||||
}
|
||||
};
|
||||
var n = ID3TagsHelper.DetermineTotalDiscNumbers(three);
|
||||
Assert.Equal(1, n);
|
||||
|
||||
three = new List<AudioMetaData>
|
||||
{
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD1\01 - Depth Charge.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD1\02 - Not A Depth Charge.mp3"
|
||||
}
|
||||
};
|
||||
n = ID3TagsHelper.DetermineTotalDiscNumbers(three);
|
||||
Assert.Equal(1, n);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Find_Total_Discs_Should_Be_Ten()
|
||||
{
|
||||
var three = new List<AudioMetaData>
|
||||
{
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 01\01 - Depth Charge.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 02\02 - Not A Depth Charge.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 04\01 - First.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 06\02 - Second.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 10\01 - Depth Charge.mp3"
|
||||
}
|
||||
};
|
||||
var n = ID3TagsHelper.DetermineTotalDiscNumbers(three);
|
||||
Assert.Equal(10, n);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Find_Total_Discs_Should_Be_Three()
|
||||
{
|
||||
var three = new List<AudioMetaData>
|
||||
{
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 01\01 - Depth Charge.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 01\02 - Not A Depth Charge.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 02\01 - First.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 02\02 - Second.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 03\01 - Depth Charge.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 03\02 - Depth Charge.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 03\03 - Depth Charge.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 03\04 - Depth Charge.mp3"
|
||||
}
|
||||
};
|
||||
var n = ID3TagsHelper.DetermineTotalDiscNumbers(three);
|
||||
Assert.Equal(3, n);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Find_Total_Discs_Should_Be_Two()
|
||||
{
|
||||
var three = new List<AudioMetaData>
|
||||
{
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 01\01 - Depth Charge.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 01\02 - Not A Depth Charge.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 01\01 - First.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 02\02 - Second.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 01\01 - Depth Charge.mp3"
|
||||
}
|
||||
};
|
||||
var n = ID3TagsHelper.DetermineTotalDiscNumbers(three);
|
||||
Assert.Equal(2, n);
|
||||
|
||||
three = new List<AudioMetaData>
|
||||
{
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD0\01 - Depth Charge.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD2\02 - Not A Depth Charge.mp3"
|
||||
}
|
||||
};
|
||||
n = ID3TagsHelper.DetermineTotalDiscNumbers(three);
|
||||
Assert.Equal(2, n);
|
||||
|
||||
three = new List<AudioMetaData>
|
||||
{
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 1\01 - Depth Charge.mp3"
|
||||
},
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 2\02 - Not A Depth Charge.mp3"
|
||||
}
|
||||
};
|
||||
n = ID3TagsHelper.DetermineTotalDiscNumbers(three);
|
||||
Assert.Equal(2, n);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Xunit;
|
||||
|
||||
namespace Roadie.Library.Tests
|
||||
|
@ -143,12 +144,90 @@ namespace Roadie.Library.Tests
|
|||
t = "[1970] 022 # Plastic Ono Band";
|
||||
Assert.Equal("[1970] 022 Plastic Ono Band", t.CleanString(this.Configuration));
|
||||
|
||||
t = "11 Love_.Mp3".CleanString(this.Configuration);
|
||||
Assert.Equal("11 Love.Mp3", t);
|
||||
}
|
||||
|
||||
t = "Love_.Mp3".CleanString(this.Configuration);
|
||||
[Fact]
|
||||
public void CleanString_Track()
|
||||
{
|
||||
|
||||
var t = "11 Love.Mp3".CleanString(this.Configuration, this.Configuration.Processing.TrackRemoveStringsRegex);
|
||||
Assert.Equal("Love.Mp3", t);
|
||||
|
||||
t = "99 -Love.Mp3".CleanString(this.Configuration, this.Configuration.Processing.TrackRemoveStringsRegex);
|
||||
Assert.Equal("Love.Mp3", t);
|
||||
|
||||
t = "99_Love.Mp3".CleanString(this.Configuration, this.Configuration.Processing.TrackRemoveStringsRegex);
|
||||
Assert.Equal("Love.Mp3", t);
|
||||
|
||||
t = "99 _ Love.Mp3".CleanString(this.Configuration, this.Configuration.Processing.TrackRemoveStringsRegex);
|
||||
Assert.Equal("Love.Mp3", t);
|
||||
|
||||
t = "001 Love.Mp3".CleanString(this.Configuration, this.Configuration.Processing.TrackRemoveStringsRegex);
|
||||
Assert.Equal("Love.Mp3", t);
|
||||
|
||||
t = "01 - Love.Mp3".CleanString(this.Configuration, this.Configuration.Processing.TrackRemoveStringsRegex);
|
||||
Assert.Equal("Love.Mp3", t);
|
||||
|
||||
t = "01. Love.Mp3".CleanString(this.Configuration, this.Configuration.Processing.TrackRemoveStringsRegex);
|
||||
Assert.Equal("Love.Mp3", t);
|
||||
|
||||
t = "Love.Mp3".CleanString(this.Configuration, this.Configuration.Processing.TrackRemoveStringsRegex);
|
||||
Assert.Equal("Love.Mp3", t);
|
||||
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Angie (Limited)")]
|
||||
[InlineData("Angie CD1")]
|
||||
[InlineData("Angie CD2")]
|
||||
[InlineData("Angie CD23")]
|
||||
[InlineData("Angie - CD1")]
|
||||
[InlineData("Angie (Limited Edition)")]
|
||||
[InlineData("Angie (Deluxe)")]
|
||||
[InlineData("Angie (Deluxe")]
|
||||
[InlineData("Angie (Remastered Deluxe Edition)")]
|
||||
[InlineData("Angie (Remastered Deluxe)")]
|
||||
[InlineData("Angie ( Deluxe )")]
|
||||
[InlineData("Angie (Deluxe Edition)")]
|
||||
[InlineData("Angie (Deluxe Expanded Edition)")]
|
||||
[InlineData("Angie (2CD Deluxe Edition)")]
|
||||
[InlineData("Angie (3CD Deluxe Edition)")]
|
||||
[InlineData("Angie [2008 Remastered Edition]")]
|
||||
[InlineData("Angie (Bonus CD)")]
|
||||
[InlineData("Angie (DELUXE)")]
|
||||
[InlineData("Angie (2013, Deluxe Expanded Edition, Disc 1)")]
|
||||
[InlineData("Angie (Deluxe Edition, CD1)")]
|
||||
[InlineData("Angie (20Th Anniversary Deluxe Edition Remastered)")]
|
||||
[InlineData("Angie (Japanese Edition)")]
|
||||
[InlineData("Angie (Asian Edition)")]
|
||||
[InlineData("Angie (2008 Remastered Edition Digipack)")]
|
||||
[InlineData("Angie (Re Release 2003)")]
|
||||
[InlineData("Angie [2006, Self Released]")]
|
||||
[InlineData("Angie (2002 Expanded Edition)")]
|
||||
[InlineData("Angie (Japan Ltd Dig")]
|
||||
public void CleanString_Release_Should_Be_Angie(string input)
|
||||
{
|
||||
var r = @"(\\s*(-\\s)*((CD[0-9][0-9]*)))|((\\(|\\[)+([0-9]|,|self|bonus|released|th|anniversary|re|release|cd|disc|deluxe|digipack|vinyl|japanese|asian|remastered|limited|expanded|edition|\\s)+(]|\\)))";
|
||||
var cleaned = input.CleanString(this.Configuration, r);
|
||||
Assert.Equal("Angie", cleaned);
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[InlineData("01 Batman Loves Robin")]
|
||||
[InlineData("01 Batman Loves Robin")]
|
||||
[InlineData("01 -Batman Loves Robin")]
|
||||
[InlineData("01 - Batman Loves Robin")]
|
||||
[InlineData("14 Batman Loves Robin")]
|
||||
[InlineData("49 Batman Loves Robin")]
|
||||
[InlineData("54 Batman Loves Robin")]
|
||||
[InlineData("348 Batman Loves Robin")]
|
||||
public void Test_Regex_String(string input)
|
||||
{
|
||||
var t1 = Regex.Replace(input, "^([0-9]+)(\\.|-|\\s)*", "");
|
||||
Assert.NotNull(t1);
|
||||
Assert.Equal("Batman Loves Robin", t1);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
"MaximumArtistImagesToAdd": 12,
|
||||
"MaximumReleaseImagesToAdd": 12,
|
||||
"MaxImageWidth": 800,
|
||||
"RemoveStringsRegex": "\\b[0-9]+\\s#\\s\\b",
|
||||
"TrackRemoveStringsRegex": "^([0-9]+)(\\.|-|\\s)*",
|
||||
"ReplaceStrings": [
|
||||
{
|
||||
"order": 1,
|
||||
|
|
|
@ -21,12 +21,18 @@ namespace Roadie.Library.Configuration
|
|||
public int MaximumArtistImagesToAdd { get; set; }
|
||||
public int MaximumReleaseImagesToAdd { get; set; }
|
||||
public string RemoveStringsRegex { get; set; }
|
||||
public string ArtistRemoveStringsRegex { get; set; }
|
||||
public string ReleaseRemoveStringsRegex { get; set; }
|
||||
public string TrackRemoveStringsRegex { get; set; }
|
||||
|
||||
public List<ReplacementString> ReplaceStrings { get; set; }
|
||||
public string UnknownFolder { get; set; }
|
||||
|
||||
public Processing()
|
||||
{
|
||||
this.ReplaceStrings = new List<ReplacementString>();
|
||||
this.DoAudioCleanup = true;
|
||||
this.DoClearComments = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@ namespace Roadie.Library.Extensions
|
|||
return input;
|
||||
}
|
||||
|
||||
public static string CleanString(this string input, IRoadieSettings settings)
|
||||
public static string CleanString(this string input, IRoadieSettings settings, string removeStringsRegex = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input) || settings == null)
|
||||
{
|
||||
|
@ -55,14 +55,10 @@ namespace Roadie.Library.Extensions
|
|||
result = result.Replace(kvp.Key, kvp.ReplaceWith, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
result = result.Trim().ToTitleCase(false);
|
||||
var removeStringsRegex = settings.Processing.RemoveStringsRegex;
|
||||
if (!string.IsNullOrEmpty(removeStringsRegex))
|
||||
var rs = removeStringsRegex ?? settings.Processing.RemoveStringsRegex;
|
||||
if (!string.IsNullOrEmpty(rs))
|
||||
{
|
||||
var regexParts = removeStringsRegex.Split('|');
|
||||
foreach (var regexPart in regexParts)
|
||||
{
|
||||
result = Regex.Replace(result, regexPart, "");
|
||||
}
|
||||
result = Regex.Replace(result, rs, "", RegexOptions.IgnoreCase);
|
||||
}
|
||||
if (result.Length > 5)
|
||||
{
|
||||
|
|
238
Roadie.Api.Library/Inspect/Inspector.cs
Normal file
238
Roadie.Api.Library/Inspect/Inspector.cs
Normal file
|
@ -0,0 +1,238 @@
|
|||
using HashidsNet;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.Extensions;
|
||||
using Roadie.Library.Inspect.Plugins;
|
||||
using Roadie.Library.MetaData.Audio;
|
||||
using Roadie.Library.MetaData.ID3Tags;
|
||||
using Roadie.Library.Processors;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Roadie.Library.Inspect
|
||||
{
|
||||
public class Inspector
|
||||
{
|
||||
private static readonly string Salt = "6856F2EE-5965-4345-884B-2CCA457AAF59";
|
||||
|
||||
private IEnumerable<IInspectorPlugin> _plugins = null;
|
||||
|
||||
public IEnumerable<IInspectorPlugin> Plugins
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._plugins == null)
|
||||
{
|
||||
var plugins = new List<IInspectorPlugin>();
|
||||
try
|
||||
{
|
||||
var type = typeof(IInspectorPlugin);
|
||||
var types = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(s => s.GetTypes())
|
||||
.Where(p => type.IsAssignableFrom(p));
|
||||
foreach (Type t in types)
|
||||
{
|
||||
if (t.GetInterface("IInspectorPlugin") != null && !t.IsAbstract && !t.IsInterface)
|
||||
{
|
||||
IInspectorPlugin plugin = Activator.CreateInstance(t, new object[] { this.Configuration, this.CacheManager, this.Logger }) as IInspectorPlugin;
|
||||
plugins.Add(plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
}
|
||||
this._plugins = plugins.ToArray();
|
||||
}
|
||||
return this._plugins;
|
||||
}
|
||||
}
|
||||
|
||||
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 Inspector()
|
||||
{
|
||||
Console.WriteLine("Roadie Media Inspector");
|
||||
|
||||
|
||||
this.MessageLogger = new EventMessageLogger();
|
||||
this.MessageLogger.Messages += MessageLogger_Messages;
|
||||
|
||||
var settings = new RoadieSettings();
|
||||
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
|
||||
configurationBuilder.AddJsonFile("appsettings.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 }] ");
|
||||
}
|
||||
|
||||
public static string ArtistInspectorToken(AudioMetaData metaData)
|
||||
{
|
||||
var hashids = new Hashids(Inspector.Salt);
|
||||
var artistId = 0;
|
||||
var bytes = System.Text.Encoding.ASCII.GetBytes(metaData.Artist);
|
||||
var looper = bytes.Length / 4;
|
||||
for(var i = 0; i < looper; i++)
|
||||
{
|
||||
artistId += BitConverter.ToInt32(bytes, i * 4);
|
||||
}
|
||||
if (artistId < 0)
|
||||
{
|
||||
artistId = artistId * -1;
|
||||
}
|
||||
var token = hashids.Encode(artistId);
|
||||
return token;
|
||||
}
|
||||
|
||||
public static string ReleaseInspectorToken(AudioMetaData metaData)
|
||||
{
|
||||
var hashids = new Hashids(Inspector.Salt);
|
||||
var releaseId = 0;
|
||||
var bytes = System.Text.Encoding.ASCII.GetBytes(metaData.Artist + metaData.Release);
|
||||
var looper = bytes.Length / 4;
|
||||
for (var i = 0; i < looper; i++)
|
||||
{
|
||||
releaseId += BitConverter.ToInt32(bytes, i * 4);
|
||||
}
|
||||
if (releaseId < 0)
|
||||
{
|
||||
releaseId = releaseId * -1;
|
||||
}
|
||||
var token = hashids.Encode(releaseId);
|
||||
return token;
|
||||
}
|
||||
|
||||
public void Inspect(bool doCopy, string folder, string destination)
|
||||
{
|
||||
// Get all the directorys in the directory
|
||||
var folderDirectories = Directory.GetDirectories(folder, "*.*", SearchOption.AllDirectories);
|
||||
var directories = new List<string>
|
||||
{
|
||||
folder
|
||||
};
|
||||
directories.AddRange(folderDirectories);
|
||||
foreach (var directory in directories)
|
||||
{
|
||||
Console.WriteLine($"╔ ░▒▓ Inspecting [{ directory }] ▓▒░");
|
||||
Console.WriteLine("╠═╗");
|
||||
// Get all the MP3 files in the folder
|
||||
var files = Directory.GetFiles(directory, "*.mp3", SearchOption.TopDirectoryOnly);
|
||||
if (files == null || !files.Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Console.WriteLine($"Found [{ files.Length }] mp3 Files");
|
||||
Console.WriteLine("╠═╣");
|
||||
// Get audiometadata and output details including weight/validity
|
||||
foreach (var file in files)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file);
|
||||
Console.WriteLine(tagLib.Data);
|
||||
}
|
||||
Console.WriteLine("╠═╣");
|
||||
List<AudioMetaData> fileMetaDatas = new List<AudioMetaData>();
|
||||
List<FileInfo> fileInfos = new List<FileInfo>();
|
||||
foreach (var file in files)
|
||||
{
|
||||
var fileInfo = new FileInfo(file);
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(fileInfo.FullName);
|
||||
var artistToken = ArtistInspectorToken(tagLib.Data);
|
||||
var releaseToken = ReleaseInspectorToken(tagLib.Data);
|
||||
var newFileName = $"{artistToken}_{releaseToken}_CD{ (tagLib.Data.Disk ?? ID3TagsHelper.DetermineDiscNumber(tagLib.Data)).ToString("000") }_{ tagLib.Data.TrackNumber.Value.ToString("0000") }.mp3";
|
||||
var subFolder = folder == destination ? fileInfo.DirectoryName : destination;
|
||||
var newPath = Path.Combine(destination, subFolder, newFileName.ToFileNameFriendly());
|
||||
if (!doCopy)
|
||||
{
|
||||
if (fileInfo.FullName != newPath)
|
||||
{
|
||||
if (File.Exists(newPath))
|
||||
{
|
||||
File.Delete(newPath);
|
||||
}
|
||||
fileInfo.MoveTo(newPath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fileInfo.CopyTo(newPath, true);
|
||||
}
|
||||
tagLib.Data.Filename = fileInfo.FullName;
|
||||
fileMetaDatas.Add(tagLib.Data);
|
||||
fileInfos.Add(fileInfo);
|
||||
}
|
||||
// Perform InspectorPlugins
|
||||
IEnumerable<AudioMetaData> pluginMetaData = fileMetaDatas.OrderBy(x => x.Filename);
|
||||
foreach (var plugin in this.Plugins.OrderBy(x => x.Order))
|
||||
{
|
||||
Console.WriteLine($"╟ Running Plugin { plugin.Description }");
|
||||
OperationResult<IEnumerable<AudioMetaData>> pluginResult = null;
|
||||
try
|
||||
{
|
||||
pluginResult = plugin.Process(pluginMetaData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Plugin Error: [{ ex.ToString() }]");
|
||||
}
|
||||
if (!pluginResult.IsSuccess)
|
||||
{
|
||||
Console.WriteLine($"Plugin Failed. Error [{ JsonConvert.SerializeObject(pluginResult)}]");
|
||||
}
|
||||
pluginMetaData = pluginResult.Data;
|
||||
}
|
||||
// Save all plugin modifications to the MetaData
|
||||
foreach (var metadata in pluginMetaData)
|
||||
{
|
||||
this.TagsHelper.WriteTags(metadata, metadata.Filename);
|
||||
}
|
||||
Console.WriteLine("╠═╣");
|
||||
// Get audiometadata and output details including weight/validity
|
||||
foreach (var fileInfo in fileInfos)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(fileInfo.FullName);
|
||||
if (!tagLib.IsSuccess || !tagLib.Data.IsValid)
|
||||
{
|
||||
Console.WriteLine($"■■ INVALID: {tagLib.Data }");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(tagLib.Data);
|
||||
}
|
||||
}
|
||||
Console.WriteLine("╚═╝");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
42
Roadie.Api.Library/Inspect/Plugins/CleanMetaData.cs
Normal file
42
Roadie.Api.Library/Inspect/Plugins/CleanMetaData.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.Extensions;
|
||||
using Roadie.Library.MetaData.Audio;
|
||||
using Roadie.Library.MetaData.ID3Tags;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins
|
||||
{
|
||||
public class CleanMetaData : PluginBase
|
||||
{
|
||||
public override int Order => 2;
|
||||
|
||||
public override string Description => "Clean: Clean the primary elements of MetaData";
|
||||
|
||||
public CleanMetaData(IRoadieSettings configuration, ICacheManager cacheManager, ILogger logger)
|
||||
: base(configuration, cacheManager, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override OperationResult<IEnumerable<AudioMetaData>> Process(IEnumerable<AudioMetaData> metaDatas)
|
||||
{
|
||||
var result = new OperationResult<IEnumerable<AudioMetaData>>();
|
||||
if (this.Configuration.Processing.DoAudioCleanup)
|
||||
{
|
||||
foreach (var metaData in metaDatas)
|
||||
{
|
||||
metaData.Artist = metaData.Artist.CleanString(this.Configuration, this.Configuration.Processing.ArtistRemoveStringsRegex).ToTitleCase(doPutTheAtEnd: false);
|
||||
metaData.Release = metaData.Release.CleanString(this.Configuration, this.Configuration.Processing.ReleaseRemoveStringsRegex).ToTitleCase(doPutTheAtEnd: false);
|
||||
metaData.TrackArtist = metaData.TrackArtist.CleanString(this.Configuration, this.Configuration.Processing.ReleaseRemoveStringsRegex).ToTitleCase(doPutTheAtEnd: false);
|
||||
metaData.Title = metaData.Title.CleanString(this.Configuration, this.Configuration.Processing.TrackRemoveStringsRegex).ToTitleCase(doPutTheAtEnd: false);
|
||||
}
|
||||
}
|
||||
result.Data = metaDatas;
|
||||
result.IsSuccess = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
14
Roadie.Api.Library/Inspect/Plugins/IInspectorPlugin.cs
Normal file
14
Roadie.Api.Library/Inspect/Plugins/IInspectorPlugin.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using Roadie.Library.MetaData.Audio;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins
|
||||
{
|
||||
public interface IInspectorPlugin
|
||||
{
|
||||
string Description { get; }
|
||||
int Order { get; }
|
||||
|
||||
OperationResult<IEnumerable<AudioMetaData>> Process(IEnumerable<AudioMetaData> metaDatas);
|
||||
}
|
||||
}
|
31
Roadie.Api.Library/Inspect/Plugins/PluginBase.cs
Normal file
31
Roadie.Api.Library/Inspect/Plugins/PluginBase.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.MetaData.Audio;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins
|
||||
{
|
||||
public abstract class PluginBase : IInspectorPlugin
|
||||
{
|
||||
protected IRoadieSettings Configuration { get; }
|
||||
protected ICacheManager CacheManager { get; }
|
||||
protected ILogger Logger { get; }
|
||||
|
||||
public abstract int Order { get; }
|
||||
public abstract string Description { get; }
|
||||
|
||||
public PluginBase(IRoadieSettings configuration, ICacheManager cacheManager, ILogger logger)
|
||||
{
|
||||
this.Configuration = configuration;
|
||||
this.CacheManager = cacheManager;
|
||||
this.Logger = logger;
|
||||
}
|
||||
|
||||
public abstract OperationResult<IEnumerable<AudioMetaData>> Process(IEnumerable<AudioMetaData> metaDatas);
|
||||
|
||||
}
|
||||
}
|
55
Roadie.Api.Library/Inspect/Plugins/Renumber.cs
Normal file
55
Roadie.Api.Library/Inspect/Plugins/Renumber.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.MetaData.Audio;
|
||||
using Roadie.Library.MetaData.ID3Tags;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins
|
||||
{
|
||||
public class Renumber : PluginBase
|
||||
{
|
||||
public override string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Renumber: Renumber all given tracks sequentially and set maximum number of tracks";
|
||||
}
|
||||
}
|
||||
|
||||
public override int Order { get; } = 1;
|
||||
|
||||
public Renumber(IRoadieSettings configuration, ICacheManager cacheManager, ILogger logger)
|
||||
: base(configuration, cacheManager, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override OperationResult<IEnumerable<AudioMetaData>> Process(IEnumerable<AudioMetaData> metaDatas)
|
||||
{
|
||||
var result = new OperationResult<IEnumerable<AudioMetaData>>();
|
||||
var totalNumberOfMedia = ID3TagsHelper.DetermineTotalDiscNumbers(metaDatas);
|
||||
var folders = metaDatas.GroupBy(x => x.FileInfo.DirectoryName);
|
||||
foreach(var folder in folders)
|
||||
{
|
||||
short looper = 0;
|
||||
foreach(var metaData in folder)
|
||||
{
|
||||
looper++;
|
||||
metaData.TrackNumber = looper;
|
||||
metaData.TotalTrackNumbers = ID3TagsHelper.DetermineTotalTrackNumbers(metaData.Filename) ?? folder.Count();
|
||||
metaData.Disk = ID3TagsHelper.DetermineDiscNumber(metaData);
|
||||
metaData.TotalDiscCount = totalNumberOfMedia;
|
||||
}
|
||||
}
|
||||
result.Data = metaDatas;
|
||||
result.IsSuccess = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
<PackageReference Include="CsvHelper" Version="12.1.2" />
|
||||
<PackageReference Include="EFCore.BulkExtensions" Version="2.4.0" />
|
||||
<PackageReference Include="FluentFTP" Version="21.0.0" />
|
||||
<PackageReference Include="Hashids.net" Version="1.2.2" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.8.14" />
|
||||
<PackageReference Include="IdSharp.Common" Version="1.0.1" />
|
||||
<PackageReference Include="IdSharp.Tagging" Version="1.0.0-rc3" />
|
||||
|
@ -19,6 +20,7 @@
|
|||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Redis" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
|
||||
<PackageReference Include="MimeMapping" Version="1.0.1.12" />
|
||||
<PackageReference Include="NodaTime" Version="2.4.4" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.1.4" />
|
||||
|
@ -27,8 +29,11 @@
|
|||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0005" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta0005" />
|
||||
<PackageReference Include="SixLabors.Shapes" Version="1.0.0-beta0007" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="4.5.1" />
|
||||
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="4.5.0" />
|
||||
<PackageReference Include="System.Runtime.Caching" Version="4.5.0" />
|
||||
<PackageReference Include="z440.atl.core" Version="2.5.0" />
|
||||
<PackageReference Include="zlib.net-mutliplatform" Version="1.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -106,6 +106,10 @@ namespace Roadie.Library.MetaData.Audio
|
|||
{
|
||||
result |= AudioMetaDataWeights.TrackNumber;
|
||||
}
|
||||
if ((this.TotalTrackNumbers ?? 0) > 1)
|
||||
{
|
||||
result |= AudioMetaDataWeights.TrackTotalNumber;
|
||||
}
|
||||
if (this.TotalSeconds > 1)
|
||||
{
|
||||
result |= AudioMetaDataWeights.Time;
|
||||
|
@ -136,11 +140,25 @@ namespace Roadie.Library.MetaData.Audio
|
|||
/// </summary>
|
||||
public int? Disk { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// TSST
|
||||
/// </summary>
|
||||
public string DiskSubTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Full filename to the file used to get this AudioMetaData
|
||||
/// </summary>
|
||||
public string Filename { get; set; }
|
||||
|
||||
private FileInfo _fileInfo = null;
|
||||
public FileInfo FileInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._fileInfo ?? (this._fileInfo = new FileInfo(this.Filename));
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<string> Genres { get; set; }
|
||||
public IEnumerable<AudioMetaDataImage> Images { get; set; }
|
||||
|
||||
|
@ -228,6 +246,11 @@ namespace Roadie.Library.MetaData.Audio
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Total number of Discs for Media
|
||||
/// </summary>
|
||||
public int? TotalDiscCount { get; set; }
|
||||
|
||||
public double TotalSeconds
|
||||
{
|
||||
get
|
||||
|
@ -288,7 +311,7 @@ namespace Roadie.Library.MetaData.Audio
|
|||
}
|
||||
if (!this._trackArtist.Contains(AudioMetaData.ArtistSplitCharacter.ToString()))
|
||||
{
|
||||
if(string.IsNullOrEmpty(this.TrackArtist))
|
||||
if (string.IsNullOrEmpty(this.TrackArtist))
|
||||
{
|
||||
return new string[0];
|
||||
}
|
||||
|
@ -375,16 +398,7 @@ namespace Roadie.Library.MetaData.Audio
|
|||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("IsValid: {0}{7}, ValidWeight {1}, Artist: {2}, Release: {3}, TrackNumber: {4}, Title: {5}, Year: {6}, Duration: {8}",
|
||||
this.IsValid,
|
||||
this.ValidWeight,
|
||||
this.Artist,
|
||||
this.Release,
|
||||
this.TrackNumber,
|
||||
this.Title,
|
||||
this.Year,
|
||||
this.IsSoundTrack ? " [SoundTrack ]" : string.Empty,
|
||||
this.Time == null ? "-" : this.Time.Value.ToString());
|
||||
return string.Format($"IsValid: {this.IsValid}{ (this.IsSoundTrack ? " [SoundTrack ]" : string.Empty)}, ValidWeight {this.ValidWeight}, Artist: {this.Artist}, Release: {this.Release}, TrackNumber: {this.TrackNumber}, TrackTotal: {this.TotalTrackNumbers}, Title: {this.Title}, Year: {this.Year}, Duration: {(this.Time == null ? "-" : this.Time.Value.ToString())}");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,4 +24,7 @@
|
|||
BandLogo = 19,
|
||||
PublisherLogo = 20,
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -9,9 +9,10 @@ namespace Roadie.Library.MetaData.Audio
|
|||
Year = 1,
|
||||
Time = 2,
|
||||
TrackNumber = 4,
|
||||
Release = 8,
|
||||
Title = 16,
|
||||
Artist = 32
|
||||
TrackTotalNumber = 8,
|
||||
Release = 16,
|
||||
Title = 32,
|
||||
Artist = 64
|
||||
}
|
||||
|
||||
//Artist + Release + TrackTitle 56
|
||||
|
|
|
@ -15,6 +15,12 @@ using IdSharp.Tagging.ID3v1;
|
|||
using IdSharp.Tagging.ID3v2;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using ATL.AudioData;
|
||||
using ATL;
|
||||
using System.Text.RegularExpressions;
|
||||
using ATL.CatalogDataReaders;
|
||||
using ATL.PlaylistReaders;
|
||||
|
||||
namespace Roadie.Library.MetaData.ID3Tags
|
||||
{
|
||||
public class ID3TagsHelper : MetaDataProviderBase, IID3TagsHelper
|
||||
|
@ -31,6 +37,11 @@ namespace Roadie.Library.MetaData.ID3Tags
|
|||
{
|
||||
return result;
|
||||
}
|
||||
result = this.MetaDataForFileFromATL(fileName);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
return new OperationResult<AudioMetaData>();
|
||||
}
|
||||
|
||||
|
@ -61,22 +72,57 @@ namespace Roadie.Library.MetaData.ID3Tags
|
|||
{
|
||||
try
|
||||
{
|
||||
// TODO
|
||||
if(!metaData.IsValid)
|
||||
{
|
||||
this.Logger.LogWarning($"Invalid MetaData `{ metaData }` to save to file [{ filename }]");
|
||||
return false;
|
||||
}
|
||||
ID3v1Tag.RemoveTag(filename);
|
||||
|
||||
var trackNumber = metaData.TrackNumber ?? 1;
|
||||
var totalTrackNumber = metaData.TotalTrackNumbers ?? trackNumber;
|
||||
|
||||
var disc = metaData.Disk ?? 1;
|
||||
var discCount = metaData.TotalDiscCount ?? disc;
|
||||
|
||||
IID3v2Tag id3v2 = new ID3v2Tag(filename)
|
||||
{
|
||||
Artist = metaData.Artist,
|
||||
Album = metaData.Release,
|
||||
Title = metaData.Title,
|
||||
Year = metaData.Year.Value.ToString(),
|
||||
TrackNumber = totalTrackNumber < 99 ? $"{trackNumber.ToString("00")}/{totalTrackNumber.ToString("00")}" : $"{trackNumber.ToString()}/{totalTrackNumber.ToString()}",
|
||||
DiscNumber = discCount < 99 ? $"{disc.ToString("00")}/{discCount.ToString("00")}" : $"{disc.ToString()}/{discCount.ToString()}"
|
||||
};
|
||||
if (metaData.TrackArtists.Any())
|
||||
{
|
||||
id3v2.OriginalArtist = string.Join("/", metaData.TrackArtists);
|
||||
}
|
||||
if (this.Configuration.Processing.DoClearComments)
|
||||
{
|
||||
if (id3v2.CommentsList.Any())
|
||||
{
|
||||
for (var i = 0; i < id3v2.CommentsList.Count; i++)
|
||||
{
|
||||
id3v2.CommentsList[i].Description = null;
|
||||
id3v2.CommentsList[i].Value = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
id3v2.Save(filename);
|
||||
|
||||
//// Delete first embedded picture (let's say it exists)
|
||||
//theTrack.EmbeddedPictures.RemoveAt(0);
|
||||
|
||||
//// Add 'CD' embedded picture
|
||||
//PictureInfo newPicture = new PictureInfo(Commons.ImageFormat.Gif, PictureInfo.PIC_TYPE.CD);
|
||||
//newPicture.PictureData = System.IO.File.ReadAllBytes("E:/temp/_Images/pic1.gif");
|
||||
//theTrack.EmbeddedPictures.Add(newPicture);
|
||||
|
||||
//// Save modifications on the disc
|
||||
//theTrack.Save();
|
||||
|
||||
|
||||
//var tagFile = TagLib.File.Create(filename);
|
||||
//tagFile.Tag.AlbumArtists = null;
|
||||
//tagFile.Tag.AlbumArtists = new[] { metaData.Artist };
|
||||
//tagFile.Tag.Performers = null;
|
||||
//if (metaData.TrackArtists.Any())
|
||||
//{
|
||||
// tagFile.Tag.Performers = metaData.TrackArtists.ToArray();
|
||||
//}
|
||||
//tagFile.Tag.Album = metaData.Release;
|
||||
//tagFile.Tag.Title = metaData.Title;
|
||||
//tagFile.Tag.Year = force ? (uint)(metaData.Year ?? 0) : tagFile.Tag.Year > 0 ? tagFile.Tag.Year : (uint)(metaData.Year ?? 0);
|
||||
//tagFile.Tag.Track = force ? (uint)(metaData.TrackNumber ?? 0) : tagFile.Tag.Track > 0 ? tagFile.Tag.Track : (uint)(metaData.TrackNumber ?? 0);
|
||||
//tagFile.Tag.TrackCount = force ? (uint)(metaData.TotalTrackNumbers ?? 0) : tagFile.Tag.TrackCount > 0 ? tagFile.Tag.TrackCount : (uint)(metaData.TotalTrackNumbers ?? 0);
|
||||
//tagFile.Tag.Disc = force ? (uint)(metaData.Disk ?? 0) : tagFile.Tag.Disc > 0 ? tagFile.Tag.Disc : (uint)(metaData.Disk ?? 0);
|
||||
//tagFile.Tag.Pictures = metaData.Images == null ? null : metaData.Images.Select(x => new TagLib.Picture
|
||||
//{
|
||||
// Data = new TagLib.ByteVector(x.Data),
|
||||
|
@ -94,6 +140,54 @@ namespace Roadie.Library.MetaData.ID3Tags
|
|||
return false;
|
||||
}
|
||||
|
||||
private OperationResult<AudioMetaData> MetaDataForFileFromATL(string fileName)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
AudioMetaData result = new AudioMetaData();
|
||||
var isSuccess = false;
|
||||
try
|
||||
{
|
||||
result.Filename = fileName;
|
||||
var theTrack = new ATL.Track(fileName);
|
||||
result.Release = theTrack.Album;
|
||||
result.Artist = theTrack.AlbumArtist ?? theTrack.Artist;
|
||||
result.ArtistRaw = theTrack.AlbumArtist ?? theTrack.Artist;
|
||||
result.Genres = theTrack.Genre?.Split(new char[] { ',', '\\' });
|
||||
result.TrackArtist = theTrack.OriginalArtist ?? theTrack.Artist ?? theTrack.AlbumArtist;
|
||||
result.TrackArtistRaw = theTrack.OriginalArtist;
|
||||
result.AudioBitrate = (int?)theTrack.Bitrate;
|
||||
result.AudioSampleRate = (int)theTrack.Bitrate;
|
||||
result.Disk = theTrack.DiscNumber;
|
||||
result.DiskSubTitle = theTrack.AdditionalFields["TSST"];
|
||||
result.Images = theTrack.EmbeddedPictures?.Select(x => new AudioMetaDataImage
|
||||
{
|
||||
Data = x.PictureData,
|
||||
Description = x.Description,
|
||||
MimeType = "image/jpg",
|
||||
Type = x.PicType == PictureInfo.PIC_TYPE.Front || x.PicType == PictureInfo.PIC_TYPE.Generic ? AudioMetaDataImageType.FrontCover : AudioMetaDataImageType.Other
|
||||
}).ToArray();
|
||||
result.Time = theTrack.DurationMs > 0 ? ((decimal?)theTrack.DurationMs).ToTimeSpan() : null;
|
||||
result.Title = theTrack.Title.ToTitleCase(false);
|
||||
result.TrackNumber = (short)theTrack.TrackNumber;
|
||||
result.Year = theTrack.Year;
|
||||
isSuccess = result.IsValid;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex, "MetaDataForFileFromTagLib Filename [" + fileName + "] Error [" + ex.Serialize() + "]");
|
||||
}
|
||||
sw.Stop();
|
||||
return new OperationResult<AudioMetaData>
|
||||
{
|
||||
IsSuccess = isSuccess,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Data = result
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private OperationResult<AudioMetaData> MetaDataForFileFromIdSharp(string fileName)
|
||||
{
|
||||
|
@ -103,6 +197,7 @@ namespace Roadie.Library.MetaData.ID3Tags
|
|||
var isSuccess = false;
|
||||
try
|
||||
{
|
||||
result.Filename = fileName;
|
||||
IAudioFile audioFile = AudioFile.Create(fileName, true);
|
||||
if (ID3v2Tag.DoesTagExist(fileName))
|
||||
{
|
||||
|
@ -117,6 +212,7 @@ namespace Roadie.Library.MetaData.ID3Tags
|
|||
result.AudioChannels = audioFile.Channels;
|
||||
result.AudioSampleRate = (int)audioFile.Bitrate;
|
||||
result.Disk = ID3TagsHelper.ParseDiscNumber(id3v2.DiscNumber);
|
||||
result.DiskSubTitle = id3v2.SetSubtitle;
|
||||
result.Images = id3v2.PictureList?.Select(x => new AudioMetaDataImage
|
||||
{
|
||||
Data = x.PictureData,
|
||||
|
@ -130,7 +226,7 @@ namespace Roadie.Library.MetaData.ID3Tags
|
|||
result.TotalTrackNumbers = ID3TagsHelper.ParseTotalTrackNumber(id3v2.TrackNumber);
|
||||
var year = id3v2.Year ?? id3v2.RecordingTimestamp ?? id3v2.ReleaseTimestamp ?? id3v2.OriginalReleaseTimestamp;
|
||||
result.Year = ID3TagsHelper.ParseYear(year);
|
||||
isSuccess = true;
|
||||
isSuccess = result.IsValid;
|
||||
}
|
||||
|
||||
if (!isSuccess)
|
||||
|
@ -149,7 +245,7 @@ namespace Roadie.Library.MetaData.ID3Tags
|
|||
result.TrackNumber = SafeParser.ToNumber<short?>(id3v1.TrackNumber);
|
||||
var date = SafeParser.ToDateTime(id3v1.Year);
|
||||
result.Year = date?.Year ?? SafeParser.ToNumber<int?>(id3v1.Year);
|
||||
isSuccess = true;
|
||||
isSuccess = result.IsValid;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,6 +263,79 @@ namespace Roadie.Library.MetaData.ID3Tags
|
|||
};
|
||||
}
|
||||
|
||||
public static short? DetermineTotalTrackNumbers(string filename, string trackNumber = null)
|
||||
{
|
||||
short? result = null;
|
||||
if(!string.IsNullOrEmpty(filename))
|
||||
{
|
||||
var fileInfo = new FileInfo(filename);
|
||||
var directoryName = fileInfo.DirectoryName;
|
||||
|
||||
// See if CUE sheet exists if so read tracks from that and return latest track number
|
||||
var cueFiles = Directory.GetFiles(directoryName, ("*.cue"));
|
||||
if(cueFiles != null && cueFiles.Any())
|
||||
{
|
||||
try
|
||||
{
|
||||
ICatalogDataReader theReader = CatalogDataReaderFactory.GetInstance().GetCatalogDataReader(cueFiles.First());
|
||||
result = (short)theReader.Tracks.Max(x => x.TrackNumber);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.Write("Error Reading Cue: " + ex.ToString());
|
||||
}
|
||||
}
|
||||
if(!result.HasValue)
|
||||
{
|
||||
// See if M3U sheet exists if so read tracks from that and return latest track number
|
||||
var m3uFiles = Directory.GetFiles(directoryName, ("*.m3u"));
|
||||
if (m3uFiles != null && m3uFiles.Any())
|
||||
{
|
||||
try
|
||||
{
|
||||
IPlaylistReader theReader = PlaylistReaderFactory.GetInstance().GetPlaylistReader(m3uFiles.First());
|
||||
result = (short)theReader.GetFiles().Count();
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.Write("Error Reading m3u: " + ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Try to parse from TrackNumber
|
||||
if (!result.HasValue)
|
||||
{
|
||||
result = ID3TagsHelper.ParseTotalTrackNumber(trackNumber);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int DetermineTotalDiscNumbers(IEnumerable<AudioMetaData> metaDatas)
|
||||
{
|
||||
var result = 1;
|
||||
foreach (var metaData in metaDatas.OrderBy(x => x.Filename))
|
||||
{
|
||||
var n = DetermineDiscNumber(metaData);
|
||||
result = result > n ? result : n;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int DetermineDiscNumber(AudioMetaData metaData)
|
||||
{
|
||||
var maxDiscNumber = 500; // Damnit Karajan
|
||||
for (var i = maxDiscNumber; i > 0; i--)
|
||||
{
|
||||
if (Regex.IsMatch(metaData.Filename, @"(cd\s*(0*" + i + "))", RegexOptions.IgnoreCase))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static short? ParseYear(string input)
|
||||
{
|
||||
if(string.IsNullOrEmpty(input))
|
||||
|
|
10
Roadie.sln
10
Roadie.sln
|
@ -18,6 +18,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roadie.Api.Services", "Road
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roadie.Api.Hubs", "Roadie.Api.Hubs\Roadie.Api.Hubs.csproj", "{E740C89E-3363-4577-873B-0871823E252C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Inspector", "Inspector\Inspector.csproj", "{9A0831DC-343A-4E0C-8617-AF62426F3BA8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -66,6 +68,14 @@ Global
|
|||
{E740C89E-3363-4577-873B-0871823E252C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E740C89E-3363-4577-873B-0871823E252C}.Release|x64.ActiveCfg = Release|x64
|
||||
{E740C89E-3363-4577-873B-0871823E252C}.Release|x64.Build.0 = Release|x64
|
||||
{9A0831DC-343A-4E0C-8617-AF62426F3BA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9A0831DC-343A-4E0C-8617-AF62426F3BA8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9A0831DC-343A-4E0C-8617-AF62426F3BA8}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{9A0831DC-343A-4E0C-8617-AF62426F3BA8}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{9A0831DC-343A-4E0C-8617-AF62426F3BA8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9A0831DC-343A-4E0C-8617-AF62426F3BA8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9A0831DC-343A-4E0C-8617-AF62426F3BA8}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{9A0831DC-343A-4E0C-8617-AF62426F3BA8}.Release|x64.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in a new issue