mirror of
https://github.com/sphildreth/roadie
synced 2024-11-10 06:44:12 +00:00
Label merge and delete implemented, many changes for images, several bugs squashed.
This commit is contained in:
parent
87ab8785b4
commit
5e01190500
26 changed files with 617 additions and 112 deletions
|
@ -195,5 +195,33 @@ namespace Roadie.Library.Tests
|
|||
// context.SaveChanges();
|
||||
// }
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
//public void Update_Label_Special_Name()
|
||||
//{
|
||||
// var optionsBuilder = new DbContextOptionsBuilder<RoadieDbContext>();
|
||||
// optionsBuilder.UseMySql("server=viking;userid=roadie;password=MenAtW0rk668;persistsecurityinfo=True;database=roadie;ConvertZeroDateTime=true");
|
||||
|
||||
// using (var context = new RoadieDbContext(optionsBuilder.Options))
|
||||
// {
|
||||
// var now = DateTime.UtcNow;
|
||||
// foreach (var label in context.Labels)
|
||||
// {
|
||||
// var labelModel = label.Adapt<Roadie.Library.Models.Label>();
|
||||
// var specialLabelName = labelModel.Name.ToAlphanumericName();
|
||||
// if (!labelModel.AlternateNamesList.Contains(specialLabelName, StringComparer.OrdinalIgnoreCase))
|
||||
// {
|
||||
// var alt = new List<string>(labelModel.AlternateNamesList)
|
||||
// {
|
||||
// specialLabelName
|
||||
// };
|
||||
// label.AlternateNames = alt.ToDelimitedList();
|
||||
// label.LastUpdated = now;
|
||||
// }
|
||||
// }
|
||||
// context.SaveChanges();
|
||||
// }
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,9 +115,11 @@ namespace Roadie.Library.Tests
|
|||
[InlineData("001 Love.Mp3")]
|
||||
[InlineData("01 - Love.Mp3")]
|
||||
[InlineData("Love.Mp3")]
|
||||
[InlineData("LOVE.Mp3")]
|
||||
[InlineData("love.mp3")]
|
||||
public void CleanString_Track(string input)
|
||||
{
|
||||
Assert.Equal("Love.Mp3", input.CleanString(Configuration, Configuration.Processing.TrackRemoveStringsRegex));
|
||||
Assert.Equal("Love.Mp3", input.CleanString(Configuration, Configuration.Processing.TrackRemoveStringsRegex).ToTitleCase());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
|
@ -18,6 +18,11 @@ namespace Roadie.Library.Configuration
|
|||
Integrations Integrations { get; set; }
|
||||
ImageSize LargeImageSize { get; set; }
|
||||
string LibraryFolder { get; set; }
|
||||
string ImageFolder { get; set; }
|
||||
string LabelImageFolder { get; }
|
||||
string CollectionImageFolder { get; }
|
||||
string PlaylistImageFolder { get; }
|
||||
string UserImageFolder { get; }
|
||||
string ListenAddress { get; set; }
|
||||
ImageSize MaximumImageSize { get; set; }
|
||||
ImageSize MediumImageSize { get; set; }
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Roadie.Library.Configuration
|
||||
{
|
||||
|
@ -44,6 +45,40 @@ namespace Roadie.Library.Configuration
|
|||
|
||||
public string LibraryFolder { get; set; }
|
||||
|
||||
public string ImageFolder { get; set; }
|
||||
|
||||
public string LabelImageFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ImageFolder ?? LibraryFolder, "__roadie_images", "labels");
|
||||
}
|
||||
}
|
||||
|
||||
public string CollectionImageFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ImageFolder ?? LibraryFolder, "__roadie_images", "collections");
|
||||
}
|
||||
}
|
||||
|
||||
public string PlaylistImageFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ImageFolder ?? LibraryFolder, "__roadie_images", "playlists");
|
||||
}
|
||||
}
|
||||
|
||||
public string UserImageFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(LibraryFolder, "__roadie_images", "users");
|
||||
}
|
||||
}
|
||||
|
||||
public string ListenAddress { get; set; }
|
||||
|
||||
public ImageSize MaximumImageSize { get; set; }
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using CsvHelper;
|
||||
using Newtonsoft.Json;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.Enums;
|
||||
using Roadie.Library.Extensions;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -39,6 +41,14 @@ namespace Roadie.Library.Data
|
|||
|
||||
public string CacheRegion => CacheRegionUrn(RoadieId);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a full file path to the Collection Image
|
||||
/// </summary>
|
||||
public string PathToImage(IRoadieSettings configuration)
|
||||
{
|
||||
return Path.Combine(configuration.CollectionImageFolder, $"{ (SortName ?? Name).ToFileNameFriendly() } [{ Id }].jpg");
|
||||
}
|
||||
|
||||
public int PositionColumn
|
||||
{
|
||||
get
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
using System;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.Extensions;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
|
@ -24,6 +28,14 @@ namespace Roadie.Library.Data
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a full file path to the Label Image
|
||||
/// </summary>
|
||||
public string PathToImage(IRoadieSettings configuration)
|
||||
{
|
||||
return Path.Combine(configuration.LabelImageFolder, $"{ (SortName ?? Name).ToFileNameFriendly() } [{ Id }].jpg");
|
||||
}
|
||||
|
||||
public bool IsValid => !string.IsNullOrEmpty(Name);
|
||||
|
||||
public static string CacheRegionUrn(Guid Id)
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
using System;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.Extensions;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Roadie.Library.Data
|
||||
{
|
||||
|
@ -18,6 +22,14 @@ namespace Roadie.Library.Data
|
|||
return $"urn:playlist_by_id:{Id}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a full file path to the Playlist Image
|
||||
/// </summary>
|
||||
public string PathToImage(IRoadieSettings configuration)
|
||||
{
|
||||
return Path.Combine(configuration.PlaylistImageFolder, $"{ (SortName ?? Name).ToFileNameFriendly() } [{ Id }].jpg");
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Id [{Id}], Name [{Name}], RoadieId [{RoadieId}]";
|
||||
|
|
|
@ -39,34 +39,57 @@ namespace Roadie.Library.Extensions
|
|||
|
||||
public static string AddToDelimitedList(this string input, IEnumerable<string> values, char delimiter = '|')
|
||||
{
|
||||
if (string.IsNullOrEmpty(input) && (values == null || !values.Any())) return null;
|
||||
if (string.IsNullOrEmpty(input)) return string.Join(delimiter.ToString(), values);
|
||||
if (values == null || !values.Any()) return input;
|
||||
if (string.IsNullOrEmpty(input) && (values == null || !values.Any()))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
return string.Join(delimiter.ToString(), values);
|
||||
}
|
||||
if (values == null || !values.Any())
|
||||
{
|
||||
return input;
|
||||
}
|
||||
foreach (var value in values)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) continue;
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!input.IsValueInDelimitedList(value, delimiter))
|
||||
{
|
||||
if (!input.EndsWith(delimiter.ToString())) input = input + delimiter;
|
||||
input = input + value;
|
||||
if (!input.EndsWith(delimiter.ToString()))
|
||||
{
|
||||
input += delimiter;
|
||||
}
|
||||
input += value;
|
||||
}
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
public static string CleanString(this string input, IRoadieSettings settings, string removeStringsRegex = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input) || settings == null) return input;
|
||||
if (string.IsNullOrEmpty(input) || settings == null)
|
||||
{
|
||||
return input;
|
||||
}
|
||||
var result = input;
|
||||
foreach (var kvp in settings.Processing.ReplaceStrings.OrderBy(x => x.Order).ThenBy(x => x.Key))
|
||||
{
|
||||
result = result.Replace(kvp.Key, kvp.ReplaceWith, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
result = result.Trim().ToTitleCase(false);
|
||||
if (string.IsNullOrEmpty(result)) return input;
|
||||
if (string.IsNullOrEmpty(result))
|
||||
{
|
||||
return input;
|
||||
}
|
||||
var rs = removeStringsRegex ?? settings.Processing.RemoveStringsRegex;
|
||||
if (!string.IsNullOrEmpty(rs)) result = Regex.Replace(result, rs, "", RegexOptions.IgnoreCase);
|
||||
if (!string.IsNullOrEmpty(rs))
|
||||
{
|
||||
result = Regex.Replace(result, rs, "", RegexOptions.IgnoreCase);
|
||||
}
|
||||
if (result.Length > 5)
|
||||
{
|
||||
var extensionStart = result.Substring(result.Length - 5, 2);
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
using Roadie.Library.Data;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.Data;
|
||||
using Roadie.Library.Enums;
|
||||
using Roadie.Library.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Roadie.Library.Identity
|
||||
{
|
||||
|
@ -13,6 +17,14 @@ namespace Roadie.Library.Identity
|
|||
|
||||
public string CacheRegion => CacheRegionUrn(RoadieId);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a full file path to the User Image
|
||||
/// </summary>
|
||||
public string PathToImage(IRoadieSettings configuration)
|
||||
{
|
||||
return Path.Combine(configuration.UserImageFolder, $"{ UserName.ToFileNameFriendly() } [{ Id }].gif");
|
||||
}
|
||||
|
||||
public ApplicationUser()
|
||||
{
|
||||
RoadieId = Guid.NewGuid();
|
||||
|
|
|
@ -20,7 +20,6 @@ namespace Roadie.Library.Imaging
|
|||
{
|
||||
public static string ArtistImageFilename = "artist.jpg";
|
||||
public static string ArtistSecondaryImageFilename = "artist {0}.jpg";
|
||||
public static string LabelImageFilename = "label.jpg";
|
||||
public static int MaximumThumbnailByteSize = 50000;
|
||||
|
||||
// Replace with counter of image
|
||||
|
@ -42,6 +41,21 @@ namespace Roadie.Library.Imaging
|
|||
}
|
||||
}
|
||||
|
||||
public static byte[] ConvertToGifFormat(byte[] imageBytes)
|
||||
{
|
||||
if (imageBytes == null) return null;
|
||||
using (var outStream = new MemoryStream())
|
||||
{
|
||||
IImageFormat imageFormat = null;
|
||||
using (var image = Image.Load(imageBytes, out imageFormat))
|
||||
{
|
||||
image.Save(outStream, ImageFormats.Gif);
|
||||
}
|
||||
return outStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static IEnumerable<FileInfo> FindImagesByName(DirectoryInfo directory, string name,
|
||||
SearchOption folderSearchOptions = SearchOption.AllDirectories)
|
||||
{
|
||||
|
|
|
@ -67,6 +67,7 @@ namespace Roadie.Library.Models.Users
|
|||
[AdaptMember("RoadieId")] public Guid UserId { get; set; }
|
||||
|
||||
[Required] [MaxLength(20)] public string UserName { get; set; }
|
||||
public Image MediumThumbnail { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
|
|
@ -40,10 +40,6 @@
|
|||
<PackageReference Include="zlib.net-mutliplatform" Version="1.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Models\Subsonic\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="IdSharp.AudioInfo-core">
|
||||
<HintPath>..\libraries\IdSharp.AudioInfo-core.dll</HintPath>
|
||||
|
|
|
@ -41,10 +41,12 @@ namespace Roadie.Api.Services
|
|||
|
||||
private IReleaseService ReleaseService { get; }
|
||||
|
||||
private ILabelService LabelService { 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
|
||||
IReleaseService releaseService, IReleaseLookupEngine releaseLookupEngine, ILabelService labelService
|
||||
)
|
||||
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
|
||||
{
|
||||
|
@ -54,6 +56,7 @@ namespace Roadie.Api.Services
|
|||
|
||||
ArtistService = artistService;
|
||||
ReleaseService = releaseService;
|
||||
LabelService = labelService;
|
||||
ReleaseLookupEngine = releaseLookupEngine;
|
||||
FileDirectoryProcessorService = fileDirectoryProcessorService;
|
||||
}
|
||||
|
@ -135,6 +138,52 @@ 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.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)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
|
@ -195,6 +244,40 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
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}]");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await LabelService.Delete(user, labelId);
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
await LogAndPublish("Error deleting artist secondary image.");
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
await LogAndPublish($"DeleteLabel `{label}`, By User `{user}`", LogLevel.Information);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteArtistSecondaryImage(ApplicationUser user, Guid artistId, int index)
|
||||
{
|
||||
|
@ -413,6 +496,11 @@ namespace Roadie.Api.Services
|
|||
|
||||
DbContext.Users.Remove(user);
|
||||
await DbContext.SaveChangesAsync();
|
||||
var userImageFilename = user.PathToImage(Configuration);
|
||||
if (File.Exists(userImageFilename))
|
||||
{
|
||||
File.Delete(userImageFilename);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -183,17 +183,18 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> Delete(ApplicationUser user, data.Artist Artist)
|
||||
public async Task<OperationResult<bool>> Delete(ApplicationUser user, data.Artist artist)
|
||||
{
|
||||
var isSuccess = false;
|
||||
try
|
||||
{
|
||||
if (Artist != null)
|
||||
if (artist != null)
|
||||
{
|
||||
DbContext.Artists.Remove(Artist);
|
||||
DbContext.Artists.Remove(artist);
|
||||
await DbContext.SaveChangesAsync();
|
||||
CacheManager.ClearRegion(Artist.CacheRegion);
|
||||
Logger.LogInformation(string.Format("x DeleteArtist [{0}]", Artist.Id));
|
||||
// TODO delete artist folder if empty?
|
||||
CacheManager.ClearRegion(artist.CacheRegion);
|
||||
Logger.LogInformation(string.Format("x DeleteArtist [{0}]", artist.Id));
|
||||
isSuccess = true;
|
||||
}
|
||||
}
|
||||
|
@ -461,22 +462,25 @@ namespace Roadie.Api.Services
|
|||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
artistToMergeInto.RealName = artistToMerge.RealName ?? artistToMergeInto.RealName;
|
||||
artistToMergeInto.MusicBrainzId = artistToMerge.MusicBrainzId ?? artistToMergeInto.MusicBrainzId;
|
||||
artistToMergeInto.ITunesId = artistToMerge.ITunesId ?? artistToMergeInto.ITunesId;
|
||||
artistToMergeInto.AmgId = artistToMerge.AmgId ?? artistToMergeInto.AmgId;
|
||||
artistToMergeInto.SpotifyId = artistToMerge.SpotifyId ?? artistToMergeInto.SpotifyId;
|
||||
artistToMergeInto.Thumbnail = artistToMerge.Thumbnail ?? artistToMergeInto.Thumbnail;
|
||||
artistToMergeInto.Profile = artistToMerge.Profile ?? artistToMergeInto.Profile;
|
||||
artistToMergeInto.BirthDate = artistToMerge.BirthDate ?? artistToMergeInto.BirthDate;
|
||||
artistToMergeInto.BeginDate = artistToMerge.BeginDate ?? artistToMergeInto.BeginDate;
|
||||
artistToMergeInto.EndDate = artistToMerge.EndDate ?? artistToMergeInto.EndDate;
|
||||
var artistToMergeFolder = artistToMerge.ArtistFileFolder(Configuration);
|
||||
var artistToMergeIntoFolder = artistToMergeInto.ArtistFileFolder(Configuration);
|
||||
|
||||
artistToMergeInto.RealName = artistToMergeInto.RealName ?? artistToMerge.RealName;
|
||||
artistToMergeInto.MusicBrainzId = artistToMergeInto.MusicBrainzId ?? artistToMerge.MusicBrainzId;
|
||||
artistToMergeInto.ITunesId = artistToMergeInto.ITunesId ?? artistToMerge.ITunesId;
|
||||
artistToMergeInto.AmgId = artistToMergeInto.AmgId ?? artistToMerge.AmgId;
|
||||
artistToMergeInto.SpotifyId = artistToMergeInto.SpotifyId ?? artistToMerge.SpotifyId;
|
||||
artistToMergeInto.Thumbnail = artistToMergeInto.Thumbnail ?? artistToMerge.Thumbnail;
|
||||
artistToMergeInto.Profile = artistToMergeInto.Profile ?? artistToMerge.Profile;
|
||||
artistToMergeInto.BirthDate = artistToMergeInto.BirthDate ?? artistToMerge.BirthDate;
|
||||
artistToMergeInto.BeginDate = artistToMergeInto.BeginDate ?? artistToMerge.BeginDate;
|
||||
artistToMergeInto.EndDate = artistToMergeInto.EndDate ?? artistToMerge.EndDate;
|
||||
if (!string.IsNullOrEmpty(artistToMerge.ArtistType) && !artistToMerge.ArtistType.Equals("Other", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
artistToMergeInto.ArtistType = artistToMerge.ArtistType;
|
||||
artistToMergeInto.ArtistType = artistToMergeInto.ArtistType ?? artistToMerge.ArtistType;
|
||||
}
|
||||
artistToMergeInto.BioContext = artistToMerge.BioContext ?? artistToMergeInto.BioContext;
|
||||
artistToMergeInto.DiscogsId = artistToMerge.DiscogsId ?? artistToMergeInto.DiscogsId;
|
||||
artistToMergeInto.BioContext = artistToMergeInto.BioContext ?? artistToMerge.BioContext;
|
||||
artistToMergeInto.DiscogsId = artistToMergeInto.DiscogsId ?? artistToMerge.DiscogsId;
|
||||
artistToMergeInto.Tags = artistToMergeInto.Tags.AddToDelimitedList(artistToMerge.Tags.ToListFromDelimited());
|
||||
var altNames = artistToMerge.AlternateNames.ToListFromDelimited().ToList();
|
||||
altNames.Add(artistToMerge.Name);
|
||||
|
@ -514,6 +518,51 @@ namespace Roadie.Api.Services
|
|||
artistImage.ArtistId = artistToMergeInto.Id;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Move any Artist and Artist Secondary images from ArtistToMerge into ArtistToMergeInto folder
|
||||
if (Directory.Exists(artistToMergeFolder))
|
||||
{
|
||||
var artistToMergeImages = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistToMergeFolder), ImageType.Artist);
|
||||
var artistToMergeSecondaryImages = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistToMergeFolder), ImageType.ArtistSecondary).ToList();
|
||||
// Primary Artist image
|
||||
if (artistToMergeImages.Any())
|
||||
{
|
||||
// If the ArtistToMergeInto already has a primary image then the ArtistToMerge primary image becomes a secondary image
|
||||
var artistToMergeIntoPrimaryImage = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistToMergeIntoFolder), ImageType.Artist).FirstOrDefault();
|
||||
if (artistToMergeIntoPrimaryImage != null)
|
||||
{
|
||||
artistToMergeSecondaryImages.Add(artistToMergeImages.First());
|
||||
}
|
||||
else
|
||||
{
|
||||
var artistImageFilename = Path.Combine(artistToMergeIntoFolder, ImageHelper.ArtistImageFilename);
|
||||
artistToMergeImages.First().MoveTo(artistImageFilename);
|
||||
}
|
||||
}
|
||||
// Secondary Artist images
|
||||
if (artistToMergeSecondaryImages.Any())
|
||||
{
|
||||
var looper = 0;
|
||||
foreach (var artistSecondaryImage in artistToMergeSecondaryImages)
|
||||
{
|
||||
var artistImageFilename = Path.Combine(artistToMergeIntoFolder, string.Format(ImageHelper.ArtistSecondaryImageFilename, looper.ToString("00")));
|
||||
while (File.Exists(artistImageFilename))
|
||||
{
|
||||
looper++;
|
||||
artistImageFilename = Path.Combine(artistToMergeIntoFolder, string.Format(ImageHelper.ArtistSecondaryImageFilename, looper.ToString("00")));
|
||||
}
|
||||
artistSecondaryImage.MoveTo(artistImageFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "MergeArtists: Error Moving Artist Primary and Secondary Images");
|
||||
}
|
||||
|
||||
var userArtists = DbContext.UserArtists.Where(x => x.ArtistId == artistToMerge.Id).ToArray();
|
||||
if (artistImages != null)
|
||||
{
|
||||
|
@ -553,10 +602,9 @@ namespace Roadie.Api.Services
|
|||
Logger.LogWarning(ex.ToString());
|
||||
}
|
||||
|
||||
var artistFolder = artistToMerge.ArtistFileFolder(Configuration);
|
||||
foreach (var release in DbContext.Releases.Include("Artist").Where(x => x.ArtistId == artistToMerge.Id).ToArray())
|
||||
{
|
||||
var originalReleaseFolder = release.ReleaseFileFolder(artistFolder);
|
||||
var originalReleaseFolder = release.ReleaseFileFolder(artistToMergeFolder);
|
||||
await ReleaseService.UpdateRelease(user, release.Adapt<Release>(), originalReleaseFolder);
|
||||
}
|
||||
await DbContext.SaveChangesAsync();
|
||||
|
@ -664,7 +712,9 @@ namespace Roadie.Api.Services
|
|||
var specialArtistName = model.Name.ToAlphanumericName();
|
||||
var alt = new List<string>(model.AlternateNamesList);
|
||||
if (!model.AlternateNamesList.Contains(specialArtistName, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
alt.Add(specialArtistName);
|
||||
}
|
||||
artist.AlternateNames = alt.ToDelimitedList();
|
||||
artist.ArtistType = model.ArtistType;
|
||||
artist.AmgId = model.AmgId;
|
||||
|
|
|
@ -18,6 +18,7 @@ using Roadie.Library.Utility;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -138,6 +139,11 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
DbContext.Collections.Remove(collection);
|
||||
await DbContext.SaveChangesAsync();
|
||||
var collectionImageFilename = collection.PathToImage(Configuration);
|
||||
if (File.Exists(collectionImageFilename))
|
||||
{
|
||||
File.Delete(collectionImageFilename);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -228,7 +234,9 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
collection = DbContext.Collections.FirstOrDefault(x => x.RoadieId == model.Id);
|
||||
if (collection == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, string.Format("Collection Not Found [{0}]", model.Id));
|
||||
}
|
||||
}
|
||||
|
||||
collection.IsLocked = model.IsLocked;
|
||||
|
@ -249,6 +257,9 @@ namespace Roadie.Api.Services
|
|||
var collectionImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
|
||||
if (collectionImage != null)
|
||||
{
|
||||
// Save unaltered collection image
|
||||
File.WriteAllBytes(collection.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(collectionImage));
|
||||
// Update Thumbnail
|
||||
collection.Thumbnail = ImageHelper.ResizeToThumbnail(collectionImage, Configuration);
|
||||
}
|
||||
|
||||
|
@ -296,8 +307,7 @@ namespace Roadie.Api.Services
|
|||
result.Tags = collection.Tags;
|
||||
result.URLs = collection.URLs;
|
||||
result.Thumbnail = MakeCollectionThumbnailImage(collection.RoadieId);
|
||||
result.MediumThumbnail = MakeThumbnailImage(id, "collection", Configuration.MediumImageSize.Width,
|
||||
Configuration.MediumImageSize.Height);
|
||||
result.MediumThumbnail = MakeThumbnailImage(id, "collection", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
|
||||
result.CollectionFoundCount = (from crc in DbContext.CollectionReleases
|
||||
where crc.CollectionId == collection.Id
|
||||
select crc.Id).Count();
|
||||
|
|
|
@ -9,6 +9,8 @@ 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,
|
||||
|
@ -16,6 +18,8 @@ namespace Roadie.Api.Services
|
|||
|
||||
Task<OperationResult<bool>> DeleteArtistSecondaryImage(ApplicationUser user, Guid artistId, int index);
|
||||
|
||||
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);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Roadie.Library;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using Roadie.Library.Models.Users;
|
||||
|
@ -15,6 +16,10 @@ namespace Roadie.Api.Services
|
|||
|
||||
Task<PagedResult<LabelList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false);
|
||||
|
||||
Task<OperationResult<bool>> Delete(ApplicationUser user, Guid id);
|
||||
|
||||
Task<OperationResult<bool>> MergeLabelsIntoLabel(ApplicationUser user, Guid intoLabelId, IEnumerable<Guid> labelIdsToMerge);
|
||||
|
||||
Task<OperationResult<Image>> SetLabelImageByUrl(User user, Guid id, string imageUrl);
|
||||
|
||||
Task<OperationResult<bool>> UpdateLabel(User user, Label label);
|
||||
|
|
|
@ -321,16 +321,31 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
var collection = GetCollection(id);
|
||||
if (collection == null)
|
||||
return Task.FromResult(new FileOperationResult<Image>(true,
|
||||
string.Format("Collection Not Found [{0}]", id)));
|
||||
{
|
||||
return Task.FromResult(new FileOperationResult<Image>(true, string.Format("Collection Not Found [{0}]", id)));
|
||||
}
|
||||
var image = new data.Image
|
||||
{
|
||||
Bytes = collection.Thumbnail,
|
||||
CreatedDate = collection.CreatedDate,
|
||||
LastUpdated = collection.LastUpdated
|
||||
};
|
||||
var collectionImageFilename = collection.PathToImage(Configuration);
|
||||
try
|
||||
{
|
||||
if (File.Exists(collectionImageFilename))
|
||||
{
|
||||
image.Bytes = File.ReadAllBytes(collectionImageFilename);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, $"Error Reading Image File [{collectionImageFilename}]");
|
||||
}
|
||||
if (collection.Thumbnail == null || !collection.Thumbnail.Any())
|
||||
{
|
||||
image = DefaultNotFoundImages.Collection;
|
||||
}
|
||||
return Task.FromResult(GenerateFileOperationResult(id, image, etag));
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -439,7 +454,22 @@ namespace Roadie.Api.Services
|
|||
CreatedDate = label.CreatedDate,
|
||||
LastUpdated = label.LastUpdated
|
||||
};
|
||||
if (label.Thumbnail == null || !label.Thumbnail.Any()) image = DefaultNotFoundImages.Label;
|
||||
var labelImageFilename = label.PathToImage(Configuration);
|
||||
try
|
||||
{
|
||||
if(File.Exists(labelImageFilename))
|
||||
{
|
||||
image.Bytes = File.ReadAllBytes(labelImageFilename);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, $"Error Reading Image File [{labelImageFilename}]");
|
||||
}
|
||||
if (label.Thumbnail == null || !label.Thumbnail.Any())
|
||||
{
|
||||
image = DefaultNotFoundImages.Label;
|
||||
}
|
||||
return Task.FromResult(GenerateFileOperationResult(id, image, etag));
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -464,7 +494,22 @@ namespace Roadie.Api.Services
|
|||
CreatedDate = playlist.CreatedDate,
|
||||
LastUpdated = playlist.LastUpdated
|
||||
};
|
||||
if (playlist.Thumbnail == null || !playlist.Thumbnail.Any()) image = DefaultNotFoundImages.Playlist;
|
||||
var playlistImageFilename = playlist.PathToImage(Configuration);
|
||||
try
|
||||
{
|
||||
if (File.Exists(playlistImageFilename))
|
||||
{
|
||||
image.Bytes = File.ReadAllBytes(playlistImageFilename);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, $"Error Reading Image File [{playlistImageFilename}]");
|
||||
}
|
||||
if (playlist.Thumbnail == null || !playlist.Thumbnail.Any())
|
||||
{
|
||||
image = DefaultNotFoundImages.Playlist;
|
||||
}
|
||||
return Task.FromResult(GenerateFileOperationResult(id, image, etag));
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -638,15 +683,31 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
var user = GetUser(id);
|
||||
if (user == null)
|
||||
return Task.FromResult(new FileOperationResult<Image>(true,
|
||||
string.Format("User Not Found [{0}]", id)));
|
||||
{
|
||||
return Task.FromResult(new FileOperationResult<Image>(true, string.Format("User Not Found [{0}]", id)));
|
||||
}
|
||||
var image = new data.Image
|
||||
{
|
||||
Bytes = user.Avatar,
|
||||
CreatedDate = user.CreatedDate.Value,
|
||||
LastUpdated = user.LastUpdated
|
||||
};
|
||||
if (user.Avatar == null || !user.Avatar.Any()) image = DefaultNotFoundImages.User;
|
||||
var userImageFilename = user.PathToImage(Configuration);
|
||||
try
|
||||
{
|
||||
if (File.Exists(userImageFilename))
|
||||
{
|
||||
image.Bytes = File.ReadAllBytes(userImageFilename);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, $"Error Reading Image File [{userImageFilename}]");
|
||||
}
|
||||
if (!(image?.Bytes?.Any() ?? false))
|
||||
{
|
||||
image = DefaultNotFoundImages.User;
|
||||
}
|
||||
return Task.FromResult(GenerateFileOperationResult(id, image, etag, "image/png"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
@ -8,6 +8,7 @@ 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.Models;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
|
@ -43,6 +44,32 @@ 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.LogInformation("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();
|
||||
|
@ -103,10 +130,11 @@ namespace Roadie.Api.Services
|
|||
? request.FilterValue.ToAlphanumericName()
|
||||
: null;
|
||||
var result = from l in DbContext.Labels
|
||||
where request.FilterValue.Length == 0 || request.FilterValue.Length > 0 && (
|
||||
l.Name != null && l.Name.Contains(request.FilterValue) ||
|
||||
l.AlternateNames != null && l.AlternateNames.Contains(request.FilterValue) ||
|
||||
l.AlternateNames != null && l.AlternateNames.Contains(normalizedFilterValue)
|
||||
where request.FilterValue == "" || (
|
||||
l.Name.Contains(request.FilterValue) ||
|
||||
l.SortName.Contains(request.FilterValue) ||
|
||||
l.AlternateNames.Contains(request.FilterValue) ||
|
||||
l.AlternateNames.Contains(normalizedFilterValue)
|
||||
)
|
||||
select new LabelList
|
||||
{
|
||||
|
@ -116,7 +144,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
Text = l.Name,
|
||||
Value = l.RoadieId.ToString()
|
||||
},
|
||||
},
|
||||
SortName = l.SortName,
|
||||
CreatedDate = l.CreatedDate,
|
||||
LastUpdated = l.LastUpdated,
|
||||
|
@ -132,7 +160,6 @@ namespace Roadie.Api.Services
|
|||
var randomLimit = roadieUser?.RandomReleaseLimit ?? 100;
|
||||
request.Limit = request.LimitValue > randomLimit ? randomLimit : request.LimitValue;
|
||||
rows = result.OrderBy(x => x.RandomSortId).Take(request.LimitValue).ToArray();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -153,6 +180,67 @@ namespace Roadie.Api.Services
|
|||
});
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> MergeLabelsIntoLabel(ApplicationUser user, Guid intoLabelId, IEnumerable<Guid> labelIdsToMerge)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
var errors = new List<Exception>();
|
||||
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == intoLabelId);
|
||||
if (label == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, string.Format("Merge Into Label Not Found [{0}]", intoLabelId));
|
||||
}
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
var labelsToMerge = (from l in DbContext.Labels
|
||||
join ltm in labelIdsToMerge on l.RoadieId equals ltm
|
||||
select l);
|
||||
foreach (var labelToMerge in labelsToMerge)
|
||||
{
|
||||
label.MusicBrainzId = label.MusicBrainzId ?? labelToMerge.MusicBrainzId;
|
||||
label.SortName = label.SortName ?? labelToMerge.SortName;
|
||||
label.Thumbnail = label.Thumbnail ?? labelToMerge.Thumbnail;
|
||||
label.Profile = label.Profile ?? labelToMerge.Profile;
|
||||
label.BeginDate = label.BeginDate ?? labelToMerge.BeginDate;
|
||||
label.EndDate = label.EndDate ?? labelToMerge.EndDate;
|
||||
label.Profile = label.Profile ?? labelToMerge.Profile;
|
||||
label.DiscogsId = label.DiscogsId ?? labelToMerge.DiscogsId;
|
||||
label.ImageUrl = label.ImageUrl ?? labelToMerge.ImageUrl;
|
||||
label.Tags = label.Tags.AddToDelimitedList(labelToMerge.Tags.ToListFromDelimited());
|
||||
var altNames = labelToMerge.AlternateNames.ToListFromDelimited().ToList();
|
||||
altNames.Add(labelToMerge.Name);
|
||||
altNames.Add(labelToMerge.SortName);
|
||||
altNames.Add(labelToMerge.Name.ToAlphanumericName());
|
||||
label.AlternateNames = label.AlternateNames.AddToDelimitedList(altNames);
|
||||
label.URLs = label.URLs.AddToDelimitedList(labelToMerge.URLs.ToListFromDelimited());
|
||||
|
||||
var labelToMergeReleases = (from rl in DbContext.ReleaseLabels
|
||||
where rl.LabelId == labelToMerge.Id
|
||||
select rl);
|
||||
foreach (var labelToMergeRelease in labelToMergeReleases)
|
||||
{
|
||||
labelToMergeRelease.LabelId = label.Id;
|
||||
labelToMergeRelease.LastUpdated = now;
|
||||
}
|
||||
label.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
}
|
||||
await UpdateLabelCounts(label.Id, now);
|
||||
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
Logger.LogInformation($"MergeLabelsIntoLabel `{label}`, Merged Label Ids [{ string.Join(",", labelIdsToMerge) }] By User `{user}`");
|
||||
|
||||
sw.Stop();
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Image>> SetLabelImageByUrl(User user, Guid id, string imageUrl)
|
||||
{
|
||||
return await SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
|
||||
|
@ -168,7 +256,11 @@ namespace Roadie.Api.Services
|
|||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
label.AlternateNames = model.AlternateNamesList.ToDelimitedList();
|
||||
var specialArtistName = model.Name.ToAlphanumericName();
|
||||
var alt = new List<string>(model.AlternateNamesList);
|
||||
if (!model.AlternateNamesList.Contains(specialArtistName, StringComparer.OrdinalIgnoreCase))
|
||||
alt.Add(specialArtistName);
|
||||
label.AlternateNames = alt.ToDelimitedList();
|
||||
label.BeginDate = model.BeginDate;
|
||||
label.DiscogsId = model.DiscogsId;
|
||||
label.EndDate = model.EndDate;
|
||||
|
@ -184,7 +276,8 @@ namespace Roadie.Api.Services
|
|||
var labelImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
|
||||
if (labelImage != null)
|
||||
{
|
||||
// Resize to store in database as thumbnail
|
||||
// Save unaltered label image
|
||||
File.WriteAllBytes(label.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(labelImage));
|
||||
label.Thumbnail = ImageHelper.ResizeToThumbnail(labelImage, Configuration);
|
||||
}
|
||||
|
||||
|
@ -319,7 +412,8 @@ namespace Roadie.Api.Services
|
|||
label.Thumbnail = imageBytes;
|
||||
if (label.Thumbnail != null)
|
||||
{
|
||||
// Ensure is jpeg first
|
||||
// Save unaltered label image
|
||||
File.WriteAllBytes(label.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(imageBytes));
|
||||
label.Thumbnail = ImageHelper.ResizeToThumbnail(label.Thumbnail, Configuration);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ using Roadie.Library.Utility;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -176,6 +177,13 @@ namespace Roadie.Api.Services
|
|||
|
||||
DbContext.Playlists.Remove(playlist);
|
||||
await DbContext.SaveChangesAsync();
|
||||
|
||||
var playlistImageFilename = playlist.PathToImage(Configuration);
|
||||
if (File.Exists(playlistImageFilename))
|
||||
{
|
||||
File.Delete(playlistImageFilename);
|
||||
}
|
||||
|
||||
Logger.LogInformation("User `{0}` deleted Playlist `{1}]`", user, playlist);
|
||||
CacheManager.ClearRegion(playlist.CacheRegion);
|
||||
sw.Stop();
|
||||
|
@ -295,7 +303,9 @@ namespace Roadie.Api.Services
|
|||
var playlistImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
|
||||
if (playlistImage != null)
|
||||
{
|
||||
// Ensure is jpeg first
|
||||
// Save unaltered playlist image
|
||||
File.WriteAllBytes(playlist.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(playlistImage));
|
||||
// Update thumbnail
|
||||
playlist.Thumbnail = ImageHelper.ResizeToThumbnail(playlistImage, Configuration);
|
||||
}
|
||||
|
||||
|
|
|
@ -569,10 +569,8 @@ namespace Roadie.Api.Services
|
|||
releaseToMergeInto.MediaCount = releaseToMergeInto.MediaCount ?? 0;
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
var releaseToMergeReleaseMedia =
|
||||
DbContext.ReleaseMedias.Where(x => x.ReleaseId == releaseToMerge.Id).ToList();
|
||||
var releaseToMergeIntoReleaseMedia =
|
||||
DbContext.ReleaseMedias.Where(x => x.ReleaseId == releaseToMergeInto.Id).ToList();
|
||||
var releaseToMergeReleaseMedia = DbContext.ReleaseMedias.Where(x => x.ReleaseId == releaseToMerge.Id).ToList();
|
||||
var releaseToMergeIntoReleaseMedia = DbContext.ReleaseMedias.Where(x => x.ReleaseId == releaseToMergeInto.Id).ToList();
|
||||
var releaseToMergeIntoLastMediaNumber = releaseToMergeIntoReleaseMedia.Max(x => x.MediaNumber);
|
||||
|
||||
// Add new ReleaseMedia
|
||||
|
@ -628,37 +626,29 @@ namespace Roadie.Api.Services
|
|||
else
|
||||
{
|
||||
// Track does exist merge two tracks together
|
||||
existingTrack.MusicBrainzId =
|
||||
existingTrack.MusicBrainzId ?? mergeTrack.MusicBrainzId;
|
||||
existingTrack.MusicBrainzId = existingTrack.MusicBrainzId ?? mergeTrack.MusicBrainzId;
|
||||
existingTrack.SpotifyId = existingTrack.SpotifyId ?? mergeTrack.SpotifyId;
|
||||
existingTrack.AmgId = existingTrack.AmgId ?? mergeTrack.AmgId;
|
||||
existingTrack.ISRC = existingTrack.ISRC ?? mergeTrack.ISRC;
|
||||
existingTrack.AmgId = existingTrack.AmgId ?? mergeTrack.AmgId;
|
||||
existingTrack.LastFMId = existingTrack.LastFMId ?? mergeTrack.LastFMId;
|
||||
existingTrack.PartTitles = existingTrack.PartTitles ?? mergeTrack.PartTitles;
|
||||
existingTrack.PlayedCount =
|
||||
(existingTrack.PlayedCount ?? 0) + (mergeTrack.PlayedCount ?? 0);
|
||||
existingTrack.PlayedCount = (existingTrack.PlayedCount ?? 0) + (mergeTrack.PlayedCount ?? 0);
|
||||
if (mergeTrack.LastPlayed.HasValue && existingTrack.LastPlayed.HasValue &&
|
||||
mergeTrack.LastPlayed > existingTrack.LastPlayed)
|
||||
existingTrack.LastPlayed = mergeTrack.LastPlayed;
|
||||
existingTrack.Thumbnail = existingTrack.Thumbnail ?? mergeTrack.Thumbnail;
|
||||
existingTrack.MusicBrainzId =
|
||||
existingTrack.MusicBrainzId ?? mergeTrack.MusicBrainzId;
|
||||
existingTrack.Tags =
|
||||
existingTrack.Tags.AddToDelimitedList(mergeTrack.Tags.ToListFromDelimited());
|
||||
existingTrack.MusicBrainzId = existingTrack.MusicBrainzId ?? mergeTrack.MusicBrainzId;
|
||||
existingTrack.Tags = existingTrack.Tags.AddToDelimitedList(mergeTrack.Tags.ToListFromDelimited());
|
||||
if (!mergeTrack.Title.Equals(existingTrack.Title,
|
||||
StringComparison.OrdinalIgnoreCase))
|
||||
existingTrack.AlternateNames =
|
||||
existingTrack.AlternateNames.AddToDelimitedList(new[]
|
||||
{mergeTrack.Title, mergeTrack.Title.ToAlphanumericName()});
|
||||
existingTrack.AlternateNames =
|
||||
existingTrack.AlternateNames.AddToDelimitedList(mergeTrack.AlternateNames
|
||||
.ToListFromDelimited());
|
||||
existingTrack.AlternateNames = existingTrack.AlternateNames.AddToDelimitedList(mergeTrack.AlternateNames.ToListFromDelimited());
|
||||
existingTrack.LastUpdated = now;
|
||||
var mergedTrackFileName =
|
||||
mergeTrack.PathToTrack(Configuration);
|
||||
var trackFileName =
|
||||
existingTrack.PathToTrack(Configuration);
|
||||
var mergedTrackFileName = mergeTrack.PathToTrack(Configuration);
|
||||
var trackFileName = existingTrack.PathToTrack(Configuration);
|
||||
if (!trackFileName.Equals(mergedTrackFileName, StringComparison.Ordinal) &&
|
||||
File.Exists(trackFileName)) mergedFilesToDelete.Add(mergedTrackFileName);
|
||||
}
|
||||
|
@ -805,8 +795,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> Delete(ApplicationUser user, data.Release release, bool doDeleteFiles = false,
|
||||
bool doUpdateArtistCounts = true)
|
||||
public async Task<OperationResult<bool>> Delete(ApplicationUser user, data.Release release, bool doDeleteFiles = false, bool doUpdateArtistCounts = true)
|
||||
{
|
||||
SimpleContract.Requires<ArgumentNullException>(release != null, "Invalid Release");
|
||||
SimpleContract.Requires<ArgumentNullException>(release.Artist != null, "Invalid Artist");
|
||||
|
|
|
@ -19,6 +19,7 @@ using Roadie.Library.Utility;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -408,8 +409,20 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
var imageData = ImageHelper.ImageDataFromUrl(userBeingUpdatedModel.AvatarData);
|
||||
if (imageData != null)
|
||||
user.Avatar = ImageHelper.ResizeImage(imageData, Configuration.ThumbnailImageSize.Width,
|
||||
Configuration.ThumbnailImageSize.Height);
|
||||
{
|
||||
imageData = ImageHelper.ConvertToGifFormat(imageData);
|
||||
|
||||
// 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)
|
||||
{
|
||||
user.Avatar = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
await DbContext.SaveChangesAsync();
|
||||
|
@ -518,21 +531,20 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
var user = GetUser(id);
|
||||
if (user == null)
|
||||
{
|
||||
return Task.FromResult(new OperationResult<User>(true, string.Format("User Not Found [{0}]", id)));
|
||||
}
|
||||
var model = user.Adapt<User>();
|
||||
model.MediumThumbnail = MakeThumbnailImage(id, "user", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
|
||||
model.IsAdmin = user.UserRoles?.Any(x => x.Role?.NormalizedName == "ADMIN") ?? false;
|
||||
model.IsEditor = model.IsAdmin ? true : user.UserRoles?.Any(x => x.Role?.NormalizedName == "EDITOR") ?? false;
|
||||
if (includes != null && includes.Any())
|
||||
{
|
||||
if (includes.Contains("stats"))
|
||||
{
|
||||
var userArtists =
|
||||
DbContext.UserArtists.Include(x => x.Artist).Where(x => x.UserId == user.Id).ToArray() ??
|
||||
new data.UserArtist[0];
|
||||
var userReleases =
|
||||
DbContext.UserReleases.Include(x => x.Release).Where(x => x.UserId == user.Id).ToArray() ??
|
||||
new data.UserRelease[0];
|
||||
var userTracks =
|
||||
DbContext.UserTracks.Include(x => x.Track).Where(x => x.UserId == user.Id).ToArray() ??
|
||||
new data.UserTrack[0];
|
||||
|
||||
var userArtists = DbContext.UserArtists.Include(x => x.Artist).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserArtist[0];
|
||||
var userReleases = DbContext.UserReleases.Include(x => x.Release).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserRelease[0];
|
||||
var userTracks = DbContext.UserTracks.Include(x => x.Track).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserTrack[0];
|
||||
var mostPlayedArtist = (from a in DbContext.Artists
|
||||
join r in DbContext.Releases on a.Id equals r.ArtistId
|
||||
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
||||
|
@ -548,7 +560,6 @@ namespace Roadie.Api.Services
|
|||
})
|
||||
.OrderByDescending(x => x.Played)
|
||||
.FirstOrDefault();
|
||||
|
||||
var mostPlayedReleaseId = (from r in DbContext.Releases
|
||||
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
||||
join t in DbContext.Tracks on rm.Id equals t.ReleaseMediaId
|
||||
|
@ -564,9 +575,7 @@ namespace Roadie.Api.Services
|
|||
.OrderByDescending(x => x.Played)
|
||||
.Select(x => x.Release.RoadieId)
|
||||
.FirstOrDefault();
|
||||
|
||||
var mostPlayedRelease = GetRelease(mostPlayedReleaseId);
|
||||
|
||||
var mostPlayedTrackUserTrack = userTracks
|
||||
.OrderByDescending(x => x.PlayedCount)
|
||||
.FirstOrDefault();
|
||||
|
@ -620,7 +629,7 @@ namespace Roadie.Api.Services
|
|||
DislikedTracks = userTracks.Where(x => x.IsDisliked ?? false).Count()
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
return Task.FromResult(new OperationResult<User>
|
||||
{
|
||||
IsSuccess = true,
|
||||
|
|
|
@ -73,6 +73,15 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("delete/label/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteLabel(Guid id)
|
||||
{
|
||||
var result = await AdminService.DeleteLabel(await UserManager.GetUserAsync(User), id);
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("delete/releasesecondaryimage/{id}/{index}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteReleaseSecondaryImage(Guid id, int index)
|
||||
|
|
|
@ -138,8 +138,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> ReleaseImage(Guid id, int? width, int? height)
|
||||
{
|
||||
var result = await ImageService.ReleaseImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width,
|
||||
height ?? RoadieSettings.ThumbnailImageSize.Height);
|
||||
var result = await ImageService.ReleaseImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height);
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
return File(result.Data.Bytes,
|
||||
|
@ -203,8 +202,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> TrackImage(Guid id, int? width, int? height)
|
||||
{
|
||||
var result = await ImageService.TrackImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width,
|
||||
height ?? RoadieSettings.ThumbnailImageSize.Height);
|
||||
var result = await ImageService.TrackImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height);
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
return File(result.Data.Bytes,
|
||||
|
@ -215,20 +213,19 @@ namespace Roadie.Api.Controllers
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// NOTE that user images/avatars are PNG not JPG this is so it looks better in the menus/applications
|
||||
/// NOTE that user images/avatars are GIF not JPG this is so it looks better in the menus/applications
|
||||
/// </summary>
|
||||
[HttpGet("user/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> UserImage(Guid id, int? width, int? height)
|
||||
{
|
||||
var result = await ImageService.UserImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width,
|
||||
height ?? RoadieSettings.ThumbnailImageSize.Height);
|
||||
var result = await ImageService.UserImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height);
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
return File(result.Data.Bytes,
|
||||
result.ContentType,
|
||||
$"{result.Data.Caption ?? id.ToString()}.png",
|
||||
$"{result.Data.Caption ?? id.ToString()}.gif",
|
||||
result.LastModified,
|
||||
result.ETag);
|
||||
}
|
||||
|
|
|
@ -68,16 +68,39 @@ namespace Roadie.Api.Controllers
|
|||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
[HttpPost("mergeLabels/{labelToMergeId}/{labelToMergeIntoId}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> MergeLabels(Guid labelToMergeId, Guid labelToMergeIntoId)
|
||||
{
|
||||
var result = await LabelService.MergeLabelsIntoLabel(await UserManager.GetUserAsync(User), labelToMergeIntoId, new Guid[1] { labelToMergeId });
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("setImageByUrl/{id}/{imageUrl}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> SetLabelImageByUrl(Guid id, string imageUrl)
|
||||
{
|
||||
var result =
|
||||
await LabelService.SetLabelImageByUrl(await CurrentUserModel(), id, HttpUtility.UrlDecode(imageUrl));
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
var result = await LabelService.SetLabelImageByUrl(await CurrentUserModel(), id, HttpUtility.UrlDecode(imageUrl));
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
|
|
@ -228,7 +228,7 @@ namespace Roadie.Api
|
|||
services.AddScoped<ILookupService, LookupService>();
|
||||
services.AddScoped<ICommentService, CommentService>();
|
||||
|
||||
var securityKey = new SymmetricSecurityKey(Encoding.Default.GetBytes(_configuration["Tokens:PrivateKey"]));
|
||||
var securityKey = new SymmetricSecurityKey(Encoding.Default.GetBytes(_configuration["Tokens:PrivateKey"]));
|
||||
|
||||
services.AddAuthentication(options =>
|
||||
{
|
||||
|
@ -288,11 +288,17 @@ namespace Roadie.Api
|
|||
services.AddHttpContextAccessor();
|
||||
services.AddScoped<IHttpContext>(factory =>
|
||||
{
|
||||
var actionContext = factory.GetService<IActionContextAccessor>()
|
||||
.ActionContext;
|
||||
|
||||
var actionContext = factory.GetService<IActionContextAccessor>().ActionContext;
|
||||
if(actionContext == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new HttpContext(factory.GetService<IRoadieSettings>(), new UrlHelper(actionContext));
|
||||
});
|
||||
|
||||
var sp = services.BuildServiceProvider();
|
||||
var adminService = sp.GetService<IAdminService>();
|
||||
adminService.PerformStartUpTasks();
|
||||
}
|
||||
|
||||
private class IntegrationKey
|
||||
|
|
Loading…
Reference in a new issue