Small buf fixes and many ToListAsync implementations.

This commit is contained in:
Steven Hildreth 2019-11-24 15:58:38 -06:00
parent c357c6dab9
commit d9a5a917f6
59 changed files with 1269 additions and 867 deletions

View file

@ -8,9 +8,11 @@ namespace Roadie.Library.Data
[Table("collection")] [Table("collection")]
public partial class Collection : NamedEntityBase public partial class Collection : NamedEntityBase
{ {
[Column("collectionCount")] public int CollectionCount { get; set; } [Column("collectionCount")]
public int CollectionCount { get; set; }
[Column("collectionType")] public CollectionType? CollectionType { get; set; } [Column("collectionType")]
public CollectionType? CollectionType { get; set; }
public ICollection<Comment> Comments { get; set; } public ICollection<Comment> Comments { get; set; }
@ -18,7 +20,9 @@ namespace Roadie.Library.Data
[MaxLength(4000)] [MaxLength(4000)]
public string Description { get; set; } public string Description { get; set; }
[Column("edition")] [MaxLength(200)] public string Edition { get; set; } [Column("edition")]
[MaxLength(200)]
public string Edition { get; set; }
[Column("listInCSV", TypeName = "text")] [Column("listInCSV", TypeName = "text")]
[MaxLength(65535)] [MaxLength(65535)]
@ -28,7 +32,8 @@ namespace Roadie.Library.Data
[MaxLength(200)] [MaxLength(200)]
public string ListInCSVFormat { get; set; } public string ListInCSVFormat { get; set; }
[Column("maintainerId")] public int MaintainerId { get; set; } [Column("maintainerId")]
public int MaintainerId { get; set; }
public ICollection<CollectionRelease> Releases { get; set; } public ICollection<CollectionRelease> Releases { get; set; }
} }

View file

@ -24,6 +24,8 @@ namespace Roadie.Library.Data.Context
DbSet<Collection> Collections { get; set; } DbSet<Collection> Collections { get; set; }
DbSet<CommentReaction> CommentReactions { get; set; } DbSet<CommentReaction> CommentReactions { get; set; }
DbSet<Comment> Comments { get; set; } DbSet<Comment> Comments { get; set; }
DbSet<Credit> Credits { get; set; }
DbSet<CreditCategory> CreditCategory { get; set; }
DatabaseFacade Database { get; } DatabaseFacade Database { get; }
DbSet<Genre> Genres { get; set; } DbSet<Genre> Genres { get; set; }
DbSet<Label> Labels { get; set; } DbSet<Label> Labels { get; set; }

View file

@ -113,9 +113,14 @@ namespace Roadie.Library.Data.Context.Implementation
} }
else else
{ {
randomArtists = await Artists.OrderBy(x => Guid.NewGuid()) randomArtists = await (from a in Artists
.Take(randomLimit) join ua in UserArtists on a.Id equals ua.ArtistId into uag
.ToListAsync(); from ua in uag.DefaultIfEmpty()
where (ua == null || (ua.UserId == userId && ua.IsDisliked == false))
select a)
.OrderBy(x => Guid.NewGuid())
.Take(randomLimit)
.ToListAsync();
} }
var dict = randomArtists.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value); var dict = randomArtists.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict); return new SortedDictionary<int, int>(dict);
@ -164,9 +169,14 @@ namespace Roadie.Library.Data.Context.Implementation
} }
else else
{ {
randomReleases = await Releases.OrderBy(x => Guid.NewGuid()) randomReleases = await(from r in Releases
.Take(randomLimit) join ur in UserReleases on r.Id equals ur.ReleaseId into urg
.ToListAsync(); from ur in urg.DefaultIfEmpty()
where (ur == null || (ur.UserId == userId && ur.IsDisliked == false))
select r)
.OrderBy(x => Guid.NewGuid())
.Take(randomLimit)
.ToListAsync();
} }
var dict = randomReleases.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value); var dict = randomReleases.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict); return new SortedDictionary<int, int>(dict);
@ -199,9 +209,14 @@ namespace Roadie.Library.Data.Context.Implementation
} }
else else
{ {
randomTracks = await Tracks.OrderBy(x => Guid.NewGuid()) randomTracks = await (from t in Tracks
.Take(randomLimit) join ut in UserTracks on t.Id equals ut.TrackId into utg
.ToListAsync(); from ut in utg.DefaultIfEmpty()
where (ut == null || (ut.UserId == userId && ut.IsDisliked == false))
select t)
.OrderBy(x => Guid.NewGuid())
.Take(randomLimit)
.ToListAsync();
} }
var dict = randomTracks.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value); var dict = randomTracks.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict); return new SortedDictionary<int, int>(dict);

View file

@ -32,6 +32,9 @@ namespace Roadie.Library.Data.Context
public DbSet<Comment> Comments { get; set; } public DbSet<Comment> Comments { get; set; }
public DbSet<Credit> Credits { get; set; }
public DbSet<CreditCategory> CreditCategory { get; set; }
public DbSet<Genre> Genres { get; set; } public DbSet<Genre> Genres { get; set; }
public DbSet<Label> Labels { get; set; } public DbSet<Label> Labels { get; set; }

View file

@ -0,0 +1,43 @@
using Roadie.Library.Enums;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Data
{
[Table("credit")]
public partial class Credit : NamedEntityBase
{
[Column("creditCategoryId")]
public int CreditCategoryId { get; set; }
[Column("description")]
[MaxLength(4000)]
public string Description { get; set; }
/// <summary>
/// Full Name when not an Artist via ArtistId (like a Producer)
/// </summary>
[Column("creditToName")]
[MaxLength(500)]
public string CreditToName { get; set; }
[Column("artistId")]
public int? ArtistId { get; set; }
[Column("releaseId")]
public int? ReleaseId { get; set; }
[Column("trackId")]
public int? TrackId { get; set; }
[NotMapped]
public override string Name { get; set; }
[NotMapped]
public override string SortName { get; set; }
[NotMapped]
public override string AlternateNames { get; set; }
}
}

View file

@ -0,0 +1,20 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Data
{
[Table("creditCategory")]
public partial class CreditCategory : NamedEntityBase
{
[Column("description")]
[MaxLength(4000)]
public string Description { get; set; }
[MaxLength(100)]
[Column("name")]
public override string Name { get; set; }
[NotMapped]
public override string SortName { get; set; }
}
}

View file

@ -16,11 +16,15 @@ namespace Roadie.Library.Data
public virtual bool? IsLocked { get; set; } public virtual bool? IsLocked { get; set; }
[Column("lastUpdated")] public DateTime? LastUpdated { get; set; } [Column("lastUpdated")]
public DateTime? LastUpdated { get; set; }
[Column("RoadieId")] [Required] public Guid RoadieId { get; set; } [Column("RoadieId")]
[Required]
public Guid RoadieId { get; set; }
[Column("status")] public Statuses? Status { get; set; } [Column("status")]
public Statuses? Status { get; set; }
public EntityBase() public EntityBase()
{ {

View file

@ -8,25 +8,24 @@ namespace Roadie.Library.Data
{ {
[Column("alternateNames", TypeName = "text")] [Column("alternateNames", TypeName = "text")]
[MaxLength(65535)] [MaxLength(65535)]
public string AlternateNames { get; set; } public virtual string AlternateNames { get; set; }
[MaxLength(250)] [Column("name")] public string Name { get; set; } [MaxLength(250)]
[Column("name")]
public virtual string Name { get; set; }
[Column("sortName")] [MaxLength(250)] public string SortName { get; set; } [Column("sortName")]
[MaxLength(250)]
public virtual string SortName { get; set; }
public string SortNameValue => string.IsNullOrEmpty(SortName) ? Name : SortName; public virtual string SortNameValue => string.IsNullOrEmpty(SortName) ? Name : SortName;
[Column("tags", TypeName = "text")] [Column("tags", TypeName = "text")]
[MaxLength(65535)] [MaxLength(65535)]
public string Tags { get; set; } public virtual string Tags { get; set; }
[Obsolete("Images moved to file system")]
[Column("thumbnail", TypeName = "blob")]
[MaxLength(65535)]
public byte[] Thumbnail { get; set; }
[Column("urls", TypeName = "text")] [Column("urls", TypeName = "text")]
[MaxLength(65535)] [MaxLength(65535)]
public string URLs { get; set; } public virtual string URLs { get; set; }
} }
} }

View file

@ -2,6 +2,7 @@
using Roadie.Library.Enums; using Roadie.Library.Enums;
using Roadie.Library.Extensions; using Roadie.Library.Extensions;
using Roadie.Library.MetaData.Audio; using Roadie.Library.MetaData.Audio;
using models = Roadie.Library.Models;
using Roadie.Library.SearchEngines.Imaging; using Roadie.Library.SearchEngines.Imaging;
using Roadie.Library.Utility; using Roadie.Library.Utility;
using SixLabors.ImageSharp; using SixLabors.ImageSharp;
@ -398,5 +399,101 @@ namespace Roadie.Library.Imaging
return imageMetaData; return imageMetaData;
} }
public static models.Image MakeThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string type, int? width = null, int? height = null, bool includeCachebuster = false)
{
return MakeImage(configuration, httpContext, id, type, width ?? configuration.ThumbnailImageSize.Width, height ?? configuration.ThumbnailImageSize.Height, null, includeCachebuster);
}
public static models.Image MakeNewImage(IHttpContext httpContext, string type)
{
return new models.Image($"{httpContext.ImageBaseUrl}/{type}.jpg", null, null);
}
public static models.Image MakePlaylistThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "playlist");
}
public static models.Image MakeReleaseThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "release");
}
public static models.Image MakeTrackThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "track");
}
public static models.Image MakeUserThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "user");
}
public static models.Image MakeLabelThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "label");
}
public static models.Image MakeArtistThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid? id)
{
if (!id.HasValue) return null;
return MakeThumbnailImage(configuration, httpContext, id.Value, "artist");
}
public static models.Image MakeCollectionThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "collection");
}
public static models.Image MakeFullsizeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string caption = null)
{
return new models.Image($"{httpContext.ImageBaseUrl}/{id}", caption,
$"{httpContext.ImageBaseUrl}/{id}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
}
public static models.Image MakeFullsizeSecondaryImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, ImageType type, int imageId, string caption = null)
{
if (type == ImageType.ArtistSecondary)
{
return new models.Image($"{httpContext.ImageBaseUrl}/artist-secondary/{id}/{imageId}", caption, $"{httpContext.ImageBaseUrl}/artist-secondary/{id}/{imageId}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
}
return new models.Image($"{httpContext.ImageBaseUrl}/release-secondary/{id}/{imageId}", caption, $"{httpContext.ImageBaseUrl}/release-secondary/{id}/{imageId}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
}
public static models.Image MakeGenreThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "genre");
}
public static models.Image MakeUnknownImage(IHttpContext httpContext, string unknownType = "unknown")
{
return new models.Image($"{httpContext.ImageBaseUrl}/{ unknownType }.jpg");
}
public static models.Image MakeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, int width = 200, int height = 200, string caption = null, bool includeCachebuster = false)
{
return new models.Image($"{httpContext.ImageBaseUrl}/{id}/{width}/{height}/{(includeCachebuster ? DateTime.UtcNow.Ticks.ToString() : string.Empty)}",
caption,
$"{httpContext.ImageBaseUrl}/{id}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
}
public static models.Image MakeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string type, IImageSize imageSize)
{
return MakeImage(configuration, httpContext, id, type, imageSize.Width, imageSize.Height);
}
public static models.Image MakeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string type, int? width, int? height, string caption = null, bool includeCachebuster = false)
{
if (width.HasValue && height.HasValue && (width.Value != configuration.ThumbnailImageSize.Width ||
height.Value != configuration.ThumbnailImageSize.Height))
return new models.Image(
$"{httpContext.ImageBaseUrl}/{type}/{id}/{width}/{height}/{(includeCachebuster ? DateTime.UtcNow.Ticks.ToString() : string.Empty)}",
caption,
$"{httpContext.ImageBaseUrl}/{type}/{id}/{configuration.ThumbnailImageSize.Width}/{configuration.ThumbnailImageSize.Height}");
return new models.Image($"{httpContext.ImageBaseUrl}/{type}/{id}", caption, null);
}
} }
} }

View file

