Track mixed catalog fields (Title, Artist credit, Duration) with picture-processing and audio-transcode pipeline state as ten flat columns plus two computed [NotMapped] flags, making the entity read like a media-pipeline worksheet. Introduce TrackPictures and TrackAudio as EF owned types mapped onto the same existing columns (explicit column names, no schema change - verified via `dotnet ef migrations has-pending-model-changes`). Track now reads as Title/Artist/Duration/Pictures/Audio instead of fourteen loose properties.
73 lines
3.1 KiB
C#
73 lines
3.1 KiB
C#
using MassTransit;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Logging;
|
|
using Musify.Application.Contracts;
|
|
using Musify.Domain.Entities;
|
|
using Musify.Domain.ValueObjects;
|
|
using Musify.Infrastructure.MassTransit.Arguments;
|
|
|
|
namespace Musify.Infrastructure.MassTransit.Activities.Audio
|
|
{
|
|
internal class GenerateAudioWorkflowPathsActivity(
|
|
IDatabase database,
|
|
ILogger<GenerateAudioWorkflowPathsActivity> logger)
|
|
: IExecuteActivity<GenerateAudioWorkflowPathsArguments>
|
|
{
|
|
public const string ExecuteEndpointName = "generate-audio-workflow-paths";
|
|
|
|
public async Task<ExecutionResult> Execute(ExecuteContext<GenerateAudioWorkflowPathsArguments> executeContext)
|
|
{
|
|
Track track;
|
|
try
|
|
{
|
|
var getTrack = await database.Tracks.SingleOrDefaultAsync(p => p.Id == executeContext.Arguments.TrackId, executeContext.CancellationToken);
|
|
track = getTrack ?? throw new InvalidOperationException($"Track with id {executeContext.Arguments.TrackId} not found.");
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
logger.LogError(exception, "Failed to retrieve track for TrackId {TrackId}",
|
|
executeContext.Arguments.TrackId);
|
|
throw;
|
|
}
|
|
|
|
try
|
|
{
|
|
track.Audio.TranscodeStatus = ProcessingStatus.Processing;
|
|
var folderName = Guid.NewGuid().ToString();
|
|
var sourceFileName = Path.GetFileName(executeContext.Arguments.SourceKey);
|
|
var workingDirectory = Path.Combine(executeContext.Arguments.TemporaryRootDirectory, folderName);
|
|
var sourceFilePath = Path.Combine(workingDirectory, sourceFileName);
|
|
|
|
Directory.CreateDirectory(workingDirectory);
|
|
await database.SaveChangesAsync(executeContext.CancellationToken);
|
|
|
|
logger.LogDebug("Generated audio workflow paths in {WorkingDirectory}", workingDirectory);
|
|
|
|
return executeContext.CompletedWithVariables(new Dictionary<string, object>
|
|
{
|
|
[RoutingSlipVariableNames.Workflow.TemporalDirectory] = workingDirectory,
|
|
[RoutingSlipVariableNames.Audio.SourceFilePath] = sourceFilePath,
|
|
[RoutingSlipVariableNames.Audio.TranscodedDirectory] = workingDirectory
|
|
} );
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
logger.LogError(exception, "Failed to generate audio workflow paths for {SourceKey}",
|
|
executeContext.Arguments.SourceKey);
|
|
|
|
try
|
|
{
|
|
track.Audio.TranscodeStatus = ProcessingStatus.Failed;
|
|
await database.SaveChangesAsync(executeContext.CancellationToken);
|
|
}
|
|
catch (Exception dbException)
|
|
{
|
|
logger.LogError(dbException, "Failed to update ProcessingStatus to Failed for track {TrackId}",
|
|
executeContext.Arguments.TrackId);
|
|
}
|
|
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
} |