Several bug fixes.

This commit is contained in:
Steven Hildreth 2019-11-21 08:44:05 -06:00
parent 818afd2eb0
commit 263176f195
13 changed files with 155 additions and 81 deletions

View file

@ -7,6 +7,8 @@ namespace Roadie.Library.Configuration
[Serializable]
public sealed class RoadieSettings : IRoadieSettings
{
public static string RoadieImageFolder = "__roadie_images";
public DbContexts DbContextToUse { get; set; }
/// <summary>
@ -21,7 +23,7 @@ namespace Roadie.Library.Configuration
{
get
{
return Path.Combine(ImageFolder ?? LibraryFolder, "__roadie_images", "collections");
return Path.Combine(ImageFolder ?? LibraryFolder, RoadieImageFolder, "collections");
}
}
@ -54,7 +56,7 @@ namespace Roadie.Library.Configuration
{
get
{
return Path.Combine(ImageFolder ?? LibraryFolder, "__roadie_images", "genres");
return Path.Combine(ImageFolder ?? LibraryFolder, RoadieImageFolder, "genres");
}
}
@ -74,7 +76,7 @@ namespace Roadie.Library.Configuration
{
get
{
return Path.Combine(ImageFolder ?? LibraryFolder, "__roadie_images", "labels");
return Path.Combine(ImageFolder ?? LibraryFolder, RoadieImageFolder, "labels");
}
}
@ -91,7 +93,7 @@ namespace Roadie.Library.Configuration
{
get
{
return Path.Combine(ImageFolder ?? LibraryFolder, "__roadie_images", "playlists");
return Path.Combine(ImageFolder ?? LibraryFolder, RoadieImageFolder, "playlists");
}
}
@ -139,7 +141,7 @@ namespace Roadie.Library.Configuration
{
get
{
return Path.Combine(LibraryFolder, "__roadie_images", "users");
return Path.Combine(LibraryFolder, RoadieImageFolder, "users");
}
}

View file

@ -45,16 +45,17 @@ namespace Roadie.Library.Imaging
}
return outStream.ToArray();
}
}
catch (Exception ex)
{
Trace.WriteLine($"Error Converting Image to Jpg [{ ex.Message }]");
}
return null;
}
/// <summary>
/// Only user avatars are GIF to allow for animation.
/// </summary>
public static byte[] ConvertToGifFormat(byte[] imageBytes)
{
if (imageBytes == null) return null;
@ -73,12 +74,10 @@ namespace Roadie.Library.Imaging
catch (Exception ex)
{
Trace.WriteLine($"Error Converting Image to Gif [{ ex.Message }]");
}
return null;
}
public static IEnumerable<FileInfo> FindImagesByName(DirectoryInfo directory, string name, SearchOption folderSearchOptions = SearchOption.AllDirectories)
{
var result = new List<FileInfo>();
@ -138,7 +137,7 @@ namespace Roadie.Library.Imaging
public static string[] GetFiles(string path, string[] patterns = null, SearchOption options = SearchOption.TopDirectoryOnly)
{
if(!Directory.Exists(path))
if (!Directory.Exists(path))
{
return new string[0];
}
@ -264,10 +263,10 @@ namespace Roadie.Library.Imaging
if (doForce || image.Width > width || image.Height > height)
{
int newWidth, newHeight;
if(doForce)
if (doForce)
{
newWidth = width;
newHeight = height;
newHeight = height;
}
else
{
@ -303,14 +302,14 @@ namespace Roadie.Library.Imaging
/// </summary>
public static byte[] ResizeToThumbnail(byte[] imageBytes, IRoadieSettings configuration)
{
if(!imageBytes?.Any() ?? false)
if (!imageBytes?.Any() ?? false)
{
return imageBytes;
}
var width = configuration?.ThumbnailImageSize?.Width ?? 80;
var height = configuration?.ThumbnailImageSize?.Height ?? 80;
var result = ImageHelper.ResizeImage(ImageHelper.ConvertToJpegFormat(imageBytes), width, height, true)?.Item2;
if(result?.Length >= ImageHelper.MaximumThumbnailByteSize)
if (result?.Length >= ImageHelper.MaximumThumbnailByteSize)
{
Trace.WriteLine($"Thumbnail larger than maximum size after resizing to [{configuration.ThumbnailImageSize.Width}x{configuration.ThumbnailImageSize.Height}] Thumbnail Size [{result.Length}]");
result = new byte[0];
@ -399,7 +398,5 @@ namespace Roadie.Library.Imaging
return imageMetaData;
}
}
}

View file

@ -251,6 +251,10 @@ namespace Roadie.Library.Utility
{
try
{
if(folder.FullName.Contains(RoadieSettings.RoadieImageFolder, StringComparison.OrdinalIgnoreCase))
{
continue;
}
if (folder.Exists)
{
if (!folder.GetFiles("*.*", SearchOption.AllDirectories).Any())

View file

@ -576,6 +576,11 @@ namespace Roadie.Api.Services
Directory.CreateDirectory(Configuration.LibraryFolder);
Logger.LogInformation($"Created Library Folder [{Configuration.LibraryFolder }]");
}
if (!Directory.Exists(Configuration.InboundFolder))
{
Directory.CreateDirectory(Configuration.InboundFolder);
Logger.LogInformation($"Created Inbound Folder [{Configuration.InboundFolder }]");
}
if (!Directory.Exists(Configuration.UserImageFolder))
{
Directory.CreateDirectory(Configuration.UserImageFolder);
@ -911,7 +916,7 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> ScanLibraryFolder(ApplicationUser user, bool isReadOnly = false)
{
var d = new DirectoryInfo(Configuration.LibraryFolder);
return await ScanFolder(user, d, isReadOnly);
return await ScanFolder(user, d, isReadOnly, false);
}
public async Task<OperationResult<bool>> ScanRelease(ApplicationUser user, Guid releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false)
@ -1075,7 +1080,7 @@ namespace Roadie.Api.Services
await ScanActivityHub.Clients.All.SendAsync("SendSystemActivity", message);
}
private async Task<OperationResult<bool>> ScanFolder(ApplicationUser user, DirectoryInfo d, bool isReadOnly)
private async Task<OperationResult<bool>> ScanFolder(ApplicationUser user, DirectoryInfo d, bool isReadOnly, bool doDeleteFiles = true)
{
var sw = new Stopwatch();
sw.Start();
@ -1086,7 +1091,10 @@ namespace Roadie.Api.Services
long processedFolders = 0;
foreach (var folder in Directory.EnumerateDirectories(d.FullName).ToArray())
{
var directoryProcessResult = await FileDirectoryProcessorService.Process(user, new DirectoryInfo(folder), isReadOnly);
var directoryProcessResult = await FileDirectoryProcessorService.Process(user:user,
folder: new DirectoryInfo(folder),
doJustInfo: isReadOnly,
doDeleteFiles: doDeleteFiles);
processedFolders++;
processedFiles += SafeParser.ToNumber<int>(directoryProcessResult.AdditionalData["ProcessedFiles"]);
}

View file

@ -540,6 +540,15 @@ namespace Roadie.Api.Services
Logger.LogError(ex, ex.Serialize());
}
}
var artistImage = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), ImageType.Artist).FirstOrDefault();
if (artistImage != null)
{
// See if image file is valid image if not delete it
if (ImageHelper.ConvertToJpegFormat(File.ReadAllBytes(artistImage.FullName)) == null)
{
artistImage.Delete();
}
}
// Any folder found in Artist folder not already scanned scan
var nonReleaseFolders = from d in Directory.EnumerateDirectories(artistFolder)
where !(from r in scannedArtistFolders select r).Contains(d)

View file

@ -76,7 +76,7 @@ namespace Roadie.Api.Services
return result;
}
public async Task<OperationResult<bool>> Process(ApplicationUser user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null)
public async Task<OperationResult<bool>> Process(ApplicationUser user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null, bool doDeleteFiles = true)
{
var sw = new Stopwatch();
sw.Start();
@ -104,7 +104,7 @@ namespace Roadie.Api.Services
if (ProcessLimit.HasValue && processedFiles > ProcessLimit.Value) break;
}
await PostProcessFolder(user, folder, pluginResultInfos, doJustInfo);
await PostProcessFolder(user, folder, pluginResultInfos, doJustInfo, doDeleteFiles);
sw.Stop();
_addedArtistIds.AddRange(ArtistLookupEngine.AddedArtistIds);
_addedReleaseIds.AddRange(ReleaseLookupEngine.AddedReleaseIds);
@ -121,7 +121,7 @@ namespace Roadie.Api.Services
/// <summary>
/// Perform any operations to the given folder and the plugin results after processing
/// </summary>
private async Task<bool> PostProcessFolder(ApplicationUser user, DirectoryInfo inboundFolder, IEnumerable<PluginResultInfo> pluginResults, bool doJustInfo)
private async Task<bool> PostProcessFolder(ApplicationUser user, DirectoryInfo inboundFolder, IEnumerable<PluginResultInfo> pluginResults, bool doJustInfo, bool doDeleteFiles = true)
{
SimpleContract.Requires<ArgumentNullException>(inboundFolder != null, "Invalid InboundFolder");
if (pluginResults != null)
@ -132,7 +132,7 @@ namespace Roadie.Api.Services
_addedTrackIds.AddRange(ReleaseService.AddedTrackIds);
}
}
if (!doJustInfo)
if (!doJustInfo && doDeleteFiles)
{
var fileExtensionsToDelete = Configuration.FileExtensionsToDelete ?? new string[0];
if (fileExtensionsToDelete.Any())

View file

@ -14,6 +14,6 @@ namespace Roadie.Api.Services
int? ProcessLimit { get; set; }
Task<OperationResult<bool>> Process(ApplicationUser user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null);
Task<OperationResult<bool>> Process(ApplicationUser user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null, bool doDeleteFiles = true);
}
}

