This commit is contained in:
Steven Hildreth 2019-11-10 08:48:07 -06:00
parent a370108b64
commit 48dd411ffb
17 changed files with 164 additions and 22 deletions

View file

@ -105,6 +105,22 @@ namespace Roadie.Library.Tests
Assert.Equal(t.FullName, artistFolder); Assert.Equal(t.FullName, artistFolder);
} }
[Theory]
[InlineData("!SÖmëthing el$e", @"S\SO")]
[InlineData("Alternative Singer/Songwriter", @"A\AL")]
[InlineData("Adult Alternative", @"A\AD")]
[InlineData("Progressive Bluegrass", @"P\PR")]
[InlineData("Western European Traditions", @"W\WE")]
[InlineData("2-Step/British Garage", @"0\2S")]
[InlineData("80's/synthwave/outrun/new retro wave", @"0\80")]
[InlineData("Western Swing Revival", @"W\WE")]
public void GenerateGenreFolderNames(string input, string shouldBe)
{
var artistFolder = FolderPathHelper.GenrePath(Configuration, input);
var t = new DirectoryInfo(Path.Combine(Configuration.GenreImageFolder, shouldBe));
Assert.Equal(t.FullName, artistFolder);
}
[Theory] [Theory]
[InlineData("What Dreams May Come", "01/15/2004", @"D\DR\Dream Theater [99]", @"D\DR\Dream Theater [99]\[2004] What Dreams May Come")] [InlineData("What Dreams May Come", "01/15/2004", @"D\DR\Dream Theater [99]", @"D\DR\Dream Theater [99]\[2004] What Dreams May Come")]
[InlineData("Killers", "01/01/1980", @"I\IR\Iron Maiden [9909]", @"I\IR\Iron Maiden [9909]\[1980] Killers")] [InlineData("Killers", "01/01/1980", @"I\IR\Iron Maiden [9909]", @"I\IR\Iron Maiden [9909]\[1980] Killers")]

View file

@ -44,9 +44,14 @@ namespace Roadie.Library.Data
/// <summary> /// <summary>
/// Returns a full file path to the Collection Image /// Returns a full file path to the Collection Image
/// </summary> /// </summary>
public string PathToImage(IRoadieSettings configuration) public string PathToImage(IRoadieSettings configuration, bool makeFolderIfNotExist = false)
{ {
return Path.Combine(configuration.CollectionImageFolder, $"{ (SortName ?? Name).ToFileNameFriendly() } [{ Id }].jpg"); var folder = configuration.CollectionImageFolder;
if (!Directory.Exists(folder) && makeFolderIfNotExist)
{
Directory.CreateDirectory(folder);
}
return Path.Combine(folder, $"{ (SortName ?? Name).ToFileNameFriendly() } [{ Id }].jpg");
} }
public int PositionColumn public int PositionColumn

View file

@ -12,7 +12,16 @@ namespace Roadie.Library.Data
public ICollection<Comment> Comments { get; set; } public ICollection<Comment> Comments { get; set; }
[Column("name")] [MaxLength(100)] public string Name { get; set; } [Column("name")]
[MaxLength(100)]
[Required]
public string Name { get; set; }
[Column("sortName")]
[MaxLength(100)]
public string SortName { get; set; }
public string SortNameValue => string.IsNullOrEmpty(SortName) ? Name : SortName;
[Column("description")] [Column("description")]
[MaxLength(4000)] [MaxLength(4000)]

View file

