Skip to content

Commit

Permalink
feat: implemented mass-converting
Browse files Browse the repository at this point in the history
  • Loading branch information
massimo-rnd authored Jan 28, 2025
2 parents 0507aa2 + e1a46da commit dceaece
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 153 deletions.
311 changes: 168 additions & 143 deletions FFMP.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,74 +12,73 @@
class FFMP
{
static void Main(string[] args)
{
try
{
Console.WriteLine("Starting application...");
try
{
Console.WriteLine("Starting application...");

// Split args into application and FFmpeg arguments
var appArgs = args.TakeWhile(arg => arg != "--").ToArray();
var ffmpegArgs = args.SkipWhile(arg => arg != "--").Skip(1).ToArray();
// Split args into application and FFmpeg arguments
var appArgs = args.TakeWhile(arg => arg != "--").ToArray();
var ffmpegArgs = args.SkipWhile(arg => arg != "--").Skip(1).ToArray();

if (!appArgs.Any())
{
Console.WriteLine("Error: No arguments provided. Please specify required arguments.");
Environment.Exit(1);
}
if (!appArgs.Any())
{
Console.WriteLine("Error: No arguments provided. Please specify required arguments.");
Environment.Exit(1);
}

Console.CancelKeyPress += (sender, e) =>
{
Console.WriteLine("Terminating processes...");
foreach (var process in TrackedProcesses.ToList())
Console.CancelKeyPress += (sender, e) =>
{
try
Console.WriteLine("Terminating processes...");
foreach (var process in TrackedProcesses.ToList())
{
if (process != null && !process.HasExited)
try
{
process.Kill();
Console.WriteLine($"Terminated FFmpeg process with ID {process.Id}");
if (process != null && !process.HasExited)
{
process.Kill();
Console.WriteLine($"Terminated FFmpeg process with ID {process.Id}");
}
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"Process already terminated or invalid: {ex.Message}");
}
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"Process already terminated or invalid: {ex.Message}");
}
}

e.Cancel = true;
Environment.Exit(0);
};
e.Cancel = true;
Environment.Exit(0);
};

Parser.Default.ParseArguments<Options>(appArgs)
.WithParsed(options =>
{
if (ValidateOptions(options))
{
Run(options, ffmpegArgs).Wait();
}
else
Parser.Default.ParseArguments<Options>(appArgs)
.WithParsed(options =>
{
Environment.Exit(1);
}
})
.WithNotParsed(errors =>
{
Console.WriteLine("Failed to parse arguments.");
foreach (var error in errors)
if (ValidateOptions(options))
{
Run(options, ffmpegArgs).Wait();
}
else
{
Environment.Exit(1);
}
})
.WithNotParsed(errors =>
{
Console.WriteLine(error.ToString());
}
Console.WriteLine("Failed to parse arguments.");
foreach (var error in errors)
{
Console.WriteLine(error.ToString());
}

Environment.Exit(1);
});
}
catch (Exception ex)
{
Console.WriteLine($"Fatal error: {ex.Message}");
Console.WriteLine(ex.StackTrace);
Environment.Exit(1);
});
}
catch (Exception ex)
{
Console.WriteLine($"Fatal error: {ex.Message}");
Console.WriteLine(ex.StackTrace);
}
}
}


private static readonly ConcurrentBag<Process> TrackedProcesses = new ConcurrentBag<Process>();

Expand Down Expand Up @@ -113,6 +112,8 @@ static async Task Run(Options options, string[] ffmpegArgs)
try
{
Console.WriteLine($"Processing file: {inputFile}");

// Call the ProcessFile method
await ProcessFile(inputFile, options, ffmpegArgs, progress, inputFiles.Count);
}
catch (Exception ex)
Expand All @@ -136,7 +137,6 @@ static async Task Run(Options options, string[] ffmpegArgs)
}
}


static IEnumerable<string> GetInputFiles(Options options)
{
try
Expand Down Expand Up @@ -191,113 +191,124 @@ static IEnumerable<string> GetInputFiles(Options options)
return Enumerable.Empty<string>();
}

