Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 1 addition & 17 deletions CompressionTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,14 @@

namespace LiteCut
{
internal class CompressionTask
internal class CompressionTask(string inputFilePath, string outputFilePath, int targetFileSizeMB, TimeSpan startTime, TimeSpan endTime, bool mergeAudio)
{
public EventHandler<double>? CompressionProgress;

public EventHandler<string>? CompressionError;

Check warning on line 10 in CompressionTask.cs

View workflow job for this annotation

GitHub Actions / build

Field 'CompressionTask.CompressionError' is never assigned to, and will always have its default value null

Check warning on line 10 in CompressionTask.cs

View workflow job for this annotation

GitHub Actions / build

Field 'CompressionTask.CompressionError' is never assigned to, and will always have its default value null

public EventHandler<string>? CompressionOutput;

Check warning on line 12 in CompressionTask.cs

View workflow job for this annotation

GitHub Actions / build

Field 'CompressionTask.CompressionOutput' is never assigned to, and will always have its default value null

Check warning on line 12 in CompressionTask.cs

View workflow job for this annotation

GitHub Actions / build

Field 'CompressionTask.CompressionOutput' is never assigned to, and will always have its default value null

private readonly string inputFilePath;
private readonly string outputFilePath;
private readonly int targetFileSizeMB;
private readonly TimeSpan startTime;
private readonly TimeSpan endTime;
private readonly bool mergeAudio;

public CompressionTask(string inputFilePath, string outputFilePath, int targetFileSizeMB, TimeSpan startTime, TimeSpan endTime, bool mergeAudio)
{
this.inputFilePath = inputFilePath;
this.outputFilePath = outputFilePath;
this.targetFileSizeMB = targetFileSizeMB;
this.startTime = startTime;
this.endTime = endTime;
this.mergeAudio = mergeAudio;
}
public async Task CompressVideo()
{
double targetFileSizeBytes = targetFileSizeMB * 1024;
Expand Down
161 changes: 161 additions & 0 deletions FFmpegInstaller.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;

namespace LiteCut
{
public static class FFmpegInstaller
{
public static bool InstallFFmpeg()
{
try
{

ProcessStartInfo startInfo = new()
{
FileName = "winget",
Arguments = "install Gyan.FFmpeg -h",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};

using Process process = new();
process.StartInfo = startInfo;
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();

// Refresh this process' PATH from the registry so newly-installed executables are found without restarting
RefreshProcessPathFromRegistry();

// Quick verification: try running `ffmpeg -version`
if (CanRunFFmpeg())
{
return true;
}

var ffmpegInstallationDirectory = FindFFmpeg();

if (!string.IsNullOrEmpty(ffmpegInstallationDirectory))
{
string dir = Path.GetDirectoryName(ffmpegInstallationDirectory);

Check warning on line 47 in FFmpegInstaller.cs

View workflow job for this annotation

GitHub Actions / build

Converting null literal or possible null value to non-nullable type.

Check warning on line 47 in FFmpegInstaller.cs

View workflow job for this annotation

GitHub Actions / build

Converting null literal or possible null value to non-nullable type.
string current = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process) ?? string.Empty;
Environment.SetEnvironmentVariable("PATH", dir + ";" + current, EnvironmentVariableTarget.Process);

if (!CanRunFFmpeg())
{
MessageBox.Show("FFmpeg was not directly accessbile. You may need to restart LiteCut or your computer.");
return true; // installation likely succeeded, but process PATH wasn't picked up by all mechanisms
}
}
else
{
MessageBox.Show("FFmpeg was installed but could not be located. Try restarting Litecut or your computer.");
return true;
}
}
catch (Exception ex)
{
MessageBox.Show($"Error: {ex.Message}");
return false;
}

return false;
}

private static void RefreshProcessPathFromRegistry()
{
try
{
const string systemEnvKey = @"SYSTEM\CurrentControlSet\Control\Session Manager\Environment";
string systemPath = Registry.LocalMachine.OpenSubKey(systemEnvKey)?.GetValue("Path") as string ?? string.Empty;
string userPath = Registry.CurrentUser.OpenSubKey("Environment")?.GetValue("Path") as string ?? string.Empty;

string merged;
if (string.IsNullOrEmpty(systemPath)) merged = userPath;
else if (string.IsNullOrEmpty(userPath)) merged = systemPath;
else merged = systemPath + ";" + userPath;

if (!string.IsNullOrEmpty(merged))
{
Environment.SetEnvironmentVariable("PATH", merged, EnvironmentVariableTarget.Process);
}
}
catch
{
// Non-fatal — leave process PATH unchanged if registry read fails.
}
}

private static bool CanRunFFmpeg()
{
try
{
ProcessStartInfo psi = new()
{
FileName = "ffmpeg",
Arguments = "-version",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};

using Process p = Process.Start(psi);

Check warning on line 110 in FFmpegInstaller.cs

View workflow job for this annotation

GitHub Actions / build

Converting null literal or possible null value to non-nullable type.

Check warning on line 110 in FFmpegInstaller.cs

View workflow job for this annotation

GitHub Actions / build

Converting null literal or possible null value to non-nullable type.
if (p is null)
{
return false;
}
p.WaitForExit(3000);
return p.ExitCode == 0;
}
catch
{
return false;
}
}


private static string FindFFmpeg()
{
try
{
ProcessStartInfo psi = new()
{
FileName = "where",
Arguments = "ffmpeg",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};

using Process p = Process.Start(psi);

Check warning on line 139 in FFmpegInstaller.cs

View workflow job for this annotation

GitHub Actions / build

Converting null literal or possible null value to non-nullable type.

Check warning on line 139 in FFmpegInstaller.cs

View workflow job for this annotation

GitHub Actions / build

Converting null literal or possible null value to non-nullable type.
if (p == null) return string.Empty;

string output = p.StandardOutput.ReadToEnd();
p.WaitForExit(2000);

if (string.IsNullOrWhiteSpace(output)) return string.Empty;

var lines = output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var path = line.Trim();
if (File.Exists(path)) return path;
}
}
catch
{
}

return string.Empty;
}
}
}
6 changes: 2 additions & 4 deletions FileAssociation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ public static void AssociateFile()
var applicationInfo = new ApplicationInfo("LiteCut", "LiteCut", "LiteCut", Application.ExecutablePath);
applicationInfo.SupportedExtensions.Add(".mp4");

IApplicationRegistrationService registrationService = new ApplicationRegistrationService();

var registrationService = new ApplicationRegistrationService();
registrationService.RegisterApplication(applicationInfo);

}
}
}
}
47 changes: 0 additions & 47 deletions InstallFFmpeg.cs

