Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of YoutubeDLSharp v1.2.0
BepInEx/core/YoutubeDLSharp.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
#define DEBUG using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Net.Http; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using YoutubeDLSharp.Converters; using YoutubeDLSharp.Helpers; using YoutubeDLSharp.Metadata; using YoutubeDLSharp.Options; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Bluegrams")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyCopyright("© 2020-2026 Bluegrams")] [assembly: AssemblyDescription("\n\t\tA simple .NET wrapper library for youtube-dl and yt-dlp.\n\nNote: Package versions >= 1.0 are optimized to work with yt-dlp.\nPackage versions 0.x retain support for the original youtube-dl.\n\t")] [assembly: AssemblyFileVersion("1.2.0.0")] [assembly: AssemblyInformationalVersion("1.2.0+86949898c089cf895e8aae40de91066de8849db3")] [assembly: AssemblyProduct("YoutubeDLSharp")] [assembly: AssemblyTitle("YoutubeDLSharp")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Bluegrams/YoutubeDLSharp")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace YoutubeDLSharp { public enum DownloadState { None, PreProcessing, Downloading, PostProcessing, Error, Success } public class DownloadProgress { public DownloadState State { get; } public float Progress { get; } public string TotalDownloadSize { get; } public string DownloadSpeed { get; } public string ETA { get; } public int VideoIndex { get; } public string Data { get; } public DownloadProgress(DownloadState status, float progress = 0f, string totalDownloadSize = null, string downloadSpeed = null, string eta = null, int index = 1, string data = null) { State = status; Progress = progress; TotalDownloadSize = totalDownloadSize; DownloadSpeed = downloadSpeed; ETA = eta; VideoIndex = index; Data = data; } } public class RunResult<T> { public bool Success { get; } public string[] ErrorOutput { get; } public T Data { get; } public RunResult(bool success, string[] error, T result) { Success = success; ErrorOutput = error; Data = result; } } public static class Utils { internal class FFmpegApi { public class Root { [JsonProperty("version")] public string Version { get; set; } [JsonProperty("permalink")] public string Permalink { get; set; } [JsonProperty("bin")] public Bin Bin { get; set; } } public class Bin { [JsonProperty("windows-64")] public OsBinVersion Windows64 { get; set; } [JsonProperty("linux-64")] public OsBinVersion Linux64 { get; set; } [JsonProperty("osx-64")] public OsBinVersion Osx64 { get; set; } } public class OsBinVersion { [JsonProperty("ffmpeg")] public string Ffmpeg { get; set; } [JsonProperty("ffprobe")] public string Ffprobe { get; set; } } public enum BinaryType { [EnumMember(Value = "ffmpeg")] FFmpeg, [EnumMember(Value = "ffprobe")] FFprobe } } private static readonly Regex rgxTimestamp = new Regex("[0-9]+(?::[0-9]+)+", RegexOptions.Compiled); private static readonly Dictionary<char, string> accentChars = "ÂÃÄÀÁÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖŐØŒÙÚÛÜŰÝÞßàáâãäåæçèéêëìíîïðñòóôõöőøœùúûüűýþÿ".Zip(new string[68] { "A", "A", "A", "A", "A", "A", "AE", "C", "E", "E", "E", "E", "I", "I", "I", "I", "D", "N", "O", "O", "O", "O", "O", "O", "O", "OE", "U", "U", "U", "U", "U", "Y", "P", "ss", "a", "a", "a", "a", "a", "a", "ae", "c", "e", "e", "e", "e", "i", "i", "i", "i", "o", "n", "o", "o", "o", "o", "o", "o", "o", "oe", "u", "u", "u", "u", "u", "y", "p", "y" }, (char c, string s) => new { Key = c, Val = s }).ToDictionary(o => o.Key, o => o.Val); private const string DENO_VERSION_URL = "https://dl.deno.land/release-latest.txt"; private const string DENO_DOWNLOAD_URL_TEMPLATE = "https://dl.deno.land/release/{0}/deno-{1}.zip"; public static int TimeoutSeconds { get; set; } = 300; public static string YtDlpBinaryName => GetYtDlpBinaryName(); public static string FfmpegBinaryName => GetFfmpegBinaryName(); public static string FfprobeBinaryName => GetFfprobeBinaryName(); public static string Sanitize(string s, bool restricted = false) { rgxTimestamp.Replace(s, (Match m) => m.Groups[0].Value.Replace(':', '_')); string text = string.Join("", s.Select((char c) => sanitizeChar(c, restricted))); text = text.Replace("__", "_").Trim(new char[1] { '_' }); if (restricted && text.StartsWith("-_")) { text = text.Substring(2); } if (text.StartsWith("-")) { text = "_" + text.Substring(1); } text = text.TrimStart(new char[1] { '.' }); if (string.IsNullOrWhiteSpace(text)) { text = "_"; } return text; } private static string sanitizeChar(char c, bool restricted) { if (restricted && accentChars.ContainsKey(c)) { return accentChars[c]; } if (c == '?' || c < ' ' || c == '\u007f') { return ""; } switch (c) { case '"': return restricted ? "" : "'"; case ':': return restricted ? "_-" : " -"; default: if (Enumerable.Contains("\\/|*<>", c)) { return "_"; } if (restricted && Enumerable.Contains("!&'()[]{}$;`^,# ", c)) { return "_"; } if (restricted && c > '\u007f') { return "_"; } return c.ToString(); } } public static string GetFullPath(string fileName) { if (File.Exists(fileName)) { return Path.GetFullPath(fileName); } string environmentVariable = Environment.GetEnvironmentVariable("PATH"); string[] array = environmentVariable.Split(new char[1] { Path.PathSeparator }); foreach (string path in array) { string text = Path.Combine(path, fileName); if (File.Exists(text)) { return text; } } return null; } public static async Task DownloadBinaries(bool skipExisting = true, string directoryPath = "", bool downloadJSRuntime = true) { if (skipExisting) { if (!File.Exists(Path.Combine(directoryPath, GetYtDlpBinaryName()))) { await DownloadYtDlp(directoryPath); } if (!File.Exists(Path.Combine(directoryPath, GetFfmpegBinaryName()))) { await DownloadFFmpeg(directoryPath); } if (!File.Exists(Path.Combine(directoryPath, GetFfprobeBinaryName()))) { await DownloadFFprobe(directoryPath); } if (downloadJSRuntime && !File.Exists(Path.Combine(directoryPath, GetDenoBinaryName()))) { await DownloadDeno(directoryPath); } } else { await DownloadYtDlp(directoryPath); await DownloadFFmpeg(directoryPath); await DownloadFFprobe(directoryPath); if (downloadJSRuntime) { await DownloadDeno(directoryPath); } } } private static string GetYtDlpBinaryName() { string ytDlpDownloadUrl = GetYtDlpDownloadUrl(); return Path.GetFileName(ytDlpDownloadUrl); } private static string GetFfmpegBinaryName() { switch (OSHelper.GetOSVersion()) { case OSVersion.Windows: return "ffmpeg.exe"; case OSVersion.OSX: case OSVersion.Linux: return "ffmpeg"; default: throw new Exception("Your OS isn't supported"); } } private static string GetFfprobeBinaryName() { switch (OSHelper.GetOSVersion()) { case OSVersion.Windows: return "ffprobe.exe"; case OSVersion.OSX: case OSVersion.Linux: return "ffprobe"; default: throw new Exception("Your OS isn't supported"); } } private static string GetDenoBinaryName() { switch (OSHelper.GetOSVersion()) { case OSVersion.Windows: return "deno.exe"; case OSVersion.OSX: case OSVersion.Linux: return "deno"; default: throw new Exception("Your OS isn't supported"); } } private static string GetYtDlpDownloadUrl() { return OSHelper.GetOSVersion() switch { OSVersion.Windows => "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe", OSVersion.OSX => "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_macos", OSVersion.Linux => "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp", _ => throw new Exception("Your OS isn't supported"), }; } public static async Task DownloadYtDlp(string directoryPath = "") { string downloadUrl = GetYtDlpDownloadUrl(); if (string.IsNullOrEmpty(directoryPath)) { directoryPath = Directory.GetCurrentDirectory(); } string downloadLocation = Path.Combine(directoryPath, Path.GetFileName(downloadUrl)); File.WriteAllBytes(downloadLocation, await DownloadFileBytesAsync(downloadUrl)); SetUnixExecPerms(downloadLocation); } public static async Task DownloadFFmpeg(string directoryPath = "") { await FFDownloader(directoryPath); } public static async Task DownloadFFprobe(string directoryPath = "") { await FFDownloader(directoryPath, FFmpegApi.BinaryType.FFprobe); } private static void SetUnixExecPerms(string filename) { if (OSHelper.IsWindows) { return; } throw new PlatformNotSupportedException("Setting Unix permissions is not supported on this platform."); } private static HttpClient GetHttpClient() { HttpClient httpClient = null; if (httpClient == null) { httpClient = new HttpClient(); httpClient.Timeout = TimeSpan.FromSeconds(TimeoutSeconds); } return httpClient; } private static async Task FFDownloader(string directoryPath = "", FFmpegApi.BinaryType binary = FFmpegApi.BinaryType.FFmpeg) { HttpClient client = GetHttpClient(); if (string.IsNullOrEmpty(directoryPath)) { directoryPath = Directory.GetCurrentDirectory(); } FFmpegApi.Root ffmpegVersion = JsonConvert.DeserializeObject<FFmpegApi.Root>(await (await client.GetAsync("https://ffbinaries.com/api/v1/version/latest")).Content.ReadAsStringAsync()); FFmpegApi.OsBinVersion ffContent = OSHelper.GetOSVersion() switch { OSVersion.Windows => ffmpegVersion?.Bin.Windows64, OSVersion.OSX => ffmpegVersion?.Bin.Osx64, OSVersion.Linux => ffmpegVersion?.Bin.Linux64, _ => throw new NotImplementedException("Your OS isn't supported"), }; string downloadUrl = ((binary == FFmpegApi.BinaryType.FFmpeg) ? ffContent.Ffmpeg : ffContent.Ffprobe); byte[] dataBytes = await DownloadFileBytesAsync(downloadUrl); string fileName = string.Empty; using (MemoryStream stream = new MemoryStream(dataBytes)) { using ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read); if (archive.Entries.Count > 0) { fileName = Path.Combine(directoryPath, archive.Entries[0].FullName); archive.Entries[0].ExtractToFile(Path.Combine(directoryPath, archive.Entries[0].FullName), overwrite: true); } } SetUnixExecPerms(fileName); client?.Dispose(); } private static async Task<byte[]> DownloadFileBytesAsync(string uri) { if (!Uri.TryCreate(uri, UriKind.Absolute, out Uri _)) { throw new InvalidOperationException("URI is invalid."); } HttpClient client = GetHttpClient(); byte[] fileBytes = await client.GetByteArrayAsync(uri); client?.Dispose(); return fileBytes; } public static async Task DownloadDeno(string directoryPath = "") { HttpClient client = GetHttpClient(); if (string.IsNullOrEmpty(directoryPath)) { directoryPath = Directory.GetCurrentDirectory(); } string denoVersion = (await (await client.GetAsync("https://dl.deno.land/release-latest.txt")).Content.ReadAsStringAsync()).Trim(); string downloadUrl = string.Format("https://dl.deno.land/release/{0}/deno-{1}.zip", denoVersion, OSHelper.GetOSVersion() switch { OSVersion.Windows => "x86_64-pc-windows-msvc", OSVersion.OSX => "aarch64-apple-darwin", OSVersion.Linux => "x86_64-unknown-linux-gnu", _ => throw new NotImplementedException("Your OS isn't supported"), }); byte[] dataBytes = await DownloadFileBytesAsync(downloadUrl); string fileName = string.Empty; using (MemoryStream stream = new MemoryStream(dataBytes)) { using ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read); if (archive.Entries.Count > 0) { fileName = Path.Combine(directoryPath, archive.Entries[0].FullName); archive.Entries[0].ExtractToFile(Path.Combine(directoryPath, archive.Entries[0].FullName), overwrite: true); } } SetUnixExecPerms(fileName); client?.Dispose(); } public static void EnsureSuccess<T>(this RunResult<T> runResult) { if (!runResult.Success) { throw new Exception("Download failed:\n" + string.Join("\n", runResult.ErrorOutput)); } } } public class YoutubeDL { private static readonly Regex rgxFile = new Regex("^outfile:\\s\\\"?(.*)\\\"?", RegexOptions.Compiled); private static Regex rgxFilePostProc = new Regex("\\[download\\] Destination: [a-zA-Z]:\\\\\\S+\\.\\S{3,}", RegexOptions.Compiled); protected ProcessRunner runner; public string YoutubeDLPath { get; set; } = Utils.YtDlpBinaryName; public string FFmpegPath { get; set; } = Utils.FfmpegBinaryName; public string OutputFolder { get; set; } = Environment.CurrentDirectory; public string OutputFileTemplate { get; set; } = "%(title)s [%(id)s].%(ext)s"; public bool RestrictFilenames { get; set; } = false; public bool OverwriteFiles { get; set; } = true; public bool IgnoreDownloadErrors { get; set; } = true; public string PythonInterpreterPath { get; set; } = null; public string Version => FileVersionInfo.GetVersionInfo(Utils.GetFullPath(YoutubeDLPath)).FileVersion; public YoutubeDL(byte maxNumberOfProcesses = 4) { runner = new ProcessRunner(maxNumberOfProcesses); } public async Task SetMaxNumberOfProcesses(byte count) { await runner.SetTotalCount(count); } public async Task<RunResult<string[]>> RunWithOptions(string[] urls, OptionSet options, CancellationToken ct) { List<string> output = new List<string>(); YoutubeDLProcess process = CreateYoutubeDLProcess(); process.OutputReceived += delegate(object o, DataReceivedEventArgs e) { output.Add(e.Data); }; var (code, errors) = await runner.RunThrottled(process, urls, options, ct); return new RunResult<string[]>(code == 0, errors, output.ToArray()); } public async Task<RunResult<string>> RunWithOptions(string url, OptionSet options, CancellationToken ct = default(CancellationToken), IProgress<DownloadProgress> progress = null, IProgress<string> output = null, bool showArgs = true) { string outFile = string.Empty; YoutubeDLProcess process = CreateYoutubeDLProcess(); if (showArgs) { output?.Report("Arguments: " + process.ConvertToArgs(new string[1] { url }, options) + "\n"); } else { output?.Report("Starting Download: " + url); } process.OutputReceived += delegate(object o, DataReceivedEventArgs e) { Match match = rgxFilePostProc.Match(e.Data); if (match.Success) { outFile = match.Groups[0].ToString().Replace("[download] Destination:", "").Replace(" ", ""); progress?.Report(new DownloadProgress(DownloadState.Success, 0f, null, null, null, 1, outFile)); } output?.Report(e.Data); }; var (code, errors) = await runner.RunThrottled(process, new string[1] { url }, options, ct, progress); return new RunResult<string>(code == 0, errors, outFile); } public async Task<string> RunUpdate() { string output = string.Empty; YoutubeDLProcess process = CreateYoutubeDLProcess(); process.OutputReceived += delegate(object o, DataReceivedEventArgs e) { output = e.Data; }; await process.RunAsync(null, new OptionSet { Update = true }); return output; } public async Task<RunResult<VideoData>> RunVideoDataFetch(string url, CancellationToken ct = default(CancellationToken), bool flat = true, bool fetchComments = false, OptionSet overrideOptions = null) { OptionSet opts = GetDownloadOptions(); opts.DumpSingleJson = true; opts.FlatPlaylist = flat; opts.WriteComments = fetchComments; if (overrideOptions != null) { opts = opts.OverrideOptions(overrideOptions); } VideoData videoData = null; YoutubeDLProcess process = CreateYoutubeDLProcess(); process.OutputReceived += delegate(object o, DataReceivedEventArgs e) { try { videoData = JsonConvert.DeserializeObject<VideoData>(e.Data); } catch (JsonSerializationException) { process.RedirectToError(e); } }; var (code, errors) = await runner.RunThrottled(process, new string[1] { url }, opts, ct); return new RunResult<VideoData>(code == 0, errors, videoData); } public async Task<RunResult<string>> RunVideoDownload(string url, string format = "bestvideo+bestaudio/best", DownloadMergeFormat mergeFormat = DownloadMergeFormat.Unspecified, VideoRecodeFormat recodeFormat = VideoRecodeFormat.None, CancellationToken ct = default(CancellationToken), IProgress<DownloadProgress> progress = null, IProgress<string> output = null, OptionSet overrideOptions = null) { OptionSet opts = GetDownloadOptions(); opts.Format = format; opts.MergeOutputFormat = mergeFormat; opts.RecodeVideo = recodeFormat; if (overrideOptions != null) { opts = opts.OverrideOptions(overrideOptions); } string outputFile = string.Empty; YoutubeDLProcess process = CreateYoutubeDLProcess(); output?.Report("Arguments: " + process.ConvertToArgs(new string[1] { url }, opts) + "\n"); process.OutputReceived += delegate(object o, DataReceivedEventArgs e) { Match match = rgxFile.Match(e.Data); if (match.Success) { outputFile = match.Groups[1].ToString().Trim(new char[1] { '"' }); progress?.Report(new DownloadProgress(DownloadState.Success, 0f, null, null, null, 1, outputFile)); } output?.Report(e.Data); }; var (code, errors) = await runner.RunThrottled(process, new string[1] { url }, opts, ct, progress); return new RunResult<string>(code == 0, errors, outputFile); } public async Task<RunResult<string[]>> RunVideoPlaylistDownload(string url, int? start = 1, int? end = null, int[] items = null, string format = "bestvideo+bestaudio/best", VideoRecodeFormat recodeFormat = VideoRecodeFormat.None, CancellationToken ct = default(CancellationToken), IProgress<DownloadProgress> progress = null, IProgress<string> output = null, OptionSet overrideOptions = null) { OptionSet opts = GetDownloadOptions(); opts.NoPlaylist = false; opts.PlaylistStart = start; opts.PlaylistEnd = end; if (items != null) { opts.PlaylistItems = string.Join(",", items); } opts.Format = format; opts.RecodeVideo = recodeFormat; if (overrideOptions != null) { opts = opts.OverrideOptions(overrideOptions); } List<string> outputFiles = new List<string>(); YoutubeDLProcess process = CreateYoutubeDLProcess(); output?.Report("Arguments: " + process.ConvertToArgs(new string[1] { url }, opts) + "\n"); process.OutputReceived += delegate(object o, DataReceivedEventArgs e) { Match match = rgxFile.Match(e.Data); if (match.Success) { string text = match.Groups[1].ToString().Trim(new char[1] { '"' }); outputFiles.Add(text); progress?.Report(new DownloadProgress(DownloadState.Success, 0f, null, null, null, 1, text)); } output?.Report(e.Data); }; var (code, errors) = await runner.RunThrottled(process, new string[1] { url }, opts, ct, progress); return new RunResult<string[]>(code == 0, errors, outputFiles.ToArray()); } public async Task<RunResult<string>> RunAudioDownload(string url, AudioConversionFormat format = AudioConversionFormat.Best, CancellationToken ct = default(CancellationToken), IProgress<DownloadProgress> progress = null, IProgress<string> output = null, OptionSet overrideOptions = null) { OptionSet opts = GetDownloadOptions(); opts.Format = "bestaudio/best"; opts.ExtractAudio = true; opts.AudioFormat = format; if (overrideOptions != null) { opts = opts.OverrideOptions(overrideOptions); } string outputFile = string.Empty; new List<string>(); YoutubeDLProcess process = CreateYoutubeDLProcess(); output?.Report("Arguments: " + process.ConvertToArgs(new string[1] { url }, opts) + "\n"); process.OutputReceived += delegate(object o, DataReceivedEventArgs e) { Match match = rgxFile.Match(e.Data); if (match.Success) { outputFile = match.Groups[1].ToString().Trim(new char[1] { '"' }); progress?.Report(new DownloadProgress(DownloadState.Success, 0f, null, null, null, 1, outputFile)); } output?.Report(e.Data); }; var (code, errors) = await runner.RunThrottled(process, new string[1] { url }, opts, ct, progress); return new RunResult<string>(code == 0, errors, outputFile); } public async Task<RunResult<string[]>> RunAudioPlaylistDownload(string url, int? start = 1, int? end = null, int[] items = null, AudioConversionFormat format = AudioConversionFormat.Best, CancellationToken ct = default(CancellationToken), IProgress<DownloadProgress> progress = null, IProgress<string> output = null, OptionSet overrideOptions = null) { List<string> outputFiles = new List<string>(); OptionSet opts = GetDownloadOptions(); opts.NoPlaylist = false; opts.PlaylistStart = start; opts.PlaylistEnd = end; if (items != null) { opts.PlaylistItems = string.Join(",", items); } opts.Format = "bestaudio/best"; opts.ExtractAudio = true; opts.AudioFormat = format; if (overrideOptions != null) { opts = opts.OverrideOptions(overrideOptions); } YoutubeDLProcess process = CreateYoutubeDLProcess(); output?.Report("Arguments: " + process.ConvertToArgs(new string[1] { url }, opts) + "\n"); process.OutputReceived += delegate(object o, DataReceivedEventArgs e) { Match match = rgxFile.Match(e.Data); if (match.Success) { string text = match.Groups[1].ToString().Trim(new char[1] { '"' }); outputFiles.Add(text); progress?.Report(new DownloadProgress(DownloadState.Success, 0f, null, null, null, 1, text)); } output?.Report(e.Data); }; var (code, errors) = await runner.RunThrottled(process, new string[1] { url }, opts, ct, progress); return new RunResult<string[]>(code == 0, errors, outputFiles.ToArray()); } protected virtual OptionSet GetDownloadOptions() { return new OptionSet { IgnoreErrors = IgnoreDownloadErrors, IgnoreConfig = true, NoPlaylist = true, Downloader = "m3u8:native", DownloaderArgs = "ffmpeg:-nostats -loglevel 0", Output = Path.Combine(OutputFolder, OutputFileTemplate), RestrictFilenames = RestrictFilenames, ForceOverwrites = OverwriteFiles, NoOverwrites = !OverwriteFiles, NoPart = true, FfmpegLocation = Utils.GetFullPath(FFmpegPath), Progress = true, Print = "after_move:outfile: %(filepath)s" }; } private YoutubeDLProcess CreateYoutubeDLProcess() { return new YoutubeDLProcess(YoutubeDLPath) { PythonPath = PythonInterpreterPath }; } } public class YoutubeDLProcess { private static readonly Regex rgxPlaylist = new Regex("Downloading video (\\d+) of (\\d+)", RegexOptions.Compiled); private static readonly Regex rgxProgress = new Regex("\\[download\\]\\s+(?:(?<percent>[\\d\\.]+)%(?:\\s+of\\s+\\~?\\s*(?<total>[\\d\\.\\w]+))?\\s+at\\s+(?:(?<speed>[\\d\\.\\w]+\\/s)|[\\w\\s]+)\\s+ETA\\s(?<eta>[\\d\\:]+))?", RegexOptions.Compiled); private static readonly Regex rgxPost = new Regex("\\[(\\w+)\\]\\s+", RegexOptions.Compiled); public string PythonPath { get; set; } public string ExecutablePath { get; set; } public event EventHandler<DataReceivedEventArgs> OutputReceived; public event EventHandler<DataReceivedEventArgs> ErrorReceived; public YoutubeDLProcess(string executablePath = "yt-dlp.exe") { ExecutablePath = executablePath; } internal string ConvertToArgs(string[] urls, OptionSet options) { return options.ToString() + " -- " + ((urls != null) ? string.Join(" ", urls.Select((string s) => "\"" + s + "\"")) : string.Empty); } internal void RedirectToError(DataReceivedEventArgs e) { this.ErrorReceived?.Invoke(this, e); } public async Task<int> RunAsync(string[] urls, OptionSet options) { return await RunAsync(urls, options, CancellationToken.None); } public async Task<int> RunAsync(string[] urls, OptionSet options, CancellationToken ct, IProgress<DownloadProgress> progress = null) { TaskCompletionSource<int> tcs = new TaskCompletionSource<int>(); Process process = new Process(); ProcessStartInfo startInfo = new ProcessStartInfo { CreateNoWindow = true, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, StandardOutputEncoding = Encoding.UTF8, StandardErrorEncoding = Encoding.UTF8 }; if (!string.IsNullOrEmpty(PythonPath)) { startInfo.FileName = PythonPath; startInfo.Arguments = "\"" + ExecutablePath + "\" " + ConvertToArgs(urls, options); } else { startInfo.FileName = ExecutablePath; startInfo.Arguments = ConvertToArgs(urls, options); } process.EnableRaisingEvents = true; process.StartInfo = startInfo; TaskCompletionSource<bool> tcsOut = new TaskCompletionSource<bool>(); bool isDownloading = false; process.OutputDataReceived += delegate(object o, DataReceivedEventArgs e) { if (e.Data == null) { tcsOut.SetResult(result: true); } else { Match match; if ((match = rgxProgress.Match(e.Data)).Success) { if (match.Groups.Count > 1 && match.Groups[1].Length > 0) { float progress2 = float.Parse(match.Groups[1].ToString(), CultureInfo.InvariantCulture) / 100f; Group obj = match.Groups["total"]; string totalDownloadSize = (obj.Success ? obj.Value : null); Group obj2 = match.Groups["speed"]; string downloadSpeed = (obj2.Success ? obj2.Value : null); Group obj3 = match.Groups["eta"]; string eta = (obj3.Success ? obj3.Value : null); progress?.Report(new DownloadProgress(DownloadState.Downloading, progress2, totalDownloadSize, downloadSpeed, eta)); } else { progress?.Report(new DownloadProgress(DownloadState.Downloading)); } isDownloading = true; } else if ((match = rgxPlaylist.Match(e.Data)).Success) { int index = int.Parse(match.Groups[1].Value); progress?.Report(new DownloadProgress(DownloadState.PreProcessing, 0f, null, null, null, index)); isDownloading = false; } else if (isDownloading && (match = rgxPost.Match(e.Data)).Success) { progress?.Report(new DownloadProgress(DownloadState.PostProcessing, 1f)); isDownloading = false; } Debug.WriteLine("[yt-dlp] " + e.Data); this.OutputReceived?.Invoke(this, e); } }; TaskCompletionSource<bool> tcsError = new TaskCompletionSource<bool>(); process.ErrorDataReceived += delegate(object o, DataReceivedEventArgs e) { if (e.Data == null) { tcsError.SetResult(result: true); } else { Debug.WriteLine("[yt-dlp ERROR] " + e.Data); progress?.Report(new DownloadProgress(DownloadState.Error, 0f, null, null, null, 1, e.Data)); this.ErrorReceived?.Invoke(this, e); } }; process.Exited += async delegate { await tcsOut.Task; await tcsError.Task; tcs.TrySetResult(process.ExitCode); process.Dispose(); }; ct.Register(delegate { if (!tcs.Task.IsCompleted) { tcs.TrySetCanceled(); } try { if (!process.HasExited) { process.KillTree(); } } catch { } }); Debug.WriteLine("[yt-dlp] Arguments: " + process.StartInfo.Arguments); if (!(await Task.Run(() => process.Start()))) { tcs.TrySetException(new InvalidOperationException("Failed to start yt-dlp process.")); } process.BeginOutputReadLine(); process.BeginErrorReadLine(); progress?.Report(new DownloadProgress(DownloadState.PreProcessing)); return await tcs.Task; } } } namespace YoutubeDLSharp.Options { public enum DownloadMergeFormat { Unspecified, Mp4, Mkv, Ogg, Webm, Flv } public enum AudioConversionFormat { Best, Aac, Flac, Mp3, M4a, Opus, Vorbis, Wav } public enum VideoRecodeFormat { None, Mp4, Mkv, Ogg, Webm, Flv, Avi } public interface IOption { string DefaultOptionString { get; } string[] OptionStrings { get; } bool IsSet { get; } bool IsCustom { get; } void SetFromString(string s); IEnumerable<string> ToStringCollection(); } public class MultiOption<T> : IOption { private MultiValue<T> value; public string DefaultOptionString => OptionStrings.Last(); public string[] OptionStrings { get; } public bool IsSet { get; private set; } public bool IsCustom { get; } public MultiValue<T> Value { get { return value; } set { IsSet = !object.Equals(value, default(T)); this.value = value; } } public MultiOption(params string[] optionStrings) { OptionStrings = optionStrings; IsSet = false; } public MultiOption(bool isCustom, params string[] optionStrings) { OptionStrings = optionStrings; IsSet = false; IsCustom = isCustom; } public void SetFromString(string s) { string[] array = s.Split(new char[1] { ' ' }); string text = s.Substring(array[0].Length).Trim(); if (typeof(T) != typeof(StringVals)) { text = text.Trim(new char[1] { '"' }); } if (!OptionStrings.Contains(array[0])) { throw new ArgumentException("Given string does not match required format."); } T val = Utils.OptionValueFromString<T>(text); if (!IsSet) { Value = val; } else { Value.Values.Add(val); } } public override string ToString() { return string.Join(" ", ToStringCollection()); } public IEnumerable<string> ToStringCollection() { if (!IsSet) { return new string[1] { "" }; } List<string> list = new List<string>(); foreach (T value in Value.Values) { list.Add(DefaultOptionString + Utils.OptionValueToString(value)); } return list; } } public class MultiValue<T> { private readonly List<T> values; public List<T> Values => values; public MultiValue(params T[] values) { this.values = values.ToList(); } public static implicit operator MultiValue<T>(T value) { return new MultiValue<T>(value); } public static implicit operator MultiValue<T>(T[] values) { return new MultiValue<T>(values); } public static explicit operator T(MultiValue<T> value) { if (value.Values.Count == 1) { return value.Values[0]; } throw new InvalidCastException($"Cannot cast sequence of values to {typeof(T)}."); } public static explicit operator T[](MultiValue<T> value) { return value.Values.ToArray(); } } public class Option<T> : IOption { private T value; public string DefaultOptionString => OptionStrings.First(); public string[] OptionStrings { get; } public bool IsSet { get; private set; } public T Value { get { return value; } set { IsSet = !object.Equals(value, default(T)); this.value = value; } } public bool IsCustom { get; } public Option(params string[] optionStrings) { OptionStrings = optionStrings; IsSet = false; } public Option(bool isCustom, params string[] optionStrings) { OptionStrings = optionStrings; IsSet = false; IsCustom = isCustom; } public void SetFromString(string s) { string[] array = s.Split(new char[1] { ' ' }); string text = s.Substring(array[0].Length).Trim(); if (typeof(T) != typeof(StringVals)) { text = text.Trim(new char[1] { '"' }); } if (!OptionStrings.Contains(array[0])) { throw new ArgumentException("Given string does not match required format."); } Value = Utils.OptionValueFromString<T>(text); } public override string ToString() { if (!IsSet) { return string.Empty; } string text = Utils.OptionValueToString(Value); return DefaultOptionString + text; } public IEnumerable<string> ToStringCollection() { return new string[1] { ToString() }; } } internal class OptionComparer : IEqualityComparer<IOption> { public bool Equals(IOption x, IOption y) { if (x != null) { return y != null && x.ToString().Equals(y.ToString()); } return y == null; } public int GetHashCode(IOption obj) { return obj.ToString().GetHashCode(); } } public class OptionSet : ICloneable { private Option<string> username = new Option<string>("-u", "--username"); private Option<string> password = new Option<string>("-p", "--password"); private Option<string> twoFactor = new Option<string>("-2", "--twofactor"); private Option<bool> netrc = new Option<bool>("-n", "--netrc"); private Option<string> netrcLocation = new Option<string>("--netrc-location"); private Option<string> netrcCmd = new Option<string>("--netrc-cmd"); private Option<string> videoPassword = new Option<string>("--video-password"); private Option<string> apMso = new Option<string>("--ap-mso"); private Option<string> apUsername = new Option<string>("--ap-username"); private Option<string> apPassword = new Option<string>("--ap-password"); private Option<bool> apListMso = new Option<bool>("--ap-list-mso"); private Option<string> clientCertificate = new Option<string>("--client-certificate"); private Option<string> clientCertificateKey = new Option<string>("--client-certificate-key"); private Option<string> clientCertificatePassword = new Option<string>("--client-certificate-password"); private static readonly OptionComparer Comparer = new OptionComparer(); public static readonly OptionSet Default = new OptionSet(); private Option<bool> getDescription = new Option<bool>("--get-description"); private Option<bool> getDuration = new Option<bool>("--get-duration"); private Option<bool> getFilename = new Option<bool>("--get-filename"); private Option<bool> getFormat = new Option<bool>("--get-format"); private Option<bool> getId = new Option<bool>("--get-id"); private Option<bool> getThumbnail = new Option<bool>("--get-thumbnail"); private Option<bool> getTitle = new Option<bool>("-e", "--get-title"); private Option<bool> getUrl = new Option<bool>("-g", "--get-url"); private Option<string> matchTitle = new Option<string>("--match-title"); private Option<string> rejectTitle = new Option<string>("--reject-title"); private Option<long?> minViews = new Option<long?>("--min-views"); private Option<long?> maxViews = new Option<long?>("--max-views"); private Option<bool> breakOnReject = new Option<bool>("--break-on-reject"); private Option<string> userAgent = new Option<string>("--user-agent"); private Option<string> referer = new Option<string>("--referer"); private Option<int?> playlistStart = new Option<int?>("--playlist-start"); private Option<int?> playlistEnd = new Option<int?>("--playlist-end"); private Option<bool> playlistReverse = new Option<bool>("--playlist-reverse"); private Option<bool> noColors = new Option<bool>("--no-colors"); private Option<bool> forceGenericExtractor = new Option<bool>("--force-generic-extractor"); private Option<string> execBeforeDownload = new Option<string>("--exec-before-download"); private Option<bool> noExecBeforeDownload = new Option<bool>("--no-exec-before-download"); private Option<bool> allFormats = new Option<bool>("--all-formats"); private Option<bool> allSubs = new Option<bool>("--all-subs"); private Option<bool> printJson = new Option<bool>("--print-json"); private Option<string> autonumberSize = new Option<string>("--autonumber-size"); private Option<int?> autonumberStart = new Option<int?>("--autonumber-start"); private Option<bool> id = new Option<bool>("--id"); private Option<string> metadataFromTitle = new Option<string>("--metadata-from-title"); private Option<bool> hlsPreferNative = new Option<bool>("--hls-prefer-native"); private Option<bool> hlsPreferFfmpeg = new Option<bool>("--hls-prefer-ffmpeg"); private Option<bool> listFormatsOld = new Option<bool>("--list-formats-old", "--no-list-formats-as-table"); private Option<bool> listFormatsAsTable = new Option<bool>("--list-formats-as-table", "--no-list-formats-old"); private Option<bool> youtubeSkipDashManifest = new Option<bool>("--youtube-skip-dash-manifest", "--no-youtube-include-dash-manifest"); private Option<bool> youtubeSkipHlsManifest = new Option<bool>("--youtube-skip-hls-manifest", "--no-youtube-include-hls-manifest"); private Option<bool> geoBypass = new Option<bool>("--geo-bypass"); private Option<bool> noGeoBypass = new Option<bool>("--no-geo-bypass"); private Option<string> geoBypassCountry = new Option<string>("--geo-bypass-country"); private Option<string> geoBypassIpBlock = new Option<string>("--geo-bypass-ip-block"); private Option<int?> concurrentFragments = new Option<int?>("-N", "--concurrent-fragments"); private Option<long?> limitRate = new Option<long?>("-r", "--limit-rate"); private Option<long?> throttledRate = new Option<long?>("--throttled-rate"); private Option<int?> retries = new Option<int?>("-R", "--retries"); private Option<int?> fileAccessRetries = new Option<int?>("--file-access-retries"); private Option<int?> fragmentRetries = new Option<int?>("--fragment-retries"); private MultiOption<string> retrySleep = new MultiOption<string>("--retry-sleep"); private Option<bool> skipUnavailableFragments = new Option<bool>("--skip-unavailable-fragments", "--no-abort-on-unavailable-fragments"); private Option<bool> abortOnUnavailableFragments = new Option<bool>("--abort-on-unavailable-fragments", "--no-skip-unavailable-fragments"); private Option<bool> keepFragments = new Option<bool>("--keep-fragments"); private Option<bool> noKeepFragments = new Option<bool>("--no-keep-fragments"); private Option<long?> bufferSize = new Option<long?>("--buffer-size"); private Option<bool> resizeBuffer = new Option<bool>("--resize-buffer"); private Option<bool> noResizeBuffer = new Option<bool>("--no-resize-buffer"); private Option<long?> httpChunkSize = new Option<long?>("--http-chunk-size"); private Option<bool> playlistRandom = new Option<bool>("--playlist-random"); private Option<bool> lazyPlaylist = new Option<bool>("--lazy-playlist"); private Option<bool> noLazyPlaylist = new Option<bool>("--no-lazy-playlist"); private Option<bool> hlsUseMpegts = new Option<bool>("--hls-use-mpegts"); private Option<bool> noHlsUseMpegts = new Option<bool>("--no-hls-use-mpegts"); private MultiOption<string> downloadSections = new MultiOption<string>("--download-sections"); private MultiOption<string> downloader = new MultiOption<string>("--downloader", "--external-downloader"); private MultiOption<string> downloaderArgs = new MultiOption<string>("--downloader-args", "--external-downloader-args"); private Option<int?> extractorRetries = new Option<int?>("--extractor-retries"); private Option<bool> allowDynamicMpd = new Option<bool>("--allow-dynamic-mpd", "--no-ignore-dynamic-mpd"); private Option<bool> ignoreDynamicMpd = new Option<bool>("--ignore-dynamic-mpd", "--no-allow-dynamic-mpd"); private Option<bool> hlsSplitDiscontinuity = new Option<bool>("--hls-split-discontinuity"); private Option<bool> noHlsSplitDiscontinuity = new Option<bool>("--no-hls-split-discontinuity"); private MultiOption<string> extractorArgs = new MultiOption<string>("--extractor-args"); private Option<string> batchFile = new Option<string>("-a", "--batch-file"); private Option<bool> noBatchFile = new Option<bool>("--no-batch-file"); private MultiOption<string> paths = new MultiOption<string>("-P", "--paths"); private Option<string> output = new Option<string>("-o", "--output"); private Option<string> outputNaPlaceholder = new Option<string>("--output-na-placeholder"); private Option<bool> restrictFilenames = new Option<bool>("--restrict-filenames"); private Option<bool> noRestrictFilenames = new Option<bool>("--no-restrict-filenames"); private Option<bool> windowsFilenames = new Option<bool>("--windows-filenames"); private Option<bool> noWindowsFilenames = new Option<bool>("--no-windows-filenames"); private Option<int?> trimFilenames = new Option<int?>("--trim-filenames"); private Option<bool> noOverwrites = new Option<bool>("-w", "--no-overwrites"); private Option<bool> forceOverwrites = new Option<bool>("--force-overwrites"); private Option<bool> noForceOverwrites = new Option<bool>("--no-force-overwrites"); private Option<bool> doContinue = new Option<bool>("-c", "--continue"); private Option<bool> noContinue = new Option<bool>("--no-continue"); private Option<bool> part = new Option<bool>("--part"); private Option<bool> noPart = new Option<bool>("--no-part"); private Option<bool> mtime = new Option<bool>("--mtime"); private Option<bool> noMtime = new Option<bool>("--no-mtime"); private Option<bool> writeDescription = new Option<bool>("--write-description"); private Option<bool> noWriteDescription = new Option<bool>("--no-write-description"); private Option<bool> writeInfoJson = new Option<bool>("--write-info-json"); private Option<bool> noWriteInfoJson = new Option<bool>("--no-write-info-json"); private Option<bool> writePlaylistMetafiles = new Option<bool>("--write-playlist-metafiles"); private Option<bool> noWritePlaylistMetafiles = new Option<bool>("--no-write-playlist-metafiles"); private Option<bool> cleanInfoJson = new Option<bool>("--clean-info-json"); private Option<bool> noCleanInfoJson = new Option<bool>("--no-clean-info-json"); private Option<bool> writeComments = new Option<bool>("--write-comments", "--get-comments"); private Option<bool> noWriteComments = new Option<bool>("--no-write-comments", "--no-get-comments"); private Option<string> loadInfoJson = new Option<string>("--load-info-json"); private Option<string> cookies = new Option<string>("--cookies"); private Option<bool> noCookies = new Option<bool>("--no-cookies"); private Option<string> cookiesFromBrowser = new Option<string>("--cookies-from-browser"); private Option<bool> noCookiesFromBrowser = new Option<bool>("--no-cookies-from-browser"); private Option<string> cacheDir = new Option<string>("--cache-dir"); private Option<bool> noCacheDir = new Option<bool>("--no-cache-dir"); private Option<bool> removeCacheDir = new Option<bool>("--rm-cache-dir"); private Option<bool> help = new Option<bool>("-h", "--help"); private Option<bool> version = new Option<bool>("--version"); private Option<bool> update = new Option<bool>("-U", "--update"); private Option<bool> noUpdate = new Option<bool>("--no-update"); private Option<string> updateTo = new Option<string>("--update-to"); private Option<bool> ignoreErrors = new Option<bool>("-i", "--ignore-errors"); private Option<bool> noAbortOnError = new Option<bool>("--no-abort-on-error"); private Option<bool> abortOnError = new Option<bool>("--abort-on-error", "--no-ignore-errors"); private Option<bool> listExtractors = new Option<bool>("--list-extractors"); private Option<bool> extractorDescriptions = new Option<bool>("--extractor-descriptions"); private Option<string> useExtractors = new Option<string>("--use-extractors", "--ies"); private Option<string> defaultSearch = new Option<string>("--default-search"); private Option<bool> ignoreConfig = new Option<bool>("--ignore-config", "--no-config"); private Option<bool> noConfigLocations = new Option<bool>("--no-config-locations"); private MultiOption<string> configLocations = new MultiOption<string>("--config-locations"); private MultiOption<string> pluginDirs = new MultiOption<string>("--plugin-dirs"); private Option<bool> noPluginDirs = new Option<bool>("--no-plugin-dirs"); private MultiOption<string> jsRuntimes = new MultiOption<string>("--js-runtimes"); private Option<bool> noJsRuntimes = new Option<bool>("--no-js-runtimes"); private MultiOption<string> remoteComponents = new MultiOption<string>("--remote-components"); private Option<bool> noRemoteComponents = new Option<bool>("--no-remote-components"); private Option<bool> flatPlaylist = new Option<bool>("--flat-playlist"); private Option<bool> noFlatPlaylist = new Option<bool>("--no-flat-playlist"); private Option<bool> liveFromStart = new Option<bool>("--live-from-start"); private Option<bool> noLiveFromStart = new Option<bool>("--no-live-from-start"); private Option<string> waitForVideo = new Option<string>("--wait-for-video"); private Option<bool> noWaitForVideo = new Option<bool>("--no-wait-for-video"); private Option<bool> markWatched = new Option<bool>("--mark-watched"); private Option<bool> noMarkWatched = new Option<bool>("--no-mark-watched"); private MultiOption<string> color = new MultiOption<string>("--color"); private Option<string> compatOptions = new Option<string>("--compat-options"); private MultiOption<StringVals> alias = new MultiOption<StringVals>("--alias"); private MultiOption<string> presetAlias = new MultiOption<string>("-t", "--preset-alias"); private Option<string> geoVerificationProxy = new Option<string>("--geo-verification-proxy"); private Option<string> xff = new Option<string>("--xff"); private Option<bool> writeLink = new Option<bool>("--write-link"); private Option<bool> writeUrlLink = new Option<bool>("--write-url-link"); private Option<bool> writeWeblocLink = new Option<bool>("--write-webloc-link"); private Option<bool> writeDesktopLink = new Option<bool>("--write-desktop-link"); private Option<string> proxy = new Option<string>("--proxy"); private Option<int?> socketTimeout = new Option<int?>("--socket-timeout"); private Option<string> sourceAddress = new Option<string>("--source-address"); private Option<string> impersonate = new Option<string>("--impersonate"); private Option<bool> listImpersonateTargets = new Option<bool>("--list-impersonate-targets"); private Option<bool> forceIPv4 = new Option<bool>("-4", "--force-ipv4"); private Option<bool> forceIPv6 = new Option<bool>("-6", "--force-ipv6"); private Option<bool> enableFileUrls = new Option<bool>("--enable-file-urls"); private Option<bool> extractAudio = new Option<bool>("-x", "--extract-audio"); private Option<AudioConversionFormat> audioFormat = new Option<AudioConversionFormat>("--audio-format"); private Option<byte?> audioQuality = new Option<byte?>("--audio-quality"); private Option<string> remuxVideo = new Option<string>("--remux-video"); private Option<VideoRecodeFormat> recodeVideo = new Option<VideoRecodeFormat>("--recode-video"); private MultiOption<string> postprocessorArgs = new MultiOption<string>("--postprocessor-args", "--ppa"); private Option<bool> keepVideo = new Option<bool>("-k", "--keep-video"); private Option<bool> noKeepVideo = new Option<bool>("--no-keep-video"); private Option<bool> postOverwrites = new Option<bool>("--post-overwrites"); private Option<bool> noPostOverwrites = new Option<bool>("--no-post-overwrites"); private Option<bool> embedSubs = new Option<bool>("--embed-subs"); private Option<bool> noEmbedSubs = new Option<bool>("--no-embed-subs"); private Option<bool> embedThumbnail = new Option<bool>("--embed-thumbnail"); private Option<bool> noEmbedThumbnail = new Option<bool>("--no-embed-thumbnail"); private Option<bool> embedMetadata = new Option<bool>("--embed-metadata", "--add-metadata"); private Option<bool> noEmbedMetadata = new Option<bool>("--no-embed-metadata", "--no-add-metadata"); private Option<bool> embedChapters = new Option<bool>("--embed-chapters", "--add-chapters"); private Option<bool> noEmbedChapters = new Option<bool>("--no-embed-chapters", "--no-add-chapters"); private Option<bool> embedInfoJson = new Option<bool>("--embed-info-json"); private Option<bool> noEmbedInfoJson = new Option<bool>("--no-embed-info-json"); private Option<string> parseMetadata = new Option<string>("--parse-metadata"); private MultiOption<StringVals> replaceInMetadata = new MultiOption<StringVals>("--replace-in-metadata"); private Option<bool> xattrs = new Option<bool>("--xattrs"); private Option<string> concatPlaylist = new Option<string>("--concat-playlist"); private Option<string> fixup = new Option<string>("--fixup"); private Option<string> ffmpegLocation = new Option<string>("--ffmpeg-location"); private MultiOption<string> exec = new MultiOption<string>("--exec"); private Option<bool> noExec = new Option<bool>("--no-exec"); private Option<string> convertSubs = new Option<string>("--convert-subs"); private Option<string> convertThumbnails = new Option<string>("--convert-thumbnails"); private Option<bool> splitChapters = new Option<bool>("--split-chapters"); private Option<bool> noSplitChapters = new Option<bool>("--no-split-chapters"); private MultiOption<string> removeChapters = new MultiOption<string>("--remove-chapters"); private Option<bool> noRemoveChapters = new Option<bool>("--no-remove-chapters"); private Option<bool> forceKeyframesAtCuts = new Option<bool>("--force-keyframes-at-cuts"); private Option<bool> noForceKeyframesAtCuts = new Option<bool>("--no-force-keyframes-at-cuts"); private MultiOption<string> usePostprocessor = new MultiOption<string>("--use-postprocessor"); private Option<string> sponsorblockMark = new Option<string>("--sponsorblock-mark"); private Option<string> sponsorblockRemove = new Option<string>("--sponsorblock-remove"); private Option<string> sponsorblockChapterTitle = new Option<string>("--sponsorblock-chapter-title"); private Option<bool> noSponsorblock = new Option<bool>("--no-sponsorblock"); private Option<string> sponsorblockApi = new Option<string>("--sponsorblock-api"); private Option<bool> writeSubs = new Option<bool>("--write-subs"); private Option<bool> noWriteSubs = new Option<bool>("--no-write-subs"); private Option<bool> writeAutoSubs = new Option<bool>("--write-auto-subs", "--write-automatic-subs"); private Option<bool> noWriteAutoSubs = new Option<bool>("--no-write-auto-subs", "--no-write-automatic-subs"); private Option<bool> listSubs = new Option<bool>("--list-subs"); private Option<string> subFormat = new Option<string>("--sub-format"); private Option<string> subLangs = new Option<string>("--sub-langs"); private Option<bool> writeThumbnail = new Option<bool>("--write-thumbnail"); private Option<bool> noWriteThumbnail = new Option<bool>("--no-write-thumbnail"); private Option<bool> writeAllThumbnails = new Option<bool>("--write-all-thumbnails"); private Option<bool> listThumbnails = new Option<bool>("--list-thumbnails"); private Option<bool> quiet = new Option<bool>("-q", "--quiet"); private Option<bool> noQuiet = new Option<bool>("--no-quiet"); private Option<bool> noWarnings = new Option<bool>("--no-warnings"); private Option<bool> simulate = new Option<bool>("-s", "--simulate"); private Option<bool> noSimulate = new Option<bool>("--no-simulate"); private Option<bool> ignoreNoFormatsError = new Option<bool>("--ignore-no-formats-error"); private Option<bool> noIgnoreNoFormatsError = new Option<bool>("--no-ignore-no-formats-error"); private Option<bool> skipDownload = new Option<bool>("--skip-download", "--no-download"); private MultiOption<string> print = new MultiOption<string>("-O", "--print"); private MultiOption<string> printToFile = new MultiOption<string>("--print-to-file"); private Option<bool> dumpJson = new Option<bool>("-j", "--dump-json"); private Option<bool> dumpSingleJson = new Option<bool>("-J", "--dump-single-json"); private Option<bool> forceWriteArchive = new Option<bool>("--force-write-archive", "--force-download-archive"); private Option<bool> newline = new Option<bool>("--newline"); private Option<bool> noProgress = new Option<bool>("--no-progress"); private Option<bool> progress = new Option<bool>("--progress"); private Option<bool> consoleTitle = new Option<bool>("--console-title"); private Option<string> progressTemplate = new Option<string>("--progress-template"); private Option<string> progressDelta = new Option<string>("--progress-delta"); private Option<bool> verbose = new Option<bool>("-v", "--verbose"); private Option<bool> dumpPages = new Option<bool>("--dump-pages"); private Option<bool> writePages = new Option<bool>("--write-pages"); private Option<bool> printTraffic = new Option<bool>("--print-traffic"); private Option<string> format = new Option<string>("-f", "--format"); private Option<string> formatSort = new Option<string>("-S", "--format-sort"); private Option<bool> formatSortForce = new Option<bool>("--format-sort-force", "--S-force"); private Option<bool> noFormatSortForce = new Option<bool>("--no-format-sort-force"); private Option<bool> videoMultistreams = new Option<bool>("--video-multistreams"); private Option<bool> noVideoMultistreams = new Option<bool>("--no-video-multistreams"); private Option<bool> audioMultistreams = new Option<bool>("--audio-multistreams"); private Option<bool> noAudioMultistreams = new Option<bool>("--no-audio-multistreams"); private Option<bool> preferFreeFormats = new Option<bool>("--prefer-free-formats"); private Option<bool> noPreferFreeFormats = new Option<bool>("--no-prefer-free-formats"); private Option<bool> checkFormats = new Option<bool>("--check-formats"); private Option<bool> checkAllFormats = new Option<bool>("--check-all-formats"); private Option<bool> noCheckFormats = new Option<bool>("--no-check-formats"); private Option<bool> listFormats = new Option<bool>("-F", "--list-formats"); private Option<DownloadMergeFormat> mergeOutputFormat = new Option<DownloadMergeFormat>("--merge-output-format"); private Option<string> playlistItems = new Option<string>("-I", "--playlist-items"); private Option<string> minFilesize = new Option<string>("--min-filesize"); private Option<string> maxFilesize = new Option<string>("--max-filesize"); private Option<DateTime> date = new Option<DateTime>("--date"); private Option<DateTime> dateBefore = new Option<DateTime>("--datebefore"); private Option<DateTime> dateAfter = new Option<DateTime>("--dateafter"); private MultiOption<string> matchFilters = new MultiOption<string>("--match-filters"); private Option<bool> noMatchFilters = new Option<bool>("--no-match-filters"); private Option<string> breakMatchFilters = new Option<string>("--break-match-filters"); private Option<bool> noBreakMatchFilters = new Option<bool>("--no-break-match-filters"); private Option<bool> noPlaylist = new Option<bool>("--no-playlist"); private Option<bool> yesPlaylist = new Option<bool>("--yes-playlist"); private Option<byte?> ageLimit = new Option<byte?>("--age-limit"); private Option<string> downloadArchive = new Option<string>("--download-archive"); private Option<bool> noDownloadArchive = new Option<bool>("--no-download-archive"); private Option<int?> maxDownloads = new Option<int?>("--max-downloads"); private Option<bool> breakOnExisting = new Option<bool>("--break-on-existing"); private Option<bool> noBreakOnExisting = new Option<bool>("--no-break-on-existing"); private Option<bool> breakPerInput = new Option<bool>("--break-per-input"); private Option<bool> noBreakPerInput = new Option<bool>("--no-break-per-input"); private Option<int?> skipPlaylistAfterErrors = new Option<int?>("--skip-playlist-after-errors"); private Option<string> encoding = new Option<string>("--encoding"); private Option<bool> legacyServerConnect = new Option<bool>("--legacy-server-connect"); private Option<bool> noCheckCertificates = new Option<bool>("--no-check-certificates"); private Option<bool> preferInsecure = new Option<bool>("--prefer-insecure"); private MultiOption<string> addHeaders = new MultiOption<string>("--add-headers"); private Option<bool> bidiWorkaround = new Option<bool>("--bidi-workaround"); private Option<int?> sleepRequests = new Option<int?>("--sleep-requests"); private Option<int?> sleepInterval = new Option<int?>("--sleep-interval", "--min-sleep-interval"); private Option<int?> maxSleepInterval = new Option<int?>("--max-sleep-interval"); private Option<int?> sleepSubtitles = new Option<int?>("--sleep-subtitles"); public string Username { get { return username.Value; } set { username.Value = value; } } public string Password { get { return password.Value; } set { password.Value = value; } } public string TwoFactor { get { return twoFactor.Value; } set { twoFactor.Value = value; } } public bool Netrc { get { return netrc.Value; } set { netrc.Value = value; } } public string NetrcLocation { get { return netrcLocation.Value; } set { netrcLocation.Value = value; } } public string NetrcCmd { get { return netrcCmd.Value; } set { netrcCmd.Value = value; } } public string VideoPassword { get { return videoPassword.Value; } set { videoPassword.Value = value; } } public string ApMso { get { return apMso.Value; } set { apMso.Value = value; } } public string ApUsername { get { return apUsername.Value; } set { apUsername.Value = value; } } public string ApPassword { get { return apPassword.Value; } set { apPassword.Value = value; } } public bool ApListMso { get { return apListMso.Value; } set { apListMso.Value = value; } } public string ClientCertificate { get { return clientCertificate.Value; } set { clientCertificate.Value = value; } } public string ClientCertificateKey { get { return clientCertificateKey.Value; } set { clientCertificateKey.Value = value; } } public string ClientCertificatePassword { get { return clientCertificatePassword.Value; } set { clientCertificatePassword.Value = value; } } public IOption[] CustomOptions { get; set; } = new IOption[0]; [Obsolete("Deprecated in favor of: --print description.")] public bool GetDescription { get { return getDescription.Value; } set { getDescription.Value = value; } } [Obsolete("Deprecated in favor of: --print duration_string.")] public bool GetDuration { get { return getDuration.Value; } set { getDuration.Value = value; } } [Obsolete("Deprecated in favor of: --print filename.")] public bool GetFilename { get { return getFilename.Value; } set { getFilename.Value = value; } } [Obsolete("Deprecated in favor of: --print format.")] public bool GetFormat { get { return getFormat.Value; } set { getFormat.Value = value; } } [Obsolete("Deprecated in favor of: --print id.")] public bool GetId { get { return getId.Value; } set { getId.Value = value; } } [Obsolete("Deprecated in favor of: --print thumbnail.")] public bool GetThumbnail { get { return getThumbnail.Value; } set { getThumbnail.Value = value; } } [Obsolete("Deprecated in favor of: --print title.")] public bool GetTitle { get { return getTitle.Value; } set { getTitle.Value = value; } } [Obsolete("Deprecated in favor of: --print urls.")] public bool GetUrl { get { return getUrl.Value; } set { getUrl.Value = value; } } [Obsolete("Deprecated in favor of: --match-filter \"title ~= (?i)REGEX\".")] public string MatchTitle { get { return matchTitle.Value; } set { matchTitle.Value = value; } } [Obsolete("Deprecated in favor of: --match-filter \"title !~= (?i)REGEX\".")] public string RejectTitle { get { return rejectTitle.Value; } set { rejectTitle.Value = value; } } [Obsolete("Deprecated in favor of: --match-filter \"view_count >=? COUNT\".")] public long? MinViews { get { return minViews.Value; } set { minViews.Value = value; } } [Obsolete("Deprecated in favor of: --match-filter \"view_count <=? COUNT\".")] public long? MaxViews { get { return maxViews.Value; } set { maxViews.Value = value; } } [Obsolete("Deprecated in favor of: Use --break-match-filter.")] public bool BreakOnReject { get { return breakOnReject.Value; } set { breakOnReject.Value = value; } } [Obsolete("Deprecated in favor of: --add-header \"User-Agent:UA\".")] public string UserAgent { get { return userAgent.Value; } set { userAgent.Value = value; } } [Obsolete("Deprecated in favor of: --add-header \"Referer:URL\".")] public string Referer { get { return referer.Value; } set { referer.Value = value; } } [Obsolete("Deprecated in favor of: -I NUMBER:.")] public int? PlaylistStart { get { return playlistStart.Value; } set { playlistStart.Value = value; } } [Obsolete("Deprecated in favor of: -I :NUMBER.")] public int? PlaylistEnd { get { return playlistEnd.Value; } set { playlistEnd.Value = value; } } [Obsolete("Deprecated in favor of: -I ::-1.")] public bool PlaylistReverse { get { return playlistReverse.Value; } set { playlistReverse.Value = value; } } [Obsolete("Deprecated in favor of: --color no_color.")] public bool NoColors { get { return noColors.Value; } set { noColors.Value = value; } } [Obsolete("Deprecated in favor of: --ies generic,default.")] public bool ForceGenericExtractor { get { return forceGenericExtractor.Value; } set { forceGenericExtractor.Value = value; } } [Obsolete("Deprecated in favor of: --exec \"before_dl:CMD\".")] public string ExecBeforeDownload { get { return execBeforeDownload.Value; } set { execBeforeDownload.Value = value; } } [Obsolete("Deprecated in favor of: --no-exec.")] public bool NoExecBeforeDownload { get { return noExecBeforeDownload.Value; } set { noExecBeforeDownload.Value = value; } } [Obsolete("Deprecated in favor of: -f all.")] public bool AllFormats { get { return allFormats.Value; } set { allFormats.Value = value; } } [Obsolete("Deprecated in favor of: --sub-langs all --write-subs.")] public bool AllSubs { get { return allSubs.Value; } set { allSubs.Value = value; } } [Obsolete("Deprecated in favor of: -j --no-simulate.")] public bool PrintJson { get { return printJson.Value; } set { printJson.Value = value; } } [Obsolete("Deprecated in favor of: Use string formatting, e.g. %(autonumber)03d.")] public string AutonumberSize { get { return autonumberSize.Value; } set { autonumberSize.Value = value; } } [Obsolete("Deprecated in favor of: Use internal field formatting like %(autonumber+NUMBER)s.")] public int? AutonumberStart { get { return autonumberStart.Value; } set { autonumberStart.Value = value; } } [Obsolete("Deprecated in favor of: -o \"%(id)s.%(ext)s\".")] public bool Id { get { return id.Value; } set { id.Value = value; } } [Obsolete("Deprecated in favor of: --parse-metadata \"%(title)s:FORMAT\".")] public string MetadataFromTitle { get { return metadataFromTitle.Value; } set { metadataFromTitle.Value = value; } } [Obsolete("Deprecated in favor of: --downloader \"m3u8:native\".")] public bool HlsPreferNative { get { return hlsPreferNative.Value; } set { hlsPreferNative.Value = value; } } [Obsolete("Deprecated in favor of: --downloader \"m3u8:ffmpeg\".")] public bool HlsPreferFfmpeg { get { return hlsPreferFfmpeg.Value; } set { hlsPreferFfmpeg.Value = value; } } [Obsolete("Deprecated in favor of: --compat-options list-formats (Alias: --no-list-formats-as-table).")] public bool ListFormatsOld { get { return listFormatsOld.Value; } set { listFormatsOld.Value = value; } } [Obsolete("Deprecated in favor of: --compat-options -list-formats [Default] (Alias: --no-list-formats-old).")] public bool ListFormatsAsTable { get { return listFormatsAsTable.Value; } set { listFormatsAsTable.Value = value; } } [Obsolete("Deprecated in favor of: --extractor-args \"youtube:skip=dash\" (Alias: --no-youtube-include-dash-manifest).")] public bool YoutubeSkipDashManifest { get { return youtubeSkipDashManifest.Value; } set { youtubeSkipDashManifest.Value = value; } } [Obsolete("Deprecated in favor of: --extractor-args \"youtube:skip=hls\" (Alias: --no-youtube-include-hls-manifest).")] public bool YoutubeSkipHlsManifest { get { return youtubeSkipHlsManifest.Value; } set { youtubeSkipHlsManifest.Value = value; } } [Obsolete("Deprecated in favor of: --xff \"default\".")] public bool GeoBypass { get { return geoBypass.Value; } set { geoBypass.Value = value; } } [Obsolete("Deprecated in favor of: --xff \"never\".")] public bool NoGeoBypass { get { return noGeoBypass.Value; } set { noGeoBypass.Value = value; } } [Obsolete("Deprecated in favor of: --xff CODE.")] public string GeoBypassCountry { get { return geoBypassCountry.Value; } set { geoBypassCountry.Value = value; } } [Obsolete("Deprecated in favor of: --xff IP_BLOCK.")] public string GeoBypassIpBlock { get { return geoBypassIpBlock.Value; } set { geoBypassIpBlock.Value = value; } } public int? ConcurrentFragments { get { return concurrentFragments.Value; } set { concurrentFragments.Value = value; } } public long? LimitRate { get { return limitRate.Value; } set { limitRate.Value = value; } } public long? ThrottledRate { get { return throttledRate.Value; } set { throttledRate.Value = value; } } public int? Retries { get { return retries.Value; } set { retries.Value = value; } } public int? FileAccessRetries { get { return fileAccessRetries.Value; } set { fileAccessRetries.Value = value; } } public int? FragmentRetries { get { return fragmentRetries.Value; } set { fragmentRetries.Value = value; } } public MultiValue<string> RetrySleep { get { return retrySleep.Value; } set { retrySleep.Value = value; } } public bool SkipUnavailableFragments { get { return skipUnavailableFragments.Value; } set { skipUnavailableFragments.Value = value; } } public bool AbortOnUnavailableFragments { get { return abortOnUnavailableFragments.Value; } set { abortOnUnavailableFragments.Value = value; } } public bool KeepFragments { get { return keepFragments.Value; } set { keepFragments.Value = value; } } public bool NoKeepFragments { get { return noKeepFragments.Value; } set { noKeepFragments.Value = value; } } public long? BufferSize { get { return bufferSize.Value; } set { bufferSize.Value = value; } } public bool ResizeBuffer { get { return resizeBuffer.Value; } set { resizeBuffer.Value = value; } } public bool NoResizeBuffer { get { return noResizeBuffer.Value; } set { noResizeBuffer.Value = value; } } public long? HttpChunkSize { get { return httpChunkSize.Value; } set { httpChunkSize.Value = value; } } public bool PlaylistRandom { get { return playlistRandom.Value; } set { playlistRandom.Value = value; } } public bool LazyPlaylist { get { return lazyPlaylist.Value; } set { lazyPlaylist.Value = value; } } public bool NoLazyPlaylist { get { return noLazyPlaylist.Value; } set { noLazyPlaylist.Value = value; } } public bool HlsUseMpegts { get { return hlsUseMpegts.Value; } set { hlsUseMpegts.Value = value; } } public bool NoHlsUseMpegts { get { return noHlsUseMpegts.Value; } set { noHlsUseMpegts.Value = value; } } public MultiValue<string> DownloadSections { get { return downloadSections.Value; } set { downloadSections.Value = value; } } public MultiValue<string> Downloader { get { return downloader.Value; } set { downloader.Value = value; } } public MultiValue<string> DownloaderArgs { get { return downloaderArgs.Value; } set { downloaderArgs.Value = value; } } public int? ExtractorRetries { get { return extractorRetries.Value; } set { extractorRetries.Value = value; } } public bool AllowDynamicMpd { get { return allowDynamicMpd.Value; } set { allowDynamicMpd.Value = value; } } public bool IgnoreDynamicMpd { get { return ignoreDynamicMpd.Value; } set { ignoreDynamicMpd.Value = value; } } public bool HlsSplitDiscontinuity { get { return hlsSplitDiscontinuity.Value; } set { hlsSplitDiscontinuity.Value = value; } } public bool NoHlsSplitDiscontinuity { get { return noHlsSplitDiscontinuity.Value; } set { noHlsSplitDiscontinuity.Value = value; } } public MultiValue<string> ExtractorArgs { get { return extractorArgs.Value; } set { extractorArgs.Value = value; } } public string BatchFile { get { return batchFile.Value; } set { batchFile.Value = value; } } public bool NoBatchFile { get { return noBatchFile.Value; } set { noBatchFile.Value = value; } } public MultiValue<string> Paths { get { return paths.Value; } set { paths.Value = value; } } public string Output { get { return output.Value; } set { output.Value = value; } } public string OutputNaPlaceholder { get { return outputNaPlaceholder.Value; } set { outputNaPlaceholder.Value = value; } } public bool RestrictFilenames { get { return restrictFilenames.Value; } set { restrictFilenames.Value = value; } } public bool NoRestrictFilenames { get { return noRestrictFilenames.Value; } set { noRestrictFilenames.Value = value; } } public bool WindowsFilenames { get { return windowsFilenames.Value; } set { windowsFilenames.Value = value; } } public bool NoWindowsFilenames { get { return noWindowsFilenames.Value; } set { noWindowsFilenames.Value = value; } } public int? TrimFilenames { get { return trimFilenames.Value; } set { trimFilenames.Value = value; } } public bool NoOverwrites { get { return noOverwrites.Value; } set { noOverwrites.Value = value; } } public bool ForceOverwrites { get { return forceOverwrites.Value; } set { forceOverwrites.Value = value; } } public bool NoForceOverwrites { get { return noForceOverwrites.Value; } set { noForceOverwrites.Value = value; } } public bool Continue { get { return doContinue.Value; } set { doContinue.Value = value; } } public bool NoContinue { get { return noContinue.Value; } set { noContinue.Value = value; } } public bool Part { get { return part.Value; } set { part.Value = value; } } public bool NoPart { get { return noPart.Value; } set { noPart.Value = value; } } public bool Mtime { get { return mtime.Value; } set { mtime.Value = value; } } public bool NoMtime { get { return noMtime.Value; } set { noMtime.Value = value; } } public bool WriteDescription { get { return writeDescription.Value; } set { writeDescription.Value = value; } } public bool NoWriteDescription { get { return noWriteDescription.Value; } set { noWriteDescription.Value = value; } } public bool WriteInfoJson { get { return writeInfoJson.Value; } set { writeInfoJson.Value = value; } } public bool NoWriteInfoJson { get { return noWriteInfoJson.Value; } set { noWriteInfoJson.Value = value; } } public bool WritePlaylistMetafiles { get { return writePlaylistMetafiles.Value; } set { writePlaylistMetafiles.Value = value; } } public bool NoWritePlaylistMetafiles { get { return noWritePlaylistMetafiles.Value; } set { noWritePlaylistMetafiles.Value = value; } } public bool CleanInfoJson { get { return cleanInfoJson.Value; } set { cleanInfoJson.Value = value; } } public bool NoCleanInfoJson { get { return noCleanInfoJson.Value; } set { noCleanInfoJson.Value = value; } } public bool WriteComments { get { return writeComments.Value; } set { writeComments.Value = value; } } public bool NoWriteComments { get { return noWriteComments.Value; } set { noWriteComments.Value = value; } } public string LoadInfoJson { get { return loadInfoJson.Value; } set { loadInfoJson.Value = value; } } public string Cookies { get { return cookies.Value; } set { cookies.Value = value; } } public bool NoCookies { get { return noCookies.Value; } set { noCookies.Value = value; } } public string CookiesFromBrowser { get { return cookiesFromBrowser.Value; } set { cookiesFromBrowser.Value = value; } } public bool NoCookiesFromBrowser { get { return noCookiesFromBrowser.Value; } set { noCookiesFromBrowser.Value = value; } } public string CacheDir { get { return cacheDir.Value; } set { cacheDir.Value = value; } } public bool NoCacheDir { get { return noCacheDir.Value; } set { noCacheDir.Value = value; } } public bool RemoveCacheDir { get { return removeCacheDir.Value; } set { removeCacheDir.Value = value; } } public bool Help { get { return help.Value; } set { help.Value = value; } } public bool Version { get { return version.Value; } set { version.Value = value; } } public bool Update { get { return update.Value; } set { update.Value = value; } } public bool NoUpdate { get { return noUpdate.Value; } set { noUpdate.Value = value; } } public string UpdateTo { get { return updateTo.Value; } set { updateTo.Value = value; } } public bool IgnoreErrors { get { return ignoreErrors.Value; } set { ignoreErrors.Value = value; } } public bool NoAbortOnError { get { return noAbortOnError.Value; } set { noAbortOnError.Value = value; } } public bool AbortOnError { get { return abortOnError.Value; } set { abortOnError.Value = value; } } public bool ListExtractors { get { return listExtractors.Value; } set { listExtractors.Value = value; } } public bool ExtractorDescriptions { get { return extractorDescriptions.Value; } set { extractorDescriptions.Value = value; } } public string UseExtractors { get { return useExtractors.Value; } set { useExtractors.Value = value; } } public string DefaultSearch { get { return defaultSearch.Value; } set { defaultSearch.Value = value; } } public bool IgnoreConfig { get { return ignoreConfig.Value; } set { ignoreConfig.Value = value; } } public bool NoConfigLocations { get { return noConfigLocations.Value; } set { noConfigLocations.Value = value; } } public MultiValue<string> ConfigLocations { get { return configLocations.Value; } set { configLocations.Value = value; } } public MultiValue<string> PluginDirs { get { return pluginDirs.Value; } set { pluginDirs.Value = value; } } public bool NoPluginDirs { get { return noPluginDirs.Value; } set { noPluginDirs.Value = value; } } public MultiValue<string> JsRuntimes { get { return jsRuntimes.Value; } set { jsRuntimes.Value = value; } } public bool NoJsRuntimes { get { return noJsRuntimes.Value; } set { noJsRuntimes.Value = value; } } public MultiValue<string> RemoteComponents { get { return remoteComponents.Value; } set { remoteComponents.Value = value; } } public bool NoRemoteComponents { get { return noRemoteComponents.Value; } set { noRemoteComponents.Value = value; } } public bool FlatPlaylist { get { return flatPlaylist.Value; } set { flatPlaylist.Value = value; } } public bool NoFlatPlaylist { get { return noFlatPlaylist.Value; } set { noFlatPlaylist.Value = value; } } public bool LiveFromStart { get { return liveFromStart.Value; } set { liveFromStart.Value = value; } } public bool NoLiveFromStart { get { return noLiveFromStart.Value; } set { noLiveFromStart.Value = value; } } public string WaitForVideo { get { return waitForVideo.Value; } set { waitForVideo.Value = value; } } public bool NoWaitForVideo { get { return noWaitForVideo.Value; } set { noWaitForVideo.Value = value; } } public bool MarkWatched { get { return markWatched.Value; } set { markWatched.Value = value; } } public bool NoMarkWatched { get { return noMarkWatched.Value; } set { noMarkWatched.Value = value; } } public MultiValue<string> Color { get { return color.Value; } set { color.Value = value; } } public string CompatOptions { get { return compatOptions.Value; } set { compatOptions.Value = value; } } public MultiValue<StringVals> Alias { get { return alias.Value; } set { alias.Value = value; } } public MultiValue<string> PresetAlias { get { return presetAlias.Value; } set { presetAlias.Value = value; } } public string GeoVerificationProxy { get { return geoVerificationProxy.Value; } set { geoVerificationProxy.Value = value; } } public string Xff { get { return xff.Value; } set { xff.Value = value; } } public bool WriteLink { get { return writeLink.Value; } set { writeLink.Value = value; } } public bool WriteUrlLink { get { return writeUrlLink.Value; } set { writeUrlLink.Value = value; } } public bool WriteWeblocLink { get { return writeWeblocLink.Value; } set { writeWeblocLink.Value = value; } } public bool WriteDesktopLink { get { return writeDesktopLink.Value; } set { writeDesktopLink.Value = value; } } public string Proxy { get { return proxy.Value; } set { proxy.Value = value; } } public int? SocketTimeout { get { return socketTimeout.Value; } set { socketTimeout.Value = value; } } public string SourceAddress { get { return sourceAddress.Value; } set { sourceAddress.Value = value; } } public string Impersonate { get { return impersonate.Value; } set { impersonate.Value = value; } } public bool ListImpersonateTargets { get { return listImpersonateTargets.Value; } set { listImpersonateTargets.Value = value; } } public bool ForceIPv4 { get { return forceIPv4.Value; } set { forceIPv4.Value = value; } } public bool ForceIPv6 { get { return forceIPv6.Value; } set { forceIPv6.Value = value; } } public bool EnableFileUrls { get { return enableFileUrls.Value; } set { enableFileUrls.Value = value; } } public bool ExtractAudio { get { return extractAudio.Value; } set { extractAudio.Value = value; } } public AudioConversionFormat AudioFormat { get { return audioFormat.Value; } set { audioFormat.Value = value; } } public byte? AudioQuality { get { return audioQuality.Value; } set { audioQuality.Value = value; } } public string RemuxVideo { get { return remuxVideo.Value; } set { remuxVideo.Value = value; } } public VideoRecodeFormat RecodeVideo { get { return recodeVideo.Value; } set { recodeVideo.Value = value; } } public MultiValue<string> PostprocessorArgs { get { return postprocessorArgs.Value; } set { postprocessorArgs.Value = value; } } public bool KeepVideo { get { return keepVideo.Value; } set { keepVideo.Value = value; } } public bool NoKeepVideo { get { return noKeepVideo.Value; } set { noKeepVideo.Value = value; } } public bool PostOverwrites { get { return postOverwrites.Value; } set { postOverwrites.Value = value; } } public bool NoPostOverwrites { get { return noPostOverwrites.Value; } set { noPostOverwrites.Value = value; } } public bool EmbedSubs { get { return embedSubs.Value; } set { embedSubs.Value = value; } } public bool NoEmbedSubs { get { return noEmbedSubs.Value; } set { noEmbedSubs.Value = value; } } public bool EmbedThumbnail { get { return embedThumbnail.Value; } set { embedThumbnail.Value = value; } } public bool NoEmbedThumbnail { get { return noEmbedThumbnail.Value; } set { noEmbedThumbnail.Value = value; } } public bool EmbedMetadata { get { return embedMetadata.Value; } set { embedMetadata.Value = value; } } public bool NoEmbedMetadata { get { return noEmbedMetadata.Value; } set { noEmbedMetadata.Value = value; } } public bool EmbedChapters { get { return embedChapters.Value; } set { embedChapters.Value = value; } } public bool NoEmbedChapters { get { return noEmbedChapters.Value; } set { noEmbedChapters.Value = value; } } public bool EmbedInfoJson { get { return embedInfoJson.Value; } set { embedInfoJson.Value = value; } } public bool NoEmbedInfoJson { get { return noEmbedInfoJson.Value; } set { noEmbedInfoJson.Value = value; } } public string ParseMetadata { get { return parseMetadata.Value; } set { parseMetadata.Value = value; } } public MultiValue<StringVals> ReplaceInMetadata { get { return replaceInMetadata.Value; } set { replaceInMetadata.Value = value; } } public bool Xattrs { get { return xattrs.Value; } set { xattrs.Value = value; } } public string ConcatPlaylist { get { return concatPlaylist.Value; } set { concatPlaylist.Value = value; } } public string Fixup { get { return fixup.Value; } set { fixup.Value = value; } } public string FfmpegLocation { get { return ffmpegLocation.Value; } set { ffmpegLocation.Value = value; } } public MultiValue<string> Exec { get { return exec.Value; } set { exec.Value = value; } } public bool NoExec { get { return noExec.Value; } set { noExec.Value = value; } } public string ConvertSubs { get { return convertSubs.Value; } set { convertSubs.Value = value; } } public string ConvertThumbnails { get { return convertThumbnails.Value; } set { convertThumbnails.Value = value; } } public bool SplitChapters { get { return splitChapters.Value; } set { splitChapters.Value = value; } } public bool NoSplitChapters { get { return noSplitChapters.Value; } set { noSplitChapters.Value = value; } } public MultiValue<string> RemoveChapters { get { return removeChapters.Value; } set { removeChapters.Value = value; } } public bool NoRemoveChapters { get { return noRemoveChapters.Value; } set { noRemoveChapters.Value = value; } } public bool ForceKeyframesAtCuts { get { return forceKeyframesAtCuts.Value; } set { forceKeyframesAtCuts.Value = value; } } public bool NoForceKeyframesAtCuts { get { return noForceKeyframesAtCuts.Value; } set { noForceKeyframesAtCuts.Value = value; } } public MultiValue<string> UsePostprocessor { get { return usePostprocessor.Value; } set { usePostprocessor.Value = value; } } public string SponsorblockMark { get { return sponsorblockMark.Value; } set { sponsorblockMark.Value = value; } } public string SponsorblockRemove { get { return sponsorblockRemove.Value; } set { sponsorblockRemove.Value = value; } } public string SponsorblockChapterTitle { get { return sponsorblockChapterTitle.Value; } set { sponsorblockChapterTitle.Value = value; } } public bool NoSponsorblock { get { return noSponsorblock.Value; } set { noSponsorblock.Value = value; } } public string SponsorblockApi { get { return sponsorblockApi.Value; } set { sponsorblockApi.Value = value; } } public bool WriteSubs { get { return writeSubs.Value; } set { writeSubs.Value = value; } } public bool NoWriteSubs { get { return noWriteSubs.Value; } set { noWriteSubs.Value = value; } } public bool WriteAutoSubs { get { return writeAutoSubs.Value; } set { writeAutoSubs.Value = value; } } public bool NoWriteAutoSubs { get { return noWriteAutoSubs.Value; } set { noWriteAutoSubs.Value = value; } } public bool ListSubs { get { return listSubs.Value; } set { listSubs.Value = value; } } public string SubFormat { get { return subFormat.Value; } set { subFormat.Value = value; } } public string SubLangs { get { return subLangs.Value; } set { subLangs.Value = value; } } public bool WriteThumbnail { get { return writeThumbnail.Value; } set { writeThumbnail.Value = value; } } public bool NoWriteThumbnail { get { return noWriteThumbnail.Value; } set { noWriteThumbnail.Value = value; } } public bool WriteAllThumbnails { get { return writeAllThumbnails.Value; } set { writeAllThumbnails.Value = value; } } public bool ListThumbnails { get { return listThumbnails.Value; } set { listThumbnails.Value = value; } } public bool Quiet { get { return quiet.Value; } set { quiet.Value = value; } } public bool NoQuiet { get { return noQuiet.Value; } set { noQuiet.Value = value; } } public bool NoWarnings { get { return noWarnings.Value; } set { noWarnings.Value = value; } } public bool Simulate { get { return simulate.Value; } set { simulate.Value = value; } } public bool NoSimulate { get { return noSimulate.Value; } set { noSimulate.Value = value; } } public bool IgnoreNoFormatsError { get { return ignoreNoFormatsError.Value; } set { ignoreNoFormatsError.Value = value; } } public bool NoIgnoreNoFormatsError { get { return noIgnoreNoFormatsError.Value; } set { noIgnoreNoFormatsError.Value = value; } } public bool SkipDownload { get { return skipDownload.Value; } set { skipDownload.Value = value; } } public MultiValue<string> Print { get { return print.Value; } set { print.Value = value; } } public MultiValue<string> PrintToFile { get { return printToFile.Value; } set { printToFile.Value = value; } } public bool DumpJson { get { return dumpJson.Value; } set { dumpJson.Value = value; } } public bool DumpSingleJson { get { return dumpSingleJson.Value; } set { dumpSingleJson.Value = value; } } public bool ForceWriteArchive { get { return forceWriteArchive.Value; } set { forceWriteArchive.Value = value; } } public bool Newline { get { return newline.Value; } set { newline.Value = value; } } public bool NoProgress { get { return noProgress.Value; } set { noProgress.Value = value; } } public bool Progress { get { return progress.Value; } set { progress.Value = value; } } public bool ConsoleTitle { get { return consoleTitle.Value; } set { consoleTitle.Value = value; } } public string ProgressTemplate { get { return progressTemplate.Value; } set { progressTemplate.Value = value; } } public string ProgressDelta { get { return progressDelta.Value; } set { progressDelta.Value = value; } } public bool Verbose { get { return verbose.Value; } set { verbose.Value = value; } } public bool DumpPages { get { return dumpPages.Value; } set { dumpPages.Value = value; } } public bool WritePages { get { return writePages.Value; } set { writePages.Value = value; } } public bool PrintTraffic { get { return printTraffic.Value; } set { printTraffic.Value = value; } } public string Format { get { return format.Value; } set { format.Value = value; } } public string FormatSort { get { return formatSort.Value; } set { formatSort.Value = value; } } public bool FormatSortForce { get { return formatSortForce.Value; } set { formatSortForce.Value = value; } } public bool NoFormatSortForce { get { return noFormatSortForce.Value; } set { noFormatSortForce.Value = value; } } public bool VideoMultistreams { get { return videoMultistreams.Value; } set { videoMultistreams.Value = value; } } public bool NoVideoMultistreams { get { return noVideoMultistreams.Value; } set { noVideoMultistreams.Value = value; } } public bool AudioMultistreams { get { return audioMultistreams.Value; } set { audioMultistreams.Value = value; } } public bool NoAudioMultistreams { get { return noAudioMultistreams.Value; } set { noAudioMultistreams.Value = value; } } public bool PreferFreeFormats { get { return preferFreeFormats.Value; } set { preferFreeFormats.Value = value; } } public bool NoPreferFreeFormats { get { return noPreferFreeFormats.Value; } set { noPreferFreeFormats.Value = value; } } public bool CheckFormats { get { return checkFormats.Value; } set { checkFormats.Value = value; } } public bool CheckAllFormats { get { return checkAllFormats.Value; } set { checkAllFormats.Value = value; } } public bool NoCheckFormats { get { return noCheckFormats.Value; } set { noCheckFormats.Value = value; } } public bool ListFormats { get { return listFormats.Value; } set { listFormats.Value = value; } } public DownloadMergeFormat MergeOutputFormat { get { return mergeOutputFormat.Value; } set { mergeOutputFormat.Value = value; } } public string PlaylistItems { get { return playlistItems.Value; } set { playlistItems.Value = value; } } public string MinFilesize { get { return minFilesize.Value; } set { minFilesize.Value = value; } } public string MaxFilesize { get { return maxFilesize.Value; } set { maxFilesize.Value = value; } } public DateTime Date { get { return date.Value; } set { date.Value = value; } } public DateTime DateBefore { get { return dateBefore.Value; } set { dateBefore.Value = value; } } public DateTime DateAfter { get { return dateAfter.Value; } set { dateAfter.Value = value; } } public MultiValue<string> MatchFilters { get { return matchFilters.Value; } set { matchFilters.Value = value; } } public bool NoMatchFilters { get { return noMatchFilters.Value; } set { noMatchFilters.Value = value; } } public string BreakMatchFilters { get { return breakMatchFilters.Value; } set { breakMatchFilters.Value = value; } } public bool NoBreakMatchFilters { get { return noBreakMatchFilters.Value; } set { noBreakMatchFilters.Value = value; } } public bool NoPlaylist { get { return noPlaylist.Value; } set { noPlaylist.Value = value; } } public bool YesPlaylist { get { return yesPlaylist.Value; } set { yesPlaylist.Value = value; } } public byte? AgeLimit { get { return ageLimit.Value; } set { ageLimit.Value = value; } } public string DownloadArchive { get { return downloadArchive.Value; } set { downloadArchive.Value = value; } } public bool NoDownloadArchive { get { return noDownloadArchive.Value; } set { noDownloadArchive.Value = value; } } public int? MaxDownloads { get { return maxDownloads.Value; } set { maxDownloads.Value = value; } } public bool BreakOnExisting { get { return breakOnExisting.Value; } set { breakOnExisting.Value = value; } } public bool NoBreakOnExisting { get { return noBreakOnExisting.Value; } set { noBreakOnExisting.Value = value; } } public bool BreakPerInput { get { return breakPerInput.Value; } set { breakPerInput.Value = value; } } public bool NoBreakPerInput { get { return noBreakPerInput.Value; } set { noBreakPerInput.Value = value; } } public int? SkipPlaylistAfterErrors { get { return skipPlaylistAfterErrors.Value; } set { skipPlaylistAfterErrors.Value = value; } } public string Encoding { get { return encoding.Value; } set { encoding.Value = value; } } public bool LegacyServerConnect { get { return legacyServerConnect.Value; } set { legacyServerConnect.Value = value; } } public bool NoCheckCertificates { get { return noCheckCertificates.Value; } set { noCheckCertificates.Value = value; } } public bool PreferInsecure { get { return preferInsecure.Value; } set { preferInsecure.Value = value; } } public MultiValue<string> AddHeaders { get { return addHeaders.Value; } set { addHeaders.Value = value; } } public bool BidiWorkaround { get { return bidiWorkaround.Value; } set { bidiWorkaround.Value = value; } } public int? SleepRequests { get { return sleepRequests.Value; } set { sleepRequests.Value = value; } } public int? SleepInterval { get { return sleepInterval.Value; } set { sleepInterval.Value = value; } } public int? MaxSleepInterval { get { return maxSleepInterval.Value; } set { maxSleepInterval.Value = value; } } public int? SleepSubtitles { get { return sleepSubtitles.Value; } set { sleepSubtitles.Value = value; } } public void WriteConfigFile(string path) { File.WriteAllLines(path, GetOptionFlags()); } public override string ToString() { return " " + string.Join(" ", GetOptionFlags()); } public IEnumerable<string> GetOptionFlags() { return from value in GetKnownOptions().Concat(CustomOptions).SelectMany((IOption opt) => opt.ToStringCollection()) where !string.IsNullOrWhiteSpace(value) select value; } internal IEnumerable<IOption> GetKnownOptions() { return (from p in GetType().GetRuntimeFields() where p.FieldType.IsGenericType && p.FieldType.GetInterfaces().Contains<Type>(typeof(IOption)) select p.GetValue(this)).Cast<IOption>(); } public OptionSet OverrideOptions(OptionSet overrideOptions, bool forceOverride = false) { OptionSet optionSet = (OptionSet)Clone(); optionSet.CustomOptions = optionSet.CustomOptions.Concat(overrideOptions.CustomOptions).Distinct(Comparer).ToArray(); IEnumerable<FieldInfo> enumerable = from p in overrideOptions.GetType().GetRuntimeFields() where p.FieldType.IsGenericType && p.FieldType.GetInterfaces().Contains<Type>(typeof(IOption)) select p; foreach (FieldInfo item in enumerable) { IOption option = (IOption)item.GetValue(overrideOptions); if (forceOverride || option.IsSet) { optionSet.GetType().GetField(item.Name, BindingFlags.Instance | BindingFlags.NonPublic).SetValue(optionSet, option); } } return optionSet; } public static OptionSet FromString(IEnumerable<string> lines) { OptionSet optionSet = new OptionSet(); IOption[] customOptions = (from option in GetOptions(lines, optionSet.GetKnownOptions()) where option.IsCustom select option).ToArray(); optionSet.CustomOptions = customOptions; return optionSet; } private static IEnumerable<IOption> GetOptions(IEnumerable<string> lines, IEnumerable<IOption> options) { IEnumerable<IOption> knownOptions = options.ToList(); foreach (string rawLine in lines) { string line = rawLine.Trim(); if (!line.StartsWith("#") && !string.IsNullOrWhiteSpace(line)) { string[] segments = line.Split(new char[1] { ' ' }); string flag =
BepInEx/patchers/DLSharpVulnerabilityYeeter.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using Microsoft.CodeAnalysis; using Mono.Cecil; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Lordfirespeed")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.2.0.0")] [assembly: AssemblyInformationalVersion("1.2.0+86949898c089cf895e8aae40de91066de8849db3")] [assembly: AssemblyProduct("DLSharpVulnerabilityYeeter")] [assembly: AssemblyTitle("DLSharpVulnerabilityYeeter")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Lordfirespeed/YoutubeDLSharpThunderstore")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace VulnerabilityYeeter { public static class VulnerabilityYeeter { internal static ManualLogSource Logger = Logger.CreateLogSource("DLSharpVulnerabilityYeeter"); internal static readonly DateTime YtDlpVulnerableBefore = new DateTime(2026, 8, 28, 0, 0, 0); public static IEnumerable<string> TargetDLLs { get; } = Array.Empty<string>(); public static void Initialize() { Logger.LogInfo((object)"Hello!"); string[] files = Directory.GetFiles(Paths.BepInExRootPath, "yt-dlp*", SearchOption.AllDirectories); string[] array = files; foreach (string text in array) { Logger.LogInfo((object)("Considering " + text + " ...")); DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(text); if (!(lastWriteTimeUtc >= YtDlpVulnerableBefore)) { Logger.LogWarning((object)$"Deleting {text} as it is older than {YtDlpVulnerableBefore:yyyy-MM-dd} and thus may be vulnerable."); File.Delete(text); } } } public static void Patch(AssemblyDefinition assembly) { } public static void Finish() { Logger.LogInfo((object)"Goodbye!"); } } }