Added playlist support
This commit is contained in:
61
Download.Designer.cs
generated
61
Download.Designer.cs
generated
@ -28,24 +28,26 @@
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
75
Download.cs
75
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<FFmpegProcess> convertion_queue = new Queue<FFmpegProcess>();
|
||||
private bool converting = false;
|
||||
protected readonly string workdir;
|
||||
protected readonly string convert_to;
|
||||
}
|
||||
|
||||
33
FFmpeg.cs
33
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<string> 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<FFmpegProgressEventArgs> 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);
|
||||
|
||||
57
Main.Designer.cs
generated
57
Main.Designer.cs
generated
@ -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;
|
||||
|
||||
21
Main.cs
21
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<Download> downloads;
|
||||
protected YTdlp ytdlp;
|
||||
}
|
||||
|
||||
43
ProcessUtil.cs
Normal file
43
ProcessUtil.cs
Normal 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.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
141
YTdlp.cs
141
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<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();
|
||||
|
||||
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);
|
||||
|
||||
@ -35,6 +35,7 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
@ -60,6 +61,7 @@
|
||||
<DependentUpon>Main.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="App.cs" />
|
||||
<Compile Include="ProcessUtil.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="YTdlp.cs" />
|
||||
|
||||
Reference in New Issue
Block a user