mirror of
https://github.com/sphildreth/roadie
synced 2025-02-17 21:48:27 +00:00
Inspector work.
This commit is contained in:
parent
af71e4c9f2
commit
f36d54a193
54 changed files with 1146 additions and 380 deletions
Inspector
Roadie.Api.Library.Tests
Roadie.Api.Library
Configuration
ApiKey.csConverting.csFilePlugins.csIApiKey.csIConverting.csIFilePlugins.csIImageSize.csIInspector.csIIntegrations.csIProcessing.csIRedisCache.csIReplacementString.csIRoadieSettings.csInspector.csIntegrations.csProcessing.csRedisCache.csReplacementString.csRoadieSettings.csThumbnails.cs
FilePlugins
Imaging
Inspect
Inspector.cs
Roadie.Library.csprojPlugins
CleanMetaData.cs
Directory
EnsureArtistConsistent.csEnsureReleaseConsistent.csEnsureYearConsistent.csFolderPluginBase.csIInspectorDirectoryPlugin.cs
File
CleanUpArtists.csCleanUpComments.csCleanUpReleaseTitle.csCleanUpTrackTitle.csFilePluginBase.csIInspectorFilePlugin.csRenumber.cs
IInspectorPlugin.csPluginBase.csRenumber.csSearchEngines
Imaging
MetaData
Utility
Roadie.Api.Services
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.IO;
|
||||
using McMaster.Extensions.CommandLineUtils;
|
||||
|
||||
namespace Inspector
|
||||
|
@ -19,10 +20,20 @@ namespace Inspector
|
|||
[Option("-c", "Copy Dont Move Originals", CommandOptionType.NoValue)]
|
||||
public bool DoCopy { get; }
|
||||
|
||||
[Option("-r", "Only show what would be done, don't modify any files", CommandOptionType.NoValue)]
|
||||
public bool IsReadOnly { get; }
|
||||
|
||||
[Option("-s", "Don't append a subfolder to the Destination folder", CommandOptionType.NoValue)]
|
||||
public bool DontAppendSubFolder { get; }
|
||||
|
||||
[Option("-x", "Don't delete empty folders after inspection, if moving", CommandOptionType.NoValue)]
|
||||
public bool DontDeleteEmptyFolders { get; }
|
||||
|
||||
|
||||
private void OnExecute()
|
||||
{
|
||||
var inspector = new Roadie.Library.Inspect.Inspector();
|
||||
inspector.Inspect(this.DoCopy, this.Folder, this.Destination ?? this.Folder);
|
||||
inspector.Inspect(DoCopy, IsReadOnly, Folder, Destination ?? Folder, DontAppendSubFolder, IsReadOnly ? true : DontDeleteEmptyFolders);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"profiles": {
|
||||
"Inspector": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "-f \"C:\\roadie_dev_root\\inbound\""
|
||||
"commandLineArgs": "-f \"C:\\roadie_dev_root\\inbound\" -r"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -93,6 +93,11 @@ namespace Roadie.Library.Tests
|
|||
[InlineData("1983/02/24")]
|
||||
[InlineData("1983//1983")]
|
||||
[InlineData("1983\\1983")]
|
||||
[InlineData("1983,1983")]
|
||||
[InlineData("1983;1983")]
|
||||
[InlineData("1983 1983")]
|
||||
[InlineData("1983;;1983")]
|
||||
[InlineData("1983; 1983")]
|
||||
[InlineData("83")]
|
||||
public void ParseYearShouldBeNinteenEightyThree(string year)
|
||||
{
|
||||
|
@ -179,6 +184,21 @@ namespace Roadie.Library.Tests
|
|||
Assert.Null(dn);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("01. Up.mp3")]
|
||||
[InlineData("01 - Relentless Ascension.mp3")]
|
||||
[InlineData("01.Say Goodbye.mp3")]
|
||||
[InlineData("01 Up.mp3")]
|
||||
[InlineData("1 - Tithe II.mp3")]
|
||||
[InlineData("1 Up.mp3")]
|
||||
[InlineData("1. Up.mp3")]
|
||||
[InlineData("1- Up.mp3")]
|
||||
public void DetermineTrackNumber(string filename)
|
||||
{
|
||||
var tn = ID3TagsHelper.DetermineTrackNumber(filename);
|
||||
Assert.True(tn > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTotalTrackNumbersFromCue_Should_Be_Five()
|
||||
{
|
||||
|
@ -386,10 +406,10 @@ namespace Roadie.Library.Tests
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(@"N:\Rita Ora - Phoenix (Deluxe) (2018) Mp3 (320kbps) [Hunter]\Rita Ora - Phoenix (Deluxe) (2018)")]
|
||||
[InlineData(@"N:\Travis Scott - ASTROWORLD (2018) Mp3 (320kbps) [Hunter]")]
|
||||
[InlineData(@"N:\Lil Wayne - Tha Carter V (2018) Mp3 (320kbps) [Hunter]")]
|
||||
[InlineData(@"N:\Beyonce & JAY-Z - EVERYTHING IS LOVE (2018) Mp3 (320kbps) [Hunter]")]
|
||||
[InlineData(@"C:\roadie_dev_root\Rita Ora - Phoenix (Deluxe) (2018) Mp3 (320kbps) [Hunter]\Rita Ora - Phoenix (Deluxe) (2018)")]
|
||||
[InlineData(@"C:\roadie_dev_root\Travis Scott - ASTROWORLD (2018) Mp3 (320kbps) [Hunter]")]
|
||||
[InlineData(@"C:\roadie_dev_root\Lil Wayne - Tha Carter V (2018) Mp3 (320kbps) [Hunter]")]
|
||||
[InlineData(@"C:\roadie_dev_root\Beyonce & JAY-Z - EVERYTHING IS LOVE (2018) Mp3 (320kbps) [Hunter]")]
|
||||
public void ReadFolderTestAllFiles(string folderName)
|
||||
{
|
||||
if (!Directory.Exists(folderName))
|
||||
|
@ -470,7 +490,7 @@ namespace Roadie.Library.Tests
|
|||
[Fact]
|
||||
public void ReadID3TagsFromFileWithAlbumNoTrackSet()
|
||||
{
|
||||
var file = new FileInfo(@"Z:\inbound\MEGAPACK ---METAL-DEATH-BLACK---\ebony_tears-evil_as_hell-2001-ss\01-deviation-ss.mp3");
|
||||
var file = new FileInfo(@"M:\inbound\MEGAPACK ---METAL-DEATH-BLACK---\ebony_tears-evil_as_hell-2001-ss\01-deviation-ss.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
|
@ -496,7 +516,7 @@ namespace Roadie.Library.Tests
|
|||
[Fact]
|
||||
public void Read_File_Test_Is_valid()
|
||||
{
|
||||
var file = new FileInfo(@"Z:\unknown\2eec19bd-3575-4b7f-84dd-db2a0ec3e2f3~[2009] Dolly - Disc 1 Of 4~06 Nobody But You (Previously Unissued).mp3");
|
||||
var file = new FileInfo(@"M:\unknown\2eec19bd-3575-4b7f-84dd-db2a0ec3e2f3~[2009] Dolly - Disc 1 Of 4~06 Nobody But You (Previously Unissued).mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
|
@ -523,7 +543,7 @@ namespace Roadie.Library.Tests
|
|||
[Fact]
|
||||
public void Read_File_Test_Is_valid2()
|
||||
{
|
||||
var file = new FileInfo(@"Z:\library_old\Perverse\[2014] Champion Dub\01 Champion Dub (Original Mix).mp3");
|
||||
var file = new FileInfo(@"M:\library_old\Perverse\[2014] Champion Dub\01 Champion Dub (Original Mix).mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
|
@ -578,7 +598,7 @@ namespace Roadie.Library.Tests
|
|||
[Fact]
|
||||
public void ReadID3TagsFromFileWithTrackAndArtistTheSame()
|
||||
{
|
||||
var file = new FileInfo(@"Z:\library\Blind Melon\[1992] Blind Melon\01. Blind Melon - Soak The Sin.mp3");
|
||||
var file = new FileInfo(@"M:\library\Blind Melon\[1992] Blind Melon\01. Blind Melon - Soak The Sin.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
|
@ -670,7 +690,7 @@ namespace Roadie.Library.Tests
|
|||
[Fact]
|
||||
public void ReadID3TagsFromFile2()
|
||||
{
|
||||
var file = new FileInfo(@"Z:\library\Denver, John\[1972] Aerie\10 Readjustment Blues.mp3");
|
||||
var file = new FileInfo(@"M:\library\Denver, John\[1972] Aerie\10 Readjustment Blues.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
|
@ -724,7 +744,7 @@ namespace Roadie.Library.Tests
|
|||
[Fact]
|
||||
public void ReadID3TagsFromFile4()
|
||||
{
|
||||
var file = new FileInfo(@"Z:\library\Ac Dc\[1975] T.N.T\01 It'S A Long Way To The Top (If You Wanna Rock 'N' Roll).mp3");
|
||||
var file = new FileInfo(@"M:\library\Ac Dc\[1975] T.N.T\01 It'S A Long Way To The Top (If You Wanna Rock 'N' Roll).mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
|
|
|
@ -46,6 +46,7 @@ namespace Roadie.Library.Tests
|
|||
[InlineData("cover.png")]
|
||||
[InlineData("Cover.Jpg")]
|
||||
[InlineData("Release.JPG")]
|
||||
[InlineData("folder.JPG")]
|
||||
[InlineData("front.jpg")]
|
||||
[InlineData("FrOnt.jpg")]
|
||||
[InlineData("Art - front.jpg")]
|
||||
|
@ -106,6 +107,7 @@ namespace Roadie.Library.Tests
|
|||
[InlineData("cover 1.jpg")]
|
||||
[InlineData("cover_01.jpg")]
|
||||
[InlineData("cover 03.jpg")]
|
||||
[InlineData("Dixieland-Front1.jpg")]
|
||||
public void Test_Should_Not_Be_Release_Images(string input)
|
||||
{
|
||||
Assert.False(ImageHelper.IsReleaseImage(new FileInfo(input)));
|
||||
|
@ -153,7 +155,8 @@ namespace Roadie.Library.Tests
|
|||
|
||||
[InlineData("Booklet-1.jpg")]
|
||||
[InlineData("Booklet-10.jpg")]
|
||||
[InlineData("Booklet_1.jpg")]
|
||||
[InlineData("Booklet_1.jpg")]
|
||||
[InlineData("Booklet 3.jpg")]
|
||||
[InlineData("Booklet.jpg")]
|
||||
[InlineData("Book.jpg")]
|
||||
[InlineData("Book_3.jpg")]
|
||||
|
@ -181,6 +184,9 @@ namespace Roadie.Library.Tests
|
|||
[InlineData("release_1.jpg")]
|
||||
[InlineData("release 3.jpg")]
|
||||
[InlineData("release 10.jpg")]
|
||||
[InlineData("Dixieland-Label-Side 1.JPG")]
|
||||
[InlineData("Dixieland-Label-Side 2.JPG")]
|
||||
[InlineData("Hearing Is Believing-Inside 1.jpg")]
|
||||
public void Test_Should_Be_Release_Secondary_Images(string input)
|
||||
{
|
||||
Assert.True(ImageHelper.IsReleaseSecondaryImage(new FileInfo(input)));
|
||||
|
|
|
@ -48,11 +48,11 @@ namespace Roadie.Library.Tests
|
|||
{
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\01 - Depth Charge.mp3"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\02 - Not A Depth Charge.mp3"
|
||||
}
|
||||
};
|
||||
var n = ID3TagsHelper.DetermineTotalDiscNumbers(three);
|
||||
|
@ -62,11 +62,11 @@ namespace Roadie.Library.Tests
|
|||
{
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD1\01 - Depth Charge.mp3"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD1\02 - Not A Depth Charge.mp3"
|
||||
}
|
||||
};
|
||||
n = ID3TagsHelper.DetermineTotalDiscNumbers(three);
|
||||
|
@ -80,23 +80,23 @@ namespace Roadie.Library.Tests
|
|||
{
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 01\01 - Depth Charge.mp3"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 10\01 - Depth Charge.mp3"
|
||||
}
|
||||
};
|
||||
var n = ID3TagsHelper.DetermineTotalDiscNumbers(three);
|
||||
|
@ -110,35 +110,35 @@ namespace Roadie.Library.Tests
|
|||
{
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 01\01 - Depth Charge.mp3"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 03\04 - Depth Charge.mp3"
|
||||
}
|
||||
};
|
||||
var n = ID3TagsHelper.DetermineTotalDiscNumbers(three);
|
||||
|
@ -152,23 +152,23 @@ namespace Roadie.Library.Tests
|
|||
{
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 01\01 - Depth Charge.mp3"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 01\01 - Depth Charge.mp3"
|
||||
}
|
||||
};
|
||||
var n = ID3TagsHelper.DetermineTotalDiscNumbers(three);
|
||||
|
@ -178,11 +178,11 @@ namespace Roadie.Library.Tests
|
|||
{
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD0\01 - Depth Charge.mp3"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD2\02 - Not A Depth Charge.mp3"
|
||||
}
|
||||
};
|
||||
n = ID3TagsHelper.DetermineTotalDiscNumbers(three);
|
||||
|
@ -192,11 +192,11 @@ namespace Roadie.Library.Tests
|
|||
{
|
||||
new AudioMetaData
|
||||
{
|
||||
Filename = @"N:\Devin Townsend (1996 - 2016)\The Devin Townsend Band (2003 - 2006)\2003 - Accelerated Evolution\CD 1\01 - Depth Charge.mp3"
|
||||
Filename = @"C:\roadie_dev_root\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"
|
||||
Filename = @"C:\roadie_dev_root\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);
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace Roadie.Library.Configuration
|
|||
/// This is a Api Key used by Roadie to interact with an API (ie KeyName is "BingImageSearch" and its key is the BingImageSearch Key)
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ApiKey
|
||||
public class ApiKey : IApiKey
|
||||
{
|
||||
public string ApiName { get; set; }
|
||||
public string Key { get; set; }
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
[Serializable]
|
||||
public class Converting
|
||||
public class Converting : IConverting
|
||||
{
|
||||
public string APEConvertCommand { get; set; }
|
||||
public bool DoDeleteAfter { get; set; }
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
[Serializable]
|
||||
public class FilePlugins
|
||||
public class FilePlugins : IFilePlugins
|
||||
{
|
||||
public int MinWeightToDelete { get; set; }
|
||||
}
|
||||
|
|
9
Roadie.Api.Library/Configuration/IApiKey.cs
Normal file
9
Roadie.Api.Library/Configuration/IApiKey.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
public interface IApiKey
|
||||
{
|
||||
string ApiName { get; set; }
|
||||
string Key { get; set; }
|
||||
string KeySecret { get; set; }
|
||||
}
|
||||
}
|
10
Roadie.Api.Library/Configuration/IConverting.cs
Normal file
10
Roadie.Api.Library/Configuration/IConverting.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
public interface IConverting
|
||||
{
|
||||
string APEConvertCommand { get; set; }
|
||||
bool DoDeleteAfter { get; set; }
|
||||
string M4AConvertCommand { get; set; }
|
||||
string OGGConvertCommand { get; set; }
|
||||
}
|
||||
}
|
7
Roadie.Api.Library/Configuration/IFilePlugins.cs
Normal file
7
Roadie.Api.Library/Configuration/IFilePlugins.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
public interface IFilePlugins
|
||||
{
|
||||
int MinWeightToDelete { get; set; }
|
||||
}
|
||||
}
|
8
Roadie.Api.Library/Configuration/IImageSize.cs
Normal file
8
Roadie.Api.Library/Configuration/IImageSize.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
public interface IImageSize
|
||||
{
|
||||
short Height { get; set; }
|
||||
short Width { get; set; }
|
||||
}
|
||||
}
|
8
Roadie.Api.Library/Configuration/IInspector.cs
Normal file
8
Roadie.Api.Library/Configuration/IInspector.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
public interface IInspector
|
||||
{
|
||||
bool DoCopyFiles { get; set; }
|
||||
bool IsInReadOnlyMode { get; set; }
|
||||
}
|
||||
}
|
20
Roadie.Api.Library/Configuration/IIntegrations.cs
Normal file
20
Roadie.Api.Library/Configuration/IIntegrations.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
public interface IIntegrations
|
||||
{
|
||||
List<ApiKey> ApiKeys { get; set; }
|
||||
string DiscogsConsumerKey { get; }
|
||||
string DiscogsConsumerSecret { get; }
|
||||
bool DiscogsProviderEnabled { get; set; }
|
||||
short? DiscogsReadWriteTimeout { get; set; }
|
||||
short? DiscogsTimeout { get; set; }
|
||||
bool ITunesProviderEnabled { get; set; }
|
||||
string LastFMApiKey { get; }
|
||||
string LastFmApiSecret { get; }
|
||||
bool LastFmProviderEnabled { get; set; }
|
||||
bool MusicBrainzProviderEnabled { get; set; }
|
||||
bool SpotifyProviderEnabled { get; set; }
|
||||
}
|
||||
}
|
28
Roadie.Api.Library/Configuration/IProcessing.cs
Normal file
28
Roadie.Api.Library/Configuration/IProcessing.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
public interface IProcessing
|
||||
{
|
||||
string ArtistRemoveStringsRegex { get; set; }
|
||||
bool DoAudioCleanup { get; set; }
|
||||
bool DoClearComments { get; set; }
|
||||
bool DoDeleteUnknowns { get; set; }
|
||||
bool DoFolderArtistNameSet { get; set; }
|
||||
bool DoMoveUnknowns { get; set; }
|
||||
bool DoParseFromDiscogsDB { get; }
|
||||
bool DoParseFromDiscogsDBFindingTrackForArtist { get; }
|
||||
bool DoParseFromFileName { get; set; }
|
||||
bool DoParseFromLastFM { get; }
|
||||
bool DoParseFromMusicBrainz { get; }
|
||||
bool DoSaveEditsToTags { get; set; }
|
||||
int MaxImageWidth { get; set; }
|
||||
int MaximumArtistImagesToAdd { get; set; }
|
||||
int MaximumReleaseImagesToAdd { get; set; }
|
||||
string ReleaseRemoveStringsRegex { get; set; }
|
||||
string RemoveStringsRegex { get; set; }
|
||||
List<ReplacementString> ReplaceStrings { get; set; }
|
||||
string TrackRemoveStringsRegex { get; set; }
|
||||
string UnknownFolder { get; set; }
|
||||
}
|
||||
}
|
7
Roadie.Api.Library/Configuration/IRedisCache.cs
Normal file
7
Roadie.Api.Library/Configuration/IRedisCache.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
public interface IRedisCache
|
||||
{
|
||||
string ConnectionString { get; set; }
|
||||
}
|
||||
}
|
9
Roadie.Api.Library/Configuration/IReplacementString.cs
Normal file
9
Roadie.Api.Library/Configuration/IReplacementString.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
public interface IReplacementString
|
||||
{
|
||||
string Key { get; set; }
|
||||
int Order { get; set; }
|
||||
string ReplaceWith { get; set; }
|
||||
}
|
||||
}
|
|
@ -7,36 +7,37 @@ namespace Roadie.Library.Configuration
|
|||
Dictionary<string, List<string>> ArtistNameReplace { get; set; }
|
||||
string ConnectionString { get; set; }
|
||||
string ContentPath { get; set; }
|
||||
Converting Converting { get; set; }
|
||||
IConverting Converting { get; set; }
|
||||
string DefaultTimeZone { get; set; }
|
||||
string DiagnosticsPassword { get; set; }
|
||||
IEnumerable<string> DontDoMetaDataProvidersSearchArtists { get; set; }
|
||||
IEnumerable<string> FileExtensionsToDelete { get; set; }
|
||||
FilePlugins FilePlugins { get; set; }
|
||||
IFilePlugins FilePlugins { get; set; }
|
||||
string InboundFolder { get; set; }
|
||||
Integrations Integrations { get; set; }
|
||||
ImageSize LargeImageSize { get; set; }
|
||||
ImageSize MaximumImageSize { get; set; }
|
||||
IIntegrations Integrations { get; set; }
|
||||
IImageSize LargeImageSize { get; set; }
|
||||
IImageSize MaximumImageSize { get; set; }
|
||||
string LibraryFolder { get; set; }
|
||||
string ListenAddress { get; set; }
|
||||
ImageSize MediumImageSize { get; set; }
|
||||
Processing Processing { get; set; }
|
||||
IImageSize MediumImageSize { get; set; }
|
||||
IProcessing Processing { get; set; }
|
||||
bool RecordNoResultSearches { get; set; }
|
||||
RedisCache Redis { get; set; }
|
||||
IRedisCache Redis { get; set; }
|
||||
string SecretKey { get; set; }
|
||||
string SingleArtistHoldingFolder { get; set; }
|
||||
string SiteName { get; set; }
|
||||
ImageSize SmallImageSize { get; set; }
|
||||
IImageSize SmallImageSize { get; set; }
|
||||
string SmtpFromAddress { get; set; }
|
||||
string SmtpHost { get; set; }
|
||||
string SmtpPassword { get; set; }
|
||||
int SmtpPort { get; set; }
|
||||
string SmtpUsername { get; set; }
|
||||
bool SmtpUseSSl { get; set; }
|
||||
ImageSize ThumbnailImageSize { get; set; }
|
||||
IImageSize ThumbnailImageSize { get; set; }
|
||||
Dictionary<string, string> TrackPathReplace { get; set; }
|
||||
bool UseSSLBehindProxy { get; set; }
|
||||
string BehindProxyHost { get; set; }
|
||||
string WebsocketAddress { get; set; }
|
||||
IInspector Inspector { get; set; }
|
||||
}
|
||||
}
|
19
Roadie.Api.Library/Configuration/Inspector.cs
Normal file
19
Roadie.Api.Library/Configuration/Inspector.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
public class Inspector : IInspector
|
||||
{
|
||||
/// <summary>
|
||||
/// When true then make a copy of files to new destination versus moving files to destination.
|
||||
/// </summary>
|
||||
public bool DoCopyFiles { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When true then don't modify any files only report what would be done.
|
||||
/// </summary>
|
||||
public bool IsInReadOnlyMode { get; set; }
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
|||
|
||||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
public class Integrations
|
||||
public class Integrations : IIntegrations
|
||||
{
|
||||
private string _discogsConsumerKey = null;
|
||||
private string _discogsConsumerSecret = null;
|
||||
|
@ -14,6 +14,7 @@ namespace Roadie.Library.Configuration
|
|||
private string _lastFMSecret = null;
|
||||
public List<ApiKey> ApiKeys { get; set; }
|
||||
|
||||
|
||||
public string DiscogsConsumerKey
|
||||
{
|
||||
get
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
|||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
[Serializable]
|
||||
public class Processing
|
||||
public class Processing : IProcessing
|
||||
{
|
||||
public bool DoAudioCleanup { get; set; }
|
||||
public bool DoClearComments { get; set; }
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
[Serializable]
|
||||
public class RedisCache
|
||||
public class RedisCache : IRedisCache
|
||||
{
|
||||
public string ConnectionString { get; set; }
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ using System.Text;
|
|||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
[Serializable]
|
||||
public class ReplacementString
|
||||
public class ReplacementString : IReplacementString
|
||||
{
|
||||
public int Order { get; set; }
|
||||
public string Key { get; set; }
|
||||
|
|
|
@ -22,23 +22,23 @@ namespace Roadie.Library.Configuration
|
|||
/// </summary>
|
||||
public string ContentPath { get; set; }
|
||||
|
||||
public Converting Converting { get; set; }
|
||||
public IConverting Converting { get; set; }
|
||||
public string DefaultTimeZone { get; set; }
|
||||
public string DiagnosticsPassword { get; set; }
|
||||
public IEnumerable<string> DontDoMetaDataProvidersSearchArtists { get; set; }
|
||||
public IEnumerable<string> FileExtensionsToDelete { get; set; }
|
||||
public FilePlugins FilePlugins { get; set; }
|
||||
public IFilePlugins FilePlugins { get; set; }
|
||||
public string InboundFolder { get; set; }
|
||||
public Integrations Integrations { get; set; }
|
||||
public ImageSize LargeImageSize { get; set; }
|
||||
public ImageSize MaximumImageSize { get; set; }
|
||||
public IIntegrations Integrations { get; set; }
|
||||
public IImageSize LargeImageSize { get; set; }
|
||||
public IImageSize MaximumImageSize { get; set; }
|
||||
public string LibraryFolder { get; set; }
|
||||
public string ListenAddress { get; set; }
|
||||
public ImageSize MediumImageSize { get; set; }
|
||||
public Processing Processing { get; set; }
|
||||
public IImageSize MediumImageSize { get; set; }
|
||||
public IProcessing Processing { get; set; }
|
||||
public bool RecordNoResultSearches { get; set; }
|
||||
public RedisCache Redis { get; set; }
|
||||
public ImageSize SmallImageSize { get; set; }
|
||||
public IRedisCache Redis { get; set; }
|
||||
public IImageSize SmallImageSize { get; set; }
|
||||
public string SecretKey { get; set; }
|
||||
public string SingleArtistHoldingFolder { get; set; }
|
||||
public string SiteName { get; set; }
|
||||
|
@ -48,19 +48,24 @@ namespace Roadie.Library.Configuration
|
|||
public int SmtpPort { get; set; }
|
||||
public string SmtpUsername { get; set; }
|
||||
public bool SmtpUseSSl { get; set; }
|
||||
public ImageSize ThumbnailImageSize { get; set; }
|
||||
public IImageSize ThumbnailImageSize { get; set; }
|
||||
public Dictionary<string, string> TrackPathReplace { get; set; }
|
||||
public bool UseSSLBehindProxy { get; set; }
|
||||
public string BehindProxyHost { get; set; }
|
||||
public string WebsocketAddress { get; set; }
|
||||
public IInspector Inspector { get; set; }
|
||||
|
||||
public RoadieSettings()
|
||||
{
|
||||
this.ThumbnailImageSize = new ImageSize { Width = 80, Height = 80 };
|
||||
this.SmallImageSize = new ImageSize { Width = 160, Height = 160 };
|
||||
this.MediumImageSize = new ImageSize { Width = 320, Height = 320 };
|
||||
this.LargeImageSize = new ImageSize { Width = 500, Height = 500 };
|
||||
this.MaximumImageSize = new ImageSize { Width = 1024, Height = 1024 };
|
||||
ThumbnailImageSize = new ImageSize { Width = 80, Height = 80 };
|
||||
SmallImageSize = new ImageSize { Width = 160, Height = 160 };
|
||||
MediumImageSize = new ImageSize { Width = 320, Height = 320 };
|
||||
LargeImageSize = new ImageSize { Width = 500, Height = 500 };
|
||||
MaximumImageSize = new ImageSize { Width = 1024, Height = 1024 };
|
||||
Inspector = new Inspector();
|
||||
Converting = new Converting();
|
||||
Integrations = new Integrations();
|
||||
Processing = new Processing();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
[Serializable]
|
||||
public class ImageSize
|
||||
public class ImageSize : IImageSize
|
||||
{
|
||||
public short Height { get; set; }
|
||||
public short Width { get; set; }
|
||||
|
|
|
@ -10,6 +10,7 @@ using Roadie.Library.Imaging;
|
|||
using Roadie.Library.MetaData.Audio;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
@ -115,11 +116,9 @@ namespace Roadie.Library.FilePlugins
|
|||
try
|
||||
{
|
||||
// See if file folder parent folder (likely file is in release folder) has primary artist image if so then move to artist folder
|
||||
var artistImages = ImageHelper.FindImageTypeInDirectory(fileInfo.Directory, Enums.ImageType.Artist);
|
||||
if (!artistImages.Any())
|
||||
{
|
||||
artistImages = ImageHelper.FindImageTypeInDirectory(fileInfo.Directory.Parent, Enums.ImageType.Artist);
|
||||
}
|
||||
var artistImages = new List<FileInfo>();
|
||||
artistImages.AddRange(ImageHelper.FindImageTypeInDirectory(fileInfo.Directory, Enums.ImageType.Artist));
|
||||
artistImages.AddRange(ImageHelper.FindImageTypeInDirectory(fileInfo.Directory.Parent, Enums.ImageType.Artist));
|
||||
if (artistImages.Any())
|
||||
{
|
||||
var artistImage = artistImages.First();
|
||||
|
@ -141,11 +140,9 @@ namespace Roadie.Library.FilePlugins
|
|||
}
|
||||
|
||||
// See if any secondary artist images if so then move to artist folder
|
||||
artistImages = ImageHelper.FindImageTypeInDirectory(fileInfo.Directory, Enums.ImageType.ArtistSecondary);
|
||||
if (!artistImages.Any())
|
||||
{
|
||||
artistImages = ImageHelper.FindImageTypeInDirectory(fileInfo.Directory.Parent, Enums.ImageType.Artist);
|
||||
}
|
||||
artistImages.Clear();
|
||||
artistImages.AddRange(ImageHelper.FindImageTypeInDirectory(fileInfo.Directory, Enums.ImageType.ArtistSecondary));
|
||||
artistImages.AddRange(ImageHelper.FindImageTypeInDirectory(fileInfo.Directory.Parent, Enums.ImageType.Artist));
|
||||
if (artistImages.Any())
|
||||
{
|
||||
var looper = 0;
|
||||
|
|
|
@ -154,7 +154,7 @@ namespace Roadie.Library.Imaging
|
|||
{
|
||||
return false;
|
||||
}
|
||||
return Regex.IsMatch(fileinfo.Name, @"((f[-_\s]*[0-9]*)|cover|release|front)\.(jpg|jpeg|png|bmp|gif)", RegexOptions.IgnoreCase);
|
||||
return Regex.IsMatch(fileinfo.Name, @"((f[-_\s]*[0-9]*)|cover|folder|release|front)\.(jpg|jpeg|png|bmp|gif)", RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
public static bool IsReleaseSecondaryImage(FileInfo fileinfo)
|
||||
|
@ -163,7 +163,7 @@ namespace Roadie.Library.Imaging
|
|||
{
|
||||
return false;
|
||||
}
|
||||
return Regex.IsMatch(fileinfo.Name, @"((book[let]*[-_]*[0-9]*)|(encartes[-_\s]*[(]*[0-9]*[)]*)|(cover[\s_-]+[0-9]+)|back|disc|inside|inlet|inlay|cd[0-9]*|inside|(release[\s_-]+[0-9]+))\.(jpg|jpeg|png|bmp|gif)", RegexOptions.IgnoreCase);
|
||||
return Regex.IsMatch(fileinfo.Name, @"((book[let]*[-_\s]*[0-9]*)|(encartes[-_\s]*[(]*[0-9]*[)]*)|(cover[\s_-]+[0-9]+)|back|disc|(.*)[in]*side(.*)|inlet|inlay|cd[0-9]*|(release[\s_-]+[0-9]+))\.(jpg|jpeg|png|bmp|gif)", RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
public static bool IsLabelImage(FileInfo fileinfo)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using HashidsNet;
|
||||
using Mapster;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
|
@ -6,14 +7,18 @@ using Roadie.Library.Caching;
|
|||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.Extensions;
|
||||
using Roadie.Library.Inspect.Plugins;
|
||||
using Roadie.Library.Inspect.Plugins.File;
|
||||
using Roadie.Library.Inspect.Plugins.Directory;
|
||||
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.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Roadie.Library.Imaging;
|
||||
using Roadie.Library.Utility;
|
||||
|
||||
namespace Roadie.Library.Inspect
|
||||
{
|
||||
|
@ -21,63 +26,94 @@ namespace Roadie.Library.Inspect
|
|||
{
|
||||
private static readonly string Salt = "6856F2EE-5965-4345-884B-2CCA457AAF59";
|
||||
|
||||
private IEnumerable<IInspectorPlugin> _plugins = null;
|
||||
private IEnumerable<IInspectorFilePlugin> _filePlugins = null;
|
||||
private IEnumerable<IInspectorDirectoryPlugin> _directoryPlugins = null;
|
||||
|
||||
public IEnumerable<IInspectorPlugin> Plugins
|
||||
public DictionaryCacheManager CacheManager { get; }
|
||||
|
||||
public IEnumerable<IInspectorFilePlugin> FilePlugins
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._plugins == null)
|
||||
if (_filePlugins == null)
|
||||
{
|
||||
var plugins = new List<IInspectorPlugin>();
|
||||
var plugins = new List<IInspectorFilePlugin>();
|
||||
try
|
||||
{
|
||||
var type = typeof(IInspectorPlugin);
|
||||
var type = typeof(IInspectorFilePlugin);
|
||||
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)
|
||||
if (t.GetInterface("IInspectorFilePlugin") != null && !t.IsAbstract && !t.IsInterface)
|
||||
{
|
||||
IInspectorPlugin plugin = Activator.CreateInstance(t, new object[] { this.Configuration, this.CacheManager, this.Logger }) as IInspectorPlugin;
|
||||
IInspectorFilePlugin plugin = Activator.CreateInstance(t, new object[] { Configuration, CacheManager, Logger, TagsHelper }) as IInspectorFilePlugin;
|
||||
plugins.Add(plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex);
|
||||
Logger.LogError(ex);
|
||||
}
|
||||
this._plugins = plugins.ToArray();
|
||||
_filePlugins = plugins.ToArray();
|
||||
}
|
||||
return this._plugins;
|
||||
return _filePlugins;
|
||||
}
|
||||
}
|
||||
|
||||
private IEventMessageLogger MessageLogger { get; }
|
||||
public IEnumerable<IInspectorDirectoryPlugin> DirectoryPlugins
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_filePlugins == null)
|
||||
{
|
||||
var plugins = new List<IInspectorDirectoryPlugin>();
|
||||
try
|
||||
{
|
||||
var type = typeof(IInspectorDirectoryPlugin);
|
||||
var types = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(s => s.GetTypes())
|
||||
.Where(p => type.IsAssignableFrom(p));
|
||||
foreach (Type t in types)
|
||||
{
|
||||
if (t.GetInterface("IInspectorDirectoryPlugin") != null && !t.IsAbstract && !t.IsInterface)
|
||||
{
|
||||
IInspectorDirectoryPlugin plugin = Activator.CreateInstance(t, new object[] { Configuration, CacheManager, Logger, TagsHelper }) as IInspectorDirectoryPlugin;
|
||||
plugins.Add(plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
}
|
||||
_directoryPlugins = plugins.ToArray();
|
||||
}
|
||||
return _directoryPlugins;
|
||||
}
|
||||
}
|
||||
|
||||
private IRoadieSettings Configuration { get; }
|
||||
|
||||
private ILogger Logger
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.MessageLogger as ILogger;
|
||||
return MessageLogger as ILogger;
|
||||
}
|
||||
}
|
||||
|
||||
private IEventMessageLogger MessageLogger { get; }
|
||||
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;
|
||||
MessageLogger = new EventMessageLogger();
|
||||
MessageLogger.Messages += MessageLogger_Messages;
|
||||
|
||||
var settings = new RoadieSettings();
|
||||
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
|
||||
|
@ -85,154 +121,283 @@ namespace Roadie.Library.Inspect
|
|||
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);
|
||||
|
||||
Configuration = settings;
|
||||
CacheManager = new DictionaryCacheManager(Logger, new CachePolicy(TimeSpan.FromHours(4)));
|
||||
TagsHelper = new ID3TagsHelper(Configuration, CacheManager, Logger);
|
||||
}
|
||||
|
||||
private void MessageLogger_Messages(object sender, EventMessage e)
|
||||
public static string ToToken(string input)
|
||||
{
|
||||
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 hashids = new Hashids(Salt);
|
||||
var numbers = 0;
|
||||
var bytes = System.Text.Encoding.ASCII.GetBytes(input);
|
||||
var looper = bytes.Length / 4;
|
||||
for (var i = 0; i < looper; i++)
|
||||
{
|
||||
releaseId += BitConverter.ToInt32(bytes, i * 4);
|
||||
numbers += BitConverter.ToInt32(bytes, i * 4);
|
||||
}
|
||||
if (releaseId < 0)
|
||||
if (numbers < 0)
|
||||
{
|
||||
releaseId = releaseId * -1;
|
||||
numbers *= -1;
|
||||
}
|
||||
var token = hashids.Encode(releaseId);
|
||||
var token = hashids.Encode(numbers);
|
||||
return token;
|
||||
}
|
||||
|
||||
public void Inspect(bool doCopy, string folder, string destination)
|
||||
public static string ArtistInspectorToken(AudioMetaData metaData) => ToToken(metaData.Artist);
|
||||
|
||||
public static string ReleaseInspectorToken(AudioMetaData metaData) => ToToken(metaData.Artist + metaData.Release);
|
||||
|
||||
public void Inspect(bool doCopy, bool isReadOnly, string directoryToInspect, string destination, bool dontAppendSubFolder, bool dontDeleteEmptyFolders)
|
||||
{
|
||||
Configuration.Inspector.IsInReadOnlyMode = isReadOnly;
|
||||
Configuration.Inspector.DoCopyFiles = doCopy;
|
||||
|
||||
var artistsFound = new List<string>();
|
||||
var releasesFound = new List<string>();
|
||||
var mp3FilesFoundCount = 0;
|
||||
// Create a new destination subfolder for each Inspector run by Current timestamp
|
||||
var dest = Path.Combine(destination, DateTime.UtcNow.ToString("yyyyMMddHHmm"));
|
||||
if (isReadOnly || dontAppendSubFolder)
|
||||
{
|
||||
dest = destination;
|
||||
}
|
||||
if (!isReadOnly && !Directory.Exists(dest))
|
||||
{
|
||||
Directory.CreateDirectory(dest);
|
||||
}
|
||||
// Get all the directorys in the directory
|
||||
var folderDirectories = Directory.GetDirectories(folder, "*.*", SearchOption.AllDirectories);
|
||||
var directoryDirectories = Directory.GetDirectories(directoryToInspect, "*.*", SearchOption.AllDirectories);
|
||||
var directories = new List<string>
|
||||
{
|
||||
folder
|
||||
directoryToInspect
|
||||
};
|
||||
directories.AddRange(folderDirectories);
|
||||
directories.AddRange(directoryDirectories);
|
||||
directories.Remove(dest);
|
||||
var inspectedImagesInDirectories = new List<string>();
|
||||
foreach (var directory in directories)
|
||||
{
|
||||
var directoryInfo = new DirectoryInfo(directory);
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
Console.WriteLine($"╔ ░▒▓ Inspecting [{ directory }] ▓▒░");
|
||||
Console.WriteLine("╠═╗");
|
||||
// Get all the MP3 files in the folder
|
||||
Console.WriteLine("╠╦════════════════════════╣");
|
||||
|
||||
// Get all the MP3 files in 'directory'
|
||||
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)
|
||||
// Run directory plugins against current directory
|
||||
foreach (var plugin in DirectoryPlugins.OrderBy(x => x.Order))
|
||||
{
|
||||
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;
|
||||
Console.WriteLine($"╠╬═ Running Directory Plugin { plugin.Description }");
|
||||
try
|
||||
{
|
||||
pluginResult = plugin.Process(pluginMetaData);
|
||||
var pluginResult = plugin.Process(directoryInfo);
|
||||
if (!pluginResult.IsSuccess)
|
||||
{
|
||||
Console.WriteLine($"Plugin Failed: Error [{ JsonConvert.SerializeObject(pluginResult)}]");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"╠╣ Directory Plugin Message: { pluginResult.Data }");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Plugin Error: [{ ex.ToString() }]");
|
||||
return;
|
||||
}
|
||||
if (!pluginResult.IsSuccess)
|
||||
}
|
||||
Console.WriteLine($"╠╝");
|
||||
Console.WriteLine($"╟─ Found [{ files.Length }] mp3 Files");
|
||||
List<AudioMetaData> fileMetaDatas = new List<AudioMetaData>();
|
||||
List<FileInfo> fileInfos = new List<FileInfo>();
|
||||
// Inspect the found MP3 files in 'directory'
|
||||
foreach (var file in files)
|
||||
{
|
||||
mp3FilesFoundCount++;
|
||||
var fileInfo = new FileInfo(file);
|
||||
Console.WriteLine($"╟─ Inspecting [{ fileInfo.FullName }]");
|
||||
var tagLib = TagsHelper.MetaDataForFile(fileInfo.FullName);
|
||||
Console.WriteLine($"╟ (Pre ) : { tagLib.Data }");
|
||||
tagLib.Data.Filename = fileInfo.FullName;
|
||||
var originalMetaData = tagLib.Data.Adapt<AudioMetaData>();
|
||||
var pluginMetaData = tagLib.Data;
|
||||
// Run all file plugins against the MP3 file modifying the MetaData
|
||||
foreach (var plugin in FilePlugins.OrderBy(x => x.Order))
|
||||
{
|
||||
Console.WriteLine($"Plugin Failed. Error [{ JsonConvert.SerializeObject(pluginResult)}]");
|
||||
Console.WriteLine($"╟┤ Running File Plugin { plugin.Description }");
|
||||
OperationResult<AudioMetaData> pluginResult = null;
|
||||
try
|
||||
{
|
||||
pluginResult = plugin.Process(pluginMetaData);
|
||||
if (!pluginResult.IsSuccess)
|
||||
{
|
||||
Console.WriteLine($"Plugin Failed: Error [{ JsonConvert.SerializeObject(pluginResult)}]");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Plugin Error: [{ ex.ToString() }]");
|
||||
return;
|
||||
}
|
||||
pluginMetaData = pluginResult.Data;
|
||||
}
|
||||
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)
|
||||
// See if the MetaData from the Plugins is different from the original
|
||||
var differences = AutoCompare.Comparer.Compare(originalMetaData, pluginMetaData);
|
||||
if (differences.Any())
|
||||
{
|
||||
Console.WriteLine($"■■ INVALID: {tagLib.Data }");
|
||||
var skipDifferences = new List<string> { "AudioMetaDataWeights", "FileInfo", "Images", "TrackArtists", "ValidWeight" };
|
||||
var differencesDescription = $"{ System.Environment.NewLine }";
|
||||
foreach (var difference in differences)
|
||||
{
|
||||
if (skipDifferences.Contains(difference.Name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
differencesDescription += $"╟ || { difference.Name } : Was [{ difference.OldValue}] Now [{ difference.NewValue}]{ System.Environment.NewLine }";
|
||||
}
|
||||
Console.Write($"╟ ≡ != ID3 Tag Modified: { differencesDescription }");
|
||||
|
||||
if (!isReadOnly)
|
||||
{
|
||||
TagsHelper.WriteTags(pluginMetaData, pluginMetaData.Filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("╟ ■ Read Only Mode: Not Modifying File ID3 Tags.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(tagLib.Data);
|
||||
Console.WriteLine($"╟ ≡ == ID3 Tag NOT Modified");
|
||||
}
|
||||
if(!pluginMetaData.IsValid)
|
||||
{
|
||||
Console.WriteLine($"╟ ■■ INVALID: { pluginMetaData }");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"╟ (Post) : { pluginMetaData }");
|
||||
}
|
||||
var artistToken = ArtistInspectorToken(tagLib.Data);
|
||||
if(!artistsFound.Contains(artistToken))
|
||||
{
|
||||
artistsFound.Add(artistToken);
|
||||
}
|
||||
var releaseToken = ReleaseInspectorToken(tagLib.Data);
|
||||
if (!releasesFound.Contains(releaseToken))
|
||||
{
|
||||
releasesFound.Add(releaseToken);
|
||||
}
|
||||
var newFileName = $"CD{ (tagLib.Data.Disk ?? ID3TagsHelper.DetermineDiscNumber(tagLib.Data)).ToString("000") }_{ tagLib.Data.TrackNumber.Value.ToString("0000") }.mp3";
|
||||
// Artist sub folder is created to hold Releases for Artist and Artist Images
|
||||
var artistSubDirectory = directory == dest ? fileInfo.DirectoryName : Path.Combine(dest, artistToken);
|
||||
// Each release is put into a subfolder into the current run Inspector folder to hold MP3 Files and Release Images
|
||||
var subDirectory = directory == dest ? fileInfo.DirectoryName : Path.Combine(dest, artistToken, releaseToken);
|
||||
if(!isReadOnly && !Directory.Exists(subDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(subDirectory);
|
||||
}
|
||||
// If enabled move MP3 to new folder
|
||||
var newPath = Path.Combine(dest, subDirectory, newFileName.ToFileNameFriendly());
|
||||
if (isReadOnly)
|
||||
{
|
||||
Console.WriteLine($"╟ ■ Read Only Mode: File would be [{ (doCopy ? "Copied" : "Moved") }] to [{ newPath }]");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!doCopy)
|
||||
{
|
||||
if (fileInfo.FullName != newPath)
|
||||
{
|
||||
if (File.Exists(newPath))
|
||||
{
|
||||
File.Delete(newPath);
|
||||
}
|
||||
fileInfo.MoveTo(newPath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fileInfo.CopyTo(newPath, true);
|
||||
}
|
||||
}
|
||||
if (!inspectedImagesInDirectories.Contains(fileInfo.DirectoryName))
|
||||
{
|
||||
// Get all artist images and move to artist folder
|
||||
var foundArtistImages = new List<FileInfo>();
|
||||
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo.Parent, Enums.ImageType.Artist, SearchOption.TopDirectoryOnly));
|
||||
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo.Parent, Enums.ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly));
|
||||
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, Enums.ImageType.Artist, SearchOption.TopDirectoryOnly));
|
||||
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, Enums.ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly));
|
||||
|
||||
foreach (var artistImage in foundArtistImages)
|
||||
{
|
||||
MoveImage(isReadOnly, doCopy, dest, artistSubDirectory, artistImage);
|
||||
}
|
||||
|
||||
// Get all release images and move to release folder
|
||||
var foundReleaseImages = new List<FileInfo>();
|
||||
foundReleaseImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, Enums.ImageType.Release, SearchOption.AllDirectories));
|
||||
foundReleaseImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, Enums.ImageType.ReleaseSecondary, SearchOption.AllDirectories));
|
||||
foreach (var foundReleaseImage in foundReleaseImages)
|
||||
{
|
||||
MoveImage(isReadOnly, doCopy, dest, subDirectory, foundReleaseImage);
|
||||
}
|
||||
inspectedImagesInDirectories.Add(fileInfo.DirectoryName);
|
||||
}
|
||||
Console.WriteLine("╠════════════════════════╣");
|
||||
}
|
||||
Console.WriteLine("╚═╝");
|
||||
sw.Stop();
|
||||
Console.WriteLine($"╚═ Elapsed Time { sw.ElapsedMilliseconds.ToString("0000000") }, Artists { artistsFound.Count() }, Releases { releasesFound.Count() }, MP3s { mp3FilesFoundCount } ═╝");
|
||||
}
|
||||
if (!dontDeleteEmptyFolders)
|
||||
{
|
||||
var delEmptyFolderIn = new DirectoryInfo(directoryToInspect);
|
||||
Console.WriteLine($"╟ X Deleting Empty folders in [{ delEmptyFolderIn.FullName }]");
|
||||
FolderPathHelper.DeleteEmptyDirs(directoryToInspect);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("╟ ■ Read Only Mode: Not deleting empty folders.");
|
||||
}
|
||||
}
|
||||
|
||||
private void MoveImage(bool isReadOnly, bool doCopy, string dest, string subdirectory, FileInfo image)
|
||||
{
|
||||
Console.WriteLine($"╟─ Inspecting Image [{ image.FullName }]");
|
||||
var newImagePath = Path.Combine(dest, subdirectory, image.Name);
|
||||
if (isReadOnly)
|
||||
{
|
||||
Console.WriteLine($"╟ ■ Read Only Mode: Would be [{ (doCopy ? "Copied" : "Moved") }] to [{ newImagePath }]");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!doCopy)
|
||||
{
|
||||
if (image.FullName != newImagePath)
|
||||
{
|
||||
if (File.Exists(newImagePath))
|
||||
{
|
||||
File.Delete(newImagePath);
|
||||
}
|
||||
image.MoveTo(newImagePath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
image.CopyTo(newImagePath, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MessageLogger_Messages(object sender, EventMessage e) => Console.WriteLine($"Log Level [{ e.Level }] Log Message [{ e.Message }] ");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.MetaData.ID3Tags;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins.Directory
|
||||
{
|
||||
public class EnsureArtistConsistent : FolderPluginBase
|
||||
{
|
||||
public override string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Consistent: Ensure all MP3 files in folder have same Artist (TPE1)";
|
||||
}
|
||||
}
|
||||
|
||||
public override int Order { get; } = 1;
|
||||
|
||||
public EnsureArtistConsistent(IRoadieSettings configuration, ICacheManager cacheManager, ILogger logger, IID3TagsHelper tagsHelper)
|
||||
: base(configuration, cacheManager, logger, tagsHelper)
|
||||
{
|
||||
}
|
||||
|
||||
public override OperationResult<string> Process(DirectoryInfo directory)
|
||||
{
|
||||
var result = new OperationResult<string>();
|
||||
var data = string.Empty;
|
||||
var found = 0;
|
||||
var modified = 0;
|
||||
var metaDatasForFilesInFolder = GetAudioMetaDatasForDirectory(directory);
|
||||
if (metaDatasForFilesInFolder.Any())
|
||||
{
|
||||
found = metaDatasForFilesInFolder.Count();
|
||||
var firstMetaData = metaDatasForFilesInFolder.OrderBy(x => x.TrackNumber).FirstOrDefault();
|
||||
if (firstMetaData == null)
|
||||
{
|
||||
return new OperationResult<string>("Error Getting First MetaData")
|
||||
{
|
||||
Data = $"Unable to read Metadatas for Directory [{ directory.FullName }]"
|
||||
};
|
||||
}
|
||||
var artist = firstMetaData.Artist;
|
||||
foreach (var metaData in metaDatasForFilesInFolder.Where(x => x.Artist != artist))
|
||||
{
|
||||
modified++;
|
||||
Console.WriteLine($"╟ Setting Arist to [{ artist }], was [{ metaData.Artist }] on file [{ metaData.FileInfo.Name}");
|
||||
metaData.Artist = artist;
|
||||
if (!Configuration.Inspector.IsInReadOnlyMode)
|
||||
{
|
||||
TagsHelper.WriteTags(metaData, metaData.Filename);
|
||||
}
|
||||
}
|
||||
data = $"Found [{ found }] files, Modified [{ modified }] files";
|
||||
}
|
||||
result.Data = data;
|
||||
result.IsSuccess = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.MetaData.ID3Tags;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins.Directory
|
||||
{
|
||||
public class EnsureReleaseConsistent : FolderPluginBase
|
||||
{
|
||||
public override string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Consistent: Ensure all MP3 files in folder have same Release Title (TALB)";
|
||||
}
|
||||
}
|
||||
|
||||
public override int Order { get; } = 1;
|
||||
|
||||
public EnsureReleaseConsistent(IRoadieSettings configuration, ICacheManager cacheManager, ILogger logger, IID3TagsHelper tagsHelper)
|
||||
: base(configuration, cacheManager, logger, tagsHelper)
|
||||
{
|
||||
}
|
||||
|
||||
public override OperationResult<string> Process(DirectoryInfo directory)
|
||||
{
|
||||
var result = new OperationResult<string>();
|
||||
var data = string.Empty;
|
||||
var found = 0;
|
||||
var modified = 0;
|
||||
var metaDatasForFilesInFolder = GetAudioMetaDatasForDirectory(directory);
|
||||
if (metaDatasForFilesInFolder.Any())
|
||||
{
|
||||
found = metaDatasForFilesInFolder.Count();
|
||||
var firstMetaData = metaDatasForFilesInFolder.OrderBy(x => x.TrackNumber).First();
|
||||
var release = firstMetaData.Release;
|
||||
foreach (var metaData in metaDatasForFilesInFolder.Where(x => x.Release != release))
|
||||
{
|
||||
modified++;
|
||||
Console.WriteLine($"╟ Setting Release to [{ release }], was [{ metaData.Release }] on file [{ metaData.FileInfo.Name}");
|
||||
metaData.Release = release;
|
||||
if (!Configuration.Inspector.IsInReadOnlyMode)
|
||||
{
|
||||
TagsHelper.WriteTags(metaData, metaData.Filename);
|
||||
}
|
||||
}
|
||||
data = $"Found [{ found }] files, Modified [{ modified }] files";
|
||||
}
|
||||
result.Data = data;
|
||||
result.IsSuccess = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.MetaData.ID3Tags;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins.Directory
|
||||
{
|
||||
public class EnsureYearConsistent : FolderPluginBase
|
||||
{
|
||||
public override string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Consistent: Ensure all MP3 files in folder have same Year (TYER)";
|
||||
}
|
||||
}
|
||||
|
||||
public override int Order { get; } = 1;
|
||||
|
||||
public EnsureYearConsistent(IRoadieSettings configuration, ICacheManager cacheManager, ILogger logger, IID3TagsHelper tagsHelper)
|
||||
: base(configuration, cacheManager, logger, tagsHelper)
|
||||
{
|
||||
}
|
||||
|
||||
public override OperationResult<string> Process(DirectoryInfo directory)
|
||||
{
|
||||
var result = new OperationResult<string>();
|
||||
var data = string.Empty;
|
||||
var found = 0;
|
||||
var modified = 0;
|
||||
var metaDatasForFilesInFolder = GetAudioMetaDatasForDirectory(directory);
|
||||
if (metaDatasForFilesInFolder.Any())
|
||||
{
|
||||
found = metaDatasForFilesInFolder.Count();
|
||||
var firstMetaData = metaDatasForFilesInFolder.OrderBy(x => x.TrackNumber).First();
|
||||
var year = firstMetaData.Year;
|
||||
foreach (var metaData in metaDatasForFilesInFolder.Where(x => x.Year != year))
|
||||
{
|
||||
modified++;
|
||||
Console.WriteLine($"╟ Setting Year to [{ year }], was [{ metaData.Year}] on file [{ metaData.FileInfo.Name}");
|
||||
metaData.Year = year;
|
||||
if (!Configuration.Inspector.IsInReadOnlyMode)
|
||||
{
|
||||
TagsHelper.WriteTags(metaData, metaData.Filename);
|
||||
}
|
||||
}
|
||||
data = $"Found [{ found }] files, Modified [{ modified }] files";
|
||||
}
|
||||
result.Data = data;
|
||||
result.IsSuccess = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.MetaData.ID3Tags;
|
||||
using System.IO;
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins.Directory
|
||||
{
|
||||
public abstract class FolderPluginBase : PluginBase, IInspectorDirectoryPlugin
|
||||
{
|
||||
public FolderPluginBase(IRoadieSettings configuration, ICacheManager cacheManager, ILogger logger, IID3TagsHelper tagsHelper)
|
||||
: base(configuration, cacheManager, logger, tagsHelper)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract OperationResult<string> Process(DirectoryInfo directory);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins.Directory
|
||||
{
|
||||
public interface IInspectorDirectoryPlugin
|
||||
{
|
||||
string Description { get; }
|
||||
int Order { get; }
|
||||
|
||||
OperationResult<string> Process(DirectoryInfo directory);
|
||||
}
|
||||
}
|
58
Roadie.Api.Library/Inspect/Plugins/File/CleanUpArtists.cs
Normal file
58
Roadie.Api.Library/Inspect/Plugins/File/CleanUpArtists.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
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;
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins.File
|
||||
{
|
||||
public class CleanUpArtists : FilePluginBase
|
||||
{
|
||||
public override string Description => "Clean: Artist (TPE1) and TrackArtist (TOPE)";
|
||||
public override int Order => 2;
|
||||
|
||||
public CleanUpArtists(IRoadieSettings configuration, ICacheManager cacheManager, ILogger logger, IID3TagsHelper tagsHelper)
|
||||
: base(configuration, cacheManager, logger, tagsHelper)
|
||||
{
|
||||
}
|
||||
|
||||
public string CleanArtist(string artist, string trackArtist = null)
|
||||
{
|
||||
artist = artist ?? string.Empty;
|
||||
trackArtist = trackArtist ?? string.Empty;
|
||||
var splitCharacter = AudioMetaData.ArtistSplitCharacter.ToString();
|
||||
|
||||
// Replace seperators with proper split character
|
||||
foreach (var replace in ListReplacements)
|
||||
{
|
||||
artist = artist.Replace(replace, splitCharacter, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
var result = artist.CleanString(this.Configuration, this.Configuration.Processing.ArtistRemoveStringsRegex).ToTitleCase(doPutTheAtEnd: false);
|
||||
|
||||
if (!string.IsNullOrEmpty(result) && !string.IsNullOrEmpty(trackArtist))
|
||||
{
|
||||
result = result.Replace(splitCharacter + trackArtist + splitCharacter, "", StringComparison.OrdinalIgnoreCase);
|
||||
result = result.Replace(trackArtist + splitCharacter, "", StringComparison.OrdinalIgnoreCase);
|
||||
result = result.Replace(splitCharacter + trackArtist, "", StringComparison.OrdinalIgnoreCase);
|
||||
result = result.Replace(trackArtist, "", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
return string.IsNullOrEmpty(result) ? null : result;
|
||||
}
|
||||
|
||||
public override OperationResult<AudioMetaData> Process(AudioMetaData metaData)
|
||||
{
|
||||
var result = new OperationResult<AudioMetaData>();
|
||||
if (this.Configuration.Processing.DoAudioCleanup)
|
||||
{
|
||||
metaData.Artist = CleanArtist(metaData.ArtistRaw);
|
||||
metaData.TrackArtist = CleanArtist(metaData.TrackArtistRaw, metaData.ArtistRaw);
|
||||
}
|
||||
result.Data = metaData;
|
||||
result.IsSuccess = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
34
Roadie.Api.Library/Inspect/Plugins/File/CleanUpComments.cs
Normal file
34
Roadie.Api.Library/Inspect/Plugins/File/CleanUpComments.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.MetaData.Audio;
|
||||
using Roadie.Library.MetaData.ID3Tags;
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins.File
|
||||
{
|
||||
public class CleanUpComments : FilePluginBase
|
||||
{
|
||||
public override string Description => "Clean: Clear Comments (COMM)";
|
||||
public override int Order => 2;
|
||||
|
||||
public CleanUpComments(IRoadieSettings configuration, ICacheManager cacheManager, ILogger logger, IID3TagsHelper tagsHelper)
|
||||
: base(configuration, cacheManager, logger, tagsHelper)
|
||||
{
|
||||
}
|
||||
|
||||
public override OperationResult<AudioMetaData> Process(AudioMetaData metaData)
|
||||
{
|
||||
var result = new OperationResult<AudioMetaData>();
|
||||
if (this.Configuration.Processing.DoAudioCleanup)
|
||||
{
|
||||
if (this.Configuration.Processing.DoClearComments)
|
||||
{
|
||||
metaData.Comments = null;
|
||||
}
|
||||
}
|
||||
result.Data = metaData;
|
||||
result.IsSuccess = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
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;
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins.File
|
||||
{
|
||||
public class CleanUpReleaseTitle : FilePluginBase
|
||||
{
|
||||
public override string Description => "Clean: Release Title (TALB)";
|
||||
public override int Order => 2;
|
||||
|
||||
public CleanUpReleaseTitle(IRoadieSettings configuration, ICacheManager cacheManager, ILogger logger, IID3TagsHelper tagsHelper)
|
||||
: base(configuration, cacheManager, logger, tagsHelper)
|
||||
{
|
||||
}
|
||||
|
||||
public override OperationResult<AudioMetaData> Process(AudioMetaData metaData)
|
||||
{
|
||||
var result = new OperationResult<AudioMetaData>();
|
||||
if (this.Configuration.Processing.DoAudioCleanup)
|
||||
{
|
||||
metaData.Release = metaData.Release.CleanString(this.Configuration, this.Configuration.Processing.ReleaseRemoveStringsRegex).ToTitleCase(doPutTheAtEnd: false);
|
||||
}
|
||||
result.Data = metaData;
|
||||
result.IsSuccess = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
32
Roadie.Api.Library/Inspect/Plugins/File/CleanUpTrackTitle.cs
Normal file
32
Roadie.Api.Library/Inspect/Plugins/File/CleanUpTrackTitle.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
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;
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins.File
|
||||
{
|
||||
public class CleanUpTrackTitle : FilePluginBase
|
||||
{
|
||||
public override string Description => "Clean: Clean Track Title (TIT2) ";
|
||||
public override int Order => 2;
|
||||
|
||||
public CleanUpTrackTitle(IRoadieSettings configuration, ICacheManager cacheManager, ILogger logger, IID3TagsHelper tagsHelper)
|
||||
: base(configuration, cacheManager, logger, tagsHelper)
|
||||
{
|
||||
}
|
||||
|
||||
public override OperationResult<AudioMetaData> Process(AudioMetaData metaData)
|
||||
{
|
||||
var result = new OperationResult<AudioMetaData>();
|
||||
if (this.Configuration.Processing.DoAudioCleanup)
|
||||
{
|
||||
metaData.Title = metaData.Title.CleanString(this.Configuration, this.Configuration.Processing.TrackRemoveStringsRegex).ToTitleCase(doPutTheAtEnd: false);
|
||||
}
|
||||
result.Data = metaData;
|
||||
result.IsSuccess = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
18
Roadie.Api.Library/Inspect/Plugins/File/FilePluginBase.cs
Normal file
18
Roadie.Api.Library/Inspect/Plugins/File/FilePluginBase.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.MetaData.Audio;
|
||||
using Roadie.Library.MetaData.ID3Tags;
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins.File
|
||||
{
|
||||
public abstract class FilePluginBase : PluginBase, IInspectorFilePlugin
|
||||
{
|
||||
public FilePluginBase(IRoadieSettings configuration, ICacheManager cacheManager, ILogger logger, IID3TagsHelper tagsHelper)
|
||||
: base(configuration, cacheManager, logger, tagsHelper)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract OperationResult<AudioMetaData> Process(AudioMetaData metaData);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using Roadie.Library.MetaData.Audio;
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins.File
|
||||
{
|
||||
public interface IInspectorFilePlugin
|
||||
{
|
||||
string Description { get; }
|
||||
int Order { get; }
|
||||
|
||||
OperationResult<AudioMetaData> Process(AudioMetaData metaData);
|
||||
}
|
||||
}
|
40
Roadie.Api.Library/Inspect/Plugins/File/Renumber.cs
Normal file
40
Roadie.Api.Library/Inspect/Plugins/File/Renumber.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.MetaData.Audio;
|
||||
using Roadie.Library.MetaData.ID3Tags;
|
||||
using System.Linq;
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins.File
|
||||
{
|
||||
public class Renumber : FilePluginBase
|
||||
{
|
||||
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, IID3TagsHelper tagsHelper)
|
||||
: base(configuration, cacheManager, logger, tagsHelper)
|
||||
{
|
||||
}
|
||||
|
||||
public override OperationResult<AudioMetaData> Process(AudioMetaData metaData)
|
||||
{
|
||||
var result = new OperationResult<AudioMetaData>();
|
||||
var metaDatasForFilesInFolder = GetAudioMetaDatasForDirectory(metaData.FileInfo.Directory);
|
||||
metaData.TrackNumber = metaData.TrackNumber ?? ID3TagsHelper.DetermineTrackNumber(metaData.Filename);
|
||||
metaData.TotalTrackNumbers = ID3TagsHelper.DetermineTotalTrackNumbers(metaData.Filename) ?? metaDatasForFilesInFolder.Count();
|
||||
metaData.Disk = ID3TagsHelper.DetermineDiscNumber(metaData);
|
||||
metaData.TotalDiscCount = ID3TagsHelper.DetermineTotalDiscNumbers(metaDatasForFilesInFolder);
|
||||
result.Data = metaData;
|
||||
result.IsSuccess = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -2,30 +2,54 @@
|
|||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.MetaData.Audio;
|
||||
using System;
|
||||
using Roadie.Library.MetaData.ID3Tags;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
|
||||
namespace Roadie.Library.Inspect.Plugins
|
||||
{
|
||||
public abstract class PluginBase : IInspectorPlugin
|
||||
public abstract class PluginBase
|
||||
{
|
||||
protected IRoadieSettings Configuration { get; }
|
||||
protected ICacheManager CacheManager { get; }
|
||||
protected ILogger Logger { get; }
|
||||
|
||||
public abstract int Order { get; }
|
||||
public abstract string Description { get; }
|
||||
public abstract int Order { get; }
|
||||
protected ICacheManager CacheManager { get; }
|
||||
protected IRoadieSettings Configuration { get; }
|
||||
protected IEnumerable<string> ListReplacements { get; } = new List<string> { " ; ", " ;", "; ", ";", " & ", " &", "& ", ";", "&" };
|
||||
protected ILogger Logger { get; }
|
||||
protected IID3TagsHelper TagsHelper { get; }
|
||||
private Dictionary<string, IEnumerable<AudioMetaData>> CachedAudioDatas { get; set; }
|
||||
|
||||
public PluginBase(IRoadieSettings configuration, ICacheManager cacheManager, ILogger logger)
|
||||
public PluginBase(IRoadieSettings configuration, ICacheManager cacheManager, ILogger logger, IID3TagsHelper tagsHelper)
|
||||
{
|
||||
this.Configuration = configuration;
|
||||
this.CacheManager = cacheManager;
|
||||
this.Logger = logger;
|
||||
this.TagsHelper = tagsHelper;
|
||||
CachedAudioDatas = new Dictionary<string, IEnumerable<AudioMetaData>>();
|
||||
}
|
||||
|
||||
public abstract OperationResult<IEnumerable<AudioMetaData>> Process(IEnumerable<AudioMetaData> metaDatas);
|
||||
|
||||
protected IEnumerable<AudioMetaData> GetAudioMetaDatasForDirectory(DirectoryInfo directory)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!CachedAudioDatas.ContainsKey(directory.FullName))
|
||||
{
|
||||
var filesInMetaDataFolder = directory.GetFiles("*.mp3", SearchOption.TopDirectoryOnly);
|
||||
var metaDatasForFilesInFolder = new List<AudioMetaData>();
|
||||
foreach (var fileInMetaDataFolder in filesInMetaDataFolder)
|
||||
{
|
||||
metaDatasForFilesInFolder.Add(TagsHelper.MetaDataForFile(fileInMetaDataFolder.FullName).Data);
|
||||
}
|
||||
CachedAudioDatas.Add(directory.FullName, metaDatasForFilesInFolder);
|
||||
}
|
||||
return CachedAudioDatas[directory.FullName];
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
}
|
||||
return Enumerable.Empty<AudioMetaData>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -8,11 +8,12 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoCompare.Core" Version="1.0.0" />
|
||||
<PackageReference Include="CsvHelper" Version="12.1.2" />
|
||||
<PackageReference Include="EFCore.BulkExtensions" Version="2.4.7" />
|
||||
<PackageReference Include="FluentFTP" Version="24.0.0" />
|
||||
<PackageReference Include="Hashids.net" Version="1.2.2" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.4" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.6" />
|
||||
<PackageReference Include="IdSharp.Common" Version="1.0.1" />
|
||||
<PackageReference Include="IdSharp.Tagging" Version="1.0.0-rc3" />
|
||||
<PackageReference Include="Inflatable.Lastfm" Version="1.1.0.339" />
|
||||
|
|
|
@ -14,10 +14,10 @@ namespace Roadie.Library.SearchEngines.Imaging
|
|||
protected readonly IRoadieSettings _configuratio = null;
|
||||
protected readonly string _referrer = null;
|
||||
protected readonly string _requestIp = null;
|
||||
protected ApiKey _apiKey = null;
|
||||
protected IApiKey _apiKey = null;
|
||||
protected ILogger _logger = null;
|
||||
|
||||
protected ApiKey ApiKey
|
||||
protected IApiKey ApiKey
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Roadie.Library.Extensions;
|
||||
using Roadie.Library.Inspect.Plugins;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
@ -9,7 +10,7 @@ namespace Roadie.Library.MetaData.Audio
|
|||
{
|
||||
[Serializable]
|
||||
[DebuggerDisplay("Artist: {Artist}, TrackArtist: {TrackArtist}, Release: {Release}, TrackNumber: {TrackNumber}, Title: {Title}, Year: {Year}")]
|
||||
public sealed class AudioMetaData
|
||||
public sealed class AudioMetaData : IAudioMetaData
|
||||
{
|
||||
public const char ArtistSplitCharacter = '/';
|
||||
|
||||
|
@ -60,27 +61,6 @@ namespace Roadie.Library.MetaData.Audio
|
|||
|
||||
public string ArtistRaw { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// TPE1 All Lead Artists
|
||||
/// <seealso cref="http://id3.org/id3v2.3.0"/>
|
||||
/// </summary>
|
||||
/// <remarks>Per ID3.Org Spec: The 'Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group' is used for the main artist(s). They are seperated with the "/" character.</remarks>
|
||||
public IEnumerable<string> Artists
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(this._artist))
|
||||
{
|
||||
return new string[0];
|
||||
}
|
||||
if (!this._artist.Contains(AudioMetaData.ArtistSplitCharacter.ToString()))
|
||||
{
|
||||
return new string[0];
|
||||
}
|
||||
return this._artist.Split(AudioMetaData.ArtistSplitCharacter).Select(x => x.ToTitleCase()).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public int? AudioBitrate { get; set; }
|
||||
|
||||
public int? AudioChannels { get; set; }
|
||||
|
@ -215,6 +195,11 @@ namespace Roadie.Library.MetaData.Audio
|
|||
/// </summary>
|
||||
public string Release { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// COMM
|
||||
/// </summary>
|
||||
public string Comments { get; set; }
|
||||
|
||||
public string ReleaseLastFmId { get; set; }
|
||||
|
||||
public string ReleaseMusicBrainzId { get; set; }
|
||||
|
@ -230,6 +215,9 @@ namespace Roadie.Library.MetaData.Audio
|
|||
/// </summary>
|
||||
public TimeSpan? Time { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// TIT2
|
||||
/// </summary>
|
||||
public string Title
|
||||
{
|
||||
get
|
||||
|
@ -269,29 +257,26 @@ namespace Roadie.Library.MetaData.Audio
|
|||
public int? TotalTrackNumbers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// TOPE First Contributing Artist
|
||||
/// TOPE First Contributing Artist, null if same as Artist
|
||||
/// </summary>
|
||||
public string TrackArtist
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrEmpty(this._trackArtist) && this._trackArtist.Contains(AudioMetaData.ArtistSplitCharacter.ToString()))
|
||||
string result = null;
|
||||
if (!string.IsNullOrEmpty(this._trackArtist))
|
||||
{
|
||||
return this._trackArtist.Split(AudioMetaData.ArtistSplitCharacter).First().ToTitleCase();
|
||||
result = this._trackArtist.Split(AudioMetaData.ArtistSplitCharacter).First().ToTitleCase();
|
||||
}
|
||||
if (!string.IsNullOrEmpty(this._artist) || !string.IsNullOrEmpty(this._trackArtist))
|
||||
if (!string.IsNullOrEmpty(this._artist) || !string.IsNullOrEmpty(result))
|
||||
{
|
||||
return !this._artist.Equals(this._trackArtist, StringComparison.OrdinalIgnoreCase) ? this._trackArtist : null;
|
||||
result = !this._artist.Equals(result, StringComparison.OrdinalIgnoreCase) ? result : null;
|
||||
}
|
||||
return null;
|
||||
return result;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._trackArtist = value;
|
||||
if (!string.IsNullOrEmpty(this._trackArtist))
|
||||
{
|
||||
this._trackArtist = this._trackArtist.Replace(';', AudioMetaData.ArtistSplitCharacter).ToTitleCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -321,7 +306,7 @@ namespace Roadie.Library.MetaData.Audio
|
|||
{
|
||||
if (!this._artist.Equals(this._trackArtist, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return this._trackArtist.Split(AudioMetaData.ArtistSplitCharacter).Where(x => !string.IsNullOrEmpty(x)).Select(x => x.ToTitleCase()).ToArray();
|
||||
return this._trackArtist.Split(AudioMetaData.ArtistSplitCharacter).Where(x => !string.IsNullOrEmpty(x)).Select(x => x.ToTitleCase()).OrderBy(x => x).ToArray();
|
||||
}
|
||||
}
|
||||
return new string[0];
|
||||
|
@ -398,7 +383,13 @@ namespace Roadie.Library.MetaData.Audio
|
|||
|
||||
public override string 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())}");
|
||||
var result = $"IsValid: {this.IsValid}{ (this.IsSoundTrack ? " [SoundTrack ]" : string.Empty)}, ValidWeight {this.ValidWeight}, Artist: {this.Artist}";
|
||||
if(!string.IsNullOrEmpty(this.TrackArtist))
|
||||
{
|
||||
result += $", TrackArtist: { this.TrackArtist}";
|
||||
}
|
||||
result += $", Release: {this.Release}, TrackNumber: {this.TrackNumber}, TrackTotal: {this.TotalTrackNumbers}, Title: {this.Title}, Year: {this.Year}, Duration: {(this.Time == null ? "-" : this.Time.Value.ToString())}";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Roadie.Library.MetaData.Audio
|
||||
{
|
||||
public interface IAudioMetaData
|
||||
{
|
||||
string AmgId { get; set; }
|
||||
string Artist { get; set; }
|
||||
string ArtistRaw { get; set; }
|
||||
int? AudioBitrate { get; set; }
|
||||
int? AudioChannels { get; set; }
|
||||
AudioMetaDataWeights AudioMetaDataWeights { get; }
|
||||
int? AudioSampleRate { get; set; }
|
||||
string Comments { get; set; }
|
||||
string Directory { get; }
|
||||
int? Disk { get; set; }
|
||||
string DiskSubTitle { get; set; }
|
||||
FileInfo FileInfo { get; }
|
||||
string Filename { get; set; }
|
||||
ICollection<string> Genres { get; set; }
|
||||
IEnumerable<AudioMetaDataImage> Images { get; set; }
|
||||
string ISRC { get; }
|
||||
bool IsSoundTrack { get; }
|
||||
bool IsValid { get; }
|
||||
string LastFmId { get; set; }
|
||||
string MusicBrainzId { get; set; }
|
||||
string Release { get; set; }
|
||||
string ReleaseLastFmId { get; set; }
|
||||
string ReleaseMusicBrainzId { get; set; }
|
||||
ulong? SampleLength { get; set; }
|
||||
string SpecialTitle { get; set; }
|
||||
string SpotifyId { get; set; }
|
||||
TimeSpan? Time { get; set; }
|
||||
string Title { get; set; }
|
||||
int? TotalDiscCount { get; set; }
|
||||
double TotalSeconds { get; }
|
||||
int? TotalTrackNumbers { get; set; }
|
||||
string TrackArtist { get; set; }
|
||||
string TrackArtistRaw { get; set; }
|
||||
IEnumerable<string> TrackArtists { get; }
|
||||
short? TrackNumber { get; set; }
|
||||
int ValidWeight { get; }
|
||||
int? Year { get; set; }
|
||||
|
||||
bool Equals(object obj);
|
||||
int GetHashCode();
|
||||
void SetArtistName(string name);
|
||||
string ToString();
|
||||
}
|
||||
}
|
|
@ -91,6 +91,7 @@ namespace Roadie.Library.MetaData.ID3Tags
|
|||
Album = metaData.Release,
|
||||
Title = metaData.Title,
|
||||
Year = metaData.Year.Value.ToString(),
|
||||
Genre = metaData.Genres == null || !metaData.Genres.Any() ? null : string.Join("/", metaData.Genres),
|
||||
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()}"
|
||||
};
|
||||
|
@ -155,7 +156,7 @@ namespace Roadie.Library.MetaData.ID3Tags
|
|||
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.TrackArtistRaw = theTrack.OriginalArtist ?? theTrack.Artist ?? theTrack.AlbumArtist;
|
||||
result.AudioBitrate = (int?)theTrack.Bitrate;
|
||||
result.AudioSampleRate = (int)theTrack.Bitrate;
|
||||
result.Disk = theTrack.DiscNumber;
|
||||
|
@ -204,18 +205,19 @@ namespace Roadie.Library.MetaData.ID3Tags
|
|||
IAudioFile audioFile = AudioFile.Create(fileName, true);
|
||||
if (ID3v2Tag.DoesTagExist(fileName))
|
||||
{
|
||||
IID3v2Tag id3v2 = new ID3v2Tag(fileName);
|
||||
result.Release = id3v2.Album;
|
||||
IID3v2Tag id3v2 = new ID3v2Tag(fileName);
|
||||
result.Artist = id3v2.AlbumArtist ?? id3v2.Artist;
|
||||
result.ArtistRaw = id3v2.AlbumArtist ?? id3v2.Artist;
|
||||
result.Genres = id3v2.Genre?.Split(new char[] { ',', '\\', ';', '|' });
|
||||
result.TrackArtist = id3v2.OriginalArtist ?? id3v2.Artist ?? id3v2.AlbumArtist;
|
||||
result.TrackArtistRaw = id3v2.OriginalArtist;
|
||||
result.AudioBitrate = (int?)audioFile.Bitrate;
|
||||
result.AudioChannels = audioFile.Channels;
|
||||
result.AudioSampleRate = (int)audioFile.Bitrate;
|
||||
result.Comments = id3v2.CommentsList != null ? string.Join("|", id3v2.CommentsList?.Select(x => x.Value)) : null;
|
||||
result.Disk = ID3TagsHelper.ParseDiscNumber(id3v2.DiscNumber);
|
||||
result.DiskSubTitle = id3v2.SetSubtitle;
|
||||
result.Genres = id3v2.Genre?.Split(new char[] { ',', '\\', ';', '|' });
|
||||
result.Release = id3v2.Album;
|
||||
result.TrackArtist = id3v2.OriginalArtist ?? id3v2.Artist ?? id3v2.AlbumArtist;
|
||||
result.TrackArtistRaw = id3v2.OriginalArtist ?? id3v2.Artist ?? id3v2.AlbumArtist;
|
||||
result.Images = id3v2.PictureList?.Select(x => new AudioMetaDataImage
|
||||
{
|
||||
Data = x.PictureData,
|
||||
|
@ -266,6 +268,16 @@ namespace Roadie.Library.MetaData.ID3Tags
|
|||
};
|
||||
}
|
||||
|
||||
public static short? DetermineTrackNumber(string filename)
|
||||
{
|
||||
var part = filename.Substring(0, 2);
|
||||
part = part.Replace(".", "");
|
||||
part = part.Replace("-", "");
|
||||
part = part.Replace(" ", "");
|
||||
return SafeParser.ToNumber<short?>(part);
|
||||
}
|
||||
|
||||
|
||||
public static short? DetermineTotalTrackNumbers(string filename, string trackNumber = null)
|
||||
{
|
||||
short? result = null;
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Roadie.Library.MetaData
|
|||
protected readonly IRoadieSettings _configuration = null;
|
||||
protected readonly ILogger _logger = null;
|
||||
|
||||
protected ApiKey _apiKey = null;
|
||||
protected IApiKey _apiKey = null;
|
||||
|
||||
public virtual bool IsEnabled
|
||||
{
|
||||
|
@ -20,7 +20,7 @@ namespace Roadie.Library.MetaData
|
|||
}
|
||||
}
|
||||
|
||||
protected ApiKey ApiKey
|
||||
protected IApiKey ApiKey
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
|
@ -28,6 +28,33 @@ namespace Roadie.Library.Utility
|
|||
return directoryInfo.FullName;
|
||||
}
|
||||
|
||||
public static void DeleteEmptyDirs(string dir)
|
||||
{
|
||||
if (String.IsNullOrEmpty(dir))
|
||||
{
|
||||
throw new ArgumentException("Starting directory is a null reference or an empty string", "dir");
|
||||
}
|
||||
try
|
||||
{
|
||||
foreach (var d in Directory.EnumerateDirectories(dir))
|
||||
{
|
||||
DeleteEmptyDirs(d);
|
||||
}
|
||||
var entries = Directory.EnumerateFileSystemEntries(dir);
|
||||
if (!entries.Any())
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(dir);
|
||||
}
|
||||
catch (UnauthorizedAccessException) { }
|
||||
catch (DirectoryNotFoundException) { }
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException) { }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Delete any empty folders in the given folder
|
||||
/// </summary>
|
||||
|
|
|
@ -91,7 +91,12 @@ namespace Roadie.Library.Utility
|
|||
var i = input as string ?? input.ToString();
|
||||
if (!string.IsNullOrEmpty(i))
|
||||
{
|
||||
if (Regex.IsMatch(i, @"([0-9]{4}).+([0-9]{4})"))
|
||||
{
|
||||
i = i.Substring(0, 4);
|
||||
}
|
||||
i = Regex.Replace(i, @"(\\)", "/");
|
||||
i = Regex.Replace(i, @"(;)", "/");
|
||||
i = Regex.Replace(i, @"(\/+)", "/");
|
||||
i = Regex.Replace(i, @"(-+)", "/");
|
||||
var parts = i.Contains("/") ? i.Split('/').ToList() : new List<string> { i };
|
||||
|
|
|
@ -290,7 +290,7 @@ namespace Roadie.Api.Services
|
|||
return new Image($"{this.HttpContext.ImageBaseUrl }/{id}/{ width }/{ height }/{ (includeCachebuster ? DateTime.UtcNow.Ticks.ToString() : string.Empty) }", caption, $"{this.HttpContext.ImageBaseUrl }/{id}/{ this.Configuration.SmallImageSize.Width }/{ this.Configuration.SmallImageSize.Height }");
|
||||
}
|
||||
|
||||
protected Image MakeImage(Guid id, string type, ImageSize imageSize)
|
||||
protected Image MakeImage(Guid id, string type, IImageSize imageSize)
|
||||
{
|
||||
return this.MakeImage(id, type, imageSize.Width, imageSize.Height);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue