Added playlist support

This commit is contained in:
2025-05-23 01:34:48 +02:00
parent fd6b3ffdf2
commit b886f0b35d
8 changed files with 320 additions and 113 deletions

61
Download.Designer.cs generated
View File

@ -28,24 +28,26 @@
/// </summary> /// </summary>
private void InitializeComponent() 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.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(); this.SuspendLayout();
// //
// lblStatus // lblDownload
// //
this.lblStatus.AutoSize = true; this.lblDownload.AutoSize = true;
this.lblStatus.Location = new System.Drawing.Point(13, 13); this.lblDownload.Location = new System.Drawing.Point(13, 13);
this.lblStatus.Name = "lblStatus"; this.lblDownload.Name = "lblDownload";
this.lblStatus.Size = new System.Drawing.Size(139, 25); this.lblDownload.Size = new System.Drawing.Size(139, 25);
this.lblStatus.TabIndex = 0; this.lblDownload.TabIndex = 0;
this.lblStatus.Text = "Connecting..."; this.lblDownload.Text = "Connecting...";
// //
// btnCancel // btnCancel
// //
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Abort; 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.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(110, 40); this.btnCancel.Size = new System.Drawing.Size(110, 40);
this.btnCancel.TabIndex = 7; this.btnCancel.TabIndex = 7;
@ -53,21 +55,38 @@
this.btnCancel.UseVisualStyleBackColor = true; this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
// //
// progressBar // pbDownload
// //
this.progressBar.Location = new System.Drawing.Point(18, 41); this.pbDownload.Location = new System.Drawing.Point(18, 41);
this.progressBar.Name = "progressBar"; this.pbDownload.Name = "pbDownload";
this.progressBar.Size = new System.Drawing.Size(601, 40); this.pbDownload.Size = new System.Drawing.Size(875, 40);
this.progressBar.TabIndex = 8; 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 // Download
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(747, 102); this.ClientSize = new System.Drawing.Size(1021, 183);
this.Controls.Add(this.progressBar); this.Controls.Add(this.pbConvertion);
this.Controls.Add(this.lblConvertion);
this.Controls.Add(this.pbDownload);
this.Controls.Add(this.btnCancel); this.Controls.Add(this.btnCancel);
this.Controls.Add(this.lblStatus); this.Controls.Add(this.lblDownload);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Name = "Download"; this.Name = "Download";
this.Text = "Downloading"; this.Text = "Downloading";
@ -80,8 +99,10 @@
#endregion #endregion
private System.Windows.Forms.Label lblStatus; private System.Windows.Forms.Label lblDownload;
private System.Windows.Forms.Button btnCancel; 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;
} }
} }

View File

@ -5,6 +5,7 @@ using System.Data;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Remoting.Contexts; using System.Runtime.Remoting.Contexts;
using System.Security.AccessControl; using System.Security.AccessControl;
using System.Security.Policy; using System.Security.Policy;
@ -25,22 +26,34 @@ namespace ytdlp_gui
InitializeComponent(); InitializeComponent();
} }
private void Download_Load(object sender, EventArgs e) private async void Download_Load(object sender, EventArgs e)
{ {
process.Start += (_sender, start_event) => process.Start += (_sender, start_event) =>
{ {
lblStatus.Text = String.Format( lblDownload.Text = String.Format(
"Connecting to %s...", "Connecting to %s...",
start_event.provider 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) => process.Progress += (_sender, prog_event) =>
{ {
int progress = (int)(prog_event.progress * 100 + 0.5); int progress = (int)(prog_event.progress * 100 + 0.5);
this.Text = "Downloading - " + progress.ToString() + "%"; this.Text = String.Format(
lblStatus.Text = prog_event.file; "Downloading {0}/{1} {2}% - {3}",
progressBar.Value = progress; prog_event.playlist_current,
prog_event.playlist_total,
progress,
prog_event.file
);
lblDownload.Text = this.Text;
pbDownload.Value = progress;
}; };
process.Finished += (_sender, finish_event) => process.Finished += (_sender, finish_event) =>
@ -66,33 +79,41 @@ namespace ytdlp_gui
{ {
System.IO.File.Move(filePath, newFilePath); System.IO.File.Move(filePath, newFilePath);
System.IO.File.SetLastWriteTime(newFilePath, DateTime.Now); System.IO.File.SetLastWriteTime(newFilePath, DateTime.Now);
this.Close();
} }
else else
{ {
newFile = Path.ChangeExtension(newFile, convert_to);
newFilePath = Path.ChangeExtension(newFilePath, 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); int progress = (int)(prog_event.progress * 100 + 0.5);
this.Text = "Converting - " + progress.ToString() + "%"; // this.Text = "Converting - " + progress.ToString() + "%";
lblStatus.Text = "Converting to " + convert_to; lblConvertion.Text = String.Format(
progressBar.Value = progress; "Converting {0}/{1} {2}% - {3}",
convertion_current,
convertion_total,
progress,
newFile
);
pbConvertion.Value = progress;
}; };
convertion.Finished += (_ffmpeg, _ffmpeg_e) => convertion.Finished += (_ffmpeg, _ffmpeg_e) =>
{ {
System.IO.File.Delete(filePath); 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 :) // 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) private void btnCancel_Click(object sender, EventArgs e)
@ -102,12 +123,30 @@ namespace ytdlp_gui
private void Download_FormClosing(object sender, FormClosingEventArgs e) private void Download_FormClosing(object sender, FormClosingEventArgs e)
{ {
if (convertion != null) process.Cancel();
convertion.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 readonly YTdlpProcess process;
protected FFmpegProcess convertion; protected int convertion_current = 0;
protected int convertion_total = 0;
protected Queue<FFmpegProcess> convertion_queue = new Queue<FFmpegProcess>();
private bool converting = false;
protected readonly string workdir; protected readonly string workdir;
protected readonly string convert_to; protected readonly string convert_to;
} }

View File

@ -29,9 +29,6 @@ namespace ytdlp_gui
this.output_file = output_file; this.output_file = output_file;
ci = (CultureInfo)CultureInfo.CurrentCulture.Clone(); ci = (CultureInfo)CultureInfo.CurrentCulture.Clone();
ci.NumberFormat.CurrencyDecimalSeparator = "."; ci.NumberFormat.CurrencyDecimalSeparator = ".";
this.header_regex = new Regex(@"Duration: (\d+):(\d+):(\d+)\.(\d+)");
this.progress_regex = new Regex(@"time=(\d+):(\d+):(\d+)\.(\d+)");
} }
~FFmpegProcess() ~FFmpegProcess()
@ -39,7 +36,7 @@ namespace ytdlp_gui
Cancel(); Cancel();
} }
public async Task<string> Run() public async Task Run()
{ {
if (File.Exists(output_file)) if (File.Exists(output_file))
System.IO.File.Delete(output_file); System.IO.File.Delete(output_file);
@ -71,37 +68,33 @@ namespace ytdlp_gui
+ int.Parse(groups[2].Value) * 60 + int.Parse(groups[2].Value) * 60
+ int.Parse(groups[3].Value); + 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.WaitForExit();
process.Close();
Finished?.Invoke(this, new EventArgs()); Finished?.Invoke(this, new EventArgs());
return null; return;
} }
public void Cancel() public void Cancel()
{ {
bool finished = true; stop = true;
try // to kill the process before deleting the file if (!process.HasExited)
{
finished = process.HasExited;
process.Kill(); process.Kill();
process.WaitForExit(); process.WaitForExit();
process.Close();
}
catch { }
// if (!finished && File.Exists(output_file))
// System.IO.File.Delete(output_file);
} }
private readonly Process process; private readonly Process process;
private readonly string output_file; private readonly string output_file;
private readonly CultureInfo ci; private readonly CultureInfo ci;
private readonly Regex header_regex; private readonly Regex header_regex = new Regex(@"Duration: (\d+):(\d+):(\d+)\.(\d+)");
private readonly Regex progress_regex; private readonly Regex progress_regex = new Regex(@"time=(\d+):(\d+):(\d+)\.(\d+)");
private bool stop = false;
public event EventHandler<FFmpegProgressEventArgs> Progress; public event EventHandler<FFmpegProgressEventArgs> Progress;
public event EventHandler Finished; public event EventHandler Finished;
} }
@ -124,7 +117,7 @@ namespace ytdlp_gui
process.StartInfo.UseShellExecute = false; process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true; process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true; // process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true; process.StartInfo.RedirectStandardError = true;
return new FFmpegProcess(process, to); return new FFmpegProcess(process, to);

57
Main.Designer.cs generated
View File