@ -14,8 +14,7 @@ namespace Roadie.Library.Models
[Serializable] [Serializable]
public class Artist : EntityModelBase public class Artist : EntityModelBase
{ {
public const string DefaultIncludes = public const string DefaultIncludes = "stats,images,associatedartists,similarartists,comments,collections,playlists,contributions,labels,genres";
"stats,images,associatedartists,similarartists,comments,collections,playlists,contributions,labels";
public IEnumerable<ReleaseList> ArtistContributionReleases; public IEnumerable<ReleaseList> ArtistContributionReleases;
public IEnumerable<LabelList> ArtistLabels; public IEnumerable<LabelList> ArtistLabels;
@ -40,7 +39,7 @@ namespace Roadie.Library.Models
[MaxLength(50)] public string DiscogsId { get; set; } [MaxLength(50)] public string DiscogsId { get; set; }
public IEnumerable<DataToken> Genres { get; set; } public IEnumerable<GenreList> Genres { get; set; }
public IEnumerable<Image> Images { get; set; } public IEnumerable<Image> Images { get; set; }

View file

@ -8,7 +8,7 @@ namespace Roadie.Library.Models
{ {
[Serializable] [Serializable]
[DebuggerDisplay("Artist Id {Id}, Name {Artist.Text}")] [DebuggerDisplay("Artist Id {Id}, Name {Artist.Text}")]
public class ArtistList : EntityInfoModelBase public sealed class ArtistList : EntityInfoModelBase
{ {
public DataToken Artist { get; set; } public DataToken Artist { get; set; }
public bool IsValid => Id != Guid.Empty; public bool IsValid => Id != Guid.Empty;

View file

@ -8,11 +8,12 @@ using System;
namespace Roadie.Library.Models namespace Roadie.Library.Models
{ {
[Serializable] [Serializable]
public class BookmarkList : EntityInfoModelBase public sealed class BookmarkList : EntityInfoModelBase
{ {
public ArtistList Artist { get; set; } public ArtistList Artist { get; set; }
public DataToken Bookmark { get; set; } public DataToken Bookmark { get; set; }
[JsonIgnore] public int BookmarkTargetId { get; set; } [JsonIgnore]
public int BookmarkTargetId { get; set; }
public string BookmarkType => Type.ToString(); public string BookmarkType => Type.ToString();
public CollectionList Collection { get; set; } public CollectionList Collection { get; set; }
public string Comment { get; set; } public string Comment { get; set; }

View file

@ -3,7 +3,7 @@
namespace Roadie.Library.Models.Collections namespace Roadie.Library.Models.Collections
{ {
[Serializable] [Serializable]
public class CollectionList : EntityInfoModelBase public sealed class CollectionList : EntityInfoModelBase
{ {
public DataToken Artist { get; set; } public DataToken Artist { get; set; }
public DataToken Collection { get; set; } public DataToken Collection { get; set; }

View file

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace Roadie.Library.Models
{
[Serializable]
public class Credit : EntityModelBase
{
public int CreditCategoryId { get; set; }
[MaxLength(4000)]
public string Description { get; set; }
/// <summary>
/// Full Name when not an Artist via ArtistId (like a Producer)
/// </summary>
[MaxLength(500)]
public string CreditToName { get; set; }
public int ArtistId { get; set; }
public int ReleaseId { get; set; }
public int TrackId { get; set; }
}
}

View file

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace Roadie.Library.Models
{
[Serializable]
public class CreditCategory : EntityModelBase
{
[MaxLength(100)]
public string Name { get; set; }
[MaxLength(4000)]
public string Description { get; set; }
}
}

View file

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Roadie.Library.Models
{
[Serializable]
public sealed class CreditList : EntityModelBase
{
public ArtistList Artist { get; set; }
public string CreditName { get; set; }
public DataToken Category { get; set; }
public string Description { get; set; }
}
}

View file

@ -26,7 +26,8 @@ namespace Roadie.Library.Models
public DateTime? LastUpdated { get; set; } public DateTime? LastUpdated { get; set; }
[MaxLength(250)] public string SortName { get; set; } [MaxLength(250)]
public virtual string SortName { get; set; }
/// <summary> /// <summary>
/// Random int to sort when Random Request /// Random int to sort when Random Request

View file

@ -21,9 +21,9 @@ namespace Roadie.Library.Models
[MaxLength(65535)] [MaxLength(65535)]
[JsonIgnore] [JsonIgnore]
[IgnoreDataMember] [IgnoreDataMember]
public string AlternateNames { get; set; } public virtual string AlternateNames { get; set; }
public IEnumerable<string> AlternateNamesList public virtual IEnumerable<string> AlternateNamesList
{ {
get get
{ {
@ -39,11 +39,12 @@ namespace Roadie.Library.Models
set => _alternateNamesList = value; set => _alternateNamesList = value;
} }
public DateTime? BeginDate { get; set; } public virtual DateTime? BeginDate { get; set; }
[Required] public virtual DateTime? CreatedDate { get; set; } [Required]
public virtual DateTime? CreatedDate { get; set; }
public DateTime? EndDate { get; set; } public virtual DateTime? EndDate { get; set; }
/// <summary> /// <summary>
/// This is the exposed Id for API consumers, not the Database Id. /// This is the exposed Id for API consumers, not the Database Id.
@ -51,22 +52,23 @@ namespace Roadie.Library.Models
[AdaptMember("RoadieId")] [AdaptMember("RoadieId")]
public virtual Guid? Id { get; set; } public virtual Guid? Id { get; set; }
public bool? IsLocked { get; set; } public virtual bool? IsLocked { get; set; }
public DateTime? LastUpdated { get; set; } public virtual DateTime? LastUpdated { get; set; }
[MaxLength(250)] public string SortName { get; set; } [MaxLength(250)]
public virtual string SortName { get; set; }
public int? Status { get; set; } public virtual int? Status { get; set; }
public string StatusVerbose => SafeParser.ToEnum<Statuses>(Status).ToString(); public string StatusVerbose => SafeParser.ToEnum<Statuses>(Status).ToString();
[MaxLength(65535)] [MaxLength(65535)]
[JsonIgnore] [JsonIgnore]
[IgnoreDataMember] [IgnoreDataMember]
public string Tags { get; set; } public virtual string Tags { get; set; }
public IEnumerable<string> TagsList public virtual IEnumerable<string> TagsList
{ {
get get
{ {
@ -84,9 +86,9 @@ namespace Roadie.Library.Models
[MaxLength(65535)] [MaxLength(65535)]
[JsonIgnore] [JsonIgnore]
[IgnoreDataMember] [IgnoreDataMember]
public string URLs { get; set; } public virtual string URLs { get; set; }
public IEnumerable<string> URLsList public virtual IEnumerable<string> URLsList
{ {
get get
{ {
@ -101,7 +103,7 @@ namespace Roadie.Library.Models
set => _urlsList = value; set => _urlsList = value;
} }
public bool? UserBookmarked { get; set; } public virtual bool? UserBookmarked { get; set; }
public EntityModelBase() public EntityModelBase()
{ {

View file

@ -3,11 +3,30 @@
namespace Roadie.Library.Models namespace Roadie.Library.Models
{ {
[Serializable] [Serializable]
public class GenreList : EntityInfoModelBase public sealed class GenreList : EntityInfoModelBase
{ {
public int? ArtistCount { get; set; } public int? ArtistCount { get; set; }
public DataToken Genre { get; set; } public DataToken Genre { get; set; }
public int? ReleaseCount { get; set; } public int? ReleaseCount { get; set; }
public Image Thumbnail { get; set; } public Image Thumbnail { get; set; }
public static GenreList FromDataGenre(Data.Genre genre, Image genreThumbnail, int? artistCount, int? releaseCount)
{
return new GenreList
{
Id = genre.RoadieId,
Genre = new DataToken
{
Text = genre.Name,
Value = genre.RoadieId.ToString()
},
SortName = genre.SortName,
CreatedDate = genre.CreatedDate,
LastUpdated = genre.LastUpdated,
ArtistCount = artistCount,
ReleaseCount = releaseCount,
Thumbnail = genreThumbnail
};
}
} }
} }

View file

@ -4,39 +4,40 @@ using System.ComponentModel.DataAnnotations;
namespace Roadie.Library.Models namespace Roadie.Library.Models
{ {
/// <summary> /// <summary>
/// Image class served to API consumers. /// Image model class served to API consumers.
/// </summary> /// </summary>
[Serializable] [Serializable]
public class Image : EntityModelBase public sealed class Image : EntityModelBase
{ {
public byte[] Bytes { get; set; } public byte[] Bytes { get; }
[MaxLength(100)] public string Caption { get; set; } [MaxLength(100)]
public string Caption { get; }
[Obsolete("Only here for transition. Will be removed in future release.")] public string ThumbnailUrl { get; }
public Guid? ArtistId { get; set; }
[Obsolete("Only here for transition. Will be removed in future release.")]
public Guid? ReleaseId { get; set; }
[MaxLength(50)] public string Signature { get; set; }
[MaxLength(500)] public string ThumbnailUrl { get; set; } public string Url { get; }
[MaxLength(500)] public string Url { get; set; }
public Image() public Image()
{ {
} }
/// <summary> /// <summary>
/// Set image Url to given value and nullify other entity values, intended to be used in List collection (like images /// Set image Url to given value and nullify other entity values, intended to be used in List collection (like images for an artist)
/// for an artist)
/// </summary> /// </summary>
public Image(string url) : this(url, null, null) public Image(string url)
: this(url, null, null)
{ {
} }
public Image(string url, string caption, string thumbnailUrl) public Image(byte[] bytes)
: this(null, null, null, bytes)
{ {
}
public Image(string url, string caption, string thumbnailUrl, byte[] bytes = null)
{
Bytes = bytes;
Url = url; Url = url;
ThumbnailUrl = thumbnailUrl; ThumbnailUrl = thumbnailUrl;
CreatedDate = null; CreatedDate = null;
@ -44,10 +45,5 @@ namespace Roadie.Library.Models
Status = null; Status = null;
Caption = caption; Caption = caption;
} }
public Image(byte[] bytes)
{
Bytes = bytes;
}
} }
} }

View file

@ -11,12 +11,15 @@ namespace Roadie.Library.Models
{ {
public const string DefaultIncludes = "comments,stats"; public const string DefaultIncludes = "comments,stats";
[MaxLength(65535)] public string BioContext { get; set; } [MaxLength(65535)]
public string BioContext { get; set; }
public DateTime? BirthDate { get; set; } public DateTime? BirthDate { get; set; }
public IEnumerable<Comment> Comments { get; set; } public IEnumerable<Comment> Comments { get; set; }
[MaxLength(50)] public string DiscogsId { get; set; }
[MaxLength(50)]
public string DiscogsId { get; set; }
public decimal? Duration { get; set; } public decimal? Duration { get; set; }
@ -30,14 +33,18 @@ namespace Roadie.Library.Models
} }
public Image MediumThumbnail { get; set; } public Image MediumThumbnail { get; set; }
[MaxLength(100)] public string MusicBrainzId { get; set; }
[MaxLength(100)]
public string MusicBrainzId { get; set; }
[MaxLength(250)] public string Name { get; set; } [MaxLength(250)]
public string Name { get; set; }
// When populated a "data:image" base64 byte array of an image to use as new Thumbnail // When populated a "data:image" base64 byte array of an image to use as new Thumbnail
public string NewThumbnailData { get; set; } public string NewThumbnailData { get; set; }
[MaxLength(65535)] public string Profile { get; set; } [MaxLength(65535)]
public string Profile { get; set; }
public ReleaseGroupingStatistics Statistics { get; set; } public ReleaseGroupingStatistics Statistics { get; set; }
public Image Thumbnail { get; set; } public Image Thumbnail { get; set; }

View file

@ -4,7 +4,7 @@ using System;
namespace Roadie.Library.Models namespace Roadie.Library.Models
{ {
[Serializable] [Serializable]
public class LabelList : EntityInfoModelBase public sealed class LabelList : EntityInfoModelBase
{ {
public int? ArtistCount { get; set; } public int? ArtistCount { get; set; }
public DataToken Label { get; set; } public DataToken Label { get; set; }

View file

@ -5,7 +5,7 @@ using System;
namespace Roadie.Library.Models.Playlists namespace Roadie.Library.Models.Playlists
{ {
[Serializable] [Serializable]
public class PlaylistList : EntityInfoModelBase public sealed class PlaylistList : EntityInfoModelBase
{ {
public decimal? Duration { get; set; } public decimal? Duration { get; set; }

View file

@ -3,7 +3,7 @@
namespace Roadie.Library.Models.Playlists namespace Roadie.Library.Models.Playlists
{ {
[Serializable] [Serializable]
public class PlaylistTrackList : EntityInfoModelBase public sealed class PlaylistTrackList : EntityInfoModelBase
{ {
public DataToken Artist { get; set; } public DataToken Artist { get; set; }
public string ArtistThumbnailUrl { get; set; } public string ArtistThumbnailUrl { get; set; }

View file

@ -10,7 +10,7 @@ namespace Roadie.Library.Models.Releases
[Serializable] [Serializable]
public class Release : EntityModelBase public class Release : EntityModelBase
{ {
public const string DefaultIncludes = "tracks,stats,images,comments,collections,labels,playlists,genres"; public const string DefaultIncludes = "tracks,stats,images,comments,collections,labels,playlists,genres,credits";
public const string DefaultListIncludes = ""; public const string DefaultListIncludes = "";
[MaxLength(50)] public string AmgId { get; set; } [MaxLength(50)] public string AmgId { get; set; }
@ -19,10 +19,12 @@ namespace Roadie.Library.Models.Releases
public List<ReleaseInCollection> Collections { get; set; } public List<ReleaseInCollection> Collections { get; set; }
public IEnumerable<CreditList> Credits { get; set; }
public IEnumerable<Comment> Comments { get; set; } public IEnumerable<Comment> Comments { get; set; }
[MaxLength(50)] public string DiscogsId { get; set; } [MaxLength(50)] public string DiscogsId { get; set; }
public IEnumerable<DataToken> Genres { get; set; } public IEnumerable<GenreList> Genres { get; set; }
public IEnumerable<Image> Images { get; set; } public IEnumerable<Image> Images { get; set; }
public bool? IsVirtual { get; set; } public bool? IsVirtual { get; set; }

View file

@ -4,7 +4,7 @@ using System;
namespace Roadie.Library.Models.Releases namespace Roadie.Library.Models.Releases
{ {
[Serializable] [Serializable]
public class ReleaseLabelList : EntityInfoModelBase public sealed class ReleaseLabelList : EntityInfoModelBase
{ {
public string BeginDate => BeginDatedDateTime.HasValue ? BeginDatedDateTime.Value.ToString("s") : null; public string BeginDate => BeginDatedDateTime.HasValue ? BeginDatedDateTime.Value.ToString("s") : null;
[JsonIgnore] public DateTime? BeginDatedDateTime { get; set; } [JsonIgnore] public DateTime? BeginDatedDateTime { get; set; }

View file

@ -11,7 +11,7 @@ namespace Roadie.Library.Models.Releases
{ {
[Serializable] [Serializable]
[DebuggerDisplay("DatabaseId [{ DatabaseId }] Name [{ ReleaseName }] IsValid [{ IsValid }]")] [DebuggerDisplay("DatabaseId [{ DatabaseId }] Name [{ ReleaseName }] IsValid [{ IsValid }]")]
public class ReleaseList : EntityInfoModelBase public sealed class ReleaseList : EntityInfoModelBase
{ {
public DataToken Artist { get; set; } public DataToken Artist { get; set; }
public Image ArtistThumbnail { get; set; } public Image ArtistThumbnail { get; set; }

View file

@ -5,7 +5,7 @@ using System.Linq;
namespace Roadie.Library.Models.Releases namespace Roadie.Library.Models.Releases
{ {
[Serializable] [Serializable]
public class ReleaseMediaList : EntityInfoModelBase public sealed class ReleaseMediaList : EntityInfoModelBase
{ {
public short? MediaNumber { get; set; } public short? MediaNumber { get; set; }
public string SubTitle { get; set; } public string SubTitle { get; set; }

View file

@ -13,14 +13,14 @@ namespace Roadie.Library.Models
[Serializable] [Serializable]
public class Track : EntityModelBase public class Track : EntityModelBase
{ {
public const string DefaultIncludes = "comments,stats"; public const string DefaultIncludes = "comments,stats,credits";
private IEnumerable<string> _partTitles; private IEnumerable<string> _partTitles;
[MaxLength(50)] public string AmgId { get; set; } [MaxLength(50)] public string AmgId { get; set; }
public ArtistList Artist { get; set; } public ArtistList Artist { get; set; }
public IEnumerable<CreditList> Credits { get; set; }
public Image ArtistThumbnail { get; set; } public Image ArtistThumbnail { get; set; }
public IEnumerable<Comment> Comments { get; set; } public IEnumerable<Comment> Comments { get; set; }
public int Duration { get; set; } public int Duration { get; set; }

View file

@ -15,7 +15,7 @@ namespace Roadie.Library.Models
{ {
[Serializable] [Serializable]
[DebuggerDisplay("Trackid [{ TrackId }], Track Name [{ TrackName }}, Release Name [{ ReleaseName }]")] [DebuggerDisplay("Trackid [{ TrackId }], Track Name [{ TrackName }}, Release Name [{ ReleaseName }]")]
public class TrackList : EntityInfoModelBase public sealed class TrackList : EntityInfoModelBase
{ {
public ArtistList Artist { get; set; } public ArtistList Artist { get; set; }
public int? Duration { get; set; } public int? Duration { get; set; }

View file

@ -6,7 +6,7 @@ using System.Linq;
namespace Roadie.Library.Models.Users namespace Roadie.Library.Models.Users
{ {
[Serializable] [Serializable]
public class UserList : EntityInfoModelBase public sealed class UserList : EntityInfoModelBase
{ {
public bool IsEditor { get; set; } public bool IsEditor { get; set; }
public bool IsAdmin { get; set; } public bool IsAdmin { get; set; }

View file

@ -11,7 +11,7 @@
<PackageReference Include="AutoCompare.Core" Version="1.0.0" /> <PackageReference Include="AutoCompare.Core" Version="1.0.0" />
<PackageReference Include="CsvHelper" Version="12.2.1" /> <PackageReference Include="CsvHelper" Version="12.2.1" />
<PackageReference Include="EFCore.BulkExtensions" Version="3.0.3" /> <PackageReference Include="EFCore.BulkExtensions" Version="3.0.3" />
<PackageReference Include="FluentFTP" Version="28.0.1" /> <PackageReference Include="FluentFTP" Version="28.0.2" />
<PackageReference Include="Hashids.net" Version="1.3.0" /> <PackageReference Include="Hashids.net" Version="1.3.0" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.16" /> <PackageReference Include="HtmlAgilityPack" Version="1.11.16" />
<PackageReference Include="IdSharp.Common" Version="1.0.1" /> <PackageReference Include="IdSharp.Common" Version="1.0.1" />

View file

@ -90,7 +90,7 @@ namespace Roadie.Api.Services
if (result?.Data != null && roadieUser != null) if (result?.Data != null && roadieUser != null)
{ {
tsw.Restart(); tsw.Restart();
var artist = GetArtist(id); var artist = await GetArtist(id);
tsw.Stop(); tsw.Stop();
timings.Add("getArtist", tsw.ElapsedMilliseconds); timings.Add("getArtist", tsw.ElapsedMilliseconds);
tsw.Restart(); tsw.Restart();
@ -285,7 +285,7 @@ namespace Roadie.Api.Services
Text = a.Name, Text = a.Name,
Value = a.RoadieId.ToString() Value = a.RoadieId.ToString()
}, },
Thumbnail = MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId), Thumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId),
Rating = a.Rating, Rating = a.Rating,
Rank = a.Rank, Rank = a.Rank,
CreatedDate = a.CreatedDate, CreatedDate = a.CreatedDate,
@ -303,7 +303,7 @@ namespace Roadie.Api.Services
if (doRandomize ?? false) if (doRandomize ?? false)
{ {
var resultData = result.ToArray(); var resultData = await result.ToArrayAsync();
rows = (from r in resultData rows = (from r in resultData
join ra in randomArtistData on r.DatabaseId equals ra.Value join ra in randomArtistData on r.DatabaseId equals ra.Value
orderby ra.Key orderby ra.Key
@ -323,16 +323,16 @@ namespace Roadie.Api.Services
{ {
sortBy = request.OrderValue(new Dictionary<string, string> { { "SortName", "ASC" }, { "Artist.Text", "ASC" } }); sortBy = request.OrderValue(new Dictionary<string, string> { { "SortName", "ASC" }, { "Artist.Text", "ASC" } });
} }
rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray(); rows = await result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArrayAsync();
} }
if (rows.Any() && roadieUser != null) if (rows.Any() && roadieUser != null)
{ {
var rowIds = rows.Select(x => x.DatabaseId).ToArray(); var rowIds = rows.Select(x => x.DatabaseId).ToArray();
var userArtistRatings = (from ua in DbContext.UserArtists var userArtistRatings = await (from ua in DbContext.UserArtists
where ua.UserId == roadieUser.Id where ua.UserId == roadieUser.Id
where rowIds.Contains(ua.ArtistId) where rowIds.Contains(ua.ArtistId)
select ua).ToArray(); select ua).ToArrayAsync();
foreach (var userArtistRating in userArtistRatings.Where(x => rows.Select(r => r.DatabaseId).Contains(x.ArtistId))) foreach (var userArtistRating in userArtistRatings.Where(x => rows.Select(r => r.DatabaseId).Contains(x.ArtistId)))
{ {
@ -667,6 +667,10 @@ namespace Roadie.Api.Services
Directory.Move(originalArtistFolder, newArtistFolder); Directory.Move(originalArtistFolder, newArtistFolder);
} }
} }
if (!Directory.Exists(newArtistFolder))
{
Directory.CreateDirectory(newArtistFolder);
}
var artistImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData); var artistImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
if (artistImage != null) if (artistImage != null)
@ -707,14 +711,14 @@ namespace Roadie.Api.Services
// Remove existing Genres not in model list // Remove existing Genres not in model list
foreach (var genre in artist.Genres.ToList()) foreach (var genre in artist.Genres.ToList())
{ {
var doesExistInModel = model.Genres.Any(x => SafeParser.ToGuid(x.Value) == genre.Genre.RoadieId); var doesExistInModel = model.Genres.Any(x => SafeParser.ToGuid(x.Genre.Value) == genre.Genre.RoadieId);
if (!doesExistInModel) artist.Genres.Remove(genre); if (!doesExistInModel) artist.Genres.Remove(genre);
} }
// Add new Genres in model not in data // Add new Genres in model not in data
foreach (var genre in model.Genres) foreach (var genre in model.Genres)
{ {
var genreId = SafeParser.ToGuid(genre.Value); var genreId = SafeParser.ToGuid(genre.Genre.Value);
var doesExistInData = artist.Genres.Any(x => x.Genre.RoadieId == genreId); var doesExistInData = artist.Genres.Any(x => x.Genre.RoadieId == genreId);
if (!doesExistInData) if (!doesExistInData)
{ {
@ -806,12 +810,6 @@ namespace Roadie.Api.Services
var similarArtists = DbContext.ArtistSimilar.Include(x => x.SimilarArtist).Where(x => x.ArtistId == artist.Id || x.SimilarArtistId == artist.Id).ToList(); var similarArtists = DbContext.ArtistSimilar.Include(x => x.SimilarArtist).Where(x => x.ArtistId == artist.Id || x.SimilarArtistId == artist.Id).ToList();
DbContext.ArtistSimilar.RemoveRange(similarArtists); DbContext.ArtistSimilar.RemoveRange(similarArtists);
} }
if (model.Images != null && model.Images.Any())
{
// TODO
}
artist.LastUpdated = now; artist.LastUpdated = now;
await DbContext.SaveChangesAsync(); await DbContext.SaveChangesAsync();
if (didRenameArtist) if (didRenameArtist)
@ -876,7 +874,7 @@ namespace Roadie.Api.Services
sw.Start(); sw.Start();
tsw.Restart(); tsw.Restart();
var artist = GetArtist(id); var artist = await GetArtist(id);
tsw.Stop(); tsw.Stop();
timings.Add("getArtist", tsw.ElapsedMilliseconds); timings.Add("getArtist", tsw.ElapsedMilliseconds);
@ -897,41 +895,60 @@ namespace Roadie.Api.Services
tsw.Stop(); tsw.Stop();
timings.Add("adapt", tsw.ElapsedMilliseconds); timings.Add("adapt", tsw.ElapsedMilliseconds);
tsw.Restart(); tsw.Restart();
result.Thumbnail = MakeArtistThumbnailImage(Configuration, HttpContext, id); result.Thumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, id);
result.MediumThumbnail = MakeThumbnailImage(Configuration, HttpContext, id, "artist", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height); result.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "artist", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
result.Genres = artist.Genres.Select(x => new DataToken
{
Text = x.Genre.Name,
Value = x.Genre.RoadieId.ToString()
});
tsw.Stop();
timings.Add("genres", tsw.ElapsedMilliseconds);
if (includes != null && includes.Any()) if (includes != null && includes.Any())
{ {
tsw.Restart(); tsw.Restart();
if(includes.Contains("genres"))
{
var artistGenreIds = artist.Genres.Select(x => x.GenreId).ToArray();
result.Genres = (await (from g in DbContext.Genres
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 artistGenreIds.Contains(g.Id)
select new { g, releaseCount, artistCount }).ToListAsync())
.Select(x => GenreList.FromDataGenre(x.g,
ImageHelper.MakeGenreThumbnailImage(Configuration, HttpContext, x.g.RoadieId),
x.artistCount,
x.releaseCount))
.ToArray();
tsw.Stop();
timings.Add("genres", tsw.ElapsedMilliseconds);
}
if (includes.Contains("releases")) if (includes.Contains("releases"))
{ {
tsw.Restart();
var dtoReleases = new List<ReleaseList>(); var dtoReleases = new List<ReleaseList>();
foreach (var release in DbContext.Releases foreach (var release in await DbContext.Releases
.Include("Medias") .Include("Medias")
.Include("Medias.Tracks") .Include("Medias.Tracks")
.Include("Medias.Tracks") .Include("Medias.Tracks")
.Where(x => x.ArtistId == artist.Id) .Where(x => x.ArtistId == artist.Id)
.ToArray()) .ToArrayAsync())
{ {
var releaseList = release.Adapt<ReleaseList>(); var releaseList = release.Adapt<ReleaseList>();
releaseList.Thumbnail = MakeReleaseThumbnailImage(Configuration, HttpContext, release.RoadieId); releaseList.Thumbnail = ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, release.RoadieId);
var dtoReleaseMedia = new List<ReleaseMediaList>(); var dtoReleaseMedia = new List<ReleaseMediaList>();
if (includes.Contains("tracks")) if (includes.Contains("tracks"))
foreach (var releasemedia in release.Medias.OrderBy(x => x.MediaNumber).ToArray()) foreach (var releasemedia in release.Medias.OrderBy(x => x.MediaNumber).ToArray())
{ {
var dtoMedia = releasemedia.Adapt<ReleaseMediaList>(); var dtoMedia = releasemedia.Adapt<ReleaseMediaList>();
var tracks = new List<TrackList>(); var tracks = new List<TrackList>();
foreach (var t in DbContext.Tracks foreach (var t in await DbContext.Tracks
.Where(x => x.ReleaseMediaId == releasemedia.Id) .Where(x => x.ReleaseMediaId == releasemedia.Id)
.OrderBy(x => x.TrackNumber) .OrderBy(x => x.TrackNumber)
.ToArray()) .ToArrayAsync())
{ {
var track = t.Adapt<TrackList>(); var track = t.Adapt<TrackList>();
ArtistList trackArtist = null; ArtistList trackArtist = null;
@ -939,18 +956,14 @@ namespace Roadie.Api.Services
{ {
var ta = DbContext.Artists.FirstOrDefault(x => x.Id == t.ArtistId.Value); var ta = DbContext.Artists.FirstOrDefault(x => x.Id == t.ArtistId.Value);
if (ta != null) if (ta != null)
trackArtist = ArtistList.FromDataArtist(ta, trackArtist = ArtistList.FromDataArtist(ta, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, ta.RoadieId));
MakeArtistThumbnailImage(Configuration, HttpContext, ta.RoadieId));
} }
track.TrackArtist = trackArtist; track.TrackArtist = trackArtist;
tracks.Add(track); tracks.Add(track);
} }
dtoMedia.Tracks = tracks; dtoMedia.Tracks = tracks;
dtoReleaseMedia.Add(dtoMedia); dtoReleaseMedia.Add(dtoMedia);
} }
releaseList.Media = dtoReleaseMedia; releaseList.Media = dtoReleaseMedia;
dtoReleases.Add(releaseList); dtoReleases.Add(releaseList);
} }
@ -1007,7 +1020,7 @@ namespace Roadie.Api.Services
var artistImagesInFolder = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly); var artistImagesInFolder = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly);
if (artistImagesInFolder.Any()) if (artistImagesInFolder.Any())
{ {
result.Images = artistImagesInFolder.Select((x, i) => MakeFullsizeSecondaryImage(Configuration, HttpContext, id, ImageType.ArtistSecondary, i)); result.Images = artistImagesInFolder.Select((x, i) => ImageHelper.MakeFullsizeSecondaryImage(Configuration, HttpContext, id, ImageType.ArtistSecondary, i));
} }
tsw.Stop(); tsw.Stop();
@ -1017,7 +1030,7 @@ namespace Roadie.Api.Services
if (includes.Contains("associatedartists")) if (includes.Contains("associatedartists"))
{ {
tsw.Restart(); tsw.Restart();
var associatedWithArtists = (from aa in DbContext.ArtistAssociations var associatedWithArtists = await (from aa in DbContext.ArtistAssociations
join a in DbContext.Artists on aa.AssociatedArtistId equals a.Id join a in DbContext.Artists on aa.AssociatedArtistId equals a.Id
where aa.ArtistId == artist.Id where aa.ArtistId == artist.Id
select new ArtistList select new ArtistList
@ -1029,7 +1042,7 @@ namespace Roadie.Api.Services
Text = a.Name, Text = a.Name,
Value = a.RoadieId.ToString() Value = a.RoadieId.ToString()
}, },
Thumbnail = MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId), Thumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId),
Rating = a.Rating, Rating = a.Rating,
Rank = a.Rank, Rank = a.Rank,
CreatedDate = a.CreatedDate, CreatedDate = a.CreatedDate,
@ -1039,9 +1052,9 @@ namespace Roadie.Api.Services
ReleaseCount = a.ReleaseCount, ReleaseCount = a.ReleaseCount,
TrackCount = a.TrackCount, TrackCount = a.TrackCount,
SortName = a.SortName SortName = a.SortName
}).ToArray(); }).ToArrayAsync();
var associatedArtists = (from aa in DbContext.ArtistAssociations var associatedArtists = await (from aa in DbContext.ArtistAssociations
join a in DbContext.Artists on aa.ArtistId equals a.Id join a in DbContext.Artists on aa.ArtistId equals a.Id
where aa.AssociatedArtistId == artist.Id where aa.AssociatedArtistId == artist.Id
select new ArtistList select new ArtistList
@ -1053,7 +1066,7 @@ namespace Roadie.Api.Services
Text = a.Name, Text = a.Name,
Value = a.RoadieId.ToString() Value = a.RoadieId.ToString()
}, },
Thumbnail = MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId), Thumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId),
Rating = a.Rating, Rating = a.Rating,
Rank = a.Rank, Rank = a.Rank,
CreatedDate = a.CreatedDate, CreatedDate = a.CreatedDate,
@ -1063,9 +1076,8 @@ namespace Roadie.Api.Services
ReleaseCount = a.ReleaseCount, ReleaseCount = a.ReleaseCount,
TrackCount = a.TrackCount, TrackCount = a.TrackCount,
SortName = a.SortName SortName = a.SortName
}).ToArray(); }).ToArrayAsync();
result.AssociatedArtists = associatedArtists.Union(associatedWithArtists, new ArtistListComparer()) result.AssociatedArtists = associatedArtists.Union(associatedWithArtists, new ArtistListComparer()).OrderBy(x => x.SortName);
.OrderBy(x => x.SortName);
result.AssociatedArtistsTokens = result.AssociatedArtists.Select(x => x.Artist).ToArray(); result.AssociatedArtistsTokens = result.AssociatedArtists.Select(x => x.Artist).ToArray();
tsw.Stop(); tsw.Stop();
timings.Add("associatedartists", tsw.ElapsedMilliseconds); timings.Add("associatedartists", tsw.ElapsedMilliseconds);
@ -1074,7 +1086,7 @@ namespace Roadie.Api.Services
if (includes.Contains("similarartists")) if (includes.Contains("similarartists"))
{ {
tsw.Restart(); tsw.Restart();
var similarWithArtists = (from aa in DbContext.ArtistSimilar var similarWithArtists = await (from aa in DbContext.ArtistSimilar
join a in DbContext.Artists on aa.SimilarArtistId equals a.Id join a in DbContext.Artists on aa.SimilarArtistId equals a.Id
where aa.ArtistId == artist.Id where aa.ArtistId == artist.Id
select new ArtistList select new ArtistList
@ -1086,7 +1098,7 @@ namespace Roadie.Api.Services
Text = a.Name, Text = a.Name,
Value = a.RoadieId.ToString() Value = a.RoadieId.ToString()
}, },
Thumbnail = MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId), Thumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId),
Rating = a.Rating, Rating = a.Rating,
Rank = a.Rank, Rank = a.Rank,
CreatedDate = a.CreatedDate, CreatedDate = a.CreatedDate,
@ -1096,9 +1108,9 @@ namespace Roadie.Api.Services
ReleaseCount = a.ReleaseCount, ReleaseCount = a.ReleaseCount,
TrackCount = a.TrackCount, TrackCount = a.TrackCount,
SortName = a.SortName SortName = a.SortName
}).ToArray(); }).ToArrayAsync();
var similarArtists = (from aa in DbContext.ArtistSimilar var similarArtists = await (from aa in DbContext.ArtistSimilar
join a in DbContext.Artists on aa.ArtistId equals a.Id join a in DbContext.Artists on aa.ArtistId equals a.Id
where aa.SimilarArtistId == artist.Id where aa.SimilarArtistId == artist.Id
select new ArtistList select new ArtistList
@ -1110,7 +1122,7 @@ namespace Roadie.Api.Services
Text = a.Name, Text = a.Name,
Value = a.RoadieId.ToString() Value = a.RoadieId.ToString()
}, },
Thumbnail = MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId), Thumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId),
Rating = a.Rating, Rating = a.Rating,
Rank = a.Rank, Rank = a.Rank,
CreatedDate = a.CreatedDate, CreatedDate = a.CreatedDate,
@ -1120,9 +1132,8 @@ namespace Roadie.Api.Services
ReleaseCount = a.ReleaseCount, ReleaseCount = a.ReleaseCount,
TrackCount = a.TrackCount, TrackCount = a.TrackCount,
SortName = a.SortName SortName = a.SortName
}).ToArray(); }).ToArrayAsync();
result.SimilarArtists = similarWithArtists.Union(similarArtists, new ArtistListComparer()) result.SimilarArtists = similarWithArtists.Union(similarArtists, new ArtistListComparer()).OrderBy(x => x.SortName);
.OrderBy(x => x.SortName);
result.SimilarArtistsTokens = result.SimilarArtists.Select(x => x.Artist).ToArray(); result.SimilarArtistsTokens = result.SimilarArtists.Select(x => x.Artist).ToArray();
tsw.Stop(); tsw.Stop();
timings.Add("similarartists", tsw.ElapsedMilliseconds); timings.Add("similarartists", tsw.ElapsedMilliseconds);
@ -1135,8 +1146,7 @@ namespace Roadie.Api.Services
{ {
Limit = 100 Limit = 100
}; };
var r = await CollectionService.List(null, var r = await CollectionService.List(null, collectionPagedRequest, artistId: artist.RoadieId);
collectionPagedRequest, artistId: artist.RoadieId);
if (r.IsSuccess) result.CollectionsWithArtistReleases = r.Rows.ToArray(); if (r.IsSuccess) result.CollectionsWithArtistReleases = r.Rows.ToArray();
tsw.Stop(); tsw.Stop();
timings.Add("collections", tsw.ElapsedMilliseconds); timings.Add("collections", tsw.ElapsedMilliseconds);
@ -1145,8 +1155,10 @@ namespace Roadie.Api.Services
if (includes.Contains("comments")) if (includes.Contains("comments"))
{ {
tsw.Restart(); tsw.Restart();
var artistComments = DbContext.Comments.Include(x => x.User).Where(x => x.ArtistId == artist.Id) var artistComments = await DbContext.Comments.Include(x => x.User)
.OrderByDescending(x => x.CreatedDate).ToArray(); .Where(x => x.ArtistId == artist.Id)
.OrderByDescending(x => x.CreatedDate)
.ToArrayAsync();
if (artistComments.Any()) if (artistComments.Any())
{ {
var comments = new List<Comment>(); var comments = new List<Comment>();
@ -1159,7 +1171,7 @@ namespace Roadie.Api.Services
var comment = artistComment.Adapt<Comment>(); var comment = artistComment.Adapt<Comment>();
comment.DatabaseId = artistComment.Id; comment.DatabaseId = artistComment.Id;
comment.User = UserList.FromDataUser(artistComment.User, comment.User = UserList.FromDataUser(artistComment.User,
MakeUserThumbnailImage(Configuration, HttpContext, artistComment.User.RoadieId)); ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, artistComment.User.RoadieId));
comment.DislikedCount = userCommentReactions.Count(x => comment.DislikedCount = userCommentReactions.Count(x =>
x.CommentId == artistComment.Id && x.ReactionValue == CommentReaction.Dislike); x.CommentId == artistComment.Id && x.ReactionValue == CommentReaction.Dislike);
comment.LikedCount = userCommentReactions.Count(x => comment.LikedCount = userCommentReactions.Count(x =>
@ -1198,17 +1210,16 @@ namespace Roadie.Api.Services
join r in DbContext.Releases on rm.ReleaseId equals r.Id join r in DbContext.Releases on rm.ReleaseId equals r.Id
where t.ArtistId == artist.Id where t.ArtistId == artist.Id
select r.Id) select r.Id)
.ToArray()
.Distinct(); .Distinct();
if (artistContributingTracks?.Any() ?? false) if (artistContributingTracks?.Any() ?? false)
{ {
result.ArtistContributionReleases = (from r in DbContext.Releases.Include(x => x.Artist) result.ArtistContributionReleases = (await (from r in DbContext.Releases.Include(x => x.Artist)
where artistContributingTracks.Contains(r.Id) where artistContributingTracks.Contains(r.Id)
select r) select r)
.OrderBy(x => x.Title) .OrderBy(x => x.Title)
.ToArray() .ToArrayAsync())
.Select(r => ReleaseList.FromDataRelease(r, r.Artist, HttpContext.BaseUrl, MakeArtistThumbnailImage(Configuration, HttpContext, r.Artist.RoadieId), MakeReleaseThumbnailImage(Configuration, HttpContext, r.RoadieId))); .Select(r => ReleaseList.FromDataRelease(r, r.Artist, HttpContext.BaseUrl, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, r.Artist.RoadieId), ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, r.RoadieId)));
result.ArtistContributionReleases = result.ArtistContributionReleases.Any() result.ArtistContributionReleases = result.ArtistContributionReleases.Any()
? result.ArtistContributionReleases ? result.ArtistContributionReleases
@ -1221,13 +1232,13 @@ namespace Roadie.Api.Services
if (includes.Contains("labels")) if (includes.Contains("labels"))
{ {
tsw.Restart(); tsw.Restart();
result.ArtistLabels = (from l in DbContext.Labels result.ArtistLabels = (await (from l in DbContext.Labels
join rl in DbContext.ReleaseLabels on l.Id equals rl.LabelId join rl in DbContext.ReleaseLabels on l.Id equals rl.LabelId
join r in DbContext.Releases on rl.ReleaseId equals r.Id join r in DbContext.Releases on rl.ReleaseId equals r.Id
where r.ArtistId == artist.Id where r.ArtistId == artist.Id
orderby l.SortName orderby l.SortName
select LabelList.FromDataLabel(l, MakeLabelThumbnailImage(Configuration, HttpContext, l.RoadieId))) select LabelList.FromDataLabel(l, ImageHelper.MakeLabelThumbnailImage(Configuration, HttpContext, l.RoadieId)))
.ToArray() .ToArrayAsync())
.GroupBy(x => x.Label.Value) .GroupBy(x => x.Label.Value)
.Select(x => x.First()) .Select(x => x.First())
.OrderBy(x => x.SortName) .OrderBy(x => x.SortName)
@ -1466,7 +1477,7 @@ namespace Roadie.Api.Services
return new OperationResult<Library.Models.Image> return new OperationResult<Library.Models.Image>
{ {
IsSuccess = !errors.Any(), IsSuccess = !errors.Any(),
Data = MakeThumbnailImage(Configuration, HttpContext, id, "artist", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height, true), Data = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "artist", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height, true),
OperationTime = sw.ElapsedMilliseconds, OperationTime = sw.ElapsedMilliseconds,
Errors = errors Errors = errors
}; };

View file

@ -5,6 +5,7 @@ using Roadie.Library.Configuration;
using Roadie.Library.Data.Context; using Roadie.Library.Data.Context;
using Roadie.Library.Encoding; using Roadie.Library.Encoding;
using Roadie.Library.Enums; using Roadie.Library.Enums;
using Roadie.Library.Imaging;
using Roadie.Library.Models.Collections; using Roadie.Library.Models.Collections;
using Roadie.Library.Models.Pagination; using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Playlists; using Roadie.Library.Models.Playlists;
@ -34,8 +35,7 @@ namespace Roadie.Api.Services
{ {
} }
public Task<Library.Models.Pagination.PagedResult<models.BookmarkList>> List(User roadieUser, public async Task<Library.Models.Pagination.PagedResult<models.BookmarkList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null)
PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null)
{ {
var sw = new Stopwatch(); var sw = new Stopwatch();
sw.Start(); sw.Start();
@ -66,7 +66,7 @@ namespace Roadie.Api.Services
var rowCount = result.Count(); var rowCount = result.Count();
var rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray(); var rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
foreach (var row in rows) foreach (var row in rows)
switch (row.Type) switch (row.Type)
@ -80,8 +80,8 @@ namespace Roadie.Api.Services
Value = artist.RoadieId.ToString() Value = artist.RoadieId.ToString()
}; };
row.Artist = row.Artist =
models.ArtistList.FromDataArtist(artist, MakeArtistThumbnailImage(Configuration, HttpContext, artist.RoadieId)); models.ArtistList.FromDataArtist(artist, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, artist.RoadieId));
row.Thumbnail = MakeArtistThumbnailImage(Configuration, HttpContext, artist.RoadieId); row.Thumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, artist.RoadieId);
row.SortName = artist.SortName ?? artist.Name; row.SortName = artist.SortName ?? artist.Name;
break; break;
@ -95,9 +95,9 @@ namespace Roadie.Api.Services
Value = release.RoadieId.ToString() Value = release.RoadieId.ToString()
}; };
row.Release = ReleaseList.FromDataRelease(release, release.Artist, HttpContext.BaseUrl, row.Release = ReleaseList.FromDataRelease(release, release.Artist, HttpContext.BaseUrl,
MakeArtistThumbnailImage(Configuration, HttpContext, release.Artist.RoadieId), ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, release.Artist.RoadieId),
MakeReleaseThumbnailImage(Configuration, HttpContext, release.RoadieId)); ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, release.RoadieId));
row.Thumbnail = MakeReleaseThumbnailImage(Configuration, HttpContext, release.RoadieId); row.Thumbnail = ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, release.RoadieId);
row.SortName = release.SortTitleValue; row.SortName = release.SortTitleValue;
break; break;
@ -114,21 +114,21 @@ namespace Roadie.Api.Services
Text = track.Title, Text = track.Title,
Value = track.RoadieId.ToString() Value = track.RoadieId.ToString()
}; };
row.Track = models.TrackList.FromDataTrack(MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.Id, track.RoadieId), row.Track = models.TrackList.FromDataTrack(MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.RoadieId),
track, track,
track.ReleaseMedia.MediaNumber, track.ReleaseMedia.MediaNumber,
track.ReleaseMedia.Release, track.ReleaseMedia.Release,
track.ReleaseMedia.Release.Artist, track.ReleaseMedia.Release.Artist,
track.TrackArtist, track.TrackArtist,
HttpContext.BaseUrl, HttpContext.BaseUrl,
MakeTrackThumbnailImage(Configuration, HttpContext, track.RoadieId), ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, track.RoadieId),
MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId), ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId),
MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId), ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId),
MakeArtistThumbnailImage(Configuration, HttpContext, track.TrackArtist == null ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.TrackArtist == null
? null ? null
: (Guid?)track.TrackArtist.RoadieId)); : (Guid?)track.TrackArtist.RoadieId));
row.Track.TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.Id, track.RoadieId); row.Track.TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.RoadieId);
row.Thumbnail = MakeTrackThumbnailImage(Configuration, HttpContext, track.RoadieId); row.Thumbnail = ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, track.RoadieId);
row.SortName = track.Title; row.SortName = track.Title;
break; break;
@ -143,9 +143,9 @@ namespace Roadie.Api.Services
Value = playlist.RoadieId.ToString() Value = playlist.RoadieId.ToString()
}; };
row.Playlist = PlaylistList.FromDataPlaylist(playlist, playlist.User, row.Playlist = PlaylistList.FromDataPlaylist(playlist, playlist.User,
MakePlaylistThumbnailImage(Configuration, HttpContext, playlist.RoadieId), ImageHelper.MakePlaylistThumbnailImage(Configuration, HttpContext, playlist.RoadieId),
MakeUserThumbnailImage(Configuration, HttpContext, playlist.User.RoadieId)); ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, playlist.User.RoadieId));
row.Thumbnail = MakePlaylistThumbnailImage(Configuration, HttpContext, playlist.RoadieId); row.Thumbnail = ImageHelper.MakePlaylistThumbnailImage(Configuration, HttpContext, playlist.RoadieId);
row.SortName = playlist.Name; row.SortName = playlist.Name;
break; break;
@ -160,8 +160,8 @@ namespace Roadie.Api.Services
row.Collection = CollectionList.FromDataCollection(collection, row.Collection = CollectionList.FromDataCollection(collection,
(from crc in DbContext.CollectionReleases (from crc in DbContext.CollectionReleases
where crc.CollectionId == collection.Id where crc.CollectionId == collection.Id
select crc.Id).Count(), MakeCollectionThumbnailImage(Configuration, HttpContext, collection.RoadieId)); select crc.Id).Count(), ImageHelper.MakeCollectionThumbnailImage(Configuration, HttpContext, collection.RoadieId));
row.Thumbnail = MakeCollectionThumbnailImage(Configuration, HttpContext, collection.RoadieId); row.Thumbnail = ImageHelper.MakeCollectionThumbnailImage(Configuration, HttpContext, collection.RoadieId);
row.SortName = collection.SortName ?? collection.Name; row.SortName = collection.SortName ?? collection.Name;
break; break;
@ -173,22 +173,22 @@ namespace Roadie.Api.Services
Text = label.Name, Text = label.Name,
Value = label.RoadieId.ToString() Value = label.RoadieId.ToString()
}; };
row.Label = models.LabelList.FromDataLabel(label, MakeLabelThumbnailImage(Configuration, HttpContext, label.RoadieId)); row.Label = models.LabelList.FromDataLabel(label, ImageHelper.MakeLabelThumbnailImage(Configuration, HttpContext, label.RoadieId));
row.Thumbnail = MakeLabelThumbnailImage(Configuration, HttpContext, label.RoadieId); row.Thumbnail = ImageHelper.MakeLabelThumbnailImage(Configuration, HttpContext, label.RoadieId);
row.SortName = label.SortName ?? label.Name; row.SortName = label.SortName ?? label.Name;
break; break;
} }
; ;
sw.Stop(); sw.Stop();
return Task.FromResult(new Library.Models.Pagination.PagedResult<models.BookmarkList> return new Library.Models.Pagination.PagedResult<models.BookmarkList>
{ {
TotalCount = rowCount, TotalCount = rowCount,
CurrentPage = request.PageValue, CurrentPage = request.PageValue,
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue), TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
OperationTime = sw.ElapsedMilliseconds, OperationTime = sw.ElapsedMilliseconds,
Rows = rows Rows = rows
}); };
} }
} }
} }

View file

@ -60,8 +60,8 @@ namespace Roadie.Api.Services
}; };
var result = collection.Adapt<Collection>(); var result = collection.Adapt<Collection>();
result.Id = id; result.Id = id;
result.Thumbnail = MakeNewImage("collection"); result.Thumbnail = ImageHelper.MakeNewImage(HttpContext,"collection");
result.MediumThumbnail = MakeNewImage("collection"); result.MediumThumbnail = ImageHelper.MakeNewImage(HttpContext,"collection");
result.Maintainer = new DataToken result.Maintainer = new DataToken
{ {
Value = roadieUser.UserId.ToString(), Value = roadieUser.UserId.ToString(),
@ -94,7 +94,7 @@ namespace Roadie.Api.Services
var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Collection); var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Collection);
if (userBookmarkResult.IsSuccess) if (userBookmarkResult.IsSuccess)
{ {
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Text == result.Data.Id.ToString()) != null; result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Value == result.Data.Id.ToString()) != null;
} }
if (result.Data.Comments.Any()) if (result.Data.Comments.Any())
{ {
@ -215,7 +215,7 @@ namespace Roadie.Api.Services
CreatedDate = c.CreatedDate, CreatedDate = c.CreatedDate,
IsLocked = c.IsLocked, IsLocked = c.IsLocked,
LastUpdated = c.LastUpdated, LastUpdated = c.LastUpdated,
Thumbnail = MakeCollectionThumbnailImage(Configuration, HttpContext, c.RoadieId) Thumbnail = ImageHelper.MakeCollectionThumbnailImage(Configuration, HttpContext, c.RoadieId)
}; };
var sortBy = string.IsNullOrEmpty(request.Sort) var sortBy = string.IsNullOrEmpty(request.Sort)
@ -327,7 +327,7 @@ namespace Roadie.Api.Services
}; };
} }
private Task<OperationResult<Collection>> CollectionByIdAction(Guid id, IEnumerable<string> includes = null) private async Task<OperationResult<Collection>> CollectionByIdAction(Guid id, IEnumerable<string> includes = null)
{ {
var timings = new Dictionary<string, long>(); var timings = new Dictionary<string, long>();
var tsw = new Stopwatch(); var tsw = new Stopwatch();
@ -336,13 +336,13 @@ namespace Roadie.Api.Services
sw.Start(); sw.Start();
tsw.Restart(); tsw.Restart();
var collection = GetCollection(id); var collection = await GetCollection(id);
tsw.Stop(); tsw.Stop();
timings.Add("getCollection", tsw.ElapsedMilliseconds); timings.Add("getCollection", tsw.ElapsedMilliseconds);
if (collection == null) if (collection == null)
{ {
return Task.FromResult(new OperationResult<Collection>(true, string.Format("Collection Not Found [{0}]", id))); return new OperationResult<Collection>(true, string.Format("Collection Not Found [{0}]", id));
} }
var result = collection.Adapt<Collection>(); var result = collection.Adapt<Collection>();
var maintainer = DbContext.Users.FirstOrDefault(x => x.Id == collection.MaintainerId); var maintainer = DbContext.Users.FirstOrDefault(x => x.Id == collection.MaintainerId);
@ -354,8 +354,8 @@ namespace Roadie.Api.Services
result.AlternateNames = collection.AlternateNames; result.AlternateNames = collection.AlternateNames;
result.Tags = collection.Tags; result.Tags = collection.Tags;
result.URLs = collection.URLs; result.URLs = collection.URLs;
result.Thumbnail = MakeCollectionThumbnailImage(Configuration, HttpContext, collection.RoadieId); result.Thumbnail = ImageHelper.MakeCollectionThumbnailImage(Configuration, HttpContext, collection.RoadieId);
result.MediumThumbnail = MakeThumbnailImage(Configuration, HttpContext, id, "collection", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height); result.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "collection", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
result.CollectionFoundCount = (from crc in DbContext.CollectionReleases result.CollectionFoundCount = (from crc in DbContext.CollectionReleases
where crc.CollectionId == collection.Id where crc.CollectionId == collection.Id
select crc.Id).Count(); select crc.Id).Count();
@ -384,7 +384,7 @@ namespace Roadie.Api.Services
select new CollectionRelease select new CollectionRelease
{ {
ListNumber = crc.ListNumber, ListNumber = crc.ListNumber,
Release = ReleaseList.FromDataRelease(r, r.Artist, HttpContext.BaseUrl, MakeArtistThumbnailImage(Configuration, HttpContext, r.Artist.RoadieId), MakeReleaseThumbnailImage(Configuration, HttpContext, r.RoadieId)) Release = ReleaseList.FromDataRelease(r, r.Artist, HttpContext.BaseUrl, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, r.Artist.RoadieId), ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, r.RoadieId))
}).ToArray(); }).ToArray();
tsw.Stop(); tsw.Stop();
timings.Add("releases", tsw.ElapsedMilliseconds); timings.Add("releases", tsw.ElapsedMilliseconds);
@ -438,7 +438,7 @@ namespace Roadie.Api.Services
{ {
var comment = collectionComment.Adapt<Comment>(); var comment = collectionComment.Adapt<Comment>();
comment.DatabaseId = collectionComment.Id; comment.DatabaseId = collectionComment.Id;
comment.User = UserList.FromDataUser(collectionComment.User, MakeUserThumbnailImage(Configuration, HttpContext, collectionComment.User.RoadieId)); comment.User = UserList.FromDataUser(collectionComment.User, ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, collectionComment.User.RoadieId));
comment.DislikedCount = userCommentReactions.Count(x => x.CommentId == collectionComment.Id && x.ReactionValue == CommentReaction.Dislike); comment.DislikedCount = userCommentReactions.Count(x => x.CommentId == collectionComment.Id && x.ReactionValue == CommentReaction.Dislike);
comment.LikedCount = userCommentReactions.Count(x => x.CommentId == collectionComment.Id && x.ReactionValue == CommentReaction.Like); comment.LikedCount = userCommentReactions.Count(x => x.CommentId == collectionComment.Id && x.ReactionValue == CommentReaction.Like);
comments.Add(comment); comments.Add(comment);
@ -451,12 +451,12 @@ namespace Roadie.Api.Services
} }
Logger.LogInformation($"ByIdAction: Collection `{ collection }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]"); Logger.LogInformation($"ByIdAction: Collection `{ collection }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]");
sw.Stop(); sw.Stop();
return Task.FromResult(new OperationResult<Collection> return new OperationResult<Collection>
{ {
Data = result, Data = result,
IsSuccess = result != null, IsSuccess = result != null,
OperationTime = sw.ElapsedMilliseconds OperationTime = sw.ElapsedMilliseconds
}); };
} }
} }
} }

