79 lines
2.8 KiB
C#
79 lines
2.8 KiB
C#
using Fragalytics.Web.Infrastructure;
|
|
using Fragalytics.Web.Models;
|
|
using Microsoft.Extensions.Options;
|
|
|
|
namespace Fragalytics.Web.Services;
|
|
|
|
public sealed class ClipMediaService
|
|
{
|
|
private readonly JsonAppStore _store;
|
|
private readonly FragalyticsOptions _options;
|
|
|
|
public ClipMediaService(JsonAppStore store, IOptions<FragalyticsOptions> options)
|
|
{
|
|
_store = store;
|
|
_options = options.Value;
|
|
}
|
|
|
|
public async Task<int> AttachClipAssetAsync(
|
|
int clipJobId,
|
|
string fileName,
|
|
string? contentType,
|
|
Stream input,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var extension = Path.GetExtension(fileName);
|
|
if (!ClipMediaFormats.AllowedExtensions.Contains(extension))
|
|
{
|
|
throw new InvalidOperationException($"Only {ClipMediaFormats.Mp4Extension} and {ClipMediaFormats.WebMExtension} clip uploads are supported.");
|
|
}
|
|
|
|
var clipsDirectory = Path.Combine(Path.GetFullPath(_options.DataDirectory), "clips");
|
|
Directory.CreateDirectory(clipsDirectory);
|
|
|
|
var safeFileName = Path.GetFileName(fileName);
|
|
var storedName = $"{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}_{clipJobId}{extension}";
|
|
var storedPath = Path.Combine(clipsDirectory, storedName);
|
|
|
|
long fileSize;
|
|
await using (var output = File.Create(storedPath))
|
|
{
|
|
await input.CopyToAsync(output, cancellationToken);
|
|
fileSize = output.Length;
|
|
}
|
|
|
|
return await _store.UpdateAsync(state =>
|
|
{
|
|
var clipJob = state.ClipJobs.FirstOrDefault(item => item.Id == clipJobId)
|
|
?? throw new InvalidOperationException("Clip job not found.");
|
|
|
|
if (clipJob.ClipAssetId is int existingAssetId)
|
|
{
|
|
var existingAsset = state.ClipAssets.FirstOrDefault(item => item.Id == existingAssetId);
|
|
if (existingAsset is not null && File.Exists(existingAsset.StoredPath))
|
|
{
|
|
File.Delete(existingAsset.StoredPath);
|
|
}
|
|
state.ClipAssets.RemoveAll(item => item.Id == existingAssetId);
|
|
}
|
|
|
|
var asset = new ClipAssetRecord
|
|
{
|
|
Id = state.NextClipAssetId++,
|
|
ClipJobId = clipJobId,
|
|
FileName = safeFileName,
|
|
StoredPath = storedPath,
|
|
ContentType = string.IsNullOrWhiteSpace(contentType) ? ClipMediaFormats.InferContentType(extension) : contentType,
|
|
FileSizeBytes = fileSize
|
|
};
|
|
|
|
state.ClipAssets.Add(asset);
|
|
clipJob.ClipAssetId = asset.Id;
|
|
clipJob.Status = ClipJobStatuses.Rendered;
|
|
clipJob.ErrorMessage = null;
|
|
clipJob.CompletedAtUtc = DateTime.UtcNow;
|
|
return asset.Id;
|
|
}, cancellationToken);
|
|
}
|
|
}
|