From fd6b3ffdf233c8e3cbd793632f4bd1c9308cde15 Mon Sep 17 00:00:00 2001 From: Tomuxs Date: Tue, 20 May 2025 03:59:39 +0200 Subject: [PATCH] Added conversion option --- Download.Designer.cs | 3 +- Download.cs | 45 +++++++++++++--- FFmpeg.cs | 123 ++++++++++++++++++++++++++++++++++++++++++- Main.Designer.cs | 3 +- Main.cs | 19 ++++++- 5 files changed, 183 insertions(+), 10 deletions(-) diff --git a/Download.Designer.cs b/Download.Designer.cs index 6787653..015ef4c 100644 --- a/Download.Designer.cs +++ b/Download.Designer.cs @@ -70,7 +70,8 @@ this.Controls.Add(this.lblStatus); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; this.Name = "Download"; - this.Text = "Download"; + this.Text = "Downloading"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Download_FormClosing); this.Load += new System.EventHandler(this.Download_Load); this.ResumeLayout(false); this.PerformLayout(); diff --git a/Download.cs b/Download.cs index 258e772..04c69e9 100644 --- a/Download.cs +++ b/Download.cs @@ -5,6 +5,7 @@ using System.Data; using System.Drawing; using System.IO; using System.Linq; +using System.Runtime.Remoting.Contexts; using System.Security.AccessControl; using System.Security.Policy; using System.Text; @@ -16,10 +17,11 @@ namespace ytdlp_gui { public partial class Download : Form { - public Download(YTdlpProcess process, string workdir) + public Download(YTdlpProcess process, string workdir, string convert_to) { this.process = process; this.workdir = workdir; + this.convert_to = convert_to; InitializeComponent(); } @@ -60,14 +62,37 @@ namespace ytdlp_gui if (File.Exists(newFilePath)) System.IO.File.Delete(newFilePath); - System.IO.File.Move(filePath, newFilePath); - System.IO.File.SetLastWriteTime(newFilePath, DateTime.Now); + if (convert_to == null || Path.GetExtension(filePath) == convert_to) + { + System.IO.File.Move(filePath, newFilePath); + System.IO.File.SetLastWriteTime(newFilePath, DateTime.Now); + this.Close(); + } + else + { + newFilePath = Path.ChangeExtension(newFilePath, convert_to); + convertion = (new FFmpeg()).Convert(filePath, newFilePath); - this.Close(); + convertion.Progress += (_ffmpeg, progress_event) => + { + int progress = (int)(progress_event.progress * 100 + 0.5); + this.Text = "Converting - " + progress.ToString() + "%"; + lblStatus.Text = "Converting to " + convert_to; + progressBar.Value = progress; + }; + + convertion.Finished += (_ffmpeg, _ffmpeg_e) => + { + System.IO.File.Delete(filePath); + this.Close(); + }; + + convertion.Run().ContinueWith(t => { MessageBox.Show(t.Exception.ToString(), "Error"); }, TaskContinuationOptions.OnlyOnFaulted); ; + } }; // Can run in background :) - _ = process.Run(); + process.Run().ContinueWith(t => { MessageBox.Show(t.Exception.ToString(), "Error"); }, TaskContinuationOptions.OnlyOnFaulted); } private void btnCancel_Click(object sender, EventArgs e) @@ -75,7 +100,15 @@ namespace ytdlp_gui this.Close(); } - protected readonly string workdir; + private void Download_FormClosing(object sender, FormClosingEventArgs e) + { + if (convertion != null) + convertion.Cancel(); + } + protected readonly YTdlpProcess process; + protected FFmpegProcess convertion; + protected readonly string workdir; + protected readonly string convert_to; } } diff --git a/FFmpeg.cs b/FFmpeg.cs index 3e6ec34..ecd7411 100644 --- a/FFmpeg.cs +++ b/FFmpeg.cs @@ -1,12 +1,133 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; using System.Linq; +using System.Security.Policy; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace ytdlp_gui { - internal class FFmpeg + public class FFmpegProgressEventArgs : EventArgs { + public FFmpegProgressEventArgs(float progress) + { + this.progress = progress; + } + + public readonly float progress; + } + + public class FFmpegProcess + { + public FFmpegProcess(Process process, string output_file) + { + this.process = process; + this.output_file = output_file; + ci = (CultureInfo)CultureInfo.CurrentCulture.Clone(); + ci.NumberFormat.CurrencyDecimalSeparator = "."; + + this.header_regex = new Regex(@"Duration: (\d+):(\d+):(\d+)\.(\d+)"); + this.progress_regex = new Regex(@"time=(\d+):(\d+):(\d+)\.(\d+)"); + } + + ~FFmpegProcess() + { + Cancel(); + } + + public async Task Run() + { + if (File.Exists(output_file)) + System.IO.File.Delete(output_file); + process.Start(); + + int duration = 0; + int progress = 0; + string line = null; + while ((line = await process.StandardError.ReadLineAsync()) != null) + { + Match match; + + match = header_regex.Match(line); + if (match.Success) + { + GroupCollection groups = match.Groups; + duration = + int.Parse(groups[1].Value) * 3600 + + int.Parse(groups[2].Value) * 60 + + int.Parse(groups[3].Value); + } + + match = progress_regex.Match(line); + if (match.Success) + { + GroupCollection groups = match.Groups; + progress = + int.Parse(groups[1].Value) * 3600 + + int.Parse(groups[2].Value) * 60 + + int.Parse(groups[3].Value); + + Progress?.Invoke(this, new FFmpegProgressEventArgs((float)progress / duration)); + } + } + + process.WaitForExit(); + process.Close(); + Finished?.Invoke(this, new EventArgs()); + + return null; + } + + public void Cancel() + { + bool finished = true; + try // to kill the process before deleting the file + { + finished = process.HasExited; + process.Kill(); + process.WaitForExit(); + process.Close(); + } + catch { } + // if (!finished && File.Exists(output_file)) + // System.IO.File.Delete(output_file); + } + + private readonly Process process; + private readonly string output_file; + private readonly CultureInfo ci; + private readonly Regex header_regex; + private readonly Regex progress_regex; + public event EventHandler Progress; + public event EventHandler Finished; + } + + public class FFmpeg : Program + { + public FFmpeg() : base("ffmpeg") + { + } + + public FFmpegProcess Convert(string from, string to) + { + Process process = new Process(); + process.StartInfo.FileName = program; + process.StartInfo.Arguments = String.Format( + "-i \"{0}\" \"{1}\"", + from.Replace("\"", "\"\"\""), + to.Replace("\"", "\"\"\"") + ); + + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + + return new FFmpegProcess(process, to); + } } } diff --git a/Main.Designer.cs b/Main.Designer.cs index 0197991..d04cda3 100644 --- a/Main.Designer.cs +++ b/Main.Designer.cs @@ -117,7 +117,6 @@ this.groupBox2.Controls.Add(this.label3); this.groupBox2.Controls.Add(this.comboConvertFormat); this.groupBox2.Controls.Add(this.checkConvert); - this.groupBox2.Enabled = false; this.groupBox2.Location = new System.Drawing.Point(397, 58); this.groupBox2.Name = "groupBox2"; this.groupBox2.Size = new System.Drawing.Size(391, 108); @@ -157,6 +156,7 @@ this.checkConvert.TabIndex = 0; this.checkConvert.Text = "Convert"; this.checkConvert.UseVisualStyleBackColor = true; + this.checkConvert.CheckedChanged += new System.EventHandler(this.checkConvert_CheckedChanged); // // btnDownload // @@ -188,6 +188,7 @@ this.checkAudioOnly.TabIndex = 7; this.checkAudioOnly.Text = "Audio only"; this.checkAudioOnly.UseVisualStyleBackColor = true; + this.checkAudioOnly.CheckedChanged += new System.EventHandler(this.checkAudioOnly_CheckedChanged); // // Main // diff --git a/Main.cs b/Main.cs index a48696f..bfc7ab7 100644 --- a/Main.cs +++ b/Main.cs @@ -36,7 +36,11 @@ namespace ytdlp_gui false, workdir ); - Download download = new Download(process, workdir); + Download download = new Download( + process, + workdir, + checkConvert.Checked ? comboConvertFormat.Text : null + ); download.Show(); downloads.Add(download); @@ -57,6 +61,19 @@ namespace ytdlp_gui ); e.Cancel = (window == DialogResult.No); } + + private void checkAudioOnly_CheckedChanged(object sender, EventArgs e) + { + if (checkAudioOnly.Checked) + comboConvertFormat.Text = "mp3"; + else + comboConvertFormat.Text = "mp4"; + } + + private void checkConvert_CheckedChanged(object sender, EventArgs e) + { + comboConvertFormat.Enabled = checkConvert.Checked; + } protected List downloads; protected YTdlp ytdlp;