View file

@ -129,9 +129,8 @@ namespace Roadie.Api.Services
ArtistCount = artistCount, ArtistCount = artistCount,
CreatedDate = g.CreatedDate, CreatedDate = g.CreatedDate,
LastUpdated = g.LastUpdated, LastUpdated = g.LastUpdated,
Thumbnail = MakeGenreThumbnailImage(Configuration, HttpContext, g.RoadieId) Thumbnail = ImageHelper.MakeGenreThumbnailImage(Configuration, HttpContext, g.RoadieId)
}; };
GenreList[] rows; GenreList[] rows;
rowCount = rowCount ?? result.Count(); rowCount = rowCount ?? result.Count();
if (doRandomize ?? false) if (doRandomize ?? false)
@ -276,8 +275,8 @@ namespace Roadie.Api.Services
var result = genre.Adapt<Genre>(); var result = genre.Adapt<Genre>();
result.AlternateNames = genre.AlternateNames; result.AlternateNames = genre.AlternateNames;
result.Tags = genre.Tags; result.Tags = genre.Tags;
result.Thumbnail = MakeGenreThumbnailImage(Configuration, HttpContext, genre.RoadieId); result.Thumbnail = ImageHelper.MakeGenreThumbnailImage(Configuration, HttpContext, genre.RoadieId);
result.MediumThumbnail = MakeThumbnailImage(Configuration, HttpContext, id, "genre", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height); result.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "genre", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
tsw.Stop(); tsw.Stop();
timings.Add("adapt", tsw.ElapsedMilliseconds); timings.Add("adapt", tsw.ElapsedMilliseconds);
if (includes != null && includes.Any()) if (includes != null && includes.Any())
@ -344,7 +343,7 @@ namespace Roadie.Api.Services
return new OperationResult<Library.Models.Image> return new OperationResult<Library.Models.Image>
{ {
IsSuccess = !errors.Any(), IsSuccess = !errors.Any(),
Data = MakeThumbnailImage(Configuration, HttpContext, id, "genre", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height, true), Data = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "genre", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height, true),
OperationTime = sw.ElapsedMilliseconds, OperationTime = sw.ElapsedMilliseconds,
Errors = errors Errors = errors
}; };

View file

@ -20,8 +20,6 @@ namespace Roadie.Api.Services
Task<FileOperationResult<IImage>> ArtistSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null); Task<FileOperationResult<IImage>> ArtistSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> ById(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> CollectionImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null); Task<FileOperationResult<IImage>> CollectionImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> GenreImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null); Task<FileOperationResult<IImage>> GenreImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);

View file

@ -24,5 +24,7 @@ namespace Roadie.Api.Services
Task<OperationResult<IEnumerable<DataToken>>> RequestStatus(); Task<OperationResult<IEnumerable<DataToken>>> RequestStatus();
Task<OperationResult<IEnumerable<DataToken>>> Status(); Task<OperationResult<IEnumerable<DataToken>>> Status();
Task<OperationResult<IEnumerable<DataToken>>> CreditCategories();
} }
} }

View file

@ -11,11 +11,9 @@ namespace Roadie.Api.Services
Task<SubsonicOperationResult<SubsonicAuthenticateResponse>> Authenticate(Request request); Task<SubsonicOperationResult<SubsonicAuthenticateResponse>> Authenticate(Request request);
Task<SubsonicOperationResult<Response>> CreateBookmark(Request request, User roadieUser, int position, Task<SubsonicOperationResult<Response>> CreateBookmark(Request request, User roadieUser, int position, string comment);
string comment);
Task<SubsonicOperationResult<Response>> CreatePlaylist(Request request, User roadieUser, string name, Task<SubsonicOperationResult<Response>> CreatePlaylist(Request request, User roadieUser, string name, string[] songIds, string playlistId = null);
string[] songIds, string playlistId = null);
Task<SubsonicOperationResult<Response>> DeleteBookmark(Request request, User roadieUser); Task<SubsonicOperationResult<Response>> DeleteBookmark(Request request, User roadieUser);
@ -23,16 +21,13 @@ namespace Roadie.Api.Services
Task<SubsonicOperationResult<Response>> GetAlbum(Request request, User roadieUser); Task<SubsonicOperationResult<Response>> GetAlbum(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> Task<SubsonicOperationResult<Response>> GetAlbumInfo(Request request, User roadieUser, AlbumInfoVersion version);
GetAlbumInfo(Request request, User roadieUser, AlbumInfoVersion version);
Task<SubsonicOperationResult<Response>> GetAlbumList(Request request, User roadieUser, Task<SubsonicOperationResult<Response>> GetAlbumList(Request request, User roadieUser, AlbumListVersions version);
AlbumListVersions version);
Task<SubsonicOperationResult<Response>> GetArtist(Request request, User roadieUser); Task<SubsonicOperationResult<Response>> GetArtist(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetArtistInfo(Request request, int? count, bool includeNotPresent, Task<SubsonicOperationResult<Response>> GetArtistInfo(Request request, int? count, bool includeNotPresent, ArtistInfoVersion version);
ArtistInfoVersion version);
Task<SubsonicOperationResult<Response>> GetArtists(Request request, User roadieUser); Task<SubsonicOperationResult<Response>> GetArtists(Request request, User roadieUser);
@ -40,12 +35,11 @@ namespace Roadie.Api.Services
Task<SubsonicOperationResult<Response>> GetChatMessages(Request request, User roadieUser, long? since); Task<SubsonicOperationResult<Response>> GetChatMessages(Request request, User roadieUser, long? since);
Task<SubsonicFileOperationResult<Image>> GetCoverArt(Request request, int? size); Task<SubsonicFileOperationResult<Library.Models.Image>> GetCoverArt(Request request, int? size);
Task<SubsonicOperationResult<Response>> GetGenres(Request request); Task<SubsonicOperationResult<Response>> GetGenres(Request request);
Task<SubsonicOperationResult<Response>> GetIndexes(Request request, User roadieUser, Task<SubsonicOperationResult<Response>> GetIndexes(Request request, User roadieUser, long? ifModifiedSince = null);
long? ifModifiedSince = null);
SubsonicOperationResult<Response> GetLicense(Request request); SubsonicOperationResult<Response> GetLicense(Request request);
@ -67,8 +61,7 @@ namespace Roadie.Api.Services
Task<SubsonicOperationResult<Response>> GetRandomSongs(Request request, User roadieUser); Task<SubsonicOperationResult<Response>> GetRandomSongs(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetSimliarSongs(Request request, User roadieUser, Task<SubsonicOperationResult<Response>> GetSimliarSongs(Request request, User roadieUser, SimilarSongsVersion version, int? count = 50);
SimilarSongsVersion version, int? count = 50);
Task<SubsonicOperationResult<Response>> GetSong(Request request, User roadieUser); Task<SubsonicOperationResult<Response>> GetSong(Request request, User roadieUser);
@ -84,15 +77,13 @@ namespace Roadie.Api.Services
SubsonicOperationResult<Response> Ping(Request request); SubsonicOperationResult<Response> Ping(Request request);
Task<SubsonicOperationResult<Response>> SavePlayQueue(Request request, User roadieUser, string current, Task<SubsonicOperationResult<Response>> SavePlayQueue(Request request, User roadieUser, string current, long? position);
long? position);
Task<SubsonicOperationResult<Response>> Search(Request request, User roadieUser, SearchVersion version); Task<SubsonicOperationResult<Response>> Search(Request request, User roadieUser, SearchVersion version);
Task<SubsonicOperationResult<Response>> SetRating(Request request, User roadieUser, short rating); Task<SubsonicOperationResult<Response>> SetRating(Request request, User roadieUser, short rating);
Task<SubsonicOperationResult<Response>> ToggleStar(Request request, User roadieUser, bool star, Task<SubsonicOperationResult<Response>> ToggleStar(Request request, User roadieUser, bool star, string[] albumIds = null, string[] artistIds = null);
string[] albumIds = null, string[] artistIds = null);
Task<SubsonicOperationResult<Response>> UpdatePlaylist(Request request, User roadieUser, string playlistId, Task<SubsonicOperationResult<Response>> UpdatePlaylist(Request request, User roadieUser, string playlistId,
string name = null, string comment = null, bool? isPublic = null, string[] songIdsToAdd = null, string name = null, string comment = null, bool? isPublic = null, string[] songIdsToAdd = null,

View file

@ -13,6 +13,8 @@ namespace Roadie.Api.Services
Task<PagedResult<UserList>> List(PagedRequest request); Task<PagedResult<UserList>> List(PagedRequest request);
Task<OperationResult<bool>> DeleteAllBookmarks(User roadieUser);
Task<OperationResult<bool>> SetArtistBookmark(Guid artistId, User roadieUser, bool isBookmarked); Task<OperationResult<bool>> SetArtistBookmark(Guid artistId, User roadieUser, bool isBookmarked);
Task<OperationResult<bool>> SetArtistDisliked(Guid artistId, User roadieUser, bool isDisliked); Task<OperationResult<bool>> SetArtistDisliked(Guid artistId, User roadieUser, bool isDisliked);

View file

@ -1,5 +1,4 @@
using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
using Roadie.Library; using Roadie.Library;
using Roadie.Library.Caching; using Roadie.Library.Caching;
@ -44,7 +43,7 @@ namespace Roadie.Api.Services
ImageSearchManager = imageSearchManager; ImageSearchManager = imageSearchManager;
} }
public ImageService(IRoadieSettings configuration, IRoadieDbContext dbContext, ICacheManager cacheManager, public ImageService(IRoadieSettings configuration, IRoadieDbContext dbContext, ICacheManager cacheManager,
ILogger logger, DefaultNotFoundImages defaultNotFoundImages) ILogger logger, DefaultNotFoundImages defaultNotFoundImages)
: base(configuration, null, dbContext, cacheManager, logger, null) : base(configuration, null, dbContext, cacheManager, logger, null)
{ {
@ -73,17 +72,6 @@ namespace Roadie.Api.Services
etag); etag);
} }
public async Task<FileOperationResult<IImage>> ById(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await GetImageFileOperation("ImageById",
Library.Imaging.Image.CacheRegionUrn(id),
id,
width,
height,
async () => { return await ImageByIdAction(id, etag); },
etag);
}
public async Task<FileOperationResult<IImage>> CollectionImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null) public async Task<FileOperationResult<IImage>> CollectionImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{ {
return await GetImageFileOperation("CollectionThumbnail", return await GetImageFileOperation("CollectionThumbnail",
@ -201,14 +189,14 @@ namespace Roadie.Api.Services
/// <summary> /// <summary>
/// Get image for an artist, see if the artist has an image in their folder and use that else use Artist.Thumbnail, is also not found use Artist DefaultNotFound image. /// Get image for an artist, see if the artist has an image in their folder and use that else use Artist.Thumbnail, is also not found use Artist DefaultNotFound image.
/// </summary> /// </summary>
private Task<FileOperationResult<IImage>> ArtistImageAction(Guid id, EntityTagHeaderValue etag = null) private async Task<FileOperationResult<IImage>> ArtistImageAction(Guid id, EntityTagHeaderValue etag = null)
{ {
try try
{ {
var artist = GetArtist(id); var artist = await GetArtist(id);
if (artist == null) if (artist == null)
{ {
return Task.FromResult(new FileOperationResult<IImage>(true, string.Format("Artist Not Found [{0}]", id))); return new FileOperationResult<IImage>(true, string.Format("Artist Not Found [{0}]", id));
} }
byte[] imageBytes = null; byte[] imageBytes = null;
string artistFolder = null; string artistFolder = null;
@ -242,24 +230,24 @@ namespace Roadie.Api.Services
{ {
image = DefaultNotFoundImages.Artist; image = DefaultNotFoundImages.Artist;
} }
return Task.FromResult(GenerateFileOperationResult(id, image, etag)); return GenerateFileOperationResult(id, image, etag);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogError($"Error fetching Artist Thumbnail [{id}]", ex); Logger.LogError($"Error fetching Artist Thumbnail [{id}]", ex);
} }
return Task.FromResult(new FileOperationResult<IImage>(OperationMessages.ErrorOccured)); return new FileOperationResult<IImage>(OperationMessages.ErrorOccured);
} }
private Task<FileOperationResult<IImage>> ArtistSecondaryImageAction(Guid id, int imageId, EntityTagHeaderValue etag = null) private async Task<FileOperationResult<IImage>> ArtistSecondaryImageAction(Guid id, int imageId, EntityTagHeaderValue etag = null)
{ {
try try
{ {
var artist = GetArtist(id); var artist = await GetArtist(id);
if (artist == null) if (artist == null)
{ {
return Task.FromResult(new FileOperationResult<IImage>(true, string.Format("Release Not Found [{0}]", id))); return new FileOperationResult<IImage>(true, string.Format("Release Not Found [{0}]", id));
} }
byte[] imageBytes = null; byte[] imageBytes = null;
string artistFolder = null; string artistFolder = null;
@ -290,24 +278,24 @@ namespace Roadie.Api.Services
Bytes = imageBytes, Bytes = imageBytes,
CreatedDate = artist.CreatedDate CreatedDate = artist.CreatedDate
}; };
return Task.FromResult(GenerateFileOperationResult(id, image, etag)); return GenerateFileOperationResult(id, image, etag);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogError($"Error fetching Release Thumbnail [{id}]", ex); Logger.LogError($"Error fetching Release Thumbnail [{id}]", ex);
} }
return Task.FromResult(new FileOperationResult<IImage>(OperationMessages.ErrorOccured)); return new FileOperationResult<IImage>(OperationMessages.ErrorOccured);
} }
private Task<FileOperationResult<IImage>> CollectionImageAction(Guid id, EntityTagHeaderValue etag = null) private async Task<FileOperationResult<IImage>> CollectionImageAction(Guid id, EntityTagHeaderValue etag = null)
{ {
try try
{ {
var collection = GetCollection(id); var collection = await GetCollection(id);
if (collection == null) if (collection == null)
{ {
return Task.FromResult(new FileOperationResult<IImage>(true, string.Format("Collection Not Found [{0}]", id))); return new FileOperationResult<IImage>(true, string.Format("Collection Not Found [{0}]", id));
} }
IImage image = new Library.Imaging.Image(id) IImage image = new Library.Imaging.Image(id)
{ {
@ -329,14 +317,14 @@ namespace Roadie.Api.Services
{ {
image = DefaultNotFoundImages.Collection; image = DefaultNotFoundImages.Collection;
} }
return Task.FromResult(GenerateFileOperationResult(id, image, etag)); return GenerateFileOperationResult(id, image, etag);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogError($"Error fetching Collection Thumbnail [{id}]", ex); Logger.LogError($"Error fetching Collection Thumbnail [{id}]", ex);
} }
return Task.FromResult(new FileOperationResult<IImage>(OperationMessages.ErrorOccured)); return new FileOperationResult<IImage>(OperationMessages.ErrorOccured);
} }
private FileOperationResult<IImage> GenerateFileOperationResult(Guid id, IImage image, EntityTagHeaderValue etag = null, string contentType = "image/jpeg") private FileOperationResult<IImage> GenerateFileOperationResult(Guid id, IImage image, EntityTagHeaderValue etag = null, string contentType = "image/jpeg")
@ -362,14 +350,14 @@ namespace Roadie.Api.Services
}; };
} }
private Task<FileOperationResult<IImage>> GenreImageAction(Guid id, EntityTagHeaderValue etag = null) private async Task<FileOperationResult<IImage>> GenreImageAction(Guid id, EntityTagHeaderValue etag = null)
{ {
try try
{ {
var genre = GetGenre(id); var genre = await GetGenre(id);
if (genre == null) if (genre == null)
{ {
return Task.FromResult(new FileOperationResult<IImage>(true, string.Format("Genre Not Found [{0}]", id))); return new FileOperationResult<IImage>(true, string.Format("Genre Not Found [{0}]", id));
} }
IImage image = new Library.Imaging.Image(id) IImage image = new Library.Imaging.Image(id)
{ {
@ -391,14 +379,14 @@ namespace Roadie.Api.Services
{ {
image = DefaultNotFoundImages.Genre; image = DefaultNotFoundImages.Genre;
} }
return Task.FromResult(GenerateFileOperationResult(id, image, etag)); return GenerateFileOperationResult(id, image, etag);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogError($"Error fetching Label Thumbnail [{id}]", ex); Logger.LogError($"Error fetching Label Thumbnail [{id}]", ex);
} }
return Task.FromResult(new FileOperationResult<IImage>(OperationMessages.ErrorOccured)); return new FileOperationResult<IImage>(OperationMessages.ErrorOccured);
} }
private async Task<FileOperationResult<IImage>> GetImageFileOperation(string type, string regionUrn, Guid id, int? width, int? height, Func<Task<FileOperationResult<IImage>>> action, EntityTagHeaderValue etag = null) private async Task<FileOperationResult<IImage>> GetImageFileOperation(string type, string regionUrn, Guid id, int? width, int? height, Func<Task<FileOperationResult<IImage>>> action, EntityTagHeaderValue etag = null)
@ -458,40 +446,15 @@ namespace Roadie.Api.Services
return new FileOperationResult<IImage>("System Error"); return new FileOperationResult<IImage>("System Error");
} }
private Task<FileOperationResult<IImage>> ImageByIdAction(Guid id, EntityTagHeaderValue etag = null) private async Task<FileOperationResult<IImage>> LabelImageAction(Guid id, EntityTagHeaderValue etag = null)
{ {
try try
{ {
// TODO #29; fetch image by ID var label = await GetLabel(id);
throw new NotImplementedException();
//var image = DbContext.Images
// .Include("Release")
// .Include("Artist")
// .FirstOrDefault(x => x.RoadieId == id);
//if (image == null)
//{
// return Task.FromResult(new FileOperationResult<IImage>(true, string.Format("ImageById Not Found [{0}]", id)));
//}
//return Task.FromResult(GenerateFileOperationResult(id, image, etag));
}
catch (Exception ex)
{
Logger.LogError($"Error fetching Image [{id}]", ex);
}
return Task.FromResult(new FileOperationResult<IImage>(OperationMessages.ErrorOccured));
}
private Task<FileOperationResult<IImage>> LabelImageAction(Guid id, EntityTagHeaderValue etag = null)
{
try
{
var label = GetLabel(id);
if (label == null) if (label == null)
return Task.FromResult(new FileOperationResult<IImage>(true, {
string.Format("Label Not Found [{0}]", id))); return new FileOperationResult<IImage>(true, string.Format("Label Not Found [{0}]", id));
}
IImage image = new Library.Imaging.Image(id) IImage image = new Library.Imaging.Image(id)
{ {
CreatedDate = label.CreatedDate CreatedDate = label.CreatedDate
@ -512,24 +475,25 @@ namespace Roadie.Api.Services
{ {
image = DefaultNotFoundImages.Label; image = DefaultNotFoundImages.Label;
} }
return Task.FromResult(GenerateFileOperationResult(id, image, etag)); return GenerateFileOperationResult(id, image, etag);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogError($"Error fetching Label Thumbnail [{id}]", ex); Logger.LogError($"Error fetching Label Thumbnail [{id}]", ex);
} }
return Task.FromResult(new FileOperationResult<IImage>(OperationMessages.ErrorOccured)); return new FileOperationResult<IImage>(OperationMessages.ErrorOccured);
} }
private Task<FileOperationResult<IImage>> PlaylistImageAction(Guid id, EntityTagHeaderValue etag = null) private async Task<FileOperationResult<IImage>> PlaylistImageAction(Guid id, EntityTagHeaderValue etag = null)
{ {
try try
{ {
var playlist = GetPlaylist(id); var playlist = await GetPlaylist(id);
if (playlist == null) if (playlist == null)
return Task.FromResult(new FileOperationResult<IImage>(true, {
string.Format("Playlist Not Found [{0}]", id))); return new FileOperationResult<IImage>(true, string.Format("Playlist Not Found [{0}]", id));
}
IImage image = new Library.Imaging.Image(id) IImage image = new Library.Imaging.Image(id)
{ {
CreatedDate = playlist.CreatedDate CreatedDate = playlist.CreatedDate
@ -550,27 +514,27 @@ namespace Roadie.Api.Services
{ {
image = DefaultNotFoundImages.Playlist; image = DefaultNotFoundImages.Playlist;
} }
return Task.FromResult(GenerateFileOperationResult(id, image, etag)); return GenerateFileOperationResult(id, image, etag);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogError($"Error fetching Playlist Thumbnail [{id}]", ex); Logger.LogError($"Error fetching Playlist Thumbnail [{id}]", ex);
} }
return Task.FromResult(new FileOperationResult<IImage>(OperationMessages.ErrorOccured)); return new FileOperationResult<IImage>(OperationMessages.ErrorOccured);
} }
/// <summary> /// <summary>
/// Get image for Release from Release folder, if not exists then use Release.Thumbnail if that is not set then use Release DefaultNotFound image. /// Get image for Release from Release folder, if not exists then use Release.Thumbnail if that is not set then use Release DefaultNotFound image.
/// </summary> /// </summary>
private Task<FileOperationResult<IImage>> ReleaseImageAction(Guid id, EntityTagHeaderValue etag = null) private async Task<FileOperationResult<IImage>> ReleaseImageAction(Guid id, EntityTagHeaderValue etag = null)
{ {
try try
{ {
var release = GetRelease(id); var release = await GetRelease(id);
if (release == null) if (release == null)
{ {
return Task.FromResult(new FileOperationResult<IImage>(true, string.Format("Release Not Found [{0}]", id))); return new FileOperationResult<IImage>(true, string.Format("Release Not Found [{0}]", id));
} }
byte[] imageBytes = null; byte[] imageBytes = null;
string artistFolder = null; string artistFolder = null;
@ -613,25 +577,24 @@ namespace Roadie.Api.Services
{ {
image = DefaultNotFoundImages.Release; image = DefaultNotFoundImages.Release;
} }
return Task.FromResult(GenerateFileOperationResult(id, image, etag)); return GenerateFileOperationResult(id, image, etag);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogError($"Error fetching Release Thumbnail [{id}]", ex); Logger.LogError($"Error fetching Release Thumbnail [{id}]", ex);
} }
return Task.FromResult(new FileOperationResult<IImage>(OperationMessages.ErrorOccured)); return new FileOperationResult<IImage>(OperationMessages.ErrorOccured);
} }
private Task<FileOperationResult<IImage>> ReleaseSecondaryImageAction(Guid id, int imageId, private async Task<FileOperationResult<IImage>> ReleaseSecondaryImageAction(Guid id, int imageId, EntityTagHeaderValue etag = null)
EntityTagHeaderValue etag = null)
{ {
try try
{ {
var release = GetRelease(id); var release = await GetRelease(id);
if (release == null) if (release == null)
{ {
return Task.FromResult(new FileOperationResult<IImage>(true, string.Format("Release Not Found [{0}]", id))); return new FileOperationResult<IImage>(true, string.Format("Release Not Found [{0}]", id));
} }
byte[] imageBytes = null; byte[] imageBytes = null;
string artistFolder = null; string artistFolder = null;
@ -672,21 +635,21 @@ namespace Roadie.Api.Services
Bytes = imageBytes, Bytes = imageBytes,
CreatedDate = release.CreatedDate CreatedDate = release.CreatedDate
}; };
return Task.FromResult(GenerateFileOperationResult(id, image, etag)); return GenerateFileOperationResult(id, image, etag);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogError($"Error fetching Release Thumbnail [{id}]", ex); Logger.LogError($"Error fetching Release Thumbnail [{id}]", ex);
} }
return Task.FromResult(new FileOperationResult<IImage>(OperationMessages.ErrorOccured)); return new FileOperationResult<IImage>(OperationMessages.ErrorOccured);
} }
private async Task<FileOperationResult<IImage>> TrackImageAction(Guid id, int? width, int? height, EntityTagHeaderValue etag = null) private async Task<FileOperationResult<IImage>> TrackImageAction(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{ {
try try
{ {
var track = GetTrack(id); var track = await GetTrack(id);
if (track == null) if (track == null)
{ {
return new FileOperationResult<IImage>(true, string.Format("Track Not Found [{0}]", id)); return new FileOperationResult<IImage>(true, string.Format("Track Not Found [{0}]", id));
@ -715,14 +678,14 @@ namespace Roadie.Api.Services
return new FileOperationResult<IImage>(OperationMessages.ErrorOccured); return new FileOperationResult<IImage>(OperationMessages.ErrorOccured);
} }
private Task<FileOperationResult<IImage>> UserImageAction(Guid id, EntityTagHeaderValue etag = null) private async Task<FileOperationResult<IImage>> UserImageAction(Guid id, EntityTagHeaderValue etag = null)
{ {
try try
{ {
var user = GetUser(id); var user = await GetUser(id);
if (user == null) if (user == null)
{ {
return Task.FromResult(new FileOperationResult<IImage>(true, string.Format("User Not Found [{0}]", id))); return new FileOperationResult<IImage>(true, string.Format("User Not Found [{0}]", id));
} }
IImage image = new Library.Imaging.Image(id) IImage image = new Library.Imaging.Image(id)
{ {
@ -744,14 +707,14 @@ namespace Roadie.Api.Services
{ {
image = DefaultNotFoundImages.User; image = DefaultNotFoundImages.User;
} }
return Task.FromResult(GenerateFileOperationResult(id, image, etag, "image/png")); return GenerateFileOperationResult(id, image, etag, "image/png");
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogError($"Error fetching User Thumbnail [{id}]", ex); Logger.LogError($"Error fetching User Thumbnail [{id}]", ex);
} }
return Task.FromResult(new FileOperationResult<IImage>(OperationMessages.ErrorOccured)); return new FileOperationResult<IImage>(OperationMessages.ErrorOccured);
} }
} }
} }

View file

@ -57,7 +57,7 @@ namespace Roadie.Api.Services
var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Label); var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Label);
if (userBookmarkResult.IsSuccess) if (userBookmarkResult.IsSuccess)
{ {
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Text == result.Data.Id.ToString()) != null; result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Value == result.Data.Id.ToString()) != null;
} }
if (result.Data.Comments.Any()) if (result.Data.Comments.Any())
{ {
@ -162,7 +162,7 @@ namespace Roadie.Api.Services
ArtistCount = l.ArtistCount, ArtistCount = l.ArtistCount,
ReleaseCount = l.ReleaseCount, ReleaseCount = l.ReleaseCount,
TrackCount = l.TrackCount, TrackCount = l.TrackCount,
Thumbnail = MakeLabelThumbnailImage(Configuration, HttpContext, l.RoadieId) Thumbnail = ImageHelper.MakeLabelThumbnailImage(Configuration, HttpContext, l.RoadieId)
}; };
LabelList[] rows = null; LabelList[] rows = null;
rowCount = rowCount ?? result.Count(); rowCount = rowCount ?? result.Count();
@ -356,7 +356,7 @@ namespace Roadie.Api.Services
return await SaveImageBytes(user, id, bytes); return await SaveImageBytes(user, id, bytes);
} }
private Task<OperationResult<Label>> LabelByIdAction(Guid id, IEnumerable<string> includes = null) private async Task<OperationResult<Label>> LabelByIdAction(Guid id, IEnumerable<string> includes = null)
{ {
var timings = new Dictionary<string, long>(); var timings = new Dictionary<string, long>();
var tsw = new Stopwatch(); var tsw = new Stopwatch();
@ -365,20 +365,20 @@ namespace Roadie.Api.Services
sw.Start(); sw.Start();
tsw.Restart(); tsw.Restart();
var label = GetLabel(id); var label = await GetLabel(id);
tsw.Stop(); tsw.Stop();
timings.Add("GetLabel", tsw.ElapsedMilliseconds); timings.Add("GetLabel", tsw.ElapsedMilliseconds);
if (label == null) if (label == null)
{ {
return Task.FromResult(new OperationResult<Label>(true, string.Format("Label Not Found [{0}]", id))); return new OperationResult<Label>(true, string.Format("Label Not Found [{0}]", id));
} }
tsw.Restart(); tsw.Restart();
var result = label.Adapt<Label>(); var result = label.Adapt<Label>();
result.AlternateNames = label.AlternateNames; result.AlternateNames = label.AlternateNames;
result.Tags = label.Tags; result.Tags = label.Tags;
result.URLs = label.URLs; result.URLs = label.URLs;
result.Thumbnail = MakeLabelThumbnailImage(Configuration, HttpContext, label.RoadieId); result.Thumbnail = ImageHelper.MakeLabelThumbnailImage(Configuration, HttpContext, label.RoadieId);
result.MediumThumbnail = MakeThumbnailImage(Configuration, HttpContext, id, "label", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height); result.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "label", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
tsw.Stop(); tsw.Stop();
timings.Add("adapt", tsw.ElapsedMilliseconds); timings.Add("adapt", tsw.ElapsedMilliseconds);
if (includes != null && includes.Any()) if (includes != null && includes.Any())
@ -430,7 +430,7 @@ namespace Roadie.Api.Services
{ {
var comment = labelComment.Adapt<Comment>(); var comment = labelComment.Adapt<Comment>();
comment.DatabaseId = labelComment.Id; comment.DatabaseId = labelComment.Id;
comment.User = UserList.FromDataUser(labelComment.User, MakeUserThumbnailImage(Configuration, HttpContext, labelComment.User.RoadieId)); comment.User = UserList.FromDataUser(labelComment.User, ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, labelComment.User.RoadieId));
comment.DislikedCount = userCommentReactions.Count(x => x.CommentId == labelComment.Id && x.ReactionValue == CommentReaction.Dislike); comment.DislikedCount = userCommentReactions.Count(x => x.CommentId == labelComment.Id && x.ReactionValue == CommentReaction.Dislike);
comment.LikedCount = userCommentReactions.Count(x => x.CommentId == labelComment.Id && x.ReactionValue == CommentReaction.Like); comment.LikedCount = userCommentReactions.Count(x => x.CommentId == labelComment.Id && x.ReactionValue == CommentReaction.Like);
comments.Add(comment); comments.Add(comment);
@ -444,12 +444,12 @@ namespace Roadie.Api.Services
sw.Stop(); sw.Stop();
Logger.LogInformation($"ByIdAction: Label `{ label }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]"); Logger.LogInformation($"ByIdAction: Label `{ label }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]");
return Task.FromResult(new OperationResult<Label> return new OperationResult<Label>
{ {
Data = result, Data = result,
IsSuccess = result != null, IsSuccess = result != null,
OperationTime = sw.ElapsedMilliseconds OperationTime = sw.ElapsedMilliseconds
}); };
} }
private async Task<OperationResult<Library.Models.Image>> SaveImageBytes(User user, Guid id, byte[] imageBytes) private async Task<OperationResult<Library.Models.Image>> SaveImageBytes(User user, Guid id, byte[] imageBytes)
@ -483,7 +483,7 @@ namespace Roadie.Api.Services
return new OperationResult<Library.Models.Image> return new OperationResult<Library.Models.Image>
{ {
IsSuccess = !errors.Any(), IsSuccess = !errors.Any(),
Data = MakeThumbnailImage(Configuration, HttpContext, id, "label", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height, true), Data = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "label", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height, true),
OperationTime = sw.ElapsedMilliseconds, OperationTime = sw.ElapsedMilliseconds,
Errors = errors Errors = errors
}; };