@ -1,5 +1,6 @@
using Roadie.Library.Configuration; using Roadie.Library.Configuration;
using Roadie.Library.Extensions; using Roadie.Library.Extensions;
using Roadie.Library.Utility;
using System; using System;
using System.IO; using System.IO;
@ -11,14 +12,37 @@ namespace Roadie.Library.Data
public string CacheRegion => CacheRegionUrn(RoadieId); public string CacheRegion => CacheRegionUrn(RoadieId);
///// <summary>
///// Returns a full file path to the Genre Image
///// </summary>
//public string PathToImage(IRoadieSettings configuration)
//{
// return Path.Combine(configuration.GenreImageFolder, $"{ Name.ToFileNameFriendly() } [{ Id }].jpg");
//}
/// <summary> /// <summary>
/// Returns a full file path to the Genre Image /// Returns a full file path to the Genre Image
/// </summary> /// </summary>
public string PathToImage(IRoadieSettings configuration) public string PathToImage(IRoadieSettings configuration, bool makeFolderIfNotExist = false)
{ {
return Path.Combine(configuration.GenreImageFolder, $"{ Name.ToFileNameFriendly() } [{ Id }].jpg"); var folder = FolderPathHelper.GenrePath(configuration, SortNameValue);
if(!Directory.Exists(folder) && makeFolderIfNotExist)
{
Directory.CreateDirectory(folder);
}
return Path.Combine(folder, $"{ SortNameValue.ToFileNameFriendly() } [{ Id }].jpg");
} }
/// <summary>
/// Returns a full file path to the Label Image
/// </summary>
[Obsolete("This is only here for migration will be removed in future release.")]
public string OldPathToImage(IRoadieSettings configuration)
{
return Path.Combine(configuration.GenreImageFolder, $"{ SortNameValue.ToFileNameFriendly() } [{ Id }].jpg");
}
public static string CacheRegionUrn(Guid Id) public static string CacheRegionUrn(Guid Id)
{ {
return string.Format("urn:genre:{0}", Id); return string.Format("urn:genre:{0}", Id);

View file

@ -28,9 +28,14 @@ namespace Roadie.Library.Data
/// <summary> /// <summary>
/// Returns a full file path to the Label Image /// Returns a full file path to the Label Image
/// </summary> /// </summary>
public string PathToImage(IRoadieSettings configuration) public string PathToImage(IRoadieSettings configuration, bool makeFolderIfNotExist = false)
{ {
return Path.Combine(FolderPathHelper.LabelPath(configuration, SortNameValue), $"{ SortNameValue.ToFileNameFriendly() } [{ Id }].jpg"); var folder = FolderPathHelper.LabelPath(configuration, SortNameValue);
if (!Directory.Exists(folder) && makeFolderIfNotExist)
{
Directory.CreateDirectory(folder);
}
return Path.Combine(folder, $"{ SortNameValue.ToFileNameFriendly() } [{ Id }].jpg");
} }
/// <summary> /// <summary>

View file

@ -25,9 +25,14 @@ namespace Roadie.Library.Data
/// <summary> /// <summary>
/// Returns a full file path to the Playlist Image /// Returns a full file path to the Playlist Image
/// </summary> /// </summary>
public string PathToImage(IRoadieSettings configuration) public string PathToImage(IRoadieSettings configuration, bool makeFolderIfNotExist = false)
{ {
return Path.Combine(configuration.PlaylistImageFolder, $"{ (SortName ?? Name).ToFileNameFriendly() } [{ Id }].jpg"); var folder = configuration.PlaylistImageFolder;
if (!Directory.Exists(folder) && makeFolderIfNotExist)
{
Directory.CreateDirectory(folder);
}
return Path.Combine(folder, $"{ (SortName ?? Name).ToFileNameFriendly() } [{ Id }].jpg");
} }
public override string ToString() public override string ToString()

View file

@ -20,9 +20,14 @@ namespace Roadie.Library.Identity
/// <summary> /// <summary>
/// Returns a full file path to the User Image /// Returns a full file path to the User Image
/// </summary> /// </summary>
public string PathToImage(IRoadieSettings configuration) public string PathToImage(IRoadieSettings configuration, bool makeFolderIfNotExist = false)
{ {
return Path.Combine(configuration.UserImageFolder, $"{ UserName.ToFileNameFriendly() } [{ Id }].gif"); var folder = configuration.UserImageFolder;
if (!Directory.Exists(folder) && makeFolderIfNotExist)
{
Directory.CreateDirectory(folder);
}
return Path.Combine(folder, $"{ UserName.ToFileNameFriendly() } [{ Id }].gif");
} }
public ApplicationUser() public ApplicationUser()

View file

@ -19,7 +19,8 @@ namespace Roadie.Library.Utility
public static int MaximumLibraryFolderNameLength = 44; public static int MaximumLibraryFolderNameLength = 44;
public static int MaximumArtistFolderNameLength = 100; public static int MaximumArtistFolderNameLength = 100;
public static int MaximumReleaseFolderNameLength = 100; public static int MaximumReleaseFolderNameLength = 100;
public static int MaximumLabelFolderNameLength = 100; public static int MaximumLabelFolderNameLength = 80;
public static int MaximumGenreFolderNameLength = 80;
public static int MaximumTrackFileNameLength = 500; public static int MaximumTrackFileNameLength = 500;
public static IEnumerable<string> FolderSpaceReplacements = new List<string> { ".", "~", "_", "=", "-" }; public static IEnumerable<string> FolderSpaceReplacements = new List<string> { ".", "~", "_", "=", "-" };
@ -78,11 +79,10 @@ namespace Roadie.Library.Utility
return directoryInfo.FullName; return directoryInfo.FullName;
} }
public static string LabelPath(IRoadieSettings configuration, string labelSortName) public static string LabelPath(IRoadieSettings configuration, string labelSortName)
{ {
SimpleContract.Requires<ArgumentException>(!string.IsNullOrEmpty(labelSortName), "Invalid Label Sort Name"); SimpleContract.Requires<ArgumentException>(!string.IsNullOrEmpty(labelSortName), "Invalid Label Sort Name");
SimpleContract.Requires<ArgumentException>(configuration.LibraryFolder.Length < MaximumLibraryFolderNameLength, $"Library Folder maximum length is [{ MaximumLibraryFolderNameLength }]"); SimpleContract.Requires<ArgumentException>(configuration.LabelImageFolder.Length < MaximumLabelFolderNameLength, $"Label Image Folder maximum length is [{ MaximumLibraryFolderNameLength }]");
var lsn = new StringBuilder(labelSortName); var lsn = new StringBuilder(labelSortName);
foreach (var stringReplacement in FolderSpaceReplacements) foreach (var stringReplacement in FolderSpaceReplacements)
@ -122,6 +122,50 @@ namespace Roadie.Library.Utility
return directoryInfo.FullName; return directoryInfo.FullName;
} }
public static string GenrePath(IRoadieSettings configuration, string genreSortName)
{
SimpleContract.Requires<ArgumentException>(!string.IsNullOrEmpty(genreSortName), "Invalid Genre Sort Name");
SimpleContract.Requires<ArgumentException>(configuration.GenreImageFolder.Length < MaximumGenreFolderNameLength, $"Genre Image Folder maximum length is [{ MaximumLibraryFolderNameLength }]");
var lsn = new StringBuilder(genreSortName);
foreach (var stringReplacement in FolderSpaceReplacements)
{
if (!lsn.Equals(stringReplacement))
{
lsn.Replace(stringReplacement, " ");
}
}
var genreFolder = lsn.ToString().ToAlphanumericName(false, false).ToFolderNameFriendly().ToTitleCase(false);
if (string.IsNullOrEmpty(genreFolder))
{
throw new Exception($"GenreFolder [{ genreFolder }] is invalid. GenreSortName [{ genreSortName }].");
}
var lfUpper = genreFolder.ToUpper();
var fnSubPart1 = lfUpper.ToUpper().ToCharArray().Take(1).First();
if (!char.IsLetterOrDigit(fnSubPart1))
{
fnSubPart1 = '#';
}
else if (char.IsNumber(fnSubPart1))
{
fnSubPart1 = '0';
}
var fnSubPart2 = lfUpper.Length > 2 ? lfUpper.Substring(0, 2) : lfUpper;
if (fnSubPart2.EndsWith(" "))
{
var pos = 1;
while (fnSubPart2.EndsWith(" "))
{
pos++;
fnSubPart2 = fnSubPart2.Substring(0, 1) + lfUpper.Substring(pos, 1);
}
}
var fnSubPart = Path.Combine(fnSubPart1.ToString(), fnSubPart2);
var directoryInfo = new DirectoryInfo(Path.Combine(configuration.GenreImageFolder, fnSubPart));
return directoryInfo.FullName;
}
[Obsolete("This is only here for migration will be removed in future release.")] [Obsolete("This is only here for migration will be removed in future release.")]
public static string ArtistPathOld(IRoadieSettings configuration, string artistSortName) public static string ArtistPathOld(IRoadieSettings configuration, string artistSortName)
{ {

View file

@ -1110,6 +1110,28 @@ namespace Roadie.Api.Services
} }
Logger.LogInformation($"Label Migration Complete. Migrated [{ labelsMigrated }] Labels."); Logger.LogInformation($"Label Migration Complete. Migrated [{ labelsMigrated }] Labels.");
var genresMigrated = 0;
foreach (var genre in DbContext.Genres.Where(x => x.Status == Statuses.ReadyToMigrate).ToArray())
{
var oldGenreImageFileName = genre.OldPathToImage(Configuration);
var genreImageFileName = genre.PathToImage(Configuration);
if (File.Exists(oldGenreImageFileName))
{
var genreFileInfo = new FileInfo(genreImageFileName);
if (!genreFileInfo.Directory.Exists)
{
Directory.CreateDirectory(genreFileInfo.Directory.FullName);
}
File.Move(oldGenreImageFileName, genreImageFileName, true);
genre.Status = Statuses.Migrated;
genre.LastUpdated = now;
await DbContext.SaveChangesAsync();
Logger.LogInformation($"Migrated Genre Storage `{ genre}` From [{ oldGenreImageFileName }] => [{ genreImageFileName }]");
genresMigrated++;
}
}
Logger.LogInformation($"Genre Migration Complete. Migrated [{ genresMigrated }] Genres.");
var releases = DbContext.Releases var releases = DbContext.Releases
.Include(x => x.Artist) .Include(x => x.Artist)
.Include(x => x.Medias) .Include(x => x.Medias)