@ -31,9 +31,9 @@
this.label1 = new System.Windows.Forms.Label(); this.label1 = new System.Windows.Forms.Label();
this.textUrl = new System.Windows.Forms.TextBox(); this.textUrl = new System.Windows.Forms.TextBox();
this.checkDownloadPlaylist = new System.Windows.Forms.CheckBox(); 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.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.checkPlaylistFolder = new System.Windows.Forms.CheckBox();
this.groupBox2 = new System.Windows.Forms.GroupBox(); this.groupBox2 = new System.Windows.Forms.GroupBox();
this.label3 = new System.Windows.Forms.Label(); this.label3 = new System.Windows.Forms.Label();
@ -42,7 +42,7 @@
this.btnDownload = new System.Windows.Forms.Button(); this.btnDownload = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button(); this.btnCancel = new System.Windows.Forms.Button();
this.checkAudioOnly = new System.Windows.Forms.CheckBox(); this.checkAudioOnly = new System.Windows.Forms.CheckBox();
this.groupBox1.SuspendLayout(); this.groupPlaylist.SuspendLayout();
this.groupBox2.SuspendLayout(); this.groupBox2.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
@ -65,42 +65,44 @@
// checkDownloadPlaylist // checkDownloadPlaylist
// //
this.checkDownloadPlaylist.AutoSize = true; this.checkDownloadPlaylist.AutoSize = true;
this.checkDownloadPlaylist.Enabled = false;
this.checkDownloadPlaylist.Location = new System.Drawing.Point(25, 178); this.checkDownloadPlaylist.Location = new System.Drawing.Point(25, 178);
this.checkDownloadPlaylist.Name = "checkDownloadPlaylist"; this.checkDownloadPlaylist.Name = "checkDownloadPlaylist";
this.checkDownloadPlaylist.Size = new System.Drawing.Size(212, 29); this.checkDownloadPlaylist.Size = new System.Drawing.Size(212, 29);
this.checkDownloadPlaylist.TabIndex = 2; this.checkDownloadPlaylist.TabIndex = 2;
this.checkDownloadPlaylist.Text = "Download playlist"; this.checkDownloadPlaylist.Text = "Download playlist";
this.checkDownloadPlaylist.UseVisualStyleBackColor = true; this.checkDownloadPlaylist.UseVisualStyleBackColor = true;
this.checkDownloadPlaylist.CheckedChanged += new System.EventHandler(this.checkDownloadPlaylist_CheckedChanged);
// //
// groupBox1 // groupPlaylist
// //
this.groupBox1.Controls.Add(this.textPlaylistFolder); this.groupPlaylist.Controls.Add(this.textPlaylistFolder);
this.groupBox1.Controls.Add(this.label2); this.groupPlaylist.Controls.Add(this.lblPlaylistFolder);
this.groupBox1.Controls.Add(this.checkPlaylistFolder); this.groupPlaylist.Controls.Add(this.checkPlaylistFolder);
this.groupBox1.Enabled = false; this.groupPlaylist.Enabled = false;
this.groupBox1.Location = new System.Drawing.Point(18, 58); this.groupPlaylist.Location = new System.Drawing.Point(18, 58);
this.groupBox1.Name = "groupBox1"; this.groupPlaylist.Name = "groupPlaylist";
this.groupBox1.Size = new System.Drawing.Size(373, 108); this.groupPlaylist.Size = new System.Drawing.Size(373, 108);
this.groupBox1.TabIndex = 3; this.groupPlaylist.TabIndex = 3;
this.groupBox1.TabStop = false; this.groupPlaylist.TabStop = false;
this.groupBox1.Text = "Playlist"; this.groupPlaylist.Text = "Playlist";
// //
// textPlaylistFolder // textPlaylistFolder
// //
this.textPlaylistFolder.Enabled = false;
this.textPlaylistFolder.Location = new System.Drawing.Point(94, 60); this.textPlaylistFolder.Location = new System.Drawing.Point(94, 60);
this.textPlaylistFolder.Name = "textPlaylistFolder"; this.textPlaylistFolder.Name = "textPlaylistFolder";
this.textPlaylistFolder.Size = new System.Drawing.Size(273, 31); this.textPlaylistFolder.Size = new System.Drawing.Size(273, 31);
this.textPlaylistFolder.TabIndex = 2; this.textPlaylistFolder.TabIndex = 2;
// //
// label2 // lblPlaylistFolder
// //
this.label2.AutoSize = true; this.lblPlaylistFolder.AutoSize = true;
this.label2.Location = new System.Drawing.Point(7, 67); this.lblPlaylistFolder.Enabled = false;
this.label2.Name = "label2"; this.lblPlaylistFolder.Location = new System.Drawing.Point(7, 67);
this.label2.Size = new System.Drawing.Size(80, 25); this.lblPlaylistFolder.Name = "lblPlaylistFolder";
this.label2.TabIndex = 1; this.lblPlaylistFolder.Size = new System.Drawing.Size(80, 25);
this.label2.Text = "Name: "; this.lblPlaylistFolder.TabIndex = 1;
this.lblPlaylistFolder.Text = "Name: ";
// //
// checkPlaylistFolder // checkPlaylistFolder
// //
@ -111,6 +113,7 @@
this.checkPlaylistFolder.TabIndex = 0; this.checkPlaylistFolder.TabIndex = 0;
this.checkPlaylistFolder.Text = "Save to folder"; this.checkPlaylistFolder.Text = "Save to folder";
this.checkPlaylistFolder.UseVisualStyleBackColor = true; this.checkPlaylistFolder.UseVisualStyleBackColor = true;
this.checkPlaylistFolder.CheckedChanged += new System.EventHandler(this.checkPlaylistFolder_CheckedChanged);
// //
// groupBox2 // groupBox2
// //
@ -201,7 +204,7 @@
this.Controls.Add(this.btnCancel); this.Controls.Add(this.btnCancel);
this.Controls.Add(this.btnDownload); this.Controls.Add(this.btnDownload);
this.Controls.Add(this.groupBox2); this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1); this.Controls.Add(this.groupPlaylist);
this.Controls.Add(this.checkDownloadPlaylist); this.Controls.Add(this.checkDownloadPlaylist);
this.Controls.Add(this.textUrl); this.Controls.Add(this.textUrl);
this.Controls.Add(this.label1); this.Controls.Add(this.label1);
@ -211,8 +214,8 @@
this.Name = "Main"; this.Name = "Main";
this.Text = "Youtube Downloader"; this.Text = "Youtube Downloader";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Main_FormClosing); this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Main_FormClosing);
this.groupBox1.ResumeLayout(false); this.groupPlaylist.ResumeLayout(false);
this.groupBox1.PerformLayout(); this.groupPlaylist.PerformLayout();
this.groupBox2.ResumeLayout(false); this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout(); this.groupBox2.PerformLayout();
this.ResumeLayout(false); this.ResumeLayout(false);
@ -225,10 +228,10 @@
private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox textUrl; private System.Windows.Forms.TextBox textUrl;
private System.Windows.Forms.CheckBox checkDownloadPlaylist; 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.CheckBox checkPlaylistFolder;
private System.Windows.Forms.TextBox textPlaylistFolder; 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.GroupBox groupBox2;
private System.Windows.Forms.ComboBox comboConvertFormat; private System.Windows.Forms.ComboBox comboConvertFormat;
private System.Windows.Forms.CheckBox checkConvert; private System.Windows.Forms.CheckBox checkConvert;

