backend: expose track count and duration on playlist responses

This commit is contained in:
2026-09-24 05:20:20 +02:00
parent 1df7f6ccf6
commit b011ccdd5b
5 changed files with 31 additions and 4 deletions
@@ -21,6 +21,8 @@ namespace Musify.Application.PlayLists
.Select(p => new .Select(p => new
{ {
PlayList = p, PlayList = p,
TrackCount = p.PlayListTracks.Count,
DurationSeconds = p.PlayListTracks.Sum(plt => (double?)plt.Track.DurationSeconds) ?? 0,
CoverTrackIds = p.PlayListTracks CoverTrackIds = p.PlayListTracks
.OrderBy(plt => plt.Position) .OrderBy(plt => plt.Position)
.Take(PlayListApplicationResponse.CoverTrackCount) .Take(PlayListApplicationResponse.CoverTrackCount)
@@ -36,7 +38,7 @@ namespace Musify.Application.PlayLists
&& entry.PlayList.UserId != request.RequestingUserId) && entry.PlayList.UserId != request.RequestingUserId)
return Error.NotFound(); return Error.NotFound();
return PlayListApplicationResponse.FromEntity(entry.PlayList, entry.CoverTrackIds); return PlayListApplicationResponse.FromEntity(entry.PlayList, entry.TrackCount, entry.DurationSeconds, entry.CoverTrackIds);
} }
} }
} }
@@ -25,6 +25,8 @@ namespace Musify.Application.PlayLists
.Select(p => new .Select(p => new
{ {
PlayList = p, PlayList = p,
TrackCount = p.PlayListTracks.Count,
DurationSeconds = p.PlayListTracks.Sum(plt => (double?)plt.Track.DurationSeconds) ?? 0,
CoverTrackIds = p.PlayListTracks CoverTrackIds = p.PlayListTracks
.OrderBy(plt => plt.Position) .OrderBy(plt => plt.Position)
.Take(PlayListApplicationResponse.CoverTrackCount) .Take(PlayListApplicationResponse.CoverTrackCount)
@@ -34,7 +36,7 @@ namespace Musify.Application.PlayLists
.ToPagedListAsync(request.PageNumber, request.PageSize, totalCount, cancellationToken); .ToPagedListAsync(request.PageNumber, request.PageSize, totalCount, cancellationToken);
var pagedPlayLists = new StaticPagedList<PlayListApplicationResponse>( var pagedPlayLists = new StaticPagedList<PlayListApplicationResponse>(
pagedEntities.Select(entry => PlayListApplicationResponse.FromEntity(entry.PlayList, entry.CoverTrackIds)), pagedEntities.Select(entry => PlayListApplicationResponse.FromEntity(entry.PlayList, entry.TrackCount, entry.DurationSeconds, entry.CoverTrackIds)),
pagedEntities.PageNumber, pagedEntities.PageSize, pagedEntities.TotalItemCount); pagedEntities.PageNumber, pagedEntities.PageSize, pagedEntities.TotalItemCount);
return PaginatedResponse<PlayListApplicationResponse>.FromPagedList(pagedPlayLists); return PaginatedResponse<PlayListApplicationResponse>.FromPagedList(pagedPlayLists);
@@ -46,6 +46,8 @@ namespace Musify.Application.PlayLists
.Select(p => new .Select(p => new
{ {
PlayList = p, PlayList = p,
TrackCount = p.PlayListTracks.Count,
DurationSeconds = p.PlayListTracks.Sum(plt => (double?)plt.Track.DurationSeconds) ?? 0,
CoverTrackIds = p.PlayListTracks CoverTrackIds = p.PlayListTracks
.OrderBy(plt => plt.Position) .OrderBy(plt => plt.Position)
.Take(PlayListApplicationResponse.CoverTrackCount) .Take(PlayListApplicationResponse.CoverTrackCount)
@@ -55,7 +57,7 @@ namespace Musify.Application.PlayLists
.ToPagedListAsync(request.PageNumber, request.PageSize, totalCount, cancellationToken); .ToPagedListAsync(request.PageNumber, request.PageSize, totalCount, cancellationToken);
var pagedPlayLists = new StaticPagedList<PlayListApplicationResponse>( var pagedPlayLists = new StaticPagedList<PlayListApplicationResponse>(
pagedEntities.Select(entry => PlayListApplicationResponse.FromEntity(entry.PlayList, entry.CoverTrackIds)), pagedEntities.Select(entry => PlayListApplicationResponse.FromEntity(entry.PlayList, entry.TrackCount, entry.DurationSeconds, entry.CoverTrackIds)),
pagedEntities.PageNumber, pagedEntities.PageSize, pagedEntities.TotalItemCount); pagedEntities.PageNumber, pagedEntities.PageSize, pagedEntities.TotalItemCount);
return PaginatedResponse<PlayListApplicationResponse>.FromPagedList(pagedPlayLists); return PaginatedResponse<PlayListApplicationResponse>.FromPagedList(pagedPlayLists);
@@ -14,6 +14,8 @@ namespace Musify.Application.PlayLists.Responses
string? LargeImageKeyName, string? LargeImageKeyName,
[property: JsonConverter(typeof(LongAsStringConverter))] long OwnerUserId, [property: JsonConverter(typeof(LongAsStringConverter))] long OwnerUserId,
PlaylistVisibility Visibility, PlaylistVisibility Visibility,
int TrackCount,
double DurationSeconds,
DateTime CreatedAt, DateTime CreatedAt,
DateTime UpdatedAt, DateTime UpdatedAt,
IReadOnlyList<Guid> CoverTrackIds) IReadOnlyList<Guid> CoverTrackIds)
@@ -22,6 +24,8 @@ namespace Musify.Application.PlayLists.Responses
public static PlayListApplicationResponse FromEntity( public static PlayListApplicationResponse FromEntity(
PlayList playList, PlayList playList,
int trackCount = 0,
double durationSeconds = 0,
IReadOnlyList<Guid>? coverTrackIds = null) IReadOnlyList<Guid>? coverTrackIds = null)
{ {
return new PlayListApplicationResponse( return new PlayListApplicationResponse(
@@ -33,6 +37,8 @@ namespace Musify.Application.PlayLists.Responses
playList.Pictures?.LargeName, playList.Pictures?.LargeName,
playList.UserId, playList.UserId,
playList.Visibility, playList.Visibility,
trackCount,
durationSeconds,
playList.CreatedAt, playList.CreatedAt,
playList.UpdatedAt, playList.UpdatedAt,
coverTrackIds ?? []); coverTrackIds ?? []);
@@ -112,7 +112,22 @@ namespace Musify.Application.PlayLists
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
logger.LogInformation("Updated playlist {PlayListId}", playListEntity.Id); logger.LogInformation("Updated playlist {PlayListId}", playListEntity.Id);
return PlayListApplicationResponse.FromEntity(playListEntity, coverTrackIds); var totals = await database.PlayListHasTracks
.AsNoTracking()
.Where(plt => plt.PlayListId == playListEntity.Id)
.GroupBy(plt => plt.PlayListId)
.Select(group => new
{
TrackCount = group.Count(),
DurationSeconds = group.Sum(plt => plt.Track.DurationSeconds)
})
.SingleOrDefaultAsync(cancellationToken);
return PlayListApplicationResponse.FromEntity(
playListEntity,
totals?.TrackCount ?? 0,
totals?.DurationSeconds ?? 0,
coverTrackIds);
} }
private async Task<ErrorOr<Success>> PublishUpdatePlayListPictureSourceEventAsync( private async Task<ErrorOr<Success>> PublishUpdatePlayListPictureSourceEventAsync(