This file was deleted.

8 changes: 4 additions & 4 deletions LiteCut.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ public LiteCut(string[] args)
{
FFMpeg.GetCodecs();
}
catch
catch (Exception e)
{
DialogResult result = MessageBox.Show("FFMpeg is not installed, or has no codecs. Do you want to try to install it now?", "error", MessageBoxButtons.YesNo);
DialogResult result = MessageBox.Show($"Error retrieving FFmpeg codecs: \n {e.Message} \n\n This usually happens when FFmpeg is not installed. Do you want to try to install it now?", "error", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
{
var installResult = InstallFFmpeg.installFFmpeg();
var installResult = FFmpegInstaller.InstallFFmpeg();
if (installResult == true)
{
MessageBox.Show("Successfully installed FFMpeg!");
Expand Down Expand Up @@ -88,7 +88,7 @@ private async void CompressButton_Click(object sender, EventArgs e)
var endTime = TimeSpan.FromSeconds((double)EndTimeBox.Value);
var mergeAudio = MergeAudioTrackCheckBox.Checked;

CompressionTask compression = new CompressionTask(fileName, fileName + "_compressed.mp4", size, startTime, endTime, mergeAudio );
var compression = new CompressionTask(fileName, fileName + "_compressed.mp4", size, startTime, endTime, mergeAudio );
compression.CompressionProgress += (sender, progress) =>
{
if (ProgressBar.InvokeRequired)
Expand Down