View file

@ -1478,7 +1478,18 @@ namespace Roadie.Api.Services
#endregion Scan Folder and Add or Update Existing Tracks from Files
var doesReleaseHaveCoverImage = ImageHelper.FindImageTypeInDirectory(releaseDirectory, ImageType.Release).FirstOrDefault() != null;
var releaseCoverImage = ImageHelper.FindImageTypeInDirectory(releaseDirectory, ImageType.Release).FirstOrDefault();
var doesReleaseHaveCoverImage = releaseCoverImage != null;
if(doesReleaseHaveCoverImage)
{
// See if image file is valid image if not delete it
if(ImageHelper.ConvertToJpegFormat(File.ReadAllBytes(releaseCoverImage.FullName)) == null)
{
releaseCoverImage.Delete();
doesReleaseHaveCoverImage = false;
Logger.LogWarning($"Deleted invalid cover image for Release `{ release }`");
}
}
if (!doesReleaseHaveCoverImage)
{
// Since no release image found see if first track has image in metadata if so then extract to cover file
@ -1492,8 +1503,13 @@ namespace Roadie.Api.Services
var metaData = await AudioMetaDataHelper.GetInfo(new FileInfo(firstTrack.PathToTrack(Configuration)), doJustInfo);
if (metaData.Images != null && metaData.Images.Any())
{
var releaseImageFilename = Path.Combine(releasePath, ImageHelper.ReleaseCoverFilename);
File.WriteAllBytes(releaseImageFilename, metaData.Images.First(x => x.Data != null).Data);
var imageBytes = ImageHelper.ConvertToJpegFormat(metaData.Images.FirstOrDefault(x => x.Data != null)?.Data);
if (imageBytes != null)
{
var releaseImageFilename = Path.Combine(releasePath, ImageHelper.ReleaseCoverFilename);
File.WriteAllBytes(releaseImageFilename, imageBytes);
Logger.LogInformation($"Extracted cover image from track for Release `{ release}`");
}
}
}
}