static async Task ProcessFile(string inputFile, Options options, string[] ffmpegArgs, ProgressBar progress, int totalFiles)
{
var outputFile = GenerateOutputFilePath(inputFile, options.OutputPattern);

if (string.IsNullOrEmpty(Path.GetDirectoryName(outputFile)))
static async Task ProcessFile(string inputFile, Options options, string[] ffmpegArgs, ProgressBar progress,
int totalFiles)
{
outputFile = Path.Combine(Path.GetDirectoryName(inputFile)!, outputFile);
}

Directory.CreateDirectory(Path.GetDirectoryName(outputFile)!);
string outputFile;

if (File.Exists(outputFile) && !options.Overwrite)
{
Console.WriteLine($"Skipping {inputFile}, output already exists.");
return;
}
// Determine output file for conversion
if (options.Convert)
{
var targetExtension = options.OutputFormat ?? ".mkv"; // Default to MKV if not provided
var baseFileName = Path.Combine(Path.GetDirectoryName(inputFile)!,
Path.GetFileNameWithoutExtension(inputFile));
outputFile = $"{baseFileName}{targetExtension}";
}
else
{
outputFile = GenerateOutputFilePath(inputFile, options.OutputPattern);
}

// Build FFmpeg arguments
var arguments = $"-i \"{Path.GetFullPath(inputFile)}\" -c:v {options.Codec}";
if (!string.IsNullOrEmpty(options.Preset))
{
arguments += $" -preset {options.Preset}";
}
// Ensure output directory exists
Directory.CreateDirectory(Path.GetDirectoryName(outputFile)!);

// Append FFmpeg-specific arguments
if (ffmpegArgs.Any())
{
arguments += $" {string.Join(" ", ffmpegArgs)}";
}
if (File.Exists(outputFile) && !options.Overwrite)
{
Console.WriteLine($"Skipping {inputFile}, output already exists.");
return;
}

arguments += $" \"{Path.GetFullPath(outputFile)}\"";
// Build FFmpeg arguments
var arguments = $"-i \"{Path.GetFullPath(inputFile)}\"";
if (options.Convert)
{
arguments += $" \"{outputFile}\"";
}
else
{
arguments += $" -c:v {options.Codec}";
if (!string.IsNullOrEmpty(options.Preset))
{
arguments += $" -preset {options.Preset}";
}

if (!options.Verbose)
{
arguments = $"-loglevel error {arguments}";
}
if (ffmpegArgs.Any())
{
arguments += $" {string.Join(" ", ffmpegArgs)}";
}

//Console.WriteLine($"Executing FFmpeg command: ffmpeg {arguments}");
arguments += $" \"{Path.GetFullPath(outputFile)}\"";
}

var process = new Process
{
StartInfo = new ProcessStartInfo
// Set log level based on verbose mode
if (options.Verbose)
{
FileName = "ffmpeg",
Arguments = arguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
UseShellExecute = false,
CreateNoWindow = true
arguments = $"-loglevel verbose {arguments}";
}
};

try
{
process.Start();
TrackedProcesses.Add(process);

if (options.Overwrite)
else
{
await process.StandardInput.WriteLineAsync("Y");
await process.StandardInput.FlushAsync();
arguments = $"-loglevel error {arguments}";
}

if (options.Verbose)
var process = new Process
{
var outputTask = Task.Run(() =>
StartInfo = new ProcessStartInfo
{
while (!process.StandardOutput.EndOfStream)
{
Console.WriteLine(process.StandardOutput.ReadLine());
}
});
FileName = "ffmpeg",
Arguments = arguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
}
};

try
{
process.Start();

var errorTask = Task.Run(() =>
// Capture and display output in verbose mode
if (options.Verbose)
{
while (!process.StandardError.EndOfStream)
var outputTask = Task.Run(() =>
{
Console.WriteLine(process.StandardError.ReadLine());
}
});
while (!process.StandardOutput.EndOfStream)
{
Console.WriteLine(process.StandardOutput.ReadLine());
}
});

await Task.WhenAll(outputTask, errorTask);
}
var errorTask = Task.Run(() =>
{
while (!process.StandardError.EndOfStream)
{
Console.WriteLine(process.StandardError.ReadLine());
}
});

await process.WaitForExitAsync();
await Task.WhenAll(outputTask, errorTask);
}
else
{
// Wait silently for process to finish
await process.WaitForExitAsync();
}

if (process.ExitCode == 0)
{
Console.WriteLine($"FFmpeg process completed successfully for file: {inputFile}");
progress.Report(1.0 / totalFiles);
if (process.ExitCode == 0)
{
Console.WriteLine($"FFmpeg process completed successfully for file: {inputFile}");
progress.Report(1.0 / totalFiles);
}
else
{
Console.WriteLine($"FFmpeg process exited with code {process.ExitCode} for file: {inputFile}");
}
}
else
catch (Exception ex)
{
Console.WriteLine($"FFmpeg process exited with code {process.ExitCode}");
Console.WriteLine($"Error executing FFmpeg for file {inputFile}: {ex.Message}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error executing FFmpeg: {ex.Message}");
}
finally
{
TrackedProcesses.TryTake(out process);
}
}


static string GenerateOutputFilePath(string inputFile, string pattern)
{
Expand All @@ -322,18 +333,32 @@ private static bool ValidateOptions(Options options)
{
bool isValid = true;

if (string.IsNullOrWhiteSpace(options.Codec))
if (options.Convert)
{
Console.WriteLine("Error: The 'codec' argument is required.");
isValid = false;
// Ensure required fields for conversion
if (string.IsNullOrWhiteSpace(options.OutputFormat))
{
Console.WriteLine("Error: The 'output-format' argument is required when using '--convert'.");
isValid = false;
}
}

if (string.IsNullOrWhiteSpace(options.OutputPattern))
else
{
Console.WriteLine("Error: The 'output-pattern' argument is required.");
isValid = false;
// Ensure required fields for transcoding
if (string.IsNullOrWhiteSpace(options.Codec))
{
Console.WriteLine("Error: The 'codec' argument is required.");
isValid = false;
}

if (string.IsNullOrWhiteSpace(options.OutputPattern))
{
Console.WriteLine("Error: The 'output-pattern' argument is required.");
isValid = false;
}
}

// Common validation for both modes
if (string.IsNullOrWhiteSpace(options.InputDirectory) && string.IsNullOrWhiteSpace(options.InputFile))
{
Console.WriteLine("Error: Either 'directory' or 'file' argument must be provided for input.");
Expand Down
Loading

0 comments on commit dceaece

Please sign in to comment.