View file

@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Roadie.Library; using Roadie.Library;
using Roadie.Library.Caching; using Roadie.Library.Caching;
using Roadie.Library.Configuration; using Roadie.Library.Configuration;
@ -21,6 +22,8 @@ namespace Roadie.Api.Services
/// </summary> /// </summary>
public class LookupService : ServiceBase, ILookupService public class LookupService : ServiceBase, ILookupService
{ {
public const string CreditCategoriesCacheKey = "urn:creditCategories";
public LookupService(IRoadieSettings configuration, public LookupService(IRoadieSettings configuration,
IHttpEncoder httpEncoder, IHttpEncoder httpEncoder,
IHttpContext httpContext, IHttpContext httpContext,
@ -119,6 +122,25 @@ namespace Roadie.Api.Services
}); });
} }
public async Task<OperationResult<IEnumerable<DataToken>>> CreditCategories()
{
var sw = Stopwatch.StartNew();
var data = await CacheManager.GetAsync(CreditCategoriesCacheKey, async () =>
{
return (await DbContext.CreditCategory.ToListAsync()).Select(x => new DataToken
{
Value = x.RoadieId.ToString(),
Text = x.Name
}).ToArray();
}, CacheManagerBase.SystemCacheRegionUrn);
return new OperationResult<IEnumerable<DataToken>>
{
Data = data,
IsSuccess = true,
OperationTime = sw.ElapsedMilliseconds
};
}
public Task<OperationResult<IEnumerable<DataToken>>> Status() public Task<OperationResult<IEnumerable<DataToken>>> Status()
{ {
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();

View file

@ -7,6 +7,7 @@ using Roadie.Library.Caching;
using Roadie.Library.Configuration; using Roadie.Library.Configuration;
using Roadie.Library.Data.Context; using Roadie.Library.Data.Context;
using Roadie.Library.Encoding; using Roadie.Library.Encoding;
using Roadie.Library.Imaging;
using Roadie.Library.Models; using Roadie.Library.Models;
using Roadie.Library.Models.Pagination; using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Users; using Roadie.Library.Models.Users;
@ -81,10 +82,10 @@ namespace Roadie.Api.Services
releaseArtist, releaseArtist,
trackArtist, trackArtist,
HttpContext.BaseUrl, HttpContext.BaseUrl,
MakeTrackThumbnailImage(Configuration, HttpContext, t.RoadieId), ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, t.RoadieId),
MakeReleaseThumbnailImage(Configuration, HttpContext, r.RoadieId), ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, r.RoadieId),
MakeArtistThumbnailImage(Configuration, HttpContext, releaseArtist.RoadieId), ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, releaseArtist.RoadieId),
MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist == null ? null : (Guid?)trackArtist.RoadieId)), ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist == null ? null : (Guid?)trackArtist.RoadieId)),
User = new DataToken User = new DataToken
{ {
Text = u.UserName, Text = u.UserName,
@ -108,10 +109,10 @@ namespace Roadie.Api.Services
UserRating = usertrack.Rating, UserRating = usertrack.Rating,
TrackPlayUrl = $"{HttpContext.BaseUrl}/play/track/{t.RoadieId}.mp3", TrackPlayUrl = $"{HttpContext.BaseUrl}/play/track/{t.RoadieId}.mp3",
ArtistThumbnail = ArtistThumbnail =
MakeArtistThumbnailImage(Configuration, HttpContext, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext,
trackArtist != null ? trackArtist.RoadieId : releaseArtist.RoadieId), trackArtist != null ? trackArtist.RoadieId : releaseArtist.RoadieId),
ReleaseThumbnail = MakeReleaseThumbnailImage(Configuration, HttpContext, r.RoadieId), ReleaseThumbnail = ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, r.RoadieId),
UserThumbnail = MakeUserThumbnailImage(Configuration, HttpContext, u.RoadieId) UserThumbnail = ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, u.RoadieId)
}; };
var sortBy = string.IsNullOrEmpty(request.Sort) var sortBy = string.IsNullOrEmpty(request.Sort)
@ -198,10 +199,10 @@ namespace Roadie.Api.Services
track.ReleaseMedia.Release.Artist, track.ReleaseMedia.Release.Artist,
track.TrackArtist, track.TrackArtist,
HttpContext.BaseUrl, HttpContext.BaseUrl,
MakeTrackThumbnailImage(Configuration, HttpContext, track.RoadieId), ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, track.RoadieId),
MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId), ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId),
MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId), ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId),
MakeArtistThumbnailImage(Configuration, HttpContext, track.TrackArtist == null ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.TrackArtist == null
? null ? null
: (Guid?)track.TrackArtist.RoadieId)), : (Guid?)track.TrackArtist.RoadieId)),
User = new DataToken User = new DataToken
@ -209,17 +210,17 @@ namespace Roadie.Api.Services
Text = roadieUser.UserName, Text = roadieUser.UserName,
Value = roadieUser.UserId.ToString() Value = roadieUser.UserId.ToString()
}, },
ArtistThumbnail = MakeArtistThumbnailImage(Configuration, HttpContext, track.TrackArtist != null ArtistThumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.TrackArtist != null
? track.TrackArtist.RoadieId ? track.TrackArtist.RoadieId
: track.ReleaseMedia.Release.Artist.RoadieId), : track.ReleaseMedia.Release.Artist.RoadieId),
PlayedDateDateTime = scrobble.TimePlayed, PlayedDateDateTime = scrobble.TimePlayed,
IsNowPlaying = isNowPlaying, IsNowPlaying = isNowPlaying,
Rating = track.Rating, Rating = track.Rating,
ReleasePlayUrl = $"{HttpContext.BaseUrl}/play/release/{track.ReleaseMedia.Release.RoadieId}", ReleasePlayUrl = $"{HttpContext.BaseUrl}/play/release/{track.ReleaseMedia.Release.RoadieId}",
ReleaseThumbnail = MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId), ReleaseThumbnail = ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId),
TrackPlayUrl = $"{HttpContext.BaseUrl}/play/track/{track.RoadieId}.mp3", TrackPlayUrl = $"{HttpContext.BaseUrl}/play/track/{track.RoadieId}.mp3",
UserRating = userTrack?.Rating, UserRating = userTrack?.Rating,
UserThumbnail = MakeUserThumbnailImage(Configuration, HttpContext, roadieUser.UserId) UserThumbnail = ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, roadieUser.UserId)
}; };
try try
{ {

View file

@ -123,10 +123,10 @@ namespace Roadie.Api.Services
{ {
if (result?.Data?.Tracks != null) if (result?.Data?.Tracks != null)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
foreach (var track in result.Data.Tracks) foreach (var track in result.Data.Tracks)
{ {
track.Track.TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.Track.DatabaseId, track.Track.Id); track.Track.TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.Track.Id);
} }
} }
@ -134,7 +134,7 @@ namespace Roadie.Api.Services
var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Playlist); var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Playlist);
if (userBookmarkResult.IsSuccess) if (userBookmarkResult.IsSuccess)
{ {
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Text == result.Data.Id.ToString()) != null; result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Value == result.Data.Id.ToString()) != null;
} }
if (result.Data.Comments.Any()) if (result.Data.Comments.Any())
{ {
@ -255,9 +255,9 @@ namespace Roadie.Api.Services
TrackCount = pl.TrackCount, TrackCount = pl.TrackCount,
CreatedDate = pl.CreatedDate, CreatedDate = pl.CreatedDate,
LastUpdated = pl.LastUpdated, LastUpdated = pl.LastUpdated,
UserThumbnail = MakeUserThumbnailImage(Configuration, HttpContext, u.RoadieId), UserThumbnail = ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, u.RoadieId),
Id = pl.RoadieId, Id = pl.RoadieId,
Thumbnail = MakePlaylistThumbnailImage(Configuration, HttpContext, pl.RoadieId) Thumbnail = ImageHelper.MakePlaylistThumbnailImage(Configuration, HttpContext, pl.RoadieId)
}; };
var sortBy = string.IsNullOrEmpty(request.Sort) var sortBy = string.IsNullOrEmpty(request.Sort)
? request.OrderValue(new Dictionary<string, string> { { "Playlist.Text", "ASC" } }) ? request.OrderValue(new Dictionary<string, string> { { "Playlist.Text", "ASC" } })
@ -441,7 +441,7 @@ namespace Roadie.Api.Services
}; };
} }
private Task<OperationResult<Playlist>> PlaylistByIdAction(Guid id, IEnumerable<string> includes = null) private async Task<OperationResult<Playlist>> PlaylistByIdAction(Guid id, IEnumerable<string> includes = null)
{ {
var timings = new Dictionary<string, long>(); var timings = new Dictionary<string, long>();
var tsw = new Stopwatch(); var tsw = new Stopwatch();
@ -450,13 +450,13 @@ namespace Roadie.Api.Services
sw.Start(); sw.Start();
tsw.Restart(); tsw.Restart();
var playlist = GetPlaylist(id); var playlist = await GetPlaylist(id);
tsw.Stop(); tsw.Stop();
timings.Add("getPlaylist", tsw.ElapsedMilliseconds); timings.Add("getPlaylist", tsw.ElapsedMilliseconds);
if (playlist == null) if (playlist == null)
{ {
return Task.FromResult(new OperationResult<Playlist>(true, string.Format("Playlist Not Found [{0}]", id))); return new OperationResult<Playlist>(true, string.Format("Playlist Not Found [{0}]", id));
} }
tsw.Restart(); tsw.Restart();
var result = playlist.Adapt<Playlist>(); var result = playlist.Adapt<Playlist>();
@ -464,9 +464,9 @@ namespace Roadie.Api.Services
result.Tags = playlist.Tags; result.Tags = playlist.Tags;
result.URLs = playlist.URLs; result.URLs = playlist.URLs;
var maintainer = DbContext.Users.Include(x => x.UserRoles).Include("UserRoles.Role").FirstOrDefault(x => x.Id == playlist.UserId); var maintainer = DbContext.Users.Include(x => x.UserRoles).Include("UserRoles.Role").FirstOrDefault(x => x.Id == playlist.UserId);
result.Maintainer = UserList.FromDataUser(maintainer, MakeUserThumbnailImage(Configuration, HttpContext, maintainer.RoadieId)); result.Maintainer = UserList.FromDataUser(maintainer, ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, maintainer.RoadieId));
result.Thumbnail = MakePlaylistThumbnailImage(Configuration, HttpContext, playlist.RoadieId); result.Thumbnail = ImageHelper.MakePlaylistThumbnailImage(Configuration, HttpContext, playlist.RoadieId);
result.MediumThumbnail = MakeThumbnailImage(Configuration, HttpContext, id, "playlist", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height); result.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "playlist", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
tsw.Stop(); tsw.Stop();
timings.Add("adapt", tsw.ElapsedMilliseconds); timings.Add("adapt", tsw.ElapsedMilliseconds);
if (includes != null && includes.Any()) if (includes != null && includes.Any())
@ -509,10 +509,10 @@ namespace Roadie.Api.Services
releaseArtist, releaseArtist,
trackArtist, trackArtist,
HttpContext.BaseUrl, HttpContext.BaseUrl,
MakeTrackThumbnailImage(Configuration, HttpContext, plt.t.RoadieId), ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, plt.t.RoadieId),
MakeReleaseThumbnailImage(Configuration, HttpContext, r.RoadieId), ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, r.RoadieId),
MakeArtistThumbnailImage(Configuration, HttpContext, releaseArtist.RoadieId), ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, releaseArtist.RoadieId),
MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist == null ? null : (Guid?)trackArtist.RoadieId)) ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist == null ? null : (Guid?)trackArtist.RoadieId))
}).ToArray(); }).ToArray();
tsw.Stop(); tsw.Stop();
timings.Add("tracks", tsw.ElapsedMilliseconds); timings.Add("tracks", tsw.ElapsedMilliseconds);
@ -535,7 +535,7 @@ namespace Roadie.Api.Services
{ {
var comment = playlistComment.Adapt<Comment>(); var comment = playlistComment.Adapt<Comment>();
comment.DatabaseId = playlistComment.Id; comment.DatabaseId = playlistComment.Id;
comment.User = UserList.FromDataUser(playlistComment.User, MakeUserThumbnailImage(Configuration, HttpContext, playlistComment.User.RoadieId)); comment.User = UserList.FromDataUser(playlistComment.User, ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, playlistComment.User.RoadieId));
comment.DislikedCount = userCommentReactions.Count(x => x.CommentId == playlistComment.Id && x.ReactionValue == CommentReaction.Dislike); comment.DislikedCount = userCommentReactions.Count(x => x.CommentId == playlistComment.Id && x.ReactionValue == CommentReaction.Dislike);
comment.LikedCount = userCommentReactions.Count(x => x.CommentId == playlistComment.Id && x.ReactionValue == CommentReaction.Like); comment.LikedCount = userCommentReactions.Count(x => x.CommentId == playlistComment.Id && x.ReactionValue == CommentReaction.Like);
comments.Add(comment); comments.Add(comment);
@ -549,12 +549,12 @@ namespace Roadie.Api.Services
sw.Stop(); sw.Stop();
Logger.LogInformation($"ByIdAction: Playlist `{ playlist }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]"); Logger.LogInformation($"ByIdAction: Playlist `{ playlist }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]");
return Task.FromResult(new OperationResult<Playlist> return new OperationResult<Playlist>
{ {
Data = result, Data = result,
IsSuccess = result != null, IsSuccess = result != null,
OperationTime = sw.ElapsedMilliseconds OperationTime = sw.ElapsedMilliseconds
}); };
} }
} }
} }

View file

