Files
ytdlp-gui/YTdlp.cs

245 lines
7.9 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Deployment.Application;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace ytdlp_gui
{
public class YTdlpStartEventArgs : EventArgs
{
public YTdlpStartEventArgs(string provider)
{
this.provider = provider;
}
public readonly string provider;
}
public class YTdlpProgressEventArgs : EventArgs
{
public YTdlpProgressEventArgs(string provider, string action, string file, float progress)
{
this.provider = provider;
this.action = action;
this.file = file;
this.progress = progress;
}
public readonly string provider;
public readonly string action;
public readonly string file;
public readonly float progress;
}
public class YTdlpErrorEventArgs : EventArgs
{
public YTdlpErrorEventArgs(string provider, string error)
{
this.provider = provider;
this.error = error;
}
public readonly string provider;
public readonly string error;
}
public class YTdlpFinishedEventArgs : EventArgs
{
public YTdlpFinishedEventArgs(string provider, string file, string[] files)
{
this.provider = provider;
this.file = file;
this.files = files;
}
public readonly string provider;
public readonly string file;
public readonly string[] files;
}
public class YTdlpProcess
{
public YTdlpProcess(Process process)
{
this.process = process;
ci = (CultureInfo)CultureInfo.CurrentCulture.Clone();
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()
{
process.Start();
string line = null;
bool first = true;
while ((line = await process.StandardOutput.ReadLineAsync()) != null)
{
if (first)
{
provider = (new Regex(@"\w+")).Match(line).Value;
first = false;
}
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());
if (line.StartsWith("[download] "))
ProgDownload(line.Substring("[download] ".Length).TrimStart());
if (line.StartsWith("[Merger] "))
ProgMerger(line.Substring("[Merger] ".Length).TrimStart());
}
Finished?.Invoke(this, new YTdlpFinishedEventArgs(provider, File, files.ToArray()));
return null;
}
protected void ProgInfo(string line)
{
}
protected void ProgDownload(string line)
{
const string dest_str = "Destination: ";
if (line.StartsWith(dest_str))
File = line.Substring(dest_str.Length);
Match match;
match = download_regex.Match(line);
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 ;
float speed = ParseFloat( groups[4].Value ) ;
string speed_unit = groups[5].Value ;
string estamated_time = groups[6].Value ;
YTdlpProgressEventArgs args = new YTdlpProgressEventArgs(
provider,
"download",
File,
progress
);
Progress?.Invoke(this, args);
}
match = download_finish_regex.Match(line);
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 ;
YTdlpProgressEventArgs args = new YTdlpProgressEventArgs(
provider,
"download",
File,
progress
);
Progress?.Invoke(this, args);
}
}
protected void ProgMerger(string line)
{
Match match;
match = merge_regex.Match(line);
if (match.Success)
{
File = match.Groups[1].Value;
YTdlpProgressEventArgs args = new YTdlpProgressEventArgs(
provider,
"merge",
file,
1
);
Progress?.Invoke(this, args);
}
}
private float ParseFloat(string str)
{
return float.Parse(str, NumberStyles.Any, ci);
}
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 string provider;
private string File {
get { return file; }
set { file = value; if (!files.Contains(value)) files.Add(value); }
}
private string file;
private List<string> files;
public event EventHandler<YTdlpStartEventArgs> Start;
public event EventHandler<YTdlpProgressEventArgs> Progress;
public event EventHandler<YTdlpErrorEventArgs> Error;
public event EventHandler<YTdlpFinishedEventArgs> Finished;
}
public class YTdlp : Program
{
public YTdlp() : base("yt-dlp")
{
}
public YTdlpProcess Download(string url, bool audio_only, bool download_playlist, string workdir)
{
Process process = new Process();
process.StartInfo.FileName = program;
process.StartInfo.Arguments = String.Format(
"{0} {1} \"{2}\"",
audio_only ? "-f ba" : "",
download_playlist ? "--yes-playlist" : "--no-playlist",
url.Replace("\"", "\"\"\"")
);
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.WorkingDirectory = workdir;
return new YTdlpProcess(process);
}
}
}