21
Main.cs
View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Data; using System.Data;
using System.Drawing; using System.Drawing;
using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -30,10 +31,17 @@ namespace ytdlp_gui
string user = Environment.GetEnvironmentVariable("USERNAME"); string user = Environment.GetEnvironmentVariable("USERNAME");
string workdir = @"C:\Users\" + user + @"\Downloads\"; 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( YTdlpProcess process = ytdlp.Download(
textUrl.Text, textUrl.Text,
checkAudioOnly.Checked, checkAudioOnly.Checked,
false, checkDownloadPlaylist.Checked,
workdir workdir
); );
Download download = new Download( Download download = new Download(
@ -75,6 +83,17 @@ namespace ytdlp_gui
comboConvertFormat.Enabled = checkConvert.Checked; 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<Download> downloads; protected List<Download> downloads;
protected YTdlp ytdlp; protected YTdlp ytdlp;
} }

43
ProcessUtil.cs Normal file
View File

@ -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
/// <summary>
/// Kill a process, and all of its children, grandchildren, etc.
/// </summary>
/// <param name="pid">Process ID.</param>
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.
}
}
}
}

127
YTdlp.cs
View File

@ -3,9 +3,12 @@ using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Deployment.Application; using System.Deployment.Application;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing.Printing;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Linq.Expressions;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -24,18 +27,31 @@ namespace ytdlp_gui
public class YTdlpProgressEventArgs : EventArgs 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.provider = provider;
this.action = action; this.action = action;
this.file = file; this.file = file;
this.progress = progress; this.progress = progress;
this.playlist = playlist;
this.playlist_current = playlist_current;
this.playlist_total = playlist_total;
} }
public readonly string provider; public readonly string provider;
public readonly string action; public readonly string action;
public readonly string file; public readonly string file;
public readonly float progress; public readonly float progress;
public readonly string playlist;
public readonly int playlist_current;
public readonly int playlist_total;
} }
public class YTdlpErrorEventArgs : EventArgs public class YTdlpErrorEventArgs : EventArgs
@ -74,21 +90,20 @@ namespace ytdlp_gui
ci.NumberFormat.CurrencyDecimalSeparator = "."; ci.NumberFormat.CurrencyDecimalSeparator = ".";
files = new List<string>(); files = new List<string>();
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<string> Run() public async Task<string[]> Run()
{ {
process.Start(); process.Start();
string line = null; string stdout = "";
int playlist_last = playlist_current;
string line;
bool first = true; bool first = true;
while ((line = await process.StandardOutput.ReadLineAsync()) != null) while ((line = await process.StandardOutput.ReadLineAsync()) != null)
{ {
Console.WriteLine(line);
stdout += line;
if (first) if (first)
{ {
provider = (new Regex(@"\w+")).Match(line).Value; provider = (new Regex(@"\w+")).Match(line).Value;
@ -96,12 +111,14 @@ namespace ytdlp_gui
} }
line = line.Trim(); line = line.Trim();
/*
Match match = this.already_downloaded_regex.Match(line); Match match = this.already_downloaded_regex.Match(line);
if (match.Success) if (match.Success)
{ {
file = match.Groups[1].Value; file = match.Groups[1].Value;
break; break;
} }
*/
if (line.StartsWith("[info] ")) if (line.StartsWith("[info] "))
ProgInfo(line.Substring("[info] ".Length).TrimStart()); ProgInfo(line.Substring("[info] ".Length).TrimStart());
@ -111,14 +128,46 @@ namespace ytdlp_gui
if (line.StartsWith("[Merger] ")) if (line.StartsWith("[Merger] "))
ProgMerger(line.Substring("[Merger] ".Length).TrimStart()); 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()));
} }
}
if (stop)
return new string[0];
process.WaitForExit(); process.WaitForExit();
process.Close(); if (process.ExitCode == 0)
{
if (File != null)
Finished?.Invoke(this, new YTdlpFinishedEventArgs(provider, File, files.ToArray())); Finished?.Invoke(this, new YTdlpFinishedEventArgs(provider, File, files.ToArray()));
return null;
} }
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) protected void ProgInfo(string line)
{ {
@ -147,7 +196,10 @@ namespace ytdlp_gui
provider, provider,
"download", "download",
File, File,
progress progress,
playlist,
playlist_current,
playlist_total
); );
Progress?.Invoke(this, args); Progress?.Invoke(this, args);
} }
@ -167,10 +219,21 @@ namespace ytdlp_gui
provider, provider,
"download", "download",
File, File,
progress progress,
playlist,
playlist_current,
playlist_total
); );
Progress?.Invoke(this, args); 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) protected void ProgMerger(string line)
@ -186,12 +249,30 @@ namespace ytdlp_gui
provider, provider,
"merge", "merge",
file, file,
1 1,
playlist,
playlist_current,
playlist_total
); );
Progress?.Invoke(this, args); 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) private float ParseFloat(string str)
{ {
return float.Parse(str, NumberStyles.Any, ci); return float.Parse(str, NumberStyles.Any, ci);
@ -199,11 +280,17 @@ namespace ytdlp_gui
private readonly Process process; private readonly Process process;
private readonly CultureInfo ci; private readonly CultureInfo ci;
private readonly Regex already_downloaded_regex; private readonly Regex download_playlist_regex = new Regex(@"Playlist (.+):\s+Downloading\s+(\d+)\s+items\s+of\s+(\d+)");
private readonly Regex download_regex; private readonly Regex download_playlist_item_regex = new Regex(@"Downloading\s+item\s(\d+)\s+of\s+(\d+)");
private readonly Regex download_finish_regex; private readonly Regex already_downloaded_regex = new Regex(@"\[download\]\s+(.+) has already been downloaded");
private readonly Regex merge_regex; 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 provider;
private string playlist;
private int playlist_current = 1;
private int playlist_total = 1;
private bool stop = false;
private string File { private string File {
get { return file; } get { return file; }
set { file = value; if (!files.Contains(value)) files.Add(value); } set { file = value; if (!files.Contains(value)) files.Add(value); }
@ -237,7 +324,7 @@ namespace ytdlp_gui
process.StartInfo.UseShellExecute = false; process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true; process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true; // process.StartInfo.RedirectStandardError = true;
process.StartInfo.WorkingDirectory = workdir; process.StartInfo.WorkingDirectory = workdir;
return new YTdlpProcess(process); return new YTdlpProcess(process);

View File

@ -35,6 +35,7 @@
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Management" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
@ -60,6 +61,7 @@
<DependentUpon>Main.cs</DependentUpon> <DependentUpon>Main.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="App.cs" /> <Compile Include="App.cs" />
<Compile Include="ProcessUtil.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="YTdlp.cs" /> <Compile Include="YTdlp.cs" />