Beta v20180216.1

This commit is contained in:
Steven Hildreth 2019-02-16 15:08:20 -06:00
parent f404a41cfe
commit 48bb25106f
25 changed files with 1397 additions and 44 deletions

View 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
View 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);
}
}
}

View file

@ -0,0 +1,8 @@
{
"profiles": {
"Inspector": {
"commandName": "Project",
"commandLineArgs": "-f \"C:\\roadie_dev_root\\inbound\""
}
}
}

104
Inspector/appsettings.json Normal file
View 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": " "
}
]
}
}
}

View file

@ -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);
}
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View file

@ -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]

View file

@ -58,7 +58,7 @@
"MaximumArtistImagesToAdd": 12,
"MaximumReleaseImagesToAdd": 12,
"MaxImageWidth": 800,
"RemoveStringsRegex": "\\b[0-9]+\\s#\\s\\b",
"TrackRemoveStringsRegex": "^([0-9]+)(\\.|-|\\s)*",
"ReplaceStrings": [
{
"order": 1,

View file

@ -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;
}
}
}

View file

@ -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)
{

View 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("╚═╝");
}
}
}
}

View 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;
}
}
}

View 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);
}
}

View 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);
}
}

View 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;
}
}
}

View file

@ -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>

View file

@ -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())}");
}
}
}

View file

@ -24,4 +24,7 @@
BandLogo = 19,
PublisherLogo = 20,
}
}

View file

@ -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

View file

@ -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))

View file

@ -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.