Several performance improvements. Updated NuGet packages.

This commit is contained in:
Steven Hildreth 2020-06-05 17:49:12 -05:00
parent 1bf0df6c97
commit 625fdf7266
17 changed files with 235 additions and 180 deletions

View file

@ -26,7 +26,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>

View file

@ -20,7 +20,7 @@ namespace Roadie.Library.Engines
Task<OperationResult<Release>> Add(Release release, bool doAddTracksInDatabase = false);
Release DatabaseQueryForReleaseTitle(Artist artist, string title, string sortTitle = null);
Task<Release> DatabaseQueryForReleaseTitle(Artist artist, string title, string sortTitle = null);
Task<OperationResult<Release>> GetByName(Artist artist, AudioMetaData metaData, bool doFindIfNotInDatabase = false, bool doAddTracksInDatabase = false, int? submissionId = null);

View file

@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Data;
@ -292,7 +293,7 @@ namespace Roadie.Library.Engines
};
}
public Release DatabaseQueryForReleaseTitle(Artist artist, string title, string sortTitle = null)
public async Task<Release> DatabaseQueryForReleaseTitle(Artist artist, string title, string sortTitle = null)
{
if (string.IsNullOrEmpty(title))
{
@ -312,7 +313,7 @@ namespace Roadie.Library.Engines
var specialSearchNameIn = $"|{specialSearchName}|";
var specialSearchNameEnd = $"|{specialSearchName}";
return (from a in DbContext.Releases
return await (from a in DbContext.Releases
where a.ArtistId == artist.Id
where a.Title.ToLower() == searchName ||
a.Title.ToLower() == specialSearchName ||
@ -328,7 +329,7 @@ namespace Roadie.Library.Engines
a.AlternateNames.ToLower().Contains(specialSearchNameIn) ||
a.AlternateNames.ToLower().EndsWith(specialSearchNameEnd)
select a
).FirstOrDefault();
).FirstOrDefaultAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
@ -360,7 +361,7 @@ namespace Roadie.Library.Engines
};
}
var release = DatabaseQueryForReleaseTitle(artist, metaData.Release);
var release = await DatabaseQueryForReleaseTitle(artist, metaData.Release).ConfigureAwait(false);
sw.Stop();
if (release?.IsValid != true)
@ -741,7 +742,7 @@ namespace Roadie.Library.Engines
{
result.Genres.Add(new ReleaseGenre
{
Genre = DbContext.Genres.Where(x => x.Name.ToLower() == g.ToLower()).FirstOrDefault() ?? new Genre
Genre = DbContext.Genres.Where(x => string.Equals(x.Name, g, StringComparison.OrdinalIgnoreCase)).FirstOrDefault() ?? new Genre
{
Name = g,
NormalizedName = g.ToAlphanumericName()

View file

@ -99,6 +99,38 @@ namespace Roadie.Library.Imaging
return result;
}
public static bool IsImageBetterQuality(string image1, string compareToImage)
{
if(string.IsNullOrEmpty(compareToImage))
{
return true;
}
try
{
if (string.IsNullOrEmpty(image1) || !File.Exists(image1))
{
return File.Exists(compareToImage);
}
using (var imageComparing = SixLabors.ImageSharp.Image.Load(image1))
{
using (var imageToCompare = SixLabors.ImageSharp.Image.Load(compareToImage))
{
// Generally a larger image is the preferred image
var isBigger = imageToCompare.Height > imageComparing.Height && imageToCompare.Width > imageComparing.Width;
if (isBigger)
{
return true;
}
}
}
}
catch (Exception ex)
{
Trace.WriteLine($"Error IsImageBetterQuality Image Comparing [{ image1 }] to [{ compareToImage }], Error [{ ex }]", "Warning");
}
return false;
}
public static IEnumerable<FileInfo> FindImageTypeInDirectory(DirectoryInfo directory, ImageType type, SearchOption folderSearchOptions = SearchOption.AllDirectories)
{
var result = new List<FileInfo>();

View file

@ -11,14 +11,14 @@
<PackageReference Include="AutoCompare.Core" Version="1.0.0" />
<PackageReference Include="CsvHelper" Version="15.0.5" />
<PackageReference Include="EFCore.BulkExtensions" Version="3.1.1" />
<PackageReference Include="FluentFTP" Version="32.4.1" />
<PackageReference Include="FluentFTP" Version="32.4.3" />
<PackageReference Include="Hashids.net" Version="1.3.0" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.23" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.24" />
<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" />
<PackageReference Include="LiteDB" Version="5.0.8" />
<PackageReference Include="Mapster" Version="5.3.1" />
<PackageReference Include="Mapster" Version="5.3.2" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.1.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.4" />
@ -39,7 +39,7 @@
<PackageReference Include="System.Drawing.Common" Version="4.7.0" />
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="4.7.0" />
<PackageReference Include="System.Runtime.Caching" Version="4.7.0" />
<PackageReference Include="z440.atl.core" Version="3.4.1" />
<PackageReference Include="z440.atl.core" Version="3.5.0" />
<PackageReference Include="zlib.net-mutliplatform" Version="1.0.4" />
</ItemGroup>

View file

@ -640,19 +640,19 @@ namespace Roadie.Api.Services
Logger.LogInformation($"Administration startup tasks completed, elapsed time [{ sw.ElapsedMilliseconds }]");
}
public async Task<OperationResult<bool>> ScanAllCollections(User user, bool isReadOnly = false,
bool doPurgeFirst = false)
public async Task<OperationResult<bool>> ScanAllCollections(User user, bool isReadOnly = false, bool doPurgeFirst = false)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var collections = await DbContext.Collections.Where(x => x.IsLocked == false).ToArrayAsync();
var collections = await DbContext.Collections.Where(x => x.IsLocked == false).ToArrayAsync().ConfigureAwait(false);
var updatedReleaseIds = new List<int>();
foreach (var collection in collections)
{
try
{
var result = await ScanCollection(user, collection.RoadieId, isReadOnly, doPurgeFirst, false);
var result = await ScanCollection(user, collection.RoadieId, isReadOnly, doPurgeFirst, false).ConfigureAwait(false);
if (!result.IsSuccess)
{
errors.AddRange(result.Errors);
@ -661,19 +661,20 @@ namespace Roadie.Api.Services
}
catch (Exception ex)
{
await LogAndPublish(ex.ToString(), LogLevel.Error);
await LogAndPublish(ex.ToString(), LogLevel.Error).ConfigureAwait(false);
errors.Add(ex);
}
}
foreach (var updatedReleaseId in updatedReleaseIds.Distinct())
{
await UpdateReleaseRank(updatedReleaseId);
await UpdateReleaseRank(updatedReleaseId).ConfigureAwait(false);
}
sw.Stop();
await LogAndPublish($"ScanAllCollections, By User `{user}`, Updated Release Count [{updatedReleaseIds.Distinct().Count()}], ElapsedTime [{sw.ElapsedMilliseconds}]", LogLevel.Warning);
await LogAndPublish($"ScanAllCollections, By User `{user}`, Updated Release Count [{updatedReleaseIds.Distinct().Count()}], ElapsedTime [{sw.ElapsedMilliseconds}]", LogLevel.Warning).ConfigureAwait(false);
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
Data = true,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
@ -758,10 +759,10 @@ namespace Roadie.Api.Services
var updatedReleaseIds = new List<int>();
var result = new List<data.PositionArtistRelease>();
var errors = new List<Exception>();
var collection = DbContext.Collections.FirstOrDefault(x => x.RoadieId == collectionId);
var collection = await DbContext.Collections.FirstOrDefaultAsync(x => x.RoadieId == collectionId).ConfigureAwait(false);
if (collection == null)
{
await LogAndPublish($"ScanCollection Unknown Collection [{collectionId}]", LogLevel.Warning);
await LogAndPublish($"ScanCollection Unknown Collection [{collectionId}]", LogLevel.Warning).ConfigureAwait(false);
return new OperationResult<bool>(true, $"Collection Not Found [{collectionId}]");
}
@ -769,15 +770,15 @@ namespace Roadie.Api.Services
{
if (doPurgeFirst)
{
await LogAndPublish($"ScanCollection Purging Collection [{collectionId}]", LogLevel.Warning);
var crs = await DbContext.CollectionReleases.Where(x => x.CollectionId == collection.Id).ToArrayAsync();
await LogAndPublish($"ScanCollection Purging Collection [{collectionId}]", LogLevel.Warning).ConfigureAwait(false);
var crs = await DbContext.CollectionReleases.Where(x => x.CollectionId == collection.Id).ToArrayAsync().ConfigureAwait(false);
DbContext.CollectionReleases.RemoveRange(crs);
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
}
var collectionMissingRecords = DbContext.CollectionMissings.Where(x => x.CollectionId == collection.Id);
DbContext.CollectionMissings.RemoveRange(collectionMissingRecords);
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
var par = collection.PositionArtistReleases();
if (par != null)
@ -800,23 +801,23 @@ namespace Roadie.Api.Services
}
else
{
artistsMatchingName = await ArtistLookupEngine.DatabaseQueryForArtistName(csvRelease.Artist);
artistsMatchingName = await ArtistLookupEngine.DatabaseQueryForArtistName(csvRelease.Artist).ConfigureAwait(false);
if (artistsMatchingName == null || !artistsMatchingName.Any())
{
await LogAndPublish($"CSV Position [{ csvRelease.Position }] Unable To Find Artist [{csvRelease.Artist}]", LogLevel.Warning);
await LogAndPublish($"CSV Position [{ csvRelease.Position }] Unable To Find Artist [{csvRelease.Artist}]", LogLevel.Warning).ConfigureAwait(false);
csvRelease.Status = Statuses.Missing;
DbContext.CollectionMissings.Add(new data.CollectionMissing
await DbContext.CollectionMissings.AddAsync(new data.CollectionMissing
{
CollectionId = collection.Id,
Position = csvRelease.Position,
Artist = csvRelease.Artist,
Release = csvRelease.Release
});
}).ConfigureAwait(false);
continue;
}
else if (artistsMatchingName.Count() > 1)
{
await LogAndPublish($"CSV Position [{ csvRelease.Position }] Found [{ artistsMatchingName.Count() }] Artists by [{csvRelease.Artist}]", LogLevel.Information);
await LogAndPublish($"CSV Position [{ csvRelease.Position }] Found [{ artistsMatchingName.Count() }] Artists by [{csvRelease.Artist}]", LogLevel.Information).ConfigureAwait(false);
}
}
foreach (var artist in artistsMatchingName)
@ -825,11 +826,11 @@ namespace Roadie.Api.Services
int? releaseId = isReleaseNameDbKey ? SafeParser.ToNumber<int?>(csvRelease.Release.Replace(Roadie.Library.Data.Collection.DatabaseIdKey, "")) : null;
if (releaseId.HasValue)
{
release = DbContext.Releases.FirstOrDefault(x => x.Id == releaseId.Value);
release = await DbContext.Releases.FirstOrDefaultAsync(x => x.Id == releaseId.Value).ConfigureAwait(false);
}
else
{
release = ReleaseLookupEngine.DatabaseQueryForReleaseTitle(artist, csvRelease.Release);
release = await ReleaseLookupEngine.DatabaseQueryForReleaseTitle(artist, csvRelease.Release).ConfigureAwait(false);
}
if (release != null)
{
@ -839,28 +840,29 @@ namespace Roadie.Api.Services
if (release == null)
{
await LogAndPublish($"CSV Position [{ csvRelease.Position }] Unable To Find Release [{csvRelease.Release}], for Artist [{csvRelease.Artist}]", LogLevel.Warning);
await LogAndPublish($"CSV Position [{ csvRelease.Position }] Unable To Find Release [{csvRelease.Release}], for Artist [{csvRelease.Artist}]", LogLevel.Warning).ConfigureAwait(false);
csvRelease.Status = Statuses.Missing;
DbContext.CollectionMissings.Add(new data.CollectionMissing
await DbContext.CollectionMissings.AddAsync(new data.CollectionMissing
{
CollectionId = collection.Id,
IsArtistFound = true,
Position = csvRelease.Position,
Artist = csvRelease.Artist,
Release = csvRelease.Release
});
}).ConfigureAwait(false);
continue;
}
var isInCollection = DbContext.CollectionReleases.FirstOrDefault(x =>
var isInCollection = await DbContext.CollectionReleases.FirstOrDefaultAsync(x =>
x.CollectionId == collection.Id &&
x.ListNumber == csvRelease.Position &&
x.ReleaseId == release.Id);
x.ReleaseId == release.Id)
.ConfigureAwait(false);
var updated = false;
// Found in Database but not in collection add to Collection
if (isInCollection == null)
{
DbContext.CollectionReleases.Add(new data.CollectionRelease
await DbContext.CollectionReleases.AddAsync(new data.CollectionRelease
{
CollectionId = collection.Id,
ReleaseId = release.Id,
@ -884,7 +886,7 @@ namespace Roadie.Api.Services
}
collection.LastUpdated = now;
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
var dto = new CollectionList
{
CollectionCount = collection.CollectionCount,
@ -903,10 +905,10 @@ namespace Roadie.Api.Services
collection.Status = Statuses.Incomplete;
}
var collectionReleasesToRemove = (from cr in DbContext.CollectionReleases
var collectionReleasesToRemove = await (from cr in DbContext.CollectionReleases
where cr.CollectionId == collection.Id
where !releaseIdsInCollection.Contains(cr.ReleaseId)
select cr).ToArray();
select cr).ToArrayAsync().ConfigureAwait(false);
if (collectionReleasesToRemove.Any())
{
await LogAndPublish($"Removing [{collectionReleasesToRemove.Count()}] Stale Release Records from Collection.", LogLevel.Information);
@ -918,7 +920,7 @@ namespace Roadie.Api.Services
{
foreach (var updatedReleaseId in updatedReleaseIds)
{
await UpdateReleaseRank(updatedReleaseId);
await UpdateReleaseRank(updatedReleaseId).ConfigureAwait(false);
}
}
CacheManager.ClearRegion(collection.CacheRegion);
@ -1113,7 +1115,7 @@ namespace Roadie.Api.Services
break;
}
await ScanActivityHub.Clients.All.SendAsync("SendSystemActivity", message);
await ScanActivityHub.Clients.All.SendAsync("SendSystemActivity", message).ConfigureAwait(false);
}
private async Task<OperationResult<bool>> ScanFolder(User user, DirectoryInfo d, bool isReadOnly, bool doDeleteFiles = true)

View file

@ -277,18 +277,16 @@ namespace Roadie.Api.Services
where randomArtistIds == null || randomArtistIds.Contains(a.Id)
where request.FilterToArtistId == null || a.RoadieId == request.FilterToArtistId
where request.FilterMinimumRating == null || a.Rating >= request.FilterMinimumRating.Value
where string.IsNullOrEmpty(request.FilterValue) ||
a.Name.Contains(request.FilterValue) ||
a.SortName.Contains(request.FilterValue) ||
a.RealName.Contains(request.FilterValue) ||
a.AlternateNames.Contains(request.FilterValue) ||
where string.IsNullOrEmpty(normalizedFilterValue) ||
a.Name.ToLower().Contains(normalizedFilterValue) ||
a.SortName.ToLower().Contains(normalizedFilterValue) ||
a.RealName.ToLower().Contains(normalizedFilterValue) ||
a.AlternateNames.Contains(normalizedFilterValue)
where !isEqualFilter ||
a.Name.Equals(request.FilterValue) ||
a.SortName.Equals(request.FilterValue) ||
a.RealName.Equals(request.FilterValue) ||
a.AlternateNames.Equals(request.FilterValue) ||
a.AlternateNames.Equals(normalizedFilterValue)
a.Name.ToLower().Equals(normalizedFilterValue) ||
a.SortName.ToLower().Equals(normalizedFilterValue) ||
a.RealName.ToLower().Equals(normalizedFilterValue) ||
a.AlternateNames.ToLower().Equals(normalizedFilterValue)
where !request.FilterFavoriteOnly || favoriteArtistIds.Contains(a.Id)
where request.FilterToLabelId == null || labelArtistIds.Contains(a.Id)
where !isFilteredToGenre || genreArtistIds.Contains(a.Id)

View file

@ -193,12 +193,19 @@ namespace Roadie.Api.Services
collections = DbContext.Collections;
}
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue)
? request.FilterValue.ToAlphanumericName()
: null;
var result = from c in collections
let collectionCount = (from crc in DbContext.CollectionReleases
where crc.CollectionId == c.Id
select crc.Id).Count()
where request.FilterValue.Length == 0 ||
request.FilterValue.Length > 0 && c.Name.Contains(request.Filter)
where string.IsNullOrEmpty(normalizedFilterValue) || (
c.Name.ToLower().Contains(normalizedFilterValue) ||
c.SortName.ToLower().Contains(normalizedFilterValue) ||
c.AlternateNames.ToLower().Contains(normalizedFilterValue)
)
where request.FilterToStatusValue == Statuses.Ok || c.Status == request.FilterToStatusValue
select new CollectionList
{

View file

@ -107,6 +107,10 @@ namespace Roadie.Api.Services
rowCount = DbContext.Genres.Count();
}
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue)
? request.FilterValue.ToAlphanumericName()
: null;
var result = from g in DbContext.Genres
where randomGenreIds == null || randomGenreIds.Contains(g.Id)
let releaseCount = (from rg in DbContext.ReleaseGenres
@ -115,7 +119,11 @@ namespace Roadie.Api.Services
let artistCount = (from rg in DbContext.ArtistGenres
where rg.GenreId == g.Id
select rg.Id).Count()
where request.FilterValue.Length == 0 || g.Name.Contains(request.FilterValue)
where string.IsNullOrEmpty(normalizedFilterValue) || (
g.Name.ToLower().Contains(normalizedFilterValue) ||
g.SortName.ToLower().Contains(normalizedFilterValue) ||
g.AlternateNames.ToLower().Contains(normalizedFilterValue)
)
select new GenreList
{
DatabaseId = g.Id,

View file

@ -141,11 +141,10 @@ namespace Roadie.Api.Services
var result = from l in DbContext.Labels
where randomLabelIds == null || randomLabelIds.Contains(l.Id)
where request.FilterValue == "" || (
l.Name.Contains(request.FilterValue) ||
l.SortName.Contains(request.FilterValue) ||
l.AlternateNames.Contains(request.FilterValue) ||
l.AlternateNames.Contains(normalizedFilterValue)
where string.IsNullOrEmpty(normalizedFilterValue) || (
l.Name.ToLower().Contains(normalizedFilterValue) ||
l.SortName.ToLower().Contains(normalizedFilterValue) ||
l.AlternateNames.ToLower().Contains(normalizedFilterValue)
)
select new LabelList
{

View file

@ -231,13 +231,19 @@ namespace Roadie.Api.Services
select pl.Id
).ToArray();
}
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue)
? request.FilterValue.ToAlphanumericName()
: null;
var result = from pl in DbContext.Playlists
join u in DbContext.Users on pl.UserId equals u.Id
where request.FilterToPlaylistId == null || pl.RoadieId == request.FilterToPlaylistId
where request.FilterToArtistId == null || playlistWithArtistTrackIds.Contains(pl.Id)
where request.FilterToReleaseId == null || playlistReleaseTrackIds.Contains(pl.Id)
where roadieUser == null && pl.IsPublic || roadieUser != null && u.RoadieId == roadieUser.UserId || pl.IsPublic
where request.FilterValue.Length == 0 || request.FilterValue.Length > 0 && pl.Name != null && pl.Name.Contains(request.FilterValue)
where string.IsNullOrEmpty(normalizedFilterValue) || (
pl.Name.ToLower().Contains(normalizedFilterValue) ||
pl.AlternateNames.ToLower().Contains(normalizedFilterValue)
)
select new PlaylistList
{
Playlist = new DataToken

View file

@ -291,41 +291,9 @@ namespace Roadie.Api.Services
select plt.PlayListId).ToListAsync().ConfigureAwait(false);
if (doDeleteFiles)
{
foreach (var track in releaseTracks)
{
string trackPath = null;
try
{
trackPath = track.PathToTrack(Configuration);
if (File.Exists(trackPath))
{
File.Delete(trackPath);
Logger.LogWarning("For Release [{0}], Deleted File [{1}]", release.Id, trackPath);
}
}
catch (Exception ex)
{
Logger.LogError(ex, $"Error Deleting File [{trackPath}] For Track `{track}` Exception [{ex}]");
}
}
// Delete all image files for Release
foreach (var file in ImageHelper.ImageFilesInFolder(release.ReleaseFileFolder(release.Artist.ArtistFileFolder(Configuration)), SearchOption.AllDirectories))
{
try
{
File.Delete(file);
Logger.LogWarning("For Release [{0}], Deleted File [{1}]", release.Id, file);
}
catch (Exception ex)
{
Logger.LogError(ex, $"Error Deleting File [{file}] Exception [{ex}]");
}
}
try
{
FolderPathHelper.DeleteEmptyFoldersForArtist(Configuration, release.Artist);
Directory.Delete(release.ReleaseFileFolder(release.Artist.ArtistFileFolder(Configuration)), true);
}
catch (Exception ex)
{
@ -522,15 +490,13 @@ namespace Roadie.Api.Services
(r.ReleaseDate != null && r.ReleaseDate.Value.Year <= request.FilterFromYear)
where request.FilterToYear == null ||
(r.ReleaseDate != null && r.ReleaseDate.Value.Year >= request.FilterToYear)
where string.IsNullOrEmpty(request.FilterValue) ||
r.Title.Contains(request.FilterValue) ||
r.AlternateNames.Contains(request.FilterValue) ||
r.AlternateNames.Contains(normalizedFilterValue)
where string.IsNullOrEmpty(normalizedFilterValue) ||
r.Title.ToLower().Contains(normalizedFilterValue) ||
r.AlternateNames.ToLower().Contains(normalizedFilterValue)
where !isEqualFilter ||
r.Title.Equals(request.FilterValue) ||
r.AlternateNames.Equals(request.FilterValue) ||
r.AlternateNames.Equals(normalizedFilterValue)
select new ReleaseList
r.Title.ToLower().Equals(normalizedFilterValue) ||
r.AlternateNames.ToLower().Contains(normalizedFilterValue)
select new ReleaseList
{
DatabaseId = r.Id,
Id = r.RoadieId,
@ -858,7 +824,6 @@ namespace Roadie.Api.Services
try
{
var mergedFilesToDelete = new List<string>();
var mergedTracksToMove = new List<data.Track>();
releaseToMergeInto.MediaCount ??= 0;
@ -947,13 +912,6 @@ namespace Roadie.Api.Services
existingTrack.AlternateNames = existingTrack.AlternateNames.AddToDelimitedList(mergeTrack.AlternateNames.ToListFromDelimited());
existingTrack.LastUpdated = now;
var mergedTrackFileName = mergeTrack.PathToTrack(Configuration);
var trackFileName = existingTrack.PathToTrack(Configuration);
if (!trackFileName.Equals(mergedTrackFileName, StringComparison.Ordinal) &&
File.Exists(trackFileName))
{
mergedFilesToDelete.Add(mergedTrackFileName);
}
}
}
}
@ -979,6 +937,13 @@ namespace Roadie.Api.Services
track.Hash = HashHelper.CreateMD5(releaseToMergeInto.ArtistId + trackFile.LastWriteTimeUtc.GetHashCode().ToString() + audioMetaData.GetHashCode());
track.LastUpdated = now;
File.Move(oldTrackPath, newTrackPath);
// If track has track image move into new folder
var trackImageFileName = track.PathToTrackThumbnail(Configuration);
if (File.Exists(trackImageFileName))
{
File.Move(trackImageFileName, newTrackPath);
}
}
}
}
@ -1060,30 +1025,61 @@ namespace Roadie.Api.Services
await Delete(user, releaseToMerge).ConfigureAwait(false);
// Delete any files flagged to be deleted (duplicate as track already exists on merged to release)
if (mergedFilesToDelete.Count > 0)
// Merge all release images
var releaseCoverFiles = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(releaseToMergeFolder), ImageType.Release);
if (releaseCoverFiles.Any())
{
foreach (var mergedFileToDelete in mergedFilesToDelete)
foreach(var releaseCoverFile in releaseCoverFiles)
{
try
var imagePath = Path.Combine(releaseToMergeIntoDirectory.FullName, releaseCoverFile.Name);
if(File.Exists(imagePath))
{
if (File.Exists(mergedFileToDelete))
if(ImageHelper.IsImageBetterQuality(releaseCoverFile.FullName, imagePath))
{
File.Delete(mergedFileToDelete);
Logger.LogWarning("x Deleted Merged File [{0}]", mergedFileToDelete);
releaseCoverFile.MoveTo(imagePath, true);
}
}
catch
else
{
releaseCoverFile.MoveTo(imagePath);
}
}
}
var secondaryReleaseCoverFiles = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(releaseToMergeFolder), ImageType.ReleaseSecondary);
if (secondaryReleaseCoverFiles.Any())
{
foreach (var secondaryReleaseCoverFile in secondaryReleaseCoverFiles)
{
var imagePath = Path.Combine(releaseToMergeIntoDirectory.FullName, secondaryReleaseCoverFile.Name);
if (File.Exists(imagePath))
{
if (ImageHelper.IsImageBetterQuality(secondaryReleaseCoverFile.FullName, imagePath))
{
secondaryReleaseCoverFile.MoveTo(imagePath, true);
}
}
else
{
secondaryReleaseCoverFile.MoveTo(imagePath, true);
}
}
}
var releaseToMergeInfoDirectory = new DirectoryInfo(releaseToMergeFolder);
if(releaseToMergeInfoDirectory.Exists)
{
releaseToMergeInfoDirectory.Delete(true);
Logger.LogWarning("x Deleted Folder [{0}]", releaseToMergeInfoDirectory);
}
// Clear cache regions for manipulated records
CacheManager.ClearRegion(releaseToMergeInto.CacheRegion);
if (releaseToMergeInto.Artist != null) CacheManager.ClearRegion(releaseToMergeInto.Artist.CacheRegion);
if (releaseToMerge.Artist != null) CacheManager.ClearRegion(releaseToMerge.Artist.CacheRegion);
// Rescan release
await ScanReleaseFolder(user, releaseToMergeInto.RoadieId, false, releaseToMergeInto).ConfigureAwait(false);
sw.Stop();
result = true;
}

