mirror of
https://github.com/unclshura/splitter.git
synced 2026-06-21 16:12:01 +00:00
Logger is a non static class now. Interface extracted
This commit is contained in:
parent
78f1bb17d6
commit
14bcd31efe
13
ILogger.cs
Normal file
13
ILogger.cs
Normal file
@ -0,0 +1,13 @@
|
||||
namespace splitter;
|
||||
|
||||
public interface ILogger
|
||||
{
|
||||
void ClearProgress(int progressLevel);
|
||||
void DrawProgress(string name, int progressLine, double progress, TimeSpan eta, double speed);
|
||||
void Log(string prefix, ConsoleColor color, string msg);
|
||||
|
||||
void LogInfo(string msg) => Log("[INFO]", ConsoleColor.Cyan, msg);
|
||||
void LogSuccess(string msg) => Log("[ OK ]", ConsoleColor.Green, msg);
|
||||
void LogWarn(string msg) => Log("[WARN]", ConsoleColor.Yellow, msg);
|
||||
void LogError(string msg) => Log("[ERR ]", ConsoleColor.Red, msg);
|
||||
}
|
||||
39
Logger.cs
39
Logger.cs
@ -1,17 +1,15 @@
|
||||
namespace splitter;
|
||||
|
||||
public static class Logger
|
||||
public class Logger(CommandLine cmd) : ILogger
|
||||
{
|
||||
static int _logLines = 0;
|
||||
static readonly object _consoleLock = new();
|
||||
int _logLines = Math.Max(1, Environment.ProcessorCount / 2) * 2;
|
||||
readonly object _consoleLock = new();
|
||||
|
||||
public static bool PlainText { get; set; }
|
||||
|
||||
public static void Log(string prefix, ConsoleColor color, string msg)
|
||||
public void Log(string prefix, ConsoleColor color, string msg)
|
||||
{
|
||||
lock (_consoleLock)
|
||||
{
|
||||
if (PlainText)
|
||||
if (cmd.PlainText)
|
||||
{
|
||||
Console.WriteLine($"{prefix} {msg}");
|
||||
}
|
||||
@ -21,27 +19,22 @@ public static class Logger
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Cyan;
|
||||
Console.Write($"{prefix} ");
|
||||
|
||||
|
||||
Console.ForegroundColor = color;
|
||||
Console.WriteLine(msg);
|
||||
|
||||
Console.ResetColor();
|
||||
|
||||
|
||||
_logLines++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void LogInfo(string msg) => Log("[INFO]", ConsoleColor.Cyan, msg);
|
||||
public static void LogSuccess(string msg) => Log("[ OK ]", ConsoleColor.Green, msg);
|
||||
public static void LogWarn(string msg) => Log("[WARN]", ConsoleColor.Yellow, msg);
|
||||
public static void LogError(string msg) => Log("[ERR ]", ConsoleColor.Red, msg);
|
||||
private readonly Dictionary<int, int> _progressTrack = new();
|
||||
|
||||
private static readonly Dictionary<int, int> _progressTrack = new();
|
||||
|
||||
public static void DrawProgress(string name, int progressLevel, double progress, TimeSpan eta, double speed)
|
||||
public void DrawProgress(string name, int progressLine, double progress, TimeSpan eta, double speed)
|
||||
{
|
||||
if (PlainText || progressLevel < 0)
|
||||
if (cmd.PlainText || progressLine < 0)
|
||||
return;
|
||||
|
||||
// Crop name to max 20 chars
|
||||
@ -60,17 +53,17 @@ public static class Logger
|
||||
if (filled > barWidth) filled = barWidth;
|
||||
|
||||
// --- NEW: skip drawing if visually unchanged ---
|
||||
if (_progressTrack.TryGetValue(progressLevel, out var lastFilled) &&
|
||||
if (_progressTrack.TryGetValue(progressLine, out var lastFilled) &&
|
||||
lastFilled == filled)
|
||||
{
|
||||
return; // no visual change → skip
|
||||
}
|
||||
|
||||
_progressTrack[progressLevel] = filled;
|
||||
_progressTrack[progressLine] = filled;
|
||||
// ------------------------------------------------
|
||||
|
||||
var barLine = _logLines + 1 + progressLevel * 2;
|
||||
var infoLine = _logLines + 2 + progressLevel * 2;
|
||||
var barLine = _logLines + 1 + progressLine * 2;
|
||||
var infoLine = _logLines + 2 + progressLine * 2;
|
||||
|
||||
// Draw progress bar
|
||||
Console.SetCursorPosition(0, barLine);
|
||||
@ -101,9 +94,9 @@ public static class Logger
|
||||
}
|
||||
|
||||
|
||||
public static void ClearProgress(int progressLevel)
|
||||
public void ClearProgress(int progressLevel)
|
||||
{
|
||||
if (PlainText || progressLevel < 0)
|
||||
if (cmd.PlainText || progressLevel < 0)
|
||||
return;
|
||||
|
||||
lock (_consoleLock)
|
||||
|
||||
@ -1,23 +1,23 @@
|
||||
using System;
|
||||
namespace splitter;
|
||||
|
||||
public abstract class LoggingBase(int progressLine)
|
||||
public abstract class LoggingBase(ILogger _logger, int _progressLine)
|
||||
{
|
||||
protected void Log(string level, ConsoleColor color, string message)
|
||||
=> Logger.Log(level, color, message);
|
||||
=> _logger.Log(level, color, message);
|
||||
|
||||
protected void LogInfo(string message)
|
||||
=> Logger.LogInfo(message);
|
||||
=> _logger.LogInfo(message);
|
||||
|
||||
protected void LogWarn(string message)
|
||||
=> Logger.LogWarn(message);
|
||||
=> _logger.LogWarn(message);
|
||||
|
||||
protected void LogError(string message)
|
||||
=> Logger.LogError(message);
|
||||
=> _logger.LogError(message);
|
||||
|
||||
protected void DrawProgress(string name, double percent, TimeSpan eta, double fps)
|
||||
=> Logger.DrawProgress(name, progressLine, percent, eta, fps);
|
||||
=> _logger.DrawProgress(name, _progressLine, percent, eta, fps);
|
||||
|
||||
protected void ClearProgress()
|
||||
=> Logger.ClearProgress(progressLine);
|
||||
=> _logger.ClearProgress(_progressLine);
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ using FFmpeg.AutoGen;
|
||||
|
||||
namespace splitter;
|
||||
|
||||
public class SimpleSplitter(int segmentNo) : LoggingBase(segmentNo), ISegmentProcessor
|
||||
public class SimpleSplitter(int segmentNo, ILogger logger) : LoggingBase(logger, segmentNo), ISegmentProcessor
|
||||
{
|
||||
public async Task ProcessSegment(string inputFile, string outputFile, double start, double length, string[] passthrough)
|
||||
{
|
||||
|
||||
@ -18,8 +18,8 @@ public class TrackingSplitter : LoggingBase, ISegmentProcessor, IDisposable
|
||||
private readonly IObjectDetector _detector;
|
||||
private readonly CommandLine _cmd;
|
||||
|
||||
public TrackingSplitter(int segmentNo, int cropWidth, int cropHeight, bool debugOverlay, bool plainText, IObjectDetector detector, CommandLine cmd)
|
||||
: base(segmentNo)
|
||||
public TrackingSplitter(int segmentNo, int cropWidth, int cropHeight, bool debugOverlay, bool plainText, IObjectDetector detector, CommandLine cmd, ILogger logger)
|
||||
: base(logger, segmentNo)
|
||||
{
|
||||
_segmentNo = segmentNo;
|
||||
_cropWidth = cropWidth;
|
||||
|
||||
@ -9,7 +9,7 @@ public sealed class UltraFaceDetector: LoggingBase, IDisposable, IObjectDetector
|
||||
{
|
||||
private readonly UltraFace _ultraFace;
|
||||
|
||||
public UltraFaceDetector() : base(-1)
|
||||
public UltraFaceDetector(ILogger logger) : base(logger, -1)
|
||||
{
|
||||
var basePath = AppDomain.CurrentDomain.BaseDirectory;
|
||||
var param = new UltraFaceParameter
|
||||
|
||||
@ -59,7 +59,7 @@ public sealed class YoloOnnxObjectDetector : LoggingBase, IObjectDetector, IDisp
|
||||
}
|
||||
}
|
||||
|
||||
public YoloOnnxObjectDetector() : base(-1)
|
||||
public YoloOnnxObjectDetector(ILogger logger) : base(logger, -1)
|
||||
{
|
||||
var options = new SessionOptions();
|
||||
options.AppendExecutionProvider_DML();
|
||||
|
||||
61
splitter.cs
61
splitter.cs
@ -5,49 +5,38 @@ using splitter;
|
||||
|
||||
static class Program
|
||||
{
|
||||
private static ILogger _logger = null!;
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
var cmd = new CommandLine(args);
|
||||
|
||||
var estimateOnly = cmd.EstimateOnly;
|
||||
var forceFixed = cmd.ForceFixed;
|
||||
var passthrough = cmd.Passthrough;
|
||||
var inputFile = cmd.InputFile;
|
||||
var outputFolder = cmd.OutputFolder;
|
||||
(int width, int height)? crop = cmd.Crop;
|
||||
string? mask = cmd.Mask;
|
||||
var debug = cmd.Debug;
|
||||
string? detect = cmd.Detect;
|
||||
double? overrideTargetDuration = cmd.OverrideTargetDuration;
|
||||
Logger.PlainText = cmd.PlainText;
|
||||
|
||||
if (!File.Exists(inputFile))
|
||||
_logger = new Logger(cmd);
|
||||
|
||||
if (!File.Exists(cmd.InputFile))
|
||||
{
|
||||
LogError("Input file not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(outputFolder))
|
||||
Directory.CreateDirectory(outputFolder);
|
||||
|
||||
var baseName = Path.GetFileNameWithoutExtension(inputFile);
|
||||
var outputMask = mask ?? $"{baseName}_Seg%03d.mp4";
|
||||
if (!Directory.Exists(cmd.OutputFolder))
|
||||
Directory.CreateDirectory(cmd.OutputFolder);
|
||||
|
||||
var baseName = Path.GetFileNameWithoutExtension(cmd.InputFile);
|
||||
var outputMask = cmd.Mask ?? $"{baseName}_Seg%03d.mp4";
|
||||
LogInfo("Reading duration via ffprobe...");
|
||||
|
||||
var duration = GetDuration(inputFile);
|
||||
var duration = GetDuration(cmd.InputFile);
|
||||
if (duration <= 0)
|
||||
{
|
||||
LogError("Could not read duration.");
|
||||
return;
|
||||
}
|
||||
|
||||
var target = overrideTargetDuration ?? 58.0;
|
||||
var target = cmd.OverrideTargetDuration ?? 58.0;
|
||||
|
||||
int segments;
|
||||
double segmentLength;
|
||||
|
||||
if (forceFixed)
|
||||
if (cmd.ForceFixed)
|
||||
{
|
||||
// Fixed chunk size, last one may be shorter
|
||||
segments = (int)Math.Ceiling(duration / target);
|
||||
@ -60,13 +49,13 @@ static class Program
|
||||
segmentLength = duration / segments;
|
||||
}
|
||||
|
||||
if (estimateOnly)
|
||||
if (cmd.EstimateOnly)
|
||||
{
|
||||
LogInfo("=== ESTIMATE MODE ===");
|
||||
LogInfo($"Total duration: {duration:F2}s");
|
||||
LogInfo($"Target duration: {target:F2}s");
|
||||
LogInfo($"Segments: {segments}");
|
||||
LogInfo(forceFixed
|
||||
LogInfo(cmd.ForceFixed
|
||||
? $"Fixed segment length: {segmentLength:F2}s (last may be shorter)"
|
||||
: $"Equalized segment length: {segmentLength:F2}s");
|
||||
return;
|
||||
@ -77,45 +66,45 @@ static class Program
|
||||
LogInfo($"Equal segment length: {segmentLength:F3}s");
|
||||
|
||||
Func<int, ISegmentProcessor> processorFactory;
|
||||
if (crop != null)
|
||||
if (cmd.Crop != null)
|
||||
{
|
||||
processorFactory = i =>
|
||||
{
|
||||
IObjectDetector detector = detect switch
|
||||
IObjectDetector detector = cmd.Detect switch
|
||||
{
|
||||
"face" => new UltraFaceDetector(),
|
||||
"body" => new YoloOnnxObjectDetector(),
|
||||
_ => throw new InvalidOperationException($"Unknown detector: {detect}")
|
||||
"face" => new UltraFaceDetector(_logger),
|
||||
"body" => new YoloOnnxObjectDetector(_logger),
|
||||
_ => throw new InvalidOperationException($"Unknown detector: {cmd.Detect}")
|
||||
};
|
||||
return new TrackingSplitter(i, crop.Value.width, crop.Value.height, debug, cmd.PlainText, detector, cmd);
|
||||
return new TrackingSplitter(i, cmd.Crop.Value.width, cmd.Crop.Value.height, cmd.Debug, cmd.PlainText, detector, cmd, _logger);
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
processorFactory = i => new SimpleSplitter(i);
|
||||
processorFactory = i => new SimpleSplitter(i, _logger);
|
||||
}
|
||||
if (cmd.SingleThreaded)
|
||||
{
|
||||
LogInfo("Starting single-threaded splitting...");
|
||||
await RunSingleThreaded(processorFactory, inputFile, outputFolder, outputMask, duration, segments, segmentLength, passthrough);
|
||||
await RunSingleThreaded(processorFactory, cmd.InputFile, cmd.OutputFolder, outputMask, duration, segments, segmentLength, cmd.Passthrough);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogInfo("Starting multi-threaded splitting...");
|
||||
await RunMultiThreaded(processorFactory, inputFile, outputFolder, outputMask, duration, segments, segmentLength, passthrough);
|
||||
await RunMultiThreaded(processorFactory, cmd.InputFile, cmd.OutputFolder, outputMask, duration, segments, segmentLength, cmd.Passthrough);
|
||||
}
|
||||
|
||||
LogInfo("Done.");
|
||||
}
|
||||
|
||||
private static void LogInfo(string message)
|
||||
=> Logger.LogInfo(message);
|
||||
=> _logger.LogInfo(message);
|
||||
|
||||
private static void LogWarn(string message)
|
||||
=> Logger.LogWarn(message);
|
||||
=> _logger.LogWarn(message);
|
||||
|
||||
private static void LogError(string message)
|
||||
=> Logger.LogError(message);
|
||||
=> _logger.LogError(message);
|
||||
|
||||
// -----------------------------
|
||||
// ffprobe
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user