src/Cli/Program.cs
+10
-11
diff --git a/src/Cli/Program.cs b/src/Cli/Program.cs
index 40614ce..aaa93d6 100644
@@ -1,4 +1,5 @@
using System.Threading;
using System;
using System.Threading;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
@@ -18,16 +19,14 @@ builder.Services.AddJellyfinDatabase().AddSlopperDatabase().AddFfmpegServices().
using var app = builder.Build();
await app.StartAsync(CancellationToken.None);
var logger = app.Services.GetRequiredService<ILogger<Program>>();
using var scope = app.Services.CreateScope();
var clipRepository = scope.ServiceProvider.GetRequiredService<IClipRepository>();
var clips = clipRepository.GetLatest();
await foreach (var clip in clips)
{
logger.LogInformation("Clip {ClipId} {Path} {CreatedAt}", clip.Id, clip.Path, clip.CreatedAt);
}
await app.StopAsync(CancellationToken.None);
var clipExtractor = scope.ServiceProvider.GetRequiredService<IClipExtractor>();
await clipExtractor.ExtractClip(
new(Guid.NewGuid(), args[0], new Subtitles.Embedded(3)),
TimeSpan.FromSeconds(11),
TimeSpan.FromSeconds(5),
args[1],
CancellationToken.None
);
src/Infrastructure/Ffmpeg/ClipExtractor.cs
+4
-12
diff --git a/src/Infrastructure/Ffmpeg/ClipExtractor.cs b/src/Infrastructure/Ffmpeg/ClipExtractor.cs
index d44f2a2..ad24f86 100644
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text.RegularExpressions;
@@ -35,7 +34,7 @@ internal sealed partial class ClipExtractor(ILogger<ClipExtractor> logger) : ICl
CancellationToken cancellationToken
)
{
var crops = new Dictionary<Rectangle, int>();
Rectangle? crop = null;
var args = FFMpegArguments
.FromFileInput(media.Path, addArguments: options => options.Seek(start).EndSeek(start + duration))
.OutputToFile(
@@ -46,7 +45,7 @@ internal sealed partial class ClipExtractor(ILogger<ClipExtractor> logger) : ICl
filter
.Add("zscale", "t=linear:npl=100")
.Add("format", "yuv420p")
.Add("cropdetect", "24:2:1")
.Add("cropdetect", "mode=black:limit=24:round=2")
)
.ForceFormat("null")
)
@@ -63,13 +62,13 @@ internal sealed partial class ClipExtractor(ILogger<ClipExtractor> logger) : ICl
{
return;
}
crops.Add(new(x, y, width, height));
crop = new(x, y, width, height);
})
.CancellableThrough(cancellationToken);
using var activity = Tracing.StartCropAreaAnalysis(media.Path, start, duration);
logger.LogInformation("Running ffmpeg {FfmpegArguments}", args.Arguments);
await args.ProcessAsynchronously();
return crops.MaxRectangle;
return crop;
}
[GeneratedRegex(@"crop=(\d+):(\d+):(\d+):(\d+)")]
@@ -162,13 +161,6 @@ internal sealed partial class ClipExtractor(ILogger<ClipExtractor> logger) : ICl
file static class Extensions
{
extension(Dictionary<Rectangle, int> dictionary)
{
public void Add(Rectangle rectangle) => dictionary[rectangle] = dictionary.GetValueOrDefault(rectangle) + 1;
public Rectangle? MaxRectangle => dictionary.Count > 0 ? dictionary.MaxBy(kvp => kvp.Value).Key : null;
}
extension(FFMpegArgumentOptions options)
{
public FFMpegArgumentOptions WithArgument(string argument) =>