#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-2024 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.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0+febe9e5d0ffbe54055cac081271280501bd308d4")]
[assembly: AssemblyProduct("YoutubeDLSharp")]
[assembly: AssemblyTitle("YoutubeDLSharp")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Lordfirespeed/YoutubeDLSharpThunderstore")]
[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 HttpClient _client = new HttpClient();
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);
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 = "")
{
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);
}
}
else
{
await DownloadYtDlp(directoryPath);
await DownloadFFmpeg(directoryPath);
await DownloadFFprobe(directoryPath);
}
}
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"),
};
}
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");
}
}
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));
}
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 async Task FFDownloader(string directoryPath = "", FFmpegApi.BinaryType binary = FFmpegApi.BinaryType.FFmpeg)
{
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);
using MemoryStream stream = new MemoryStream(await DownloadFileBytesAsync(downloadUrl));
using ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read);
if (archive.Entries.Count > 0)
{
archive.Entries[0].ExtractToFile(Path.Combine(directoryPath, archive.Entries[0].FullName), overwrite: true);
}
}
private static async Task<byte[]> DownloadFileBytesAsync(string uri)
{
if (!Uri.TryCreate(uri, UriKind.Absolute, out Uri _))
{
throw new InvalidOperationException("URI is invalid.");
}
return await _client.GetByteArrayAsync(uri);
}
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),
Exec = "echo outfile: {}"
};
}
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 bool UseWindowsEncodingWorkaround { get; set; } = true;
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 (OSHelper.IsWindows && UseWindowsEncodingWorkaround)
{
startInfo.FileName = "cmd.exe";
string runCommand = (string.IsNullOrEmpty(PythonPath) ? ("\"" + ExecutablePath + "\" " + ConvertToArgs(urls, options)) : ("\"" + PythonPath + "\" \"" + ExecutablePath + "\" " + ConvertToArgs(urls, options)));
startInfo.Arguments = "/C chcp 65001 >nul 2>&1 && " + runCommand;
}
else 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 group = match.Groups["total"];
string totalDownloadSize = (group.Success ? group.Value : null);
Group group2 = match.Groups["speed"];
string downloadSpeed = (group2.Success ? group2.Value : null);
Group group3 = match.Groups["eta"];
string eta = (group3.Success ? group3.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 stringValue = s.Substring(array[0].Length).Trim().Trim(new char[1] { '"' });
if (!OptionStrings.Contains(array[0]))
{
throw new ArgumentException("Given string does not match required format.");
}
T val = Utils.OptionValueFromString<T>(stringValue);
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 stringValue = s.Substring(array[0].Length).Trim().Trim(new char[1] { '"' });
if (!OptionStrings.Contains(array[0]))
{
throw new ArgumentException("Given string does not match required format.");
}
Value = Utils.OptionValueFromString<T>(stringValue);
}
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> xattrSetFilesize = new Option<bool>("--xattr-set-filesize");
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 Option<string> paths = new Option<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> dumpUserAgent = new Option<bool>("--dump-user-agent");
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 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<string> alias = new MultiOption<string>("--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<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<string> replaceInMetadata = new MultiOption<string>("--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", "--convert-subtitles");
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<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> 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 XattrSetFilesize
{
get
{
return xattrSetFilesize.Value;
}
set
{
xattrSetFilesize.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 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 DumpUserAgent
{
get
{
return dumpUserAgent.Value;
}
set
{
dumpUserAgent.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 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<string> Alias
{
get
{
return alias.Value;
}
set
{
alias.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 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<string> 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 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 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(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(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 = segments[0];
IOption knownOption = knownOptions.FirstOrDefault((IOption o) => o.OptionStrings.Contains(flag));
IOption option3;
if (segments.Length <= 1)
{
IOption option2 = new Option<bool>(true, flag);
option3 = option2;
}
else
{
IOption option2 = new Option<string>(true, flag);
option3 = option2;
}
IOption customOption = option3;
IOption option = knownOption ?? customOption;
option.SetFromString(line);
yield return option;
}
}
}
public static OptionSet LoadConfigFile(string path)
{
return FromString(File.ReadAllLines(path));
}
public object Clone()
{
return FromString(GetOptionFlags());
}
public void AddCustomOption<T>(string optionString, T value)
{
Option<T> option = new Option<T>(true, optionString);
option.Value = value;
CustomOptions = CustomOptions.Concat(new Option<T>[1] { option }).ToArray();
}
public void SetCustomOption<T>(string optionString, T value)
{
foreach (IOption item in CustomOptions.Where((IOption o) => o.OptionStrings.Contains(optionString)))
{
if (item is Option<T> option)
{
option.Value = value;
continue;
}
throw new ArgumentException($"Value passed to option '{optionString}' has invalid type '{value.GetType()}'.");
}
}
public void DeleteCustomOption(string optionString)
{
CustomOptions = CustomOptions.Where((IOption o) => !o.OptionStrings.Contains(optionString)).ToArray();
}
}
internal static class Utils
{
internal static T OptionValueFromString<T>(string stringValue)
{
if (typeof(T) == typeof(bool))
{
return (T)(object)true;
}
if (typeof(T) == typeof(Enum))
{
string value = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(stringValue);
return (T)Enum.Parse(typeof(T), value);
}
if (typeof(T) == typeof(DateTime))
{
return (T)(object)DateTime.ParseExact(stringValue, "yyyyMMdd", null);
}
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
return (T)converter.ConvertFrom(stringValue);
}
internal static string OptionValueToString<T>(T value)
{
if (value is bool)
{
return string.Empty;
}
if (value is Enum)
{
return " \"" + value.ToString().ToLower() + "\"";
}
if (value is DateTime)
{
object obj = value;
DateTime dateTime = (DateTime)((obj is DateTime) ? obj : null);
if (true)
{
return " " + dateTime.ToString("yyyyMMdd");
}
}
if (value is string)
{
return $" \"{value}\"";
}
T val = value;
return " " + val;
}
}
}
namespace YoutubeDLSharp.Metadata
{
public class ChapterData
{
[JsonProperty("start_time")]
public float? StartTime { get; set; }
[JsonProperty("end_time")]
public float? EndTime { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
}
public class CommentData
{
[JsonProperty("id")]
public string ID { get; set; }
[JsonProperty("author")]
public string Author { get; set; }
[JsonProperty("author_id")]
public string AuthorID { get; set; }
[JsonProperty("author_thumbnail")]
public string AuthorThumbnail { get; set; }
[JsonProperty("html")]
public string Html { get; set; }
[JsonProperty("text")]
public string Text { get; set; }
[JsonProperty("timestamp")]
[JsonConverter(typeof(UnixTimestampConverter))]
public DateTime Timestamp { get; set; }
[JsonProperty("parent")]
public string Parent { get; set; }
[JsonProperty("like_count")]
public int? LikeCount { get; set; }
[JsonProperty("dislike_count")]
public int? DislikeCount { get; set; }
[JsonProperty("is_favorited")]
public bool? IsFavorited { get; set; }
[JsonProperty("author_is_uploader")]
public bool? AuthorIsUploader { get; set; }
}
public class FormatData
{
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("manifest_url")]
public string ManifestUrl { get; set; }
[JsonProperty("ext")]
public string Extension { get; set; }
[JsonProperty("format")]
public string Format { get; set; }
[JsonProperty("format_id")]
public string FormatId { get; set; }
[JsonProperty("format_note")]
public string FormatNote { get; set; }
[JsonProperty("width")]
public int? Width { get; set; }
[JsonProperty("height")]
public int? Height { get; set; }
[JsonProperty("resolution")]
public string Resolution { get; set; }
[JsonProperty("dynamic_range")]
public string DynamicRange { get; set; }
[JsonProperty("tbr")]
public double? Bitrate { get; set; }