View file

@ -301,7 +301,7 @@ namespace Roadie.Api.Services
if (collectionImage != null) if (collectionImage != null)
{ {
// Save unaltered collection image // Save unaltered collection image
File.WriteAllBytes(collection.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(collectionImage)); File.WriteAllBytes(collection.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(collectionImage));
} }
if (model.Maintainer?.Value != null) if (model.Maintainer?.Value != null)
{ {

View file

@ -236,14 +236,17 @@ namespace Roadie.Api.Services
sw.Start(); sw.Start();
var errors = new List<Exception>(); var errors = new List<Exception>();
var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == id); var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == id);
if (genre == null) return new OperationResult<Library.Models.Image>(true, string.Format("Genre Not Found [{0}]", id)); if (genre == null)
{
return new OperationResult<Library.Models.Image>(true, string.Format("Genre Not Found [{0}]", id));
}
try try
{ {
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
if (imageBytes != null) if (imageBytes != null)
{ {
// Save unaltered label image // Save unaltered genre image
File.WriteAllBytes(genre.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(imageBytes)); File.WriteAllBytes(genre.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(imageBytes));
} }
genre.LastUpdated = now; genre.LastUpdated = now;
await DbContext.SaveChangesAsync(); await DbContext.SaveChangesAsync();

View file

@ -461,7 +461,7 @@ namespace Roadie.Api.Services
if (imageBytes != null) if (imageBytes != null)
{ {
// Save unaltered label image // Save unaltered label image
File.WriteAllBytes(label.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(imageBytes)); File.WriteAllBytes(label.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(imageBytes));
} }
label.LastUpdated = now; label.LastUpdated = now;
await DbContext.SaveChangesAsync(); await DbContext.SaveChangesAsync();

View file

@ -352,7 +352,7 @@ namespace Roadie.Api.Services
if (playlistImage != null) if (playlistImage != null)
{ {
// Save unaltered playlist image // Save unaltered playlist image
File.WriteAllBytes(playlist.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(playlistImage)); File.WriteAllBytes(playlist.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(playlistImage));
} }
playlist.LastUpdated = now; playlist.LastUpdated = now;
await DbContext.SaveChangesAsync(); await DbContext.SaveChangesAsync();

View file

@ -503,7 +503,7 @@ namespace Roadie.Api.Services
imageData = ImageHelper.ConvertToGifFormat(imageData); imageData = ImageHelper.ConvertToGifFormat(imageData);
// Save unaltered user image // Save unaltered user image
File.WriteAllBytes(user.PathToImage(Configuration), imageData); File.WriteAllBytes(user.PathToImage(Configuration, true), imageData);
} }
} }