@ -85,7 +85,7 @@ namespace Roadie.Api.Services
if (result?.Data != null && roadieUser != null) if (result?.Data != null && roadieUser != null)
{ {
tsw.Restart(); tsw.Restart();
var release = GetRelease(id); var release = await GetRelease(id);
tsw.Stop(); tsw.Stop();
timings.Add("getRelease", tsw.ElapsedMilliseconds); timings.Add("getRelease", tsw.ElapsedMilliseconds);
@ -97,14 +97,14 @@ namespace Roadie.Api.Services
if (result.Data.Medias != null) if (result.Data.Medias != null)
{ {
tsw.Restart(); tsw.Restart();
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
tsw.Stop(); tsw.Stop();
timings.Add("getUser", tsw.ElapsedMilliseconds); timings.Add("getUser", tsw.ElapsedMilliseconds);
tsw.Restart(); tsw.Restart();
Parallel.ForEach(result.Data.Medias.SelectMany(x => x.Tracks), track => Parallel.ForEach(result.Data.Medias.SelectMany(x => x.Tracks), track =>
{ {
track.TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.DatabaseId, track.Id); track.TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.Id);
}); });
tsw.Stop(); tsw.Stop();
@ -460,11 +460,6 @@ namespace Roadie.Api.Services
request.Order = "ASC"; request.Order = "ASC";
} }
} }
//
// TODO list should honor disliked artist and albums for random
//
var isEqualFilter = false; var isEqualFilter = false;
if (!string.IsNullOrEmpty(request.FilterValue)) if (!string.IsNullOrEmpty(request.FilterValue))
{ {
@ -525,7 +520,7 @@ namespace Roadie.Api.Services
Text = r.Title, Text = r.Title,
Value = r.RoadieId.ToString() Value = r.RoadieId.ToString()
}, },
ArtistThumbnail = MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId), ArtistThumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId),
CreatedDate = r.CreatedDate, CreatedDate = r.CreatedDate,
Duration = r.Duration, Duration = r.Duration,
LastPlayed = r.LastPlayed, LastPlayed = r.LastPlayed,
@ -537,7 +532,7 @@ namespace Roadie.Api.Services
ReleaseDateDateTime = r.ReleaseDate, ReleaseDateDateTime = r.ReleaseDate,
ReleasePlayUrl = $"{HttpContext.BaseUrl}/play/release/{r.RoadieId}", ReleasePlayUrl = $"{HttpContext.BaseUrl}/play/release/{r.RoadieId}",
Status = r.Status, Status = r.Status,
Thumbnail = MakeReleaseThumbnailImage(Configuration, HttpContext, r.RoadieId), Thumbnail = ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, r.RoadieId),
TrackCount = r.TrackCount, TrackCount = r.TrackCount,
TrackPlayedCount = r.PlayedCount TrackPlayedCount = r.PlayedCount
}); });
@ -548,7 +543,7 @@ namespace Roadie.Api.Services
if (doRandomize ?? false) if (doRandomize ?? false)
{ {
var resultData = result.ToArray(); var resultData = await result.ToArrayAsync();
rows = (from r in resultData rows = (from r in resultData
join ra in randomReleaseData on r.DatabaseId equals ra.Value join ra in randomReleaseData on r.DatabaseId equals ra.Value
orderby ra.Key orderby ra.Key
@ -583,24 +578,24 @@ namespace Roadie.Api.Services
if (request.FilterToCollectionId.HasValue) if (request.FilterToCollectionId.HasValue)
{ {
rows = result.ToArray(); rows = await result.ToArrayAsync();
} }
else else
{ {
sortBy = sortBy.Replace("ReleaseDate ", "ReleaseDateDateTime "); sortBy = sortBy.Replace("ReleaseDate ", "ReleaseDateDateTime ");
rows = result rows = await result
.OrderBy(sortBy) .OrderBy(sortBy)
.Skip(request.SkipValue) .Skip(request.SkipValue)
.Take(request.LimitValue) .Take(request.LimitValue)
.ToArray(); .ToArrayAsync();
} }
} }
if (rows.Any()) if (rows.Any())
{ {
var rowIds = rows.Select(x => x.DatabaseId).ToArray(); var rowIds = rows.Select(x => x.DatabaseId).ToArray();
var genreData = (from rg in DbContext.ReleaseGenres var genreData = await (from rg in DbContext.ReleaseGenres
join g in DbContext.Genres on rg.GenreId equals g.Id join g in DbContext.Genres on rg.GenreId equals g.Id
where rowIds.Contains(rg.ReleaseId) where rowIds.Contains(rg.ReleaseId)
orderby rg.Id orderby rg.Id
@ -612,7 +607,7 @@ namespace Roadie.Api.Services
Text = g.Name, Text = g.Name,
Value = g.RoadieId.ToString() Value = g.RoadieId.ToString()
} }
}).ToArray(); }).ToArrayAsync();
foreach (var release in rows) foreach (var release in rows)
{ {
@ -623,7 +618,7 @@ namespace Roadie.Api.Services
if (request.FilterToCollectionId.HasValue) if (request.FilterToCollectionId.HasValue)
{ {
var newRows = new List<ReleaseList>(rows); var newRows = new List<ReleaseList>(rows);
var collection = GetCollection(request.FilterToCollectionId.Value); var collection = await GetCollection(request.FilterToCollectionId.Value);
var collectionReleases = from c in DbContext.Collections var collectionReleases = from c in DbContext.Collections
join cr in DbContext.CollectionReleases on c.Id equals cr.CollectionId join cr in DbContext.CollectionReleases on c.Id equals cr.CollectionId
where c.RoadieId == request.FilterToCollectionId where c.RoadieId == request.FilterToCollectionId
@ -654,8 +649,8 @@ namespace Roadie.Api.Services
Text = par.Release Text = par.Release
}, },
Status = Statuses.Missing, Status = Statuses.Missing,
ArtistThumbnail = new Image($"{HttpContext.ImageBaseUrl}/unknown.jpg"), ArtistThumbnail = ImageHelper.MakeUnknownImage(HttpContext),
Thumbnail = new Image($"{HttpContext.ImageBaseUrl}/unknown.jpg"), Thumbnail = ImageHelper.MakeUnknownImage(HttpContext),
ListNumber = par.Position ListNumber = par.Position
}); });
} }
@ -676,10 +671,10 @@ namespace Roadie.Api.Services
if (roadieUser != null) if (roadieUser != null)
{ {
var userReleaseRatings = (from ur in DbContext.UserReleases var userReleaseRatings = await (from ur in DbContext.UserReleases
where ur.UserId == roadieUser.Id where ur.UserId == roadieUser.Id
where rowIds.Contains(ur.ReleaseId) where rowIds.Contains(ur.ReleaseId)
select ur).ToArray(); select ur).ToArrayAsync();
foreach (var userReleaseRating in userReleaseRatings.Where(x => foreach (var userReleaseRating in userReleaseRatings.Where(x =>
rows.Select(r => r.DatabaseId).Contains(x.ReleaseId))) rows.Select(r => r.DatabaseId).Contains(x.ReleaseId)))
@ -708,13 +703,13 @@ namespace Roadie.Api.Services
if (includes.Contains("tracks")) if (includes.Contains("tracks"))
{ {
var rowIds = rows.Select(x => x.DatabaseId).ToArray(); var rowIds = rows.Select(x => x.DatabaseId).ToArray();
var userRatingsForResult = (from ut in DbContext.UserTracks.Include(x => x.Track) var userRatingsForResult = await (from ut in DbContext.UserTracks.Include(x => x.Track)
join t in DbContext.Tracks on ut.TrackId equals t.Id join t in DbContext.Tracks on ut.TrackId equals t.Id
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
where rowIds.Contains(rm.ReleaseId) where rowIds.Contains(rm.ReleaseId)
where ut.UserId == roadieUser.Id where ut.UserId == roadieUser.Id
select ut) select ut)
.ToArray() ?? new data.UserTrack[0]; .ToArrayAsync() ?? new data.UserTrack[0];
foreach (var release in rows) foreach (var release in rows)
{ {
@ -725,7 +720,7 @@ namespace Roadie.Api.Services
.AsQueryable() .AsQueryable()
.ProjectToType<ReleaseMediaList>() .ProjectToType<ReleaseMediaList>()
.OrderBy(x => x.MediaNumber) .OrderBy(x => x.MediaNumber)
.ToArray(); .ToArray(); // Async operation on Project Mapping async throws error
Parallel.ForEach(release.Media, (media) => Parallel.ForEach(release.Media, (media) =>
{ {
@ -752,7 +747,10 @@ namespace Roadie.Api.Services
} }
} }
if (request.FilterFavoriteOnly) rows = rows.OrderBy(x => x.UserRating.Rating).ToArray(); if (request.FilterFavoriteOnly)
{
rows = rows.OrderBy(x => x.UserRating.Rating).ToArray();
}
sw.Stop(); sw.Stop();
return new Library.Models.Pagination.PagedResult<ReleaseList> return new Library.Models.Pagination.PagedResult<ReleaseList>
{ {
@ -1065,12 +1063,11 @@ namespace Roadie.Api.Services
}; };
} }
public Task<FileOperationResult<byte[]>> ReleaseZipped(User roadieUser, Guid id) public async Task<FileOperationResult<byte[]>> ReleaseZipped(User roadieUser, Guid id)
{ {
var release = GetRelease(id); var release = await GetRelease(id);
if (release == null) if (release == null)
return Task.FromResult(new FileOperationResult<byte[]>(true, return new FileOperationResult<byte[]>(true, string.Format("Release Not Found [{0}]", id));
string.Format("Release Not Found [{0}]", id)));
byte[] zipBytes = null; byte[] zipBytes = null;
string zipFileName = null; string zipFileName = null;
@ -1081,8 +1078,7 @@ namespace Roadie.Api.Services
if (!Directory.Exists(releaseFolder)) if (!Directory.Exists(releaseFolder))
{ {
Logger.LogCritical($"Release Folder [{releaseFolder}] not found for Release `{release}`"); Logger.LogCritical($"Release Folder [{releaseFolder}] not found for Release `{release}`");
return Task.FromResult(new FileOperationResult<byte[]>(true, return new FileOperationResult<byte[]>(true, string.Format("Release Folder Not Found [{0}]", id));
string.Format("Release Folder Not Found [{0}]", id)));
} }
var releaseFiles = Directory.GetFiles(releaseFolder); var releaseFiles = Directory.GetFiles(releaseFolder);
@ -1119,12 +1115,12 @@ namespace Roadie.Api.Services
Logger.LogError(ex, "Error creating zip for Release `{0}`", release.ToString()); Logger.LogError(ex, "Error creating zip for Release `{0}`", release.ToString());
} }
return Task.FromResult(new FileOperationResult<byte[]> return new FileOperationResult<byte[]>
{ {
IsSuccess = zipBytes != null, IsSuccess = zipBytes != null,
Data = zipBytes, Data = zipBytes,
AdditionalData = new Dictionary<string, object> { { "ZipFileName", zipFileName } } AdditionalData = new Dictionary<string, object> { { "ZipFileName", zipFileName } }
}); };
} }
/// <summary> /// <summary>
@ -1668,15 +1664,17 @@ namespace Roadie.Api.Services
// Remove existing Genres not in model list // Remove existing Genres not in model list
foreach (var genre in release.Genres.ToList()) foreach (var genre in release.Genres.ToList())
{ {
var doesExistInModel = var doesExistInModel = model.Genres.Any(x => SafeParser.ToGuid(x.Genre.Value) == genre.Genre.RoadieId);
model.Genres.Any(x => SafeParser.ToGuid(x.Value) == genre.Genre.RoadieId); if (!doesExistInModel)
if (!doesExistInModel) release.Genres.Remove(genre); {
release.Genres.Remove(genre);
}
} }
// Add new Genres in model not in data // Add new Genres in model not in data
foreach (var genre in model.Genres) foreach (var genre in model.Genres)
{ {
var genreId = SafeParser.ToGuid(genre.Value); var genreId = SafeParser.ToGuid(genre.Genre.Value);
var doesExistInData = release.Genres.Any(x => x.Genre.RoadieId == genreId); var doesExistInData = release.Genres.Any(x => x.Genre.RoadieId == genreId);
if (!doesExistInData) if (!doesExistInData)
{ {
@ -1696,10 +1694,98 @@ namespace Roadie.Api.Services
release.Genres.Clear(); release.Genres.Clear();
} }
if (model.Labels != null && model.Labels.Any()) if(model.Labels == null || !model.Labels.Any())
{ {
// TODO // Delete all existing labels for release
var releaseLabelsToDelete = (from l in DbContext.ReleaseLabels
where l.ReleaseId == release.Id
select l).ToArray();
DbContext.ReleaseLabels.RemoveRange(releaseLabelsToDelete);
} }
else if (model.Labels != null && model.Labels.Any())
{
var releaseLabelIds = model.Labels.Select(x => x.Id).ToArray();
// Delete any labels not in given model (removed by edit operation)
var releaseLabelsToDelete = (from l in DbContext.ReleaseLabels
where l.ReleaseId == release.Id
where !releaseLabelIds.Contains(l.RoadieId)
select l).ToArray();
DbContext.ReleaseLabels.RemoveRange(releaseLabelsToDelete);
// Update any existing
foreach(var label in model.Labels)
{
var trackLabel = DbContext.ReleaseLabels.FirstOrDefault(x => x.RoadieId == label.Id);
if (trackLabel == null)
{
// Add new
trackLabel = new data.ReleaseLabel
{
ReleaseId = release.Id,
CreatedDate = now
};
DbContext.ReleaseLabels.Add(trackLabel);
}
trackLabel.CatalogNumber = label.CatalogNumber;
trackLabel.BeginDate = label.BeginDate;
trackLabel.EndDate = label.EndDate;
var releaseLabel = await GetLabel(SafeParser.ToGuid(label.Label.Label.Value).Value);
trackLabel.LabelId = releaseLabel.Id;
trackLabel.IsLocked = label.IsLocked;
trackLabel.Status = SafeParser.ToEnum<Statuses>(label.Status);
trackLabel.LastUpdated = now;
}
}
if (model.Credits == null || !model.Credits.Any())
{
// Delete all existing credits for release
var releaseCreditsToDelete = (from c in DbContext.Credits
where c.ReleaseId == release.Id
select c).ToArray();
DbContext.Credits.RemoveRange(releaseCreditsToDelete);
}
else if (model.Credits != null && model.Credits.Any())
{
var releaseCreditIds = model.Credits.Select(x => x.Id).ToArray();
// Delete any credits not given in model (removed by edit operation)
var releaseCreditsToDelete = (from c in DbContext.Credits
where c.TrackId == release.Id
where !releaseCreditIds.Contains(c.RoadieId)
select c).ToArray();
DbContext.Credits.RemoveRange(releaseCreditsToDelete);
// Update any existing
foreach (var credit in model.Credits)
{
var trackCredit = DbContext.Credits.FirstOrDefault(x => x.RoadieId == credit.Id);
if (trackCredit == null)
{
// Add new
trackCredit = new data.Credit
{
ReleaseId = release.Id,
CreatedDate = now
};
DbContext.Credits.Add(trackCredit);
}
data.Artist artistForCredit = null;
if (credit.Artist != null)
{
artistForCredit = await GetArtist(credit.Artist.Id);
}
var creditCategory = DbContext.CreditCategory.FirstOrDefault(x => x.RoadieId.ToString() == credit.Category.Value);
trackCredit.CreditCategoryId = creditCategory.Id;
trackCredit.ArtistId = artistForCredit == null ? null : (int?)artistForCredit.Id;
trackCredit.IsLocked = credit.IsLocked;
trackCredit.Status = SafeParser.ToEnum<Statuses>(credit.Status);
trackCredit.CreditToName = artistForCredit == null ? credit.CreditName : null;
trackCredit.Description = credit.Description;
trackCredit.URLs = credit.URLs;
trackCredit.Tags = credit.Tags;
trackCredit.LastUpdated = now;
}
}
release.LastUpdated = now; release.LastUpdated = now;
await DbContext.SaveChangesAsync(); await DbContext.SaveChangesAsync();
@ -1761,7 +1847,7 @@ namespace Roadie.Api.Services
sw.Start(); sw.Start();
tsw.Restart(); tsw.Restart();
var release = GetRelease(id); var release = await GetRelease(id);
tsw.Stop(); tsw.Stop();
timings.Add("getRelease", tsw.ElapsedMilliseconds); timings.Add("getRelease", tsw.ElapsedMilliseconds);
@ -1771,9 +1857,9 @@ namespace Roadie.Api.Services
} }
tsw.Restart(); tsw.Restart();
var result = release.Adapt<Release>(); var result = release.Adapt<Release>();
result.Artist = ArtistList.FromDataArtist(release.Artist, MakeArtistThumbnailImage(Configuration, HttpContext, release.Artist.RoadieId)); result.Artist = ArtistList.FromDataArtist(release.Artist, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, release.Artist.RoadieId));
result.Thumbnail = MakeReleaseThumbnailImage(Configuration, HttpContext, release.RoadieId); result.Thumbnail = ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, release.RoadieId);
result.MediumThumbnail = MakeThumbnailImage(Configuration, HttpContext, id, "release", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height); result.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "release", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
result.ReleasePlayUrl = $"{HttpContext.BaseUrl}/play/release/{release.RoadieId}"; result.ReleasePlayUrl = $"{HttpContext.BaseUrl}/play/release/{release.RoadieId}";
result.Profile = release.Profile; result.Profile = release.Profile;
result.ReleaseDate = release.ReleaseDate.Value; result.ReleaseDate = release.ReleaseDate.Value;
@ -1804,7 +1890,7 @@ namespace Roadie.Api.Services
Text = submission.User.UserName, Text = submission.User.UserName,
Value = submission.User.RoadieId.ToString() Value = submission.User.RoadieId.ToString()
}, },
UserThumbnail = MakeUserThumbnailImage(Configuration, HttpContext, submission.User.RoadieId), UserThumbnail = ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, submission.User.RoadieId),
SubmittedDate = submission.CreatedDate SubmittedDate = submission.CreatedDate
}; };
} }
@ -1815,14 +1901,50 @@ namespace Roadie.Api.Services
if (includes != null && includes.Any()) if (includes != null && includes.Any())
{ {
if(includes.Contains("credits"))
{
tsw.Restart();
result.Credits = (await (from c in DbContext.Credits
join cc in DbContext.CreditCategory on c.CreditCategoryId equals cc.Id
join a in DbContext.Artists on c.ArtistId equals a.Id into agg
from a in agg.DefaultIfEmpty()
where c.ReleaseId == release.Id
select new { c, cc, a })
.ToListAsync())
.Select(x => new CreditList
{
Id = x.c.RoadieId,
Artist = x.a == null ? null : ArtistList.FromDataArtist(x.a, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, x.a.RoadieId)),
Category = new DataToken {
Text =x.cc.Name,
Value = x.cc.RoadieId.ToString()
},
CreditName = x.a?.Name ?? x.c.CreditToName,
Description = x.c.Description
}).ToArray();
tsw.Stop();
timings.Add("credits", tsw.ElapsedMilliseconds);
}
if (includes.Contains("genres")) if (includes.Contains("genres"))
{ {
tsw.Restart(); tsw.Restart();
result.Genres = release.Genres.Select(x => new DataToken var releaseGenreIds = release.Genres.Select(x => x.GenreId).ToArray();
{ result.Genres = (await (from g in DbContext.Genres
Text = x.Genre.Name, let releaseCount = (from rg in DbContext.ReleaseGenres
Value = x.Genre.RoadieId.ToString() 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 releaseGenreIds.Contains(g.Id)
select new { g, releaseCount, artistCount }).ToListAsync())
.Select(x => GenreList.FromDataGenre(x.g,
ImageHelper.MakeGenreThumbnailImage(Configuration, HttpContext, x.g.RoadieId),
x.artistCount,
x.releaseCount))
.ToArray();
tsw.Stop(); tsw.Stop();
timings.Add("genres", tsw.ElapsedMilliseconds); timings.Add("genres", tsw.ElapsedMilliseconds);
} }
@ -1873,7 +1995,7 @@ namespace Roadie.Api.Services
var releaseImagesInFolder = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(releaseFolder), ImageType.ReleaseSecondary, SearchOption.TopDirectoryOnly); var releaseImagesInFolder = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(releaseFolder), ImageType.ReleaseSecondary, SearchOption.TopDirectoryOnly);
if (releaseImagesInFolder.Any()) if (releaseImagesInFolder.Any())
{ {
result.Images = releaseImagesInFolder.Select((x, i) => MakeFullsizeSecondaryImage(Configuration, HttpContext, id, ImageType.ReleaseSecondary, i)); result.Images = releaseImagesInFolder.Select((x, i) => ImageHelper.MakeFullsizeSecondaryImage(Configuration, HttpContext, id, ImageType.ReleaseSecondary, i));
} }
tsw.Stop(); tsw.Stop();
timings.Add("images", tsw.ElapsedMilliseconds); timings.Add("images", tsw.ElapsedMilliseconds);
@ -1930,7 +2052,7 @@ namespace Roadie.Api.Services
ArtistCount = releaseLabel.l.ArtistCount, ArtistCount = releaseLabel.l.ArtistCount,
ReleaseCount = releaseLabel.l.ReleaseCount, ReleaseCount = releaseLabel.l.ReleaseCount,
TrackCount = releaseLabel.l.TrackCount, TrackCount = releaseLabel.l.TrackCount,
Thumbnail = MakeLabelThumbnailImage(Configuration, HttpContext, releaseLabel.l.RoadieId) Thumbnail = ImageHelper.MakeLabelThumbnailImage(Configuration, HttpContext, releaseLabel.l.RoadieId)
} }
}; };
labels.Add(rl); labels.Add(rl);
@ -1975,7 +2097,7 @@ namespace Roadie.Api.Services
CreatedDate = releaseCollection.Collection.CreatedDate, CreatedDate = releaseCollection.Collection.CreatedDate,
IsLocked = releaseCollection.Collection.IsLocked, IsLocked = releaseCollection.Collection.IsLocked,
LastUpdated = releaseCollection.Collection.LastUpdated, LastUpdated = releaseCollection.Collection.LastUpdated,
Thumbnail = MakeCollectionThumbnailImage(Configuration, HttpContext, releaseCollection.Collection.RoadieId) Thumbnail = ImageHelper.MakeCollectionThumbnailImage(Configuration, HttpContext, releaseCollection.Collection.RoadieId)
}, },
ListNumber = releaseCollection.ListNumber ListNumber = releaseCollection.ListNumber
}); });
@ -2004,7 +2126,7 @@ namespace Roadie.Api.Services
{ {
var comment = releaseComment.Adapt<Comment>(); var comment = releaseComment.Adapt<Comment>();
comment.DatabaseId = releaseComment.Id; comment.DatabaseId = releaseComment.Id;
comment.User = UserList.FromDataUser(releaseComment.User, MakeUserThumbnailImage(Configuration, HttpContext, releaseComment.User.RoadieId)); comment.User = UserList.FromDataUser(releaseComment.User, ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, releaseComment.User.RoadieId));
comment.DislikedCount = userCommentReactions.Count(x => x.CommentId == releaseComment.Id && x.ReactionValue == CommentReaction.Dislike); comment.DislikedCount = userCommentReactions.Count(x => x.CommentId == releaseComment.Id && x.ReactionValue == CommentReaction.Dislike);
comment.LikedCount = userCommentReactions.Count(x => x.CommentId == releaseComment.Id && x.ReactionValue == CommentReaction.Like); comment.LikedCount = userCommentReactions.Count(x => x.CommentId == releaseComment.Id && x.ReactionValue == CommentReaction.Like);
comments.Add(comment); comments.Add(comment);
@ -2035,7 +2157,7 @@ namespace Roadie.Api.Services
t.Status = track.Status; t.Status = track.Status;
t.TrackArtist = track.TrackArtist != null t.TrackArtist = track.TrackArtist != null
? ArtistList.FromDataArtist(track.TrackArtist, ? ArtistList.FromDataArtist(track.TrackArtist,
MakeArtistThumbnailImage(Configuration, HttpContext, track.TrackArtist.RoadieId)) ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.TrackArtist.RoadieId))
: null; : null;
rmTracks.Add(t); rmTracks.Add(t);
} }
@ -2091,7 +2213,7 @@ namespace Roadie.Api.Services
return new OperationResult<Image> return new OperationResult<Image>
{ {
IsSuccess = !errors.Any(), IsSuccess = !errors.Any(),
Data = MakeThumbnailImage(Configuration, HttpContext, id, "release", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height, true), Data = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "release", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height, true),
OperationTime = sw.ElapsedMilliseconds, OperationTime = sw.ElapsedMilliseconds,
Errors = errors Errors = errors
}; };

View file

@ -8,7 +8,6 @@ using Roadie.Library.Data.Context;
using Roadie.Library.Encoding; using Roadie.Library.Encoding;
using Roadie.Library.Enums; using Roadie.Library.Enums;
using Roadie.Library.Identity; using Roadie.Library.Identity;
using Roadie.Library.Models;
using Roadie.Library.Utility; using Roadie.Library.Utility;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -72,10 +71,7 @@ namespace Roadie.Api.Services
return TrackPlayToken(user, trackRoadieId).Equals(token); return TrackPlayToken(user, trackRoadieId).Equals(token);
} }
public static string MakeTrackPlayUrl(ApplicationUser user, string baseUrl, int trackId, Guid trackRoadieId) public static string MakeTrackPlayUrl(ApplicationUser user, string baseUrl, Guid trackRoadieId) => $"{baseUrl}/play/track/{user.Id}/{TrackPlayToken(user, trackRoadieId)}/{trackRoadieId}.mp3";
{
return $"{baseUrl}/play/track/{user.Id}/{TrackPlayToken(user, trackRoadieId)}/{trackRoadieId}.mp3";
}
public static string TrackPlayToken(ApplicationUser user, Guid trackId) public static string TrackPlayToken(ApplicationUser user, Guid trackId)
{ {
@ -88,11 +84,6 @@ namespace Roadie.Api.Services
return token; return token;
} }
public static Image MakeThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string type, int? width = null, int? height = null, bool includeCachebuster = false)
{
return MakeImage(configuration, httpContext, id, type, width ?? configuration.ThumbnailImageSize.Width, height ?? configuration.ThumbnailImageSize.Height, null, includeCachebuster);
}
protected IEnumerable<int> ArtistIdsForRelease(int releaseId) protected IEnumerable<int> ArtistIdsForRelease(int releaseId)
{ {
var trackArtistIds = (from r in DbContext.Releases var trackArtistIds = (from r in DbContext.Releases
@ -105,219 +96,137 @@ namespace Roadie.Api.Services
return trackArtistIds.Distinct().ToArray(); return trackArtistIds.Distinct().ToArray();
} }
protected data.Artist GetArtist(string artistName) protected async Task<data.Artist> GetArtist(string artistName)
{ {
if (string.IsNullOrEmpty(artistName)) return null; if (string.IsNullOrEmpty(artistName)) return null;
var artistByName = CacheManager.Get(data.Artist.CacheUrnByName(artistName), () => var artistByName = await CacheManager.GetAsync(data.Artist.CacheUrnByName(artistName), async () =>
{ {
return DbContext.Artists return await DbContext.Artists
.FirstOrDefault(x => x.Name == artistName); .FirstOrDefaultAsync(x => x.Name == artistName);
}, null); }, null);
if (artistByName == null) return null; if (artistByName == null) return null;
return GetArtist(artistByName.RoadieId); return await GetArtist(artistByName.RoadieId);
} }
protected data.Artist GetArtist(Guid id) protected async Task<data.Artist> GetArtist(Guid id)
{ {
return CacheManager.Get(data.Artist.CacheUrn(id), () => return await CacheManager.GetAsync(data.Artist.CacheUrn(id), async () =>
{ {
return DbContext.Artists return await DbContext.Artists
.Include(x => x.Genres) .Include(x => x.Genres)
.Include("Genres.Genre") .Include("Genres.Genre")
.FirstOrDefault(x => x.RoadieId == id); .FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Artist.CacheRegionUrn(id)); }, data.Artist.CacheRegionUrn(id));
} }
protected data.Collection GetCollection(Guid id) protected async Task<data.Collection> GetCollection(Guid id)
{ {
return CacheManager.Get(data.Collection.CacheUrn(id), () => return await CacheManager.GetAsync(data.Collection.CacheUrn(id), async () =>
{ {
return DbContext.Collections return await DbContext.Collections
.FirstOrDefault(x => x.RoadieId == id); .FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Collection.CacheRegionUrn(id)); }, data.Collection.CacheRegionUrn(id));
} }
protected data.Genre GetGenre(Guid id) protected async Task<data.Genre> GetGenre(Guid id)
{ {
return CacheManager.Get(data.Genre.CacheUrn(id), () => return await CacheManager.GetAsync(data.Genre.CacheUrn(id), async () =>
{ {
return DbContext.Genres return await DbContext.Genres
.FirstOrDefault(x => x.RoadieId == id); .FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Genre.CacheRegionUrn(id)); }, data.Genre.CacheRegionUrn(id));
} }
protected data.Label GetLabel(Guid id) protected async Task<data.Label> GetLabel(Guid id)
{ {
return CacheManager.Get(data.Label.CacheUrn(id), () => return await CacheManager.GetAsync(data.Label.CacheUrn(id), async () =>
{ {
return DbContext.Labels return await DbContext.Labels
.FirstOrDefault(x => x.RoadieId == id); .FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Label.CacheRegionUrn(id)); }, data.Label.CacheRegionUrn(id));
} }
protected data.Playlist GetPlaylist(Guid id) protected async Task<data.Playlist> GetPlaylist(Guid id)
{ {
return CacheManager.Get(data.Playlist.CacheUrn(id), () => return await CacheManager.Get(data.Playlist.CacheUrn(id), async () =>
{ {
return DbContext.Playlists return await DbContext.Playlists
.Include(x => x.User) .Include(x => x.User)
.FirstOrDefault(x => x.RoadieId == id); .FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Playlist.CacheRegionUrn(id)); }, data.Playlist.CacheRegionUrn(id));
} }
protected data.Release GetRelease(Guid id) protected async Task<data.Release> GetRelease(Guid id)
{ {
return CacheManager.Get(data.Release.CacheUrn(id), () => return await CacheManager.Get(data.Release.CacheUrn(id), async () =>
{ {
return DbContext.Releases return await DbContext.Releases
.Include(x => x.Artist) .Include(x => x.Artist)
.Include(x => x.Genres) .Include(x => x.Genres)
.Include("Genres.Genre") .Include("Genres.Genre")
.Include(x => x.Medias) .Include(x => x.Medias)
.Include("Medias.Tracks") .Include("Medias.Tracks")
.Include("Medias.Tracks.TrackArtist") .Include("Medias.Tracks.TrackArtist")
.FirstOrDefault(x => x.RoadieId == id); .FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Release.CacheRegionUrn(id)); }, data.Release.CacheRegionUrn(id));
} }
/// <summary> /// <summary>
/// Get Track by Subsonic Id ("T:guid") /// Get Track by Subsonic Id ("T:guid")
/// </summary> /// </summary>
protected data.Track GetTrack(string id) protected async Task<data.Track> GetTrack(string id)
{ {
var trackId = Guid.Empty; if (Guid.TryParse(id, out Guid trackId))
if (Guid.TryParse(id, out trackId)) return GetTrack(trackId); {
return await GetTrack(trackId);
}
return null; return null;
} }
// Only read operations // Only read operations
protected data.Track GetTrack(Guid id) protected async Task<data.Track> GetTrack(Guid id)
{ {
return CacheManager.Get(data.Track.CacheUrn(id), () => return await CacheManager.GetAsync(data.Track.CacheUrn(id), async () =>
{ {
return DbContext.Tracks return await DbContext.Tracks
.Include(x => x.ReleaseMedia) .Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release) .Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist) .Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist) .Include(x => x.TrackArtist)
.FirstOrDefault(x => x.RoadieId == id); .FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Track.CacheRegionUrn(id)); }, data.Track.CacheRegionUrn(id));
} }
protected ApplicationUser GetUser(string username) protected async Task<ApplicationUser> GetUser(string username)
{ {
if (string.IsNullOrEmpty(username)) return null; if (string.IsNullOrEmpty(username))
var userByUsername = CacheManager.Get(ApplicationUser.CacheUrnByUsername(username),
() => { return DbContext.Users.FirstOrDefault(x => x.UserName == username); }, null);
return GetUser(userByUsername?.RoadieId);
}
protected ApplicationUser GetUser(Guid? id)
{
if (!id.HasValue) return null;
return CacheManager.Get(ApplicationUser.CacheUrn(id.Value), () =>
{ {
return DbContext.Users return null;
.Include(x => x.UserRoles)
.Include("UserRoles.Role")
.Include("UserRoles.Role.RoleClaims")
.Include(x => x.Claims)
.Include(x => x.UserQues)
.Include("UserQues.Track")
.FirstOrDefault(x => x.RoadieId == id);
}, ApplicationUser.CacheRegionUrn(id.Value));
}
protected static Image MakeArtistThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid? id)
{
if (!id.HasValue) return null;
return MakeThumbnailImage(configuration, httpContext, id.Value, "artist");
}
protected static Image MakeCollectionThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "collection");
}
protected static Image MakeFullsizeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string caption = null)
{
return new Image($"{httpContext.ImageBaseUrl}/{id}", caption,
$"{httpContext.ImageBaseUrl}/{id}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
}
protected static Image MakeFullsizeSecondaryImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, ImageType type, int imageId, string caption = null)
{
if (type == ImageType.ArtistSecondary)
{
return new Image($"{httpContext.ImageBaseUrl}/artist-secondary/{id}/{imageId}", caption,
$"{httpContext.ImageBaseUrl}/artist-secondary/{id}/{imageId}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
} }
return new Image($"{httpContext.ImageBaseUrl}/release-secondary/{id}/{imageId}", caption, var userByUsername = await CacheManager.GetAsync(ApplicationUser.CacheUrnByUsername(username), async () =>
$"{httpContext.ImageBaseUrl}/release-secondary/{id}/{imageId}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}"); {
return await DbContext.Users.FirstOrDefaultAsync(x => x.UserName == username);
}, null);
return await GetUser(userByUsername?.RoadieId);
} }
protected static Image MakeGenreThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id) protected async Task<ApplicationUser> GetUser(Guid? id)
{ {
return MakeThumbnailImage(configuration, httpContext, id, "genre"); if (!id.HasValue) return null;
return await CacheManager.GetAsync(ApplicationUser.CacheUrn(id.Value), async () =>
{
return await DbContext.Users
.Include(x => x.UserRoles)
.Include("UserRoles.Role")
.Include("UserRoles.Role.RoleClaims")
.Include(x => x.Claims)
.Include(x => x.UserQues)
.Include("UserQues.Track")
.FirstOrDefaultAsync(x => x.RoadieId == id);
}, ApplicationUser.CacheRegionUrn(id.Value));
} }
protected static Image MakeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, int width = 200, int height = 200, string caption = null, bool includeCachebuster = false) protected string MakeLastFmUrl(string artistName, string releaseTitle) => "http://www.last.fm/music/" + HttpEncoder.UrlEncode($"{artistName}/{releaseTitle}");
{
return new Image(
$"{httpContext.ImageBaseUrl}/{id}/{width}/{height}/{(includeCachebuster ? DateTime.UtcNow.Ticks.ToString() : string.Empty)}",
caption,
$"{httpContext.ImageBaseUrl}/{id}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
}
protected static Image MakeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string type, IImageSize imageSize)
{
return MakeImage(configuration, httpContext, id, type, imageSize.Width, imageSize.Height);
}
private static Image MakeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string type, int? width, int? height, string caption = null, bool includeCachebuster = false)
{
if (width.HasValue && height.HasValue && (width.Value != configuration.ThumbnailImageSize.Width ||
height.Value != configuration.ThumbnailImageSize.Height))
return new Image(
$"{httpContext.ImageBaseUrl}/{type}/{id}/{width}/{height}/{(includeCachebuster ? DateTime.UtcNow.Ticks.ToString() : string.Empty)}",
caption,
$"{httpContext.ImageBaseUrl}/{type}/{id}/{configuration.ThumbnailImageSize.Width}/{configuration.ThumbnailImageSize.Height}");
return new Image($"{httpContext.ImageBaseUrl}/{type}/{id}", caption, null);
}
protected static Image MakeLabelThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "label");
}
protected string MakeLastFmUrl(string artistName, string releaseTitle)
{
return "http://www.last.fm/music/" + HttpEncoder.UrlEncode($"{artistName}/{releaseTitle}");
}
protected Image MakeNewImage(string type)
{
return new Image($"{HttpContext.ImageBaseUrl}/{type}.jpg", null, null);
}
protected static Image MakePlaylistThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "playlist");
}
protected static Image MakeReleaseThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "release");
}
protected static Image MakeTrackThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "track");
}
protected static Image MakeUserThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "user");
}
protected async Task<OperationResult<short>> SetArtistRating(Guid artistId, ApplicationUser user, short rating) protected async Task<OperationResult<short>> SetArtistRating(Guid artistId, ApplicationUser user, short rating)
{ {
@ -358,7 +267,7 @@ namespace Roadie.Api.Services
CacheManager.ClearRegion(user.CacheRegion); CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(artist.CacheRegion); CacheManager.ClearRegion(artist.CacheRegion);
artist = GetArtist(artistId); artist = await GetArtist(artistId);
return new OperationResult<short> return new OperationResult<short>
{ {
@ -367,8 +276,7 @@ namespace Roadie.Api.Services
}; };
} }
protected async Task<OperationResult<short>> SetReleaseRating(Guid releaseId, ApplicationUser user, protected async Task<OperationResult<short>> SetReleaseRating(Guid releaseId, ApplicationUser user, short rating)
short rating)
{ {
var release = DbContext.Releases var release = DbContext.Releases
.Include(x => x.Artist) .Include(x => x.Artist)
@ -413,7 +321,7 @@ namespace Roadie.Api.Services
CacheManager.ClearRegion(release.CacheRegion); CacheManager.ClearRegion(release.CacheRegion);
CacheManager.ClearRegion(release.Artist.CacheRegion); CacheManager.ClearRegion(release.Artist.CacheRegion);
release = GetRelease(releaseId); release = await GetRelease(releaseId);
return new OperationResult<short> return new OperationResult<short>
{ {
@ -477,8 +385,7 @@ namespace Roadie.Api.Services
}; };
} }
protected async Task<OperationResult<bool>> ToggleArtistDisliked(Guid artistId, ApplicationUser user, protected async Task<OperationResult<bool>> ToggleArtistDisliked(Guid artistId, ApplicationUser user, bool isDisliked)
bool isDisliked)
{ {
var artist = DbContext.Artists var artist = DbContext.Artists
.Include(x => x.Genres) .Include(x => x.Genres)
@ -594,8 +501,7 @@ namespace Roadie.Api.Services
}; };
} }
protected async Task<OperationResult<bool>> ToggleReleaseFavorite(Guid releaseId, ApplicationUser user, protected async Task<OperationResult<bool>> ToggleReleaseFavorite(Guid releaseId, ApplicationUser user, bool isFavorite)
bool isFavorite)
{ {
var release = DbContext.Releases var release = DbContext.Releases
.Include(x => x.Artist) .Include(x => x.Artist)
@ -845,6 +751,7 @@ namespace Roadie.Api.Services
join t in DbContext.Tracks on rm.Id equals t.ReleaseMediaId join t in DbContext.Tracks on rm.Id equals t.ReleaseMediaId
where rl.LabelId == label.Id where rl.LabelId == label.Id
select t).Count(); select t).Count();
label.LastUpdated = now;
await DbContext.SaveChangesAsync(); await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(label.CacheRegion); CacheManager.ClearRegion(label.CacheRegion);
} }
@ -883,6 +790,7 @@ namespace Roadie.Api.Services
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
where rm.ReleaseId == releaseId where rm.ReleaseId == releaseId
select t).Sum(x => x.Duration); select t).Sum(x => x.Duration);
release.LastUpdated = now;
await DbContext.SaveChangesAsync(); await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(release.CacheRegion); CacheManager.ClearRegion(release.CacheRegion);
} }
@ -941,7 +849,5 @@ namespace Roadie.Api.Services
updateArtistRank); updateArtistRank);
} }
} }
} }
} }

View file

