roadie/Roadie.Api.Services/ServiceBase.cs

925 lines
38 KiB
C#
Raw Normal View History

2019-01-02 02:03:17 +00:00
using HashidsNet;
using Microsoft.EntityFrameworkCore;
2018-11-11 20:10:10 +00:00
using Microsoft.Extensions.Logging;
2018-12-01 03:22:35 +00:00
using Roadie.Library;
2018-11-06 04:31:25 +00:00
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Encoding;
2019-02-10 00:19:26 +00:00
using Roadie.Library.Enums;
2018-11-11 20:10:10 +00:00
using Roadie.Library.Identity;
2018-11-06 04:31:25 +00:00
using Roadie.Library.Models;
2018-11-11 20:10:10 +00:00
using Roadie.Library.Utility;
2018-11-06 04:31:25 +00:00
using System;
2018-12-30 20:57:06 +00:00
using System.Collections.Generic;
2019-03-10 16:55:21 +00:00
using System.Diagnostics;
2018-11-06 04:31:25 +00:00
using System.Linq;
2018-12-01 03:22:35 +00:00
using System.Threading.Tasks;
2018-11-11 20:10:10 +00:00
using data = Roadie.Library.Data;
2018-11-06 04:31:25 +00:00
namespace Roadie.Api.Services
{
public abstract class ServiceBase
{
2019-01-02 02:03:17 +00:00
public static string TrackTokenSalt = "B0246908-FBD6-4E12-A96C-AF5B086115B3";
2019-06-30 22:14:36 +00:00
protected readonly ICacheManager _cacheManager;
protected readonly IRoadieSettings _configuration;
protected readonly data.IRoadieDbContext _dbContext;
protected readonly IHttpContext _httpContext;
protected readonly IHttpEncoder _httpEncoder;
protected readonly ILogger _logger;
2018-11-06 04:31:25 +00:00
2019-06-30 22:14:36 +00:00
protected ICacheManager CacheManager => _cacheManager;
2018-11-06 04:31:25 +00:00
2019-06-30 22:14:36 +00:00
protected IRoadieSettings Configuration => _configuration;
2018-11-06 04:31:25 +00:00
2019-06-30 22:14:36 +00:00
protected data.IRoadieDbContext DbContext => _dbContext;
2018-11-06 04:31:25 +00:00
2019-06-30 22:14:36 +00:00
protected IHttpContext HttpContext => _httpContext;
2018-11-06 04:31:25 +00:00
2019-06-30 22:14:36 +00:00
protected IHttpEncoder HttpEncoder => _httpEncoder;
2018-11-06 04:31:25 +00:00
2019-06-30 22:14:36 +00:00
protected ILogger Logger => _logger;
2018-11-06 21:55:31 +00:00
2018-11-06 04:31:25 +00:00
public ServiceBase(IRoadieSettings configuration, IHttpEncoder httpEncoder, data.IRoadieDbContext context,
2019-06-30 22:14:36 +00:00
ICacheManager cacheManager, ILogger logger, IHttpContext httpContext)
2018-11-06 21:55:31 +00:00
{
2019-06-30 22:14:36 +00:00
_configuration = configuration;
_httpEncoder = httpEncoder;
_dbContext = context;
_cacheManager = cacheManager;
_logger = logger;
_httpContext = httpContext;
2018-11-06 21:55:31 +00:00
}
2019-01-08 22:40:26 +00:00
public static bool ConfirmTrackPlayToken(ApplicationUser user, Guid trackRoadieId, string token)
{
2019-06-30 22:14:36 +00:00
if (string.IsNullOrEmpty(token)) return false;
return TrackPlayToken(user, trackRoadieId).Equals(token);
2019-01-08 22:40:26 +00:00
}
public static string TrackPlayToken(ApplicationUser user, Guid trackId)
{
2019-06-30 22:14:36 +00:00
var hashids = new Hashids(TrackTokenSalt);
2019-01-08 22:40:26 +00:00
var trackIdPart = BitConverter.ToInt32(trackId.ToByteArray(), 6);
2019-07-13 12:28:27 +00:00
if (trackIdPart < 0) trackIdPart *= -1;
var token = hashids.Encode(user.Id, SafeParser.ToNumber<int>(user.CreatedDate.Value.ToString("DDHHmmss")), trackIdPart);
2019-01-08 22:40:26 +00:00
return token;
}
2019-07-13 12:28:27 +00:00
public Image MakeThumbnailImage(Guid id, string type, int? width = null, int? height = null, bool includeCachebuster = false)
2018-12-04 23:26:27 +00:00
{
2019-07-13 12:28:27 +00:00
return MakeImage(id, type, width ?? Configuration.ThumbnailImageSize.Width, height ?? Configuration.ThumbnailImageSize.Height, null, includeCachebuster);
2018-12-04 23:26:27 +00:00
}
2019-01-08 22:40:26 +00:00
protected IEnumerable<int> ArtistIdsForRelease(int releaseId)
{
2019-06-30 22:14:36 +00:00
var trackArtistIds = (from r in DbContext.Releases
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
2019-01-08 22:40:26 +00:00
where r.Id == releaseId
where tr.ArtistId != null
select tr.ArtistId.Value).ToList();
2019-06-30 22:14:36 +00:00
trackArtistIds.Add(DbContext.Releases.FirstOrDefault(x => x.Id == releaseId).ArtistId);
2019-01-08 22:40:26 +00:00
return trackArtistIds.Distinct().ToArray();
}
2018-11-22 23:12:57 +00:00
protected data.Artist GetArtist(string artistName)
{
2019-06-30 22:14:36 +00:00
if (string.IsNullOrEmpty(artistName)) return null;
var artistByName = CacheManager.Get(data.Artist.CacheUrnByName(artistName), () =>
2018-11-22 23:12:57 +00:00
{
2019-06-30 22:14:36 +00:00
return DbContext.Artists
.FirstOrDefault(x => x.Name == artistName);
2018-11-22 23:12:57 +00:00
}, null);
2019-06-30 22:14:36 +00:00
if (artistByName == null) return null;
return GetArtist(artistByName.RoadieId);
2018-11-22 23:12:57 +00:00
}
2018-11-11 20:10:10 +00:00
protected data.Artist GetArtist(Guid id)
2018-11-06 21:55:31 +00:00
{
2019-06-30 22:14:36 +00:00
return CacheManager.Get(data.Artist.CacheUrn(id), () =>
2018-11-11 20:10:10 +00:00
{
2019-06-30 22:14:36 +00:00
return DbContext.Artists
.Include(x => x.Genres)
.Include("Genres.Genre")
.FirstOrDefault(x => x.RoadieId == id);
2018-11-11 20:10:10 +00:00
}, data.Artist.CacheRegionUrn(id));
2018-11-06 21:55:31 +00:00
}
2018-11-11 20:10:10 +00:00
protected data.Collection GetCollection(Guid id)
2018-11-07 04:33:22 +00:00
{
2019-06-30 22:14:36 +00:00
return CacheManager.Get(data.Collection.CacheUrn(id), () =>
2018-11-11 20:10:10 +00:00
{
2019-06-30 22:14:36 +00:00
return DbContext.Collections
.FirstOrDefault(x => x.RoadieId == id);
2018-11-11 20:10:10 +00:00
}, data.Collection.CacheRegionUrn(id));
2018-11-07 04:33:22 +00:00
}
2018-11-11 20:10:10 +00:00
protected data.Label GetLabel(Guid id)
2018-11-07 04:33:22 +00:00
{
2019-06-30 22:14:36 +00:00
return CacheManager.Get(data.Label.CacheUrn(id), () =>
2018-11-11 20:10:10 +00:00
{
2019-06-30 22:14:36 +00:00
return DbContext.Labels
.FirstOrDefault(x => x.RoadieId == id);
2018-11-11 20:10:10 +00:00
}, data.Label.CacheRegionUrn(id));
2018-11-07 04:33:22 +00:00
}
2019-08-02 20:59:24 +00:00
protected data.Genre GetGenre(Guid id)
{
return CacheManager.Get(data.Genre.CacheUrn(id), () =>
{
return DbContext.Genres
.FirstOrDefault(x => x.RoadieId == id);
}, data.Genre.CacheRegionUrn(id));
}
2018-11-11 20:10:10 +00:00
protected data.Playlist GetPlaylist(Guid id)
2018-11-06 21:55:31 +00:00
{
2019-06-30 22:14:36 +00:00
return CacheManager.Get(data.Playlist.CacheUrn(id), () =>
2018-11-11 20:10:10 +00:00
{
2019-06-30 22:14:36 +00:00
return DbContext.Playlists
.Include(x => x.User)
.FirstOrDefault(x => x.RoadieId == id);
2018-11-11 20:10:10 +00:00
}, data.Playlist.CacheRegionUrn(id));
2018-11-06 21:55:31 +00:00
}
2018-11-11 20:10:10 +00:00
protected data.Release GetRelease(Guid id)
2018-11-06 21:55:31 +00:00
{
2019-06-30 22:14:36 +00:00
return CacheManager.Get(data.Release.CacheUrn(id), () =>
2018-11-11 20:10:10 +00:00
{
2019-06-30 22:14:36 +00:00
return DbContext.Releases
.Include(x => x.Artist)
.Include(x => x.Genres)
.Include("Genres.Genre")
.Include(x => x.Medias)
.Include("Medias.Tracks")
.Include("Medias.Tracks.TrackArtist")
.FirstOrDefault(x => x.RoadieId == id);
2018-11-11 20:10:10 +00:00
}, data.Release.CacheRegionUrn(id));
}
/// <summary>
2019-06-30 22:14:36 +00:00
/// Get Track by Subsonic Id ("T:guid")
/// </summary>
2018-11-17 02:14:32 +00:00
protected data.Track GetTrack(string id)
{
2019-06-30 22:14:36 +00:00
var trackId = Guid.Empty;
if (Guid.TryParse(id, out trackId)) return GetTrack(trackId);
2018-11-17 02:14:32 +00:00
return null;
}
2019-01-12 21:10:00 +00:00
// Only read operations
protected data.Track GetTrack(Guid id)
{
2019-06-30 22:14:36 +00:00
return CacheManager.Get(data.Track.CacheUrn(id), () =>
{
2019-06-30 22:14:36 +00:00
return DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefault(x => x.RoadieId == id);
}, data.Track.CacheRegionUrn(id));
}
2018-11-20 14:36:07 +00:00
protected ApplicationUser GetUser(string username)
{
2019-06-30 22:14:36 +00:00
if (string.IsNullOrEmpty(username)) return null;
var userByUsername = CacheManager.Get(ApplicationUser.CacheUrnByUsername(username),
() => { return DbContext.Users.FirstOrDefault(x => x.UserName == username); }, null);
return GetUser(userByUsername?.RoadieId);
2018-11-20 14:36:07 +00:00
}
protected ApplicationUser GetUser(Guid? id)
2018-11-11 20:10:10 +00:00
{
2019-06-30 22:14:36 +00:00
if (!id.HasValue) return null;
return CacheManager.Get(ApplicationUser.CacheUrn(id.Value), () =>
{
return DbContext.Users
.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));
2018-11-11 20:10:10 +00:00
}
2018-12-11 23:09:52 +00:00
protected Image MakeArtistThumbnailImage(Guid? id)
2018-12-04 23:26:27 +00:00
{
2019-06-30 22:14:36 +00:00
if (!id.HasValue) return null;
2018-12-11 23:09:52 +00:00
return MakeThumbnailImage(id.Value, "artist");
2018-12-04 23:26:27 +00:00
}
protected Image MakeCollectionThumbnailImage(Guid id)
{
return MakeThumbnailImage(id, "collection");
}
2019-01-08 22:40:26 +00:00
protected Image MakeFullsizeImage(Guid id, string caption = null)
2018-12-04 23:26:27 +00:00
{
2019-06-30 22:14:36 +00:00
return new Image($"{HttpContext.ImageBaseUrl}/{id}", caption,
$"{HttpContext.ImageBaseUrl}/{id}/{Configuration.SmallImageSize.Width}/{Configuration.SmallImageSize.Height}");
2018-12-04 23:26:27 +00:00
}
2019-02-10 00:19:26 +00:00
protected Image MakeFullsizeSecondaryImage(Guid id, ImageType type, int imageId, string caption = null)
{
2019-05-29 22:25:40 +00:00
if (type == ImageType.ArtistSecondary)
2019-07-13 12:28:27 +00:00
{
2019-06-30 22:14:36 +00:00
return new Image($"{HttpContext.ImageBaseUrl}/artist-secondary/{id}/{imageId}", caption,
$"{HttpContext.ImageBaseUrl}/artist-secondary/{id}/{imageId}/{Configuration.SmallImageSize.Width}/{Configuration.SmallImageSize.Height}");
2019-07-13 12:28:27 +00:00
}
2019-06-30 22:14:36 +00:00
return new Image($"{HttpContext.ImageBaseUrl}/release-secondary/{id}/{imageId}", caption,
$"{HttpContext.ImageBaseUrl}/release-secondary/{id}/{imageId}/{Configuration.SmallImageSize.Width}/{Configuration.SmallImageSize.Height}");
2019-02-10 00:19:26 +00:00
}
2019-06-30 22:14:36 +00:00
protected Image MakeImage(Guid id, int width = 200, int height = 200, string caption = null,
bool includeCachebuster = false)
2018-12-04 23:26:27 +00:00
{
2019-06-30 22:14:36 +00:00
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}");
2018-12-04 23:26:27 +00:00
}
2019-06-02 04:27:17 +00:00
protected Image MakeImage(Guid id, string type, IImageSize imageSize)
2018-12-04 23:26:27 +00:00
{
2019-06-30 22:14:36 +00:00
return MakeImage(id, type, imageSize.Width, imageSize.Height);
2018-12-04 23:26:27 +00:00
}
protected Image MakeLabelThumbnailImage(Guid id)
{
return MakeThumbnailImage(id, "label");
}
2019-08-02 20:59:24 +00:00
protected Image MakeGenreThumbnailImage(Guid id)
{
return MakeThumbnailImage(id, "genre");
}
2018-12-04 23:26:27 +00:00
protected string MakeLastFmUrl(string artistName, string releaseTitle)
{
2019-06-30 22:14:36 +00:00
return "http://www.last.fm/music/" + HttpEncoder.UrlEncode($"{artistName}/{releaseTitle}");
2018-12-04 23:26:27 +00:00
}
2019-05-29 22:25:40 +00:00
protected Image MakeNewImage(string type)
{
2019-06-30 22:14:36 +00:00
return new Image($"{HttpContext.ImageBaseUrl}/{type}.jpg", null, null);
2019-05-29 22:25:40 +00:00
}
2018-12-04 23:26:27 +00:00
protected Image MakePlaylistThumbnailImage(Guid id)
{
return MakeThumbnailImage(id, "playlist");
}
protected Image MakeReleaseThumbnailImage(Guid id)
{
return MakeThumbnailImage(id, "release");
}
2019-01-08 22:40:26 +00:00
protected string MakeTrackPlayUrl(ApplicationUser user, int trackId, Guid trackRoadieId)
{
2019-06-30 22:14:36 +00:00
return
$"{HttpContext.BaseUrl}/play/track/{user.Id}/{TrackPlayToken(user, trackRoadieId)}/{trackRoadieId}.mp3";
2019-01-08 22:40:26 +00:00
}
2018-12-04 23:26:27 +00:00
protected Image MakeTrackThumbnailImage(Guid id)
{
return MakeThumbnailImage(id, "track");
}
protected Image MakeUserThumbnailImage(Guid id)
{
return MakeThumbnailImage(id, "user");
}
2018-12-01 03:22:35 +00:00
2018-12-01 14:57:27 +00:00
protected async Task<OperationResult<short>> SetArtistRating(Guid artistId, ApplicationUser user, short rating)
2018-12-01 03:22:35 +00:00
{
2019-06-30 22:14:36 +00:00
var artist = DbContext.Artists
.Include(x => x.Genres)
.Include("Genres.Genre")
.FirstOrDefault(x => x.RoadieId == artistId);
if (artist == null) return new OperationResult<short>(true, $"Invalid Artist Id [{artistId}]");
2019-01-12 21:10:00 +00:00
var now = DateTime.UtcNow;
2019-06-30 22:14:36 +00:00
var userArtist = DbContext.UserArtists.FirstOrDefault(x => x.ArtistId == artist.Id && x.UserId == user.Id);
2018-12-01 03:22:35 +00:00
if (userArtist == null)
{
userArtist = new data.UserArtist
{
Rating = rating,
UserId = user.Id,
ArtistId = artist.Id
};
2019-06-30 22:14:36 +00:00
DbContext.UserArtists.Add(userArtist);
2018-12-01 03:22:35 +00:00
}
else
{
userArtist.Rating = rating;
2019-01-12 21:10:00 +00:00
userArtist.LastUpdated = now;
2018-12-01 03:22:35 +00:00
}
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
var ratings = DbContext.UserArtists.Where(x => x.ArtistId == artist.Id && x.Rating > 0)
.Select(x => x.Rating);
2019-01-13 03:12:09 +00:00
if (ratings != null && ratings.Any())
artist.Rating = (short)ratings.Average(x => (decimal)x);
else
artist.Rating = 0;
2019-01-12 21:10:00 +00:00
artist.LastUpdated = now;
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
await UpdateArtistRank(artist.Id);
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(artist.CacheRegion);
2018-12-01 03:22:35 +00:00
2019-06-30 22:14:36 +00:00
artist = GetArtist(artistId);
2018-12-01 14:57:27 +00:00
return new OperationResult<short>
2018-12-01 03:22:35 +00:00
{
IsSuccess = true,
2018-12-01 14:57:27 +00:00
Data = artist.Rating ?? 0
2018-12-01 03:22:35 +00:00
};
}
2019-06-30 22:14:36 +00:00
protected async Task<OperationResult<short>> SetReleaseRating(Guid releaseId, ApplicationUser user,
short rating)
{
var release = DbContext.Releases
.Include(x => x.Artist)
.Include(x => x.Genres)
.Include("Genres.Genre")
.Include(x => x.Medias)
.Include("Medias.Tracks")
.Include("Medias.Tracks.TrackArtist")
.FirstOrDefault(x => x.RoadieId == releaseId);
if (release == null) return new OperationResult<short>(true, $"Invalid Release Id [{releaseId}]");
var userRelease =
DbContext.UserReleases.FirstOrDefault(x => x.ReleaseId == release.Id && x.UserId == user.Id);
2018-12-01 03:22:35 +00:00
var now = DateTime.UtcNow;
if (userRelease == null)
{
userRelease = new data.UserRelease
{
Rating = rating,
UserId = user.Id,
ReleaseId = release.Id
};
2019-06-30 22:14:36 +00:00
DbContext.UserReleases.Add(userRelease);
2018-12-01 03:22:35 +00:00
}
else
{
userRelease.Rating = rating;
userRelease.LastUpdated = now;
}
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
var ratings = DbContext.UserReleases.Where(x => x.ReleaseId == release.Id && x.Rating > 0)
.Select(x => x.Rating);
2019-01-13 03:12:09 +00:00
if (ratings != null && ratings.Any())
release.Rating = (short)ratings.Average(x => (decimal)x);
else
release.Rating = 0;
2019-01-12 21:10:00 +00:00
release.LastUpdated = now;
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
await UpdateReleaseRank(release.Id);
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(release.CacheRegion);
CacheManager.ClearRegion(release.Artist.CacheRegion);
2018-12-01 03:22:35 +00:00
2019-06-30 22:14:36 +00:00
release = GetRelease(releaseId);
2018-12-01 14:57:27 +00:00
return new OperationResult<short>
2018-12-01 03:22:35 +00:00
{
IsSuccess = true,
2018-12-01 14:57:27 +00:00
Data = release.Rating ?? 0
2018-12-01 03:22:35 +00:00
};
}
2018-12-01 14:57:27 +00:00
protected async Task<OperationResult<short>> SetTrackRating(Guid trackId, ApplicationUser user, short rating)
2018-12-01 03:22:35 +00:00
{
2019-03-10 16:55:21 +00:00
var sw = Stopwatch.StartNew();
2019-05-29 22:25:40 +00:00
2019-06-30 22:14:36 +00:00
var track = DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefault(x => x.RoadieId == trackId);
if (track == null) return new OperationResult<short>(true, $"Invalid Track Id [{trackId}]");
2019-01-12 21:10:00 +00:00
var now = DateTime.UtcNow;
2019-06-30 22:14:36 +00:00
var userTrack = DbContext.UserTracks.FirstOrDefault(x => x.TrackId == track.Id && x.UserId == user.Id);
2018-12-01 03:22:35 +00:00
if (userTrack == null)
{
userTrack = new data.UserTrack
{
Rating = rating,
UserId = user.Id,
TrackId = track.Id
};
2019-06-30 22:14:36 +00:00
DbContext.UserTracks.Add(userTrack);
2018-12-01 03:22:35 +00:00
}
else
{
userTrack.Rating = rating;
2019-01-12 21:10:00 +00:00
userTrack.LastUpdated = now;
2018-12-01 03:22:35 +00:00
}
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
var ratings = DbContext.UserTracks.Where(x => x.TrackId == track.Id && x.Rating > 0).Select(x => x.Rating);
2019-01-13 03:12:09 +00:00
if (ratings != null && ratings.Any())
track.Rating = (short)ratings.Average(x => (decimal)x);
2019-05-29 22:25:40 +00:00
else
2019-01-13 03:12:09 +00:00
track.Rating = 0;
2019-01-12 21:10:00 +00:00
track.LastUpdated = now;
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
await UpdateReleaseRank(track.ReleaseMedia.Release.Id);
2018-12-01 03:22:35 +00:00
2019-06-30 22:14:36 +00:00
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(track.CacheRegion);
CacheManager.ClearRegion(track.ReleaseMedia.Release.CacheRegion);
CacheManager.ClearRegion(track.ReleaseMedia.Release.Artist.CacheRegion);
if (track.TrackArtist != null) CacheManager.ClearRegion(track.TrackArtist.CacheRegion);
2018-12-01 03:22:35 +00:00
2019-03-10 16:55:21 +00:00
sw.Stop();
2018-12-01 14:57:27 +00:00
return new OperationResult<short>
2018-12-01 03:22:35 +00:00
{
IsSuccess = true,
2019-03-10 16:55:21 +00:00
Data = track.Rating,
OperationTime = sw.ElapsedMilliseconds
2018-12-01 03:22:35 +00:00
};
}
2019-06-30 22:14:36 +00:00
protected async Task<OperationResult<bool>> ToggleArtistDisliked(Guid artistId, ApplicationUser user,
bool isDisliked)
2018-12-01 18:05:24 +00:00
{
2019-06-30 22:14:36 +00:00
var artist = DbContext.Artists
.Include(x => x.Genres)
.Include("Genres.Genre")
.FirstOrDefault(x => x.RoadieId == artistId);
if (artist == null) return new OperationResult<bool>(true, $"Invalid Artist Id [{artistId}]");
var userArtist = DbContext.UserArtists.FirstOrDefault(x => x.ArtistId == artist.Id && x.UserId == user.Id);
2018-12-01 18:05:24 +00:00
if (userArtist == null)
{
userArtist = new data.UserArtist
{
2019-01-08 22:40:26 +00:00
IsDisliked = isDisliked,
2018-12-01 18:05:24 +00:00
UserId = user.Id,
ArtistId = artist.Id
};
2019-06-30 22:14:36 +00:00
DbContext.UserArtists.Add(userArtist);
2018-12-01 18:05:24 +00:00
}
else
{
2019-01-08 22:40:26 +00:00
userArtist.IsDisliked = isDisliked;
2018-12-01 18:05:24 +00:00
userArtist.LastUpdated = DateTime.UtcNow;
}
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(artist.CacheRegion);
2018-12-01 18:05:24 +00:00
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
2019-06-30 22:14:36 +00:00
protected async Task<OperationResult<bool>> ToggleArtistFavorite(Guid artistId, ApplicationUser user,
bool isFavorite)
2018-12-24 22:35:59 +00:00
{
2019-06-30 22:14:36 +00:00
var artist = DbContext.Artists
.Include(x => x.Genres)
.Include("Genres.Genre")
.FirstOrDefault(x => x.RoadieId == artistId);
if (artist == null) return new OperationResult<bool>(true, $"Invalid Artist Id [{artistId}]");
var userArtist = DbContext.UserArtists.FirstOrDefault(x => x.ArtistId == artist.Id && x.UserId == user.Id);
2018-12-24 22:35:59 +00:00
if (userArtist == null)
{
userArtist = new data.UserArtist
{
2019-01-08 22:40:26 +00:00
IsFavorite = isFavorite,
2018-12-24 22:35:59 +00:00
UserId = user.Id,
ArtistId = artist.Id
};
2019-06-30 22:14:36 +00:00
DbContext.UserArtists.Add(userArtist);
2018-12-24 22:35:59 +00:00
}
else
{
2019-01-08 22:40:26 +00:00
userArtist.IsFavorite = isFavorite;
2018-12-24 22:35:59 +00:00
userArtist.LastUpdated = DateTime.UtcNow;
}
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(artist.CacheRegion);
2018-12-24 22:35:59 +00:00
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
2019-06-30 22:14:36 +00:00
protected async Task<OperationResult<bool>> ToggleReleaseDisliked(Guid releaseId, ApplicationUser user,
bool isDisliked)
{
var release = DbContext.Releases
.Include(x => x.Artist)
.Include(x => x.Genres)
.Include("Genres.Genre")
.Include(x => x.Medias)
.Include("Medias.Tracks")
.Include("Medias.Tracks.TrackArtist")
.FirstOrDefault(x => x.RoadieId == releaseId);
if (release == null) return new OperationResult<bool>(true, $"Invalid Release Id [{releaseId}]");
var userRelease =
DbContext.UserReleases.FirstOrDefault(x => x.ReleaseId == release.Id && x.UserId == user.Id);
2018-12-24 22:35:59 +00:00
if (userRelease == null)
{
userRelease = new data.UserRelease
{
IsDisliked = isDisliked,
UserId = user.Id,
ReleaseId = release.Id
};
2019-06-30 22:14:36 +00:00
DbContext.UserReleases.Add(userRelease);
2018-12-24 22:35:59 +00:00
}
else
{
userRelease.IsDisliked = isDisliked;
userRelease.LastUpdated = DateTime.UtcNow;
}
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(release.CacheRegion);
CacheManager.ClearRegion(release.Artist.CacheRegion);
2018-12-24 22:35:59 +00:00
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
2019-06-30 22:14:36 +00:00
protected async Task<OperationResult<bool>> ToggleReleaseFavorite(Guid releaseId, ApplicationUser user,
bool isFavorite)
{
var release = DbContext.Releases
.Include(x => x.Artist)
.Include(x => x.Genres)
.Include("Genres.Genre")
.Include(x => x.Medias)
.Include("Medias.Tracks")
.Include("Medias.Tracks.TrackArtist")
.FirstOrDefault(x => x.RoadieId == releaseId);
if (release == null) return new OperationResult<bool>(true, $"Invalid Release Id [{releaseId}]");
var userRelease =
DbContext.UserReleases.FirstOrDefault(x => x.ReleaseId == release.Id && x.UserId == user.Id);
2018-12-01 18:05:24 +00:00
if (userRelease == null)
{
userRelease = new data.UserRelease
{
2018-12-24 22:35:59 +00:00
IsFavorite = isFavorite,
2018-12-01 18:05:24 +00:00
UserId = user.Id,
ReleaseId = release.Id
};
2019-06-30 22:14:36 +00:00
DbContext.UserReleases.Add(userRelease);
2018-12-01 18:05:24 +00:00
}
else
{
userRelease.IsFavorite = isFavorite;
userRelease.LastUpdated = DateTime.UtcNow;
}
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(release.CacheRegion);
CacheManager.ClearRegion(release.Artist.CacheRegion);
2018-12-01 18:05:24 +00:00
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
2019-06-30 22:14:36 +00:00
protected async Task<OperationResult<bool>> ToggleTrackDisliked(Guid trackId, ApplicationUser user,
bool isDisliked)
2018-12-01 18:05:24 +00:00
{
2019-06-30 22:14:36 +00:00
var track = DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefault(x => x.RoadieId == trackId);
if (track == null) return new OperationResult<bool>(true, $"Invalid Track Id [{trackId}]");
var userTrack = DbContext.UserTracks.FirstOrDefault(x => x.TrackId == track.Id && x.UserId == user.Id);
2018-12-01 18:05:24 +00:00
if (userTrack == null)
{
userTrack = new data.UserTrack
{
2019-01-08 22:40:26 +00:00
IsDisliked = isDisliked,
2018-12-01 18:05:24 +00:00
UserId = user.Id,
TrackId = track.Id
};
2019-06-30 22:14:36 +00:00
DbContext.UserTracks.Add(userTrack);
2018-12-01 18:05:24 +00:00
}
else
{
2019-01-08 22:40:26 +00:00
userTrack.IsDisliked = isDisliked;
2018-12-01 18:05:24 +00:00
userTrack.LastUpdated = DateTime.UtcNow;
}
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(track.CacheRegion);
CacheManager.ClearRegion(track.ReleaseMedia.Release.CacheRegion);
CacheManager.ClearRegion(track.ReleaseMedia.Release.Artist.CacheRegion);
2018-12-01 18:05:24 +00:00
2019-01-05 22:40:33 +00:00
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
2019-06-30 22:14:36 +00:00
protected async Task<OperationResult<bool>> ToggleTrackFavorite(Guid trackId, ApplicationUser user,
bool isFavorite)
2019-01-05 22:40:33 +00:00
{
2019-06-30 22:14:36 +00:00
var track = DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefault(x => x.RoadieId == trackId);
if (track == null) return new OperationResult<bool>(true, $"Invalid Track Id [{trackId}]");
var userTrack = DbContext.UserTracks.FirstOrDefault(x => x.TrackId == track.Id && x.UserId == user.Id);
2019-01-05 22:40:33 +00:00
if (userTrack == null)
{
userTrack = new data.UserTrack
{
2019-01-08 22:40:26 +00:00
IsFavorite = isFavorite,
2019-01-05 22:40:33 +00:00
UserId = user.Id,
TrackId = track.Id
};
2019-06-30 22:14:36 +00:00
DbContext.UserTracks.Add(userTrack);
2019-01-05 22:40:33 +00:00
}
else
{
2019-01-08 22:40:26 +00:00
userTrack.IsFavorite = isFavorite;
2019-01-05 22:40:33 +00:00
userTrack.LastUpdated = DateTime.UtcNow;
}
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(track.CacheRegion);
CacheManager.ClearRegion(track.ReleaseMedia.Release.CacheRegion);
CacheManager.ClearRegion(track.ReleaseMedia.Release.Artist.CacheRegion);
2019-01-05 22:40:33 +00:00
2018-12-01 18:05:24 +00:00
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
2018-12-30 20:57:06 +00:00
protected async Task UpdateArtistCounts(int artistId, DateTime now)
{
2019-06-30 22:14:36 +00:00
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == artistId);
2018-12-30 20:57:06 +00:00
if (artist != null)
{
artist.ReleaseCount = DbContext.Releases.Where(x => x.ArtistId == artistId).Count();
2019-06-30 22:14:36 +00:00
artist.TrackCount = (from r in DbContext.Releases
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
where tr.ArtistId == artistId || r.ArtistId == artistId
2018-12-30 20:57:06 +00:00
select tr).Count();
2018-12-30 20:57:06 +00:00
artist.LastUpdated = now;
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(artist.CacheRegion);
2018-12-30 20:57:06 +00:00
}
}
2019-01-08 22:40:26 +00:00
/// <summary>
2019-06-30 22:14:36 +00:00
/// Update the counts for all artists on a release (both track and release artists)
2019-01-08 22:40:26 +00:00
/// </summary>
protected async Task UpdateArtistCountsForRelease(int releaseId, DateTime now)
2018-12-30 20:57:06 +00:00
{
foreach (var artistId in ArtistIdsForRelease(releaseId))
{
await UpdateArtistCounts(artistId, now);
}
2018-12-30 20:57:06 +00:00
}
2019-05-29 22:25:40 +00:00
/// <summary>
2019-06-30 22:14:36 +00:00
/// Update Artist Rank
/// Artist Rank is a sum of the artists release ranks + artist tracks rating + artist user rating
2019-05-29 22:25:40 +00:00
/// </summary>
protected async Task UpdateArtistRank(int artistId, bool updateReleaseRanks = false)
{
try
{
2019-06-30 22:14:36 +00:00
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == artistId);
2019-05-29 22:25:40 +00:00
if (artist != null)
{
if (updateReleaseRanks)
{
2019-06-30 22:14:36 +00:00
var artistReleaseIds = DbContext.Releases.Where(x => x.ArtistId == artistId).Select(x => x.Id)
.ToArray();
2019-05-29 22:25:40 +00:00
foreach (var artistReleaseId in artistReleaseIds)
2019-06-30 22:14:36 +00:00
await UpdateReleaseRank(artistReleaseId, false);
2019-05-29 22:25:40 +00:00
}
2019-06-30 22:14:36 +00:00
var artistTrackAverage = (from t in DbContext.Tracks
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
join ut in DbContext.UserTracks on t.Id equals ut.TrackId
2019-05-29 22:25:40 +00:00
where t.ArtistId == artist.Id
select ut.Rating).Select(x => (decimal?)x).Average();
2019-06-30 22:14:36 +00:00
var artistReleaseRatingRating = (from r in DbContext.Releases
join ur in DbContext.UserReleases on r.Id equals ur.ReleaseId
2019-05-29 22:25:40 +00:00
where r.ArtistId == artist.Id
select ur.Rating).Select(x => (decimal?)x).Average();
2019-06-30 22:14:36 +00:00
var artistReleaseRankSum = (from r in DbContext.Releases
2019-05-29 22:25:40 +00:00
where r.ArtistId == artist.Id
select r.Rank).ToArray().Sum(x => x) ?? 0;
2019-06-30 22:14:36 +00:00
artist.Rank = SafeParser.ToNumber<decimal>(artistTrackAverage + artistReleaseRatingRating) +
artistReleaseRankSum + artist.Rating;
2019-05-29 22:25:40 +00:00
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(artist.CacheRegion);
Logger.LogTrace("UpdatedArtistRank For Artist `{0}`", artist);
2019-05-29 22:25:40 +00:00
}
}
catch (Exception ex)
{
2019-06-30 22:14:36 +00:00
Logger.LogError(ex, "Error in UpdateArtistRank ArtistId [{0}], UpdateReleaseRanks [{1}]", artistId,
updateReleaseRanks);
2019-05-29 22:25:40 +00:00
}
}
/// <summary>
2019-06-30 22:14:36 +00:00
/// Find all artists involved with release and update their rank
2019-05-29 22:25:40 +00:00
/// </summary>
protected async Task UpdateArtistsRankForRelease(data.Release release)
{
if (release != null)
{
var artistsForRelease = new List<int>
{
release.ArtistId
};
2019-06-30 22:14:36 +00:00
var trackArtistsForRelease = (from t in DbContext.Tracks
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
2019-05-29 22:25:40 +00:00
where rm.ReleaseId == release.Id
where t.ArtistId.HasValue
select t.ArtistId.Value).ToArray();
artistsForRelease.AddRange(trackArtistsForRelease);
2019-06-30 22:14:36 +00:00
foreach (var artistId in artistsForRelease.Distinct()) await UpdateArtistRank(artistId);
2019-05-29 22:25:40 +00:00
}
}
2018-12-30 20:57:06 +00:00
protected async Task UpdateLabelCounts(int labelId, DateTime now)
{
2019-06-30 22:14:36 +00:00
var label = DbContext.Labels.FirstOrDefault(x => x.Id == labelId);
2018-12-30 20:57:06 +00:00
if (label != null)
{
2019-06-30 22:14:36 +00:00
label.ReleaseCount = DbContext.ReleaseLabels.Where(x => x.LabelId == label.Id).Count();
label.ArtistCount = (from r in DbContext.Releases
join rl in DbContext.ReleaseLabels on r.Id equals rl.ReleaseId
join a in DbContext.Artists on r.ArtistId equals a.Id
2018-12-30 20:57:06 +00:00
where rl.LabelId == label.Id
2019-06-30 22:14:36 +00:00
group a by a.Id
into artists
2018-12-30 20:57:06 +00:00
select artists).Select(x => x.Key).Count();
2019-06-30 22:14:36 +00:00
label.TrackCount = (from r in DbContext.Releases
join rl in DbContext.ReleaseLabels on r.Id equals rl.ReleaseId
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join t in DbContext.Tracks on rm.Id equals t.ReleaseMediaId
2018-12-30 20:57:06 +00:00
where rl.LabelId == label.Id
select t).Count();
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(label.CacheRegion);
2018-12-30 20:57:06 +00:00
}
}
2019-01-08 22:40:26 +00:00
protected async Task UpdatePlaylistCounts(int playlistId, DateTime now)
{
2019-06-30 22:14:36 +00:00
var playlist = DbContext.Playlists.FirstOrDefault(x => x.Id == playlistId);
2019-01-08 22:40:26 +00:00
if (playlist != null)
{
2019-06-30 22:14:36 +00:00
var playlistTracks = DbContext.PlaylistTracks
.Include(x => x.Track)
.Include("Track.ReleaseMedia")
.Where(x => x.PlayListId == playlist.Id).ToArray();
2019-01-08 22:40:26 +00:00
playlist.TrackCount = (short)playlistTracks.Count();
playlist.Duration = playlistTracks.Sum(x => x.Track.Duration);
2019-06-30 22:14:36 +00:00
playlist.ReleaseCount =
(short)playlistTracks.Select(x => x.Track.ReleaseMedia.ReleaseId).Distinct().Count();
2019-01-08 22:40:26 +00:00
playlist.LastUpdated = now;
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(playlist.CacheRegion);
2019-01-08 22:40:26 +00:00
}
}
2018-12-30 20:57:06 +00:00
protected async Task UpdateReleaseCounts(int releaseId, DateTime now)
{
2019-06-30 22:14:36 +00:00
var release = DbContext.Releases.FirstOrDefault(x => x.Id == releaseId);
2018-12-30 20:57:06 +00:00
if (release != null)
{
2019-06-30 22:14:36 +00:00
release.PlayedCount = (from t in DbContext.Tracks
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
2019-05-29 22:25:40 +00:00
where rm.ReleaseId == releaseId
where t.PlayedCount.HasValue
select t).Sum(x => x.PlayedCount);
2019-06-30 22:14:36 +00:00
release.Duration = (from t in DbContext.Tracks
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
2018-12-30 20:57:06 +00:00
where rm.ReleaseId == releaseId
select t).Sum(x => x.Duration);
2019-06-30 22:14:36 +00:00
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(release.CacheRegion);
2018-12-30 20:57:06 +00:00
}
}
2019-01-02 02:03:17 +00:00
2019-01-22 00:04:58 +00:00
/// <summary>
2019-06-30 22:14:36 +00:00
/// Update Relase Rank
/// Release Rank Calculation = Average of Track User Ratings + (User Rating of Release / Release Track Count) +
/// Collection Rank Value
2019-01-22 00:04:58 +00:00
/// </summary>
2019-01-23 16:50:36 +00:00
protected async Task UpdateReleaseRank(int releaseId, bool updateArtistRank = true)
2019-01-22 00:04:58 +00:00
{
2019-02-03 00:24:34 +00:00
try
2019-01-22 00:04:58 +00:00
{
2019-06-30 22:14:36 +00:00
var release = DbContext.Releases.FirstOrDefault(x => x.Id == releaseId);
2019-02-03 00:24:34 +00:00
if (release != null)
2019-01-22 00:04:58 +00:00
{
2019-06-30 22:14:36 +00:00
var releaseTrackAverage = (from ut in DbContext.UserTracks
join t in DbContext.Tracks on ut.TrackId equals t.Id
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
2019-02-03 00:24:34 +00:00
where rm.ReleaseId == releaseId
2019-05-14 20:20:09 +00:00
select ut.Rating).Select(x => (decimal?)x).Average();
2019-02-03 00:24:34 +00:00
2019-06-30 22:14:36 +00:00
var releaseUserRatingRank = release.Rating > 0 ? release.Rating / (decimal?)release.TrackCount : 0;
2019-02-03 00:24:34 +00:00
2019-06-30 22:14:36 +00:00
var collectionsWithRelease = from c in DbContext.Collections
join cr in DbContext.CollectionReleases on c.Id equals cr.CollectionId
where c.CollectionType != CollectionType.Chart
where cr.ReleaseId == release.Id
select new
{
c.CollectionCount,
cr.ListNumber
};
2019-02-03 00:24:34 +00:00
decimal releaseCollectionRank = 0;
foreach (var collectionWithRelease in collectionsWithRelease)
{
2019-06-30 22:14:36 +00:00
var rank = (decimal)(collectionWithRelease.CollectionCount * .01 -
(collectionWithRelease.ListNumber - 1) * .01);
2019-02-03 00:24:34 +00:00
releaseCollectionRank += rank;
}
2019-01-22 00:04:58 +00:00
2019-06-30 22:14:36 +00:00
release.Rank = SafeParser.ToNumber<decimal>(releaseTrackAverage) + releaseUserRatingRank +
releaseCollectionRank;
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(release.CacheRegion);
Logger.LogTrace("UpdateReleaseRank For Release `{0}`", release);
2019-06-30 22:14:36 +00:00
if (updateArtistRank) await UpdateArtistsRankForRelease(release);
2019-01-23 16:50:36 +00:00
}
2019-01-22 00:04:58 +00:00
}
2019-02-03 00:24:34 +00:00
catch (Exception ex)
{
2019-06-30 22:14:36 +00:00
Logger.LogError(ex, "Error UpdateReleaseRank RelaseId [{0}], UpdateArtistRank [{1}]", releaseId,
updateArtistRank);
2019-02-03 00:24:34 +00:00
}
2019-01-22 00:04:58 +00:00
}
2019-06-30 22:14:36 +00:00
private Image MakeImage(Guid id, string type, int? width, int? height, string caption = null,
bool includeCachebuster = false)
2019-01-02 02:03:17 +00:00
{
2019-06-30 22:14:36 +00:00
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);
2019-01-02 02:03:17 +00:00
}
2018-11-06 04:31:25 +00:00
}
2018-11-11 20:10:10 +00:00
}