View file

@ -9,8 +9,8 @@
<PackageReference Include="Hashids.net" Version="1.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="3.1.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.5.1" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.1.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.6.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.1.2" />
</ItemGroup>
<ItemGroup>

View file

@ -93,9 +93,8 @@ namespace Roadie.Api.Services
}
var artistByName = await CacheManager.GetAsync(data.Artist.CacheUrnByName(artistName), async () =>
{
return await DbContext.Artists
.FirstOrDefaultAsync(x => x.Name == artistName);
}, null);
return await DbContext.Artists.FirstOrDefaultAsync(x => x.Name == artistName).ConfigureAwait(false);
}, null).ConfigureAwait(false);
if (artistByName == null)
{
return null;
@ -103,83 +102,80 @@ namespace Roadie.Api.Services
return await GetArtist(artistByName.RoadieId);
}
protected async Task<data.Artist> GetArtist(Guid id)
protected Task<data.Artist> GetArtist(Guid id)
{
if (id == Guid.Empty)
{
return null;
return Task.FromResult<data.Artist>(null);
}
return await CacheManager.GetAsync(data.Artist.CacheUrn(id), async () =>
return CacheManager.GetAsync(data.Artist.CacheUrn(id), () =>
{
return await DbContext.Artists
return DbContext.Artists
.Include(x => x.Genres)
.Include("Genres.Genre")
.FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Artist.CacheRegionUrn(id));
}
protected async Task<data.Collection> GetCollection(Guid id)
protected Task<data.Collection> GetCollection(Guid id)
{
if (id == Guid.Empty)
{
return null;
return Task.FromResult<data.Collection>(null);
}
return await CacheManager.GetAsync(data.Collection.CacheUrn(id), async () =>
return CacheManager.GetAsync(data.Collection.CacheUrn(id), () =>
{
return await DbContext.Collections
.FirstOrDefaultAsync(x => x.RoadieId == id);
return DbContext.Collections.FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Collection.CacheRegionUrn(id));
}
protected async Task<data.Genre> GetGenre(Guid id)
protected Task<data.Genre> GetGenre(Guid id)
{
if (id == Guid.Empty)
{
return null;
return Task.FromResult<data.Genre>(null);
}
return await CacheManager.GetAsync(data.Genre.CacheUrn(id), async () =>
return CacheManager.GetAsync(data.Genre.CacheUrn(id), () =>
{
return await DbContext.Genres
.FirstOrDefaultAsync(x => x.RoadieId == id);
return DbContext.Genres.FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Genre.CacheRegionUrn(id));
}
protected async Task<data.Label> GetLabel(Guid id)
protected Task<data.Label> GetLabel(Guid id)
{
if (id == Guid.Empty)
{
return null;
return Task.FromResult<data.Label>(null);
}
return await CacheManager.GetAsync(data.Label.CacheUrn(id), async () =>
return CacheManager.GetAsync(data.Label.CacheUrn(id), () =>
{
return await DbContext.Labels
.FirstOrDefaultAsync(x => x.RoadieId == id);
return DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Label.CacheRegionUrn(id));
}
protected async Task<data.Playlist> GetPlaylist(Guid id)
protected Task<data.Playlist> GetPlaylist(Guid id)
{
if (id == Guid.Empty)
{
return null;
return Task.FromResult<data.Playlist>(null);
}
return await CacheManager.Get(data.Playlist.CacheUrn(id), async () =>
return CacheManager.GetAsync(data.Playlist.CacheUrn(id), () =>
{
return await DbContext.Playlists
.Include(x => x.User)
.FirstOrDefaultAsync(x => x.RoadieId == id);
return DbContext.Playlists
.Include(x => x.User)
.FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Playlist.CacheRegionUrn(id));
}
protected async Task<data.Release> GetRelease(Guid id)
protected Task<data.Release> GetRelease(Guid id)
{
if (id == Guid.Empty)
{
return null;
return Task.FromResult<data.Release>(null);
}
return await CacheManager.Get(data.Release.CacheUrn(id), async () =>
return CacheManager.GetAsync(data.Release.CacheUrn(id), () =>
{
return await DbContext.Releases
return DbContext.Releases
.Include(x => x.Artist)
.Include(x => x.Genres)
.Include("Genres.Genre")
@ -203,15 +199,15 @@ namespace Roadie.Api.Services
}
// Only read operations
protected async Task<data.Track> GetTrack(Guid id)
protected Task<data.Track> GetTrack(Guid id)
{
if(id == Guid.Empty)
{
return null;
return Task.FromResult<data.Track>(null);
}
return await CacheManager.GetAsync(data.Track.CacheUrn(id), async () =>
return CacheManager.GetAsync(data.Track.CacheUrn(id), () =>
{
return await DbContext.Tracks
return DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
@ -226,19 +222,22 @@ namespace Roadie.Api.Services
{
return null;
}
var userByUsername = await CacheManager.GetAsync(User.CacheUrnByUsername(username), async () =>
var userByUsername = await CacheManager.GetAsync(User.CacheUrnByUsername(username), () =>
{
return await DbContext.Users.FirstOrDefaultAsync(x => x.UserName == username);
return DbContext.Users.FirstOrDefaultAsync(x => x.UserName == username);
}, null);
return await GetUser(userByUsername?.RoadieId);
return await GetUser(userByUsername?.RoadieId).ConfigureAwait(false);
}
protected async Task<User> GetUser(Guid? id)
protected Task<User> GetUser(Guid? id)
{
if (!id.HasValue) return null;
return await CacheManager.GetAsync(User.CacheUrn(id.Value), async () =>
if (!id.HasValue)
{
return Task.FromResult<User>(null);
}
return CacheManager.GetAsync(User.CacheUrn(id.Value), () =>
{
return await DbContext.Users
return DbContext.Users
.Include(x => x.UserRoles)
.Include("UserRoles.Role")
.Include("UserRoles.Role.RoleClaims")
@ -276,9 +275,9 @@ namespace Roadie.Api.Services
userArtist.LastUpdated = now;
}
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
var ratings = await DbContext.UserArtists.Where(x => x.ArtistId == artist.Id && x.Rating > 0).Select(x => x.Rating).ToListAsync();
var ratings = await DbContext.UserArtists.Where(x => x.ArtistId == artist.Id && x.Rating > 0).Select(x => x.Rating).ToListAsync().ConfigureAwait(false);
if (ratings != null && ratings.Any())
{
artist.Rating = (short)ratings.Average(x => (decimal)x);
@ -288,12 +287,12 @@ namespace Roadie.Api.Services
artist.Rating = 0;
}
artist.LastUpdated = now;
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
await UpdateArtistRank(artist.Id);
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(artist.CacheRegion);
artist = await GetArtist(artistId);
artist = await GetArtist(artistId).ConfigureAwait(false);
return new OperationResult<short>
{
@ -947,7 +946,7 @@ namespace Roadie.Api.Services
join t in DbContext.Tracks on ut.TrackId equals t.Id
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
where rm.ReleaseId == releaseId
select ut.Rating).Select(x => (decimal?)x).ToArrayAsync()).Average();
select ut.Rating).Select(x => (decimal?)x).ToArrayAsync().ConfigureAwait(false)).Average();
var releaseUserRatingRank = release.Rating > 0 ? release.Rating / (decimal?)release.TrackCount : 0;
@ -970,12 +969,12 @@ namespace Roadie.Api.Services
release.Rank = SafeParser.ToNumber<decimal>(releaseTrackAverage) + releaseUserRatingRank + releaseCollectionRank;
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(release.CacheRegion);
Logger.LogTrace("UpdateReleaseRank For Release `{0}`", release);
if (updateArtistRank)
{
await UpdateArtistsRankForRelease(release);
await UpdateArtistsRankForRelease(release).ConfigureAwait(false);
}
}
}

View file

@ -341,8 +341,15 @@ namespace Roadie.Api.Services
where filterToTrackIds == null || filterToTrackIds.Contains(t.RoadieId)
where releaseId == null || r.RoadieId == releaseId
where request.FilterMinimumRating == null || t.Rating >= request.FilterMinimumRating.Value
where string.IsNullOrEmpty(request.FilterValue) || (trackArtist != null && trackArtist.Name.Contains(request.FilterValue)) || t.Title.Contains(request.FilterValue) || t.AlternateNames.Contains(request.FilterValue) || t.AlternateNames.Contains(normalizedFilterValue) || t.PartTitles.Contains(request.FilterValue)
where !isEqualFilter || t.Title.Equals(request.FilterValue) || t.AlternateNames.Equals(request.FilterValue) || t.AlternateNames.Equals(normalizedFilterValue) || t.PartTitles.Equals(request.FilterValue)
where string.IsNullOrEmpty(normalizedFilterValue) ||
(trackArtist != null && trackArtist.Name.ToLower().Contains(normalizedFilterValue)) ||
t.Title.ToLower().Contains(normalizedFilterValue) ||
t.AlternateNames.Contains(normalizedFilterValue) ||
t.PartTitles.ToLower().Contains(normalizedFilterValue)
where !isEqualFilter ||
t.Title.ToLower().Equals(normalizedFilterValue) ||
t.AlternateNames.ToLower().Equals(normalizedFilterValue) ||
t.PartTitles.ToLower().Equals(request.FilterValue)
where !request.FilterFavoriteOnly || favoriteTrackIds.Contains(t.Id)
where request.FilterToPlaylistId == null || playlistTrackIds.Contains(t.Id)
where !request.FilterTopPlayedOnly || topTrackids.Contains(t.Id)

View file

@ -212,7 +212,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> ScanAllCollections()
{
var result = await AdminService.ScanAllCollections(await UserManager.GetUserAsync(User));
var result = await AdminService.ScanAllCollections(await UserManager.GetUserAsync(User).ConfigureAwait(false)).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
@ -260,7 +260,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> ScanCollection(Guid id, bool doPurgeFirst = false)
{
var result = await AdminService.ScanCollection(await UserManager.GetUserAsync(User), id, doPurgeFirst: doPurgeFirst);
var result = await AdminService.ScanCollection(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, doPurgeFirst: doPurgeFirst).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)

View file

@ -29,7 +29,7 @@
<ItemGroup>
<PackageReference Include="BCrypt-Core" Version="2.0.0" />
<PackageReference Include="Mapster" Version="5.3.1" />
<PackageReference Include="Mapster" Version="5.3.2" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.14.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.4" />
@ -43,13 +43,13 @@
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.3" />
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
<PackageReference Include="Serilog.Exceptions" Version="5.4.0" />
<PackageReference Include="Serilog.Exceptions" Version="5.5.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.LiteDB.NetStandard" Version="1.0.14" />
<PackageReference Include="Serilog.Sinks.RollingFileAlternate" Version="2.0.9" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.5.1" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.1.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.6.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.1.2" />
</ItemGroup>
<ItemGroup>