@ -10,6 +10,7 @@ using Roadie.Library.Encoding;
using Roadie.Library.Enums; using Roadie.Library.Enums;
using Roadie.Library.Extensions; using Roadie.Library.Extensions;
using Roadie.Library.Identity; using Roadie.Library.Identity;
using Roadie.Library.Imaging;
using Roadie.Library.Models; using Roadie.Library.Models;
using Roadie.Library.Models.Pagination; using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Playlists; using Roadie.Library.Models.Playlists;
@ -228,7 +229,7 @@ namespace Roadie.Api.Services
await DbContext.SaveChangesAsync(); await DbContext.SaveChangesAsync();
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
CacheManager.ClearRegion(user.CacheRegion); CacheManager.ClearRegion(user.CacheRegion);
Logger.LogTrace( Logger.LogTrace(
@ -353,7 +354,7 @@ namespace Roadie.Api.Services
DbContext.Bookmarks.Remove(userBookmark); DbContext.Bookmarks.Remove(userBookmark);
await DbContext.SaveChangesAsync(); await DbContext.SaveChangesAsync();
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
CacheManager.ClearRegion(user.CacheRegion); CacheManager.ClearRegion(user.CacheRegion);
Logger.LogTrace($"Subsonic: Deleted Bookmark `{userBookmark}` for User `{roadieUser}`"); Logger.LogTrace($"Subsonic: Deleted Bookmark `{userBookmark}` for User `{roadieUser}`");
@ -417,7 +418,7 @@ namespace Roadie.Api.Services
if (!releaseId.HasValue) if (!releaseId.HasValue)
return new subsonic.SubsonicOperationResult<subsonic.Response>( return new subsonic.SubsonicOperationResult<subsonic.Response>(
subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release [{request.ReleaseId}]"); subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release [{request.ReleaseId}]");
var release = GetRelease(releaseId.Value); var release = await GetRelease(releaseId.Value);
if (release == null) if (release == null)
return new subsonic.SubsonicOperationResult<subsonic.Response>( return new subsonic.SubsonicOperationResult<subsonic.Response>(
subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release [{request.ReleaseId}]"); subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release [{request.ReleaseId}]");
@ -473,22 +474,19 @@ namespace Roadie.Api.Services
/// <summary> /// <summary>
/// Returns album notes, image URLs etc, using data from last.fm. /// Returns album notes, image URLs etc, using data from last.fm.
/// </summary> /// </summary>
public Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetAlbumInfo(subsonic.Request request, public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetAlbumInfo(subsonic.Request request, User roadieUser, subsonic.AlbumInfoVersion version)
User roadieUser, subsonic.AlbumInfoVersion version)
{ {
var releaseId = SafeParser.ToGuid(request.id); var releaseId = SafeParser.ToGuid(request.id);
if (!releaseId.HasValue) if (!releaseId.HasValue)
return Task.FromResult(new subsonic.SubsonicOperationResult<subsonic.Response>( return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release [{request.id}]");
subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release [{request.id}]")); var release = await GetRelease(releaseId.Value);
var release = GetRelease(releaseId.Value);
if (release == null) if (release == null)
return Task.FromResult(new subsonic.SubsonicOperationResult<subsonic.Response>( return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release [{request.id}]");
subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release [{request.id}]"));
switch (version) switch (version)
{ {
case subsonic.AlbumInfoVersion.One: case subsonic.AlbumInfoVersion.One:
case subsonic.AlbumInfoVersion.Two: case subsonic.AlbumInfoVersion.Two:
return Task.FromResult(new subsonic.SubsonicOperationResult<subsonic.Response> return new subsonic.SubsonicOperationResult<subsonic.Response>
{ {
IsSuccess = true, IsSuccess = true,
Data = new subsonic.Response Data = new subsonic.Response
@ -499,22 +497,22 @@ namespace Roadie.Api.Services
Item = new subsonic.AlbumInfo Item = new subsonic.AlbumInfo
{ {
largeImageUrl = largeImageUrl =
MakeImage(Configuration, HttpContext, release.RoadieId, "release", Configuration.LargeImageSize).Url, ImageHelper.MakeImage(Configuration, HttpContext, release.RoadieId, "release", Configuration.LargeImageSize).Url,
mediumImageUrl = MakeImage(Configuration, HttpContext, release.RoadieId, "release", Configuration.MediumImageSize) mediumImageUrl = ImageHelper.MakeImage(Configuration, HttpContext, release.RoadieId, "release", Configuration.MediumImageSize)
.Url, .Url,
smallImageUrl = smallImageUrl =
MakeImage(Configuration, HttpContext, release.RoadieId, "release", Configuration.SmallImageSize).Url, ImageHelper.MakeImage(Configuration, HttpContext, release.RoadieId, "release", Configuration.SmallImageSize).Url,
lastFmUrl = MakeLastFmUrl(release.Artist.Name, release.Title), lastFmUrl = MakeLastFmUrl(release.Artist.Name, release.Title),
musicBrainzId = release.MusicBrainzId, musicBrainzId = release.MusicBrainzId,
notes = release.Profile notes = release.Profile
} }
} }
}); };
default: default:
return Task.FromResult(new subsonic.SubsonicOperationResult<subsonic.Response>( return new subsonic.SubsonicOperationResult<subsonic.Response>(
subsonic.ErrorCodes.IncompatibleServerRestProtocolVersion, subsonic.ErrorCodes.IncompatibleServerRestProtocolVersion,
$"Unknown Album Info Version [{request.Type}]")); $"Unknown Album Info Version [{request.Type}]");
} }
} }
@ -631,22 +629,20 @@ namespace Roadie.Api.Services
/// <summary> /// <summary>
/// Returns artist info with biography, image URLs and similar artists, using data from last.fm. /// Returns artist info with biography, image URLs and similar artists, using data from last.fm.
/// </summary> /// </summary>
public Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetArtistInfo(subsonic.Request request, public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetArtistInfo(subsonic.Request request, int? count, bool includeNotPresent, subsonic.ArtistInfoVersion version)
int? count, bool includeNotPresent, subsonic.ArtistInfoVersion version)
{ {
var artistId = SafeParser.ToGuid(request.id); var artistId = SafeParser.ToGuid(request.id);
if (!artistId.HasValue) if (!artistId.HasValue)
return Task.FromResult(new subsonic.SubsonicOperationResult<subsonic.Response>( return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid ArtistId [{request.id}]");
subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid ArtistId [{request.id}]")); var artist = await GetArtist(artistId.Value);
var artist = GetArtist(artistId.Value);
if (artist == null) if (artist == null)
return Task.FromResult(new subsonic.SubsonicOperationResult<subsonic.Response>( {
subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid ArtistId [{request.id}]")); return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid ArtistId [{request.id}]");
}
switch (version) switch (version)
{ {
case subsonic.ArtistInfoVersion.One: case subsonic.ArtistInfoVersion.One:
return Task.FromResult(new subsonic.SubsonicOperationResult<subsonic.Response> return new subsonic.SubsonicOperationResult<subsonic.Response>
{ {
IsSuccess = true, IsSuccess = true,
Data = new subsonic.Response Data = new subsonic.Response
@ -656,10 +652,10 @@ namespace Roadie.Api.Services
ItemElementName = subsonic.ItemChoiceType.artistInfo, ItemElementName = subsonic.ItemChoiceType.artistInfo,
Item = SubsonicArtistInfoForArtist(artist) Item = SubsonicArtistInfoForArtist(artist)
} }
}); };
case subsonic.ArtistInfoVersion.Two: case subsonic.ArtistInfoVersion.Two:
return Task.FromResult(new subsonic.SubsonicOperationResult<subsonic.Response> return new subsonic.SubsonicOperationResult<subsonic.Response>
{ {
IsSuccess = true, IsSuccess = true,
Data = new subsonic.Response Data = new subsonic.Response
@ -669,12 +665,12 @@ namespace Roadie.Api.Services
ItemElementName = subsonic.ItemChoiceType.artistInfo2, ItemElementName = subsonic.ItemChoiceType.artistInfo2,
Item = SubsonicArtistInfo2InfoForArtist(artist) Item = SubsonicArtistInfo2InfoForArtist(artist)
} }
}); };
default: default:
return Task.FromResult(new subsonic.SubsonicOperationResult<subsonic.Response>( return new subsonic.SubsonicOperationResult<subsonic.Response>(
subsonic.ErrorCodes.IncompatibleServerRestProtocolVersion, subsonic.ErrorCodes.IncompatibleServerRestProtocolVersion,
$"Unknown ArtistInfoVersion [{version}]")); $"Unknown ArtistInfoVersion [{version}]");
} }
} }
@ -756,59 +752,55 @@ namespace Roadie.Api.Services
/// <summary> /// <summary>
/// Returns a cover art image. /// Returns a cover art image.
/// </summary> /// </summary>
public async Task<subsonic.SubsonicFileOperationResult<Image>> GetCoverArt(subsonic.Request request, int? size) public async Task<subsonic.SubsonicFileOperationResult<Library.Models.Image>> GetCoverArt(subsonic.Request request, int? size)
{ {
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();
var result = new subsonic.SubsonicFileOperationResult<Image> var result = new subsonic.SubsonicFileOperationResult<Library.Models.Image>();
{
Data = new Image()
};
if (request.ArtistId != null) if (request.ArtistId != null)
{ {
var artistImage = await ImageService.ArtistImage(request.ArtistId.Value, size, size); var artistImage = await ImageService.ArtistImage(request.ArtistId.Value, size, size);
if (!artistImage.IsSuccess) return artistImage.Adapt<subsonic.SubsonicFileOperationResult<Image>>(); if (!artistImage.IsSuccess) return artistImage.Adapt<subsonic.SubsonicFileOperationResult<Library.Models.Image>>();
result.Data.Bytes = artistImage.Data.Bytes; result.Data = new Library.Models.Image(artistImage.Data.Bytes);
} }
else if (request.TrackId != null) else if (request.TrackId != null)
{ {
var trackimage = await ImageService.TrackImage(request.TrackId.Value, size, size); var trackimage = await ImageService.TrackImage(request.TrackId.Value, size, size);
if (!trackimage.IsSuccess) return trackimage.Adapt<subsonic.SubsonicFileOperationResult<Image>>(); if (!trackimage.IsSuccess) return trackimage.Adapt<subsonic.SubsonicFileOperationResult<Library.Models.Image>>();
result.Data.Bytes = trackimage.Data.Bytes; result.Data = new Library.Models.Image(trackimage.Data.Bytes);
} }
else if (request.CollectionId != null) else if (request.CollectionId != null)
{ {
var collectionImage = await ImageService.CollectionImage(request.CollectionId.Value, size, size); var collectionImage = await ImageService.CollectionImage(request.CollectionId.Value, size, size);
if (!collectionImage.IsSuccess) if (!collectionImage.IsSuccess)
return collectionImage.Adapt<subsonic.SubsonicFileOperationResult<Image>>(); return collectionImage.Adapt<subsonic.SubsonicFileOperationResult<Library.Models.Image>>();
result.Data.Bytes = collectionImage.Data.Bytes; result.Data = new Library.Models.Image(collectionImage.Data.Bytes);
} }
else if (request.ReleaseId != null) else if (request.ReleaseId != null)
{ {
var releaseimage = await ImageService.ReleaseImage(request.ReleaseId.Value, size, size); var releaseimage = await ImageService.ReleaseImage(request.ReleaseId.Value, size, size);
if (!releaseimage.IsSuccess) return releaseimage.Adapt<subsonic.SubsonicFileOperationResult<Image>>(); if (!releaseimage.IsSuccess) return releaseimage.Adapt<subsonic.SubsonicFileOperationResult<Library.Models.Image>>();
result.Data.Bytes = releaseimage.Data.Bytes; result.Data = new Library.Models.Image(releaseimage.Data.Bytes);
} }
else if (request.PlaylistId != null) else if (request.PlaylistId != null)
{ {
var playlistImage = await ImageService.PlaylistImage(request.PlaylistId.Value, size, size); var playlistImage = await ImageService.PlaylistImage(request.PlaylistId.Value, size, size);
if (!playlistImage.IsSuccess) return playlistImage.Adapt<subsonic.SubsonicFileOperationResult<Image>>(); if (!playlistImage.IsSuccess) return playlistImage.Adapt<subsonic.SubsonicFileOperationResult<Library.Models.Image>>();
result.Data.Bytes = playlistImage.Data.Bytes; result.Data = new Library.Models.Image(playlistImage.Data.Bytes);
} }
else if (!string.IsNullOrEmpty(request.u)) else if (!string.IsNullOrEmpty(request.u))
{ {
var user = GetUser(request.u); var user = await GetUser(request.u);
if (user == null) if (user == null)
return new subsonic.SubsonicFileOperationResult<Image>( return new subsonic.SubsonicFileOperationResult<Library.Models.Image>(
subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Username [{request.u}]"); subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Username [{request.u}]");
var userImage = await ImageService.UserImage(user.RoadieId, size, size); var userImage = await ImageService.UserImage(user.RoadieId, size, size);
if (!userImage.IsSuccess) return userImage.Adapt<subsonic.SubsonicFileOperationResult<Image>>(); if (!userImage.IsSuccess) return userImage.Adapt<subsonic.SubsonicFileOperationResult<Library.Models.Image>>();
result.Data.Bytes = userImage.Data.Bytes; result.Data = new Library.Models.Image(userImage.Data.Bytes);
} }
result.IsSuccess = result.Data.Bytes != null; result.IsSuccess = result.Data.Bytes != null;
sw.Stop(); sw.Stop();
return new subsonic.SubsonicFileOperationResult<Image>(result.Messages) return new subsonic.SubsonicFileOperationResult<Library.Models.Image>(result.Messages)
{ {
Data = result.Data, Data = result.Data,
ETag = result.ETag, ETag = result.ETag,
@ -936,17 +928,16 @@ namespace Roadie.Api.Services
/// getMusicDirectory. /// getMusicDirectory.
/// </param> /// </param>
/// <returns></returns> /// <returns></returns>
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetMusicDirectory( public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetMusicDirectory(subsonic.Request request, User roadieUser)
subsonic.Request request, User roadieUser)
{ {
var directory = new subsonic.Directory(); var directory = new subsonic.Directory();
var user = GetUser(roadieUser?.UserId); var user = await GetUser(roadieUser?.UserId);
// Request to get albums for an Artist // Request to get albums for an Artist
if (request.ArtistId != null) if (request.ArtistId != null)
{ {
var artistId = SafeParser.ToGuid(request.id); var artistId = SafeParser.ToGuid(request.id);
var artist = GetArtist(artistId.Value); var artist = await GetArtist(artistId.Value);
if (artist == null) if (artist == null)
return new subsonic.SubsonicOperationResult<subsonic.Response>( return new subsonic.SubsonicOperationResult<subsonic.Response>(
subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid ArtistId [{request.id}]"); subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid ArtistId [{request.id}]");
@ -972,7 +963,7 @@ namespace Roadie.Api.Services
else if (request.CollectionId != null) else if (request.CollectionId != null)
{ {
var collectionId = SafeParser.ToGuid(request.id); var collectionId = SafeParser.ToGuid(request.id);
var collection = GetCollection(collectionId.Value); var collection = await GetCollection(collectionId.Value);
if (collection == null) if (collection == null)
return new subsonic.SubsonicOperationResult<subsonic.Response>( return new subsonic.SubsonicOperationResult<subsonic.Response>(
subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid CollectionId [{request.id}]"); subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid CollectionId [{request.id}]");
@ -988,7 +979,7 @@ namespace Roadie.Api.Services
else if (request.ReleaseId.HasValue) else if (request.ReleaseId.HasValue)
{ {
var releaseId = SafeParser.ToGuid(request.id); var releaseId = SafeParser.ToGuid(request.id);
var release = GetRelease(releaseId.Value); var release = await GetRelease(releaseId.Value);
if (release == null) if (release == null)
return new subsonic.SubsonicOperationResult<subsonic.Response>( return new subsonic.SubsonicOperationResult<subsonic.Response>(
subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid ReleaseId [{request.id}]"); subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid ReleaseId [{request.id}]");
@ -1171,7 +1162,7 @@ namespace Roadie.Api.Services
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetPlayQueue(subsonic.Request request, public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetPlayQueue(subsonic.Request request,
User roadieUser) User roadieUser)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
subsonic.PlayQueue playQue = null; subsonic.PlayQueue playQue = null;
@ -1436,8 +1427,8 @@ namespace Roadie.Api.Services
{ {
data.Artist artist = null; data.Artist artist = null;
if (!string.IsNullOrEmpty(request.ArtistName)) if (!string.IsNullOrEmpty(request.ArtistName))
artist = base.GetArtist(request.ArtistName); artist = await base.GetArtist(request.ArtistName);
else if (request.ArtistId.HasValue) artist = GetArtist(request.ArtistId.Value); else if (request.ArtistId.HasValue) artist = await GetArtist(request.ArtistId.Value);
if (artist == null) if (artist == null)
return new subsonic.SubsonicOperationResult<subsonic.Response>( return new subsonic.SubsonicOperationResult<subsonic.Response>(
subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Unknown Artist [{request.ArtistName}]"); subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Unknown Artist [{request.ArtistName}]");
@ -1470,7 +1461,7 @@ namespace Roadie.Api.Services
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetUser(subsonic.Request request, public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetUser(subsonic.Request request,
string username) string username)
{ {
var user = GetUser(username); var user = await GetUser(username);
if (user == null) if (user == null)
return new subsonic.SubsonicOperationResult<subsonic.Response>( return new subsonic.SubsonicOperationResult<subsonic.Response>(
subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Username [{username}]"); subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Username [{username}]");
@ -1533,7 +1524,7 @@ namespace Roadie.Api.Services
User roadieUser, string current, long? position) User roadieUser, string current, long? position)
{ {
// Remove any existing Que for User // Remove any existing Que for User
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user.UserQues != null && user.UserQues.Any()) DbContext.UserQues.RemoveRange(user.UserQues); if (user.UserQues != null && user.UserQues.Any()) DbContext.UserQues.RemoveRange(user.UserQues);
// Create a new UserQue for each posted TrackId in ids // Create a new UserQue for each posted TrackId in ids
@ -1663,7 +1654,7 @@ namespace Roadie.Api.Services
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> SetRating(subsonic.Request request, public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> SetRating(subsonic.Request request,
User roadieUser, short rating) User roadieUser, short rating)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user == null) if (user == null)
return new subsonic.SubsonicOperationResult<subsonic.Response>( return new subsonic.SubsonicOperationResult<subsonic.Response>(
subsonic.ErrorCodes.UserIsNotAuthorizedForGivenOperation, $"Invalid User [{roadieUser}]"); subsonic.ErrorCodes.UserIsNotAuthorizedForGivenOperation, $"Invalid User [{roadieUser}]");
@ -1711,7 +1702,7 @@ namespace Roadie.Api.Services
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> ToggleStar(subsonic.Request request, public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> ToggleStar(subsonic.Request request,
User roadieUser, bool star, string[] albumIds = null, string[] artistIds = null) User roadieUser, bool star, string[] albumIds = null, string[] artistIds = null)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user == null) if (user == null)
return new subsonic.SubsonicOperationResult<subsonic.Response>( return new subsonic.SubsonicOperationResult<subsonic.Response>(
subsonic.ErrorCodes.UserIsNotAuthorizedForGivenOperation, $"Invalid User [{roadieUser}]"); subsonic.ErrorCodes.UserIsNotAuthorizedForGivenOperation, $"Invalid User [{roadieUser}]");
@ -1799,7 +1790,7 @@ namespace Roadie.Api.Services
if (!request.PlaylistId.HasValue) if (!request.PlaylistId.HasValue)
return new subsonic.SubsonicOperationResult<subsonic.Response>( return new subsonic.SubsonicOperationResult<subsonic.Response>(
subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Playlist Id [{request.id}]"); subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Playlist Id [{request.id}]");
var playlist = GetPlaylist(request.PlaylistId.Value); var playlist = await GetPlaylist(request.PlaylistId.Value);
if (playlist == null) if (playlist == null)
return new subsonic.SubsonicOperationResult<subsonic.Response>( return new subsonic.SubsonicOperationResult<subsonic.Response>(
subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Playlist Id [{request.TrackId.Value}]"); subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Playlist Id [{request.TrackId.Value}]");
@ -1842,7 +1833,7 @@ namespace Roadie.Api.Services
await DbContext.SaveChangesAsync(); await DbContext.SaveChangesAsync();
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
CacheManager.ClearRegion(user.CacheRegion); CacheManager.ClearRegion(user.CacheRegion);
return new subsonic.SubsonicOperationResult<subsonic.Response> return new subsonic.SubsonicOperationResult<subsonic.Response>
@ -1941,7 +1932,7 @@ namespace Roadie.Api.Services
{ {
id = subsonic.Request.CollectionIdentifier + c.RoadieId, id = subsonic.Request.CollectionIdentifier + c.RoadieId,
name = c.Name, name = c.Name,
artistImageUrl = MakeCollectionThumbnailImage(Configuration, HttpContext, c.RoadieId).Url, artistImageUrl = ImageHelper.MakeCollectionThumbnailImage(Configuration, HttpContext, c.RoadieId).Url,
averageRating = 0, averageRating = 0,
userRating = 0 userRating = 0
}).ToArray() }).ToArray()
@ -2072,7 +2063,7 @@ namespace Roadie.Api.Services
{ {
id = subsonic.Request.ArtistIdIdentifier + artist.Artist.Value, id = subsonic.Request.ArtistIdIdentifier + artist.Artist.Value,
name = artist.Artist.Text, name = artist.Artist.Text,
artistImageUrl = MakeArtistThumbnailImage(Configuration, HttpContext, artist.Id).Url, artistImageUrl = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, artist.Id).Url,
averageRating = artist.Rating ?? 0, averageRating = artist.Rating ?? 0,
averageRatingSpecified = true, averageRatingSpecified = true,
starred = artist.UserRating?.RatedDate ?? DateTime.UtcNow, starred = artist.UserRating?.RatedDate ?? DateTime.UtcNow,
@ -2084,7 +2075,7 @@ namespace Roadie.Api.Services
private subsonic.ArtistID3 SubsonicArtistID3ForArtist(ArtistList artist) private subsonic.ArtistID3 SubsonicArtistID3ForArtist(ArtistList artist)
{ {
var artistImageUrl = MakeArtistThumbnailImage(Configuration, HttpContext, artist.Id).Url; var artistImageUrl = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, artist.Id).Url;
return new subsonic.ArtistID3 return new subsonic.ArtistID3
{ {
id = subsonic.Request.ArtistIdIdentifier + artist.Artist.Value, id = subsonic.Request.ArtistIdIdentifier + artist.Artist.Value,
@ -2108,11 +2099,11 @@ namespace Roadie.Api.Services
return new subsonic.ArtistInfo2 return new subsonic.ArtistInfo2
{ {
biography = artist.BioContext, biography = artist.BioContext,
largeImageUrl = MakeImage(Configuration, HttpContext, artist.RoadieId, "artist", Configuration.LargeImageSize).Url, largeImageUrl = ImageHelper.MakeImage(Configuration, HttpContext, artist.RoadieId, "artist", Configuration.LargeImageSize).Url,
mediumImageUrl = MakeImage(Configuration, HttpContext, artist.RoadieId, "artist", Configuration.MediumImageSize).Url, mediumImageUrl = ImageHelper.MakeImage(Configuration, HttpContext, artist.RoadieId, "artist", Configuration.MediumImageSize).Url,
musicBrainzId = artist.MusicBrainzId, musicBrainzId = artist.MusicBrainzId,
similarArtist = new subsonic.ArtistID3[0], similarArtist = new subsonic.ArtistID3[0],
smallImageUrl = MakeImage(Configuration, HttpContext, artist.RoadieId, "artist", Configuration.SmallImageSize).Url smallImageUrl = ImageHelper.MakeImage(Configuration, HttpContext, artist.RoadieId, "artist", Configuration.SmallImageSize).Url
}; };
} }
@ -2121,11 +2112,11 @@ namespace Roadie.Api.Services
return new subsonic.ArtistInfo return new subsonic.ArtistInfo
{ {
biography = artist.BioContext, biography = artist.BioContext,
largeImageUrl = MakeImage(Configuration, HttpContext, artist.RoadieId, "artist", Configuration.LargeImageSize).Url, largeImageUrl = ImageHelper.MakeImage(Configuration, HttpContext, artist.RoadieId, "artist", Configuration.LargeImageSize).Url,
mediumImageUrl = MakeImage(Configuration, HttpContext, artist.RoadieId, "artist", Configuration.MediumImageSize).Url, mediumImageUrl = ImageHelper.MakeImage(Configuration, HttpContext, artist.RoadieId, "artist", Configuration.MediumImageSize).Url,
musicBrainzId = artist.MusicBrainzId, musicBrainzId = artist.MusicBrainzId,
similarArtist = new subsonic.Artist[0], similarArtist = new subsonic.Artist[0],
smallImageUrl = MakeImage(Configuration, HttpContext, artist.RoadieId, "artist", Configuration.SmallImageSize).Url smallImageUrl = ImageHelper.MakeImage(Configuration, HttpContext, artist.RoadieId, "artist", Configuration.SmallImageSize).Url
}; };
} }
@ -2138,7 +2129,7 @@ namespace Roadie.Api.Services
private subsonic.ArtistWithAlbumsID3 SubsonicArtistWithAlbumsID3ForArtist(ArtistList artist, private subsonic.ArtistWithAlbumsID3 SubsonicArtistWithAlbumsID3ForArtist(ArtistList artist,
subsonic.AlbumID3[] releases) subsonic.AlbumID3[] releases)
{ {
var artistImageUrl = MakeArtistThumbnailImage(Configuration, HttpContext, artist.Id).Url; var artistImageUrl = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, artist.Id).Url;
return new subsonic.ArtistWithAlbumsID3 return new subsonic.ArtistWithAlbumsID3
{ {
id = subsonic.Request.ArtistIdIdentifier + artist.Artist.Value, id = subsonic.Request.ArtistIdIdentifier + artist.Artist.Value,
@ -2291,7 +2282,7 @@ namespace Roadie.Api.Services
{ {
return new subsonic.PlaylistWithSongs return new subsonic.PlaylistWithSongs
{ {
coverArt = MakePlaylistThumbnailImage(Configuration, HttpContext, playlist.Id).Url, coverArt = ImageHelper.MakePlaylistThumbnailImage(Configuration, HttpContext, playlist.Id).Url,
allowedUser = playlist.IsPublic ? AllowedUsers() : null, allowedUser = playlist.IsPublic ? AllowedUsers() : null,
changed = playlist.LastUpdated ?? playlist.CreatedDate ?? DateTime.UtcNow, changed = playlist.LastUpdated ?? playlist.CreatedDate ?? DateTime.UtcNow,
created = playlist.CreatedDate ?? DateTime.UtcNow, created = playlist.CreatedDate ?? DateTime.UtcNow,

View file

@ -129,16 +129,16 @@ namespace Roadie.Api.Services
if (result?.Data != null && roadieUser != null) if (result?.Data != null && roadieUser != null)
{ {
tsw.Restart(); tsw.Restart();
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
tsw.Stop(); tsw.Stop();
timings.Add("getUser", tsw.ElapsedMilliseconds); timings.Add("getUser", tsw.ElapsedMilliseconds);
tsw.Restart(); tsw.Restart();
var track = GetTrack(id); var track = await GetTrack(id);
tsw.Stop(); tsw.Stop();
timings.Add("getTrack", tsw.ElapsedMilliseconds); timings.Add("getTrack", tsw.ElapsedMilliseconds);
result.Data.TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.Id, track.RoadieId); result.Data.TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.RoadieId);
tsw.Restart(); tsw.Restart();
var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Track); var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Track);
@ -227,7 +227,7 @@ namespace Roadie.Api.Services
var playlistTrackIds = new int[0]; var playlistTrackIds = new int[0];
if (request.FilterToPlaylistId.HasValue) if (request.FilterToPlaylistId.HasValue)
{ {
var playlistTrackInfos = (from plt in DbContext.PlaylistTracks var playlistTrackInfos = await (from plt in DbContext.PlaylistTracks
join p in DbContext.Playlists on plt.PlayListId equals p.Id join p in DbContext.Playlists on plt.PlayListId equals p.Id
join t in DbContext.Tracks on plt.TrackId equals t.Id join t in DbContext.Tracks on plt.TrackId equals t.Id
where p.RoadieId == request.FilterToPlaylistId.Value where p.RoadieId == request.FilterToPlaylistId.Value
@ -236,7 +236,7 @@ namespace Roadie.Api.Services
{ {
plt.ListNumber, plt.ListNumber,
t.Id t.Id
}).ToArray(); }).ToArrayAsync();
rowCount = playlistTrackInfos.Count(); rowCount = playlistTrackInfos.Count();
playListTrackPositions = playlistTrackInfos playListTrackPositions = playlistTrackInfos
@ -255,7 +255,7 @@ namespace Roadie.Api.Services
{ {
request.Limit = roadieUser?.PlayerTrackLimit ?? 50; request.Limit = roadieUser?.PlayerTrackLimit ?? 50;
collectionTrackIds = (from cr in DbContext.CollectionReleases collectionTrackIds = await (from cr in DbContext.CollectionReleases
join c in DbContext.Collections on cr.CollectionId equals c.Id join c in DbContext.Collections on cr.CollectionId equals c.Id
join r in DbContext.Releases on cr.ReleaseId equals r.Id join r in DbContext.Releases on cr.ReleaseId equals r.Id
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
@ -265,7 +265,7 @@ namespace Roadie.Api.Services
select t.Id) select t.Id)
.Skip(request.SkipValue) .Skip(request.SkipValue)
.Take(request.LimitValue) .Take(request.LimitValue)
.ToArray(); .ToArrayAsync();
} }
IQueryable<int> topTrackids = null; IQueryable<int> topTrackids = null;
@ -388,7 +388,7 @@ namespace Roadie.Api.Services
Text = r.Title, Text = r.Title,
Value = r.RoadieId.ToString() Value = r.RoadieId.ToString()
}, },
ArtistThumbnail = MakeArtistThumbnailImage(Configuration, HttpContext, releaseArtist.RoadieId), ArtistThumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, releaseArtist.RoadieId),
CreatedDate = r.CreatedDate, CreatedDate = r.CreatedDate,
Duration = r.Duration, Duration = r.Duration,
LastPlayed = r.LastPlayed, LastPlayed = r.LastPlayed,
@ -400,7 +400,7 @@ namespace Roadie.Api.Services
ReleaseDateDateTime = r.ReleaseDate, ReleaseDateDateTime = r.ReleaseDate,
ReleasePlayUrl = $"{HttpContext.BaseUrl}/play/release/{r.RoadieId}", ReleasePlayUrl = $"{HttpContext.BaseUrl}/play/release/{r.RoadieId}",
Status = r.Status, Status = r.Status,
Thumbnail = MakeReleaseThumbnailImage(Configuration, HttpContext, r.RoadieId), Thumbnail = ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, r.RoadieId),
TrackCount = r.TrackCount, TrackCount = r.TrackCount,
TrackPlayedCount = r.PlayedCount TrackPlayedCount = r.PlayedCount
}, },
@ -421,7 +421,7 @@ namespace Roadie.Api.Services
ReleaseCount = trackArtist.ReleaseCount, ReleaseCount = trackArtist.ReleaseCount,
TrackCount = trackArtist.TrackCount, TrackCount = trackArtist.TrackCount,
SortName = trackArtist.SortName, SortName = trackArtist.SortName,
Thumbnail = MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist.RoadieId) Thumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist.RoadieId)
}, },
ra = new ArtistList ra = new ArtistList
{ {
@ -438,7 +438,7 @@ namespace Roadie.Api.Services
ReleaseCount = releaseArtist.ReleaseCount, ReleaseCount = releaseArtist.ReleaseCount,
TrackCount = releaseArtist.TrackCount, TrackCount = releaseArtist.TrackCount,
SortName = releaseArtist.SortName, SortName = releaseArtist.SortName,
Thumbnail = MakeArtistThumbnailImage(Configuration, HttpContext, releaseArtist.RoadieId) Thumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, releaseArtist.RoadieId)
} }
}; };
@ -452,7 +452,7 @@ namespace Roadie.Api.Services
} }
} }
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
var result = resultQuery.Select(x => var result = resultQuery.Select(x =>
new TrackList new TrackList
{ {
@ -476,11 +476,11 @@ namespace Roadie.Api.Services
Rating = x.ti.Rating, Rating = x.ti.Rating,
Release = x.rl, Release = x.rl,
ReleaseDate = x.rl.ReleaseDateDateTime, ReleaseDate = x.rl.ReleaseDateDateTime,
Thumbnail = MakeTrackThumbnailImage(Configuration, HttpContext, x.ti.RoadieId), Thumbnail = ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, x.ti.RoadieId),
Title = x.ti.Title, Title = x.ti.Title,
TrackArtist = x.ta, TrackArtist = x.ta,
TrackNumber = x.ti.TrackNumber, TrackNumber = x.ti.TrackNumber,
TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, x.ti.Id, x.ti.RoadieId) TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, x.ti.RoadieId)
}); });
string sortBy = null; string sortBy = null;
@ -513,7 +513,7 @@ namespace Roadie.Api.Services
if (doRandomize ?? false) if (doRandomize ?? false)
{ {
var resultData = result.ToArray(); var resultData = await result.ToArrayAsync();
rows = (from r in resultData rows = (from r in resultData
join ra in randomTrackData on r.DatabaseId equals ra.Value join ra in randomTrackData on r.DatabaseId equals ra.Value
orderby ra.Key orderby ra.Key
@ -522,19 +522,19 @@ namespace Roadie.Api.Services
} }
else else
{ {
rows = result rows = await result
.OrderBy(sortBy) .OrderBy(sortBy)
.Skip(request.SkipValue) .Skip(request.SkipValue)
.Take(request.LimitValue) .Take(request.LimitValue)
.ToArray(); .ToArrayAsync();
} }
if (rows.Any() && roadieUser != null) if (rows.Any() && roadieUser != null)
{ {
var rowIds = rows.Select(x => x.DatabaseId).ToArray(); var rowIds = rows.Select(x => x.DatabaseId).ToArray();
var userTrackRatings = (from ut in DbContext.UserTracks var userTrackRatings = await (from ut in DbContext.UserTracks
where ut.UserId == roadieUser.Id where ut.UserId == roadieUser.Id
where rowIds.Contains(ut.TrackId) where rowIds.Contains(ut.TrackId)
select ut).ToArray(); select ut).ToArrayAsync();
foreach (var userTrackRating in userTrackRatings) foreach (var userTrackRating in userTrackRatings)
{ {
var row = rows.FirstOrDefault(x => x.DatabaseId == userTrackRating.TrackId); var row = rows.FirstOrDefault(x => x.DatabaseId == userTrackRating.TrackId);
@ -552,10 +552,10 @@ namespace Roadie.Api.Services
} }
var releaseIds = rows.Select(x => x.Release.DatabaseId).Distinct().ToArray(); var releaseIds = rows.Select(x => x.Release.DatabaseId).Distinct().ToArray();
var userReleaseRatings = (from ur in DbContext.UserReleases var userReleaseRatings = await (from ur in DbContext.UserReleases
where ur.UserId == roadieUser.Id where ur.UserId == roadieUser.Id
where releaseIds.Contains(ur.ReleaseId) where releaseIds.Contains(ur.ReleaseId)
select ur).ToArray(); select ur).ToArrayAsync();
foreach (var userReleaseRating in userReleaseRatings) foreach (var userReleaseRating in userReleaseRatings)
{ {
foreach (var row in rows.Where(x => x.Release.DatabaseId == userReleaseRating.ReleaseId)) foreach (var row in rows.Where(x => x.Release.DatabaseId == userReleaseRating.ReleaseId))
@ -567,10 +567,10 @@ namespace Roadie.Api.Services
var artistIds = rows.Select(x => x.Artist.DatabaseId).ToArray(); var artistIds = rows.Select(x => x.Artist.DatabaseId).ToArray();
if (artistIds != null && artistIds.Any()) if (artistIds != null && artistIds.Any())
{ {
var userArtistRatings = (from ua in DbContext.UserArtists var userArtistRatings = await (from ua in DbContext.UserArtists
where ua.UserId == roadieUser.Id where ua.UserId == roadieUser.Id
where artistIds.Contains(ua.ArtistId) where artistIds.Contains(ua.ArtistId)
select ua).ToArray(); select ua).ToArrayAsync();
foreach (var userArtistRating in userArtistRatings) foreach (var userArtistRating in userArtistRatings)
{ {
foreach (var artistTrack in rows.Where( foreach (var artistTrack in rows.Where(
@ -584,10 +584,10 @@ namespace Roadie.Api.Services
var trackArtistIds = rows.Where(x => x.TrackArtist != null).Select(x => x.TrackArtist.DatabaseId).ToArray(); var trackArtistIds = rows.Where(x => x.TrackArtist != null).Select(x => x.TrackArtist.DatabaseId).ToArray();
if (trackArtistIds != null && trackArtistIds.Any()) if (trackArtistIds != null && trackArtistIds.Any())
{ {
var userTrackArtistRatings = (from ua in DbContext.UserArtists var userTrackArtistRatings = await (from ua in DbContext.UserArtists
where ua.UserId == roadieUser.Id where ua.UserId == roadieUser.Id
where trackArtistIds.Contains(ua.ArtistId) where trackArtistIds.Contains(ua.ArtistId)
select ua).ToArray(); select ua).ToArrayAsync();
if (userTrackArtistRatings != null && userTrackArtistRatings.Any()) if (userTrackArtistRatings != null && userTrackArtistRatings.Any())
{ {
foreach (var userTrackArtistRating in userTrackArtistRatings) foreach (var userTrackArtistRating in userTrackArtistRatings)
@ -606,10 +606,10 @@ namespace Roadie.Api.Services
if (rows.Any()) if (rows.Any())
{ {
var rowIds = rows.Select(x => x.DatabaseId).ToArray(); var rowIds = rows.Select(x => x.DatabaseId).ToArray();
var favoriteUserTrackRatings = (from ut in DbContext.UserTracks var favoriteUserTrackRatings = await (from ut in DbContext.UserTracks
where ut.IsFavorite ?? false where ut.IsFavorite ?? false
where rowIds.Contains(ut.TrackId) where rowIds.Contains(ut.TrackId)
select ut).ToArray(); select ut).ToArrayAsync();
foreach (var row in rows) foreach (var row in rows)
{ {
row.FavoriteCount = favoriteUserTrackRatings.Where(x => x.TrackId == row.DatabaseId).Count(); row.FavoriteCount = favoriteUserTrackRatings.Where(x => x.TrackId == row.DatabaseId).Count();
@ -841,7 +841,7 @@ namespace Roadie.Api.Services
var artistId = SafeParser.ToGuid(model.TrackArtistToken.Value); var artistId = SafeParser.ToGuid(model.TrackArtistToken.Value);
if (artistId.HasValue) if (artistId.HasValue)
{ {
trackArtist = GetArtist(artistId.Value); trackArtist = await GetArtist(artistId.Value);
if (trackArtist != null) if (trackArtist != null)
{ {
track.ArtistId = trackArtist.Id; track.ArtistId = trackArtist.Id;
@ -853,6 +853,56 @@ namespace Roadie.Api.Services
track.ArtistId = null; track.ArtistId = null;
} }
if(model.Credits == null || !model.Credits.Any())
{
// Delete all existing credits for track
var trackCreditsToDelete = (from c in DbContext.Credits
where c.TrackId == track.Id
select c).ToArray();
DbContext.Credits.RemoveRange(trackCreditsToDelete);
}
else if(model.Credits != null && model.Credits.Any())
{
var trackCreditIds = model.Credits.Select(x => x.Id).ToArray();
// Delete any credits not given in model (removed by edit operation)
var trackCreditsToDelete = (from c in DbContext.Credits
where c.TrackId == track.Id
where !trackCreditIds.Contains(c.RoadieId)
select c).ToArray();
DbContext.Credits.RemoveRange(trackCreditsToDelete);
// Update any existing
foreach(var credit in model.Credits)
{
var trackCredit = DbContext.Credits.FirstOrDefault(x => x.RoadieId == credit.Id);
if(trackCredit == null)
{
// Add new
trackCredit = new data.Credit
{
TrackId = track.Id,
CreatedDate = now
};
DbContext.Credits.Add(trackCredit);
}
data.Artist artistForCredit = null;
if (credit.Artist != null)
{
artistForCredit = await GetArtist(credit.Artist.Id);
}
var creditCategory = DbContext.CreditCategory.FirstOrDefault(x => x.RoadieId.ToString() == credit.Category.Value);
trackCredit.CreditCategoryId = creditCategory.Id;
trackCredit.ArtistId = artistForCredit == null ? null : (int?)artistForCredit.Id;
trackCredit.IsLocked = credit.IsLocked;
trackCredit.Status = SafeParser.ToEnum<Statuses>(credit.Status);
trackCredit.CreditToName = artistForCredit == null ? credit.CreditName : null;
trackCredit.Description = credit.Description;
trackCredit.URLs = credit.URLs;
trackCredit.Tags = credit.Tags;
trackCredit.LastUpdated = now;
}
}
var trackImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData); var trackImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
if (trackImage != null) if (trackImage != null)
{ {
@ -902,7 +952,7 @@ namespace Roadie.Api.Services
}; };
} }
private Task<OperationResult<Track>> TrackByIdAction(Guid id, IEnumerable<string> includes) private async Task<OperationResult<Track>> TrackByIdAction(Guid id, IEnumerable<string> includes)
{ {
var timings = new Dictionary<string, long>(); var timings = new Dictionary<string, long>();
var tsw = new Stopwatch(); var tsw = new Stopwatch();
@ -911,13 +961,13 @@ namespace Roadie.Api.Services
sw.Start(); sw.Start();
tsw.Restart(); tsw.Restart();
var track = GetTrack(id); var track = await GetTrack(id);
tsw.Stop(); tsw.Stop();
timings.Add("getTrack", tsw.ElapsedMilliseconds); timings.Add("getTrack", tsw.ElapsedMilliseconds);
if (track == null) if (track == null)
{ {
return Task.FromResult(new OperationResult<Track>(true, string.Format("Track Not Found [{0}]", id))); return new OperationResult<Track>(true, string.Format("Track Not Found [{0}]", id));
} }
tsw.Restart(); tsw.Restart();
var result = track.Adapt<Track>(); var result = track.Adapt<Track>();
@ -925,16 +975,16 @@ namespace Roadie.Api.Services
(track.ReleaseMedia.IsLocked ?? false) || (track.ReleaseMedia.IsLocked ?? false) ||
(track.ReleaseMedia.Release.IsLocked ?? false) || (track.ReleaseMedia.Release.IsLocked ?? false) ||
(track.ReleaseMedia.Release.Artist.IsLocked ?? false); (track.ReleaseMedia.Release.Artist.IsLocked ?? false);
result.Thumbnail = MakeTrackThumbnailImage(Configuration, HttpContext, id); result.Thumbnail = ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, id);
result.MediumThumbnail = MakeThumbnailImage(Configuration, HttpContext, id, "track", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height); result.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "track", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
result.ReleaseMediaId = track.ReleaseMedia.RoadieId.ToString(); result.ReleaseMediaId = track.ReleaseMedia.RoadieId.ToString();
result.Artist = ArtistList.FromDataArtist(track.ReleaseMedia.Release.Artist, result.Artist = ArtistList.FromDataArtist(track.ReleaseMedia.Release.Artist,
MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId)); ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId));
result.ArtistThumbnail = MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId); result.ArtistThumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId);
result.Release = ReleaseList.FromDataRelease(track.ReleaseMedia.Release, track.ReleaseMedia.Release.Artist, result.Release = ReleaseList.FromDataRelease(track.ReleaseMedia.Release, track.ReleaseMedia.Release.Artist,
HttpContext.BaseUrl, MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId), HttpContext.BaseUrl, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId),
MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId)); ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId));
result.ReleaseThumbnail = MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId); result.ReleaseThumbnail = ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId);
tsw.Stop(); tsw.Stop();
timings.Add("adapt", tsw.ElapsedMilliseconds); timings.Add("adapt", tsw.ElapsedMilliseconds);
if (track.ArtistId.HasValue) if (track.ArtistId.HasValue)
@ -948,9 +998,9 @@ namespace Roadie.Api.Services
else else
{ {
result.TrackArtist = result.TrackArtist =
ArtistList.FromDataArtist(trackArtist, MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist.RoadieId)); ArtistList.FromDataArtist(trackArtist, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist.RoadieId));
result.TrackArtistToken = result.TrackArtist.Artist; result.TrackArtistToken = result.TrackArtist.Artist;
result.TrackArtistThumbnail = MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist.RoadieId); result.TrackArtistThumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist.RoadieId);
} }
tsw.Stop(); tsw.Stop();
timings.Add("trackArtist", tsw.ElapsedMilliseconds); timings.Add("trackArtist", tsw.ElapsedMilliseconds);
@ -958,6 +1008,32 @@ namespace Roadie.Api.Services
if (includes != null && includes.Any()) if (includes != null && includes.Any())
{ {
if (includes.Contains("credits"))
{
tsw.Restart();
result.Credits = (await(from c in DbContext.Credits
join cc in DbContext.CreditCategory on c.CreditCategoryId equals cc.Id
join a in DbContext.Artists on c.ArtistId equals a.Id into agg
from a in agg.DefaultIfEmpty()
where c.TrackId == track.Id
select new { c, cc, a })
.ToListAsync())
.Select(x => new CreditList
{
Id = x.c.RoadieId,
Artist = x.a == null ? null : ArtistList.FromDataArtist(x.a, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, x.a.RoadieId)),
Category = new DataToken {
Text = x.cc.Name,
Value = x.cc.RoadieId.ToString()
},
CreditName = x.a?.Name ?? x.c.CreditToName,
Description = x.c.Description
}).ToArray();
tsw.Stop();
timings.Add("credits", tsw.ElapsedMilliseconds);
}
if (includes.Contains("stats")) if (includes.Contains("stats"))
{ {
tsw.Restart(); tsw.Restart();
@ -997,7 +1073,7 @@ namespace Roadie.Api.Services
var comment = trackComment.Adapt<Comment>(); var comment = trackComment.Adapt<Comment>();
comment.DatabaseId = trackComment.Id; comment.DatabaseId = trackComment.Id;
comment.User = UserList.FromDataUser(trackComment.User, comment.User = UserList.FromDataUser(trackComment.User,
MakeUserThumbnailImage(Configuration, HttpContext, trackComment.User.RoadieId)); ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, trackComment.User.RoadieId));
comment.DislikedCount = userCommentReactions.Count(x => comment.DislikedCount = userCommentReactions.Count(x =>
x.CommentId == trackComment.Id && x.ReactionValue == CommentReaction.Dislike); x.CommentId == trackComment.Id && x.ReactionValue == CommentReaction.Dislike);
comment.LikedCount = userCommentReactions.Count(x => comment.LikedCount = userCommentReactions.Count(x =>
@ -1014,12 +1090,12 @@ namespace Roadie.Api.Services
sw.Stop(); sw.Stop();
Logger.LogInformation($"ByIdAction: Track `{ track }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]"); Logger.LogInformation($"ByIdAction: Track `{ track }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]");
return Task.FromResult(new OperationResult<Track> return new OperationResult<Track>
{ {
Data = result, Data = result,
IsSuccess = result != null, IsSuccess = result != null,
OperationTime = sw.ElapsedMilliseconds OperationTime = sw.ElapsedMilliseconds
}); };
} }
} }
} }

View file

@ -58,8 +58,10 @@ namespace Roadie.Api.Services
{ {
if (user.UserId != id && !user.IsAdmin) if (user.UserId != id && !user.IsAdmin)
{ {
var r = new OperationResult<User>("Access Denied"); var r = new OperationResult<User>("Access Denied")
r.IsAccessDeniedResult = true; {
IsAccessDeniedResult = true
};
return r; return r;
} }
} }
@ -74,7 +76,7 @@ namespace Roadie.Api.Services
sw.Stop(); sw.Stop();
if (result?.Data != null) if (result?.Data != null)
{ {
result.Data.Avatar = MakeUserThumbnailImage(Configuration, HttpContext, id); result.Data.Avatar = ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, id);
if (!isAccountSettingsEdit) if (!isAccountSettingsEdit)
{ {
result.Data.ApiToken = null; result.Data.ApiToken = null;
@ -114,7 +116,7 @@ namespace Roadie.Api.Services
IsEditor = u.UserRoles.Any(x => x.Role.Name == "Editor"), IsEditor = u.UserRoles.Any(x => x.Role.Name == "Editor"),
IsAdmin = u.UserRoles.Any(x => x.Role.Name == "Admin"), IsAdmin = u.UserRoles.Any(x => x.Role.Name == "Admin"),
IsPrivate = u.IsPrivate, IsPrivate = u.IsPrivate,
Thumbnail = MakeUserThumbnailImage(Configuration, HttpContext, u.RoadieId), Thumbnail = ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, u.RoadieId),
CreatedDate = u.CreatedDate, CreatedDate = u.CreatedDate,
LastUpdated = u.LastUpdated, LastUpdated = u.LastUpdated,
RegisteredDate = u.RegisteredOn, RegisteredDate = u.RegisteredOn,
@ -170,14 +172,34 @@ namespace Roadie.Api.Services
}); });
} }
public async Task<OperationResult<bool>> SetArtistBookmark(Guid artistId, User roadieUser, bool isBookmarked) public async Task<OperationResult<bool>> DeleteAllBookmarks(User roadieUser)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user == null) if (user == null)
{ {
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]"); return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
} }
var artist = GetArtist(artistId);
DbContext.Bookmarks.RemoveRange(DbContext.Bookmarks.Where(x => x.UserId == user.Id));
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(user.CacheRegion);
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
public async Task<OperationResult<bool>> SetArtistBookmark(Guid artistId, User roadieUser, bool isBookmarked)
{
var user = await GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
}
var artist = await GetArtist(artistId);
if (artist == null) if (artist == null)
{ {
return new OperationResult<bool>(true, $"Invalid Artist [{artistId}]"); return new OperationResult<bool>(true, $"Invalid Artist [{artistId}]");
@ -195,7 +217,7 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> SetArtistDisliked(Guid artistId, User roadieUser, bool isDisliked) public async Task<OperationResult<bool>> SetArtistDisliked(Guid artistId, User roadieUser, bool isDisliked)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user == null) if (user == null)
{ {
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]"); return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
@ -205,7 +227,7 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> SetArtistFavorite(Guid artistId, User roadieUser, bool isFavorite) public async Task<OperationResult<bool>> SetArtistFavorite(Guid artistId, User roadieUser, bool isFavorite)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user == null) if (user == null)
{ {
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]"); return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
@ -215,23 +237,22 @@ namespace Roadie.Api.Services
public async Task<OperationResult<short>> SetArtistRating(Guid artistId, User roadieUser, short rating) public async Task<OperationResult<short>> SetArtistRating(Guid artistId, User roadieUser, short rating)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user == null) if (user == null)
{ {
return new OperationResult<short>(true, $"Invalid User [{roadieUser}]"); return new OperationResult<short>(true, $"Invalid User [{roadieUser}]");
} }
return await base.SetArtistRating(artistId, user, rating); return await SetArtistRating(artistId, user, rating);
} }
public async Task<OperationResult<bool>> SetCollectionBookmark(Guid collectionId, User roadieUser, public async Task<OperationResult<bool>> SetCollectionBookmark(Guid collectionId, User roadieUser, bool isBookmarked)
bool isBookmarked)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user == null) if (user == null)
{ {
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]"); return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
} }
var collection = GetCollection(collectionId); var collection = await GetCollection(collectionId);
if (collection == null) if (collection == null)
{ {
return new OperationResult<bool>(true, $"Invalid Collection [{collectionId}]"); return new OperationResult<bool>(true, $"Invalid Collection [{collectionId}]");
@ -249,12 +270,12 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> SetLabelBookmark(Guid labelId, User roadieUser, bool isBookmarked) public async Task<OperationResult<bool>> SetLabelBookmark(Guid labelId, User roadieUser, bool isBookmarked)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user == null) if (user == null)
{ {
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]"); return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
} }
var label = GetLabel(labelId); var label = await GetLabel(labelId);
if (label == null) if (label == null)
{ {
return new OperationResult<bool>(true, $"Invalid Label [{labelId}]"); return new OperationResult<bool>(true, $"Invalid Label [{labelId}]");
@ -273,17 +294,17 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> SetPlaylistBookmark(Guid playlistId, User roadieUser, public async Task<OperationResult<bool>> SetPlaylistBookmark(Guid playlistId, User roadieUser,
bool isBookmarked) bool isBookmarked)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user == null) if (user == null)
{ {
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]"); return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
} }
var playlist = GetPlaylist(playlistId); var playlist = await GetPlaylist(playlistId);
if (playlist == null) if (playlist == null)
{ {
return new OperationResult<bool>(true, $"Invalid Playlist [{playlistId}]"); return new OperationResult<bool>(true, $"Invalid Playlist [{playlistId}]");
} }
var result = await SetBookmark(user, BookmarkType.Playlist, playlist.Id, isBookmarked); await SetBookmark(user, BookmarkType.Playlist, playlist.Id, isBookmarked);
CacheManager.ClearRegion(playlist.CacheRegion); CacheManager.ClearRegion(playlist.CacheRegion);
@ -296,17 +317,17 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> SetReleaseBookmark(Guid releaseid, User roadieUser, bool isBookmarked) public async Task<OperationResult<bool>> SetReleaseBookmark(Guid releaseid, User roadieUser, bool isBookmarked)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user == null) if (user == null)
{ {
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]"); return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
} }
var release = GetRelease(releaseid); var release = await GetRelease(releaseid);
if (release == null) if (release == null)
{ {
return new OperationResult<bool>(true, $"Invalid Release [{releaseid}]"); return new OperationResult<bool>(true, $"Invalid Release [{releaseid}]");
} }
var result = await SetBookmark(user, BookmarkType.Release, release.Id, isBookmarked); await SetBookmark(user, BookmarkType.Release, release.Id, isBookmarked);
CacheManager.ClearRegion(release.CacheRegion); CacheManager.ClearRegion(release.CacheRegion);
@ -319,7 +340,7 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> SetReleaseDisliked(Guid releaseId, User roadieUser, bool isDisliked) public async Task<OperationResult<bool>> SetReleaseDisliked(Guid releaseId, User roadieUser, bool isDisliked)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user == null) if (user == null)
{ {
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]"); return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
@ -329,7 +350,7 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> SetReleaseFavorite(Guid releaseId, User roadieUser, bool isFavorite) public async Task<OperationResult<bool>> SetReleaseFavorite(Guid releaseId, User roadieUser, bool isFavorite)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user == null) if (user == null)
{ {
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]"); return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
@ -339,7 +360,7 @@ namespace Roadie.Api.Services
public async Task<OperationResult<short>> SetReleaseRating(Guid releaseId, User roadieUser, short rating) public async Task<OperationResult<short>> SetReleaseRating(Guid releaseId, User roadieUser, short rating)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user == null) if (user == null)
{ {
return new OperationResult<short>(true, $"Invalid User [{roadieUser}]"); return new OperationResult<short>(true, $"Invalid User [{roadieUser}]");
@ -349,17 +370,17 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> SetTrackBookmark(Guid trackId, User roadieUser, bool isBookmarked) public async Task<OperationResult<bool>> SetTrackBookmark(Guid trackId, User roadieUser, bool isBookmarked)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user == null) if (user == null)
{ {
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]"); return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
} }
var track = GetTrack(trackId); var track = await GetTrack(trackId);
if (track == null) if (track == null)
{ {
return new OperationResult<bool>(true, $"Invalid Track [{trackId}]"); return new OperationResult<bool>(true, $"Invalid Track [{trackId}]");
} }
var result = await SetBookmark(user, BookmarkType.Track, track.Id, isBookmarked); await SetBookmark(user, BookmarkType.Track, track.Id, isBookmarked);
CacheManager.ClearRegion(track.CacheRegion); CacheManager.ClearRegion(track.CacheRegion);
@ -372,7 +393,7 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> SetTrackDisliked(Guid trackId, User roadieUser, bool isDisliked) public async Task<OperationResult<bool>> SetTrackDisliked(Guid trackId, User roadieUser, bool isDisliked)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user == null) if (user == null)
{ {
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]"); return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
@ -382,7 +403,7 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> SetTrackFavorite(Guid trackId, User roadieUser, bool isFavorite) public async Task<OperationResult<bool>> SetTrackFavorite(Guid trackId, User roadieUser, bool isFavorite)
{ {
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
if (user == null) if (user == null)
{ {
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]"); return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
@ -394,7 +415,7 @@ namespace Roadie.Api.Services
{ {
var timings = new Dictionary<string, long>(); var timings = new Dictionary<string, long>();
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();
var user = GetUser(roadieUser.UserId); var user = await GetUser(roadieUser.UserId);
sw.Stop(); sw.Stop();
timings.Add("GetUser", sw.ElapsedMilliseconds); timings.Add("GetUser", sw.ElapsedMilliseconds);
@ -616,7 +637,7 @@ namespace Roadie.Api.Services
var tsw = new Stopwatch(); var tsw = new Stopwatch();
tsw.Restart(); tsw.Restart();
var user = GetUser(id); var user = await GetUser(id);
tsw.Stop(); tsw.Stop();
timings.Add("getUser", tsw.ElapsedMilliseconds); timings.Add("getUser", tsw.ElapsedMilliseconds);
@ -626,7 +647,7 @@ namespace Roadie.Api.Services
} }
tsw.Restart(); tsw.Restart();
var model = user.Adapt<User>(); var model = user.Adapt<User>();
model.MediumThumbnail = MakeThumbnailImage(Configuration, HttpContext, id, "user", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height); model.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "user", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
model.IsAdmin = user.UserRoles?.Any(x => x.Role?.NormalizedName == "ADMIN") ?? false; 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; model.IsEditor = model.IsAdmin ? true : user.UserRoles?.Any(x => x.Role?.NormalizedName == "EDITOR") ?? false;
tsw.Stop(); tsw.Stop();
@ -650,44 +671,44 @@ namespace Roadie.Api.Services
LastPlayedTrack = lastPlayedTrack == null LastPlayedTrack = lastPlayedTrack == null
? null ? null
: models.TrackList.FromDataTrack( : models.TrackList.FromDataTrack(
MakeTrackPlayUrl(user, HttpContext.BaseUrl, lastPlayedTrack.Id, lastPlayedTrack.RoadieId), MakeTrackPlayUrl(user, HttpContext.BaseUrl, lastPlayedTrack.RoadieId),
lastPlayedTrack, lastPlayedTrack,
lastPlayedTrack.ReleaseMedia.MediaNumber, lastPlayedTrack.ReleaseMedia.MediaNumber,
lastPlayedTrack.ReleaseMedia.Release, lastPlayedTrack.ReleaseMedia.Release,
lastPlayedTrack.ReleaseMedia.Release.Artist, lastPlayedTrack.ReleaseMedia.Release.Artist,
lastPlayedTrack.TrackArtist, lastPlayedTrack.TrackArtist,
HttpContext.BaseUrl, HttpContext.BaseUrl,
MakeTrackThumbnailImage(Configuration, HttpContext, lastPlayedTrack.RoadieId), ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, lastPlayedTrack.RoadieId),
MakeReleaseThumbnailImage(Configuration, HttpContext, lastPlayedTrack.ReleaseMedia.Release.RoadieId), ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, lastPlayedTrack.ReleaseMedia.Release.RoadieId),
MakeArtistThumbnailImage(Configuration, HttpContext, lastPlayedTrack.ReleaseMedia.Release.Artist.RoadieId), ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, lastPlayedTrack.ReleaseMedia.Release.Artist.RoadieId),
MakeArtistThumbnailImage(Configuration, HttpContext, lastPlayedTrack.TrackArtist == null ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, lastPlayedTrack.TrackArtist == null
? null ? null
: (Guid?)lastPlayedTrack.TrackArtist.RoadieId)), : (Guid?)lastPlayedTrack.TrackArtist.RoadieId)),
MostPlayedArtist = mostPlayedArtist == null MostPlayedArtist = mostPlayedArtist == null
? null ? null
: models.ArtistList.FromDataArtist(mostPlayedArtist, : models.ArtistList.FromDataArtist(mostPlayedArtist,
MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedArtist.RoadieId)), ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedArtist.RoadieId)),
MostPlayedRelease = mostPlayedRelease == null MostPlayedRelease = mostPlayedRelease == null
? null ? null
: ReleaseList.FromDataRelease(mostPlayedRelease, : ReleaseList.FromDataRelease(mostPlayedRelease,
mostPlayedRelease.Artist, mostPlayedRelease.Artist,
HttpContext.BaseUrl, HttpContext.BaseUrl,
MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedRelease.Artist.RoadieId), ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedRelease.Artist.RoadieId),
MakeReleaseThumbnailImage(Configuration, HttpContext, mostPlayedRelease.RoadieId)), ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, mostPlayedRelease.RoadieId)),
MostPlayedTrack = mostPlayedTrack == null MostPlayedTrack = mostPlayedTrack == null
? null ? null
: models.TrackList.FromDataTrack( : models.TrackList.FromDataTrack(
MakeTrackPlayUrl(user, HttpContext.BaseUrl, mostPlayedTrack.Id, mostPlayedTrack.RoadieId), MakeTrackPlayUrl(user, HttpContext.BaseUrl, mostPlayedTrack.RoadieId),
mostPlayedTrack, mostPlayedTrack,
mostPlayedTrack.ReleaseMedia.MediaNumber, mostPlayedTrack.ReleaseMedia.MediaNumber,
mostPlayedTrack.ReleaseMedia.Release, mostPlayedTrack.ReleaseMedia.Release,
mostPlayedTrack.ReleaseMedia.Release.Artist, mostPlayedTrack.ReleaseMedia.Release.Artist,
mostPlayedTrack.TrackArtist, mostPlayedTrack.TrackArtist,
HttpContext.BaseUrl, HttpContext.BaseUrl,
MakeTrackThumbnailImage(Configuration, HttpContext, mostPlayedTrack.RoadieId), ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, mostPlayedTrack.RoadieId),
MakeReleaseThumbnailImage(Configuration, HttpContext, mostPlayedTrack.ReleaseMedia.Release.RoadieId), ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, mostPlayedTrack.ReleaseMedia.Release.RoadieId),
MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedTrack.ReleaseMedia.Release.Artist.RoadieId), ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedTrack.ReleaseMedia.Release.Artist.RoadieId),
MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedTrack.TrackArtist == null ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedTrack.TrackArtist == null
? null ? null
: (Guid?)mostPlayedTrack.TrackArtist.RoadieId)), : (Guid?)mostPlayedTrack.TrackArtist.RoadieId)),
RatedArtists = userArtists.Where(x => x.Rating > 0).Count(), RatedArtists = userArtists.Where(x => x.Rating > 0).Count(),

