mirror of
https://github.com/sphildreth/roadie
synced 2024-11-10 06:44:12 +00:00
Updated NuGet packages and CodeMaid services.
This commit is contained in:
parent
14a7119993
commit
004ca33d48
21 changed files with 497 additions and 577 deletions
|
@ -10,8 +10,8 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="AutoCompare.Core" Version="1.0.0" />
|
||||
<PackageReference Include="CsvHelper" Version="12.1.2" />
|
||||
<PackageReference Include="EFCore.BulkExtensions" Version="2.5.2" />
|
||||
<PackageReference Include="FluentFTP" Version="27.0.1" />
|
||||
<PackageReference Include="EFCore.BulkExtensions" Version="2.6.0" />
|
||||
<PackageReference Include="FluentFTP" Version="27.0.2" />
|
||||
<PackageReference Include="Hashids.net" Version="1.2.2" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.12" />
|
||||
<PackageReference Include="IdSharp.Common" Version="1.0.1" />
|
||||
|
@ -24,7 +24,7 @@
|
|||
<PackageReference Include="Microsoft.Extensions.Caching.Redis" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.PowerShell.SDK" Version="6.2.2" />
|
||||
<PackageReference Include="MimeMapping" Version="1.0.1.12" />
|
||||
<PackageReference Include="MimeMapping" Version="1.0.1.14" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
<PackageReference Include="NodaTime" Version="2.4.6" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.2.0" />
|
||||
|
|
|
@ -35,18 +35,17 @@ namespace Roadie.Api.Services
|
|||
|
||||
private IFileDirectoryProcessorService FileDirectoryProcessorService { get; }
|
||||
|
||||
private IGenreService GenreService { get; }
|
||||
private ILabelService LabelService { get; }
|
||||
private IReleaseLookupEngine ReleaseLookupEngine { get; }
|
||||
|
||||
private IReleaseService ReleaseService { get; }
|
||||
|
||||
private ILabelService LabelService { get; }
|
||||
private IGenreService GenreService { get; }
|
||||
|
||||
public AdminService(IRoadieSettings configuration, IHttpEncoder httpEncoder, IHttpContext httpContext,
|
||||
data.IRoadieDbContext context, ICacheManager cacheManager, ILogger<ArtistService> logger,
|
||||
IHubContext<ScanActivityHub> scanActivityHub, IFileDirectoryProcessorService fileDirectoryProcessorService, IArtistService artistService,
|
||||
IReleaseService releaseService, IReleaseLookupEngine releaseLookupEngine, ILabelService labelService, IGenreService genreService
|
||||
)
|
||||
)
|
||||
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
|
||||
{
|
||||
ScanActivityHub = scanActivityHub;
|
||||
|
@ -137,143 +136,38 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform checks/setup on start of application
|
||||
/// </summary>
|
||||
public void PerformStartUpTasks()
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
#region Setup Configured storage folders
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(Configuration.LibraryFolder))
|
||||
{
|
||||
Directory.CreateDirectory(Configuration.LibraryFolder);
|
||||
Logger.LogInformation($"Created Library Folder [{Configuration.LibraryFolder }]");
|
||||
}
|
||||
if (!Directory.Exists(Configuration.UserImageFolder))
|
||||
{
|
||||
Directory.CreateDirectory(Configuration.UserImageFolder);
|
||||
Logger.LogInformation($"Created User Image Folder [{Configuration.UserImageFolder }]");
|
||||
}
|
||||
if (!Directory.Exists(Configuration.GenreImageFolder))
|
||||
{
|
||||
Directory.CreateDirectory(Configuration.GenreImageFolder);
|
||||
Logger.LogInformation($"Created Genre Image Folder [{Configuration.GenreImageFolder }]");
|
||||
}
|
||||
if (!Directory.Exists(Configuration.PlaylistImageFolder))
|
||||
{
|
||||
Directory.CreateDirectory(Configuration.PlaylistImageFolder);
|
||||
Logger.LogInformation($"Created Playlist Image Folder [{Configuration.PlaylistImageFolder }]");
|
||||
}
|
||||
if (!Directory.Exists(Configuration.CollectionImageFolder))
|
||||
{
|
||||
Directory.CreateDirectory(Configuration.CollectionImageFolder);
|
||||
Logger.LogInformation($"Created Collection Image Folder [{Configuration.CollectionImageFolder }]");
|
||||
}
|
||||
if (!Directory.Exists(Configuration.LabelImageFolder))
|
||||
{
|
||||
Directory.CreateDirectory(Configuration.LabelImageFolder);
|
||||
Logger.LogInformation($"Created Label Image Folder [{Configuration.LabelImageFolder}]");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "Error setting up storage folders. Ensure application has create folder permissions.");
|
||||
throw;
|
||||
}
|
||||
#endregion
|
||||
sw.Stop();
|
||||
Logger.LogInformation($"Administration startup tasks completed, elapsed time [{ sw.ElapsedMilliseconds }]");
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ValidateInviteToken(Guid? tokenId)
|
||||
public async Task<OperationResult<bool>> DeleteArtistSecondaryImage(ApplicationUser user, Guid artistId, int index)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
if(tokenId == null)
|
||||
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
|
||||
if (artist == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Invalid Invite TokenId [{tokenId}]");
|
||||
}
|
||||
var token = DbContext.InviteTokens.FirstOrDefault(x => x.RoadieId == tokenId);
|
||||
if(token == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Invite Token Not Found [{tokenId}]");
|
||||
}
|
||||
if(token.ExpiresDate < DateTime.UtcNow || token.Status == Statuses.Expired)
|
||||
{
|
||||
token.Status = Statuses.Expired;
|
||||
token.LastUpdated = DateTime.UtcNow;
|
||||
await DbContext.SaveChangesAsync();
|
||||
return new OperationResult<bool>(true, $"Invite Token [{tokenId}] Expired [{ token.ExpiresDate }]");
|
||||
}
|
||||
if(token.Status == Statuses.Complete)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Invite Token [{tokenId}] Already Used");
|
||||
}
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdateInviteTokenUsed(Guid? tokenId)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
if (tokenId == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Invalid Invite TokenId [{tokenId}]");
|
||||
}
|
||||
var token = DbContext.InviteTokens.FirstOrDefault(x => x.RoadieId == tokenId);
|
||||
if (token == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Invite Token Not Found [{tokenId}]");
|
||||
}
|
||||
token.Status = Statuses.Complete;
|
||||
token.LastUpdated = DateTime.UtcNow;
|
||||
await DbContext.SaveChangesAsync();
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteLabel(ApplicationUser user, Guid labelId)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == labelId);
|
||||
if (label == null)
|
||||
{
|
||||
await LogAndPublish($"DeleteLabel Unknown Label [{labelId}]", LogLevel.Warning);
|
||||
return new OperationResult<bool>(true, $"Label Not Found [{labelId}]");
|
||||
await LogAndPublish($"DeleteArtistSecondaryImage Unknown Artist [{artistId}]", LogLevel.Warning);
|
||||
return new OperationResult<bool>(true, $"Artist Not Found [{artistId}]");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await LabelService.Delete(user, labelId);
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
var artistFolder = artist.ArtistFileFolder(Configuration);
|
||||
var artistImagesInFolder = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly);
|
||||
var artistImageFilename = artistImagesInFolder.Skip(index).FirstOrDefault();
|
||||
if (artistImageFilename.Exists)
|
||||
{
|
||||
artistImageFilename.Delete();
|
||||
}
|
||||
CacheManager.ClearRegion(artist.CacheRegion);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
await LogAndPublish("Error deleting Label.");
|
||||
await LogAndPublish("Error deleting artist secondary image.");
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
await LogAndPublish($"DeleteLabel `{label}`, By User `{user}`", LogLevel.Information);
|
||||
await LogAndPublish($"DeleteArtistSecondaryImage `{artist}` Index [{index}], By User `{user}`", LogLevel.Information);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
|
@ -318,39 +212,32 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteArtistSecondaryImage(ApplicationUser user, Guid artistId, int index)
|
||||
public async Task<OperationResult<bool>> DeleteLabel(ApplicationUser user, Guid labelId)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
|
||||
if (artist == null)
|
||||
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == labelId);
|
||||
if (label == null)
|
||||
{
|
||||
await LogAndPublish($"DeleteArtistSecondaryImage Unknown Artist [{artistId}]", LogLevel.Warning);
|
||||
return new OperationResult<bool>(true, $"Artist Not Found [{artistId}]");
|
||||
await LogAndPublish($"DeleteLabel Unknown Label [{labelId}]", LogLevel.Warning);
|
||||
return new OperationResult<bool>(true, $"Label Not Found [{labelId}]");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var artistFolder = artist.ArtistFileFolder(Configuration);
|
||||
var artistImagesInFolder = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly);
|
||||
var artistImageFilename = artistImagesInFolder.Skip(index).FirstOrDefault();
|
||||
if (artistImageFilename.Exists)
|
||||
{
|
||||
artistImageFilename.Delete();
|
||||
}
|
||||
CacheManager.ClearRegion(artist.CacheRegion);
|
||||
await LabelService.Delete(user, labelId);
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
await LogAndPublish("Error deleting artist secondary image.");
|
||||
await LogAndPublish("Error deleting Label.");
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
await LogAndPublish($"DeleteArtistSecondaryImage `{artist}` Index [{index}], By User `{user}`", LogLevel.Information);
|
||||
await LogAndPublish($"DeleteLabel `{label}`, By User `{user}`", LogLevel.Information);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
|
@ -506,7 +393,6 @@ namespace Roadie.Api.Services
|
|||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteUser(ApplicationUser applicationUser, Guid userId)
|
||||
|
@ -670,6 +556,60 @@ namespace Roadie.Api.Services
|
|||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform checks/setup on start of application
|
||||
/// </summary>
|
||||
public void PerformStartUpTasks()
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
#region Setup Configured storage folders
|
||||
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(Configuration.LibraryFolder))
|
||||
{
|
||||
Directory.CreateDirectory(Configuration.LibraryFolder);
|
||||
Logger.LogInformation($"Created Library Folder [{Configuration.LibraryFolder }]");
|
||||
}
|
||||
if (!Directory.Exists(Configuration.UserImageFolder))
|
||||
{
|
||||
Directory.CreateDirectory(Configuration.UserImageFolder);
|
||||
Logger.LogInformation($"Created User Image Folder [{Configuration.UserImageFolder }]");
|
||||
}
|
||||
if (!Directory.Exists(Configuration.GenreImageFolder))
|
||||
{
|
||||
Directory.CreateDirectory(Configuration.GenreImageFolder);
|
||||
Logger.LogInformation($"Created Genre Image Folder [{Configuration.GenreImageFolder }]");
|
||||
}
|
||||
if (!Directory.Exists(Configuration.PlaylistImageFolder))
|
||||
{
|
||||
Directory.CreateDirectory(Configuration.PlaylistImageFolder);
|
||||
Logger.LogInformation($"Created Playlist Image Folder [{Configuration.PlaylistImageFolder }]");
|
||||
}
|
||||
if (!Directory.Exists(Configuration.CollectionImageFolder))
|
||||
{
|
||||
Directory.CreateDirectory(Configuration.CollectionImageFolder);
|
||||
Logger.LogInformation($"Created Collection Image Folder [{Configuration.CollectionImageFolder }]");
|
||||
}
|
||||
if (!Directory.Exists(Configuration.LabelImageFolder))
|
||||
{
|
||||
Directory.CreateDirectory(Configuration.LabelImageFolder);
|
||||
Logger.LogInformation($"Created Label Image Folder [{Configuration.LabelImageFolder}]");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "Error setting up storage folders. Ensure application has create folder permissions.");
|
||||
throw;
|
||||
}
|
||||
|
||||
#endregion Setup Configured storage folders
|
||||
|
||||
sw.Stop();
|
||||
Logger.LogInformation($"Administration startup tasks completed, elapsed time [{ sw.ElapsedMilliseconds }]");
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanAllCollections(ApplicationUser user, bool isReadOnly = false,
|
||||
bool doPurgeFirst = false)
|
||||
{
|
||||
|
@ -710,32 +650,6 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanArtists(ApplicationUser user, IEnumerable<Guid> artistIds, bool isReadOnly = false)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
var errors = new List<Exception>();
|
||||
foreach (var artistId in artistIds)
|
||||
{
|
||||
var result = await ScanArtist(user, artistId, isReadOnly);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Errors?.Any() ?? false)
|
||||
{
|
||||
errors.AddRange(result.Errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
await LogAndPublish($"** Completed! ScanArtists: Artist Count [{ artistIds.Count() }], Elapsed Time [{sw.Elapsed}]");
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanArtist(ApplicationUser user, Guid artistId, bool isReadOnly = false)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
@ -779,6 +693,32 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanArtists(ApplicationUser user, IEnumerable<Guid> artistIds, bool isReadOnly = false)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
var errors = new List<Exception>();
|
||||
foreach (var artistId in artistIds)
|
||||
{
|
||||
var result = await ScanArtist(user, artistId, isReadOnly);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Errors?.Any() ?? false)
|
||||
{
|
||||
errors.AddRange(result.Errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
await LogAndPublish($"** Completed! ScanArtists: Artist Count [{ artistIds.Count() }], Elapsed Time [{sw.Elapsed}]");
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanCollection(ApplicationUser user, Guid collectionId,
|
||||
bool isReadOnly = false, bool doPurgeFirst = false, bool doUpdateRanks = true)
|
||||
{
|
||||
|
@ -975,32 +915,6 @@ namespace Roadie.Api.Services
|
|||
return await ScanFolder(user, d, isReadOnly);
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanReleases(ApplicationUser user, IEnumerable<Guid> releaseIds, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
var errors = new List<Exception>();
|
||||
foreach (var releaseId in releaseIds)
|
||||
{
|
||||
var result = await ScanRelease(user, releaseId, isReadOnly, wasDoneForInvalidTrackPlay);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Errors?.Any() ?? false)
|
||||
{
|
||||
errors.AddRange(result.Errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
await LogAndPublish($"** Completed! ScanReleases: Release Count [{ releaseIds.Count() }], Elapsed Time [{sw.Elapsed}]");
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanRelease(ApplicationUser user, Guid releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
|
@ -1046,6 +960,92 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanReleases(ApplicationUser user, IEnumerable<Guid> releaseIds, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
var errors = new List<Exception>();
|
||||
foreach (var releaseId in releaseIds)
|
||||
{
|
||||
var result = await ScanRelease(user, releaseId, isReadOnly, wasDoneForInvalidTrackPlay);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Errors?.Any() ?? false)
|
||||
{
|
||||
errors.AddRange(result.Errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
await LogAndPublish($"** Completed! ScanReleases: Release Count [{ releaseIds.Count() }], Elapsed Time [{sw.Elapsed}]");
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdateInviteTokenUsed(Guid? tokenId)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
if (tokenId == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Invalid Invite TokenId [{tokenId}]");
|
||||
}
|
||||
var token = DbContext.InviteTokens.FirstOrDefault(x => x.RoadieId == tokenId);
|
||||
if (token == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Invite Token Not Found [{tokenId}]");
|
||||
}
|
||||
token.Status = Statuses.Complete;
|
||||
token.LastUpdated = DateTime.UtcNow;
|
||||
await DbContext.SaveChangesAsync();
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ValidateInviteToken(Guid? tokenId)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
if (tokenId == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Invalid Invite TokenId [{tokenId}]");
|
||||
}
|
||||
var token = DbContext.InviteTokens.FirstOrDefault(x => x.RoadieId == tokenId);
|
||||
if (token == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Invite Token Not Found [{tokenId}]");
|
||||
}
|
||||
if (token.ExpiresDate < DateTime.UtcNow || token.Status == Statuses.Expired)
|
||||
{
|
||||
token.Status = Statuses.Expired;
|
||||
token.LastUpdated = DateTime.UtcNow;
|
||||
await DbContext.SaveChangesAsync();
|
||||
return new OperationResult<bool>(true, $"Invite Token [{tokenId}] Expired [{ token.ExpiresDate }]");
|
||||
}
|
||||
if (token.Status == Statuses.Complete)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Invite Token [{tokenId}] Already Used");
|
||||
}
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
private void EventMessageLogger_Messages(object sender, EventMessage e) => Task.WaitAll(LogAndPublish(e.Message, e.Level));
|
||||
|
||||
private async Task LogAndPublish(string message, LogLevel level = LogLevel.Trace)
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Roadie.Library;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
|
@ -13,9 +12,6 @@ using Roadie.Library.Extensions;
|
|||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Imaging;
|
||||
using Roadie.Library.MetaData.Audio;
|
||||
using Roadie.Library.MetaData.FileName;
|
||||
using Roadie.Library.MetaData.ID3Tags;
|
||||
using Roadie.Library.MetaData.LastFm;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using Roadie.Library.Models.Releases;
|
||||
|
@ -30,7 +26,6 @@ using System.Linq;
|
|||
using System.Linq.Dynamic.Core;
|
||||
using System.Threading.Tasks;
|
||||
using data = Roadie.Library.Data;
|
||||
using mb = Roadie.Library.MetaData.MusicBrainz;
|
||||
|
||||
namespace Roadie.Api.Services
|
||||
{
|
||||
|
@ -45,20 +40,9 @@ namespace Roadie.Api.Services
|
|||
private ICollectionService CollectionService { get; }
|
||||
|
||||
private IFileDirectoryProcessorService FileDirectoryProcessorService { get; }
|
||||
private IFileNameHelper FileNameHelper { get; }
|
||||
|
||||
private IID3TagsHelper ID3TagsHelper { get; }
|
||||
|
||||
private ILabelLookupEngine LabelLookupEngine { get; }
|
||||
|
||||
private ILastFmHelper LastFmHelper { get; }
|
||||
|
||||
private mb.IMusicBrainzProvider MusicBrainzProvider { get; }
|
||||
|
||||
private IPlaylistService PlaylistService { get; }
|
||||
|
||||
private IReleaseLookupEngine ReleaseLookupEngine { get; }
|
||||
|
||||
private IReleaseService ReleaseService { get; }
|
||||
|
||||
public ArtistService(IRoadieSettings configuration,
|
||||
|
@ -72,13 +56,7 @@ namespace Roadie.Api.Services
|
|||
IBookmarkService bookmarkService,
|
||||
IReleaseService releaseService,
|
||||
IArtistLookupEngine artistLookupEngine,
|
||||
mb.IMusicBrainzProvider musicBrainzProvider,
|
||||
ILastFmHelper lastFmHelper,
|
||||
IFileNameHelper fileNameHelper,
|
||||
IID3TagsHelper id3tagsHelper,
|
||||
IAudioMetaDataHelper audioMetaDataHelper,
|
||||
IReleaseLookupEngine releaseLookupEngine,
|
||||
ILabelLookupEngine labelLookupEngine,
|
||||
IFileDirectoryProcessorService fileDirectoryProcessorService
|
||||
)
|
||||
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
|
||||
|
@ -86,18 +64,8 @@ namespace Roadie.Api.Services
|
|||
CollectionService = collectionService;
|
||||
PlaylistService = playlistService;
|
||||
BookmarkService = bookmarkService;
|
||||
|
||||
MusicBrainzProvider = musicBrainzProvider;
|
||||
LastFmHelper = lastFmHelper;
|
||||
FileNameHelper = fileNameHelper;
|
||||
ID3TagsHelper = id3tagsHelper;
|
||||
|
||||
ArtistLookupEngine = artistLookupEngine;
|
||||
LabelLookupEngine = labelLookupEngine;
|
||||
ReleaseLookupEngine = releaseLookupEngine;
|
||||
|
||||
AudioMetaDataHelper = audioMetaDataHelper;
|
||||
|
||||
ReleaseService = releaseService;
|
||||
FileDirectoryProcessorService = fileDirectoryProcessorService;
|
||||
}
|
||||
|
@ -238,7 +206,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
IQueryable<int> genreArtistIds = null;
|
||||
var isFilteredToGenre = false;
|
||||
if(request.FilterToGenreId.HasValue)
|
||||
if (request.FilterToGenreId.HasValue)
|
||||
{
|
||||
genreArtistIds = (from ag in DbContext.ArtistGenres
|
||||
join g in DbContext.Genres on ag.GenreId equals g.Id
|
||||
|
@ -275,7 +243,7 @@ namespace Roadie.Api.Services
|
|||
: null;
|
||||
|
||||
int[] randomArtistIds = null;
|
||||
if (doRandomize ??false)
|
||||
if (doRandomize ?? false)
|
||||
{
|
||||
var randomLimit = request.Limit ?? roadieUser?.RandomReleaseLimit ?? request.LimitValue;
|
||||
var userId = roadieUser?.Id ?? -1;
|
||||
|
@ -288,27 +256,26 @@ namespace Roadie.Api.Services
|
|||
AND {2} = 0)
|
||||
order BY RIGHT(HEX((1 << 24) * (1 + RAND())), 6)
|
||||
LIMIT 0, {0}";
|
||||
randomArtistIds = (from a in DbContext.Artists.FromSql(sql, randomLimit, userId, request.FilterFavoriteOnly ? "1" : "0")
|
||||
randomArtistIds = (from a in DbContext.Artists.FromSql(sql, randomLimit, userId, request.FilterFavoriteOnly ? "1" : "0")
|
||||
select a.Id).ToArray();
|
||||
rowCount = DbContext.Artists.Count();
|
||||
|
||||
}
|
||||
var result = (from a in DbContext.Artists
|
||||
where !onlyWithReleases || a.ReleaseCount > 0
|
||||
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 request.FilterValue == "" ||
|
||||
a.Name.Contains(request.FilterValue) ||
|
||||
where request.FilterValue == "" ||
|
||||
a.Name.Contains(request.FilterValue) ||
|
||||
a.SortName.Contains(request.FilterValue) ||
|
||||
a.RealName.Contains(request.FilterValue) ||
|
||||
a.AlternateNames.Contains(request.FilterValue) ||
|
||||
a.AlternateNames.Contains(normalizedFilterValue)
|
||||
where !isEqualFilter ||
|
||||
a.Name.Equals(request.FilterValue) ||
|
||||
a.AlternateNames.Contains(request.FilterValue) ||
|
||||
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(request.FilterValue) ||
|
||||
a.AlternateNames.Equals(normalizedFilterValue)
|
||||
where !request.FilterFavoriteOnly || favoriteArtistIds.Contains(a.Id)
|
||||
where request.FilterToLabelId == null || labelArtistIds.Contains(a.Id)
|
||||
|
@ -642,10 +609,10 @@ namespace Roadie.Api.Services
|
|||
return new OperationResult<bool>(true, $"Artist Not Found [{model.Id}]");
|
||||
}
|
||||
// If artist is being renamed, see if artist already exists with new model supplied name
|
||||
if(artist.Name.ToAlphanumericName() != model.Name.ToAlphanumericName())
|
||||
if (artist.Name.ToAlphanumericName() != model.Name.ToAlphanumericName())
|
||||
{
|
||||
var existingArtist = DbContext.Artists.FirstOrDefault(x => x.Name == model.Name);
|
||||
if(existingArtist != null)
|
||||
if (existingArtist != null)
|
||||
{
|
||||
return new OperationResult<bool>($"Artist already exists with name [{ model.Name }].");
|
||||
}
|
||||
|
@ -1240,7 +1207,7 @@ namespace Roadie.Api.Services
|
|||
if (r.IsSuccess)
|
||||
{
|
||||
result.PlaylistsWithArtistReleases = r.Rows.ToArray();
|
||||
}
|
||||
}
|
||||
tsw.Stop();
|
||||
timings.Add("playlists", tsw.ElapsedMilliseconds);
|
||||
}
|
||||
|
@ -1265,7 +1232,6 @@ namespace Roadie.Api.Services
|
|||
.ToArray()
|
||||
.Select(r => ReleaseList.FromDataRelease(r, r.Artist, HttpContext.BaseUrl, MakeArtistThumbnailImage(r.Artist.RoadieId), MakeReleaseThumbnailImage(r.RoadieId)));
|
||||
|
||||
|
||||
result.ArtistContributionReleases = result.ArtistContributionReleases.Any()
|
||||
? result.ArtistContributionReleases
|
||||
: null;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Roadie.Library;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
|
@ -84,7 +83,7 @@ namespace Roadie.Api.Services
|
|||
sw.Start();
|
||||
|
||||
var cacheKey = string.Format("urn:collection_by_id_operation:{0}:{1}", id, includes == null ? "0" : string.Join("|", includes));
|
||||
var result = await CacheManager.GetAsync(cacheKey, async () =>
|
||||
var result = await CacheManager.GetAsync(cacheKey, async () =>
|
||||
{
|
||||
return await CollectionByIdAction(id, includes);
|
||||
}, data.Artist.CacheRegionUrn(id));
|
||||
|
@ -179,7 +178,6 @@ namespace Roadie.Api.Services
|
|||
join a in DbContext.Artists on r.ArtistId equals a.Id
|
||||
where a.RoadieId == artistId
|
||||
select c).Distinct();
|
||||
|
||||
}
|
||||
else if (releaseId.HasValue)
|
||||
{
|
||||
|
@ -302,7 +300,7 @@ namespace Roadie.Api.Services
|
|||
var collectionImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
|
||||
if (collectionImage != null)
|
||||
{
|
||||
// Save unaltered collection image
|
||||
// Save unaltered collection image
|
||||
File.WriteAllBytes(collection.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(collectionImage));
|
||||
// Update Thumbnail
|
||||
collection.Thumbnail = ImageHelper.ResizeToThumbnail(collectionImage, Configuration);
|
||||
|
|
|
@ -37,11 +37,10 @@ namespace Roadie.Api.Services
|
|||
|
||||
private IAudioMetaDataHelper AudioMetaDataHelper { get; }
|
||||
|
||||
private IFileProcessor FileProcessor { get; }
|
||||
private IReleaseLookupEngine ReleaseLookupEngine { get; }
|
||||
private IReleaseService ReleaseService { get; }
|
||||
|
||||
private IFileProcessor FileProcessor { get; }
|
||||
|
||||
public FileDirectoryProcessorService(IRoadieSettings configuration,
|
||||
IHttpEncoder httpEncoder,
|
||||
IHttpContext httpContext,
|
||||
|
|
|
@ -2,12 +2,11 @@
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Roadie.Library;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.Extensions;
|
||||
using Roadie.Library.Encoding;
|
||||
using Roadie.Library.Extensions;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Imaging;
|
||||
using Roadie.Library.Models;
|
||||
|
@ -42,7 +41,7 @@ namespace Roadie.Api.Services
|
|||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
var cacheKey = string.Format("urn:genre_by_id_operation:{0}:{1}", id, includes == null ? "0" : string.Join("|", includes));
|
||||
var result = await CacheManager.GetAsync(cacheKey, async () =>
|
||||
var result = await CacheManager.GetAsync(cacheKey, async () =>
|
||||
{
|
||||
return await GenreByIdAction(id, includes);
|
||||
}, data.Genre.CacheRegionUrn(id));
|
||||
|
@ -83,7 +82,99 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public Task<Library.Models.Pagination.PagedResult<GenreList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
int? rowCount = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(request.Sort))
|
||||
{
|
||||
request.Sort = request.Sort.Replace("createdDate", "createdDateTime");
|
||||
request.Sort = request.Sort.Replace("lastUpdated", "lastUpdatedDateTime");
|
||||
}
|
||||
|
||||
int[] randomGenreIds = null;
|
||||
if (doRandomize ?? false)
|
||||
{
|
||||
var randomLimit = request.Limit ?? roadieUser?.RandomReleaseLimit ?? request.LimitValue;
|
||||
// This is MySQL specific but I can't figure out how else to get random without throwing EF local evaluate warnings.
|
||||
var sql = @"select g.id
|
||||
FROM `genre` g
|
||||
order BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
||||
LIMIT 0, {0}";
|
||||
randomGenreIds = (from l in DbContext.Genres.FromSql(sql, randomLimit)
|
||||
select l.Id).ToArray();
|
||||
rowCount = DbContext.Genres.Count();
|
||||
}
|
||||
|
||||
var result = from g in DbContext.Genres
|
||||
where randomGenreIds == null || randomGenreIds.Contains(g.Id)
|
||||
let releaseCount = (from rg in DbContext.ReleaseGenres
|
||||
where rg.GenreId == g.Id
|
||||
select rg.Id).Count()
|
||||
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)
|
||||
select new GenreList
|
||||
{
|
||||
DatabaseId = g.Id,
|
||||
Id = g.RoadieId,
|
||||
Genre = new DataToken
|
||||
{
|
||||
Text = g.Name,
|
||||
Value = g.RoadieId.ToString()
|
||||
},
|
||||
ReleaseCount = releaseCount,
|
||||
ArtistCount = artistCount,
|
||||
CreatedDate = g.CreatedDate,
|
||||
LastUpdated = g.LastUpdated,
|
||||
Thumbnail = MakeGenreThumbnailImage(g.RoadieId)
|
||||
};
|
||||
|
||||
GenreList[] rows;
|
||||
rowCount = rowCount ?? result.Count();
|
||||
if (doRandomize ?? false)
|
||||
{
|
||||
rows = result.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
var sortBy = string.IsNullOrEmpty(request.Sort)
|
||||
? request.OrderValue(new Dictionary<string, string> { { "Genre.Text", "ASC" } })
|
||||
: request.OrderValue();
|
||||
rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
return Task.FromResult(new Library.Models.Pagination.PagedResult<GenreList>
|
||||
{
|
||||
TotalCount = rowCount.Value,
|
||||
CurrentPage = request.PageValue,
|
||||
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Rows = rows
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Image>> SetGenreImageByUrl(User user, Guid id, string imageUrl)
|
||||
{
|
||||
return await SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Image>> UploadGenreImage(User user, Guid id, IFormFile file)
|
||||
{
|
||||
var bytes = new byte[0];
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
file.CopyTo(ms);
|
||||
bytes = ms.ToArray();
|
||||
}
|
||||
|
||||
return await SaveImageBytes(user, id, bytes);
|
||||
}
|
||||
|
||||
private Task<OperationResult<Genre>> GenreByIdAction(Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
|
@ -139,24 +230,6 @@ namespace Roadie.Api.Services
|
|||
});
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Image>> UploadGenreImage(User user, Guid id, IFormFile file)
|
||||
{
|
||||
var bytes = new byte[0];
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
file.CopyTo(ms);
|
||||
bytes = ms.ToArray();
|
||||
}
|
||||
|
||||
return await SaveImageBytes(user, id, bytes);
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Image>> SetGenreImageByUrl(User user, Guid id, string imageUrl)
|
||||
{
|
||||
return await SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
|
||||
}
|
||||
|
||||
|
||||
private async Task<OperationResult<Image>> SaveImageBytes(User user, Guid id, byte[] imageBytes)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
|
@ -170,7 +243,7 @@ namespace Roadie.Api.Services
|
|||
genre.Thumbnail = imageBytes;
|
||||
if (genre.Thumbnail != null)
|
||||
{
|
||||
// Save unaltered label image
|
||||
// Save unaltered label image
|
||||
File.WriteAllBytes(genre.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(imageBytes));
|
||||
genre.Thumbnail = ImageHelper.ResizeToThumbnail(genre.Thumbnail, Configuration);
|
||||
}
|
||||
|
@ -196,84 +269,5 @@ namespace Roadie.Api.Services
|
|||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public Task<Library.Models.Pagination.PagedResult<GenreList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
int? rowCount = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(request.Sort))
|
||||
{
|
||||
request.Sort = request.Sort.Replace("createdDate", "createdDateTime");
|
||||
request.Sort = request.Sort.Replace("lastUpdated", "lastUpdatedDateTime");
|
||||
}
|
||||
|
||||
int[] randomGenreIds = null;
|
||||
if (doRandomize ?? false)
|
||||
{
|
||||
var randomLimit = request.Limit ?? roadieUser?.RandomReleaseLimit ?? request.LimitValue;
|
||||
// This is MySQL specific but I can't figure out how else to get random without throwing EF local evaluate warnings.
|
||||
var sql = @"select g.id
|
||||
FROM `genre` g
|
||||
order BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
||||
LIMIT 0, {0}";
|
||||
randomGenreIds = (from l in DbContext.Genres.FromSql(sql, randomLimit)
|
||||
select l.Id).ToArray();
|
||||
rowCount = DbContext.Genres.Count();
|
||||
|
||||
}
|
||||
|
||||
var result = from g in DbContext.Genres
|
||||
where randomGenreIds == null || randomGenreIds.Contains(g.Id)
|
||||
let releaseCount = (from rg in DbContext.ReleaseGenres
|
||||
where rg.GenreId == g.Id
|
||||
select rg.Id).Count()
|
||||
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)
|
||||
select new GenreList
|
||||
{
|
||||
DatabaseId = g.Id,
|
||||
Id = g.RoadieId,
|
||||
Genre = new DataToken
|
||||
{
|
||||
Text = g.Name,
|
||||
Value = g.RoadieId.ToString()
|
||||
},
|
||||
ReleaseCount = releaseCount,
|
||||
ArtistCount = artistCount,
|
||||
CreatedDate = g.CreatedDate,
|
||||
LastUpdated = g.LastUpdated,
|
||||
Thumbnail = MakeGenreThumbnailImage(g.RoadieId)
|
||||
};
|
||||
|
||||
GenreList[] rows;
|
||||
rowCount = rowCount ?? result.Count();
|
||||
if (doRandomize ?? false)
|
||||
{
|
||||
rows = result.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
var sortBy = string.IsNullOrEmpty(request.Sort)
|
||||
? request.OrderValue(new Dictionary<string, string> { { "Genre.Text", "ASC" } })
|
||||
: request.OrderValue();
|
||||
rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
return Task.FromResult(new Library.Models.Pagination.PagedResult<GenreList>
|
||||
{
|
||||
TotalCount = rowCount.Value,
|
||||
CurrentPage = request.PageValue,
|
||||
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Rows = rows
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,18 +9,16 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface IAdminService
|
||||
{
|
||||
void PerformStartUpTasks();
|
||||
|
||||
Task<OperationResult<bool>> DeleteArtist(ApplicationUser user, Guid artistId);
|
||||
|
||||
Task<OperationResult<bool>> DeleteArtistReleases(ApplicationUser user, Guid artistId, bool doDeleteFiles = false);
|
||||
|
||||
Task<OperationResult<bool>> DeleteArtistSecondaryImage(ApplicationUser user, Guid artistId, int index);
|
||||
|
||||
Task<OperationResult<bool>> DeleteLabel(ApplicationUser user, Guid labelId);
|
||||
|
||||
Task<OperationResult<bool>> DeleteGenre(ApplicationUser user, Guid genreId);
|
||||
|
||||
Task<OperationResult<bool>> DeleteLabel(ApplicationUser user, Guid labelId);
|
||||
|
||||
Task<OperationResult<bool>> DeleteRelease(ApplicationUser user, Guid releaseId, bool? doDeleteFiles);
|
||||
|
||||
Task<OperationResult<bool>> DeleteReleaseSecondaryImage(ApplicationUser user, Guid releaseId, int index);
|
||||
|
@ -33,6 +31,8 @@ namespace Roadie.Api.Services
|
|||
|
||||
Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleases(ApplicationUser user);
|
||||
|
||||
void PerformStartUpTasks();
|
||||
|
||||
Task<OperationResult<bool>> ScanAllCollections(ApplicationUser user, bool isReadOnly = false, bool doPurgeFirst = false);
|
||||
|
||||
Task<OperationResult<bool>> ScanArtist(ApplicationUser user, Guid artistId, bool isReadOnly = false);
|
||||
|
@ -49,8 +49,8 @@ namespace Roadie.Api.Services
|
|||
|
||||
Task<OperationResult<bool>> ScanReleases(ApplicationUser user, IEnumerable<Guid> releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false);
|
||||
|
||||
Task<OperationResult<bool>> ValidateInviteToken(Guid? tokenId);
|
||||
|
||||
Task<OperationResult<bool>> UpdateInviteTokenUsed(Guid? tokenId);
|
||||
|
||||
Task<OperationResult<bool>> ValidateInviteToken(Guid? tokenId);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
using System.Collections.Generic;
|
||||
using Roadie.Library;
|
||||
using Roadie.Library.Identity;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Roadie.Library;
|
||||
using Roadie.Library.Identity;
|
||||
|
||||
namespace Roadie.Api.Services
|
||||
{
|
||||
|
|
|
@ -13,10 +13,13 @@ namespace Roadie.Api.Services
|
|||
public interface IGenreService
|
||||
{
|
||||
Task<OperationResult<Genre>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null);
|
||||
Task<OperationResult<bool>> Delete(ApplicationUser user, Guid id);
|
||||
Task<PagedResult<GenreList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false);
|
||||
Task<OperationResult<Image>> SetGenreImageByUrl(User user, Guid id, string imageUrl);
|
||||
Task<OperationResult<Image>> UploadGenreImage(User user, Guid id, IFormFile file);
|
||||
|
||||
Task<OperationResult<bool>> Delete(ApplicationUser user, Guid id);
|
||||
|
||||
Task<PagedResult<GenreList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false);
|
||||
|
||||
Task<OperationResult<Image>> SetGenreImageByUrl(User user, Guid id, string imageUrl);
|
||||
|
||||
Task<OperationResult<Image>> UploadGenreImage(User user, Guid id, IFormFile file);
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@
|
|||
using Roadie.Library;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.Users;
|
||||
using Roadie.Library.SearchEngines.Imaging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -26,10 +25,10 @@ namespace Roadie.Api.Services
|
|||
|
||||
Task<OperationResult<bool>> Delete(ApplicationUser user, Guid id);
|
||||
|
||||
Task<FileOperationResult<Image>> LabelImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<FileOperationResult<Image>> GenreImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<FileOperationResult<Image>> LabelImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<FileOperationResult<Image>> PlaylistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<FileOperationResult<Image>> ReleaseImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
|
|
@ -14,10 +14,10 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
Task<OperationResult<Label>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null);
|
||||
|
||||
Task<PagedResult<LabelList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false);
|
||||
|
||||
Task<OperationResult<bool>> Delete(ApplicationUser user, Guid id);
|
||||
|
||||
Task<PagedResult<LabelList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false);
|
||||
|
||||
Task<OperationResult<bool>> MergeLabelsIntoLabel(ApplicationUser user, Guid intoLabelId, IEnumerable<Guid> labelIdsToMerge);
|
||||
|
||||
Task<OperationResult<Image>> SetLabelImageByUrl(User user, Guid id, string imageUrl);
|
||||
|
|
|
@ -7,12 +7,9 @@ using Roadie.Library.Caching;
|
|||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.Encoding;
|
||||
using Roadie.Library.Enums;
|
||||
using Roadie.Library.Extensions;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Imaging;
|
||||
using Roadie.Library.MetaData.Audio;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.Users;
|
||||
using Roadie.Library.SearchEngines.Imaging;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
|
@ -27,14 +24,12 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public class ImageService : ServiceBase, IImageService
|
||||
{
|
||||
public string Referrer { get; set; }
|
||||
public string RequestIp { get; set; }
|
||||
private IDefaultNotFoundImages DefaultNotFoundImages { get; }
|
||||
|
||||
private IImageSearchManager ImageSearchManager { get; }
|
||||
|
||||
public string Referrer { get; set; }
|
||||
|
||||
public string RequestIp { get; set; }
|
||||
|
||||
public ImageService(IRoadieSettings configuration,
|
||||
IHttpEncoder httpEncoder,
|
||||
IHttpContext httpContext,
|
||||
|
@ -116,6 +111,16 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<Image>> GenreImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return await GetImageFileOperation("GenreThumbnail",
|
||||
data.Label.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => { return await GenreImageAction(id, etag); },
|
||||
etag);
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<Image>> LabelImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
|
@ -128,17 +133,6 @@ namespace Roadie.Api.Services
|
|||
etag);
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<Image>> GenreImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return await GetImageFileOperation("GenreThumbnail",
|
||||
data.Label.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => { return await GenreImageAction(id, etag); },
|
||||
etag);
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<Image>> PlaylistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return await GetImageFileOperation("PlaylistThumbnail",
|
||||
|
@ -196,7 +190,6 @@ namespace Roadie.Api.Services
|
|||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<Image>> TrackImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
|
@ -387,6 +380,47 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
private Task<FileOperationResult<Image>> GenreImageAction(Guid id, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var genre = GetGenre(id);
|
||||
if (genre == null)
|
||||
{
|
||||
return Task.FromResult(new FileOperationResult<Image>(true, string.Format("Genre Not Found [{0}]", id)));
|
||||
}
|
||||
var image = new data.Image
|
||||
{
|
||||
Bytes = genre.Thumbnail,
|
||||
CreatedDate = genre.CreatedDate,
|
||||
LastUpdated = genre.LastUpdated
|
||||
};
|
||||
var genreImageFilename = genre.PathToImage(Configuration);
|
||||
try
|
||||
{
|
||||
if (File.Exists(genreImageFilename))
|
||||
{
|
||||
image.Bytes = File.ReadAllBytes(genreImageFilename);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, $"Error Reading Image File [{genreImageFilename}]");
|
||||
}
|
||||
if (genre.Thumbnail == null || !genre.Thumbnail.Any())
|
||||
{
|
||||
image = DefaultNotFoundImages.Genre;
|
||||
}
|
||||
return Task.FromResult(GenerateFileOperationResult(id, image, etag));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Error fetching Label Thumbnail [{id}]", ex);
|
||||
}
|
||||
|
||||
return Task.FromResult(new FileOperationResult<Image>(OperationMessages.ErrorOccured));
|
||||
}
|
||||
|
||||
private async Task<FileOperationResult<Image>> GetImageFileOperation(string type, string regionUrn, Guid id, int? width, int? height, Func<Task<FileOperationResult<Image>>> action, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
try
|
||||
|
@ -475,7 +509,7 @@ namespace Roadie.Api.Services
|
|||
var labelImageFilename = label.PathToImage(Configuration);
|
||||
try
|
||||
{
|
||||
if(File.Exists(labelImageFilename))
|
||||
if (File.Exists(labelImageFilename))
|
||||
{
|
||||
image.Bytes = File.ReadAllBytes(labelImageFilename);
|
||||
}
|
||||
|
@ -498,47 +532,6 @@ namespace Roadie.Api.Services
|
|||
return Task.FromResult(new FileOperationResult<Image>(OperationMessages.ErrorOccured));
|
||||
}
|
||||
|
||||
private Task<FileOperationResult<Image>> GenreImageAction(Guid id, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var genre = GetGenre(id);
|
||||
if (genre == null)
|
||||
{
|
||||
return Task.FromResult(new FileOperationResult<Image>(true, string.Format("Genre Not Found [{0}]", id)));
|
||||
}
|
||||
var image = new data.Image
|
||||
{
|
||||
Bytes = genre.Thumbnail,
|
||||
CreatedDate = genre.CreatedDate,
|
||||
LastUpdated = genre.LastUpdated
|
||||
};
|
||||
var genreImageFilename = genre.PathToImage(Configuration);
|
||||
try
|
||||
{
|
||||
if (File.Exists(genreImageFilename))
|
||||
{
|
||||
image.Bytes = File.ReadAllBytes(genreImageFilename);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, $"Error Reading Image File [{genreImageFilename}]");
|
||||
}
|
||||
if (genre.Thumbnail == null || !genre.Thumbnail.Any())
|
||||
{
|
||||
image = DefaultNotFoundImages.Genre;
|
||||
}
|
||||
return Task.FromResult(GenerateFileOperationResult(id, image, etag));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Error fetching Label Thumbnail [{id}]", ex);
|
||||
}
|
||||
|
||||
return Task.FromResult(new FileOperationResult<Image>(OperationMessages.ErrorOccured));
|
||||
}
|
||||
|
||||
private Task<FileOperationResult<Image>> PlaylistImageAction(Guid id, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -44,32 +44,6 @@ namespace Roadie.Api.Services
|
|||
BookmarkService = bookmarkService;
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> Delete(ApplicationUser user, Guid id)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (label == null) return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", id));
|
||||
DbContext.Labels.Remove(label);
|
||||
await DbContext.SaveChangesAsync();
|
||||
|
||||
var labelImageFilename = label.PathToImage(Configuration);
|
||||
if(File.Exists(labelImageFilename))
|
||||
{
|
||||
File.Delete(labelImageFilename);
|
||||
}
|
||||
|
||||
Logger.LogWarning("User `{0}` deleted Label `{1}]`", user, label);
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
sw.Stop();
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Label>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
@ -112,6 +86,32 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> Delete(ApplicationUser user, Guid id)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (label == null) return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", id));
|
||||
DbContext.Labels.Remove(label);
|
||||
await DbContext.SaveChangesAsync();
|
||||
|
||||
var labelImageFilename = label.PathToImage(Configuration);
|
||||
if (File.Exists(labelImageFilename))
|
||||
{
|
||||
File.Delete(labelImageFilename);
|
||||
}
|
||||
|
||||
Logger.LogWarning("User `{0}` deleted Label `{1}]`", user, label);
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
sw.Stop();
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public Task<Library.Models.Pagination.PagedResult<LabelList>> List(User roadieUser, PagedRequest request,
|
||||
bool? doRandomize = false)
|
||||
{
|
||||
|
@ -135,19 +135,18 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
var randomLimit = request.Limit ?? roadieUser?.RandomReleaseLimit ?? request.LimitValue;
|
||||
// This is MySQL specific but I can't figure out how else to get random without throwing EF local evaluate warnings.
|
||||
var sql = @"select l.id
|
||||
var sql = @"select l.id
|
||||
FROM `label` l
|
||||
order BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
||||
LIMIT 0, {0}";
|
||||
randomLabelIds = (from l in DbContext.Labels.FromSql(sql, randomLimit)
|
||||
select l.Id).ToArray();
|
||||
rowCount = DbContext.Labels.Count();
|
||||
|
||||
}
|
||||
|
||||
var result = from l in DbContext.Labels
|
||||
where randomLabelIds == null || randomLabelIds.Contains(l.Id)
|
||||
where request.FilterValue == "" || (
|
||||
where request.FilterValue == "" || (
|
||||
l.Name.Contains(request.FilterValue) ||
|
||||
l.SortName.Contains(request.FilterValue) ||
|
||||
l.AlternateNames.Contains(request.FilterValue) ||
|
||||
|
@ -317,7 +316,7 @@ namespace Roadie.Api.Services
|
|||
var labelImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
|
||||
if (labelImage != null)
|
||||
{
|
||||
// Save unaltered label image
|
||||
// Save unaltered label image
|
||||
File.WriteAllBytes(label.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(labelImage));
|
||||
label.Thumbnail = ImageHelper.ResizeToThumbnail(labelImage, Configuration);
|
||||
}
|
||||
|
@ -379,7 +378,7 @@ namespace Roadie.Api.Services
|
|||
result.Tags = label.Tags;
|
||||
result.URLs = label.URLs;
|
||||
result.Thumbnail = MakeLabelThumbnailImage(label.RoadieId);
|
||||
result.MediumThumbnail = MakeThumbnailImage(id, "label", Configuration.MediumImageSize.Width,Configuration.MediumImageSize.Height);
|
||||
result.MediumThumbnail = MakeThumbnailImage(id, "label", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
|
||||
tsw.Stop();
|
||||
timings.Add("adapt", tsw.ElapsedMilliseconds);
|
||||
if (includes != null && includes.Any())
|
||||
|
@ -466,7 +465,7 @@ namespace Roadie.Api.Services
|
|||
label.Thumbnail = imageBytes;
|
||||
if (label.Thumbnail != null)
|
||||
{
|
||||
// Save unaltered label image
|
||||
// Save unaltered label image
|
||||
File.WriteAllBytes(label.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(imageBytes));
|
||||
label.Thumbnail = ImageHelper.ResizeToThumbnail(label.Thumbnail, Configuration);
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ namespace Roadie.Api.Services
|
|||
sw.Start();
|
||||
var cacheKey = string.Format("urn:playlist_by_id_operation:{0}:{1}", id,
|
||||
includes == null ? "0" : string.Join("|", includes));
|
||||
var result = await CacheManager.GetAsync(cacheKey, async () =>
|
||||
var result = await CacheManager.GetAsync(cacheKey, async () =>
|
||||
{
|
||||
return await PlaylistByIdAction(id, includes);
|
||||
}, data.Artist.CacheRegionUrn(id));
|
||||
|
@ -351,7 +351,7 @@ namespace Roadie.Api.Services
|
|||
var playlistImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
|
||||
if (playlistImage != null)
|
||||
{
|
||||
// Save unaltered playlist image
|
||||
// Save unaltered playlist image
|
||||
File.WriteAllBytes(playlist.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(playlistImage));
|
||||
// Update thumbnail
|
||||
playlist.Thumbnail = ImageHelper.ResizeToThumbnail(playlistImage, Configuration);
|
||||
|
|
|
@ -12,10 +12,6 @@ using Roadie.Library.Extensions;
|
|||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Imaging;
|
||||
using Roadie.Library.MetaData.Audio;
|
||||
using Roadie.Library.MetaData.FileName;
|
||||
using Roadie.Library.MetaData.ID3Tags;
|
||||
using Roadie.Library.MetaData.LastFm;
|
||||
using Roadie.Library.MetaData.MusicBrainz;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.Collections;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
|
@ -48,53 +44,24 @@ namespace Roadie.Api.Services
|
|||
|
||||
private IBookmarkService BookmarkService { get; }
|
||||
|
||||
private ICollectionService CollectionService { get; }
|
||||
|
||||
private IFileNameHelper FileNameHelper { get; }
|
||||
|
||||
private IID3TagsHelper ID3TagsHelper { get; }
|
||||
|
||||
private ILabelLookupEngine LabelLookupEngine { get; }
|
||||
|
||||
private ILastFmHelper LastFmHelper { get; }
|
||||
|
||||
private IMusicBrainzProvider MusicBrainzProvider { get; }
|
||||
|
||||
private IPlaylistService PlaylistService { get; }
|
||||
|
||||
private IReleaseLookupEngine ReleaseLookupEngine { get; }
|
||||
|
||||
public ReleaseService(IRoadieSettings configuration,
|
||||
IHttpEncoder httpEncoder,
|
||||
IHttpContext httpContext,
|
||||
data.IRoadieDbContext dbContext,
|
||||
ICacheManager cacheManager,
|
||||
ICollectionService collectionService,
|
||||
IPlaylistService playlistService,
|
||||
ILogger<ReleaseService> logger,
|
||||
IBookmarkService bookmarkService,
|
||||
IArtistLookupEngine artistLookupEngine,
|
||||
IReleaseLookupEngine releaseLookupEngine,
|
||||
IMusicBrainzProvider musicBrainzProvider,
|
||||
ILastFmHelper lastFmHelper,
|
||||
IFileNameHelper fileNameHelper,
|
||||
IID3TagsHelper id3tagsHelper,
|
||||
IAudioMetaDataHelper audioMetaDataHelper,
|
||||
ILabelLookupEngine labelLookupEngine)
|
||||
IAudioMetaDataHelper audioMetaDataHelper
|
||||
)
|
||||
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
|
||||
{
|
||||
CollectionService = collectionService;
|
||||
PlaylistService = playlistService;
|
||||
BookmarkService = bookmarkService;
|
||||
|
||||
MusicBrainzProvider = musicBrainzProvider;
|
||||
LastFmHelper = lastFmHelper;
|
||||
FileNameHelper = fileNameHelper;
|
||||
ID3TagsHelper = id3tagsHelper;
|
||||
|
||||
ArtistLookupEngine = artistLookupEngine;
|
||||
LabelLookupEngine = labelLookupEngine;
|
||||
ReleaseLookupEngine = releaseLookupEngine;
|
||||
AudioMetaDataHelper = audioMetaDataHelper;
|
||||
}
|
||||
|
||||
|
@ -1688,7 +1655,7 @@ namespace Roadie.Api.Services
|
|||
release.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
await CheckAndChangeReleaseTitle(release, originalReleaseFolder);
|
||||
// Update release ID3 Tags
|
||||
// Update release ID3 Tags
|
||||
foreach (var mp3 in Directory.GetFiles(releaseFolder, "*.mp3", SearchOption.AllDirectories))
|
||||
{
|
||||
var trackFileInfo = new FileInfo(mp3);
|
||||
|
@ -1697,7 +1664,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
audioMetaData.Year = release.ReleaseYear;
|
||||
audioMetaData.Release = release.Title;
|
||||
if(artist != null)
|
||||
if (artist != null)
|
||||
{
|
||||
audioMetaData.Artist = artist.Name;
|
||||
}
|
||||
|
|
|
@ -22,18 +22,23 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public static string TrackTokenSalt = "B0246908-FBD6-4E12-A96C-AF5B086115B3";
|
||||
|
||||
private static readonly Lazy<Hashids> hashIds = new Lazy<Hashids>(() =>
|
||||
{
|
||||
return new Hashids(TrackTokenSalt);
|
||||
});
|
||||
|
||||
protected readonly ICacheManager _cacheManager;
|
||||
|
||||
protected readonly IRoadieSettings _configuration;
|
||||
|
||||
protected readonly data.IRoadieDbContext _dbContext;
|
||||
|
||||
protected readonly IHttpContext _httpContext;
|
||||
|
||||
protected readonly IHttpEncoder _httpEncoder;
|
||||
|
||||
protected readonly ILogger _logger;
|
||||
|
||||
private static readonly Lazy<Hashids> hashIds = new Lazy<Hashids>(() =>
|
||||
{
|
||||
return new Hashids(TrackTokenSalt);
|
||||
});
|
||||
|
||||
protected ICacheManager CacheManager => _cacheManager;
|
||||
|
||||
protected IRoadieSettings Configuration => _configuration;
|
||||
|
@ -66,6 +71,11 @@ namespace Roadie.Api.Services
|
|||
return TrackPlayToken(user, trackRoadieId).Equals(token);
|
||||
}
|
||||
|
||||
public static string MakeTrackPlayUrl(ApplicationUser user, string baseUrl, int trackId, Guid trackRoadieId)
|
||||
{
|
||||
return $"{baseUrl}/play/track/{user.Id}/{TrackPlayToken(user, trackRoadieId)}/{trackRoadieId}.mp3";
|
||||
}
|
||||
|
||||
public static string TrackPlayToken(ApplicationUser user, Guid trackId)
|
||||
{
|
||||
var trackIdPart = BitConverter.ToInt32(trackId.ToByteArray(), 6);
|
||||
|
@ -126,15 +136,6 @@ namespace Roadie.Api.Services
|
|||
}, data.Collection.CacheRegionUrn(id));
|
||||
}
|
||||
|
||||
protected data.Label GetLabel(Guid id)
|
||||
{
|
||||
return CacheManager.Get(data.Label.CacheUrn(id), () =>
|
||||
{
|
||||
return DbContext.Labels
|
||||
.FirstOrDefault(x => x.RoadieId == id);
|
||||
}, data.Label.CacheRegionUrn(id));
|
||||
}
|
||||
|
||||
protected data.Genre GetGenre(Guid id)
|
||||
{
|
||||
return CacheManager.Get(data.Genre.CacheUrn(id), () =>
|
||||
|
@ -144,6 +145,15 @@ namespace Roadie.Api.Services
|
|||
}, data.Genre.CacheRegionUrn(id));
|
||||
}
|
||||
|
||||
protected data.Label GetLabel(Guid id)
|
||||
{
|
||||
return CacheManager.Get(data.Label.CacheUrn(id), () =>
|
||||
{
|
||||
return DbContext.Labels
|
||||
.FirstOrDefault(x => x.RoadieId == id);
|
||||
}, data.Label.CacheRegionUrn(id));
|
||||
}
|
||||
|
||||
protected data.Playlist GetPlaylist(Guid id)
|
||||
{
|
||||
return CacheManager.Get(data.Playlist.CacheUrn(id), () =>
|
||||
|
@ -245,8 +255,13 @@ namespace Roadie.Api.Services
|
|||
$"{HttpContext.ImageBaseUrl}/release-secondary/{id}/{imageId}/{Configuration.SmallImageSize.Width}/{Configuration.SmallImageSize.Height}");
|
||||
}
|
||||
|
||||
protected Image MakeGenreThumbnailImage(Guid id)
|
||||
{
|
||||
return MakeThumbnailImage(id, "genre");
|
||||
}
|
||||
|
||||
protected Image MakeImage(Guid id, int width = 200, int height = 200, string caption = null,
|
||||
bool includeCachebuster = false)
|
||||
bool includeCachebuster = false)
|
||||
{
|
||||
return new Image(
|
||||
$"{HttpContext.ImageBaseUrl}/{id}/{width}/{height}/{(includeCachebuster ? DateTime.UtcNow.Ticks.ToString() : string.Empty)}",
|
||||
|
@ -264,11 +279,6 @@ namespace Roadie.Api.Services
|
|||
return MakeThumbnailImage(id, "label");
|
||||
}
|
||||
|
||||
protected Image MakeGenreThumbnailImage(Guid id)
|
||||
{
|
||||
return MakeThumbnailImage(id, "genre");
|
||||
}
|
||||
|
||||
protected string MakeLastFmUrl(string artistName, string releaseTitle)
|
||||
{
|
||||
return "http://www.last.fm/music/" + HttpEncoder.UrlEncode($"{artistName}/{releaseTitle}");
|
||||
|
@ -289,11 +299,6 @@ namespace Roadie.Api.Services
|
|||
return MakeThumbnailImage(id, "release");
|
||||
}
|
||||
|
||||
public static string MakeTrackPlayUrl(ApplicationUser user, string baseUrl, int trackId, Guid trackRoadieId)
|
||||
{
|
||||
return $"{baseUrl}/play/track/{user.Id}/{TrackPlayToken(user, trackRoadieId)}/{trackRoadieId}.mp3";
|
||||
}
|
||||
|
||||
protected Image MakeTrackThumbnailImage(Guid id)
|
||||
{
|
||||
return MakeThumbnailImage(id, "track");
|
||||
|
@ -535,7 +540,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
protected async Task<OperationResult<bool>> ToggleReleaseDisliked(Guid releaseId, ApplicationUser user, bool isDisliked)
|
||||
protected async Task<OperationResult<bool>> ToggleReleaseDisliked(Guid releaseId, ApplicationUser user, bool isDisliked)
|
||||
{
|
||||
var release = DbContext.Releases
|
||||
.Include(x => x.Artist)
|
||||
|
@ -549,7 +554,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
return new OperationResult<bool>(true, $"Invalid Release Id [{releaseId}]");
|
||||
}
|
||||
var userRelease = DbContext.UserReleases.FirstOrDefault(x => x.ReleaseId == release.Id && x.UserId == user.Id);
|
||||
var userRelease = DbContext.UserReleases.FirstOrDefault(x => x.ReleaseId == release.Id && x.UserId == user.Id);
|
||||
if (userRelease == null)
|
||||
{
|
||||
userRelease = new data.UserRelease
|
||||
|
@ -717,13 +722,13 @@ namespace Roadie.Api.Services
|
|||
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == artistId);
|
||||
if (artist != null)
|
||||
{
|
||||
artist.ReleaseCount = DbContext.Releases.Where(x => x.ArtistId == artistId).Count();
|
||||
artist.ReleaseCount = DbContext.Releases.Where(x => x.ArtistId == artistId).Count();
|
||||
artist.TrackCount = (from r in DbContext.Releases
|
||||
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
||||
join tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
|
||||
where tr.ArtistId == artistId || r.ArtistId == artistId
|
||||
select tr).Count();
|
||||
|
||||
|
||||
artist.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
CacheManager.ClearRegion(artist.CacheRegion);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using MySql.Data.MySqlClient;
|
||||
using Roadie.Library;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
|
|
|
@ -372,9 +372,9 @@ namespace Roadie.Api.Services
|
|||
/// <summary>
|
||||
/// Deletes a saved playlist.
|
||||
/// </summary>
|
||||
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> DeletePlaylist(subsonic.Request request,User roadieUser)
|
||||
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> DeletePlaylist(subsonic.Request request, User roadieUser)
|
||||
{
|
||||
//request.PlaylistId.Value
|
||||
//request.PlaylistId.Value
|
||||
|
||||
var deleteResult = await PlaylistService.DeletePlaylist(roadieUser, request.PlaylistId.Value);
|
||||
if (deleteResult == null || deleteResult.IsNotFoundResult)
|
||||
|
@ -2221,7 +2221,7 @@ namespace Roadie.Api.Services
|
|||
private subsonic.Child SubsonicChildForTrack(TrackList t)
|
||||
{
|
||||
var userRating = t.UserRating?.Rating ?? 0;
|
||||
if(userRating > 0)
|
||||
if (userRating > 0)
|
||||
{
|
||||
// This is done as many subsonic apps think rating "1" is don't play song, versus a minimum indication of like as intended for Roadie.
|
||||
// To disable this set the configuration SubsonicRatingBoost to 0
|
||||
|
|
|
@ -37,8 +37,8 @@ namespace Roadie.Api.Services
|
|||
|
||||
private IBookmarkService BookmarkService { get; }
|
||||
|
||||
public TrackService(IRoadieSettings configuration, IHttpEncoder httpEncoder,IHttpContext httpContext,
|
||||
data.IRoadieDbContext dbContext, ICacheManager cacheManager,ILogger<TrackService> logger,
|
||||
public TrackService(IRoadieSettings configuration, IHttpEncoder httpEncoder, IHttpContext httpContext,
|
||||
data.IRoadieDbContext dbContext, ICacheManager cacheManager, ILogger<TrackService> logger,
|
||||
IBookmarkService bookmarkService, IAdminService adminService, IAudioMetaDataHelper audioMetaDataHelper)
|
||||
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
|
||||
{
|
||||
|
@ -112,14 +112,13 @@ namespace Roadie.Api.Services
|
|||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
var cacheKey = string.Format("urn:track_by_id_operation:{0}:{1}", id, includes == null ? "0" : string.Join("|", includes));
|
||||
var result = await CacheManager.GetAsync(cacheKey, async () =>
|
||||
var result = await CacheManager.GetAsync(cacheKey, async () =>
|
||||
{
|
||||
tsw.Restart();
|
||||
var rr = await TrackByIdAction(id, includes);
|
||||
tsw.Stop();
|
||||
timings.Add("TrackByIdAction", tsw.ElapsedMilliseconds);
|
||||
return rr;
|
||||
|
||||
}, data.Track.CacheRegionUrn(id));
|
||||
if (result?.Data != null && roadieUser != null)
|
||||
{
|
||||
|
@ -162,7 +161,6 @@ namespace Roadie.Api.Services
|
|||
tsw.Stop();
|
||||
timings.Add("userTracks", tsw.ElapsedMilliseconds);
|
||||
|
||||
|
||||
if (result.Data.Comments.Any())
|
||||
{
|
||||
tsw.Restart();
|
||||
|
@ -311,28 +309,28 @@ namespace Roadie.Api.Services
|
|||
request.FilterFavoriteOnly = false;
|
||||
}
|
||||
randomTrackIds = (from t in DbContext.Tracks
|
||||
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join r in DbContext.Releases on rm.ReleaseId equals r.Id
|
||||
join a in DbContext.Artists on r.ArtistId equals a.Id
|
||||
where !request.FilterRatedOnly || request.FilterRatedOnly && t.Rating > 0
|
||||
where !dislikedArtistIds.Contains(r.ArtistId)
|
||||
where !dislikedArtistIds.Contains(t.ArtistId ?? 0)
|
||||
where !dislikedReleaseIds.Contains(r.Id)
|
||||
where !dislikedTrackIds.Contains(t.Id)
|
||||
where favoritedTrackIds == null || favoritedTrackIds.Contains(t.Id)
|
||||
where t.Hash != null
|
||||
select new TrackList
|
||||
{
|
||||
DatabaseId = t.Id,
|
||||
Artist = new ArtistList
|
||||
{
|
||||
Artist = new DataToken { Value = a.RoadieId.ToString(), Text = a.Name }
|
||||
},
|
||||
Release = new ReleaseList
|
||||
{
|
||||
Release = new DataToken { Value = r.RoadieId.ToString(), Text = r.Title }
|
||||
}
|
||||
})
|
||||
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join r in DbContext.Releases on rm.ReleaseId equals r.Id
|
||||
join a in DbContext.Artists on r.ArtistId equals a.Id
|
||||
where !request.FilterRatedOnly || request.FilterRatedOnly && t.Rating > 0
|
||||
where !dislikedArtistIds.Contains(r.ArtistId)
|
||||
where !dislikedArtistIds.Contains(t.ArtistId ?? 0)
|
||||
where !dislikedReleaseIds.Contains(r.Id)
|
||||
where !dislikedTrackIds.Contains(t.Id)
|
||||
where favoritedTrackIds == null || favoritedTrackIds.Contains(t.Id)
|
||||
where t.Hash != null
|
||||
select new TrackList
|
||||
{
|
||||
DatabaseId = t.Id,
|
||||
Artist = new ArtistList
|
||||
{
|
||||
Artist = new DataToken { Value = a.RoadieId.ToString(), Text = a.Name }
|
||||
},
|
||||
Release = new ReleaseList
|
||||
{
|
||||
Release = new DataToken { Value = r.RoadieId.ToString(), Text = r.Title }
|
||||
}
|
||||
})
|
||||
.OrderBy(x => x.Artist.RandomSortId)
|
||||
.ThenBy(x => x.RandomSortId)
|
||||
.ThenBy(x => x.RandomSortId)
|
||||
|
@ -539,7 +537,7 @@ namespace Roadie.Api.Services
|
|||
if (request.Action == User.ActionKeyUserRated)
|
||||
{
|
||||
sortBy = string.IsNullOrEmpty(request.Sort)
|
||||
? request.OrderValue(new Dictionary<string, string>{{"UserTrack.Rating", "DESC"}, {"MediaNumber", "ASC"}, {"TrackNumber", "ASC"}})
|
||||
? request.OrderValue(new Dictionary<string, string> { { "UserTrack.Rating", "DESC" }, { "MediaNumber", "ASC" }, { "TrackNumber", "ASC" } })
|
||||
: request.OrderValue();
|
||||
}
|
||||
else
|
||||
|
@ -557,7 +555,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
}
|
||||
|
||||
if(doRandomize ?? false)
|
||||
if (doRandomize ?? false)
|
||||
{
|
||||
rows = TrackList.Shuffle(result).ToArray();
|
||||
}
|
||||
|
@ -670,7 +668,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "Error In List, Request [{0}], User [{1}]", JsonConvert.SerializeObject(request),roadieUser);
|
||||
Logger.LogError(ex, "Error In List, Request [{0}], User [{1}]", JsonConvert.SerializeObject(request), roadieUser);
|
||||
return Task.FromResult(new Library.Models.Pagination.PagedResult<TrackList>
|
||||
{
|
||||
Message = "An Error has occured"
|
||||
|
@ -813,7 +811,7 @@ namespace Roadie.Api.Services
|
|||
info.CacheControl = "no-store, must-revalidate, no-cache, max-age=0";
|
||||
info.Pragma = "no-cache";
|
||||
info.Expires = "Mon, 01 Jan 1990 00:00:00 GMT";
|
||||
}
|
||||
}
|
||||
var bytesToRead = (int)(endBytes - beginBytes) + 1;
|
||||
var trackBytes = new byte[bytesToRead];
|
||||
using (var fs = trackFileInfo.OpenRead())
|
||||
|
@ -857,7 +855,7 @@ namespace Roadie.Api.Services
|
|||
try
|
||||
{
|
||||
var originalTitle = track.Title;
|
||||
var originalTrackNumber = track.TrackNumber;
|
||||
var originalTrackNumber = track.TrackNumber;
|
||||
var originalFilename = track.PathToTrack(Configuration);
|
||||
var now = DateTime.UtcNow;
|
||||
track.IsLocked = model.IsLocked;
|
||||
|
@ -906,13 +904,13 @@ namespace Roadie.Api.Services
|
|||
|
||||
// See if Title was changed if so then modify DB Filename and rename track
|
||||
var shouldFileNameBeUpdated = originalTitle != track.Title || originalTrackNumber != track.TrackNumber;
|
||||
if(shouldFileNameBeUpdated)
|
||||
if (shouldFileNameBeUpdated)
|
||||
{
|
||||
track.FileName = FolderPathHelper.TrackFileName(Configuration, track.Title, track.TrackNumber, track.ReleaseMedia.MediaNumber, track.ReleaseMedia.TrackCount);
|
||||
File.Move(originalFilename, track.PathToTrack(Configuration));
|
||||
}
|
||||
track.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync();
|
||||
|
||||
var trackFileInfo = new FileInfo(track.PathToTrack(Configuration));
|
||||
var audioMetaData = await AudioMetaDataHelper.GetInfo(trackFileInfo);
|
||||
|
|
|
@ -53,9 +53,9 @@ namespace Roadie.Api.Services
|
|||
|
||||
public async Task<OperationResult<User>> ById(User user, Guid id, IEnumerable<string> includes, bool isAccountSettingsEdit = false)
|
||||
{
|
||||
if(isAccountSettingsEdit)
|
||||
if (isAccountSettingsEdit)
|
||||
{
|
||||
if(user.UserId != id && !user.IsAdmin)
|
||||
if (user.UserId != id && !user.IsAdmin)
|
||||
{
|
||||
var r = new OperationResult<User>("Access Denied");
|
||||
r.IsAccessDeniedResult = true;
|
||||
|
@ -74,9 +74,9 @@ namespace Roadie.Api.Services
|
|||
if (result?.Data != null)
|
||||
{
|
||||
result.Data.Avatar = MakeUserThumbnailImage(id);
|
||||
if(!isAccountSettingsEdit)
|
||||
if (!isAccountSettingsEdit)
|
||||
{
|
||||
result.Data.ApiToken = null;
|
||||
result.Data.ApiToken = null;
|
||||
result.Data.ConcurrencyStamp = null;
|
||||
}
|
||||
}
|
||||
|
@ -502,11 +502,11 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
imageData = ImageHelper.ConvertToGifFormat(imageData);
|
||||
|
||||
// Save unaltered user image
|
||||
// Save unaltered user image
|
||||
File.WriteAllBytes(user.PathToImage(Configuration), imageData);
|
||||
// Update thumbnail
|
||||
user.Avatar = ImageHelper.ResizeImage(imageData, Configuration.ThumbnailImageSize.Width, Configuration.ThumbnailImageSize.Height);
|
||||
if(user.Avatar.Length >= ImageHelper.MaximumThumbnailByteSize)
|
||||
if (user.Avatar.Length >= ImageHelper.MaximumThumbnailByteSize)
|
||||
{
|
||||
user.Avatar = null;
|
||||
}
|
||||
|
@ -752,7 +752,7 @@ namespace Roadie.Api.Services
|
|||
RatedTracks = userTracks.Where(x => x.Rating > 0).Count(),
|
||||
PlayedTracks = userTracks.Where(x => x.PlayedCount.HasValue).Select(x => x.PlayedCount).Sum(),
|
||||
FavoritedTracks = userTracks.Where(x => x.IsFavorite ?? false).Count(),
|
||||
DislikedTracks = userTracks.Where(x => x.IsDisliked ?? false).Count()
|
||||
DislikedTracks = userTracks.Where(x => x.IsDisliked ?? false).Count()
|
||||
};
|
||||
tsw.Stop();
|
||||
timings.Add("stats", tsw.ElapsedMilliseconds);
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.10.0" />
|
||||
<PackageReference Include="Microsoft.AspNet.SignalR" Version="2.4.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.All" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="3.2.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.2.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.2.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="3.2.1" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.2.1" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.2.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
|
|
Loading…
Reference in a new issue