View file

@ -19,6 +19,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Scripts", "Scripts", "{1BA7
Upgrade0005.sql = Upgrade0005.sql Upgrade0005.sql = Upgrade0005.sql
Upgrade0006.sql = Upgrade0006.sql Upgrade0006.sql = Upgrade0006.sql
Upgrade0007.sql = Upgrade0007.sql Upgrade0007.sql = Upgrade0007.sql
Upgrade0008.sql = Upgrade0008.sql
EndProjectSection EndProjectSection
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roadie.Api.Services", "Roadie.Api.Services\Roadie.Api.Services.csproj", "{7B37031E-F2AE-4BE2-9F6F-005CA7A6FDF1}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roadie.Api.Services", "Roadie.Api.Services\Roadie.Api.Services.csproj", "{7B37031E-F2AE-4BE2-9F6F-005CA7A6FDF1}"

2
Upgrade0008.sql Normal file
View file

@ -0,0 +1,2 @@
-- New SortName columns
ALTER TABLE `genre` ADD sortName varchar(100) NULL;

View file

@ -337,6 +337,7 @@ CREATE TABLE `genre` (
`createdDate` datetime DEFAULT NULL, `createdDate` datetime DEFAULT NULL,
`lastUpdated` datetime DEFAULT NULL, `lastUpdated` datetime DEFAULT NULL,
`name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL, `name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
`sortName` varchar(250) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`normalizedName` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `normalizedName` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`thumbnail` blob DEFAULT NULL, `thumbnail` blob DEFAULT NULL,
`alternateNames` mediumtext COLLATE utf8mb4_unicode_ci DEFAULT NULL, `alternateNames` mediumtext COLLATE utf8mb4_unicode_ci DEFAULT NULL,
@ -511,6 +512,7 @@ CREATE TABLE `release` (
`lastUpdated` datetime DEFAULT NULL, `lastUpdated` datetime DEFAULT NULL,
`isVirtual` tinyint(1) DEFAULT NULL, `isVirtual` tinyint(1) DEFAULT NULL,
`title` varchar(250) COLLATE utf8mb4_unicode_ci NOT NULL, `title` varchar(250) COLLATE utf8mb4_unicode_ci NOT NULL,
`sortTitle` varchar(250) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`alternateNames` mediumtext COLLATE utf8mb4_unicode_ci DEFAULT NULL, `alternateNames` mediumtext COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`releaseDate` date DEFAULT NULL, `releaseDate` date DEFAULT NULL,
`rating` smallint(6) NOT NULL, `rating` smallint(6) NOT NULL,
@ -534,7 +536,6 @@ CREATE TABLE `release` (
`playedCount` int(11) DEFAULT NULL, `playedCount` int(11) DEFAULT NULL,
`duration` int(11) DEFAULT NULL, `duration` int(11) DEFAULT NULL,
`rank` decimal(9,2) DEFAULT NULL, `rank` decimal(9,2) DEFAULT NULL,
`sortTitle` varchar(250) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `idx_releaseArtistAndTitle` (`artistId`,`title`), UNIQUE KEY `idx_releaseArtistAndTitle` (`artistId`,`title`),
KEY `ix_release_roadieId` (`roadieId`), KEY `ix_release_roadieId` (`roadieId`),