This commit is contained in:
2026-05-28 18:37:54 +02:00
parent 868af6dc49
commit 5c75b611f0
29 changed files with 683 additions and 219 deletions
@@ -0,0 +1,12 @@
namespace Musify.Application.Events
{
public record CreatePlayListResourcesEvent(
Guid PlayListId,
Guid PictureIntentId,
string Bucket,
string PictureSourceKey,
string PictureDestinationKey,
ImageSize Small,
ImageSize Medium,
ImageSize Large);
}
@@ -0,0 +1,16 @@
namespace Musify.Application.Events
{
public record CreateTrackResourcesEvent(
Guid TrackId,
Guid PictureIntentId,
Guid AudioIntentId,
string Bucket,
string PictureSourceKey,
string PictureDestinationKey,
string AudioSourceKey,
string AudioDestinationKey,
string AudioProcessedFolderKey,
ImageSize Small,
ImageSize Medium,
ImageSize Large);
}
@@ -0,0 +1,12 @@
namespace Musify.Application.Events
{
public record UpdatePlayListPictureSourceEvent(
Guid PlayListId,
Guid PictureIntentId,
string Bucket,
string PictureSourceKey,
string PictureDestinationKey,
ImageSize Small,
ImageSize Medium,
ImageSize Large);
}
@@ -17,7 +17,6 @@ namespace Musify.Application.PlayLists.Handlers
IEventBus eventBus,
IDatabase database,
UploadIntentValidator uploadIntentValidator,
IStorageService storageService,
ILogger<CreatePlayListCommandHandler> logger,
ApplicationStorageConfiguration storageConfiguration,
PlayListConfiguration playListConfiguration,
@@ -35,8 +34,8 @@ namespace Musify.Application.PlayLists.Handlers
return Result.NotFound($"User {request.UserId} not found");
}
string originalPictureName;
UploadIntent? pictureIntent = null;
string originalPictureName;
if (request.PictureIntentId.HasValue)
{
@@ -48,17 +47,6 @@ namespace Musify.Application.PlayLists.Handlers
pictureIntent = validation.Value;
originalPictureName = pictureIntent.ObjectName;
var finalKey = playListConfiguration.Routes.BuildOriginalPicturePath(request.UserId, originalPictureName);
try
{
await storageService.CopyFileAsync(pictureIntent.Bucket, pictureIntent.Key, pictureIntent.Bucket, finalKey, cancellationToken);
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to copy playlist picture from temp {TempKey} to final {FinalKey}", pictureIntent.Key, finalKey);
return Result.Error("Failed to move uploaded file to its final location.");
}
}
else
{
@@ -81,9 +69,9 @@ namespace Musify.Application.PlayLists.Handlers
if (pictureIntent is not null)
{
pictureIntent.Status = UploadIntentStatus.Consumed;
var publishResult = await PublishPictureUpdateEventAsync(playList, cancellationToken);
var finalPictureKey = playListConfiguration.Routes.BuildOriginalPicturePath(request.UserId, originalPictureName);
var publishResult = await PublishCreatePlayListEventAsync(
playList.Id, pictureIntent, finalPictureKey, cancellationToken);
if (!publishResult.IsSuccess)
return publishResult;
}
@@ -102,35 +90,41 @@ namespace Musify.Application.PlayLists.Handlers
return Result.Created(PlayListApplicationResponse.FromEntity(playList));
}
async Task<Result> PublishPictureUpdateEventAsync(PlayList playList, CancellationToken cancellationToken)
async Task<Result<PlayListApplicationResponse>> PublishCreatePlayListEventAsync(
Guid playListId,
UploadIntent pictureIntent,
string finalPictureKey,
CancellationToken cancellationToken)
{
try
{
var updateEvent = new UpdatePlayListPictureEvent(
playList.Id,
storageConfiguration.Bucket,
playListConfiguration.Routes.BuildOriginalPicturePath(playList.UserId, playList.OriginalPictureName),
new ImageSize(
playListConfiguration.Routes.SmallPicturesPath,
playListConfiguration.PicturesSizes.SmallPictureWidth,
playListConfiguration.PicturesSizes.SmallPictureHeight),
new ImageSize(
playListConfiguration.Routes.MediumPicturesPath,
playListConfiguration.PicturesSizes.MediumPictureWidth,
playListConfiguration.PicturesSizes.MediumPictureHeight),
new ImageSize(
playListConfiguration.Routes.LargePicturesPath,
playListConfiguration.PicturesSizes.LargePictureWidth,
playListConfiguration.PicturesSizes.LargePictureHeight));
await eventBus.PublishAsync(updateEvent, cancellationToken);
await eventBus.PublishAsync(
new CreatePlayListResourcesEvent(
playListId,
pictureIntent.Id,
storageConfiguration.Bucket,
pictureIntent.Key,
finalPictureKey,
new ImageSize(
playListConfiguration.Routes.SmallPicturesPath,
playListConfiguration.PicturesSizes.SmallPictureWidth,
playListConfiguration.PicturesSizes.SmallPictureHeight),
new ImageSize(
playListConfiguration.Routes.MediumPicturesPath,
playListConfiguration.PicturesSizes.MediumPictureWidth,
playListConfiguration.PicturesSizes.MediumPictureHeight),
new ImageSize(
playListConfiguration.Routes.LargePicturesPath,
playListConfiguration.PicturesSizes.LargePictureWidth,
playListConfiguration.PicturesSizes.LargePictureHeight)),
cancellationToken);
return Result.Success();
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to publish picture update event for playlist {PlayListId}", playList.Id);
return Result.Error($"Failed to publish picture update event for playlist {playList.Id}");
logger.LogError(exception, "Failed to publish create playlist event for playlist {PlayListId}", playListId);
return Result.Error($"Failed to publish create playlist event for playlist {playListId}");
}
}
}
}
}
@@ -17,7 +17,6 @@ namespace Musify.Application.PlayLists.Handlers
IEventBus eventBus,
IDatabase database,
UploadIntentValidator uploadIntentValidator,
IStorageService storageService,
ILogger<UpdatePlayListCommandHandler> logger,
ApplicationStorageConfiguration storageConfiguration,
PlayListConfiguration playListConfiguration,
@@ -50,6 +49,9 @@ namespace Musify.Application.PlayLists.Handlers
playListEntity.Description = request.NewDescription;
}
UploadIntent? pictureIntent = null;
string? finalPictureKey = null;
if (request.NewPictureIntentId.HasValue)
{
var validation = await uploadIntentValidator.ValidateAndLoadAsync(
@@ -58,29 +60,23 @@ namespace Musify.Application.PlayLists.Handlers
if (!validation.IsSuccess)
return validation.As<UploadIntent, PlayListApplicationResponse>();
var intent = validation.Value;
var finalKey = playListConfiguration.Routes.BuildOriginalPicturePath(request.UserId, intent.ObjectName);
try
{
await storageService.CopyFileAsync(intent.Bucket, intent.Key, intent.Bucket, finalKey, cancellationToken);
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to copy playlist picture from temp {TempKey} to final {FinalKey}", intent.Key, finalKey);
return Result.Error("Failed to move uploaded file to its final location.");
}
pictureIntent = validation.Value;
playListEntity.OriginalPictureName = pictureIntent.ObjectName;
finalPictureKey = playListConfiguration.Routes.BuildOriginalPicturePath(request.UserId, pictureIntent.ObjectName);
}
playListEntity.OriginalPictureName = intent.ObjectName;
intent.Status = UploadIntentStatus.Consumed;
database.PlayLists.Update(playListEntity);
var publishResult = await PublishPlayListPictureEvent(playListEntity.UserId, playListEntity.Id, playListEntity.OriginalPictureName, cancellationToken);
if (pictureIntent is not null && finalPictureKey is not null)
{
var publishResult = await PublishUpdatePlayListPictureSourceEventAsync(
playListEntity.Id, pictureIntent, finalPictureKey, cancellationToken);
if (!publishResult.IsSuccess)
return publishResult;
}
try
{
database.PlayLists.Update(playListEntity);
await database.SaveChangesAsync(cancellationToken);
}
catch (Exception exception)
@@ -93,34 +89,41 @@ namespace Musify.Application.PlayLists.Handlers
return Result.Success(PlayListApplicationResponse.FromEntity(playListEntity));
}
async Task<Result> PublishPlayListPictureEvent(Guid userId, Guid playListId, string originalPictureName, CancellationToken cancellationToken)
async Task<Result<PlayListApplicationResponse>> PublishUpdatePlayListPictureSourceEventAsync(
Guid playListId,
UploadIntent pictureIntent,
string finalPictureKey,
CancellationToken cancellationToken)
{
try
{
await eventBus.PublishAsync(new UpdatePlayListPictureEvent(
playListId,
storageConfiguration.Bucket,
playListConfiguration.Routes.BuildOriginalPicturePath(userId, originalPictureName),
new ImageSize(
playListConfiguration.Routes.SmallPicturesPath,
playListConfiguration.PicturesSizes.SmallPictureWidth,
playListConfiguration.PicturesSizes.SmallPictureHeight),
new ImageSize(
playListConfiguration.Routes.MediumPicturesPath,
playListConfiguration.PicturesSizes.MediumPictureWidth,
playListConfiguration.PicturesSizes.MediumPictureHeight),
new ImageSize(
playListConfiguration.Routes.LargePicturesPath,
playListConfiguration.PicturesSizes.LargePictureWidth,
playListConfiguration.PicturesSizes.LargePictureHeight)),
await eventBus.PublishAsync(
new UpdatePlayListPictureSourceEvent(
playListId,
pictureIntent.Id,
storageConfiguration.Bucket,
pictureIntent.Key,
finalPictureKey,
new ImageSize(
playListConfiguration.Routes.SmallPicturesPath,
playListConfiguration.PicturesSizes.SmallPictureWidth,
playListConfiguration.PicturesSizes.SmallPictureHeight),
new ImageSize(
playListConfiguration.Routes.MediumPicturesPath,
playListConfiguration.PicturesSizes.MediumPictureWidth,
playListConfiguration.PicturesSizes.MediumPictureHeight),
new ImageSize(
playListConfiguration.Routes.LargePicturesPath,
playListConfiguration.PicturesSizes.LargePictureWidth,
playListConfiguration.PicturesSizes.LargePictureHeight)),
cancellationToken);
return Result.Success();
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to publish playlist picture update event for playlist {PlayListId}", playListId);
return Result.Error($"Failed to publish playlist {playListId} picture update event");
logger.LogError(exception, "Failed to publish update playlist picture source event for playlist {PlayListId}", playListId);
return Result.Error($"Failed to publish update playlist picture source event for playlist {playListId}");
}
}
}
}
}
@@ -17,7 +17,6 @@ namespace Musify.Application.Tracks.Handler
IDatabase database,
IEventBus eventBus,
UploadIntentValidator uploadIntentValidator,
IStorageService storageService,
ILogger<CreateTrackCommandHandler> logger,
ApplicationStorageConfiguration storageConfiguration,
TrackConfiguration trackConfiguration,
@@ -51,17 +50,7 @@ namespace Musify.Application.Tracks.Handler
var finalPictureKey = trackConfiguration.Routes.BuildOriginalPicturePath(request.UserId, pictureIntent.ObjectName);
var finalAudioKey = trackConfiguration.Routes.BuildOriginalAudioPath(request.UserId, audioIntent.ObjectName);
try
{
await storageService.CopyFileAsync(pictureIntent.Bucket, pictureIntent.Key, pictureIntent.Bucket, finalPictureKey, cancellationToken);
await storageService.CopyFileAsync(audioIntent.Bucket, audioIntent.Key, audioIntent.Bucket, finalAudioKey, cancellationToken);
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to copy track files from temp to final location for user {UserId}", request.UserId);
return Result.Error("Failed to move uploaded files to their final locations.");
}
var audioProcessedFolderKey = trackConfiguration.Routes.BuildProcessedAudioPath(Guid.NewGuid().ToString());
var trackEntity = new Track
{
@@ -78,16 +67,38 @@ namespace Musify.Application.Tracks.Handler
await database.Tracks.AddAsync(trackEntity, cancellationToken);
pictureIntent.Status = UploadIntentStatus.Consumed;
audioIntent.Status = UploadIntentStatus.Consumed;
var publishPictureResult = await PublishUpdateEvent(request.UserId, trackEntity, cancellationToken);
if (!publishPictureResult.IsSuccess)
return Result.Error($"Failed to create track for {request.Title}");
var publishTranscodeResult = await PublishTranscodeEvent(request.UserId, trackEntity, cancellationToken);
if (!publishTranscodeResult.IsSuccess)
try
{
await eventBus.PublishAsync(
new CreateTrackResourcesEvent(
trackEntity.Id,
pictureIntent.Id,
audioIntent.Id,
storageConfiguration.Bucket,
pictureIntent.Key,
finalPictureKey,
audioIntent.Key,
finalAudioKey,
audioProcessedFolderKey,
new ImageSize(
trackConfiguration.Routes.SmallPicturesPath,
trackConfiguration.PicturesSizes.SmallPictureWidth,
trackConfiguration.PicturesSizes.SmallPictureHeight),
new ImageSize(
trackConfiguration.Routes.MediumPicturesPath,
trackConfiguration.PicturesSizes.MediumPictureWidth,
trackConfiguration.PicturesSizes.MediumPictureHeight),
new ImageSize(
trackConfiguration.Routes.LargePicturesPath,
trackConfiguration.PicturesSizes.LargePictureWidth,
trackConfiguration.PicturesSizes.LargePictureHeight)),
cancellationToken);
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to publish create track event for track {TrackId}", trackEntity.Id);
return Result.Error($"Failed to create track for {request.Title}");
}
try
{
@@ -101,55 +112,5 @@ namespace Musify.Application.Tracks.Handler
return Result.Created(TrackApplicationResponse.FromEntity(trackEntity));
}
async Task<Result> PublishUpdateEvent(Guid userId, Track track, CancellationToken cancellationToken)
{
try
{
await eventBus.PublishAsync(new UpdateTrackPictureEvent(
track.Id,
storageConfiguration.Bucket,
trackConfiguration.Routes.BuildOriginalPicturePath(userId, track.OriginalPictureName),
new ImageSize(
trackConfiguration.Routes.SmallPicturesPath,
trackConfiguration.PicturesSizes.SmallPictureWidth,
trackConfiguration.PicturesSizes.SmallPictureHeight),
new ImageSize(
trackConfiguration.Routes.MediumPicturesPath,
trackConfiguration.PicturesSizes.MediumPictureWidth,
trackConfiguration.PicturesSizes.MediumPictureHeight),
new ImageSize(
trackConfiguration.Routes.LargePicturesPath,
trackConfiguration.PicturesSizes.LargePictureWidth,
trackConfiguration.PicturesSizes.LargePictureHeight)), cancellationToken);
return Result.Success();
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to publish track picture update event for track {TrackId}", track.Id);
return Result.Error($"Failed to publish track picture update event for track {track.Id}");
}
}
async Task<Result> PublishTranscodeEvent(Guid userId, Track track, CancellationToken cancellationToken)
{
var destinationFolderAudio = trackConfiguration.Routes.BuildProcessedAudioPath(Guid.NewGuid().ToString());
try
{
await eventBus.PublishAsync(new UpdateTrackAudioEvent(
track.Id,
storageConfiguration.Bucket,
trackConfiguration.Routes.BuildOriginalAudioPath(userId, track.OriginalAudioName),
storageConfiguration.Bucket,
destinationFolderAudio), cancellationToken);
return Result.Success();
}
catch (Exception exception)
{
logger.LogError(exception, "Failed to publish track audio update event for track {TrackId}", track.Id);
return Result.Error($"Failed to publish track audio update event for track {track.Id}");
}
}
}
}