View file

@ -133,6 +133,7 @@ namespace Roadie.Api.Controllers
return Ok(new
{
Username = user.UserName,
InstanceName = RoadieSettings.SiteName,
RecentLimit = user.RecentlyPlayedLimit,
user.RemoveTrackFromQueAfterPlayed,
user.Email,
@ -239,6 +240,7 @@ namespace Roadie.Api.Controllers
return Ok(new
{
Username = user.UserName,
InstanceName = RoadieSettings.SiteName,
RecentLimit = user.RecentlyPlayedLimit,
user.RemoveTrackFromQueAfterPlayed,
user.Email,
@ -285,6 +287,7 @@ namespace Roadie.Api.Controllers
return Ok(new
{
Username = user.UserName,
InstanceName = RoadieSettings.SiteName,
RecentLimit = user.RecentlyPlayedLimit,
user.RemoveTrackFromQueAfterPlayed,
user.Email,

View file

@ -3,7 +3,7 @@
"Roadie.Api": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
"ASPNETCORE_ENVIRONMENT": "DevelopmentFIle"
},
"applicationUrl": "http://localhost:5123/"
}

View file

@ -61,7 +61,6 @@ namespace Roadie.Api
TypeAdapterConfig.GlobalSettings.Default.PreserveReference(true);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
@ -69,10 +68,9 @@ namespace Roadie.Api
app.UseDeveloperExceptionPage();
}
app.UseCors("CORSPolicy");
app.UseStaticFiles();
app.UseAuthorization();
app.UseAuthentication();
app.UseRouting();
//app.UseSwagger();
//app.UseSwaggerUI(c =>
@ -83,15 +81,17 @@ namespace Roadie.Api
app.UseSerilogRequestLogging();
app.UseStaticFiles();
app.UseCors("CORSPolicy");
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<PlayActivityHub>("/playActivityHub");
endpoints.MapHub<ScanActivityHub>("/scanActivityHub");
endpoints.MapControllers();
endpoints.MapDefaultControllerRoute();
});
}
@ -119,7 +119,6 @@ namespace Roadie.Api
options => options.UseMySql(_configuration.GetConnectionString("RoadieDatabaseConnection"),
mySqlOptions =>
{
mySqlOptions.ServerVersion(new Version(5, 5), ServerType.MariaDb);
mySqlOptions.EnableRetryOnFailure(
10,
TimeSpan.FromSeconds(30),
@ -130,7 +129,6 @@ namespace Roadie.Api
options => options.UseMySql(_configuration.GetConnectionString("RoadieDatabaseConnection"),
mySqlOptions =>
{
mySqlOptions.ServerVersion(new Version(5, 5), ServerType.MariaDb);
mySqlOptions.EnableRetryOnFailure(
10,
TimeSpan.FromSeconds(30),
@ -154,6 +152,10 @@ namespace Roadie.Api
throw new NotImplementedException("Unknown DbContext Type");
}
//services.AddDefaultIdentity<ApplicationUser>(
// options => options.SignIn.RequireConfirmedAccount = false)
// .AddEntityFrameworkStores<ApplicationUserDbContext>();
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddRoles<ApplicationRole>()
.AddEntityFrameworkStores<ApplicationUserDbContext>()

View file

@ -57,56 +57,16 @@
"ConnectionStrings": {
"RoadieDatabaseConnection": "server=viking;userid=roadie;password=MenAtW0rk668;persistsecurityinfo=True;database=roadie_dev;ConvertZeroDateTime=true;Max Pool Size=200;default command timeout=180;"
},
"CORSOrigins": "http://localhost:4200|http://localhost:8080|https://localhost:8080|http://localhost:80|https://localhost:80|http://192.168.1.177:8080",
"CORSOrigins": "http://localhost:4200|http://localhost:8080|https://localhost:8080|http://localhost:80|https://localhost:80",
"RoadieSettings": {
"DbContextToUse": "File",
"FileDatabaseOptions": {
"DatabaseFolder": "C:\\\\roadie_dev_root\\\\db"
},
"InboundFolder": "C:\\roadie_dev_root\\inbound",
"LibraryFolder": "C:\\\\roadie_dev_root\\\\library",
"SiteName": "Roadie Dev",
"InboundFolder": "C:\\\\roadie_dev_root\\\\inbound",
"LibraryFolder": "C:\\\\roadie_dev_root\\\\library",
"Dlna": {
"IsEnabled": false
},
"Processing": {
"RemoveStringsRegex": "\\b[0-9]+\\s#\\s\\b",
"ReplaceStrings": [
{
"order": 1,
"key": "-OBSERVER",
"replaceWith": ""
},
{
"order": 2,
"key": "[Torrent Tatty]",
"replaceWith": ""
},
{
"order": 3,
"key": "_",
"replaceWith": ""
},
{
"order": 4,
"key": "-",
"replaceWith": ""
},
{
"order": 5,
"key": "~",
"replaceWith": ""
},
{
"order": 6,
"key": "^",
"replaceWith": ""
},
{
"order": 7,
"key": "#",
"replaceWith": ""
}
]
"RemoveStringsRegex": "\\b[0-9]+\\s#\\s\\b"
}
}
}

View file

@ -0,0 +1,73 @@
{
"Kestrel": {
"EndPoints": {
"Http": {
"Url": "http://192.168.1.177:5123/"
}
}
},
"Serilog": {
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.RollingFileAlternate", "Serilog.Sinks.LiteDB" ],
"MinimumLevel": {
"Default": "Verbose",
"Override": {
"System": "Warning",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Warning"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console",
"restrictedToMinimumLevel": "Verbose"
}
},
{
"Name": "LiteDB",
"Args": {
"databaseUrl": "logs\\logs.db",
"restrictedToMinimumLevel": "Verbose"
}
},
{
"Name": "RollingFileAlternate",
"Args": {
"minimumLevel": "Verbose",
"logDirectory": "logs",
"fileSizeLimitBytes": 26214400,
"retainedFileCountLimit": 30,
"buffered": true
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId", "WithExceptionDetails" ],
"Properties": {
"Application": "Roadie API"
}
},
"Tokens": {
"PrivateKey": "!1232bcdb4bebc80a0d080883d6deefuxlsh8bfc920c2a8cskeuxd8349sk412aa785662e594b4df48cb46aa3c652b40b3#",
"PublicKey": "91i4874y24134E50sz7dges68AB08",
"Lifetime": "86400",
"Issuer": "http://localhost:5123",
"Audience": "http://localhost:5500"
},
"CORSOrigins": "http://localhost:4200|http://localhost:8080|https://localhost:8080|http://localhost:80|https://localhost:80",
"RoadieSettings": {
"DbContextToUse": "File",
"SiteName": "Roadie File",
"FileDatabaseOptions": {
"DatabaseFolder": "C:\\roadie_dev_file_root\\db"
},
"InboundFolder": "C:\\roadie_dev_file_root\\inbound",
"LibraryFolder": "C:\\roadie_dev_file_root\\library",
"Dlna": {
"IsEnabled": false
},
"Processing": {
"RemoveStringsRegex": "\\b[0-9]+\\s#\\s\\b"
}
}
}