View file

@ -13,6 +13,7 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using models = Roadie.Library.Models.Users; using models = Roadie.Library.Models.Users;
@ -150,6 +151,6 @@ namespace Roadie.Api.Controllers
result.IsAdmin = User.IsInRole("Admin"); result.IsAdmin = User.IsInRole("Admin");
result.IsEditor = User.IsInRole("Editor") || result.IsAdmin; result.IsEditor = User.IsInRole("Editor") || result.IsAdmin;
return result; return result;
} }
} }
} }

View file

@ -1,8 +1,7 @@
using Mapster; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using Roadie.Api.Services; using Roadie.Api.Services;
using Roadie.Library.Caching; using Roadie.Library.Caching;
using Roadie.Library.Configuration; using Roadie.Library.Configuration;
@ -43,12 +42,7 @@ namespace Roadie.Api.Controllers
{ {
return StatusCode((int)HttpStatusCode.InternalServerError); return StatusCode((int)HttpStatusCode.InternalServerError);
} }
var model = result.Data.Adapt<Library.Models.Image>(); return MakeFileResult(result.Data.Bytes, $"{id}.jpg", result.ContentType, result.LastModified, result.ETag);
return File(model.Bytes,
result.ContentType,
$"{model.Caption ?? id.ToString()}.jpg",
result.LastModified,
result.ETag);
} }
[HttpGet("artist-secondary/{id}/{imageId}/{width:int?}/{height:int?}/{cacheBuster?}")] [HttpGet("artist-secondary/{id}/{imageId}/{width:int?}/{height:int?}/{cacheBuster?}")]
@ -65,12 +59,7 @@ namespace Roadie.Api.Controllers
{ {
return StatusCode((int)HttpStatusCode.InternalServerError); return StatusCode((int)HttpStatusCode.InternalServerError);
} }
var model = result.Data.Adapt<Library.Models.Image>(); return MakeFileResult(result.Data.Bytes, $"{id}.jpg", result.ContentType, result.LastModified, result.ETag);
return File(model.Bytes,
result.ContentType,
$"{model.Caption ?? id.ToString()}.jpg",
result.LastModified,
result.ETag);
} }
[HttpGet("collection/{id}/{width:int?}/{height:int?}/{cacheBuster?}")] [HttpGet("collection/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
@ -87,34 +76,7 @@ namespace Roadie.Api.Controllers
{ {
return StatusCode((int)HttpStatusCode.InternalServerError); return StatusCode((int)HttpStatusCode.InternalServerError);
} }
var model = result.Data.Adapt<Library.Models.Image>(); return MakeFileResult(result.Data.Bytes, $"{id}.jpg", result.ContentType, result.LastModified, result.ETag);
return File(model.Bytes,
result.ContentType,
$"{model.Caption ?? id.ToString()}.jpg",
result.LastModified,
result.ETag);
}
[HttpGet("{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> Get(Guid id, int? width, int? height)
{
var result = await ImageService.ById(id, width, height);
if (result == null)
{
return NotFound();
}
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
var model = result.Data.Adapt<Library.Models.Image>();
return File(model.Bytes,
result.ContentType,
$"{model.Caption ?? id.ToString()}.jpg",
result.LastModified,
result.ETag);
} }
[HttpGet("label/{id}/{width:int?}/{height:int?}/{cacheBuster?}")] [HttpGet("label/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
@ -131,12 +93,7 @@ namespace Roadie.Api.Controllers
{ {
return StatusCode((int)HttpStatusCode.InternalServerError); return StatusCode((int)HttpStatusCode.InternalServerError);
} }
var model = result.Data.Adapt<Library.Models.Image>(); return MakeFileResult(result.Data.Bytes, $"{id}.jpg", result.ContentType, result.LastModified, result.ETag);
return File(model.Bytes,
result.ContentType,
$"{model.Caption ?? id.ToString()}.jpg",
result.LastModified,
result.ETag);
} }
[HttpGet("genre/{id}/{width:int?}/{height:int?}/{cacheBuster?}")] [HttpGet("genre/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
@ -153,12 +110,7 @@ namespace Roadie.Api.Controllers
{ {
return StatusCode((int)HttpStatusCode.InternalServerError); return StatusCode((int)HttpStatusCode.InternalServerError);
} }
var model = result.Data.Adapt<Library.Models.Image>(); return MakeFileResult(result.Data.Bytes, $"{id}.jpg", result.ContentType, result.LastModified, result.ETag);
return File(model.Bytes,
result.ContentType,
$"{model.Caption ?? id.ToString()}.jpg",
result.LastModified,
result.ETag);
} }
[HttpGet("playlist/{id}/{width:int?}/{height:int?}/{cacheBuster?}")] [HttpGet("playlist/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
@ -175,12 +127,7 @@ namespace Roadie.Api.Controllers
{ {
return StatusCode((int)HttpStatusCode.InternalServerError); return StatusCode((int)HttpStatusCode.InternalServerError);
} }
var model = result.Data.Adapt<Library.Models.Image>(); return MakeFileResult(result.Data.Bytes, $"{id}.jpg", result.ContentType, result.LastModified, result.ETag);
return File(model.Bytes,
result.ContentType,
$"{model.Caption ?? id.ToString()}.jpg",
result.LastModified,
result.ETag);
} }
[HttpGet("release/{id}/{width:int?}/{height:int?}/{cacheBuster?}")] [HttpGet("release/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
@ -197,12 +144,7 @@ namespace Roadie.Api.Controllers
{ {
return StatusCode((int)HttpStatusCode.InternalServerError); return StatusCode((int)HttpStatusCode.InternalServerError);
} }
var model = result.Data.Adapt<Library.Models.Image>(); return MakeFileResult(result.Data.Bytes, $"{id}.jpg", result.ContentType, result.LastModified, result.ETag);
return File(model.Bytes,
result.ContentType,
$"{model.Caption ?? id.ToString()}.jpg",
result.LastModified,
result.ETag);
} }
[HttpGet("release-secondary/{id}/{imageId}/{width:int?}/{height:int?}/{cacheBuster?}")] [HttpGet("release-secondary/{id}/{imageId}/{width:int?}/{height:int?}/{cacheBuster?}")]
@ -219,12 +161,7 @@ namespace Roadie.Api.Controllers
{ {
return StatusCode((int)HttpStatusCode.InternalServerError); return StatusCode((int)HttpStatusCode.InternalServerError);
} }
var model = result.Data.Adapt<Library.Models.Image>(); return MakeFileResult(result.Data.Bytes, $"{id}.jpg", result.ContentType, result.LastModified, result.ETag);
return File(model.Bytes,
result.ContentType,
$"{model.Caption ?? id.ToString()}.jpg",
result.LastModified,
result.ETag);
} }
[HttpPost("search/artist/{query}/{resultsCount:int?}")] [HttpPost("search/artist/{query}/{resultsCount:int?}")]
@ -297,16 +234,13 @@ namespace Roadie.Api.Controllers
{ {
return StatusCode((int)HttpStatusCode.InternalServerError); return StatusCode((int)HttpStatusCode.InternalServerError);
} }
var model = result.Data.Adapt<Library.Models.Image>(); return MakeFileResult(result.Data.Bytes, $"{id}.jpg", result.ContentType, result.LastModified, result.ETag);
return File(model.Bytes,
result.ContentType,
$"{model.Caption ?? id.ToString()}.jpg",
result.LastModified,
result.ETag);
} }
private IActionResult MakeFileResult(byte[] bytes, string fileName, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue eTag) => File(bytes, contentType, fileName, lastModified, eTag);
/// <summary> /// <summary>
/// NOTE that user images/avatars are GIF 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 and allows for animated avatars.
/// </summary> /// </summary>
[HttpGet("user/{id}/{width:int?}/{height:int?}/{cacheBuster?}")] [HttpGet("user/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
[ProducesResponseType(200)] [ProducesResponseType(200)]
@ -322,12 +256,7 @@ namespace Roadie.Api.Controllers
{ {
return StatusCode((int)HttpStatusCode.InternalServerError); return StatusCode((int)HttpStatusCode.InternalServerError);
} }
var model = result.Data.Adapt<Library.Models.Image>(); return MakeFileResult(result.Data.Bytes, $"{id}.gif", result.ContentType, result.LastModified, result.ETag);
return File(model.Bytes,
result.ContentType,
$"{model.Caption ?? id.ToString()}.gif",
result.LastModified,
result.ETag);
} }
} }
} }

