feat(backend): save a YouTube album with all of its tracks

POST /albums/youtube/{albumId} creates the album in your library and links
every song in it, provisioning each one as an external track without queueing
any download. The external id is kept on the album so saving it twice returns
a conflict instead of a duplicate, and albums can now hold external tracks,
not just the ones you uploaded.
This commit is contained in:
2026-07-20 20:47:50 +02:00
parent 29c220a1cf
commit df1cd5f1e9
8 changed files with 1256 additions and 7 deletions
@@ -32,16 +32,19 @@ namespace Musify.Application.Albums
return Error.Unauthorized();
}
var track = await database.LocalTracks
var trackExists = await database.Tracks
.AsNoTracking()
.SingleOrDefaultAsync(t => t.Id == request.TrackId, cancellationToken);
if (track is null)
.AnyAsync(t => t.Id == request.TrackId, cancellationToken);
if (!trackExists)
{
logger.LogInformation("Local track {TrackId} not found", request.TrackId);
return Error.NotFound(description: "Only tracks you uploaded can be added to an album.");
logger.LogInformation("Track {TrackId} not found", request.TrackId);
return Error.NotFound(description: $"Track {request.TrackId} not found");
}
if (track.OwnerUserId != request.UserId)
var localTrack = await database.LocalTracks
.AsNoTracking()
.SingleOrDefaultAsync(t => t.Id == request.TrackId, cancellationToken);
if (localTrack is not null && localTrack.OwnerUserId != request.UserId)
{
logger.LogWarning("User {UserId} does not own track {TrackId}", request.UserId, request.TrackId);
return Error.Unauthorized();