diff --git a/Download.Designer.cs b/Download.Designer.cs index 015ef4c..8f26df2 100644 --- a/Download.Designer.cs +++ b/Download.Designer.cs @@ -28,24 +28,26 @@ /// private void InitializeComponent() { - this.lblStatus = new System.Windows.Forms.Label(); + this.lblDownload = new System.Windows.Forms.Label(); this.btnCancel = new System.Windows.Forms.Button(); - this.progressBar = new System.Windows.Forms.ProgressBar(); + this.pbDownload = new System.Windows.Forms.ProgressBar(); + this.pbConvertion = new System.Windows.Forms.ProgressBar(); + this.lblConvertion = new System.Windows.Forms.Label(); this.SuspendLayout(); // - // lblStatus + // lblDownload // - this.lblStatus.AutoSize = true; - this.lblStatus.Location = new System.Drawing.Point(13, 13); - this.lblStatus.Name = "lblStatus"; - this.lblStatus.Size = new System.Drawing.Size(139, 25); - this.lblStatus.TabIndex = 0; - this.lblStatus.Text = "Connecting..."; + this.lblDownload.AutoSize = true; + this.lblDownload.Location = new System.Drawing.Point(13, 13); + this.lblDownload.Name = "lblDownload"; + this.lblDownload.Size = new System.Drawing.Size(139, 25); + this.lblDownload.TabIndex = 0; + this.lblDownload.Text = "Connecting..."; // // btnCancel // this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Abort; - this.btnCancel.Location = new System.Drawing.Point(625, 41); + this.btnCancel.Location = new System.Drawing.Point(899, 127); this.btnCancel.Name = "btnCancel"; this.btnCancel.Size = new System.Drawing.Size(110, 40); this.btnCancel.TabIndex = 7; @@ -53,21 +55,38 @@ this.btnCancel.UseVisualStyleBackColor = true; this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); // - // progressBar + // pbDownload // - this.progressBar.Location = new System.Drawing.Point(18, 41); - this.progressBar.Name = "progressBar"; - this.progressBar.Size = new System.Drawing.Size(601, 40); - this.progressBar.TabIndex = 8; + this.pbDownload.Location = new System.Drawing.Point(18, 41); + this.pbDownload.Name = "pbDownload"; + this.pbDownload.Size = new System.Drawing.Size(875, 40); + this.pbDownload.TabIndex = 8; + // + // pbConvertion + // + this.pbConvertion.Location = new System.Drawing.Point(18, 127); + this.pbConvertion.Name = "pbConvertion"; + this.pbConvertion.Size = new System.Drawing.Size(875, 40); + this.pbConvertion.TabIndex = 10; + // + // lblConvertion + // + this.lblConvertion.AutoSize = true; + this.lblConvertion.Location = new System.Drawing.Point(13, 99); + this.lblConvertion.Name = "lblConvertion"; + this.lblConvertion.Size = new System.Drawing.Size(0, 25); + this.lblConvertion.TabIndex = 9; // // Download // this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(747, 102); - this.Controls.Add(this.progressBar); + this.ClientSize = new System.Drawing.Size(1021, 183); + this.Controls.Add(this.pbConvertion); + this.Controls.Add(this.lblConvertion); + this.Controls.Add(this.pbDownload); this.Controls.Add(this.btnCancel); - this.Controls.Add(this.lblStatus); + this.Controls.Add(this.lblDownload); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; this.Name = "Download"; this.Text = "Downloading"; @@ -80,8 +99,10 @@ #endregion - private System.Windows.Forms.Label lblStatus; + private System.Windows.Forms.Label lblDownload; private System.Windows.Forms.Button btnCancel; - private System.Windows.Forms.ProgressBar progressBar; + private System.Windows.Forms.ProgressBar pbDownload; + private System.Windows.Forms.ProgressBar pbConvertion; + private System.Windows.Forms.Label lblConvertion; } } \ No newline at end of file diff --git a/Download.cs b/Download.cs index 04c69e9..c69f6d5 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.Linq.Expressions; using System.Runtime.Remoting.Contexts; using System.Security.AccessControl; using System.Security.Policy; @@ -25,22 +26,34 @@ namespace ytdlp_gui InitializeComponent(); } - private void Download_Load(object sender, EventArgs e) + private async void Download_Load(object sender, EventArgs e) { process.Start += (_sender, start_event) => { - lblStatus.Text = String.Format( + lblDownload.Text = String.Format( "Connecting to %s...", start_event.provider ); }; + process.Error += (_sender, error_event) => + { + MessageBox.Show(this, error_event.error, "yt-dlp error", MessageBoxButtons.OK, MessageBoxIcon.Error ); + this.Close(); + }; + process.Progress += (_sender, prog_event) => { int progress = (int)(prog_event.progress * 100 + 0.5); - this.Text = "Downloading - " + progress.ToString() + "%"; - lblStatus.Text = prog_event.file; - progressBar.Value = progress; + this.Text = String.Format( + "Downloading {0}/{1} {2}% - {3}", + prog_event.playlist_current, + prog_event.playlist_total, + progress, + prog_event.file + ); + lblDownload.Text = this.Text; + pbDownload.Value = progress; }; process.Finished += (_sender, finish_event) => @@ -66,33 +79,41 @@ namespace ytdlp_gui { System.IO.File.Move(filePath, newFilePath); System.IO.File.SetLastWriteTime(newFilePath, DateTime.Now); - this.Close(); } else { + newFile = Path.ChangeExtension(newFile, convert_to); newFilePath = Path.ChangeExtension(newFilePath, convert_to); - convertion = (new FFmpeg()).Convert(filePath, newFilePath); + FFmpegProcess convertion = (new FFmpeg()).Convert(filePath, newFilePath); - convertion.Progress += (_ffmpeg, progress_event) => + convertion.Progress += (_ffmpeg, prog_event) => { - int progress = (int)(progress_event.progress * 100 + 0.5); - this.Text = "Converting - " + progress.ToString() + "%"; - lblStatus.Text = "Converting to " + convert_to; - progressBar.Value = progress; + int progress = (int)(prog_event.progress * 100 + 0.5); + // this.Text = "Converting - " + progress.ToString() + "%"; + lblConvertion.Text = String.Format( + "Converting {0}/{1} {2}% - {3}", + convertion_current, + convertion_total, + progress, + newFile + ); + pbConvertion.Value = progress; }; convertion.Finished += (_ffmpeg, _ffmpeg_e) => { System.IO.File.Delete(filePath); - this.Close(); + triggerConvertionQueue(); }; - convertion.Run().ContinueWith(t => { MessageBox.Show(t.Exception.ToString(), "Error"); }, TaskContinuationOptions.OnlyOnFaulted); ; + convertion_queue.Enqueue(convertion); + convertion_total += 1; + triggerConvertionQueue(); } }; // Can run in background :) - process.Run().ContinueWith(t => { MessageBox.Show(t.Exception.ToString(), "Error"); }, TaskContinuationOptions.OnlyOnFaulted); + _ = await process.Run(); } private void btnCancel_Click(object sender, EventArgs e) @@ -102,12 +123,30 @@ namespace ytdlp_gui private void Download_FormClosing(object sender, FormClosingEventArgs e) { - if (convertion != null) - convertion.Cancel(); + process.Cancel(); + foreach (FFmpegProcess conversion in convertion_queue) + conversion.Cancel(); + } + + protected async void triggerConvertionQueue() + { + if (converting) + return; + + if (convertion_queue.Count() == 0) + return; + + converting = true; + convertion_current += 1; + await convertion_queue.Dequeue().Run(); + converting = false; } protected readonly YTdlpProcess process; - protected FFmpegProcess convertion; + protected int convertion_current = 0; + protected int convertion_total = 0; + protected Queue convertion_queue = new Queue(); + private bool converting = false; protected readonly string workdir; protected readonly string convert_to; } diff --git a/FFmpeg.cs b/FFmpeg.cs index ecd7411..a488f20 100644 --- a/FFmpeg.cs +++ b/FFmpeg.cs @@ -29,9 +29,6 @@ namespace ytdlp_gui 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() @@ -39,7 +36,7 @@ namespace ytdlp_gui Cancel(); } - public async Task Run() + public async Task Run() { if (File.Exists(output_file)) System.IO.File.Delete(output_file); @@ -71,37 +68,33 @@ namespace ytdlp_gui + int.Parse(groups[2].Value) * 60 + int.Parse(groups[3].Value); - Progress?.Invoke(this, new FFmpegProgressEventArgs((float)progress / duration)); + Progress?.Invoke(this, new FFmpegProgressEventArgs(Math.Min((float)progress / duration, 1))); } } + if (stop) + return; + process.WaitForExit(); - process.Close(); Finished?.Invoke(this, new EventArgs()); - return null; + return; } public void Cancel() { - bool finished = true; - try // to kill the process before deleting the file - { - finished = process.HasExited; + stop = true; + if (!process.HasExited) process.Kill(); - process.WaitForExit(); - process.Close(); - } - catch { } - // if (!finished && File.Exists(output_file)) - // System.IO.File.Delete(output_file); + process.WaitForExit(); } private readonly Process process; private readonly string output_file; private readonly CultureInfo ci; - private readonly Regex header_regex; - private readonly Regex progress_regex; + private readonly Regex header_regex = new Regex(@"Duration: (\d+):(\d+):(\d+)\.(\d+)"); + private readonly Regex progress_regex = new Regex(@"time=(\d+):(\d+):(\d+)\.(\d+)"); + private bool stop = false; public event EventHandler Progress; public event EventHandler Finished; } @@ -124,7 +117,7 @@ namespace ytdlp_gui process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; - process.StartInfo.RedirectStandardOutput = 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 d04cda3..8554f66 100644 --- a/Main.Designer.cs +++ b/Main.Designer.cs @@ -31,9 +31,9 @@ this.label1 = new System.Windows.Forms.Label(); this.textUrl = new System.Windows.Forms.TextBox(); this.checkDownloadPlaylist = new System.Windows.Forms.CheckBox(); - this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.groupPlaylist = new System.Windows.Forms.GroupBox(); this.textPlaylistFolder = new System.Windows.Forms.TextBox(); - this.label2 = new System.Windows.Forms.Label(); + this.lblPlaylistFolder = new System.Windows.Forms.Label(); this.checkPlaylistFolder = new System.Windows.Forms.CheckBox(); this.groupBox2 = new System.Windows.Forms.GroupBox(); this.label3 = new System.Windows.Forms.Label(); @@ -42,7 +42,7 @@ this.btnDownload = new System.Windows.Forms.Button(); this.btnCancel = new System.Windows.Forms.Button(); this.checkAudioOnly = new System.Windows.Forms.CheckBox(); - this.groupBox1.SuspendLayout(); + this.groupPlaylist.SuspendLayout(); this.groupBox2.SuspendLayout(); this.SuspendLayout(); // @@ -65,42 +65,44 @@ // checkDownloadPlaylist // this.checkDownloadPlaylist.AutoSize = true; - this.checkDownloadPlaylist.Enabled = false; this.checkDownloadPlaylist.Location = new System.Drawing.Point(25, 178); this.checkDownloadPlaylist.Name = "checkDownloadPlaylist"; this.checkDownloadPlaylist.Size = new System.Drawing.Size(212, 29); this.checkDownloadPlaylist.TabIndex = 2; this.checkDownloadPlaylist.Text = "Download playlist"; this.checkDownloadPlaylist.UseVisualStyleBackColor = true; + this.checkDownloadPlaylist.CheckedChanged += new System.EventHandler(this.checkDownloadPlaylist_CheckedChanged); // - // groupBox1 + // groupPlaylist // - this.groupBox1.Controls.Add(this.textPlaylistFolder); - this.groupBox1.Controls.Add(this.label2); - this.groupBox1.Controls.Add(this.checkPlaylistFolder); - this.groupBox1.Enabled = false; - this.groupBox1.Location = new System.Drawing.Point(18, 58); - this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(373, 108); - this.groupBox1.TabIndex = 3; - this.groupBox1.TabStop = false; - this.groupBox1.Text = "Playlist"; + this.groupPlaylist.Controls.Add(this.textPlaylistFolder); + this.groupPlaylist.Controls.Add(this.lblPlaylistFolder); + this.groupPlaylist.Controls.Add(this.checkPlaylistFolder); + this.groupPlaylist.Enabled = false; + this.groupPlaylist.Location = new System.Drawing.Point(18, 58); + this.groupPlaylist.Name = "groupPlaylist"; + this.groupPlaylist.Size = new System.Drawing.Size(373, 108); + this.groupPlaylist.TabIndex = 3; + this.groupPlaylist.TabStop = false; + this.groupPlaylist.Text = "Playlist"; // // textPlaylistFolder // + this.textPlaylistFolder.Enabled = false; this.textPlaylistFolder.Location = new System.Drawing.Point(94, 60); this.textPlaylistFolder.Name = "textPlaylistFolder"; this.textPlaylistFolder.Size = new System.Drawing.Size(273, 31); this.textPlaylistFolder.TabIndex = 2; // - // label2 + // lblPlaylistFolder // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(7, 67); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(80, 25); - this.label2.TabIndex = 1; - this.label2.Text = "Name: "; + this.lblPlaylistFolder.AutoSize = true; + this.lblPlaylistFolder.Enabled = false; + this.lblPlaylistFolder.Location = new System.Drawing.Point(7, 67); + this.lblPlaylistFolder.Name = "lblPlaylistFolder"; + this.lblPlaylistFolder.Size = new System.Drawing.Size(80, 25); + this.lblPlaylistFolder.TabIndex = 1; + this.lblPlaylistFolder.Text = "Name: "; // // checkPlaylistFolder // @@ -111,6 +113,7 @@ this.checkPlaylistFolder.TabIndex = 0; this.checkPlaylistFolder.Text = "Save to folder"; this.checkPlaylistFolder.UseVisualStyleBackColor = true; + this.checkPlaylistFolder.CheckedChanged += new System.EventHandler(this.checkPlaylistFolder_CheckedChanged); // // groupBox2 // @@ -201,7 +204,7 @@ this.Controls.Add(this.btnCancel); this.Controls.Add(this.btnDownload); this.Controls.Add(this.groupBox2); - this.Controls.Add(this.groupBox1); + this.Controls.Add(this.groupPlaylist); this.Controls.Add(this.checkDownloadPlaylist); this.Controls.Add(this.textUrl); this.Controls.Add(this.label1); @@ -211,8 +214,8 @@ this.Name = "Main"; this.Text = "Youtube Downloader"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Main_FormClosing); - this.groupBox1.ResumeLayout(false); - this.groupBox1.PerformLayout(); + this.groupPlaylist.ResumeLayout(false); + this.groupPlaylist.PerformLayout(); this.groupBox2.ResumeLayout(false); this.groupBox2.PerformLayout(); this.ResumeLayout(false); @@ -225,10 +228,10 @@ private System.Windows.Forms.Label label1; private System.Windows.Forms.TextBox textUrl; private System.Windows.Forms.CheckBox checkDownloadPlaylist; - private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.GroupBox groupPlaylist; private System.Windows.Forms.CheckBox checkPlaylistFolder; private System.Windows.Forms.TextBox textPlaylistFolder; - private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label lblPlaylistFolder; private System.Windows.Forms.GroupBox groupBox2; private System.Windows.Forms.ComboBox comboConvertFormat; private System.Windows.Forms.CheckBox checkConvert; diff --git a/Main.cs b/Main.cs index bfc7ab7..8097fef 100644 --- a/Main.cs +++ b/Main.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -30,10 +31,17 @@ namespace ytdlp_gui string user = Environment.GetEnvironmentVariable("USERNAME"); string workdir = @"C:\Users\" + user + @"\Downloads\"; + if (checkDownloadPlaylist.Checked && checkPlaylistFolder.Checked) + { + workdir = Path.Combine(workdir, textPlaylistFolder.Text); + if (!Directory.Exists(workdir)) + System.IO.Directory.CreateDirectory(workdir); + } + YTdlpProcess process = ytdlp.Download( textUrl.Text, checkAudioOnly.Checked, - false, + checkDownloadPlaylist.Checked, workdir ); Download download = new Download( @@ -75,6 +83,17 @@ namespace ytdlp_gui comboConvertFormat.Enabled = checkConvert.Checked; } + private void checkDownloadPlaylist_CheckedChanged(object sender, EventArgs e) + { + groupPlaylist.Enabled = checkDownloadPlaylist.Checked; + } + + private void checkPlaylistFolder_CheckedChanged(object sender, EventArgs e) + { + textPlaylistFolder.Enabled = checkPlaylistFolder.Checked; + lblPlaylistFolder.Enabled = checkPlaylistFolder.Checked; + } + protected List downloads; protected YTdlp ytdlp; } diff --git a/ProcessUtil.cs b/ProcessUtil.cs new file mode 100644 index 0000000..180a679 --- /dev/null +++ b/ProcessUtil.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Management; + +namespace ytdlp_gui +{ + internal static class ProcessUtil + { + /// https://stackoverflow.com/questions/5901679/kill-process-tree-programmatically-in-c-sharp#answer-10402906 + /// + /// Kill a process, and all of its children, grandchildren, etc. + /// + /// Process ID. + public static void KillProcessAndChildren(int pid) + { + // Cannot close 'system idle process'. + if (pid == 0) + { + return; + } + ManagementObjectSearcher searcher = new ManagementObjectSearcher + ("Select * From Win32_Process Where ParentProcessID=" + pid); + ManagementObjectCollection moc = searcher.Get(); + foreach (ManagementObject mo in moc) + { + KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"])); + } + try + { + Process proc = Process.GetProcessById(pid); + proc.Kill(); + } + catch (ArgumentException) + { + // Process already exited. + } + } + } +} diff --git a/YTdlp.cs b/YTdlp.cs index 534b9a9..803f64e 100644 --- a/YTdlp.cs +++ b/YTdlp.cs @@ -3,9 +3,12 @@ using System.Collections.Generic; using System.ComponentModel; using System.Deployment.Application; using System.Diagnostics; +using System.Drawing.Printing; using System.Globalization; using System.IO; using System.Linq; +using System.Linq.Expressions; +using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -24,18 +27,31 @@ namespace ytdlp_gui public class YTdlpProgressEventArgs : EventArgs { - public YTdlpProgressEventArgs(string provider, string action, string file, float progress) - { + public YTdlpProgressEventArgs( + string provider, + string action, + string file, + float progress, + string playlist, + int playlist_current, + int playlist_total + ){ this.provider = provider; this.action = action; this.file = file; this.progress = progress; + this.playlist = playlist; + this.playlist_current = playlist_current; + this.playlist_total = playlist_total; } public readonly string provider; public readonly string action; public readonly string file; public readonly float progress; + public readonly string playlist; + public readonly int playlist_current; + public readonly int playlist_total; } public class YTdlpErrorEventArgs : EventArgs @@ -74,21 +90,20 @@ namespace ytdlp_gui ci.NumberFormat.CurrencyDecimalSeparator = "."; files = new List(); - - this.already_downloaded_regex = new Regex(@"\[download\]\s+(.+) has already been downloaded"); - this.download_regex = new Regex(@"([0-9.]+)%\s+of\s+([0-9.]+)(\w+)\s+at\s+([0-9.]+)(\w+\/\w+)\sETA\s(\d+:\d+)"); - this.download_finish_regex = new Regex(@"([0-9.]+)%\s+of\s+([0-9.]+)(\w+)\s+in\s+(\d+:\d+:\d+)\s+at\s+([0-9.]+)(\w+\/\w+)"); - this.merge_regex = new Regex(@"Merging formats into ""(.+)"""); } - public async Task Run() + public async Task Run() { process.Start(); - string line = null; + string stdout = ""; + int playlist_last = playlist_current; + string line; bool first = true; while ((line = await process.StandardOutput.ReadLineAsync()) != null) { + Console.WriteLine(line); + stdout += line; if (first) { provider = (new Regex(@"\w+")).Match(line).Value; @@ -96,12 +111,14 @@ namespace ytdlp_gui } line = line.Trim(); + /* Match match = this.already_downloaded_regex.Match(line); if (match.Success) { file = match.Groups[1].Value; break; } + */ if (line.StartsWith("[info] ")) ProgInfo(line.Substring("[info] ".Length).TrimStart()); @@ -111,15 +128,47 @@ namespace ytdlp_gui if (line.StartsWith("[Merger] ")) ProgMerger(line.Substring("[Merger] ".Length).TrimStart()); + + if (line.StartsWith("[youtube:tab] ")) + ProgYoutube(line.Substring("[youtube:tab] ".Length).TrimStart()); + + if (playlist_last != playlist_current) + { + playlist_last = playlist_current; + if (File != null) + Finished?.Invoke(this, new YTdlpFinishedEventArgs(provider, File, files.ToArray())); + } } - process.WaitForExit(); - process.Close(); - Finished?.Invoke(this, new YTdlpFinishedEventArgs(provider, File, files.ToArray())); + if (stop) + return new string[0]; - return null; + process.WaitForExit(); + if (process.ExitCode == 0) + { + if (File != null) + Finished?.Invoke(this, new YTdlpFinishedEventArgs(provider, File, files.ToArray())); + } + else + Error?.Invoke(this, new YTdlpErrorEventArgs(provider, stdout)); + + return files.ToArray(); } + public void Cancel() + { + stop = true; + if (!process.HasExited) try + { + ProcessUtil.KillProcessAndChildren(process.Id); + } + catch (Exception) { /* We tried ¯\_(ツ)_/¯ */ } + process.WaitForExit(); + } + + [DllImport("kernel32.dll")] + private static extern int GetParentProcessId(int processId); + protected void ProgInfo(string line) { } @@ -147,7 +196,10 @@ namespace ytdlp_gui provider, "download", File, - progress + progress, + playlist, + playlist_current, + playlist_total ); Progress?.Invoke(this, args); } @@ -156,21 +208,32 @@ namespace ytdlp_gui if (match.Success) { GroupCollection groups = match.Groups; - float progress = ParseFloat( groups[1].Value ) / 100 ; - float total = ParseFloat( groups[2].Value ) ; - string total_unit = groups[3].Value ; - string total_time = groups[4].Value ; - float speed = ParseFloat( groups[5].Value ) ; - string speed_unit = groups[6].Value ; + float progress = ParseFloat(groups[1].Value) / 100; + float total = ParseFloat(groups[2].Value); + string total_unit = groups[3].Value; + string total_time = groups[4].Value; + float speed = ParseFloat(groups[5].Value); + string speed_unit = groups[6].Value; YTdlpProgressEventArgs args = new YTdlpProgressEventArgs( provider, "download", File, - progress + progress, + playlist, + playlist_current, + playlist_total ); Progress?.Invoke(this, args); } + + match = download_playlist_item_regex.Match(line); + if (match.Success) + { + GroupCollection groups = match.Groups; + playlist_current = int.Parse(groups[1].Value); + playlist_total = int.Parse(groups[2].Value); + } } protected void ProgMerger(string line) @@ -186,12 +249,30 @@ namespace ytdlp_gui provider, "merge", file, - 1 + 1, + playlist, + playlist_current, + playlist_total ); Progress?.Invoke(this, args); } } + protected void ProgYoutube(string line) + { + Match match; + + match = download_playlist_regex.Match(line); + if (match.Success) + { + playlist = match.Groups[1].Value; + // How much we downloading + playlist_total = int.Parse(match.Groups[2].Value); + // How much there is + // playlist_total = int.Parse(match.Groups[3].Value); + } + } + private float ParseFloat(string str) { return float.Parse(str, NumberStyles.Any, ci); @@ -199,11 +280,17 @@ namespace ytdlp_gui private readonly Process process; private readonly CultureInfo ci; - private readonly Regex already_downloaded_regex; - private readonly Regex download_regex; - private readonly Regex download_finish_regex; - private readonly Regex merge_regex; + private readonly Regex download_playlist_regex = new Regex(@"Playlist (.+):\s+Downloading\s+(\d+)\s+items\s+of\s+(\d+)"); + private readonly Regex download_playlist_item_regex = new Regex(@"Downloading\s+item\s(\d+)\s+of\s+(\d+)"); + private readonly Regex already_downloaded_regex = new Regex(@"\[download\]\s+(.+) has already been downloaded"); + private readonly Regex download_regex = new Regex(@"([0-9.]+)%\s+of\s*~?\s+([0-9.]+)(\w+)\s+at\s+([0-9.]+)(\w+\/\w+)\sETA\s(\d+:\d+)"); + private readonly Regex download_finish_regex = new Regex(@"([0-9.]+)%\s+of\s+([0-9.]+)(\w+)\s+in\s+(\d+:\d+:\d+)\s+at\s+([0-9.]+)(\w+\/\w+)"); + private readonly Regex merge_regex = new Regex(@"Merging formats into ""(.+)"""); private string provider; + private string playlist; + private int playlist_current = 1; + private int playlist_total = 1; + private bool stop = false; private string File { get { return file; } set { file = value; if (!files.Contains(value)) files.Add(value); } @@ -237,7 +324,7 @@ namespace ytdlp_gui process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.StartInfo.RedirectStandardOutput = true; - process.StartInfo.RedirectStandardError = true; + // process.StartInfo.RedirectStandardError = true; process.StartInfo.WorkingDirectory = workdir; return new YTdlpProcess(process); diff --git a/ytdlp-gui.csproj b/ytdlp-gui.csproj index 6a2d6dd..b0040b0 100644 --- a/ytdlp-gui.csproj +++ b/ytdlp-gui.csproj @@ -35,6 +35,7 @@ + @@ -60,6 +61,7 @@ Main.cs +