Genre work. Artist counts now are both tracks and releases.

This commit is contained in:
Steven Hildreth 2018-12-28 12:58:17 -06:00
parent f5e57d083d
commit 70d754aa5f
11 changed files with 112 additions and 59 deletions

View file

@ -26,7 +26,7 @@ namespace Roadie.Library.Data
public ICollection<CollectionRelease> Collections { get; set; }
[Column("duration")]
public int? Duration { get; set; } // TODO update this on release scan
public int? Duration { get; set; }
[Column("discogsId")]
[MaxLength(50)]

View file

@ -6,6 +6,7 @@ using Roadie.Library.Encoding;
using Roadie.Library.Engines;
using Roadie.Library.SearchEngines.MetaData;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@ -35,6 +36,29 @@ namespace Roadie.Library.Factories
this.ReleaseLookupEngine = releaseLookupEngine;
}
protected IEnumerable<int> ArtistIdsForRelease(int releaseId)
{
var trackArtistIds = (from r in this.DbContext.Releases
join rm in this.DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join tr in this.DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
where r.Id == releaseId
where tr.ArtistId != null
select tr.ArtistId.Value).ToList();
trackArtistIds.Add(this.DbContext.Releases.FirstOrDefault(x => x.Id == releaseId).ArtistId);
return trackArtistIds.Distinct().ToArray();
}
/// <summary>
/// Update the counts for all artists on a release (both track and release artists)
/// </summary>
protected async Task UpdateArtistCountsForRelease(int releaseId, DateTime now)
{
foreach(var artistId in this.ArtistIdsForRelease(releaseId))
{
await this.UpdateArtistCounts(artistId, now);
}
}
protected async Task UpdateArtistCounts(int artistId, DateTime now)
{
var artist = this.DbContext.Artists.FirstOrDefault(x => x.Id == artistId);
@ -44,8 +68,9 @@ namespace Roadie.Library.Factories
artist.TrackCount = (from r in this.DbContext.Releases
join rm in this.DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join tr in this.DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
where r.ArtistId == artistId
where (tr.ArtistId == artistId || r.ArtistId == artistId)
select tr).Count();
artist.LastUpdated = now;
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(artist.CacheRegion);

View file

@ -809,8 +809,9 @@ namespace Roadie.Library.Factories
sw.Stop();
await base.UpdateReleaseCounts(release.Id, now);
await base.UpdateArtistCounts(release.ArtistId, now);
await base.UpdateArtistCountsForRelease(release.Id, now);
if(release.Labels != null && release.Labels.Any())
{
foreach(var label in release.Labels)

View file

@ -8,6 +8,8 @@ namespace Roadie.Library.Models
public class GenreList : EntityInfoModelBase
{
public DataToken Genre { get; set; }
public int? ReleaseCount { get; set; }
public int? ArtistCount { get; set; }
}
}

View file

@ -219,13 +219,10 @@ namespace Roadie.Api.Services
if (includes.Contains("stats"))
{
tsw.Restart();
// TODO this should be on artist properties to speed up fetch times
var artistTracks = (from r in this.DbContext.Releases
join rm in this.DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join t in this.DbContext.Tracks on rm.Id equals t.ReleaseMediaId
where r.ArtistId == artist.Id
where (r.ArtistId == artist.Id || t.ArtistId == artist.Id)
select new
{
t.Id,

View file

@ -28,7 +28,7 @@ namespace Roadie.Api.Services
{
}
public Task<Library.Models.Pagination.PagedResult<GenreList>> List(User roadieUser, PagedRequest request)
public Task<Library.Models.Pagination.PagedResult<GenreList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false)
{
var sw = new Stopwatch();
sw.Start();
@ -39,6 +39,12 @@ namespace Roadie.Api.Services
request.Sort = request.Sort.Replace("lastUpdated", "lastUpdatedDateTime");
}
var result = (from g in this.DbContext.Genres
let releaseCount = (from rg in this.DbContext.ReleaseGenres
where rg.GenreId == g.Id
select rg.Id).Count()
let artistCount = (from rg in this.DbContext.ArtistGenres
where rg.GenreId == g.Id
select rg.Id).Count()
where (request.FilterValue.Length == 0 || (g.Name.Contains(request.FilterValue)))
select new GenreList
{
@ -49,14 +55,25 @@ namespace Roadie.Api.Services
Text = g.Name,
Value = g.RoadieId.ToString()
},
ReleaseCount = releaseCount,
ArtistCount = artistCount,
CreatedDate = g.CreatedDate,
LastUpdated = g.LastUpdated,
});
GenreList[] rows = null;
var rowCount = result.Count();
var sortBy = string.IsNullOrEmpty(request.Sort) ? request.OrderValue(new Dictionary<string, string> { { "Genre.Text", "ASC" } }) : request.OrderValue(null);
rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
if (doRandomize ?? false)
{
var randomLimit = roadieUser?.RandomReleaseLimit ?? 100;
request.Limit = request.LimitValue > randomLimit ? randomLimit : request.LimitValue;
rows = result.OrderBy(x => Guid.NewGuid()).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
}
else
{
var sortBy = string.IsNullOrEmpty(request.Sort) ? request.OrderValue(new Dictionary<string, string> { { "Genre.Text", "ASC" } }) : request.OrderValue(null);
rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
}
sw.Stop();
return Task.FromResult(new Library.Models.Pagination.PagedResult<GenreList>
{

View file

@ -7,6 +7,6 @@ namespace Roadie.Api.Services
{
public interface IGenreService
{
Task<PagedResult<GenreList>> List(User roadieUser, PagedRequest request);
Task<PagedResult<GenreList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false);
}
}

View file

@ -732,7 +732,6 @@ namespace Roadie.Api.Services
}
if (includes.Contains("stats"))
{
// TODO move these to release properties to speed up fetch times
var releaseTracks = (from r in this.DbContext.Releases
join rm in this.DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join t in this.DbContext.Tracks on rm.Id equals t.ReleaseMediaId

View file

@ -366,51 +366,59 @@ namespace Roadie.Api.Services
/// </summary>
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetAlbum(subsonic.Request request, User roadieUser)
{
var releaseId = SafeParser.ToGuid(request.id);
if (!releaseId.HasValue)
try
{
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release [{ request.ReleaseId}]");
}
var release = this.GetRelease(releaseId.Value);
if (release == null)
{
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release [{ request.ReleaseId}]");
}
var trackPagedRequest = request.PagedRequest;
trackPagedRequest.Sort = "TrackNumber";
trackPagedRequest.Order = "ASC";
var releaseTracks = await this.TrackService.List(trackPagedRequest, roadieUser, false, releaseId);
var userRelease = roadieUser == null ? null : this.DbContext.UserReleases.FirstOrDefault(x => x.ReleaseId == release.Id && x.UserId == roadieUser.Id);
var genre = release.Genres.FirstOrDefault();
return new subsonic.SubsonicOperationResult<subsonic.Response>
{
IsSuccess = true,
Data = new subsonic.Response
var releaseId = SafeParser.ToGuid(request.id);
if (!releaseId.HasValue)
{
version = SubsonicService.SubsonicVersion,
status = subsonic.ResponseStatus.ok,
ItemElementName = subsonic.ItemChoiceType.album,
Item = new subsonic.AlbumWithSongsID3
{
artist = release.Artist.Name,
artistId = subsonic.Request.ArtistIdIdentifier + release.Artist.RoadieId.ToString(),
coverArt = subsonic.Request.ReleaseIdIdentifier + release.RoadieId.ToString(),
created = release.CreatedDate,
duration = release.Duration.ToSecondsFromMilliseconds(),
genre = genre == null ? null : genre.Genre.Name,
id = subsonic.Request.ReleaseIdIdentifier + release.RoadieId.ToString(),
name = release.Title,
playCount = releaseTracks.Rows.Sum(x => x.PlayedCount) ?? 0,
playCountSpecified = releaseTracks.Rows.Any(),
songCount = releaseTracks.Rows.Count(),
starred = userRelease?.LastUpdated ?? userRelease?.CreatedDate ?? DateTime.UtcNow,
starredSpecified = userRelease?.IsFavorite ?? false,
year = release.ReleaseDate != null ? release.ReleaseDate.Value.Year : 0,
yearSpecified = release.ReleaseDate != null,
song = this.SubsonicChildrenForTracks(releaseTracks.Rows)
}
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release [{ request.ReleaseId}]");
}
};
var release = this.GetRelease(releaseId.Value);
if (release == null)
{
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release [{ request.ReleaseId}]");
}
var trackPagedRequest = request.PagedRequest;
trackPagedRequest.Sort = "TrackNumber";
trackPagedRequest.Order = "ASC";
var releaseTracks = await this.TrackService.List(trackPagedRequest, roadieUser, false, releaseId);
var userRelease = roadieUser == null ? null : this.DbContext.UserReleases.FirstOrDefault(x => x.ReleaseId == release.Id && x.UserId == roadieUser.Id);
var genre = release.Genres.FirstOrDefault();
return new subsonic.SubsonicOperationResult<subsonic.Response>
{
IsSuccess = true,
Data = new subsonic.Response
{
version = SubsonicService.SubsonicVersion,
status = subsonic.ResponseStatus.ok,
ItemElementName = subsonic.ItemChoiceType.album,
Item = new subsonic.AlbumWithSongsID3
{
artist = release.Artist.Name,
artistId = subsonic.Request.ArtistIdIdentifier + release.Artist.RoadieId.ToString(),
coverArt = subsonic.Request.ReleaseIdIdentifier + release.RoadieId.ToString(),
created = release.CreatedDate,
duration = release.Duration.ToSecondsFromMilliseconds(),
genre = genre == null ? null : genre.Genre.Name,
id = subsonic.Request.ReleaseIdIdentifier + release.RoadieId.ToString(),
name = release.Title,
playCount = releaseTracks.Rows.Sum(x => x.PlayedCount) ?? 0,
playCountSpecified = releaseTracks.Rows.Any(),
songCount = releaseTracks.Rows.Count(),
starred = userRelease?.LastUpdated ?? userRelease?.CreatedDate ?? DateTime.UtcNow,
starredSpecified = userRelease?.IsFavorite ?? false,
year = release.ReleaseDate != null ? release.ReleaseDate.Value.Year : 0,
yearSpecified = release.ReleaseDate != null,
song = this.SubsonicChildrenForTracks(releaseTracks.Rows)
}
}
};
}
catch (Exception ex)
{
this.Logger.LogError(ex, "GetAlbum Request [{0}], User [{1}]", JsonConvert.SerializeObject(request), roadieUser.ToString());
}
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release [{ request.ReleaseId}]");
}
/// <summary>

View file

@ -516,11 +516,14 @@ namespace Roadie.Api.Services
where ua.UserId == roadieUser.Id
where trackArtistIds.Contains(ua.ArtistId)
select ua).ToArray();
foreach (var userTrackArtistRating in userTrackArtistRatings)
if (userTrackArtistRatings != null && userTrackArtistRatings.Any())
{
foreach (var artistTrack in rows.Where(x => x.TrackArtist.DatabaseId == userTrackArtistRating.ArtistId))
foreach (var userTrackArtistRating in userTrackArtistRatings)
{
artistTrack.Artist.UserRating = userTrackArtistRating.Adapt<UserArtist>();
foreach (var artistTrack in rows.Where(x => x.TrackArtist != null && x.TrackArtist.DatabaseId == userTrackArtistRating.ArtistId))
{
artistTrack.Artist.UserRating = userTrackArtistRating.Adapt<UserArtist>();
}
}
}
}

View file

@ -57,10 +57,11 @@ namespace Roadie.Api.Controllers
[HttpGet]
[ProducesResponseType(200)]
public async Task<IActionResult> List([FromQuery]PagedRequest request)
public async Task<IActionResult> List([FromQuery]PagedRequest request, bool? doRandomize = false)
{
var result = await this.GenreService.List(roadieUser: await this.CurrentUserModel(),
request: request);
request: request,
doRandomize: doRandomize);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);