using ErrorOr; using Mediator; using Microsoft.EntityFrameworkCore; using Musify.Application.Configuration; using Musify.Application.Contracts; namespace Musify.Application.Tracks { public record GetTrackCoverQuery(Guid TrackId, string Size) : IQuery>; public record TrackCoverLocation(string Bucket, string Key, string ContentType); public class GetTrackCoverQueryHandler( IDatabase database, ApplicationStorageConfiguration storageConfiguration, TrackConfiguration trackConfiguration) : IQueryHandler> { public async ValueTask> Handle(GetTrackCoverQuery request, CancellationToken cancellationToken) { var track = await database.Tracks.AsNoTracking() .Where(t => t.Id == request.TrackId) .Select(t => new { t.SmallPictureName, t.MediumPictureName, t.LargePictureName }) .SingleOrDefaultAsync(cancellationToken); if (track == null) return Error.NotFound(); var routes = trackConfiguration.Routes; var (name, key) = request.Size.ToLowerInvariant() switch { "small" => (track.SmallPictureName, BuildKey(routes.BuildSmallPicturePath, track.SmallPictureName)), "large" => (track.LargePictureName, BuildKey(routes.BuildLargePicturePath, track.LargePictureName)), _ => (track.MediumPictureName, BuildKey(routes.BuildMediumPicturePath, track.MediumPictureName)) }; if (string.IsNullOrEmpty(name) || key == null) return Error.NotFound(); var contentType = name.EndsWith(".webp", StringComparison.OrdinalIgnoreCase) ? "image/webp" : name.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ? "image/png" : "image/jpeg"; return new TrackCoverLocation(storageConfiguration.Bucket, key, contentType); } private static string? BuildKey(Func builder, string? name) => string.IsNullOrEmpty(name)? null: builder(name); } }