View file

@ -117,5 +117,16 @@ namespace Roadie.Api.Controllers
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError); if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
return Ok(result); return Ok(result);
} }
[HttpGet("creditCategory")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> CreditCategories(Guid id, string inc = null)
{
var result = await LookupService.Status();
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
return Ok(result);
}
} }
} }

View file

@ -153,6 +153,16 @@ namespace Roadie.Api.Controllers
return Ok(result); return Ok(result);
} }
[HttpPost("deleteAllBookmarks")]
[ProducesResponseType(200)]
public async Task<IActionResult> DeleteAllBookmarks()
{
var result = await UserService.DeleteAllBookmarks(await CurrentUserModel());
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
CacheManager.ClearRegion(ControllerCacheRegionUrn);
return Ok(result);
}
[HttpPost("setCollectionBookmark/{collectionId}/{isBookmarked}")] [HttpPost("setCollectionBookmark/{collectionId}/{isBookmarked}")]
[ProducesResponseType(200)] [ProducesResponseType(200)]
public async Task<IActionResult> SetCollectionBookmark(Guid collectionId, bool isBookmarked) public async Task<IActionResult> SetCollectionBookmark(Guid collectionId, bool isBookmarked)

View file

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

View file

@ -1,5 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<VersionPrefix>1.0.1</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework> <TargetFramework>netcoreapp3.0</TargetFramework>
<Platforms>AnyCPU;x64</Platforms> <Platforms>AnyCPU;x64</Platforms>

View file

@ -45,6 +45,7 @@ using Serilog;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Reflection;
using System.Text; using System.Text;
#endregion Usings #endregion Usings
@ -79,6 +80,12 @@ namespace Roadie.Api
// c.RoutePrefix = string.Empty; // c.RoutePrefix = string.Empty;
//}); //});
app.Use((context, next) =>
{
context.Response.Headers["Roadie-Api-Version"] = RoadieApiVersion();
return next.Invoke();
});
app.UseSerilogRequestLogging(); app.UseSerilogRequestLogging();
app.UseCors("CORSPolicy"); app.UseCors("CORSPolicy");
@ -329,6 +336,20 @@ namespace Roadie.Api
adminService.PerformStartUpTasks(); adminService.PerformStartUpTasks();
} }
private static string _roadieApiVersion = null;
public static string RoadieApiVersion()
{
if (string.IsNullOrEmpty(_roadieApiVersion))
{
_roadieApiVersion = typeof(Startup)
.GetTypeInfo()
.Assembly
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
.InformationalVersion;
}
return _roadieApiVersion;
}
private class IntegrationKey private class IntegrationKey
{ {
public string BingImageSearch { get; set; } public string BingImageSearch { get; set; }

View file

@ -0,0 +1,45 @@
CREATE TABLE `creditCategory` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`isLocked` tinyint(1) DEFAULT NULL,
`status` smallint(6) DEFAULT NULL,
`roadieId` varchar(36) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`createdDate` datetime DEFAULT NULL,
`lastUpdated` datetime DEFAULT NULL,
`name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
`description` varchar(4000) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`urls` mediumtext COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`tags` mediumtext COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`alternateNames` mediumtext COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `ix_creditCategory_roadieId` (`roadieId`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE `credit` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`artistId` int(11) NULL DEFAULT NULL,
`releaseId` int(11) NULL DEFAULT NULL,
`trackId` int(11) NULL DEFAULT NULL,
`creditCategoryId` int(11) NOT NULL,
`isLocked` tinyint(1) DEFAULT NULL,
`status` smallint(6) DEFAULT NULL,
`roadieId` varchar(36) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`createdDate` datetime DEFAULT NULL,
`lastUpdated` datetime DEFAULT NULL,
`creditToName` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`description` varchar(4000) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`urls` mediumtext COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`tags` mediumtext COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `ix_credit_roadieId` (`roadieId`),
KEY `idx_creditCreditandRelease` (`releaseId`,`id`),
KEY `idx_creditCreditandTrack` (`trackId`,`id`),
CONSTRAINT `credit_artist_ibfk_1` FOREIGN KEY (`artistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE,
CONSTRAINT `credit_release_ibfk_1` FOREIGN KEY (`releaseId`) REFERENCES `release` (`id`) ON DELETE CASCADE,
CONSTRAINT `credit_track_ibfk_1` FOREIGN KEY (`trackId`) REFERENCES `track` (`id`) ON DELETE CASCADE,
CONSTRAINT `credit_category_ibfk_1` FOREIGN KEY (`creditCategoryId`) REFERENCES `creditCategory` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `creditCategory` VALUES (null,0,1,'d4008de3-2735-4991-968b-b6dfe868990a', UTC_TIMESTAMP(), null, 'Vocals', 'Provided lead or backup vocals',null,null,null);
INSERT INTO `creditCategory` VALUES (null,0,1,'aea463b8-0b90-47d5-8fde-5e68d3c454ed', UTC_TIMESTAMP(), null, 'Instrument', 'Played an instrument',null,null,null);
INSERT INTO `creditCategory` VALUES (null,0,1,'e3178aae-2359-4654-ab29-b45338b5984f', UTC_TIMESTAMP(), null, 'Production', 'Provided some role in production',null,null,null);

View file

@ -62,7 +62,7 @@ CREATE TABLE `artist` (
UNIQUE KEY `ix_artist_name` (`name`), UNIQUE KEY `ix_artist_name` (`name`),
UNIQUE KEY `ix_artist_sortname` (`sortName`), UNIQUE KEY `ix_artist_sortname` (`sortName`),
KEY `ix_artist_roadieId` (`roadieId`) KEY `ix_artist_roadieId` (`roadieId`)
) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -81,7 +81,7 @@ CREATE TABLE `artistAssociation` (
KEY `idx_artistAssociation` (`artistId`,`associatedArtistId`), KEY `idx_artistAssociation` (`artistId`,`associatedArtistId`),
CONSTRAINT `artistAssociation_ibfk_1` FOREIGN KEY (`artistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE, CONSTRAINT `artistAssociation_ibfk_1` FOREIGN KEY (`artistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE,
CONSTRAINT `artistAssociation_ibfk_2` FOREIGN KEY (`associatedArtistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE CONSTRAINT `artistAssociation_ibfk_2` FOREIGN KEY (`associatedArtistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -101,7 +101,7 @@ CREATE TABLE `artistGenreTable` (
KEY `ix_artistGenreTable_artistId` (`artistId`), KEY `ix_artistGenreTable_artistId` (`artistId`),
CONSTRAINT `artistGenreTable_ibfk_1` FOREIGN KEY (`artistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE, CONSTRAINT `artistGenreTable_ibfk_1` FOREIGN KEY (`artistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE,
CONSTRAINT `artistGenreTable_ibfk_2` FOREIGN KEY (`genreId`) REFERENCES `genre` (`id`) ON DELETE CASCADE CONSTRAINT `artistGenreTable_ibfk_2` FOREIGN KEY (`genreId`) REFERENCES `genre` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=63 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -120,7 +120,7 @@ CREATE TABLE `artistSimilar` (
KEY `idx_artistSimilar` (`artistId`,`similarArtistId`), KEY `idx_artistSimilar` (`artistId`,`similarArtistId`),
CONSTRAINT `artistSimilar_ibfk_1` FOREIGN KEY (`artistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE, CONSTRAINT `artistSimilar_ibfk_1` FOREIGN KEY (`artistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE,
CONSTRAINT `artistSimilar_ibfk_2` FOREIGN KEY (`similarArtistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE CONSTRAINT `artistSimilar_ibfk_2` FOREIGN KEY (`similarArtistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -147,7 +147,7 @@ CREATE TABLE `bookmark` (
KEY `ix_bookmark_roadieId` (`roadieId`), KEY `ix_bookmark_roadieId` (`roadieId`),
KEY `ix_bookmark_userId` (`userId`), KEY `ix_bookmark_userId` (`userId`),
CONSTRAINT `bookmark_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE CONSTRAINT `bookmark_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -204,7 +204,7 @@ CREATE TABLE `collection` (
KEY `maintainerId` (`maintainerId`), KEY `maintainerId` (`maintainerId`),
KEY `ix_collection_roadieId` (`roadieId`), KEY `ix_collection_roadieId` (`roadieId`),
CONSTRAINT `collection_ibfk_1` FOREIGN KEY (`maintainerId`) REFERENCES `user` (`id`) ON DELETE SET NULL CONSTRAINT `collection_ibfk_1` FOREIGN KEY (`maintainerId`) REFERENCES `user` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -223,7 +223,7 @@ CREATE TABLE `collectionMissing` (
`release` varchar(1000) COLLATE utf8mb4_unicode_ci NOT NULL, `release` varchar(1000) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `ix_collection_collectionId` (`collectionId`) KEY `ix_collection_collectionId` (`collectionId`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -249,7 +249,7 @@ CREATE TABLE `collectionrelease` (
KEY `ix_collectionrelease_roadieId` (`roadieId`), KEY `ix_collectionrelease_roadieId` (`roadieId`),
CONSTRAINT `collectionrelease_ibfk_1` FOREIGN KEY (`releaseId`) REFERENCES `release` (`id`) ON DELETE CASCADE, CONSTRAINT `collectionrelease_ibfk_1` FOREIGN KEY (`releaseId`) REFERENCES `release` (`id`) ON DELETE CASCADE,
CONSTRAINT `collectionrelease_ibfk_2` FOREIGN KEY (`collectionId`) REFERENCES `collection` (`id`) ON DELETE CASCADE CONSTRAINT `collectionrelease_ibfk_2` FOREIGN KEY (`collectionId`) REFERENCES `collection` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -293,7 +293,7 @@ CREATE TABLE `comment` (
CONSTRAINT `commentrelease_ibfk_1` FOREIGN KEY (`releaseId`) REFERENCES `release` (`id`) ON DELETE CASCADE, CONSTRAINT `commentrelease_ibfk_1` FOREIGN KEY (`releaseId`) REFERENCES `release` (`id`) ON DELETE CASCADE,
CONSTRAINT `commenttrack_ibfk_1` FOREIGN KEY (`trackId`) REFERENCES `track` (`id`) ON DELETE CASCADE, CONSTRAINT `commenttrack_ibfk_1` FOREIGN KEY (`trackId`) REFERENCES `track` (`id`) ON DELETE CASCADE,
CONSTRAINT `commentuser_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE CONSTRAINT `commentuser_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=54 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -319,7 +319,7 @@ CREATE TABLE `commentReaction` (
KEY `commentReactioncomment_ibfk_1` (`commentId`), KEY `commentReactioncomment_ibfk_1` (`commentId`),
CONSTRAINT `commentReactioncomment_ibfk_1` FOREIGN KEY (`commentId`) REFERENCES `comment` (`id`) ON DELETE CASCADE, CONSTRAINT `commentReactioncomment_ibfk_1` FOREIGN KEY (`commentId`) REFERENCES `comment` (`id`) ON DELETE CASCADE,
CONSTRAINT `commentReactionuser_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE CONSTRAINT `commentReactionuser_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -347,7 +347,7 @@ CREATE TABLE `genre` (
UNIQUE KEY `ix_genre_name` (`name`), UNIQUE KEY `ix_genre_name` (`name`),
KEY `ix_genre_roadieId` (`roadieId`), KEY `ix_genre_roadieId` (`roadieId`),
KEY `genre_normalizedName_IDX` (`normalizedName`) USING BTREE KEY `genre_normalizedName_IDX` (`normalizedName`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -398,7 +398,7 @@ CREATE TABLE `inviteToken` (
KEY `ix_inviteToken_roadieId` (`roadieId`), KEY `ix_inviteToken_roadieId` (`roadieId`),
KEY `inviteToken_fk_1` (`createdByUserId`), KEY `inviteToken_fk_1` (`createdByUserId`),
CONSTRAINT `inviteToken_fk_1` FOREIGN KEY (`createdByUserId`) REFERENCES `user` (`id`) ON DELETE CASCADE CONSTRAINT `inviteToken_fk_1` FOREIGN KEY (`createdByUserId`) REFERENCES `user` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -433,7 +433,7 @@ CREATE TABLE `label` (
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `ix_label_name` (`name`), UNIQUE KEY `ix_label_name` (`name`),
KEY `ix_label_roadieId` (`roadieId`) KEY `ix_label_roadieId` (`roadieId`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -466,7 +466,7 @@ CREATE TABLE `playlist` (
KEY `ix_playlist_roadieId` (`roadieId`), KEY `ix_playlist_roadieId` (`roadieId`),
KEY `ix_playlist_userId` (`userId`), KEY `ix_playlist_userId` (`userId`),
CONSTRAINT `playlist_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE CONSTRAINT `playlist_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -492,7 +492,7 @@ CREATE TABLE `playlisttrack` (
KEY `ix_playlisttrack_roadieId` (`roadieId`), KEY `ix_playlisttrack_roadieId` (`roadieId`),
CONSTRAINT `playlisttrack_ibfk_1` FOREIGN KEY (`trackId`) REFERENCES `track` (`id`) ON DELETE CASCADE, CONSTRAINT `playlisttrack_ibfk_1` FOREIGN KEY (`trackId`) REFERENCES `track` (`id`) ON DELETE CASCADE,
CONSTRAINT `playlisttrack_ibfk_2` FOREIGN KEY (`playListId`) REFERENCES `playlist` (`id`) ON DELETE CASCADE CONSTRAINT `playlisttrack_ibfk_2` FOREIGN KEY (`playListId`) REFERENCES `playlist` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=694 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -541,7 +541,7 @@ CREATE TABLE `release` (
KEY `ix_release_roadieId` (`roadieId`), KEY `ix_release_roadieId` (`roadieId`),
KEY `ix_release_title` (`title`), KEY `ix_release_title` (`title`),
CONSTRAINT `release_ibfk_1` FOREIGN KEY (`artistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE CONSTRAINT `release_ibfk_1` FOREIGN KEY (`artistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=64 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -560,7 +560,7 @@ CREATE TABLE `releaseGenreTable` (
KEY `idx_releaseGenreTableReleaseAndGenre` (`releaseId`,`genreId`), KEY `idx_releaseGenreTableReleaseAndGenre` (`releaseId`,`genreId`),
CONSTRAINT `releaseGenreTable_ibfk_1` FOREIGN KEY (`releaseId`) REFERENCES `release` (`id`) ON DELETE CASCADE, CONSTRAINT `releaseGenreTable_ibfk_1` FOREIGN KEY (`releaseId`) REFERENCES `release` (`id`) ON DELETE CASCADE,
CONSTRAINT `releaseGenreTable_ibfk_2` FOREIGN KEY (`genreId`) REFERENCES `genre` (`id`) ON DELETE CASCADE CONSTRAINT `releaseGenreTable_ibfk_2` FOREIGN KEY (`genreId`) REFERENCES `genre` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=107 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -588,7 +588,7 @@ CREATE TABLE `releaselabel` (
KEY `ix_releaselabel_roadieId` (`roadieId`), KEY `ix_releaselabel_roadieId` (`roadieId`),
CONSTRAINT `releaselabel_ibfk_1` FOREIGN KEY (`releaseId`) REFERENCES `release` (`id`) ON DELETE CASCADE, CONSTRAINT `releaselabel_ibfk_1` FOREIGN KEY (`releaseId`) REFERENCES `release` (`id`) ON DELETE CASCADE,
CONSTRAINT `releaselabel_ibfk_2` FOREIGN KEY (`labelId`) REFERENCES `label` (`id`) ON DELETE CASCADE CONSTRAINT `releaselabel_ibfk_2` FOREIGN KEY (`labelId`) REFERENCES `label` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -613,7 +613,7 @@ CREATE TABLE `releasemedia` (
KEY `ix_releasemedia_roadieId` (`roadieId`), KEY `ix_releasemedia_roadieId` (`roadieId`),
KEY `releasemedia_releaseId_IDX` (`releaseId`,`releaseMediaNumber`) USING BTREE, KEY `releasemedia_releaseId_IDX` (`releaseId`,`releaseMediaNumber`) USING BTREE,
CONSTRAINT `releasemedia_ibfk_1` FOREIGN KEY (`releaseId`) REFERENCES `release` (`id`) ON DELETE CASCADE CONSTRAINT `releasemedia_ibfk_1` FOREIGN KEY (`releaseId`) REFERENCES `release` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=62 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -635,7 +635,7 @@ CREATE TABLE `request` (
KEY `ix_request_roadieId` (`roadieId`), KEY `ix_request_roadieId` (`roadieId`),
KEY `requestartist_ibfk_1` (`userId`), KEY `requestartist_ibfk_1` (`userId`),
CONSTRAINT `requestartist_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE CONSTRAINT `requestartist_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=148 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -661,7 +661,7 @@ CREATE TABLE `scanHistory` (
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `ix_scanHistory_roadieId` (`roadieId`), KEY `ix_scanHistory_roadieId` (`roadieId`),
KEY `rscanHistoryt_ibfk_1` (`userId`) KEY `rscanHistoryt_ibfk_1` (`userId`)
) ENGINE=InnoDB AUTO_INCREMENT=107 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -729,7 +729,7 @@ CREATE TABLE `track` (
KEY `track_artistId_IDX` (`artistId`) USING BTREE, KEY `track_artistId_IDX` (`artistId`) USING BTREE,
KEY `track_releaseMediaId_IDX` (`releaseMediaId`) USING BTREE, KEY `track_releaseMediaId_IDX` (`releaseMediaId`) USING BTREE,
CONSTRAINT `track_ibfk_1` FOREIGN KEY (`releaseMediaId`) REFERENCES `releasemedia` (`id`) ON DELETE CASCADE CONSTRAINT `track_ibfk_1` FOREIGN KEY (`releaseMediaId`) REFERENCES `releasemedia` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=623 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -803,7 +803,7 @@ CREATE TABLE `user` (
UNIQUE KEY `email` (`email`), UNIQUE KEY `email` (`email`),
UNIQUE KEY `ix_user_username` (`username`), UNIQUE KEY `ix_user_username` (`username`),
KEY `ix_user_roadieId` (`roadieId`) KEY `ix_user_roadieId` (`roadieId`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -894,7 +894,7 @@ CREATE TABLE `userartist` (
KEY `ix_userartist_roadieId` (`roadieId`), KEY `ix_userartist_roadieId` (`roadieId`),
CONSTRAINT `userartist_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE, CONSTRAINT `userartist_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE,
CONSTRAINT `userartist_ibfk_2` FOREIGN KEY (`artistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE CONSTRAINT `userartist_ibfk_2` FOREIGN KEY (`artistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -922,7 +922,7 @@ CREATE TABLE `userrelease` (
KEY `ix_userrelease_roadieId` (`roadieId`), KEY `ix_userrelease_roadieId` (`roadieId`),
CONSTRAINT `userrelease_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE, CONSTRAINT `userrelease_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE,
CONSTRAINT `userrelease_ibfk_2` FOREIGN KEY (`releaseId`) REFERENCES `release` (`id`) ON DELETE CASCADE CONSTRAINT `userrelease_ibfk_2` FOREIGN KEY (`releaseId`) REFERENCES `release` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -946,7 +946,7 @@ CREATE TABLE `userrole` (
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`), UNIQUE KEY `name` (`name`),
KEY `ix_userrole_roadieId` (`roadieId`) KEY `ix_userrole_roadieId` (`roadieId`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -965,7 +965,7 @@ CREATE TABLE `usersInRoles` (
KEY `ix_usersInRoles_userId` (`userId`), KEY `ix_usersInRoles_userId` (`userId`),
CONSTRAINT `usersInRoles_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE, CONSTRAINT `usersInRoles_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE,
CONSTRAINT `usersInRoles_ibfk_2` FOREIGN KEY (`userRoleId`) REFERENCES `userrole` (`id`) ON DELETE CASCADE CONSTRAINT `usersInRoles_ibfk_2` FOREIGN KEY (`userRoleId`) REFERENCES `userrole` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -995,7 +995,7 @@ CREATE TABLE `usertrack` (
KEY `ix_usertrack_roadieId` (`roadieId`), KEY `ix_usertrack_roadieId` (`roadieId`),
CONSTRAINT `usertrack_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE, CONSTRAINT `usertrack_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE,
CONSTRAINT `usertrack_ibfk_2` FOREIGN KEY (`trackId`) REFERENCES `track` (`id`) ON DELETE CASCADE CONSTRAINT `usertrack_ibfk_2` FOREIGN KEY (`trackId`) REFERENCES `track` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=238 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --