

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using JetBrains.Annotations;
using JukeboxCore;
using JukeboxCore.Events;
using JukeboxCore.Exceptions;
using JukeboxCore.Models.Downloader;
using JukeboxCore.Utils;
using JukeboxDownloader.Events;
using JukeboxDownloader.Exceptions;
using JukeboxDownloader.Models;
using JukeboxDownloader.Service;
using JukeboxDownloader.Service.YouTube;
using JukeboxDownloader.UI;
using JukeboxDownloader.Utils;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using YoutubeDLSharp;
using YoutubeDLSharp.Metadata;
using YoutubeDLSharp.Options;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("JukeboxDownloader")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("JukeboxDownloader")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("5C0415F4-8665-489A-A19E-094051311242")]
[assembly: AssemblyFileVersion("2.2.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("2.2.0.0")]
namespace JukeboxDownloader
{
[BepInProcess("ULTRAKILL.exe")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("dev.flazhik.jukebox.downloader", "JukeboxDownloader", "2.2.0")]
public class JukeboxDownloaderPlugin : BaseUnityPlugin
{
}
public class QueueManager : IDisposable
{
private readonly Channel<Func<CancellationToken, Task>> channel;
private readonly List<Task> workers;
private CancellationTokenSource token;
private readonly object @lock = new object();
private bool disposed;
public QueueManager(int workersCount)
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Expected O, but got Unknown
channel = Channel.CreateUnbounded<Func<CancellationToken, Task>>(new UnboundedChannelOptions
{
SingleReader = false,
SingleWriter = false
});
token = new CancellationTokenSource();
workers = (from _ in Enumerable.Range(0, workersCount)
select Task.Run((Func<Task?>)WorkerLoop)).ToList();
}
public void Enqueue(Func<CancellationToken, Task> taskFactory)
{
if (!((Channel<Func<CancellationToken, Task>, Func<CancellationToken, Task>>)(object)channel).Writer.TryWrite(taskFactory))
{
throw new InvalidOperationException("Queue is closed.");
}
}
public void CancelAll()
{
lock (@lock)
{
token.Cancel();
token.Dispose();
token = new CancellationTokenSource();
Func<CancellationToken, Task> func = default(Func<CancellationToken, Task>);
while (((Channel<Func<CancellationToken, Task>, Func<CancellationToken, Task>>)(object)channel).Reader.TryRead(ref func))
{
}
}
}
private async Task WorkerLoop()
{
Func<CancellationToken, Task> func = default(Func<CancellationToken, Task>);
while (await ((Channel<Func<CancellationToken, Task>, Func<CancellationToken, Task>>)(object)channel).Reader.WaitToReadAsync(default(CancellationToken)))
{
if (((Channel<Func<CancellationToken, Task>, Func<CancellationToken, Task>>)(object)channel).Reader.TryRead(ref func))
{
CancellationToken ct;
lock (@lock)
{
ct = token.Token;
}
try
{
await func(ct);
}
catch (OperationCanceledException) when (ct.IsCancellationRequested)
{
}
ct = default(CancellationToken);
}
}
}
public void Dispose()
{
if (!disposed)
{
disposed = true;
((Channel<Func<CancellationToken, Task>, Func<CancellationToken, Task>>)(object)channel).Writer.TryComplete((Exception)null);
try
{
Task.WhenAll(workers).GetAwaiter().GetResult();
}
catch
{
}
token.Cancel();
token.Dispose();
}
}
}
internal static class PluginInfo
{
public const string Guid = "dev.flazhik.jukebox.downloader";
public const string Name = "JukeboxDownloader";
public const string Version = "2.2.0";
}
}
namespace JukeboxDownloader.Utils
{
public static class ThirdPartySoftwareUtils
{
internal class YtDlpReleases
{
public class YtDlpRelease
{
[JsonProperty("tag_name")]
public string Tag { get; set; }
[JsonProperty("assets")]
public List<YtDlpAsset> Assets { get; set; }
}
public class YtDlpAsset
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("digest")]
public string Digest { get; set; }
[JsonProperty("browser_download_url")]
public string DownloadUrl { get; set; }
}
}
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; }
}
public class OsBinVersion
{
[JsonProperty("ffmpeg")]
public string Ffmpeg { get; set; }
[JsonProperty("ffprobe")]
public string Ffprobe { get; set; }
}
}
private const string FfmpegApiUrl = "https://ffbinaries.com/api/v1/version/6.1";
private const string YtDlpUrl = "https://github.com/yt-dlp/yt-dlp/releases/download";
private const string YtDlpLastReleaseUrl = "https://api.github.com/repos/yt-dlp/yt-dlp/releases?per_page=1";
private static readonly string YtDlpHashPath = Path.Combine(PathsUtils.AssemblyPath, "yt-dlp.sha256");
private static readonly List<string> BinariesNames = new List<string>
{
Utils.FfmpegBinaryName,
Utils.FfprobeBinaryName
};
private static readonly Dictionary<string, string> BinariesHashes = new Dictionary<string, string>
{
{ "ffmpeg.exe", "ba242553f0ff60ad788069d5d376c1b4f7a2f3a3566416e0ed950ca7920da5fa" },
{ "ffprobe.exe", "ae5db42a4b7d7fa719a325082e447adb5df674a69935117eb9dff2292a1f23ec" }
};
private static readonly SHA256CryptoServiceProvider SHA256Provider = new SHA256CryptoServiceProvider();
public static bool AllRequiredSoftwarePresent()
{
return BinariesNames.All(ThirdPartySoftwarePresent);
}
public static bool ValidateThirdPartySoftwareIntegrity()
{
return BinariesNames.All(ValidateBinaryIntegrity);
}
public static async Task<bool> IsYtDlpUpToDate()
{
await ObtainLastYtDlpRelease();
if (!File.Exists(YtDlpHashPath))
{
return false;
}
FileInfo fileInfo = new FileInfo(Path.Combine(PathsUtils.AssemblyPath, Utils.YtDlpBinaryName));
return fileInfo.Exists && GetFileHash(fileInfo.FullName).Equals(File.ReadAllText(YtDlpHashPath));
}
public static bool ThirdPartySoftwarePresent(string binary)
{
if (new FileInfo(Path.Combine(PathsUtils.AssemblyPath, binary)).Exists)
{
return BinariesHashes.ContainsKey(binary);
}
return false;
}
public static bool ValidateBinaryIntegrity(string binary)
{
FileInfo fileInfo = new FileInfo(Path.Combine(PathsUtils.AssemblyPath, binary));
if (fileInfo.Exists)
{
return GetFileHash(fileInfo.FullName).Equals(BinariesHashes[binary]);
}
return false;
}
public static async Task DownloadYtDlp(WebClient client)
{
string path = Path.Combine(PathsUtils.AssemblyPath, Utils.YtDlpBinaryName);
if (File.Exists(path))
{
File.Delete(path);
}
await client.DownloadFileTaskAsync(new Uri(GetYtDlpUrl((await ObtainLastYtDlpRelease()).Tag)), path);
}
public static async Task DownloadFfmpeg(WebClient client)
{
await DownloadFf(client, (FfmpegApi.OsBinVersion downloader) => downloader.Ffmpeg, "ffmpeg.exe");
}
public static async Task DownloadFfprobe(WebClient client)
{
await DownloadFf(client, (FfmpegApi.OsBinVersion downloader) => downloader.Ffprobe, "ffprobe.exe");
}
private static async Task DownloadFf(WebClient client, Func<FfmpegApi.OsBinVersion, string> url, string fileName)
{
string zipPath = Path.Combine(PathsUtils.AssemblyPath, fileName);
FfmpegApi.OsBinVersion arg = await FfDownloader();
if (File.Exists(zipPath))
{
File.Delete(zipPath);
}
await client.DownloadFileTaskAsync(new Uri(url(arg)), zipPath);
await Task.Run(delegate
{
Unzip(zipPath);
});
}
private static string GetYtDlpUrl(string version)
{
return "https://github.com/yt-dlp/yt-dlp/releases/download/" + version + "/yt-dlp.exe";
}
private static async Task<YtDlpReleases.YtDlpRelease> ObtainLastYtDlpRelease()
{
YtDlpReleases.YtDlpRelease ytDlpRelease = JsonConvert.DeserializeObject<List<YtDlpReleases.YtDlpRelease>>(await NetworkUtils.GetRaw("https://api.github.com/repos/yt-dlp/yt-dlp/releases?per_page=1"))[0];
YtDlpReleases.YtDlpAsset ytDlpAsset = ytDlpRelease.Assets.FirstOrDefault((YtDlpReleases.YtDlpAsset a) => a.Name == Utils.YtDlpBinaryName);
if (ytDlpAsset == null)
{
return null;
}
File.WriteAllText(YtDlpHashPath, ytDlpAsset.Digest.Split(new char[1] { ':' })[1]);
return ytDlpRelease;
}
public static void CleanUp()
{
foreach (FileInfo item in from file in new DirectoryInfo(PathsUtils.AssemblyPath).EnumerateFiles()
where file.Extension.ToLower().Equals(".zip")
select file)
{
item.Delete();
}
}
private static async Task<FfmpegApi.OsBinVersion> FfDownloader()
{
return JsonConvert.DeserializeObject<FfmpegApi.Root>(await NetworkUtils.GetRaw("https://ffbinaries.com/api/v1/version/6.1"))?.Bin.Windows64;
}
private static void Unzip(string path)
{
using MemoryStream stream = new MemoryStream(File.ReadAllBytes(path));
using ZipArchive zipArchive = new ZipArchive(stream, ZipArchiveMode.Read);
if (zipArchive.Entries.Count > 0)
{
string path2 = Path.Combine(PathsUtils.AssemblyPath, zipArchive.Entries[0].FullName);
if (File.Exists(path2))
{
File.Delete(path2);
}
zipArchive.Entries[0].ExtractToFile(Path.Combine(PathsUtils.AssemblyPath, zipArchive.Entries[0].FullName), overwrite: true);
}
}
private static string GetFileHash(string path)
{
using FileStream inputStream = File.OpenRead(path);
byte[] array = SHA256Provider.ComputeHash(inputStream);
StringBuilder stringBuilder = new StringBuilder(array.Length * 2);
byte[] array2 = array;
foreach (byte b in array2)
{
stringBuilder.Append(b.ToString("x2"));
}
return stringBuilder.ToString();
}
}
}
namespace JukeboxDownloader.UI
{
public class DownloadableTrackElement : MonoBehaviour
{
private static readonly Color DefaultColor = new Color(0f, 0f, 0f, 0.851f);
private static readonly Color SuccessColor = new Color(0f, 0.2f, 0f, 0.851f);
private static readonly Color FailColor = new Color(0.4f, 0f, 0f, 0.851f);
[HideInInspector]
public string id;
[SerializeField]
public TMP_Text titleText;
[SerializeField]
public TMP_Text artistText;
[SerializeField]
public TMP_Text progressPercentage;
[SerializeField]
public TMP_Text downloadEta;
[SerializeField]
public Image thumbnail;
[SerializeField]
public GradualProgressBar progressBar;
[SerializeField]
public Button downloadButton;
[SerializeField]
public Button retryButton;
[SerializeField]
public GameObject thumbnailPlaceholder;
[SerializeField]
public GameObject downloadProgressSection;
[SerializeField]
public GameObject enqueuedGo;
[SerializeField]
public GameObject preprocessingGo;
[SerializeField]
public GameObject postprocessingGo;
private DownloaderUIEventManager uiEventManager;
private MainThreadDispatcher mainThread;
private void Awake()
{
uiEventManager = MonoSingleton<JukeboxDownloaderService>.Instance.UIEventManager;
mainThread = MonoSingleton<MainThreadDispatcher>.Instance;
}
private void OnEnable()
{
DownloadableEntityState val = ((EventManager<DownloadableEntityState>)uiEventManager).StateOf(id);
if (val != null)
{
SetTrackState(val);
}
((EventManager<DownloadableEntityState>)uiEventManager).Subscribe(id, (Action<JukeboxEvent<DownloadableEntityState>>)OnUpdated);
}
private void OnDisable()
{
((EventManager<DownloadableEntityState>)uiEventManager).Unsubscribe(id, (Action<JukeboxEvent<DownloadableEntityState>>)OnUpdated);
}
private void SetTrackState(DownloadableEntityState state)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
HandleState(state.state.Value);
SetThumbnail(state.thumbnail);
SetProgressBar(state);
if (state.progress.HasValue)
{
progressPercentage.text = $"{(int)(state.progress.Value * 100f)}%";
}
if (state.eta != null)
{
progressPercentage.text = state.eta;
}
}
private void SetThumbnail(Sprite texture)
{
thumbnailPlaceholder.SetActive((Object)(object)texture == (Object)null);
((Component)thumbnail).gameObject.SetActive((Object)(object)texture != (Object)null);
thumbnail.sprite = texture;
}
private void SetProgressBar(DownloadableEntityState state)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Invalid comparison between Unknown and I4
if ((int)state.state.GetValueOrDefault() != 3 || !state.progress.HasValue)
{
((Component)progressBar).gameObject.SetActive(false);
}
else
{
progressBar.ForceSetProgress(state.progress.Value);
}
}
private void UpdateProgress(float progress)
{
progressBar.UpdateProgress(progress);
progressPercentage.text = $"{(int)(progress * 100f)}%";
}
private void OnUpdated(JukeboxEvent<DownloadableEntityState> e)
{
mainThread.Enqueue((Action)delegate
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
if (e.newState.state.HasValue)
{
HandleState(e.newState.state.Value);
}
if ((Object)(object)e.newState.thumbnail != (Object)null)
{
SetThumbnail(e.newState.thumbnail);
}
if (e.newState.progress.HasValue)
{
UpdateProgress(e.newState.progress.Value);
}
if (e.newState.eta != null)
{
downloadEta.text = e.newState.eta;
}
});
}
private void HandleState(TrackDownloadingState state)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Invalid comparison between Unknown and I4
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Invalid comparison between Unknown and I4
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Invalid comparison between Unknown and I4
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Invalid comparison between Unknown and I4
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Invalid comparison between Unknown and I4
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Invalid comparison between Unknown and I4
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Invalid comparison between Unknown and I4
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Invalid comparison between Unknown and I4
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Invalid comparison between Unknown and I4
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
((Component)progressBar).gameObject.SetActive((int)state == 3);
((Component)downloadButton).gameObject.SetActive((int)state == 0);
((Component)retryButton).gameObject.SetActive((int)state == 6);
downloadProgressSection.SetActive((int)state == 3);
enqueuedGo.SetActive((int)state == 1);
preprocessingGo.SetActive((int)state == 2);
postprocessingGo.SetActive((int)state == 4);
Image component = ((Component)this).GetComponent<Image>();
Color color = (((int)state == 5) ? SuccessColor : (((int)state != 6) ? DefaultColor : FailColor));
((Graphic)component).color = color;
}
}
public class DownloaderErrorDialogue : MonoBehaviour
{
[SerializeField]
public TMP_Text messageText;
}
public class GradualProgressBar : MonoBehaviour
{
private const float Epsilon = 0.001f;
[SerializeField]
public Slider progressBar;
[SerializeField]
public float smoothTime;
private float progressBarTargetValue;
private float progressBarVelocity;
private void Update()
{
float num = progressBarTargetValue - progressBar.value;
if (!(Math.Abs(num) < 0.001f))
{
if (num > 0f)
{
progressBar.value = Mathf.SmoothDamp(progressBar.value, progressBarTargetValue, ref progressBarVelocity, smoothTime, float.PositiveInfinity, Time.unscaledDeltaTime);
}
else
{
progressBar.value = progressBarTargetValue;
}
}
}
public void UpdateProgress(float progress)
{
progressBarTargetValue = progress;
}
public void ForceSetProgress(float progress)
{
progressBarTargetValue = progress;
progressBar.value = progressBarTargetValue;
}
}
public class TotalDownloadProgress : MonoBehaviour
{
[SerializeField]
public TMP_Text downloadedText;
[SerializeField]
public TMP_Text failedText;
[SerializeField]
public TMP_Text enqueuedText;
private int mDownloaded;
private int mFailed;
private int mEnqueued;
public int Downloaded
{
set
{
mDownloaded = value;
downloadedText.text = mDownloaded.ToString();
}
}
public int Failed
{
set
{
mFailed = value;
failedText.text = mFailed.ToString();
}
}
public int Enqueued
{
set
{
mEnqueued = value;
enqueuedText.text = mEnqueued.ToString();
}
}
}
}
namespace JukeboxDownloader.Service
{
public abstract class AbstractDownloaderClient
{
public abstract bool SupportsUrl(string url);
public abstract Task<List<DownloadableSongMetadata>> GetMetadata(string url, CancellationToken token);
public abstract Task Download(string url, string playlist, IProgress<DownloadProgress> progress, CancellationToken token);
}
public class DownloaderUIEventManager : EventManager<DownloadableEntityState>
{
private static readonly Dictionary<string, Sprite> ThumbnailCache = new Dictionary<string, Sprite>();
public async Task<Sprite> DownloadThumbnail(string id, string thumbnailUrl)
{
if (ThumbnailCache.TryGetValue(id, out var value))
{
return value;
}
value = await DownloadSprite(thumbnailUrl);
ThumbnailCache.Add(id, value);
base.Invoke(id, (JukeboxEvent<DownloadableEntityState>)new ThumbnailLoadedEvent(value));
return value;
}
private static async Task<Sprite> DownloadSprite(string url)
{
Texture2D val = await NetworkUtils.DownloadImage(url);
int num = Mathf.Min(((Texture)val).width, ((Texture)val).height);
Rect val2 = default(Rect);
((Rect)(ref val2))..ctor((float)(((Texture)val).width - num) / 2f, (float)(((Texture)val).height - num) / 2f, (float)num, (float)num);
return Sprite.Create(val, val2, new Vector2(0.5f, 0.5f));
}
protected override DownloadableEntityState DefaultState(string id)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
Sprite value;
return new DownloadableEntityState
{
state = (TrackDownloadingState)0,
thumbnail = (ThumbnailCache.TryGetValue(id, out value) ? value : null)
};
}
}
[ConfigureSingleton(/*Could not decode attribute arguments.*/)]
public class JukeboxDownloaderService : MonoSingleton<JukeboxDownloaderService>
{
private readonly ConfigEntry<int> queueSize = ConfigUtils.BepInExConfig.Bind<int>("Concurrency", "DownloaderQueueSize", 3, "The size of the downloader queue");
private static readonly List<AbstractDownloaderClient> Clients = new List<AbstractDownloaderClient>
{
new YoutubeClient()
};
private QueueManager queue;
private CancellationTokenSource tokenSource = new CancellationTokenSource();
private ThirdPartyExecsState thirdPartySoftwareState = new ThirdPartyExecsState();
private MainThreadDispatcher mainThread;
private int mTotalDownloaded;
private int mTotalFailed;
private int mTotalEnqueued;
private JukeboxDownloaderState state;
public int TotalDownloaded
{
get
{
return mTotalDownloaded;
}
private set
{
mTotalDownloaded = value;
}
}
public int TotalFailed
{
get
{
return mTotalFailed;
}
private set
{
mTotalFailed = value;
}
}
public int TotalEnqueued
{
get
{
return mTotalEnqueued;
}
private set
{
mTotalEnqueued = value;
}
}
public JukeboxDownloaderState State
{
get
{
return state;
}
set
{
state = value;
mainThread.Enqueue((Action)delegate
{
this.OnStateChanged?.Invoke(value);
});
}
}
public ThirdPartyExecsState ThirdPartySoftwareState
{
get
{
return thirdPartySoftwareState;
}
set
{
thirdPartySoftwareState = value;
mainThread.Enqueue((Action)delegate
{
this.OnThirdPartySoftwareChanged?.Invoke(value);
});
}
}
public DownloaderUIEventManager UIEventManager { get; } = new DownloaderUIEventManager();
public List<DownloadableSongMetadata> Metadata { get; private set; } = new List<DownloadableSongMetadata>();
public event Action<ThirdPartyExecsState> OnThirdPartySoftwareChanged;
public event Action<JukeboxDownloaderState> OnStateChanged;
public event Action<List<DownloadableSongMetadata>> OnMetadataChanged;
protected void Start()
{
queue = new QueueManager(queueSize.Value);
mainThread = MonoSingleton<MainThreadDispatcher>.Instance;
}
public static bool SupportsUrl(string url)
{
return Clients.Any((AbstractDownloaderClient client) => client.SupportsUrl(url));
}
public void Clear()
{
((EventManager<DownloadableEntityState>)UIEventManager).Clear();
}
public void CancelEverything()
{
tokenSource.Cancel();
queue.CancelAll();
ResetCounters();
((EventManager<DownloadableEntityState>)UIEventManager).Map((Action<KeyValuePair<string, DownloadableEntityState>>)delegate(KeyValuePair<string, DownloadableEntityState> kv)
{
TrackDownloadingState? val = kv.Value.state;
if (val.HasValue && !ObjectExtensions.IsOneOf((object)val, new object[2]
{
(object)(TrackDownloadingState)6,
(object)(TrackDownloadingState)5
}))
{
((EventManager<DownloadableEntityState>)UIEventManager).Invoke(kv.Key, (JukeboxEvent<DownloadableEntityState>)new DownloadCanceledEvent());
}
});
}
public async Task LoadMetadata(string url)
{
try
{
queue.CancelAll();
State = JukeboxDownloaderState.LoadingMetadata;
Metadata = await GetClientFor(url).GetMetadata(url, RegenerateTokenSource().Token);
foreach (DownloadableSongMetadata metadatum in Metadata)
{
((EventManager<DownloadableEntityState>)UIEventManager).Register(metadatum.Id);
}
mainThread.Enqueue((Action)delegate
{
this.OnMetadataChanged?.Invoke(Metadata);
});
}
catch (JukeboxException val)
{
JukeboxException val2 = val;
JukeboxException e = val2;
mainThread.Enqueue((Action)delegate
{
Debug.LogError((object)("Unable to retrieve metadata: " + ((Exception)(object)e).Message));
});
throw;
}
finally
{
State = JukeboxDownloaderState.Idle;
}
}
public void EnqueueDownload(string id, string url, string playlist, bool decrementFailed = false)
{
Interlocked.Increment(ref mTotalEnqueued);
if (decrementFailed)
{
Interlocked.Decrement(ref mTotalFailed);
}
((EventManager<DownloadableEntityState>)UIEventManager).Invoke(id, (JukeboxEvent<DownloadableEntityState>)new TrackEnqueuedEvent());
queue.Enqueue(delegate(CancellationToken token)
{
Progress<DownloadProgress> progress = new Progress<DownloadProgress>(delegate(DownloadProgress p)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Invalid comparison between Unknown and I4
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Invalid comparison between Unknown and I4
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
if (!token.IsCancellationRequested)
{
TrackDownloadingState val = p.State;
if ((int)val != 5)
{
if ((int)val == 6)
{
Interlocked.Decrement(ref mTotalEnqueued);
Interlocked.Increment(ref mTotalFailed);
}
}
else
{
Interlocked.Decrement(ref mTotalEnqueued);
Interlocked.Increment(ref mTotalDownloaded);
}
((EventManager<DownloadableEntityState>)UIEventManager).Invoke(id, (JukeboxEvent<DownloadableEntityState>)new ProgressUpdatedEvent(p.State, p.Progress, p.Eta));
}
});
return GetClientFor(url).Download(url, playlist, progress, token);
});
}
public async Task DownloadThirdPartySoftware()
{
_ = 2;
try
{
await DownloadSoftwarePiece("ffmpeg", Utils.FfmpegBinaryName, ThirdPartySoftwareUtils.DownloadFfmpeg);
await DownloadSoftwarePiece("ffprobe", Utils.FfprobeBinaryName, ThirdPartySoftwareUtils.DownloadFfprobe);
await UpdateYtDlp();
ThirdPartySoftwareUtils.CleanUp();
ThirdPartySoftwareState = ThirdPartyExecsState.Present();
}
catch (Exception)
{
ThirdPartySoftwareState = ThirdPartyExecsState.Failed();
}
}
public async Task UpdateYtDlp()
{
try
{
await DownloadSoftwarePiece("yt-dlp", Utils.YtDlpBinaryName, ThirdPartySoftwareUtils.DownloadYtDlp);
ThirdPartySoftwareUtils.CleanUp();
ThirdPartySoftwareState = ThirdPartyExecsState.Present();
}
catch (Exception)
{
ThirdPartySoftwareState = ThirdPartyExecsState.Failed();
}
}
private async Task DownloadSoftwarePiece(string softwareTitle, string filename, Func<WebClient, Task> downloadRoutine)
{
try
{
if (ThirdPartySoftwareUtils.ThirdPartySoftwarePresent(filename) && ThirdPartySoftwareUtils.ValidateBinaryIntegrity(filename))
{
return;
}
ThirdPartySoftwareState = ThirdPartyExecsState.DownloadingStarted();
using WebClient client = new WebClient();
client.DownloadProgressChanged += delegate(object _, DownloadProgressChangedEventArgs e)
{
ThirdPartySoftwareState = ThirdPartyExecsState.DownloadingProgress(softwareTitle, (float)e.ProgressPercentage / 100f);
};
await downloadRoutine(client);
}
catch (Exception ex)
{
Exception ex2 = ex;
Exception e2 = ex2;
mainThread.Enqueue((Action)delegate
{
Debug.LogError((object)("An error has occured while downloading 3rd-party software: " + e2.Message));
});
ThirdPartySoftwareState = ThirdPartyExecsState.Failed();
throw;
}
}
private void ResetCounters()
{
TotalDownloaded = 0;
TotalFailed = 0;
TotalEnqueued = 0;
}
private CancellationTokenSource RegenerateTokenSource()
{
tokenSource.Cancel();
tokenSource = new CancellationTokenSource();
return tokenSource;
}
private static AbstractDownloaderClient GetClientFor(string url)
{
return Clients.FirstOrDefault((AbstractDownloaderClient client) => client.SupportsUrl(url)) ?? throw new UrlIsNotSupported();
}
protected void OnDestroy()
{
CancelEverything();
}
}
public enum JukeboxDownloaderState
{
Idle,
LoadingMetadata
}
}
namespace JukeboxDownloader.Service.YouTube
{
public class YoutubeClient : AbstractDownloaderClient
{
private const string YouTubeVideoRegex = "^(?:https:\\/\\/)?(?:(?:www|m)\\.)?(?:youtube\\.com|youtu.be)(?:\\/(?:[\\w\\-]+\\?v=|embed\\/|v\\/)?)([\\w\\-]+)(\\S+)?$";
private const string YouTubePlaylistRegex = "^(?:https:\\/\\/)?(?:(?:www|m)\\.)?(?:youtube\\.com|youtu.be).*?list=([a-zA-Z0-9\\-_]*).*(?:&|$)$";
private readonly YtDlpClient client;
public YoutubeClient()
{
client = new YtDlpClient();
}
public override bool SupportsUrl(string url)
{
if (!UrlIsSingleTrack(url))
{
return UrlIsPlaylist(url);
}
return true;
}
public override async Task<List<DownloadableSongMetadata>> GetMetadata(string url, CancellationToken token)
{
string targetUrl = url;
if (UrlIsPlaylist(url))
{
targetUrl = ConstructPlaylistUrl(GetPlaylistId(url));
}
RunResult<VideoData> data = await client.GetMetadata(targetUrl, token);
if (!data.Success || data.Data == null)
{
throw HandleErrorOutput(data.ErrorOutput);
}
bool isPlaylist = data.Data.Entries != null && data.Data.Entries.Length != 0;
return ((IEnumerable<VideoData>)(isPlaylist ? ((Array)data.Data.Entries) : ((Array)new VideoData[1] { data.Data }))).Select((Func<VideoData, DownloadableSongMetadata>)((VideoData entry) => new DownloadableSongMetadata(entry.ID, isPlaylist ? entry.Url : targetUrl, "https://i.ytimg.com/vi/" + entry.ID + "/hqdefault.jpg", entry.Title, entry.Uploader, isPlaylist ? data.Data.Title : null))).ToList();
}
public override async Task Download(string url, string playlist, IProgress<DownloadProgress> progress, CancellationToken token)
{
IProgress<DownloadProgress> progress2 = new Progress<DownloadProgress>(delegate(DownloadProgress p)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Expected I4, but got Unknown
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
DownloadState state = p.State;
progress.Report(new DownloadProgress((TrackDownloadingState)((int)state switch
{
0 => 0,
1 => 2,
2 => 3,
3 => 4,
5 => 5,
4 => 2,
_ => 0,
}), p.Progress, p.ETA));
});
RunResult<string> val = await client.Download(url, playlist, progress2, token);
progress.Report(val.Success ? new DownloadProgress((TrackDownloadingState)5, 1f, string.Empty) : new DownloadProgress((TrackDownloadingState)6, 0f, string.Empty));
}
private static bool UrlIsSingleTrack(string url)
{
return Regex.IsMatch(url, "^(?:https:\\/\\/)?(?:(?:www|m)\\.)?(?:youtube\\.com|youtu.be)(?:\\/(?:[\\w\\-]+\\?v=|embed\\/|v\\/)?)([\\w\\-]+)(\\S+)?$", RegexOptions.IgnoreCase);
}
private static bool UrlIsPlaylist(string url)
{
return Regex.IsMatch(url, "^(?:https:\\/\\/)?(?:(?:www|m)\\.)?(?:youtube\\.com|youtu.be).*?list=([a-zA-Z0-9\\-_]*).*(?:&|$)$", RegexOptions.IgnoreCase);
}
private static string GetPlaylistId(string url)
{
return Regex.Match(url, "^(?:https:\\/\\/)?(?:(?:www|m)\\.)?(?:youtube\\.com|youtu.be).*?list=([a-zA-Z0-9\\-_]*).*(?:&|$)$").Groups[1].Value;
}
private static string ConstructPlaylistUrl(string playlistId)
{
return "https://youtube.com/playlist?list=" + playlistId;
}
private static Exception HandleErrorOutput(string[] errorOutput)
{
string output = string.Join("\n", errorOutput);
return Handle(output, new(string[], Func<JukeboxException>)[4]
{
(new string[1] { "Sign in to confirm you" }, () => (JukeboxException)new CookiesRequiredException()),
(new string[2] { "Incomplete YouTube ID", "Video unavailable" }, () => (JukeboxException)new InvalidVideoUrlException()),
(new string[1] { "skipping cookie file entry" }, () => (JukeboxException)new InvalidCookiesFileException()),
(new string[1] { "This playlist type is unviewable" }, () => (JukeboxException)new PlaylistIsUnviewableException())
});
Exception Handle(string o, params (string[], Func<JukeboxException>)[] handlers)
{
(string[], Func<JukeboxException>) tuple = handlers.FirstOrDefault(((string[], Func<JukeboxException>) handler) => handler.Item1.FirstOrDefault(o.Contains) != null);
var (array, func) = tuple;
if (array != null || (Delegate?)func != (Delegate?)null)
{
throw tuple.Item2();
}
return (Exception)(object)new UnableToFetchMetadata(output);
}
}
}
public class YtDlpClient
{
private readonly ConfigEntry<byte> ytDlpMaxProcesses = ConfigUtils.BepInExConfig.Bind<byte>("Concurrency", "YtDlpMaxProcesses", (byte)3, "Maximum number of yt-dlp processes");
private readonly string cookiesPath = Path.Combine(PathsUtils.AssemblyPath, "cookies.txt");
private const string PostProcessing = "EmbedThumbnail+ffmpeg_o:-c:v mjpeg -vf crop=\\\"w='min(iw,ih)':h='min(iw,ih)'\\\"";
private const string EjsParam = "ejs:github";
private static readonly string OutputFolder = Path.Combine(PathsUtils.MusicPath, "YouTube");
private static readonly Progress<string> Logger = new Progress<string>(delegate(string msg)
{
MonoSingleton<MainThreadDispatcher>.Instance.Enqueue((Action)delegate
{
Debug.Log((object)msg);
});
});
private readonly YoutubeDL client;
private static bool SaveIntoSeparateFolders => MonoSingleton<PrefsManager>.Instance.GetBoolLocal("jukebox.downloader.separateFolderPerPlaylist", false);
public YtDlpClient()
{
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Expected O, but got Unknown
client = new YoutubeDL(ytDlpMaxProcesses.Value)
{
YoutubeDLPath = Path.Combine(PathsUtils.AssemblyPath, "yt-dlp.exe"),
FFmpegPath = "ffmpeg.exe"
};
}
public async Task<RunResult<VideoData>> GetMetadata(string url, CancellationToken token)
{
OptionSet val = new OptionSet
{
Cookies = cookiesPath
};
YoutubeDL obj = client;
OptionSet val2 = val;
return await obj.RunVideoDataFetch(url, token, true, false, val2);
}
public async Task<RunResult<string>> Download(string url, string playlist, IProgress<DownloadProgress> progress, CancellationToken token)
{
string text = ((!string.IsNullOrEmpty(playlist) || !SaveIntoSeparateFolders) ? Path.Combine(OutputFolder, PathsUtils.CoerceValidFileName(playlist)) : OutputFolder);
OptionSet val = new OptionSet
{
ExtractAudio = true,
EmbedThumbnail = true,
EmbedMetadata = true,
AudioFormat = (AudioConversionFormat)3,
Output = text + "\\%(title)s.%(ext)s",
Cookies = cookiesPath
};
val.AddCustomOption<string>("--ppa", "EmbedThumbnail+ffmpeg_o:-c:v mjpeg -vf crop=\\\"w='min(iw,ih)':h='min(iw,ih)'\\\"");
val.AddCustomOption<string>("--remote-components", "ejs:github");
return await client.RunWithOptions(url, val, token, progress, (IProgress<string>)Logger, true);
}
}
}
namespace JukeboxDownloader.Models
{
public class DownloadProgress
{
public TrackDownloadingState State { get; private set; }
public float Progress { get; private set; }
public string Eta { get; private set; }
public DownloadProgress(TrackDownloadingState state, float progress, string eta)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
State = state;
Progress = progress;
Eta = eta;
}
}
public class ThirdPartyExecsState
{
public ExecsState state;
public float? progress;
[CanBeNull]
public string currentBinary;
public ThirdPartyExecsState()
{
state = ExecsState.None;
}
public static ThirdPartyExecsState DownloadingStarted()
{
return new ThirdPartyExecsState
{
state = ExecsState.Downloading,
currentBinary = null,
progress = null
};
}
public static ThirdPartyExecsState DownloadingProgress(string software, float progress)
{
return new ThirdPartyExecsState
{
state = ExecsState.Downloading,
currentBinary = software,
progress = progress
};
}
public static ThirdPartyExecsState Failed()
{
return new ThirdPartyExecsState
{
state = ExecsState.Failed,
currentBinary = null,
progress = null
};
}
public static ThirdPartyExecsState Present()
{
return new ThirdPartyExecsState
{
state = ExecsState.Present,
currentBinary = null,
progress = null
};
}
}
public enum ExecsState
{
None,
Missing,
Present,
UpdateRequired,
Downloading,
Failed
}
}
namespace JukeboxDownloader.Exceptions
{
public class UnableToFetchMetadata : JukeboxException
{
private readonly string message;
public override string Message => "Unable to fetch metadata: " + message;
public UnableToFetchMetadata(string message)
{
this.message = message;
}
}
public class UrlIsNotSupported : JukeboxException
{
public override string Message => "URL is not supported";
}
}
namespace JukeboxDownloader.Events
{
public class DownloadCanceledEvent : DownloadableEntityStateEvent
{
public DownloadCanceledEvent()
: base(GetState())
{
}
private static DownloadableEntityState GetState()
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Expected O, but got Unknown
return new DownloadableEntityState
{
state = (TrackDownloadingState)0
};
}
public override void Mutate(DownloadableEntityState state)
{
state.state = ((JukeboxEvent<DownloadableEntityState>)this).newState.state;
}
}
public class DownloadFailedEvent : DownloadableEntityStateEvent
{
public DownloadFailedEvent()
: base(GetState())
{
}
private static DownloadableEntityState GetState()
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Expected O, but got Unknown
return new DownloadableEntityState
{
state = (TrackDownloadingState)6
};
}
public override void Mutate(DownloadableEntityState state)
{
state.state = ((JukeboxEvent<DownloadableEntityState>)this).newState.state;
}
}
public abstract class DownloadableEntityStateEvent : JukeboxEvent<DownloadableEntityState>
{
protected DownloadableEntityStateEvent(DownloadableEntityState newState)
{
base.newState = newState;
}
}
public class ProgressUpdatedEvent : DownloadableEntityStateEvent
{
public ProgressUpdatedEvent(TrackDownloadingState state, float progress, string eta)
: base(GetState(state, progress, eta))
{
}//IL_0001: Unknown result type (might be due to invalid IL or missing references)
private static DownloadableEntityState GetState(TrackDownloadingState newState, float newProgress, string eta)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Expected O, but got Unknown
return new DownloadableEntityState
{
state = newState,
progress = newProgress,
eta = eta
};
}
public override void Mutate(DownloadableEntityState state)
{
state.state = ((JukeboxEvent<DownloadableEntityState>)this).newState.state;
state.progress = ((JukeboxEvent<DownloadableEntityState>)this).newState.progress;
}
}
public class ThumbnailLoadedEvent : DownloadableEntityStateEvent
{
public ThumbnailLoadedEvent(Sprite sprite)
: base(GetState(sprite))
{
}
private static DownloadableEntityState GetState(Sprite sprite)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Expected O, but got Unknown
return new DownloadableEntityState
{
thumbnail = sprite
};
}
public override void Mutate(DownloadableEntityState state)
{
state.thumbnail = ((JukeboxEvent<DownloadableEntityState>)this).newState.thumbnail;
}
}
public class TrackEnqueuedEvent : DownloadableEntityStateEvent
{
public TrackEnqueuedEvent()
: base(GetState())
{
}
private static DownloadableEntityState GetState()
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Expected O, but got Unknown
return new DownloadableEntityState
{
state = (TrackDownloadingState)1
};
}
public override void Mutate(DownloadableEntityState state)
{
state.state = ((JukeboxEvent<DownloadableEntityState>)this).newState.state;
}
}
}
namespace JukeboxDownloader.Components
{
public class JukeboxDownloader : MonoBehaviour
{
[CompilerGenerated]
private sealed class <>c__DisplayClass22_0
{
public JukeboxDownloader <>4__this;
public string value;
internal Task <URLChangedRoutine>b__0()
{
return <>4__this.downloaderService.LoadMetadata(value);
}
}
[CompilerGenerated]
private sealed class <URLChangedRoutine>d__22 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public JukeboxDownloader <>4__this;
public string value;
private <>c__DisplayClass22_0 <>8__1;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <URLChangedRoutine>d__22(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>8__1 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Expected O, but got Unknown
int num = <>1__state;
JukeboxDownloader jukeboxDownloader = <>4__this;
switch (num)
{
default:
return false;
case 0:
<>1__state = -1;
<>8__1 = new <>c__DisplayClass22_0();
<>8__1.<>4__this = <>4__this;
<>8__1.value = value;
<>2__current = (object)new WaitForSecondsRealtime(1f);
<>1__state = 1;
return true;
case 1:
<>1__state = -1;
((Component)jukeboxDownloader.errorDialogue).gameObject.SetActive(false);
if (!JukeboxDownloaderService.SupportsUrl(<>8__1.value))
{
return false;
}
jukeboxDownloader.downloaderService.CancelEverything();
jukeboxDownloader.downloaderService.Clear();
jukeboxDownloader.downloadProgress.SetActive(false);
jukeboxDownloader.Run(() => <>8__1.<>4__this.downloaderService.LoadMetadata(<>8__1.value));
return false;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
private const float OnUrlChangedDelay = 1f;
[SerializeField]
public JukeboxDownloaderBrowser browser;
[SerializeField]
public DownloaderErrorDialogue errorDialogue;
[SerializeField]
public TMP_InputField urlInputField;
[SerializeField]
public GameObject downloadProgress;
[SerializeField]
public GameObject loadingPlaceholder;
[SerializeField]
public GameObject bottomPanel;
[SerializeField]
public GameObject cookiesRequiredWindow;
[SerializeField]
public Button downloadAllButton;
private JukeboxDownloaderService downloaderService;
private MainThreadDispatcher mainThread;
private Coroutine urlChangedRoutine;
private TotalDownloadProgress downloadProgressComponent;
private void Awake()
{
downloaderService = MonoSingleton<JukeboxDownloaderService>.Instance;
mainThread = MonoSingleton<MainThreadDispatcher>.Instance;
downloadProgressComponent = downloadProgress.GetComponent<TotalDownloadProgress>();
}
private void Update()
{
bool flag = downloaderService.TotalEnqueued == 0 && downloaderService.TotalDownloaded == 0 && downloaderService.TotalFailed == 0;
downloadProgress.SetActive(!flag);
if (!flag)
{
downloadProgressComponent.Downloaded = downloaderService.TotalDownloaded;
downloadProgressComponent.Failed = downloaderService.TotalFailed;
downloadProgressComponent.Enqueued = downloaderService.TotalEnqueued;
}
}
private void OnEnable()
{
((UnityEvent<string>)(object)urlInputField.onValueChanged).AddListener((UnityAction<string>)OnURLChanged);
ReloadBrowserMetadata(downloaderService.Metadata);
OnDownloaderState(downloaderService.State);
downloaderService.OnMetadataChanged += ReloadBrowserMetadata;
downloaderService.OnStateChanged += OnDownloaderState;
}
private void OnDisable()
{
((UnityEvent<string>)(object)urlInputField.onValueChanged).RemoveListener((UnityAction<string>)OnURLChanged);
downloaderService.OnMetadataChanged -= ReloadBrowserMetadata;
downloaderService.OnStateChanged -= OnDownloaderState;
}
public void Cancel()
{
downloaderService.CancelEverything();
}
private void OnURLChanged(string value)
{
if (urlChangedRoutine != null)
{
((MonoBehaviour)this).StopCoroutine(urlChangedRoutine);
}
urlChangedRoutine = ((MonoBehaviour)this).StartCoroutine(URLChangedRoutine(value));
}
private void ReloadBrowserMetadata(List<DownloadableSongMetadata> metadata)
{
bool active = metadata == null || metadata.Count != 0;
bottomPanel.SetActive(active);
((Component)downloadAllButton).gameObject.SetActive(active);
browser.ReloadMetadata(metadata);
}
public void DownloadAll()
{
foreach (DownloadableSongMetadata metadatum in browser.Metadata)
{
downloaderService.EnqueueDownload(metadatum.Id, metadatum.Url, metadatum.Playlist);
}
}
private void OnDownloaderState(JukeboxDownloaderState state)
{
switch (state)
{
case JukeboxDownloaderState.Idle:
loadingPlaceholder.SetActive(false);
break;
case JukeboxDownloaderState.LoadingMetadata:
browser.Clear();
bottomPanel.SetActive(false);
loadingPlaceholder.SetActive(true);
break;
}
}
[IteratorStateMachine(typeof(<URLChangedRoutine>d__22))]
private IEnumerator URLChangedRoutine(string value)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <URLChangedRoutine>d__22(0)
{
<>4__this = this,
value = value
};
}
private void Run(Func<Task> function)
{
Task.Run(function).ContinueWith(ErrorHandler());
}
private Action<Task> ErrorHandler()
{
return delegate(Task t)
{
mainThread.Enqueue((Action)delegate
{
if (t.IsFaulted)
{
RaiseErrorDialogue(t.Exception);
}
});
};
}
private void RaiseErrorDialogue(Exception e)
{
if (e is AggregateException)
{
Exception innerException = e.InnerException;
if (!(innerException is CookiesRequiredException) && !(innerException is InvalidCookiesFileException))
{
JukeboxException val = (JukeboxException)(object)((innerException is JukeboxException) ? innerException : null);
if (val != null)
{
((Component)errorDialogue).gameObject.SetActive(true);
errorDialogue.messageText.text = ((Exception)(object)val).Message;
}
}
else
{
cookiesRequiredWindow.SetActive(true);
}
}
else
{
errorDialogue.messageText.text = "Unexpected error " + e.Message;
}
}
public void RevealModLocation()
{
Application.OpenURL(PathsUtils.AssemblyPath);
}
public void OpenURL(string url)
{
Application.OpenURL(url);
}
}
public class JukeboxDownloaderBrowser : DirectoryTreeBrowser<DownloadableSongMetadata>
{
private JukeboxDownloaderService downloaderService;
public List<DownloadableSongMetadata> Metadata { get; private set; } = new List<DownloadableSongMetadata>();
protected override int maxPageLength => 5;
protected override IDirectoryTree<DownloadableSongMetadata> baseDirectory => (IDirectoryTree<DownloadableSongMetadata>)(object)new FakeDirectoryTree<DownloadableSongMetadata>("Downloads", Metadata, (List<FakeDirectoryTree<DownloadableSongMetadata>>)null, (IDirectoryTree<DownloadableSongMetadata>)null);
protected void Awake()
{
downloaderService = MonoSingleton<JukeboxDownloaderService>.Instance;
}
public void ReloadMetadata(List<DownloadableSongMetadata> newMetadata)
{
Metadata = newMetadata;
((DirectoryTreeBrowser<DownloadableSongMetadata>)this).Rebuild(true);
}
public void Clear()
{
Metadata.Clear();
((DirectoryTreeBrowser<DownloadableSongMetadata>)this).Rebuild(true);
}
protected override Action BuildLeaf(DownloadableSongMetadata item, int indexInPage)
{
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Expected O, but got Unknown
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Expected O, but got Unknown
GameObject go = Object.Instantiate<GameObject>(base.itemButtonTemplate, base.itemParent, false);
DownloadableTrackElement component = go.GetComponent<DownloadableTrackElement>();
component.id = item.Id;
component.titleText.text = item.Title;
component.artistText.text = item.Artist;
((UnityEvent)component.downloadButton.onClick).AddListener((UnityAction)delegate
{
Download();
});
((UnityEvent)component.retryButton.onClick).AddListener((UnityAction)delegate
{
Download(decrementFailed: true);
});
go.SetActive(true);
Task.Run(() => downloaderService.UIEventManager.DownloadThumbnail(item.Id, item.ThumbnailUrl));
return delegate
{
Object.Destroy((Object)(object)go);
};
void Download(bool decrementFailed = false)
{
downloaderService.EnqueueDownload(item.Id, item.Url, item.Playlist, decrementFailed);
}
}
public override void Rebuild(bool setToPageZero = true)
{
base.currentDirectory = ((DirectoryTreeBrowser<DownloadableSongMetadata>)this).baseDirectory;
base.Rebuild(setToPageZero);
Transform itemParent = base.itemParent;
LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)(object)((itemParent is RectTransform) ? itemParent : null));
}
}
public class JukeboxDownloaderContainer : MonoBehaviour
{
[SerializeField]
public GameObject loadingScreen;
[SerializeField]
public JukeboxDownloader downloader;
[SerializeField]
public ThirdPartyExecsDownloader thirdPartyExecsDownloader;
[SerializeField]
public YtDlpUpdater ytDlpUpdater;
private JukeboxDownloaderService downloaderService;
private void Awake()
{
downloaderService = MonoSingleton<JukeboxDownloaderService>.Instance;
Task.Run((Func<Task<bool>?>)ThirdPartySoftwareUtils.IsYtDlpUpToDate).ContinueWith((Task<bool> ytDlpIsUtToDate) => Task.Run(delegate
{
bool softwareIntact = ThirdPartySoftwareUtils.AllRequiredSoftwarePresent() && ThirdPartySoftwareUtils.ValidateThirdPartySoftwareIntegrity();
MonoSingleton<MainThreadDispatcher>.Instance.Enqueue((Action)delegate
{
downloaderService.ThirdPartySoftwareState = new ThirdPartyExecsState
{
state = ((!softwareIntact) ? ExecsState.Missing : ((ytDlpIsUtToDate.IsFaulted || ytDlpIsUtToDate.IsCanceled || ytDlpIsUtToDate.Result) ? ExecsState.Present : ExecsState.UpdateRequired))
};
loadingScreen.SetActive(false);
});
}));
}
private void OnEnable()
{
HandleState(downloaderService.ThirdPartySoftwareState);
downloaderService.OnThirdPartySoftwareChanged += HandleState;
}
private void OnDisable()
{
downloaderService.OnThirdPartySoftwareChanged -= HandleState;
}
private void HandleState(ThirdPartyExecsState state)
{
((Component)downloader).gameObject.SetActive(state.state == ExecsState.Present);
if (!ObjectExtensions.IsOneOf((object)state.state, new object[2]
{
ExecsState.Downloading,
ExecsState.Failed
}))
{
((Component)thirdPartyExecsDownloader).gameObject.SetActive(!ObjectExtensions.IsOneOf((object)state.state, new object[3]
{
ExecsState.Present,
ExecsState.None,
ExecsState.UpdateRequired
}));
((Component)ytDlpUpdater).gameObject.SetActive(state.state == ExecsState.UpdateRequired);
}
}
}
public class ThirdPartyExecsDownloader : MonoBehaviour
{
[SerializeField]
public Button installButton;
[SerializeField]
public GradualProgressBar progressBar;
[SerializeField]
public GameObject errorMessage;
[SerializeField]
public TMP_Text progressText;
private JukeboxDownloaderService downloaderService;
public void RevealModLocation()
{
Application.OpenURL(PathsUtils.AssemblyPath);
}
public void OpenURL(string url)
{
Application.OpenURL(url);
}
private void Awake()
{
downloaderService = MonoSingleton<JukeboxDownloaderService>.Instance;
}
private void OnEnable()
{
downloaderService.OnThirdPartySoftwareChanged += SetState;
SetState(downloaderService.ThirdPartySoftwareState);
}
private void OnDisable()
{
downloaderService.OnThirdPartySoftwareChanged -= SetState;
}
private void SetState(ThirdPartyExecsState state)
{
HandleState(state.state);
SetProgressBar(state);
}
private void SetProgressBar(ThirdPartyExecsState state, bool forced = false)
{
string arg = state.currentBinary ?? string.Empty;
if (!state.progress.HasValue)
{
progressBar.ForceSetProgress(0f);
progressText.text = "Downloading...";
return;
}
if (forced)
{
progressBar.ForceSetProgress(state.progress.Value);
}
else
{
progressBar.UpdateProgress(state.progress.Value);
}
progressText.text = $"Downloading {arg}: {(int)(state.progress * 100f).Value}%";
}
public void Install()
{
downloaderService.ThirdPartySoftwareState = ThirdPartyExecsState.DownloadingStarted();
Task.Run(() => downloaderService.DownloadThirdPartySoftware());
}
private void HandleState(ExecsState state)
{
if (state == ExecsState.Present)
{
((Component)this).gameObject.SetActive(false);
return;
}
((Component)installButton).gameObject.SetActive(state == ExecsState.Missing);
((Component)progressText).gameObject.SetActive(state == ExecsState.Downloading);
errorMessage.gameObject.SetActive(state == ExecsState.Failed);
}
}
public class YtDlpUpdater : MonoBehaviour
{
[SerializeField]
public Button updateButton;
[SerializeField]
public GradualProgressBar progressBar;
[SerializeField]
public GameObject errorMessage;
[SerializeField]
public TMP_Text progressText;
private JukeboxDownloaderService downloaderService;
private void Awake()
{
downloaderService = MonoSingleton<JukeboxDownloaderService>.Instance;
}
private void OnEnable()
{
downloaderService.OnThirdPartySoftwareChanged += SetState;
SetState(downloaderService.ThirdPartySoftwareState);
}
private void OnDisable()
{
downloaderService.OnThirdPartySoftwareChanged -= SetState;
}
private void SetState(ThirdPartyExecsState state)
{
HandleState(state.state);
SetProgressBar(state);
}
private void SetProgressBar(ThirdPartyExecsState state, bool forced = false)
{
if (!state.progress.HasValue)
{
progressBar.ForceSetProgress(0f);
progressText.text = "Downloading...";
return;
}
if (forced)
{
progressBar.ForceSetProgress(state.progress.Value);
}
else
{
progressBar.UpdateProgress(state.progress.Value);
}
progressText.text = $"Updating yt-dlp: {(int)(state.progress * 100f).Value}%";
}
public void UpdateYtDlp()
{
downloaderService.ThirdPartySoftwareState = ThirdPartyExecsState.DownloadingStarted();
Task.Run(() => downloaderService.UpdateYtDlp());
}
private void HandleState(ExecsState state)
{
if (state == ExecsState.Present)
{
((Component)this).gameObject.SetActive(false);
return;
}
((Component)updateButton).gameObject.SetActive(state == ExecsState.UpdateRequired);
((Component)progressText).gameObject.SetActive(state == ExecsState.Downloading);
errorMessage.gameObject.SetActive(state == ExecsState.Failed);
}
}
}using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyMetadata("Serviceable", "True")]
[assembly: AssemblyMetadata("PreferInbox", "True")]
[assembly: AssemblyDefaultAlias("Microsoft.Bcl.AsyncInterfaces")]
[assembly: CLSCompliant(true)]
[assembly: AssemblyMetadata("IsTrimmable", "True")]
[assembly: DefaultDllImportSearchPaths(DllImportSearchPath.System32 | DllImportSearchPath.AssemblyDirectory)]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
[assembly: AssemblyDescription("Provides the IAsyncEnumerable<T> and IAsyncDisposable interfaces and helper types for .NET Standard 2.0. This package is not required starting with .NET Standard 2.1 and .NET Core 3.0.")]
[assembly: AssemblyFileVersion("9.0.725.31616")]
[assembly: AssemblyInformationalVersion("9.0.7+3c298d9f00936d651cc47d221762474e25277672")]
[assembly: AssemblyProduct("Microsoft® .NET")]
[assembly: AssemblyTitle("Microsoft.Bcl.AsyncInterfaces")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/dotnet/runtime")]
[assembly: AssemblyVersion("9.0.0.7")]
[module: RefSafetyRules(11)]
[module: System.Runtime.CompilerServices.NullablePublicOnly(false)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class IsReadOnlyAttribute : Attribute
{
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.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]
[Microsoft.CodeAnalysis.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]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class NullablePublicOnlyAttribute : Attribute
{
public readonly bool IncludesInternals;
public NullablePublicOnlyAttribute(bool P_0)
{
IncludesInternals = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 System
{
public interface IAsyncDisposable
{
ValueTask DisposeAsync();
}
}
namespace System.Diagnostics.CodeAnalysis
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)]
internal sealed class AllowNullAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)]
internal sealed class DisallowNullAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)]
internal sealed class MaybeNullAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)]
internal sealed class NotNullAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
internal sealed class MaybeNullWhenAttribute : Attribute
{
public bool ReturnValue { get; }
public MaybeNullWhenAttribute(bool returnValue)
{
ReturnValue = returnValue;
}
}
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
internal sealed class NotNullWhenAttribute : Attribute
{
public bool ReturnValue { get; }
public NotNullWhenAttribute(bool returnValue)
{
ReturnValue = returnValue;
}
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
internal sealed class NotNullIfNotNullAttribute : Attribute
{
public string ParameterName { get; }
public NotNullIfNotNullAttribute(string parameterName)
{
ParameterName = parameterName;
}
}
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
internal sealed class DoesNotReturnAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
internal sealed class DoesNotReturnIfAttribute : Attribute
{
public bool ParameterValue { get; }
public DoesNotReturnIfAttribute(bool parameterValue)
{
ParameterValue = parameterValue;
}
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
internal sealed class MemberNotNullAttribute : Attribute
{
public string[] Members { get; }
public MemberNotNullAttribute(string member)
{
Members = new string[1] { member };
}
public MemberNotNullAttribute(params string[] members)
{
Members = members;
}
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
internal sealed class MemberNotNullWhenAttribute : Attribute
{
public bool ReturnValue { get; }
public string[] Members { get; }
public MemberNotNullWhenAttribute(bool returnValue, string member)
{
ReturnValue = returnValue;
Members = new string[1] { member };
}
public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
{
ReturnValue = returnValue;
Members = members;
}
}
}
namespace System.Collections.Generic
{
public interface IAsyncEnumerable<out T>
{
IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default(CancellationToken));
}
public interface IAsyncEnumerator<out T> : IAsyncDisposable
{
T Current { get; }
ValueTask<bool> MoveNextAsync();
}
}
namespace System.Runtime.InteropServices
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
internal sealed class LibraryImportAttribute : Attribute
{
public string LibraryName { get; }
public string EntryPoint { get; set; }
public StringMarshalling StringMarshalling { get; set; }
public Type StringMarshallingCustomType { get; set; }
public bool SetLastError { get; set; }
public LibraryImportAttribute(string libraryName)
{
LibraryName = libraryName;
}
}
internal enum StringMarshalling
{
Custom,
Utf8,
Utf16
}
}
namespace System.Runtime.CompilerServices
{
[StructLayout(LayoutKind.Auto)]
public struct AsyncIteratorMethodBuilder
{
private AsyncTaskMethodBuilder _methodBuilder;
private object _id;
internal object ObjectIdForDebugger => _id ?? Interlocked.CompareExchange(ref _id, new object(), null) ?? _id;
public static AsyncIteratorMethodBuilder Create()
{
AsyncIteratorMethodBuilder result = default(AsyncIteratorMethodBuilder);
result._methodBuilder = AsyncTaskMethodBuilder.Create();
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MoveNext<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
_methodBuilder.Start(ref stateMachine);
}
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine
{
_methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine);
}
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine
{
_methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
}
public void Complete()
{
_methodBuilder.SetResult();
}
}
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public sealed class AsyncIteratorStateMachineAttribute : StateMachineAttribute
{
public AsyncIteratorStateMachineAttribute(Type stateMachineType)
: base(stateMachineType)
{
}
}
[StructLayout(LayoutKind.Auto)]
public readonly struct ConfiguredAsyncDisposable
{
private readonly IAsyncDisposable _source;
private readonly bool _continueOnCapturedContext;
internal ConfiguredAsyncDisposable(IAsyncDisposable source, bool continueOnCapturedContext)
{
_source = source;
_continueOnCapturedContext = continueOnCapturedContext;
}
public ConfiguredValueTaskAwaitable DisposeAsync()
{
return _source.DisposeAsync().ConfigureAwait(_continueOnCapturedContext);
}
}
[StructLayout(LayoutKind.Auto)]
public readonly struct ConfiguredCancelableAsyncEnumerable<T>
{
[StructLayout(LayoutKind.Auto)]
public readonly struct Enumerator
{
private readonly IAsyncEnumerator<T> _enumerator;
private readonly bool _continueOnCapturedContext;
public T Current => _enumerator.Current;
internal Enumerator(IAsyncEnumerator<T> enumerator, bool continueOnCapturedContext)
{
_enumerator = enumerator;
_continueOnCapturedContext = continueOnCapturedContext;
}
public ConfiguredValueTaskAwaitable<bool> MoveNextAsync()
{
return _enumerator.MoveNextAsync().ConfigureAwait(_continueOnCapturedContext);
}
public ConfiguredValueTaskAwaitable DisposeAsync()
{
return _enumerator.DisposeAsync().ConfigureAwait(_continueOnCapturedContext);
}
}
private readonly IAsyncEnumerable<T> _enumerable;
private readonly CancellationToken _cancellationToken;
private readonly bool _continueOnCapturedContext;
internal ConfiguredCancelableAsyncEnumerable(IAsyncEnumerable<T> enumerable, bool continueOnCapturedContext, CancellationToken cancellationToken)
{
_enumerable = enumerable;
_continueOnCapturedContext = continueOnCapturedContext;
_cancellationToken = cancellationToken;
}
public ConfiguredCancelableAsyncEnumerable<T> ConfigureAwait(bool continueOnCapturedContext)
{
return new ConfiguredCancelableAsyncEnumerable<T>(_enumerable, continueOnCapturedContext, _cancellationToken);
}
public ConfiguredCancelableAsyncEnumerable<T> WithCancellation(CancellationToken cancellationToken)
{
return new ConfiguredCancelableAsyncEnumerable<T>(_enumerable, _continueOnCapturedContext, cancellationToken);
}
public Enumerator GetAsyncEnumerator()
{
return new Enumerator(_enumerable.GetAsyncEnumerator(_cancellationToken), _continueOnCapturedContext);
}
}
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
public sealed class EnumeratorCancellationAttribute : Attribute
{
}
}
namespace System.Threading.Tasks
{
public static class TaskAsyncEnumerableExtensions
{
public static ConfiguredAsyncDisposable ConfigureAwait(this IAsyncDisposable source, bool continueOnCapturedContext)
{
return new ConfiguredAsyncDisposable(source, continueOnCapturedContext);
}
public static ConfiguredCancelableAsyncEnumerable<T> ConfigureAwait<T>(this IAsyncEnumerable<T> source, bool continueOnCapturedContext)
{
return new ConfiguredCancelableAsyncEnumerable<T>(source, continueOnCapturedContext, default(CancellationToken));
}
public static ConfiguredCancelableAsyncEnumerable<T> WithCancellation<T>(this IAsyncEnumerable<T> source, CancellationToken cancellationToken)
{
return new ConfiguredCancelableAsyncEnumerable<T>(source, continueOnCapturedContext: true, cancellationToken);
}
}
}
namespace System.Threading.Tasks.Sources
{
[StructLayout(LayoutKind.Auto)]
public struct ManualResetValueTaskSourceCore<TResult>
{
private Action<object> _continuation;
private object _continuationState;
private ExecutionContext _executionContext;
private object _capturedContext;
private bool _completed;
private TResult _result;
private ExceptionDispatchInfo _error;
private short _version;
public bool RunContinuationsAsynchronously { get; set; }
public short Version => _version;
public void Reset()
{
_version++;
_completed = false;
_result = default(TResult);
_error = null;
_executionContext = null;
_capturedContext = null;
_continuation = null;
_continuationState = null;
}
public void SetResult(TResult result)
{
_result = result;
SignalCompletion();
}
public void SetException(Exception error)
{
_error = ExceptionDispatchInfo.Capture(error);
SignalCompletion();
}
public ValueTaskSourceStatus GetStatus(short token)
{
ValidateToken(token);
if (_continuation != null && _completed)
{
if (_error != null)
{
if (!(_error.SourceException is OperationCanceledException))
{
return ValueTaskSourceStatus.Faulted;
}
return ValueTaskSourceStatus.Canceled;
}
return ValueTaskSourceStatus.Succeeded;
}
return ValueTaskSourceStatus.Pending;
}
public TResult GetResult(short token)
{
ValidateToken(token);
if (!_completed)
{
throw new InvalidOperationException();
}
_error?.Throw();
return _result;
}
public void OnCompleted(Action<object?> continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags)
{
if (continuation == null)
{
throw new ArgumentNullException("continuation");
}
ValidateToken(token);
if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0)
{
_executionContext = ExecutionContext.Capture();
}
if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0)
{
SynchronizationContext current = SynchronizationContext.Current;
if (current != null && current.GetType() != typeof(SynchronizationContext))
{
_capturedContext = current;
}
else
{
TaskScheduler current2 = TaskScheduler.Current;
if (current2 != TaskScheduler.Default)
{
_capturedContext = current2;
}
}
}
object obj = _continuation;
if (obj == null)
{
_continuationState = state;
obj = Interlocked.CompareExchange(ref _continuation, continuation, null);
}
if (obj == null)
{
return;
}
if (obj != System.Threading.Tasks.Sources.ManualResetValueTaskSourceCoreShared.s_sentinel)
{
throw new InvalidOperationException();
}
object capturedContext = _capturedContext;
if (capturedContext != null)
{
if (!(capturedContext is SynchronizationContext synchronizationContext))
{
if (capturedContext is TaskScheduler scheduler)
{
Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, scheduler);
}
}
else
{
synchronizationContext.Post(delegate(object s)
{
Tuple<Action<object>, object> tuple = (Tuple<Action<object>, object>)s;
tuple.Item1(tuple.Item2);
}, Tuple.Create(continuation, state));
}
}
else
{
Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
}
}
private void ValidateToken(short token)
{
if (token != _version)
{
throw new InvalidOperationException();
}
}
private void SignalCompletion()
{
if (_completed)
{
throw new InvalidOperationException();
}
_completed = true;
if (_continuation == null && Interlocked.CompareExchange(ref _continuation, System.Threading.Tasks.Sources.ManualResetValueTaskSourceCoreShared.s_sentinel, null) == null)
{
return;
}
if (_executionContext != null)
{
ExecutionContext.Run(_executionContext, delegate(object s)
{
((ManualResetValueTaskSourceCore<TResult>)s).InvokeContinuation();
}, this);
}
else
{
InvokeContinuation();
}
}
private void InvokeContinuation()
{
object capturedContext = _capturedContext;
if (capturedContext != null)
{
if (!(capturedContext is SynchronizationContext synchronizationContext))
{
if (capturedContext is TaskScheduler scheduler)
{
Task.Factory.StartNew(_continuation, _continuationState, CancellationToken.None, TaskCreationOptions.DenyChildAttach, scheduler);
}
}
else
{
synchronizationContext.Post(delegate(object s)
{
Tuple<Action<object>, object> tuple = (Tuple<Action<object>, object>)s;
tuple.Item1(tuple.Item2);
}, Tuple.Create(_continuation, _continuationState));
}
}
else if (RunContinuationsAsynchronously)
{
Task.Factory.StartNew(_continuation, _continuationState, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
}
else
{
_continuation(_continuationState);
}
}
}
internal static class ManualResetValueTaskSourceCoreShared
{
internal static readonly Action<object> s_sentinel = CompletionSentinel;
private static void CompletionSentinel(object _)
{
throw new InvalidOperationException();
}
}
}using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Sources;
using FxResources.System.Threading.Channels;
using Internal;
using Microsoft.CodeAnalysis;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyMetadata("Serviceable", "True")]
[assembly: AssemblyMetadata("PreferInbox", "True")]
[assembly: AssemblyDefaultAlias("System.Threading.Channels")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: CLSCompliant(true)]
[assembly: AssemblyMetadata("IsTrimmable", "True")]
[assembly: DefaultDllImportSearchPaths(DllImportSearchPath.System32 | DllImportSearchPath.AssemblyDirectory)]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
[assembly: AssemblyDescription("Provides types for passing data between producers and consumers.\r\n\r\nCommonly Used Types:\r\nSystem.Threading.Channel\r\nSystem.Threading.Channel<T>")]
[assembly: AssemblyFileVersion("9.0.725.31616")]
[assembly: AssemblyInformationalVersion("9.0.7+3c298d9f00936d651cc47d221762474e25277672")]
[assembly: AssemblyProduct("Microsoft® .NET")]
[assembly: AssemblyTitle("System.Threading.Channels")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/dotnet/runtime")]
[assembly: AssemblyVersion("9.0.0.7")]
[module: RefSafetyRules(11)]
[module: System.Runtime.CompilerServices.NullablePublicOnly(false)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class IsReadOnlyAttribute : Attribute
{
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.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]
[Microsoft.CodeAnalysis.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]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class NullablePublicOnlyAttribute : Attribute
{
public readonly bool IncludesInternals;
public NullablePublicOnlyAttribute(bool P_0)
{
IncludesInternals = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 FxResources.System.Threading.Channels
{
internal static class SR
{
}
}
namespace Internal
{
internal static class PaddingHelpers
{
internal const int CACHE_LINE_SIZE = 128;
}
[StructLayout(LayoutKind.Explicit, Size = 124)]
internal struct PaddingFor32
{
}
}
namespace System
{
[StructLayout(LayoutKind.Sequential, Size = 1)]
internal readonly struct VoidResult
{
}
internal static class Obsoletions
{
internal const string SharedUrlFormat = "https://aka.ms/dotnet-warnings/{0}";
internal const string SystemTextEncodingUTF7Message = "The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead.";
internal const string SystemTextEncodingUTF7DiagId = "SYSLIB0001";
internal const string PrincipalPermissionAttributeMessage = "PrincipalPermissionAttribute is not honored by the runtime and must not be used.";
internal const string PrincipalPermissionAttributeDiagId = "SYSLIB0002";
internal const string CodeAccessSecurityMessage = "Code Access Security is not supported or honored by the runtime.";
internal const string CodeAccessSecurityDiagId = "SYSLIB0003";
internal const string ConstrainedExecutionRegionMessage = "The Constrained Execution Region (CER) feature is not supported.";
internal const string ConstrainedExecutionRegionDiagId = "SYSLIB0004";
internal const string GlobalAssemblyCacheMessage = "The Global Assembly Cache is not supported.";
internal const string GlobalAssemblyCacheDiagId = "SYSLIB0005";
internal const string ThreadAbortMessage = "Thread.Abort is not supported and throws PlatformNotSupportedException.";
internal const string ThreadResetAbortMessage = "Thread.ResetAbort is not supported and throws PlatformNotSupportedException.";
internal const string ThreadAbortDiagId = "SYSLIB0006";
internal const string DefaultCryptoAlgorithmsMessage = "The default implementation of this cryptography algorithm is not supported.";
internal const string DefaultCryptoAlgorithmsDiagId = "SYSLIB0007";
internal const string CreatePdbGeneratorMessage = "The CreatePdbGenerator API is not supported and throws PlatformNotSupportedException.";
internal const string CreatePdbGeneratorDiagId = "SYSLIB0008";
internal const string AuthenticationManagerMessage = "AuthenticationManager is not supported. Methods will no-op or throw PlatformNotSupportedException.";
internal const string AuthenticationManagerDiagId = "SYSLIB0009";
internal const string RemotingApisMessage = "This Remoting API is not supported and throws PlatformNotSupportedException.";
internal const string RemotingApisDiagId = "SYSLIB0010";
internal const string BinaryFormatterMessage = "BinaryFormatter serialization is obsolete and should not be used. See https://aka.ms/binaryformatter for more information.";
internal const string BinaryFormatterDiagId = "SYSLIB0011";
internal const string CodeBaseMessage = "Assembly.CodeBase and Assembly.EscapedCodeBase are only included for .NET Framework compatibility. Use Assembly.Location instead.";
internal const string CodeBaseDiagId = "SYSLIB0012";
internal const string EscapeUriStringMessage = "Uri.EscapeUriString can corrupt the Uri string in some cases. Consider using Uri.EscapeDataString for query string components instead.";
internal const string EscapeUriStringDiagId = "SYSLIB0013";
internal const string WebRequestMessage = "WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead.";
internal const string WebRequestDiagId = "SYSLIB0014";
internal const string DisablePrivateReflectionAttributeMessage = "DisablePrivateReflectionAttribute has no effect in .NET 6.0+.";
internal const string DisablePrivateReflectionAttributeDiagId = "SYSLIB0015";
internal const string GetContextInfoMessage = "Use the Graphics.GetContextInfo overloads that accept arguments for better performance and fewer allocations.";
internal const string GetContextInfoDiagId = "SYSLIB0016";
internal const string StrongNameKeyPairMessage = "Strong name signing is not supported and throws PlatformNotSupportedException.";
internal const string StrongNameKeyPairDiagId = "SYSLIB0017";
internal const string ReflectionOnlyLoadingMessage = "ReflectionOnly loading is not supported and throws PlatformNotSupportedException.";
internal const string ReflectionOnlyLoadingDiagId = "SYSLIB0018";
internal const string RuntimeEnvironmentMessage = "RuntimeEnvironment members SystemConfigurationFile, GetRuntimeInterfaceAsIntPtr, and GetRuntimeInterfaceAsObject are not supported and throw PlatformNotSupportedException.";
internal const string RuntimeEnvironmentDiagId = "SYSLIB0019";
internal const string JsonSerializerOptionsIgnoreNullValuesMessage = "JsonSerializerOptions.IgnoreNullValues is obsolete. To ignore null values when serializing, set DefaultIgnoreCondition to JsonIgnoreCondition.WhenWritingNull.";
internal const string JsonSerializerOptionsIgnoreNullValuesDiagId = "SYSLIB0020";
internal const string DerivedCryptographicTypesMessage = "Derived cryptographic types are obsolete. Use the Create method on the base type instead.";
internal const string DerivedCryptographicTypesDiagId = "SYSLIB0021";
internal const string RijndaelMessage = "The Rijndael and RijndaelManaged types are obsolete. Use Aes instead.";
internal const string RijndaelDiagId = "SYSLIB0022";
internal const string RNGCryptoServiceProviderMessage = "RNGCryptoServiceProvider is obsolete. To generate a random number, use one of the RandomNumberGenerator static methods instead.";
internal const string RNGCryptoServiceProviderDiagId = "SYSLIB0023";
internal const string AppDomainCreateUnloadMessage = "Creating and unloading AppDomains is not supported and throws an exception.";
internal const string AppDomainCreateUnloadDiagId = "SYSLIB0024";
internal const string SuppressIldasmAttributeMessage = "SuppressIldasmAttribute has no effect in .NET 6.0+.";
internal const string SuppressIldasmAttributeDiagId = "SYSLIB0025";
internal const string X509CertificateImmutableMessage = "X509Certificate and X509Certificate2 are immutable. Use X509CertificateLoader to create a new certificate.";
internal const string X509CertificateImmutableDiagId = "SYSLIB0026";
internal const string PublicKeyPropertyMessage = "PublicKey.Key is obsolete. Use the appropriate method to get the public key, such as GetRSAPublicKey.";
internal const string PublicKeyPropertyDiagId = "SYSLIB0027";
internal const string X509CertificatePrivateKeyMessage = "X509Certificate2.PrivateKey is obsolete. Use the appropriate method to get the private key, such as GetRSAPrivateKey, or use the CopyWithPrivateKey method to create a new instance with a private key.";
internal const string X509CertificatePrivateKeyDiagId = "SYSLIB0028";
internal const string ProduceLegacyHmacValuesMessage = "ProduceLegacyHmacValues is obsolete. Producing legacy HMAC values is not supported.";
internal const string ProduceLegacyHmacValuesDiagId = "SYSLIB0029";
internal const string UseManagedSha1Message = "HMACSHA1 always uses the algorithm implementation provided by the platform. Use a constructor without the useManagedSha1 parameter.";
internal const string UseManagedSha1DiagId = "SYSLIB0030";
internal const string CryptoConfigEncodeOIDMessage = "EncodeOID is obsolete. Use the ASN.1 functionality provided in System.Formats.Asn1.";
internal const string CryptoConfigEncodeOIDDiagId = "SYSLIB0031";
internal const string CorruptedStateRecoveryMessage = "Recovery from corrupted process state exceptions is not supported; HandleProcessCorruptedStateExceptionsAttribute is ignored.";
internal const string CorruptedStateRecoveryDiagId = "SYSLIB0032";
internal const string Rfc2898CryptDeriveKeyMessage = "Rfc2898DeriveBytes.CryptDeriveKey is obsolete and is not supported. Use PasswordDeriveBytes.CryptDeriveKey instead.";
internal const string Rfc2898CryptDeriveKeyDiagId = "SYSLIB0033";
internal const string CmsSignerCspParamsCtorMessage = "CmsSigner(CspParameters) is obsolete and is not supported. Use an alternative constructor instead.";
internal const string CmsSignerCspParamsCtorDiagId = "SYSLIB0034";
internal const string SignerInfoCounterSigMessage = "ComputeCounterSignature without specifying a CmsSigner is obsolete and is not supported. Use the overload that accepts a CmsSigner.";
internal const string SignerInfoCounterSigDiagId = "SYSLIB0035";
internal const string RegexCompileToAssemblyMessage = "Regex.CompileToAssembly is obsolete and not supported. Use the GeneratedRegexAttribute with the regular expression source generator instead.";
internal const string RegexCompileToAssemblyDiagId = "SYSLIB0036";
internal const string AssemblyNameMembersMessage = "AssemblyName members HashAlgorithm, ProcessorArchitecture, and VersionCompatibility are obsolete and not supported.";
internal const string AssemblyNameMembersDiagId = "SYSLIB0037";
internal const string SystemDataSerializationFormatBinaryMessage = "SerializationFormat.Binary is obsolete and should not be used. See https://aka.ms/serializationformat-binary-obsolete for more information.";
internal const string SystemDataSerializationFormatBinaryDiagId = "SYSLIB0038";
internal const string TlsVersion10and11Message = "TLS versions 1.0 and 1.1 have known vulnerabilities and are not recommended. Use a newer TLS version instead, or use SslProtocols.None to defer to OS defaults.";
internal const string TlsVersion10and11DiagId = "SYSLIB0039";
internal const string EncryptionPolicyMessage = "EncryptionPolicy.NoEncryption and AllowEncryption significantly reduce security and should not be used in production code.";
internal const string EncryptionPolicyDiagId = "SYSLIB0040";
internal const string Rfc2898OutdatedCtorMessage = "The default hash algorithm and iteration counts in Rfc2898DeriveBytes constructors are outdated and insecure. Use a constructor that accepts the hash algorithm and the number of iterations.";
internal const string Rfc2898OutdatedCtorDiagId = "SYSLIB0041";
internal const string EccXmlExportImportMessage = "ToXmlString and FromXmlString have no implementation for ECC types, and are obsolete. Use a standard import and export format such as ExportSubjectPublicKeyInfo or ImportSubjectPublicKeyInfo for public keys and ExportPkcs8PrivateKey or ImportPkcs8PrivateKey for private keys.";
internal const string EccXmlExportImportDiagId = "SYSLIB0042";
internal const string EcDhPublicKeyBlobMessage = "ECDiffieHellmanPublicKey.ToByteArray() and the associated constructor do not have a consistent and interoperable implementation on all platforms. Use ECDiffieHellmanPublicKey.ExportSubjectPublicKeyInfo() instead.";
internal const string EcDhPublicKeyBlobDiagId = "SYSLIB0043";
internal const string AssemblyNameCodeBaseMessage = "AssemblyName.CodeBase and AssemblyName.EscapedCodeBase are obsolete. Using them for loading an assembly is not supported.";
internal const string AssemblyNameCodeBaseDiagId = "SYSLIB0044";
internal const string CryptoStringFactoryMessage = "Cryptographic factory methods accepting an algorithm name are obsolete. Use the parameterless Create factory method on the algorithm type instead.";
internal const string CryptoStringFactoryDiagId = "SYSLIB0045";
internal const string ControlledExecutionRunMessage = "ControlledExecution.Run method may corrupt the process and should not be used in production code.";
internal const string ControlledExecutionRunDiagId = "SYSLIB0046";
internal const string XmlSecureResolverMessage = "XmlSecureResolver is obsolete. Use XmlResolver.ThrowingResolver instead when attempting to forbid XML external entity resolution.";
internal const string XmlSecureResolverDiagId = "SYSLIB0047";
internal const string RsaEncryptDecryptValueMessage = "RSA.EncryptValue and DecryptValue are not supported and throw NotSupportedException. Use RSA.Encrypt and RSA.Decrypt instead.";
internal const string RsaEncryptDecryptDiagId = "SYSLIB0048";
internal const string JsonSerializerOptionsAddContextMessage = "JsonSerializerOptions.AddContext is obsolete. To register a JsonSerializerContext, use either the TypeInfoResolver or TypeInfoResolverChain properties.";
internal const string JsonSerializerOptionsAddContextDiagId = "SYSLIB0049";
internal const string LegacyFormatterMessage = "Formatter-based serialization is obsolete and should not be used.";
internal const string LegacyFormatterDiagId = "SYSLIB0050";
internal const string LegacyFormatterImplMessage = "This API supports obsolete formatter-based serialization. It should not be called or extended by application code.";
internal const string LegacyFormatterImplDiagId = "SYSLIB0051";
internal const string RegexExtensibilityImplMessage = "This API supports obsolete mechanisms for Regex extensibility. It is not supported.";
internal const string RegexExtensibilityDiagId = "SYSLIB0052";
internal const string AesGcmTagConstructorMessage = "AesGcm should indicate the required tag size for encryption and decryption. Use a constructor that accepts the tag size.";
internal const string AesGcmTagConstructorDiagId = "SYSLIB0053";
internal const string ThreadVolatileReadWriteMessage = "Thread.VolatileRead and Thread.VolatileWrite are obsolete. Use Volatile.Read or Volatile.Write respectively instead.";
internal const string ThreadVolatileReadWriteDiagId = "SYSLIB0054";
internal const string ArmIntrinsicPerformsUnsignedOperationMessage = "The underlying hardware instruction does not perform a signed saturate narrowing operation, and it always returns an unsigned result. Use the unsigned overload instead.";
internal const string ArmIntrinsicPerformsUnsignedOperationDiagId = "SYSLIB0055";
internal const string LoadFromHashAlgorithmMessage = "LoadFrom with a custom AssemblyHashAlgorithm is obsolete. Use overloads without an AssemblyHashAlgorithm.";
internal const string LoadFromHashAlgorithmDiagId = "SYSLIB0056";
internal const string X509CtorCertDataObsoleteMessage = "Loading certificate data through the constructor or Import is obsolete. Use X509CertificateLoader instead to load certificates.";
internal const string X509CtorCertDataObsoleteDiagId = "SYSLIB0057";
}
internal static class SR
{
private static readonly bool s_usingResourceKeys = GetUsingResourceKeysSwitchValue();
private static ResourceManager s_resourceManager;
internal static ResourceManager ResourceManager => s_resourceManager ?? (s_resourceManager = new ResourceManager(typeof(SR)));
internal static string ChannelClosedException_DefaultMessage => GetResourceString("ChannelClosedException_DefaultMessage");
internal static string InvalidOperation_IncompleteAsyncOperation => GetResourceString("InvalidOperation_IncompleteAsyncOperation");
internal static string InvalidOperation_MultipleContinuations => GetResourceString("InvalidOperation_MultipleContinuations");
internal static string InvalidOperation_IncorrectToken => GetResourceString("InvalidOperation_IncorrectToken");
private static bool GetUsingResourceKeysSwitchValue()
{
if (!AppContext.TryGetSwitch("System.Resources.UseSystemResourceKeys", out var isEnabled))
{
return false;
}
return isEnabled;
}
internal static bool UsingResourceKeys()
{
return s_usingResourceKeys;
}
private static string GetResourceString(string resourceKey)
{
if (UsingResourceKeys())
{
return resourceKey;
}
string result = null;
try
{
result = ResourceManager.GetString(resourceKey);
}
catch (MissingManifestResourceException)
{
}
return result;
}
private static string GetResourceString(string resourceKey, string defaultString)
{
string resourceString = GetResourceString(resourceKey);
if (!(resourceKey == resourceString) && resourceString != null)
{
return resourceString;
}
return defaultString;
}
internal static string Format(string resourceFormat, object p1)
{
if (UsingResourceKeys())
{
return string.Join(", ", resourceFormat, p1);
}
return string.Format(resourceFormat, p1);
}
internal static string Format(string resourceFormat, object p1, object p2)
{
if (UsingResourceKeys())
{
return string.Join(", ", resourceFormat, p1, p2);
}
return string.Format(resourceFormat, p1, p2);
}
internal static string Format(string resourceFormat, object p1, object p2, object p3)
{
if (UsingResourceKeys())
{
return string.Join(", ", resourceFormat, p1, p2, p3);
}
return string.Format(resourceFormat, p1, p2, p3);
}
internal static string Format(string resourceFormat, params object[] args)
{
if (args != null)
{
if (UsingResourceKeys())
{
return resourceFormat + ", " + string.Join(", ", args);
}
return string.Format(resourceFormat, args);
}
return resourceFormat;
}
internal static string Format(IFormatProvider provider, string resourceFormat, object p1)
{
if (UsingResourceKeys())
{
return string.Join(", ", resourceFormat, p1);
}
return string.Format(provider, resourceFormat, p1);
}
internal static string Format(IFormatProvider provider, string resourceFormat, object p1, object p2)
{
if (UsingResourceKeys())
{
return string.Join(", ", resourceFormat, p1, p2);
}
return string.Format(provider, resourceFormat, p1, p2);
}
internal static string Format(IFormatProvider provider, string resourceFormat, object p1, object p2, object p3)
{
if (UsingResourceKeys())
{
return string.Join(", ", resourceFormat, p1, p2, p3);
}
return string.Format(provider, resourceFormat, p1, p2, p3);
}
internal static string Format(IFormatProvider provider, string resourceFormat, params object[] args)
{
if (args != null)
{
if (UsingResourceKeys())
{
return resourceFormat + ", " + string.Join(", ", args);
}
return string.Format(provider, resourceFormat, args);
}
return resourceFormat;
}
}
}
namespace System.Diagnostics.CodeAnalysis
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)]
internal sealed class AllowNullAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)]
internal sealed class DisallowNullAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)]
internal sealed class MaybeNullAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)]
internal sealed class NotNullAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
internal sealed class MaybeNullWhenAttribute : Attribute
{
public bool ReturnValue { get; }
public MaybeNullWhenAttribute(bool returnValue)
{
ReturnValue = returnValue;
}
}
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
internal sealed class NotNullWhenAttribute : Attribute
{
public bool ReturnValue { get; }
public NotNullWhenAttribute(bool returnValue)
{
ReturnValue = returnValue;
}
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
internal sealed class NotNullIfNotNullAttribute : Attribute
{
public string ParameterName { get; }
public NotNullIfNotNullAttribute(string parameterName)
{
ParameterName = parameterName;
}
}
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
internal sealed class DoesNotReturnAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
internal sealed class DoesNotReturnIfAttribute : Attribute
{
public bool ParameterValue { get; }
public DoesNotReturnIfAttribute(bool parameterValue)
{
ParameterValue = parameterValue;
}
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
internal sealed class MemberNotNullAttribute : Attribute
{
public string[] Members { get; }
public MemberNotNullAttribute(string member)
{
Members = new string[1] { member };
}
public MemberNotNullAttribute(params string[] members)
{
Members = members;
}
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
internal sealed class MemberNotNullWhenAttribute : Attribute
{
public bool ReturnValue { get; }
public string[] Members { get; }
public MemberNotNullWhenAttribute(bool returnValue, string member)
{
ReturnValue = returnValue;
Members = new string[1] { member };
}
public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
{
ReturnValue = returnValue;
Members = members;
}
}
}
namespace System.Runtime.InteropServices
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
internal sealed class LibraryImportAttribute : Attribute
{
public string LibraryName { get; }
public string EntryPoint { get; set; }
public StringMarshalling StringMarshalling { get; set; }
public Type StringMarshallingCustomType { get; set; }
public bool SetLastError { get; set; }
public LibraryImportAttribute(string libraryName)
{
LibraryName = libraryName;
}
}
internal enum StringMarshalling
{
Custom,
Utf8,
Utf16
}
}
namespace System.Collections.Generic
{
[DebuggerDisplay("Count = {_size}")]
internal sealed class Deque<T>
{
private T[] _array = Array.Empty<T>();
private int _head;
private int _tail;
private int _size;
public int Count => _size;
public bool IsEmpty => _size == 0;
public void EnqueueTail(T item)
{
if (_size == _array.Length)
{
Grow();
}
_array[_tail] = item;
if (++_tail == _array.Length)
{
_tail = 0;
}
_size++;
}
public T DequeueHead()
{
T result = _array[_head];
_array[_head] = default(T);
if (++_head == _array.Length)
{
_head = 0;
}
_size--;
return result;
}
public T PeekHead()
{
return _array[_head];
}
public T PeekTail()
{
int num = _tail - 1;
if (num == -1)
{
num = _array.Length - 1;
}
return _array[num];
}
public T DequeueTail()
{
if (--_tail == -1)
{
_tail = _array.Length - 1;
}
T result = _array[_tail];
_array[_tail] = default(T);
_size--;
return result;
}
public IEnumerator<T> GetEnumerator()
{
int pos = _head;
int count = _size;
while (count-- > 0)
{
yield return _array[pos];
pos = (pos + 1) % _array.Length;
}
}
private void Grow()
{
int num = (int)((long)_array.Length * 2L);
if (num < _array.Length + 4)
{
num = _array.Length + 4;
}
T[] array = new T[num];
if (_head == 0)
{
Array.Copy(_array, array, _size);
}
else
{
Array.Copy(_array, _head, array, 0, _array.Length - _head);
Array.Copy(_array, 0, array, _array.Length - _head, _tail);
}
_array = array;
_head = 0;
_tail = _size;
}
}
}
namespace System.Collections.Concurrent
{
internal interface IProducerConsumerQueue<T> : IEnumerable<T>, IEnumerable
{
bool IsEmpty { get; }
int Count { get; }
void Enqueue(T item);
bool TryDequeue([MaybeNullWhen(false)] out T result);
int GetCountSafe(object syncObj);
}
[DebuggerDisplay("Count = {Count}")]
internal sealed class MultiProducerMultiConsumerQueue<T> : ConcurrentQueue<T>, IProducerConsumerQueue<T>, IEnumerable<T>, IEnumerable
{
bool IProducerConsumerQueue<T>.IsEmpty => base.IsEmpty;
int IProducerConsumerQueue<T>.Count => base.Count;
void IProducerConsumerQueue<T>.Enqueue(T item)
{
Enqueue(item);
}
bool IProducerConsumerQueue<T>.TryDequeue([MaybeNullWhen(false)] out T result)
{
return TryDequeue(out result);
}
int IProducerConsumerQueue<T>.GetCountSafe(object syncObj)
{
return base.Count;
}
}
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(SingleProducerSingleConsumerQueue<>.SingleProducerSingleConsumerQueue_DebugView))]
internal sealed class SingleProducerSingleConsumerQueue<T> : IProducerConsumerQueue<T>, IEnumerable<T>, IEnumerable
{
[StructLayout(LayoutKind.Sequential)]
private sealed class Segment
{
internal Segment _next;
internal readonly T[] _array;
internal SegmentState _state;
internal Segment(int size)
{
_array = new T[size];
}
}
private struct SegmentState
{
internal Internal.PaddingFor32 _pad0;
internal volatile int _first;
internal int _lastCopy;
internal Internal.PaddingFor32 _pad1;
internal int _firstCopy;
internal volatile int _last;
internal Internal.PaddingFor32 _pad2;
}
private sealed class SingleProducerSingleConsumerQueue_DebugView
{
private readonly SingleProducerSingleConsumerQueue<T> _queue;
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public T[] Items => new List<T>(_queue).ToArray();
public SingleProducerSingleConsumerQueue_DebugView(SingleProducerSingleConsumerQueue<T> queue)
{
_queue = queue;
}
}
private const int InitialSegmentSize = 32;
private const int MaxSegmentSize = 16777216;
private volatile Segment _head;
private volatile Segment _tail;
public bool IsEmpty
{
get
{
Segment head = _head;
if (head._state._first != head._state._lastCopy)
{
return false;
}
if (head._state._first != head._state._last)
{
return false;
}
return head._next == null;
}
}
public int Count
{
get
{
int num = 0;
for (Segment segment = _head; segment != null; segment = segment._next)
{
int num2 = segment._array.Length;
int first;
int last;
do
{
first = segment._state._first;
last = segment._state._last;
}
while (first != segment._state._first);
num += (last - first) & (num2 - 1);
}
return num;
}
}
public SingleProducerSingleConsumerQueue()
{
_head = (_tail = new Segment(32));
}
public void Enqueue(T item)
{
Segment segment = _tail;
T[] array = segment._array;
int last = segment._state._last;
int num = (last + 1) & (array.Length - 1);
if (num != segment._state._firstCopy)
{
array[last] = item;
segment._state._last = num;
}
else
{
EnqueueSlow(item, ref segment);
}
}
private void EnqueueSlow(T item, ref Segment segment)
{
if (segment._state._firstCopy != segment._state._first)
{
segment._state._firstCopy = segment._state._first;
Enqueue(item);
return;
}
Segment segment2 = new Segment(Math.Min(_tail._array.Length * 2, 16777216));
segment2._array[0] = item;
segment2._state._last = 1;
segment2._state._lastCopy = 1;
try
{
}
finally
{
Volatile.Write(ref _tail._next, segment2);
_tail = segment2;
}
}
public bool TryDequeue([MaybeNullWhen(false)] out T result)
{
Segment head = _head;
T[] array = head._array;
int first = head._state._first;
if (first != head._state._lastCopy)
{
result = array[first];
array[first] = default(T);
head._state._first = (first + 1) & (array.Length - 1);
return true;
}
return TryDequeueSlow(head, array, peek: false, out result);
}
public bool TryPeek([MaybeNullWhen(false)] out T result)
{
Segment head = _head;
T[] array = head._array;
int first = head._state._first;
if (first != head._state._lastCopy)
{
result = array[first];
return true;
}
return TryDequeueSlow(head, array, peek: true, out result);
}
private bool TryDequeueSlow(Segment segment, T[] array, bool peek, [MaybeNullWhen(false)] out T result)
{
if (segment._state._last != segment._state._lastCopy)
{
segment._state._lastCopy = segment._state._last;
if (!peek)
{
return TryDequeue(out result);
}
return TryPeek(out result);
}
if (segment._next != null && segment._state._first == segment._state._last)
{
segment = segment._next;
array = segment._array;
_head = segment;
}
int first = segment._state._first;
if (first == segment._state._last)
{
result = default(T);
return false;
}
result = array[first];
if (!peek)
{
array[first] = default(T);
segment._state._first = (first + 1) & (segment._array.Length - 1);
segment._state._lastCopy = segment._state._last;
}
return true;
}
public bool TryDequeueIf(Predicate<T> predicate, [MaybeNullWhen(false)] out T result)
{
Segment head = _head;
T[] array = head._array;
int first = head._state._first;
if (first != head._state._lastCopy)
{
result = array[first];
if (predicate == null || predicate(result))
{
array[first] = default(T);
head._state._first = (first + 1) & (array.Length - 1);
return true;
}
result = default(T);
return false;
}
return TryDequeueIfSlow(predicate, head, array, out result);
}
private bool TryDequeueIfSlow(Predicate<T> predicate, Segment segment, T[] array, [MaybeNullWhen(false)] out T result)
{
if (segment._state._last != segment._state._lastCopy)
{
segment._state._lastCopy = segment._state._last;
return TryDequeueIf(predicate, out result);
}
if (segment._next != null && segment._state._first == segment._state._last)
{
segment = segment._next;
array = segment._array;
_head = segment;
}
int first = segment._state._first;
if (first == segment._state._last)
{
result = default(T);
return false;
}
result = array[first];
if (predicate == null || predicate(result))
{
array[first] = default(T);
segment._state._first = (first + 1) & (segment._array.Length - 1);
segment._state._lastCopy = segment._state._last;
return true;
}
result = default(T);
return false;
}
public void Clear()
{
T result;
while (TryDequeue(out result))
{
}
}
public IEnumerator<T> GetEnumerator()
{
for (Segment segment = _head; segment != null; segment = segment._next)
{
for (int pt = segment._state._first; pt != segment._state._last; pt = (pt + 1) & (segment._array.Length - 1))
{
yield return segment._array[pt];
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
int IProducerConsumerQueue<T>.GetCountSafe(object syncObj)
{
lock (syncObj)
{
return Count;
}
}
}
}
namespace System.Threading.Channels
{
internal abstract class AsyncOperation
{
protected static readonly Action<object> s_availableSentinel = AvailableSentinel;
protected static readonly Action<object> s_completedSentinel = CompletedSentinel;
private static void AvailableSentinel(object s)
{
}
private static void CompletedSentinel(object s)
{
}
protected static void ThrowIncompleteOperationException()
{
throw new InvalidOperationException(System.SR.InvalidOperation_IncompleteAsyncOperation);
}
protected static void ThrowMultipleContinuations()
{
throw new InvalidOperationException(System.SR.InvalidOperation_MultipleContinuations);
}
protected static void ThrowIncorrectCurrentIdException()
{
throw new InvalidOperationException(System.SR.InvalidOperation_IncorrectToken);
}
}
internal class AsyncOperation<TResult> : AsyncOperation, IValueTaskSource, IValueTaskSource<TResult>
{
private readonly CancellationTokenRegistration _registration;
private readonly bool _pooled;
private readonly bool _runContinuationsAsynchronously;
private volatile int _completionReserved;
private TResult _result;
private ExceptionDispatchInfo _error;
private Action<object> _continuation;
private object _continuationState;
private object _schedulingContext;
private ExecutionContext _executionContext;
private short _currentId;
public AsyncOperation<TResult> Next { get; set; }
public CancellationToken CancellationToken { get; }
public ValueTask ValueTask => new ValueTask(this, _currentId);
public ValueTask<TResult> ValueTaskOfT => new ValueTask<TResult>(this, _currentId);
internal bool IsCompleted => (object)_continuation == AsyncOperation.s_completedSentinel;
public AsyncOperation(bool runContinuationsAsynchronously, CancellationToken cancellationToken = default(CancellationToken), bool pooled = false)
{
_continuation = (pooled ? AsyncOperation.s_availableSentinel : null);
_pooled = pooled;
_runContinuationsAsynchronously = runContinuationsAsynchronously;
if (cancellationToken.CanBeCanceled)
{
CancellationToken = cancellationToken;
_registration = UnsafeRegister(cancellationToken, delegate(object s)
{
AsyncOperation<TResult> obj = (AsyncOperation<TResult>)s;
obj.TrySetCanceled(obj.CancellationToken);
}, this);
}
}
public ValueTaskSourceStatus GetStatus(short token)
{
if (_currentId != token)
{
AsyncOperation.ThrowIncorrectCurrentIdException();
}
if (IsCompleted)
{
if (_error != null)
{
if (!(_error.SourceException is OperationCanceledException))
{
return ValueTaskSourceStatus.Faulted;
}
return ValueTaskSourceStatus.Canceled;
}
return ValueTaskSourceStatus.Succeeded;
}
return ValueTaskSourceStatus.Pending;
}
public TResult GetResult(short token)
{
if (_currentId != token)
{
AsyncOperation.ThrowIncorrectCurrentIdException();
}
if (!IsCompleted)
{
AsyncOperation.ThrowIncompleteOperationException();
}
ExceptionDispatchInfo error = _error;
TResult result = _result;
_currentId++;
if (_pooled)
{
Volatile.Write(ref _continuation, AsyncOperation.s_availableSentinel);
}
error?.Throw();
return result;
}
void IValueTaskSource.GetResult(short token)
{
if (_currentId != token)
{
AsyncOperation.ThrowIncorrectCurrentIdException();
}
if (!IsCompleted)
{
AsyncOperation.ThrowIncompleteOperationException();
}
ExceptionDispatchInfo error = _error;
_currentId++;
if (_pooled)
{
Volatile.Write(ref _continuation, AsyncOperation.s_availableSentinel);
}
error?.Throw();
}
public bool TryOwnAndReset()
{
if ((object)Interlocked.CompareExchange(ref _continuation, null, AsyncOperation.s_availableSentinel) == AsyncOperation.s_availableSentinel)
{
_continuationState = null;
_result = default(TResult);
_error = null;
_schedulingContext = null;
_executionContext = null;
return true;
}
return false;
}
public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
{
if (_currentId != token)
{
AsyncOperation.ThrowIncorrectCurrentIdException();
}
if (_continuationState != null)
{
AsyncOperation.ThrowMultipleContinuations();
}
_continuationState = state;
if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0)
{
_executionContext = ExecutionContext.Capture();
}
SynchronizationContext synchronizationContext = null;
TaskScheduler taskScheduler = null;
if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0)
{
synchronizationContext = SynchronizationContext.Current;
if (synchronizationContext != null && synchronizationContext.GetType() != typeof(SynchronizationContext))
{
_schedulingContext = synchronizationContext;
}
else
{
synchronizationContext = null;
taskScheduler = TaskScheduler.Current;
if (taskScheduler != TaskScheduler.Default)
{
_schedulingContext = taskScheduler;
}
}
}
Action<object> action = Interlocked.CompareExchange(ref _continuation, continuation, null);
if (action == null)
{
return;
}
if ((object)action != AsyncOperation.s_completedSentinel)
{
AsyncOperation.ThrowMultipleContinuations();
}
if (_schedulingContext == null)
{
if (_executionContext == null)
{
UnsafeQueueUserWorkItem(continuation, state);
}
else
{
QueueUserWorkItem(continuation, state);
}
}
else if (synchronizationContext != null)
{
synchronizationContext.Post(delegate(object s)
{
KeyValuePair<Action<object>, object> keyValuePair = (KeyValuePair<Action<object>, object>)s;
keyValuePair.Key(keyValuePair.Value);
}, new KeyValuePair<Action<object>, object>(continuation, state));
}
else
{
Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, taskScheduler);
}
}
public bool UnregisterCancellation()
{
if (CancellationToken.CanBeCanceled)
{
CancellationTokenRegistration registration = _registration;
registration.Dispose();
return _completionReserved == 0;
}
return true;
}
public bool TrySetResult(TResult item)
{
UnregisterCancellation();
if (TryReserveCompletionIfCancelable())
{
_result = item;
SignalCompletion();
return true;
}
return false;
}
public bool TrySetException(Exception exception)
{
UnregisterCancellation();
if (TryReserveCompletionIfCancelable())
{
_error = ExceptionDispatchInfo.Capture(exception);
SignalCompletion();
return true;
}
return false;
}
public bool TrySetCanceled(CancellationToken cancellationToken = default(CancellationToken))
{
if (TryReserveCompletionIfCancelable())
{
_error = ExceptionDispatchInfo.Capture(new OperationCanceledException(cancellationToken));
SignalCompletion();
return true;
}
return false;
}
private bool TryReserveCompletionIfCancelable()
{
if (CancellationToken.CanBeCanceled)
{
return Interlocked.CompareExchange(ref _completionReserved, 1, 0) == 0;
}
return true;
}
private void SignalCompletion()
{
if (_continuation == null && Interlocked.CompareExchange(ref _continuation, AsyncOperation.s_completedSentinel, null) == null)
{
return;
}
if (_schedulingContext == null)
{
if (_runContinuationsAsynchronously)
{
UnsafeQueueSetCompletionAndInvokeContinuation();
return;
}
}
else if (_schedulingContext is SynchronizationContext synchronizationContext)
{
if (_runContinuationsAsynchronously || synchronizationContext != SynchronizationContext.Current)
{
synchronizationContext.Post(delegate(object s)
{
((AsyncOperation<TResult>)s).SetCompletionAndInvokeContinuation();
}, this);
return;
}
}
else
{
TaskScheduler taskScheduler = (TaskScheduler)_schedulingContext;
if (_runContinuationsAsynchronously || taskScheduler != TaskScheduler.Current)
{
Task.Factory.StartNew(delegate(object s)
{
((AsyncOperation<TResult>)s).SetCompletionAndInvokeContinuation();
}, this, CancellationToken.None, TaskCreationOptions.DenyChildAttach, taskScheduler);
return;
}
}
SetCompletionAndInvokeContinuation();
}
private void SetCompletionAndInvokeContinuation()
{
if (_executionContext == null)
{
Action<object> continuation = _continuation;
_continuation = AsyncOperation.s_completedSentinel;
continuation(_continuationState);
return;
}
ExecutionContext.Run(_executionContext, delegate(object s)
{
AsyncOperation<TResult> asyncOperation = (AsyncOperation<TResult>)s;
Action<object> continuation2 = asyncOperation._continuation;
asyncOperation._continuation = AsyncOperation.s_completedSentinel;
continuation2(asyncOperation._continuationState);
}, this);
}
private void UnsafeQueueSetCompletionAndInvokeContinuation()
{
ThreadPool.UnsafeQueueUserWorkItem(delegate(object s)
{
((AsyncOperation<TResult>)s).SetCompletionAndInvokeContinuation();
}, this);
}
private static void UnsafeQueueUserWorkItem(Action<object> action, object state)
{
QueueUserWorkItem(action, state);
}
private static void QueueUserWorkItem(Action<object> action, object state)
{
Task.Factory.StartNew(action, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
}
private static CancellationTokenRegistration UnsafeRegister(CancellationToken cancellationToken, Action<object> action, object state)
{
return cancellationToken.Register(action, state);
}
}
internal sealed class VoidAsyncOperationWithData<TData> : AsyncOperation<VoidResult>
{
public TData Item { get; set; }
public VoidAsyncOperationWithData(bool runContinuationsAsynchronously, CancellationToken cancellationToken = default(CancellationToken), bool pooled = false)
: base(runContinuationsAsynchronously, cancellationToken, pooled)
{
}
}
[DebuggerDisplay("Items = {ItemsCountForDebugger}, Capacity = {_bufferedCapacity}, Mode = {_mode}, Closed = {ChannelIsClosedForDebugger}")]
[DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
internal sealed class BoundedChannel<T> : Channel<T>, IDebugEnumerable<T>
{
[DebuggerDisplay("Items = {ItemsCountForDebugger}")]
[DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
private sealed class BoundedChannelReader : ChannelReader<T>, IDebugEnumerable<T>
{
internal readonly BoundedChannel<T> _parent;
private readonly AsyncOperation<T> _readerSingleton;
private readonly AsyncOperation<bool> _waiterSingleton;
public override Task Completion => _parent._completion.Task;
public override bool CanCount => true;
public override bool CanPeek => true;
public override int Count
{
get
{
BoundedChannel<T> parent = _parent;
lock (parent.SyncObj)
{
return parent._items.Count;
}
}
}
private int ItemsCountForDebugger => _parent._items.Count;
internal BoundedChannelReader(BoundedChannel<T> parent)
{
_parent = parent;
_readerSingleton = new AsyncOperation<T>(parent._runContinuationsAsynchronously, default(CancellationToken), pooled: true);
_waiterSingleton = new AsyncOperation<bool>(parent._runContinuationsAsynchronously, default(CancellationToken), pooled: true);
}
public override bool TryRead([MaybeNullWhen(false)] out T item)
{
BoundedChannel<T> parent = _parent;
lock (parent.SyncObj)
{
if (!parent._items.IsEmpty)
{
item = DequeueItemAndPostProcess();
return true;
}
}
item = default(T);
return false;
}
public override bool TryPeek([MaybeNullWhen(false)] out T item)
{
BoundedChannel<T> parent = _parent;
lock (parent.SyncObj)
{
if (!parent._items.IsEmpty)
{
item = parent._items.PeekHead();
return true;
}
}
item = default(T);
return false;
}
public override ValueTask<T> ReadAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return new ValueTask<T>(Task.FromCanceled<T>(cancellationToken));
}
BoundedChannel<T> parent = _parent;
lock (parent.SyncObj)
{
if (!parent._items.IsEmpty)
{
return new ValueTask<T>(DequeueItemAndPostProcess());
}
if (parent._doneWriting != null)
{
return ChannelUtilities.GetInvalidCompletionValueTask<T>(parent._doneWriting);
}
if (!cancellationToken.CanBeCanceled)
{
AsyncOperation<T> readerSingleton = _readerSingleton;
if (readerSingleton.TryOwnAndReset())
{
parent._blockedReaders.EnqueueTail(readerSingleton);
return readerSingleton.ValueTaskOfT;
}
}
AsyncOperation<T> asyncOperation = new AsyncOperation<T>(parent._runContinuationsAsynchronously | cancellationToken.CanBeCanceled, cancellationToken);
parent._blockedReaders.EnqueueTail(asyncOperation);
return asyncOperation.ValueTaskOfT;
}
}
public override ValueTask<bool> WaitToReadAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken));
}
BoundedChannel<T> parent = _parent;
lock (parent.SyncObj)
{
if (!parent._items.IsEmpty)
{
return new ValueTask<bool>(result: true);
}
if (parent._doneWriting != null)
{
return (parent._doneWriting != ChannelUtilities.s_doneWritingSentinel) ? new ValueTask<bool>(Task.FromException<bool>(parent._doneWriting)) : default(ValueTask<bool>);
}
if (!cancellationToken.CanBeCanceled)
{
AsyncOperation<bool> waiterSingleton = _waiterSingleton;
if (waiterSingleton.TryOwnAndReset())
{
ChannelUtilities.QueueWaiter(ref parent._waitingReadersTail, waiterSingleton);
return waiterSingleton.ValueTaskOfT;
}
}
AsyncOperation<bool> asyncOperation = new AsyncOperation<bool>(parent._runContinuationsAsynchronously | cancellationToken.CanBeCanceled, cancellationToken);
ChannelUtilities.QueueWaiter(ref _parent._waitingReadersTail, asyncOperation);
return asyncOperation.ValueTaskOfT;
}
}
private T DequeueItemAndPostProcess()
{
BoundedChannel<T> parent = _parent;
T result = parent._items.DequeueHead();
if (parent._doneWriting != null)
{
if (parent._items.IsEmpty)
{
ChannelUtilities.Complete(parent._completion, parent._doneWriting);
}
}
else
{
while (!parent._blockedWriters.IsEmpty)
{
VoidAsyncOperationWithData<T> voidAsyncOperationWithData = parent._blockedWriters.DequeueHead();
if (voidAsyncOperationWithData.TrySetResult(default(VoidResult)))
{
parent._items.EnqueueTail(voidAsyncOperationWithData.Item);
return result;
}
}
ChannelUtilities.WakeUpWaiters(ref parent._waitingWritersTail, result: true);
}
return result;
}
IEnumerator<T> IDebugEnumerable<T>.GetEnumerator()
{
return _parent._items.GetEnumerator();
}
}
[DebuggerDisplay("Items = {ItemsCountForDebugger}, Capacity = {CapacityForDebugger}")]
[DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
private sealed class BoundedChannelWriter : ChannelWriter<T>, IDebugEnumerable<T>
{
internal readonly BoundedChannel<T> _parent;
private readonly VoidAsyncOperationWithData<T> _writerSingleton;
private readonly AsyncOperation<bool> _waiterSingleton;
private int ItemsCountForDebugger => _parent._items.Count;
private int CapacityForDebugger => _parent._bufferedCapacity;
internal BoundedChannelWriter(BoundedChannel<T> parent)
{
_parent = parent;
_writerSingleton = new VoidAsyncOperationWithData<T>(runContinuationsAsynchronously: true, default(CancellationToken), pooled: true);
_waiterSingleton = new AsyncOperation<bool>(runContinuationsAsynchronously: true, default(CancellationToken), pooled: true);
}
public override bool TryComplete(Exception error)
{
BoundedChannel<T> parent = _parent;
bool isEmpty;
lock (parent.SyncObj)
{
if (parent._doneWriting != null)
{
return false;
}
parent._doneWriting = error ?? ChannelUtilities.s_doneWritingSentinel;
isEmpty = parent._items.IsEmpty;
}
if (isEmpty)
{
ChannelUtilities.Complete(parent._completion, error);
}
ChannelUtilities.FailOperations<AsyncOperation<T>, T>(parent._blockedReaders, ChannelUtilities.CreateInvalidCompletionException(error));
ChannelUtilities.FailOperations<VoidAsyncOperationWithData<T>, VoidResult>(parent._blockedWriters, ChannelUtilities.CreateInvalidCompletionException(error));
ChannelUtilities.WakeUpWaiters(ref parent._waitingReadersTail, result: false, error);
ChannelUtilities.WakeUpWaiters(ref parent._waitingWritersTail, result: false, error);
return true;
}
public override bool TryWrite(T item)
{
AsyncOperation<T> asyncOperation = null;
AsyncOperation<bool> listTail = null;
BoundedChannel<T> parent = _parent;
bool lockTaken = false;
try
{
Monitor.Enter(parent.SyncObj, ref lockTaken);
if (parent._doneWriting != null)
{
return false;
}
int count = parent._items.Count;
if (count != 0)
{
if (count < parent._bufferedCapacity)
{
parent._items.EnqueueTail(item);
return true;
}
if (parent._mode == BoundedChannelFullMode.Wait)
{
return false;
}
if (parent._mode == BoundedChannelFullMode.DropWrite)
{
Monitor.Exit(parent.SyncObj);
lockTaken = false;
parent._itemDropped?.Invoke(item);
return true;
}
T obj = ((parent._mode == BoundedChannelFullMode.DropNewest) ? parent._items.DequeueTail() : parent._items.DequeueHead());
parent._items.EnqueueTail(item);
Monitor.Exit(parent.SyncObj);
lockTaken = false;
parent._itemDropped?.Invoke(obj);
return true;
}
while (!parent._blockedReaders.IsEmpty)
{
AsyncOperation<T> asyncOperation2 = parent._blockedReaders.DequeueHead();
if (asyncOperation2.UnregisterCancellation())
{
asyncOperation = asyncOperation2;
break;
}
}
if (asyncOperation == null)
{
parent._items.EnqueueTail(item);
listTail = parent._waitingReadersTail;
if (listTail == null)
{
return true;
}
parent._waitingReadersTail = null;
}
}
finally
{
if (lockTaken)
{
Monitor.Exit(parent.SyncObj);
}
}
if (asyncOperation != null)
{
asyncOperation.TrySetResult(item);
}
else
{
ChannelUtilities.WakeUpWaiters(ref listTail, result: true);
}
return true;
}
public override ValueTask<bool> WaitToWriteAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken));
}
BoundedChannel<T> parent = _parent;
lock (parent.SyncObj)
{
if (parent._doneWriting != null)
{
return (parent._doneWriting != ChannelUtilities.s_doneWritingSentinel) ? new ValueTask<bool>(Task.FromException<bool>(parent._doneWriting)) : default(ValueTask<bool>);
}
if (parent._items.Count < parent._bufferedCapacity || parent._mode != 0)
{
return new ValueTask<bool>(result: true);
}
if (!cancellationToken.CanBeCanceled)
{
AsyncOperation<bool> waiterSingleton = _waiterSingleton;
if (waiterSingleton.TryOwnAndReset())
{
ChannelUtilities.QueueWaiter(ref parent._waitingWritersTail, waiterSingleton);
return waiterSingleton.ValueTaskOfT;
}
}
AsyncOperation<bool> asyncOperation = new AsyncOperation<bool>(runContinuationsAsynchronously: true, cancellationToken);
ChannelUtilities.QueueWaiter(ref parent._waitingWritersTail, asyncOperation);
return asyncOperation.ValueTaskOfT;
}
}
public override ValueTask WriteAsync(T item, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return new ValueTask(Task.FromCanceled(cancellationToken));
}
AsyncOperation<T> asyncOperation = null;
AsyncOperation<bool> listTail = null;
BoundedChannel<T> parent = _parent;
bool lockTaken = false;
try
{
Monitor.Enter(parent.SyncObj, ref lockTaken);
if (parent._doneWriting != null)
{
return new ValueTask(Task.FromException(ChannelUtilities.CreateInvalidCompletionException(parent._doneWriting)));
}
int count = parent._items.Count;
if (count != 0)
{
if (count < parent._bufferedCapacity)
{
parent._items.EnqueueTail(item);
return default(ValueTask);
}
if (parent._mode == BoundedChannelFullMode.Wait)
{
if (!cancellationToken.CanBeCanceled)
{
VoidAsyncOperationWithData<T> writerSingleton = _writerSingleton;
if (writerSingleton.TryOwnAndReset())
{
writerSingleton.Item = item;
parent._blockedWriters.EnqueueTail(writerSingleton);
return writerSingleton.ValueTask;
}
}
VoidAsyncOperationWithData<T> voidAsyncOperationWithData = new VoidAsyncOperationWithData<T>(runContinuationsAsynchronously: true, cancellationToken);
voidAsyncOperationWithData.Item = item;
parent._blockedWriters.EnqueueTail(voidAsyncOperationWithData);
return voidAsyncOperationWithData.ValueTask;
}
if (parent._mode == BoundedChannelFullMode.DropWrite)
{
Monitor.Exit(parent.SyncObj);
lockTaken = false;
parent._itemDropped?.Invoke(item);
return default(ValueTask);
}
T obj = ((parent._mode == BoundedChannelFullMode.DropNewest) ? parent._items.DequeueTail() : parent._items.DequeueHead());
parent._items.EnqueueTail(item);
Monitor.Exit(parent.SyncObj);
lockTaken = false;
parent._itemDropped?.Invoke(obj);
return default(ValueTask);
}
while (!parent._blockedReaders.IsEmpty)
{
AsyncOperation<T> asyncOperation2 = parent._blockedReaders.DequeueHead();
if (asyncOperation2.UnregisterCancellation())
{
asyncOperation = asyncOperation2;
break;
}
}
if (asyncOperation == null)
{
parent._items.EnqueueTail(item);
listTail = parent._waitingReadersTail;
if (listTail == null)
{
return default(ValueTask);
}
parent._waitingReadersTail = null;
}
}
finally
{
if (lockTaken)
{
Monitor.Exit(parent.SyncObj);
}
}
if (asyncOperation != null)
{
asyncOperation.TrySetResult(item);
}
else
{
ChannelUtilities.WakeUpWaiters(ref listTail, result: true);
}
return default(ValueTask);
}
IEnumerator<T> IDebugEnumerable<T>.GetEnumerator()
{
return _parent._items.GetEnumerator();
}
}
private readonly BoundedChannelFullMode _mode;
private readonly Action<T> _itemDropped;
private readonly TaskCompletionSource _completion;
private readonly int _bufferedCapacity;
private readonly Deque<T> _items = new Deque<T>();
private readonly Deque<AsyncOperation<T>> _blockedReaders = new Deque<AsyncOperation<T>>();
private readonly Deque<VoidAsyncOperationWithData<T>> _blockedWriters = new Deque<VoidAsyncOperationWithData<T>>();
private AsyncOperation<bool> _waitingReadersTail;
private AsyncOperation<bool> _waitingWritersTail;
private readonly bool _runContinuationsAsynchronously;
private Exception _doneWriting;
private object SyncObj => _items;
private int ItemsCountForDebugger => _items.Count;
private bool ChannelIsClosedForDebugger => _doneWriting != null;
internal BoundedChannel(int bufferedCapacity, BoundedChannelFullMode mode, bool runContinuationsAsynchronously, Action<T> itemDropped)
{
_bufferedCapacity = bufferedCapacity;
_mode = mode;
_runContinuationsAsynchronously = runContinuationsAsynchronously;
_itemDropped = itemDropped;
_completion = new TaskCompletionSource(runContinuationsAsynchronously ? TaskCreationOptions.RunContinuationsAsynchronously : TaskCreationOptions.None);
base.Reader = new BoundedChannelReader(this);
base.Writer = new BoundedChannelWriter(this);
}
[Conditional("DEBUG")]
private void AssertInvariants()
{
_ = _items.IsEmpty;
_ = _items.Count;
_ = _bufferedCapacity;
_ = _blockedReaders.IsEmpty;
_ = _blockedWriters.IsEmpty;
_ = _completion.Task.IsCompleted;
}
IEnumerator<T> IDebugEnumerable<T>.GetEnumerator()
{
return _items.GetEnumerator();
}
}
public enum BoundedChannelFullMode
{
Wait,
DropNewest,
DropOldest,
DropWrite
}
public static class Channel
{
public static Channel<T> CreateUnbounded<T>()
{
return new UnboundedChannel<T>(runContinuationsAsynchronously: true);
}
public static Channel<T> CreateUnbounded<T>(UnboundedChannelOptions options)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
if (options.SingleReader)
{
return new SingleConsumerUnboundedChannel<T>(!options.AllowSynchronousContinuations);
}
return new UnboundedChannel<T>(!options.AllowSynchronousContinuations);
}
public static Channel<T> CreateBounded<T>(int capacity)
{
if (capacity < 1)
{
throw new ArgumentOutOfRangeException("capacity");
}
return new BoundedChannel<T>(capacity, BoundedChannelFullMode.Wait, runContinuationsAsynchronously: true, null);
}
public static Channel<T> CreateBounded<T>(BoundedChannelOptions options)
{
return CreateBounded<T>(options, null);
}
public static Channel<T> CreateBounded<T>(BoundedChannelOptions options, Action<T>? itemDropped)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
return new BoundedChannel<T>(options.Capacity, options.FullMode, !options.AllowSynchronousContinuations, itemDropped);
}
}
public class ChannelClosedException : InvalidOperationException
{
public ChannelClosedException()
: base(System.SR.ChannelClosedException_DefaultMessage)
{
}
public ChannelClosedException(string? message)
: base(message ?? System.SR.ChannelClosedException_DefaultMessage)
{
}
public ChannelClosedException(Exception? innerException)
: base(System.SR.ChannelClosedException_DefaultMessage, innerException)
{
}
public ChannelClosedException(string? message, Exception? innerException)
: base(message ?? System.SR.ChannelClosedException_DefaultMessage, innerException)
{
}
}
public abstract class ChannelOptions
{
public bool SingleWriter { get; set; }
public bool SingleReader { get; set; }
public bool AllowSynchronousContinuations { get; set; }
}
public sealed class BoundedChannelOptions : ChannelOptions
{
private int _capacity;
private BoundedChannelFullMode _mode;
public int Capacity
{
get
{
return _capacity;
}
set
{
if (value < 1)
{
throw new ArgumentOutOfRangeException("value");
}
_capacity = value;
}
}
public BoundedChannelFullMode FullMode
{
get
{
return _mode;
}
set
{
if ((uint)value <= 3u)
{
_mode = value;
return;
}
throw new ArgumentOutOfRangeException("value");
}
}
public BoundedChannelOptions(int capacity)
{
if (capacity < 1)
{
throw new ArgumentOutOfRangeException("capacity");
}
_capacity = capacity;
}
}
public sealed class UnboundedChannelOptions : ChannelOptions
{
}
public abstract class ChannelReader<T>
{
public virtual Task Completion => ChannelUtilities.s_neverCompletingTask;
public virtual bool CanCount => false;
public virtual bool CanPeek => false;
public virtual int Count
{
get
{
throw new NotSupportedException();
}
}
public abstract bool TryRead([MaybeNullWhen(false)] out T item);
public virtual bool TryPeek([MaybeNullWhen(false)] out T item)
{
item = default(T);
return false;
}
public abstract ValueTask<bool> WaitToReadAsync(CancellationToken cancellationToken = default(CancellationToken));
public virtual ValueTask<T> ReadAsync(CancellationToken cancellationToken = default(CancellationToken))
{
if (cancellationToken.IsCancellationRequested)
{
return new ValueTask<T>(Task.FromCanceled<T>(cancellationToken));
}
try
{
if (TryRead(out var item))
{
return new ValueTask<T>(item);
}
}
catch (Exception ex) when (!(ex is ChannelClosedException) && !(ex is OperationCanceledException))
{
return new ValueTask<T>(Task.FromException<T>(ex));
}
return ReadAsyncCore(cancellationToken);
async ValueTask<T> ReadAsyncCore(CancellationToken ct)
{
T item2;
do
{
if (!(await WaitToReadAsync(ct).ConfigureAwait(continueOnCapturedContext: false)))
{
throw new ChannelClosedException();
}
}
while (!TryRead(out item2));
return item2;
}
}
public virtual async IAsyncEnumerable<T> ReadAllAsync([EnumeratorCancellation] CancellationToken cancellationToken = default(CancellationToken))
{
while (await WaitToReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false))
{
T item;
while (TryRead(out item))
{
yield return item;
}
}
}
}
internal static class ChannelUtilities
{
internal static readonly Exception s_doneWritingSentinel = new Exception("s_doneWritingSentinel");
internal static readonly Task<bool> s_trueTask = Task.FromResult(result: true);
internal static readonly Task<bool> s_falseTask = Task.FromResult(result: false);
internal static readonly Task s_neverCompletingTask = new TaskCompletionSource<bool>().Task;
internal static void Complete(TaskCompletionSource tcs, Exception error = null)
{
if (error is OperationCanceledException ex)
{
tcs.TrySetCanceled(ex.CancellationToken);
}
else if (error != null && error != s_doneWritingSentinel)
{
if (tcs.TrySetException(error))
{
_ = tcs.Task.Exception;
}
}
else
{
tcs.TrySetResult();
}
}
internal static ValueTask<T> GetInvalidCompletionValueTask<T>(Exception error)
{
return new ValueTask<T>((error == s_doneWritingSentinel) ? Task.FromException<T>(CreateInvalidCompletionException()) : ((error is OperationCanceledException ex) ? Task.FromCanceled<T>(ex.CancellationToken.IsCancellationRequested ? ex.CancellationToken : new CancellationToken(canceled: true)) : Task.FromException<T>(CreateInvalidCompletionException(error))));
}
internal static void QueueWaiter(ref AsyncOperation<bool> tail, AsyncOperation<bool> waiter)
{
AsyncOperation<bool> asyncOperation = tail;
if (asyncOperation == null)
{
waiter.Next = waiter;
}
else
{
waiter.Next = asyncOperation.Next;
asyncOperation.Next = waiter;
}
tail = waiter;
}
internal static void WakeUpWaiters(ref AsyncOperation<bool> listTail, bool result, Exception error = null)
{
AsyncOperation<bool> asyncOperation = listTail;
if (asyncOperation == null)
{
return;
}
listTail = null;
AsyncOperation<bool> next = asyncOperation.Next;
AsyncOperation<bool> asyncOperation2 = next;
do
{
AsyncOperation<bool> next2 = asyncOperation2.Next;
asyncOperation2.Next = null;
if (error == null)
{
asyncOperation2.TrySetResult(result);
}
else
{
asyncOperation2.TrySetException(error);
}
asyncOperation2 = next2;
}
while (asyncOperation2 != next);
}
internal static void FailOperations<T, TInner>(Deque<T> operations, Exception error) where T : AsyncOperation<TInner>
{
while (!operations.IsEmpty)
{
operations.DequeueHead().TrySetException(error);
}
}
internal static Exception CreateInvalidCompletionException(Exception inner = null)
{
if (!(inner is OperationCanceledException))
{
if (inner == null || inner == s_doneWritingSentinel)
{
return new ChannelClosedException();
}
return new ChannelClosedException(inner);
}
return inner;
}
}
public abstract class ChannelWriter<T>
{
public virtual bool TryComplete(Exception? error = null)
{
return false;
}
public abstract bool TryWrite(T item);
public abstract ValueTask<bool> WaitToWriteAsync(CancellationToken cancellationToken = default(CancellationToken));
public virtual ValueTask WriteAsync(T item, CancellationToken cancellationToken = default(CancellationToken))
{
try
{
return cancellationToken.IsCancellationRequested ? new ValueTask(Task.FromCanceled<T>(cancellationToken)) : (TryWrite(item) ? default(ValueTask) : WriteAsyncCore(item, cancellationToken));
}
catch (Exception exception)
{
return new ValueTask(Task.FromException(exception));
}
}
private async ValueTask WriteAsyncCore(T innerItem, CancellationToken ct)
{
while (await WaitToWriteAsync(ct).ConfigureAwait(continueOnCapturedContext: false))
{
if (TryWrite(innerItem))
{
return;
}
}
throw ChannelUtilities.CreateInvalidCompletionException();
}
public void Complete(Exception? error = null)
{
if (!TryComplete(error))
{
throw ChannelUtilities.CreateInvalidCompletionException();
}
}
}
public abstract class Channel<T> : Channel<T, T>
{
}
public abstract class Channel<TWrite, TRead>
{
public ChannelReader<TRead> Reader { get; protected set; }
public ChannelWriter<TWrite> Writer { get; protected set; }
public static implicit operator ChannelReader<TRead>(Channel<TWrite, TRead> channel)
{
return channel.Reader;
}
public static implicit operator ChannelWriter<TWrite>(Channel<TWrite, TRead> channel)
{
return channel.Writer;
}
}
internal interface IDebugEnumerable<T>
{
IEnumerator<T> GetEnumerator();
}
internal sealed class DebugEnumeratorDebugView<T>
{
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public T[] Items { get; }
public DebugEnumeratorDebugView(IDebugEnumerable<T> enumerable)
{
List<T> list = new List<T>();
foreach (T item in enumerable)
{
list.Add(item);
}
Items = list.ToArray();
}
}
[DebuggerDisplay("Items = {ItemsCountForDebugger}, Closed = {ChannelIsClosedForDebugger}")]
[DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
internal sealed class SingleConsumerUnboundedChannel<T> : Channel<T>, IDebugEnumerable<T>
{
[DebuggerDisplay("Items = {ItemsCountForDebugger}")]
[DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
private sealed class UnboundedChannelReader : ChannelReader<T>, IDebugEnumerable<T>
{
internal readonly SingleConsumerUnboundedChannel<T> _parent;
private readonly AsyncOperation<T> _readerSingleton;
private readonly AsyncOperation<bool> _waiterSingleton;
public override Task Completion => _parent._completion.Task;
public override bool CanPeek => true;
private int ItemsCountForDebugger => _parent._items.Count;
internal UnboundedChannelReader(SingleConsumerUnboundedChannel<T> parent)
{
_parent = parent;
_readerSingleton = new AsyncOperation<T>(parent._runContinuationsAsynchronously, default(CancellationToken), pooled: true);
_waiterSingleton = new AsyncOperation<bool>(parent._runContinuationsAsynchronously, default(CancellationToken), pooled: true);
}
public override ValueTask<T> ReadAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return new ValueTask<T>(Task.FromCanceled<T>(cancellationToken));
}
if (TryRead(out var item))
{
return new ValueTask<T>(item);
}
SingleConsumerUnboundedChannel<T> parent = _parent;
AsyncOperation<T> asyncOperation;
AsyncOperation<T> asyncOperation2;
lock (parent.SyncObj)
{
if (TryRead(out item))
{
return new ValueTask<T>(item);
}
if (parent._doneWriting != null)
{
return ChannelUtilities.GetInvalidCompletionValueTask<T>(parent._doneWriting);
}
asyncOperation = parent._blockedReader;
if (!cancellationToken.CanBeCanceled && _readerSingleton.TryOwnAndReset())
{
asyncOperation2 = _readerSingleton;
if (asyncOperation2 == asyncOperation)
{
asyncOperation = null;
}
}
else
{
asyncOperation2 = new AsyncOperation<T>(_parent._runContinuationsAsynchronously, cancellationToken);
}
parent._blockedReader = asyncOperation2;
}
asyncOperation?.TrySetCanceled();
return asyncOperation2.ValueTaskOfT;
}
public override bool TryRead([MaybeNullWhen(false)] out T item)
{
SingleConsumerUnboundedChannel<T> parent = _parent;
if (parent._items.TryDequeue(out item))
{
if (parent._doneWriting != null && parent._items.IsEmpty)
{
ChannelUtilities.Complete(parent._completion, parent._doneWriting);
}
return true;
}
return false;
}
public override bool TryPeek([MaybeNullWhen(false)] out T item)
{
return _parent._items.TryPeek(out item);
}
public override ValueTask<bool> WaitToReadAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken));
}
if (!_parent._items.IsEmpty)
{
return new ValueTask<bool>(result: true);
}
SingleConsumerUnboundedChannel<T> parent = _parent;
AsyncOperation<bool> asyncOperation = null;
AsyncOperation<bool> asyncOperation2;
lock (parent.SyncObj)
{
if (!parent._items.IsEmpty)
{
return new ValueTask<bool>(result: true);
}
if (parent._doneWriting != null)
{
return (parent._doneWriting != ChannelUtilities.s_doneWritingSentinel) ? new ValueTask<bool>(Task.FromException<bool>(parent._doneWriting)) : default(ValueTask<bool>);
}
asyncOperation = parent._waitingReader;
if (!cancellationToken.CanBeCanceled && _waiterSingleton.TryOwnAndReset())
{
asyncOperation2 = _waiterSingleton;
if (asyncOperation2 == asyncOperation)
{
asyncOperation = null;
}
}
else
{
asyncOperation2 = new AsyncOperation<bool>(_parent._runContinuationsAsynchronously, cancellationToken);
}
parent._waitingReader = asyncOperation2;
}
asyncOperation?.TrySetCanceled();
return asyncOperation2.ValueTaskOfT;
}
IEnumerator<T> IDebugEnumerable<T>.GetEnumerator()
{
return _parent._items.GetEnumerator();
}
}
[DebuggerDisplay("Items = {ItemsCountForDebugger}")]
[DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
private sealed class UnboundedChannelWriter : ChannelWriter<T>, IDebugEnumerable<T>
{
internal readonly SingleConsumerUnboundedChannel<T> _parent;
private int ItemsCountForDebugger => _parent._items.Count;
internal UnboundedChannelWriter(SingleConsumerUnboundedChannel<T> parent)
{
_parent = parent;
}
public override bool TryComplete(Exception error)
{
AsyncOperation<T> asyncOperation = null;
AsyncOperation<bool> asyncOperation2 = null;
bool flag = false;
SingleConsumerUnboundedChannel<T> parent = _parent;
lock (parent.SyncObj)
{
if (parent._doneWriting != null)
{
return false;
}
parent._doneWriting = error ?? ChannelUtilities.s_doneWritingSentinel;
if (parent._items.IsEmpty)
{
flag = true;
if (parent._blockedReader != null)
{
asyncOperation = parent._blockedReader;
parent._blockedReader = null;
}
if (parent._waitingReader != null)
{
asyncOperation2 = parent._waitingReader;
parent._waitingReader = null;
}
}
}
if (flag)
{
ChannelUtilities.Complete(parent._completion, error);
}
if (asyncOperation != null)
{
error = ChannelUtilities.CreateInvalidCompletionException(error);
asyncOperation.TrySetException(error);
}
if (asyncOperation2 != null)
{
if (error != null)
{
asyncOperation2.TrySetException(error);
}
else
{
asyncOperation2.TrySetResult(item: false);
}
}
return true;
}
public override bool TryWrite(T item)
{
SingleConsumerUnboundedChannel<T> parent = _parent;
AsyncOperation<T> asyncOperation;
do
{
asyncOperation = null;
AsyncOperation<bool> asyncOperation2 = null;
lock (parent.SyncObj)
{
if (parent._doneWriting != null)
{
return false;
}
asyncOperation = parent._blockedReader;
if (asyncOperation != null)
{
parent._blockedReader = null;
}
else
{
parent._items.Enqueue(item);
asyncOperation2 = parent._waitingReader;
if (asyncOperation2 == null)
{
return true;
}
parent._waitingReader = null;
}
}
if (asyncOperation2 != null)
{
asyncOperation2.TrySetResult(item: true);
return true;
}
}
while (!asyncOperation.TrySetResult(item));
return true;
}
public override ValueTask<bool> WaitToWriteAsync(CancellationToken cancellationToken)
{
Exception doneWriting = _parent._doneWriting;
if (!cancellationToken.IsCancellationRequested)
{
if (doneWriting != null)
{
if (doneWriting == ChannelUtilities.s_doneWritingSentinel)
{
return default(ValueTask<bool>);
}
return new ValueTask<bool>(Task.FromException<bool>(doneWriting));
}
return new ValueTask<bool>(result: true);
}
return new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken));
}
public override ValueTask WriteAsync(T item, CancellationToken cancellationToken)
{
if (!cancellationToken.IsCancellationRequested)
{
if (!TryWrite(item))
{
return new ValueTask(Task.FromException(ChannelUtilities.CreateInvalidCompletionException(_parent._doneWriting)));
}
return default(ValueTask);
}
return new ValueTask(Task.FromCanceled(cancellationToken));
}
IEnumerator<T> IDebugEnumerable<T>.GetEnumerator()
{
return _parent._items.GetEnumerator();
}
}
private readonly TaskCompletionSource _completion;
private readonly SingleProducerSingleConsumerQueue<T> _items = new SingleProducerSingleConsumerQueue<T>();
private readonly bool _runContinuationsAsynchronously;
private volatile Exception _doneWriting;
private AsyncOperation<T> _blockedReader;
private AsyncOperation<bool> _waitingReader;
private object SyncObj => _items;
private int ItemsCountForDebugger => _items.Count;
private bool ChannelIsClosedForDebugger => _doneWriting != null;
internal SingleConsumerUnboundedChannel(bool runContinuationsAsynchronously)
{
_runContinuationsAsynchronously = runContinuationsAsynchronously;
_completion = new TaskCompletionSource(runContinuationsAsynchronously ? TaskCreationOptions.RunContinuationsAsynchronously : TaskCreationOptions.None);
base.Reader = new UnboundedChannelReader(this);
base.Writer = new UnboundedChannelWriter(this);
}
IEnumerator<T> IDebugEnumerable<T>.GetEnumerator()
{
return _items.GetEnumerator();
}
}
[DebuggerDisplay("Items = {ItemsCountForDebugger}, Closed = {ChannelIsClosedForDebugger}")]
[DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
internal sealed class UnboundedChannel<T> : Channel<T>, IDebugEnumerable<T>
{
[DebuggerDisplay("Items = {Count}")]
[DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
private sealed class UnboundedChannelReader : ChannelReader<T>, IDebugEnumerable<T>
{
internal readonly UnboundedChannel<T> _parent;
private readonly AsyncOperation<T> _readerSingleton;
private readonly AsyncOperation<bool> _waiterSingleton;
public override Task Completion => _parent._completion.Task;
public override bool CanCount => true;
public override bool CanPeek => true;
public override int Count => _parent._items.Count;
internal UnboundedChannelReader(UnboundedChannel<T> parent)
{
_parent = parent;
_readerSingleton = new AsyncOperation<T>(parent._runContinuationsAsynchronously, default(CancellationToken), pooled: true);
_waiterSingleton = new AsyncOperation<bool>(parent._runContinuationsAsynchronously, default(CancellationToken), pooled: true);
}
public override ValueTask<T> ReadAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return new ValueTask<T>(Task.FromCanceled<T>(cancellationToken));
}
UnboundedChannel<T> parent = _parent;
if (parent._items.TryDequeue(out var result))
{
CompleteIfDone(parent);
return new ValueTask<T>(result);
}
lock (parent.SyncObj)
{
if (parent._items.TryDequeue(out result))
{
CompleteIfDone(parent);
return new ValueTask<T>(result);
}
if (parent._doneWriting != null)
{
return ChannelUtilities.GetInvalidCompletionValueTask<T>(parent._doneWriting);
}
if (!cancellationToken.CanBeCanceled)
{
AsyncOperation<T> readerSingleton = _readerSingleton;
if (readerSingleton.TryOwnAndReset())
{
parent._blockedReaders.EnqueueTail(readerSingleton);
return readerSingleton.ValueTaskOfT;
}
}
AsyncOperation<T> asyncOperation = new AsyncOperation<T>(parent._runContinuationsAsynchronously, cancellationToken);
parent._blockedReaders.EnqueueTail(asyncOperation);
return asyncOperation.ValueTaskOfT;
}
}
public override bool TryRead([MaybeNullWhen(false)] out T item)
{
UnboundedChannel<T> parent = _parent;
if (parent._items.TryDequeue(out item))
{
CompleteIfDone(parent);
return true;
}
item = default(T);
return false;
}
public override bool TryPeek([MaybeNullWhen(false)] out T item)
{
return _parent._items.TryPeek(out item);
}
private static void CompleteIfDone(UnboundedChannel<T> parent)
{
if (parent._doneWriting != null && parent._items.IsEmpty)
{
ChannelUtilities.Complete(parent._completion, parent._doneWriting);
}
}
public override ValueTask<bool> WaitToReadAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken));
}
if (!_parent._items.IsEmpty)
{
return new ValueTask<bool>(result: true);
}
UnboundedChannel<T> parent = _parent;
lock (parent.SyncObj)
{
if (!parent._items.IsEmpty)
{
return new ValueTask<bool>(result: true);
}
if (parent._doneWriting != null)
{
return (parent._doneWriting != ChannelUtilities.s_doneWritingSentinel) ? new ValueTask<bool>(Task.FromException<bool>(parent._doneWriting)) : default(ValueTask<bool>);
}
if (!cancellationToken.CanBeCanceled)
{
AsyncOperation<bool> waiterSingleton = _waiterSingleton;
if (waiterSingleton.TryOwnAndReset())
{
ChannelUtilities.QueueWaiter(ref parent._waitingReadersTail, waiterSingleton);
return waiterSingleton.ValueTaskOfT;
}
}
AsyncOperation<bool> asyncOperation = new AsyncOperation<bool>(parent._runContinuationsAsynchronously, cancellationToken);
ChannelUtilities.QueueWaiter(ref parent._waitingReadersTail, asyncOperation);
return asyncOperation.ValueTaskOfT;
}
}
IEnumerator<T> IDebugEnumerable<T>.GetEnumerator()
{
return _parent._items.GetEnumerator();
}
}
[DebuggerDisplay("Items = {ItemsCountForDebugger}")]
[DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
private sealed class UnboundedChannelWriter : ChannelWriter<T>, IDebugEnumerable<T>
{
internal readonly UnboundedChannel<T> _parent;
private int ItemsCountForDebugger => _parent._items.Count;
internal UnboundedChannelWriter(UnboundedChannel<T> parent)
{
_parent = parent;
}
public override bool TryComplete(Exception error)
{
UnboundedChannel<T> parent = _parent;
bool isEmpty;
lock (parent.SyncObj)
{
if (parent._doneWriting != null)
{
return false;
}
parent._doneWriting = error ?? ChannelUtilities.s_doneWritingSentinel;
isEmpty = parent._items.IsEmpty;
}
if (isEmpty)
{
ChannelUtilities.Complete(parent._completion, error);
}
ChannelUtilities.FailOperations<AsyncOperation<T>, T>(parent._blockedReaders, ChannelUtilities.CreateInvalidCompletionException(error));
ChannelUtilities.WakeUpWaiters(ref parent._waitingReadersTail, result: false, error);
return true;
}
public override bool TryWrite(T item)
{
UnboundedChannel<T> parent = _parent;
AsyncOperation<bool> listTail;
while (true)
{
AsyncOperation<T> asyncOperation = null;
listTail = null;
lock (parent.SyncObj)
{
if (parent._doneWriting != null)
{
return false;
}
if (parent._blockedReaders.IsEmpty)
{
parent._items.Enqueue(item);
listTail = parent._waitingReadersTail;
if (listTail == null)
{
return true;
}
parent._waitingReadersTail = null;
}
else
{
asyncOperation = parent._blockedReaders.DequeueHead();
}
}
if (asyncOperation == null)
{
break;
}
if (asyncOperation.TrySetResult(item))
{
return true;
}
}
ChannelUtilities.WakeUpWaiters(ref listTail, result: true);
return true;
}
public override ValueTask<bool> WaitToWriteAsync(CancellationToken cancellationToken)
{
Exception doneWriting = _parent._doneWriting;
if (!cancellationToken.IsCancellationRequested)
{
if (doneWriting != null)
{
if (doneWriting == ChannelUtilities.s_doneWritingSentinel)
{
return default(ValueTask<bool>);
}
return new ValueTask<bool>(Task.FromException<bool>(doneWriting));
}
return new ValueTask<bool>(result: true);
}
return new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken));
}
public override ValueTask WriteAsync(T item, CancellationToken cancellationToken)
{
if (!cancellationToken.IsCancellationRequested)
{
if (!TryWrite(item))
{
return new ValueTask(Task.FromException(ChannelUtilities.CreateInvalidCompletionException(_parent._doneWriting)));
}
return default(ValueTask);
}
return new ValueTask(Task.FromCanceled(cancellationToken));
}
IEnumerator<T> IDebugEnumerable<T>.GetEnumerator()
{
return _parent._items.GetEnumerator();
}
}
private readonly TaskCompletionSource _completion;
private readonly ConcurrentQueue<T> _items = new ConcurrentQueue<T>();
private readonly Deque<AsyncOperation<T>> _blockedReaders = new Deque<AsyncOperation<T>>();
private readonly bool _runContinuationsAsynchronously;
private AsyncOperation<bool> _waitingReadersTail;
private Exception _doneWriting;
private object SyncObj => _items;
private int ItemsCountForDebugger => _items.Count;
private bool ChannelIsClosedForDebugger => _doneWriting != null;
internal UnboundedChannel(bool runContinuationsAsynchronously)
{
_runContinuationsAsynchronously = runContinuationsAsynchronously;
_completion = new TaskCompletionSource(runContinuationsAsynchronously ? TaskCreationOptions.RunContinuationsAsynchronously : TaskCreationOptions.None);
base.Reader = new UnboundedChannelReader(this);
base.Writer = new UnboundedChannelWriter(this);
}
[Conditional("DEBUG")]
private void AssertInvariants()
{
if (!_items.IsEmpty)
{
_ = _runContinuationsAsynchronously;
}
if (!_blockedReaders.IsEmpty || _waitingReadersTail != null)
{
_ = _runContinuationsAsynchronously;
}
_ = _completion.Task.IsCompleted;
}
IEnumerator<T> IDebugEnumerable<T>.GetEnumerator()
{
return _items.GetEnumerator();
}
}
internal sealed class TaskCompletionSource : TaskCompletionSource<VoidResult>
{
public TaskCompletionSource(TaskCreationOptions creationOptions)
: base(creationOptions)
{
}
public bool TrySetResult()
{
return TrySetResult(default(VoidResult));
}
}
}using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Threading.Tasks;
using System.Threading.Tasks.Sources;
using Microsoft.CodeAnalysis;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("System.Threading.Tasks.Extensions")]
[assembly: AssemblyDescription("System.Threading.Tasks.Extensions")]
[assembly: AssemblyDefaultAlias("System.Threading.Tasks.Extensions")]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyProduct("Microsoft® .NET Framework")]
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
[assembly: AssemblyFileVersion("4.6.28619.01")]
[assembly: AssemblyInformationalVersion("4.6.28619.01 @BuiltBy: dlab14-DDVSOWINAGE069 @Branch: release/2.1 @SrcCode: https://github.com/dotnet/corefx/tree/7601f4f6225089ffb291dc7d58293c7bbf5c5d4f")]
[assembly: CLSCompliant(true)]
[assembly: AssemblyMetadata(".NETFrameworkAssembly", "")]
[assembly: AssemblyMetadata("Serviceable", "True")]
[assembly: AssemblyMetadata("PreferInbox", "True")]
[assembly: AssemblyVersion("4.2.0.1")]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class IsReadOnlyAttribute : Attribute
{
}
}
namespace System
{
internal static class ThrowHelper
{
internal static void ThrowArgumentNullException(System.ExceptionArgument argument)
{
throw GetArgumentNullException(argument);
}
internal static void ThrowArgumentOutOfRangeException(System.ExceptionArgument argument)
{
throw GetArgumentOutOfRangeException(argument);
}
private static ArgumentNullException GetArgumentNullException(System.ExceptionArgument argument)
{
return new ArgumentNullException(GetArgumentName(argument));
}
private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(System.ExceptionArgument argument)
{
return new ArgumentOutOfRangeException(GetArgumentName(argument));
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static string GetArgumentName(System.ExceptionArgument argument)
{
return argument.ToString();
}
}
internal enum ExceptionArgument
{
task,
source,
state
}
}
namespace System.Threading.Tasks
{
[StructLayout(LayoutKind.Auto)]
[AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder))]
public readonly struct ValueTask : IEquatable<ValueTask>
{
private sealed class ValueTaskSourceAsTask : TaskCompletionSource<bool>
{
private static readonly Action<object> s_completionAction = delegate(object state)
{
IValueTaskSource source;
if (!(state is ValueTaskSourceAsTask valueTaskSourceAsTask) || (source = valueTaskSourceAsTask._source) == null)
{
System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.state);
return;
}
valueTaskSourceAsTask._source = null;
ValueTaskSourceStatus status = source.GetStatus(valueTaskSourceAsTask._token);
try
{
source.GetResult(valueTaskSourceAsTask._token);
valueTaskSourceAsTask.TrySetResult(result: false);
}
catch (Exception exception)
{
if (status == ValueTaskSourceStatus.Canceled)
{
valueTaskSourceAsTask.TrySetCanceled();
}
else
{
valueTaskSourceAsTask.TrySetException(exception);
}
}
};
private IValueTaskSource _source;
private readonly short _token;
public ValueTaskSourceAsTask(IValueTaskSource source, short token)
{
_token = token;
_source = source;
source.OnCompleted(s_completionAction, this, token, ValueTaskSourceOnCompletedFlags.None);
}
}
private static readonly Task s_canceledTask = Task.Delay(-1, new CancellationToken(canceled: true));
internal readonly object _obj;
internal readonly short _token;
internal readonly bool _continueOnCapturedContext;
internal static Task CompletedTask { get; } = Task.Delay(0);
public bool IsCompleted
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
object obj = _obj;
if (obj == null)
{
return true;
}
if (obj is Task task)
{
return task.IsCompleted;
}
return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).GetStatus(_token) != ValueTaskSourceStatus.Pending;
}
}
public bool IsCompletedSuccessfully
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
object obj = _obj;
if (obj == null)
{
return true;
}
if (obj is Task task)
{
return task.Status == TaskStatus.RanToCompletion;
}
return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).GetStatus(_token) == ValueTaskSourceStatus.Succeeded;
}
}
public bool IsFaulted
{
get
{
object obj = _obj;
if (obj == null)
{
return false;
}
if (obj is Task task)
{
return task.IsFaulted;
}
return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).GetStatus(_token) == ValueTaskSourceStatus.Faulted;
}
}
public bool IsCanceled
{
get
{
object obj = _obj;
if (obj == null)
{
return false;
}
if (obj is Task task)
{
return task.IsCanceled;
}
return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).GetStatus(_token) == ValueTaskSourceStatus.Canceled;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ValueTask(Task task)
{
if (task == null)
{
System.ThrowHelper.ThrowArgumentNullException(System.ExceptionArgument.task);
}
_obj = task;
_continueOnCapturedContext = true;
_token = 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ValueTask(IValueTaskSource source, short token)
{
if (source == null)
{
System.ThrowHelper.ThrowArgumentNullException(System.ExceptionArgument.source);
}
_obj = source;
_token = token;
_continueOnCapturedContext = true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ValueTask(object obj, short token, bool continueOnCapturedContext)
{
_obj = obj;
_token = token;
_continueOnCapturedContext = continueOnCapturedContext;
}
public override int GetHashCode()
{
return _obj?.GetHashCode() ?? 0;
}
public override bool Equals(object obj)
{
if (obj is ValueTask)
{
return Equals((ValueTask)obj);
}
return false;
}
public bool Equals(ValueTask other)
{
if (_obj == other._obj)
{
return _token == other._token;
}
return false;
}
public static bool operator ==(ValueTask left, ValueTask right)
{
return left.Equals(right);
}
public static bool operator !=(ValueTask left, ValueTask right)
{
return !left.Equals(right);
}
public Task AsTask()
{
object obj = _obj;
object obj2;
if (obj != null)
{
obj2 = obj as Task;
if (obj2 == null)
{
return GetTaskForValueTaskSource(System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj));
}
}
else
{
obj2 = CompletedTask;
}
return (Task)obj2;
}
public ValueTask Preserve()
{
if (_obj != null)
{
return new ValueTask(AsTask());
}
return this;
}
private Task GetTaskForValueTaskSource(IValueTaskSource t)
{
ValueTaskSourceStatus status = t.GetStatus(_token);
if (status != 0)
{
try
{
t.GetResult(_token);
return CompletedTask;
}
catch (Exception exception)
{
if (status == ValueTaskSourceStatus.Canceled)
{
return s_canceledTask;
}
TaskCompletionSource<bool> taskCompletionSource = new TaskCompletionSource<bool>();
taskCompletionSource.TrySetException(exception);
return taskCompletionSource.Task;
}
}
ValueTaskSourceAsTask valueTaskSourceAsTask = new ValueTaskSourceAsTask(t, _token);
return valueTaskSourceAsTask.Task;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[StackTraceHidden]
internal void ThrowIfCompletedUnsuccessfully()
{
object obj = _obj;
if (obj != null)
{
if (obj is Task task)
{
task.GetAwaiter().GetResult();
}
else
{
System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).GetResult(_token);
}
}
}
public ValueTaskAwaiter GetAwaiter()
{
return new ValueTaskAwaiter(this);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext)
{
return new ConfiguredValueTaskAwaitable(new ValueTask(_obj, _token, continueOnCapturedContext));
}
}
[StructLayout(LayoutKind.Auto)]
[AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder<>))]
public readonly struct ValueTask<TResult> : IEquatable<ValueTask<TResult>>
{
private sealed class ValueTaskSourceAsTask : TaskCompletionSource<TResult>
{
private static readonly Action<object> s_completionAction = delegate(object state)
{
IValueTaskSource<TResult> source;
if (!(state is ValueTaskSourceAsTask valueTaskSourceAsTask) || (source = valueTaskSourceAsTask._source) == null)
{
System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.state);
return;
}
valueTaskSourceAsTask._source = null;
ValueTaskSourceStatus status = source.GetStatus(valueTaskSourceAsTask._token);
try
{
valueTaskSourceAsTask.TrySetResult(source.GetResult(valueTaskSourceAsTask._token));
}
catch (Exception exception)
{
if (status == ValueTaskSourceStatus.Canceled)
{
valueTaskSourceAsTask.TrySetCanceled();
}
else
{
valueTaskSourceAsTask.TrySetException(exception);
}
}
};
private IValueTaskSource<TResult> _source;
private readonly short _token;
public ValueTaskSourceAsTask(IValueTaskSource<TResult> source, short token)
{
_source = source;
_token = token;
source.OnCompleted(s_completionAction, this, token, ValueTaskSourceOnCompletedFlags.None);
}
}
private static Task<TResult> s_canceledTask;
internal readonly object _obj;
internal readonly TResult _result;
internal readonly short _token;
internal readonly bool _continueOnCapturedContext;
public bool IsCompleted
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
object obj = _obj;
if (obj == null)
{
return true;
}
if (obj is Task<TResult> task)
{
return task.IsCompleted;
}
return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).GetStatus(_token) != ValueTaskSourceStatus.Pending;
}
}
public bool IsCompletedSuccessfully
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
object obj = _obj;
if (obj == null)
{
return true;
}
if (obj is Task<TResult> task)
{
return task.Status == TaskStatus.RanToCompletion;
}
return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).GetStatus(_token) == ValueTaskSourceStatus.Succeeded;
}
}
public bool IsFaulted
{
get
{
object obj = _obj;
if (obj == null)
{
return false;
}
if (obj is Task<TResult> task)
{
return task.IsFaulted;
}
return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).GetStatus(_token) == ValueTaskSourceStatus.Faulted;
}
}
public bool IsCanceled
{
get
{
object obj = _obj;
if (obj == null)
{
return false;
}
if (obj is Task<TResult> task)
{
return task.IsCanceled;
}
return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).GetStatus(_token) == ValueTaskSourceStatus.Canceled;
}
}
public TResult Result
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
object obj = _obj;
if (obj == null)
{
return _result;
}
if (obj is Task<TResult> task)
{
return task.GetAwaiter().GetResult();
}
return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).GetResult(_token);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ValueTask(TResult result)
{
_result = result;
_obj = null;
_continueOnCapturedContext = true;
_token = 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ValueTask(Task<TResult> task)
{
if (task == null)
{
System.ThrowHelper.ThrowArgumentNullException(System.ExceptionArgument.task);
}
_obj = task;
_result = default(TResult);
_continueOnCapturedContext = true;
_token = 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ValueTask(IValueTaskSource<TResult> source, short token)
{
if (source == null)
{
System.ThrowHelper.ThrowArgumentNullException(System.ExceptionArgument.source);
}
_obj = source;
_token = token;
_result = default(TResult);
_continueOnCapturedContext = true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ValueTask(object obj, TResult result, short token, bool continueOnCapturedContext)
{
_obj = obj;
_result = result;
_token = token;
_continueOnCapturedContext = continueOnCapturedContext;
}
public override int GetHashCode()
{
if (_obj == null)
{
if (_result == null)
{
return 0;
}
return _result.GetHashCode();
}
return _obj.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj is ValueTask<TResult>)
{
return Equals((ValueTask<TResult>)obj);
}
return false;
}
public bool Equals(ValueTask<TResult> other)
{
if (_obj == null && other._obj == null)
{
return EqualityComparer<TResult>.Default.Equals(_result, other._result);
}
if (_obj == other._obj)
{
return _token == other._token;
}
return false;
}
public static bool operator ==(ValueTask<TResult> left, ValueTask<TResult> right)
{
return left.Equals(right);
}
public static bool operator !=(ValueTask<TResult> left, ValueTask<TResult> right)
{
return !left.Equals(right);
}
public Task<TResult> AsTask()
{
object obj = _obj;
if (obj == null)
{
return Task.FromResult(_result);
}
if (obj is Task<TResult> result)
{
return result;
}
return GetTaskForValueTaskSource(System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj));
}
public ValueTask<TResult> Preserve()
{
if (_obj != null)
{
return new ValueTask<TResult>(AsTask());
}
return this;
}
private Task<TResult> GetTaskForValueTaskSource(IValueTaskSource<TResult> t)
{
ValueTaskSourceStatus status = t.GetStatus(_token);
if (status != 0)
{
try
{
return Task.FromResult(t.GetResult(_token));
}
catch (Exception exception)
{
if (status == ValueTaskSourceStatus.Canceled)
{
Task<TResult> task = s_canceledTask;
if (task == null)
{
TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<TResult>();
taskCompletionSource.TrySetCanceled();
task = (s_canceledTask = taskCompletionSource.Task);
}
return task;
}
TaskCompletionSource<TResult> taskCompletionSource2 = new TaskCompletionSource<TResult>();
taskCompletionSource2.TrySetException(exception);
return taskCompletionSource2.Task;
}
}
ValueTaskSourceAsTask valueTaskSourceAsTask = new ValueTaskSourceAsTask(t, _token);
return valueTaskSourceAsTask.Task;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ValueTaskAwaiter<TResult> GetAwaiter()
{
return new ValueTaskAwaiter<TResult>(this);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ConfiguredValueTaskAwaitable<TResult> ConfigureAwait(bool continueOnCapturedContext)
{
return new ConfiguredValueTaskAwaitable<TResult>(new ValueTask<TResult>(_obj, _result, _token, continueOnCapturedContext));
}
public override string ToString()
{
if (IsCompletedSuccessfully)
{
TResult result = Result;
if (result != null)
{
return result.ToString();
}
}
return string.Empty;
}
}
}
namespace System.Threading.Tasks.Sources
{
[Flags]
public enum ValueTaskSourceOnCompletedFlags
{
None = 0,
UseSchedulingContext = 1,
FlowExecutionContext = 2
}
public enum ValueTaskSourceStatus
{
Pending,
Succeeded,
Faulted,
Canceled
}
public interface IValueTaskSource
{
ValueTaskSourceStatus GetStatus(short token);
void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags);
void GetResult(short token);
}
public interface IValueTaskSource<out TResult>
{
ValueTaskSourceStatus GetStatus(short token);
void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags);
TResult GetResult(short token);
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false, AllowMultiple = false)]
public sealed class AsyncMethodBuilderAttribute : Attribute
{
public Type BuilderType { get; }
public AsyncMethodBuilderAttribute(Type builderType)
{
BuilderType = builderType;
}
}
[StructLayout(LayoutKind.Auto)]
public struct AsyncValueTaskMethodBuilder
{
private AsyncTaskMethodBuilder _methodBuilder;
private bool _haveResult;
private bool _useBuilder;
public ValueTask Task
{
get
{
if (_haveResult)
{
return default(ValueTask);
}
_useBuilder = true;
return new ValueTask(_methodBuilder.Task);
}
}
public static AsyncValueTaskMethodBuilder Create()
{
return default(AsyncValueTaskMethodBuilder);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
_methodBuilder.Start(ref stateMachine);
}
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
_methodBuilder.SetStateMachine(stateMachine);
}
public void SetResult()
{
if (_useBuilder)
{
_methodBuilder.SetResult();
}
else
{
_haveResult = true;
}
}
public void SetException(Exception exception)
{
_methodBuilder.SetException(exception);
}
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine
{
_useBuilder = true;
_methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine);
}
[SecuritySafeCritical]
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine
{
_useBuilder = true;
_methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
}
}
[StructLayout(LayoutKind.Auto)]
public struct AsyncValueTaskMethodBuilder<TResult>
{
private AsyncTaskMethodBuilder<TResult> _methodBuilder;
private TResult _result;
private bool _haveResult;
private bool _useBuilder;
public ValueTask<TResult> Task
{
get
{
if (_haveResult)
{
return new ValueTask<TResult>(_result);
}
_useBuilder = true;
return new ValueTask<TResult>(_methodBuilder.Task);
}
}
public static AsyncValueTaskMethodBuilder<TResult> Create()
{
return default(AsyncValueTaskMethodBuilder<TResult>);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
_methodBuilder.Start(ref stateMachine);
}
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
_methodBuilder.SetStateMachine(stateMachine);
}
public void SetResult(TResult result)
{
if (_useBuilder)
{
_methodBuilder.SetResult(result);
return;
}
_result = result;
_haveResult = true;
}
public void SetException(Exception exception)
{
_methodBuilder.SetException(exception);
}
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine
{
_useBuilder = true;
_methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine);
}
[SecuritySafeCritical]
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine
{
_useBuilder = true;
_methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
}
}
[StructLayout(LayoutKind.Auto)]
public readonly struct ConfiguredValueTaskAwaitable
{
[StructLayout(LayoutKind.Auto)]
public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion, INotifyCompletion
{
private readonly ValueTask _value;
public bool IsCompleted
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return _value.IsCompleted;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ConfiguredValueTaskAwaiter(ValueTask value)
{
_value = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[StackTraceHidden]
public void GetResult()
{
_value.ThrowIfCompletedUnsuccessfully();
}
public void OnCompleted(Action continuation)
{
object obj = _value._obj;
if (obj is Task task)
{
task.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
}
else if (obj != null)
{
System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.FlowExecutionContext | (_value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None));
}
else
{
ValueTask.CompletedTask.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
}
}
public void UnsafeOnCompleted(Action continuation)
{
object obj = _value._obj;
if (obj is Task task)
{
task.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
}
else if (obj != null)
{
System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, _value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);
}
else
{
ValueTask.CompletedTask.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
}
}
}
private readonly ValueTask _value;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ConfiguredValueTaskAwaitable(ValueTask value)
{
_value = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ConfiguredValueTaskAwaiter GetAwaiter()
{
return new ConfiguredValueTaskAwaiter(_value);
}
}
[StructLayout(LayoutKind.Auto)]
public readonly struct ConfiguredValueTaskAwaitable<TResult>
{
[StructLayout(LayoutKind.Auto)]
public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion, INotifyCompletion
{
private readonly ValueTask<TResult> _value;
public bool IsCompleted
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return _value.IsCompleted;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ConfiguredValueTaskAwaiter(ValueTask<TResult> value)
{
_value = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[StackTraceHidden]
public TResult GetResult()
{
return _value.Result;
}
public void OnCompleted(Action continuation)
{
object obj = _value._obj;
if (obj is Task<TResult> task)
{
task.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
}
else if (obj != null)
{
System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.FlowExecutionContext | (_value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None));
}
else
{
ValueTask.CompletedTask.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
}
}
public void UnsafeOnCompleted(Action continuation)
{
object obj = _value._obj;
if (obj is Task<TResult> task)
{
task.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
}
else if (obj != null)
{
System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, _value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);
}
else
{
ValueTask.CompletedTask.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
}
}
}
private readonly ValueTask<TResult> _value;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ConfiguredValueTaskAwaitable(ValueTask<TResult> value)
{
_value = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ConfiguredValueTaskAwaiter GetAwaiter()
{
return new ConfiguredValueTaskAwaiter(_value);
}
}
public readonly struct ValueTaskAwaiter : ICriticalNotifyCompletion, INotifyCompletion
{
internal static readonly Action<object> s_invokeActionDelegate = delegate(object state)
{
if (!(state is Action action))
{
System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.state);
}
else
{
action();
}
};
private readonly ValueTask _value;
public bool IsCompleted
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return _value.IsCompleted;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ValueTaskAwaiter(ValueTask value)
{
_value = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[StackTraceHidden]
public void GetResult()
{
_value.ThrowIfCompletedUnsuccessfully();
}
public void OnCompleted(Action continuation)
{
object obj = _value._obj;
if (obj is Task task)
{
task.GetAwaiter().OnCompleted(continuation);
}
else if (obj != null)
{
System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext);
}
else
{
ValueTask.CompletedTask.GetAwaiter().OnCompleted(continuation);
}
}
public void UnsafeOnCompleted(Action continuation)
{
object obj = _value._obj;
if (obj is Task task)
{
task.GetAwaiter().UnsafeOnCompleted(continuation);
}
else if (obj != null)
{
System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext);
}
else
{
ValueTask.CompletedTask.GetAwaiter().UnsafeOnCompleted(continuation);
}
}
}
public readonly struct ValueTaskAwaiter<TResult> : ICriticalNotifyCompletion, INotifyCompletion
{
private readonly ValueTask<TResult> _value;
public bool IsCompleted
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return _value.IsCompleted;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ValueTaskAwaiter(ValueTask<TResult> value)
{
_value = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[StackTraceHidden]
public TResult GetResult()
{
return _value.Result;
}
public void OnCompleted(Action continuation)
{
object obj = _value._obj;
if (obj is Task<TResult> task)
{
task.GetAwaiter().OnCompleted(continuation);
}
else if (obj != null)
{
System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext);
}
else
{
ValueTask.CompletedTask.GetAwaiter().OnCompleted(continuation);
}
}
public void UnsafeOnCompleted(Action continuation)
{
object obj = _value._obj;
if (obj is Task<TResult> task)
{
task.GetAwaiter().UnsafeOnCompleted(continuation);
}
else if (obj != null)
{
System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext);
}
else
{
ValueTask.CompletedTask.GetAwaiter().UnsafeOnCompleted(continuation);
}
}
}
}
namespace System.Diagnostics
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method, Inherited = false)]
internal sealed class StackTraceHiddenAttribute : Attribute
{
}
}using System;
using System.Diagnostics;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using FxResources.System.ValueTuple;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyTitle("System.ValueTuple")]
[assembly: AssemblyDescription("System.ValueTuple")]
[assembly: AssemblyDefaultAlias("System.ValueTuple")]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyProduct("Microsoft® .NET Framework")]
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
[assembly: AssemblyFileVersion("4.6.26515.06")]
[assembly: AssemblyInformationalVersion("4.6.26515.06 @BuiltBy: dlab-DDVSOWINAGE059 @Branch: release/2.1 @SrcCode: https://github.com/dotnet/corefx/tree/30ab651fcb4354552bd4891619a0bdd81e0ebdbf")]
[assembly: CLSCompliant(true)]
[assembly: AssemblyMetadata(".NETFrameworkAssembly", "")]
[assembly: AssemblyMetadata("Serviceable", "True")]
[assembly: AssemblyMetadata("PreferInbox", "True")]
[assembly: AssemblyVersion("4.0.3.0")]
[assembly: TypeForwardedTo(typeof(TupleElementNamesAttribute))]
[assembly: TypeForwardedTo(typeof(TupleExtensions))]
[assembly: TypeForwardedTo(typeof(ValueTuple))]
[assembly: TypeForwardedTo(typeof(ValueTuple<>))]
[assembly: TypeForwardedTo(typeof(ValueTuple<, >))]
[assembly: TypeForwardedTo(typeof(ValueTuple<, , >))]
[assembly: TypeForwardedTo(typeof(ValueTuple<, , , >))]
[assembly: TypeForwardedTo(typeof(ValueTuple<, , , , >))]
[assembly: TypeForwardedTo(typeof(ValueTuple<, , , , , >))]
[assembly: TypeForwardedTo(typeof(ValueTuple<, , , , , , >))]
[assembly: TypeForwardedTo(typeof(ValueTuple<, , , , , , , >))]
namespace FxResources.System.ValueTuple
{
internal static class SR
{
}
}
namespace System
{
internal static class SR
{
private static ResourceManager s_resourceManager;
private static ResourceManager ResourceManager => s_resourceManager ?? (s_resourceManager = new ResourceManager(ResourceType));
internal static Type ResourceType { get; } = typeof(SR);
internal static string ArgumentException_ValueTupleIncorrectType => GetResourceString("ArgumentException_ValueTupleIncorrectType", null);
internal static string ArgumentException_ValueTupleLastArgumentNotAValueTuple => GetResourceString("ArgumentException_ValueTupleLastArgumentNotAValueTuple", null);
[MethodImpl(MethodImplOptions.NoInlining)]
private static bool UsingResourceKeys()
{
return false;
}
internal static string GetResourceString(string resourceKey, string defaultString)
{
string text = null;
try
{
text = ResourceManager.GetString(resourceKey);
}
catch (MissingManifestResourceException)
{
}
if (defaultString != null && resourceKey.Equals(text, StringComparison.Ordinal))
{
return defaultString;
}
return text;
}
internal static string Format(string resourceFormat, params object[] args)
{
if (args != null)
{
if (UsingResourceKeys())
{
return resourceFormat + string.Join(", ", args);
}
return string.Format(resourceFormat, args);
}
return resourceFormat;
}
internal static string Format(string resourceFormat, object p1)
{
if (UsingResourceKeys())
{
return string.Join(", ", resourceFormat, p1);
}
return string.Format(resourceFormat, p1);
}
internal static string Format(string resourceFormat, object p1, object p2)
{
if (UsingResourceKeys())
{
return string.Join(", ", resourceFormat, p1, p2);
}
return string.Format(resourceFormat, p1, p2);
}
internal static string Format(string resourceFormat, object p1, object p2, object p3)
{
if (UsingResourceKeys())
{
return string.Join(", ", resourceFormat, p1, p2, p3);
}
return string.Format(resourceFormat, p1, p2, p3);
}
}
}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.Serialization;
using System.Runtime.Versioning;
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.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]
[assembly: AssemblyCompany("Bluegrams")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("© 2020-2025 Bluegrams")]
[assembly: AssemblyDescription("\r\n\t\tA simple .NET wrapper library for youtube-dl and yt-dlp.\r\n\r\nNote: Package versions >= 1.0 are optimized to work with yt-dlp.\r\nPackage versions 0.x retain support for the original youtube-dl.\r\n\t")]
[assembly: AssemblyFileVersion("1.1.2.25113")]
[assembly: AssemblyInformationalVersion("1.1.2+278031d4e0ac90b92bd8b5860e5bf26e777afe14")]
[assembly: AssemblyProduct("YoutubeDLSharp")]
[assembly: AssemblyTitle("YoutubeDLSharp")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Bluegrams/YoutubeDLSharp")]
[assembly: AssemblyVersion("1.1.2.25113")]
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 >= ' ')
{
switch (c)
{
case '\u007f':
break;
case '"':
if (!restricted)
{
return "'";
}
return "";
case ':':
if (!restricted)
{
return " -";
}
return "_-";
default:
if (Enumerable.Contains("\\/|*<>", c))
{
return "_";
}
if (restricted && Enumerable.Contains("!&'()[]{}$;`^,# ", c))
{
return "_";
}
if (restricted && c > '\u007f')
{
return "_";
}
return c.ToString();
}
}
return "";
}
public static string GetFullPath(string fileName)
{
if (File.Exists(fileName))
{
return Path.GetFullPath(fileName);
}
string[] array = Environment.GetEnvironmentVariable("PATH").Split(new char[1] { Path.PathSeparator });
for (int i = 0; i < array.Length; i++)
{
string text = Path.Combine(array[i], 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()
{
return Path.GetFileName(GetYtDlpDownloadUrl());
}
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 ytDlpDownloadUrl = GetYtDlpDownloadUrl();
if (string.IsNullOrEmpty(directoryPath))
{
directoryPath = Directory.GetCurrentDirectory();
}
string downloadLocation = Path.Combine(directoryPath, Path.GetFileName(ytDlpDownloadUrl));
File.WriteAllBytes(downloadLocation, await DownloadFileBytesAsync(ytDlpDownloadUrl));
}
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 root = JsonConvert.DeserializeObject<FFmpegApi.Root>(await (await _client.GetAsync("https://ffbinaries.com/api/v1/version/latest")).Content.ReadAsStringAsync());
FFmpegApi.OsBinVersion osBinVersion = OSHelper.GetOSVersion() switch
{
OSVersion.Windows => root?.Bin.Windows64,
OSVersion.OSX => root?.Bin.Osx64,
OSVersion.Linux => root?.Bin.Linux64,
_ => throw new NotImplementedException("Your OS isn't supported"),
};
using MemoryStream stream = new MemoryStream(await DownloadFileBytesAsync((binary == FFmpegApi.BinaryType.FFmpeg) ? osBinVersion.Ffmpeg : osBinVersion.Ffprobe));
using ZipArchive zipArchive = new ZipArchive(stream, ZipArchiveMode.Read);
if (zipArchive.Entries.Count > 0)
{
zipArchive.Entries[0].ExtractToFile(Path.Combine(directoryPath, zipArchive.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; }
public bool OverwriteFiles { get; set; } = true;
public bool IgnoreDownloadErrors { get; set; } = true;
public string PythonInterpreterPath { get; set; }
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 youtubeDLProcess = CreateYoutubeDLProcess();
youtubeDLProcess.OutputReceived += delegate(object o, DataReceivedEventArgs e)
{
output.Add(e.Data);
};
var (num, error) = await runner.RunThrottled(youtubeDLProcess, urls, options, ct);
return new RunResult<string[]>(num == 0, error, 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 youtubeDLProcess = CreateYoutubeDLProcess();
if (showArgs)
{
output?.Report("Arguments: " + youtubeDLProcess.ConvertToArgs(new string[1] { url }, options) + "\n");
}
else
{
output?.Report("Starting Download: " + url);
}
youtubeDLProcess.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 (num, error) = await runner.RunThrottled(youtubeDLProcess, new string[1] { url }, options, ct, progress);
return new RunResult<string>(num == 0, error, outFile);
}
public async Task<string> RunUpdate()
{
string output = string.Empty;
YoutubeDLProcess youtubeDLProcess = CreateYoutubeDLProcess();
youtubeDLProcess.OutputReceived += delegate(object o, DataReceivedEventArgs e)
{
output = e.Data;
};
await youtubeDLProcess.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 optionSet = GetDownloadOptions();
optionSet.DumpSingleJson = true;
optionSet.FlatPlaylist = flat;
optionSet.WriteComments = fetchComments;
if (overrideOptions != null)
{
optionSet = optionSet.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 (num, error) = await runner.RunThrottled(process, new string[1] { url }, optionSet, ct);
return new RunResult<VideoData>(num == 0, error, 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 optionSet = GetDownloadOptions();
optionSet.Format = format;
optionSet.MergeOutputFormat = mergeFormat;
optionSet.RecodeVideo = recodeFormat;
if (overrideOptions != null)
{
optionSet = optionSet.OverrideOptions(overrideOptions);
}
string outputFile = string.Empty;
YoutubeDLProcess youtubeDLProcess = CreateYoutubeDLProcess();
output?.Report("Arguments: " + youtubeDLProcess.ConvertToArgs(new string[1] { url }, optionSet) + "\n");
youtubeDLProcess.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 (num, error) = await runner.RunThrottled(youtubeDLProcess, new string[1] { url }, optionSet, ct, progress);
return new RunResult<string>(num == 0, error, 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 optionSet = GetDownloadOptions();
optionSet.NoPlaylist = false;
optionSet.PlaylistStart = start;
optionSet.PlaylistEnd = end;
if (items != null)
{
optionSet.PlaylistItems = string.Join(",", items);
}
optionSet.Format = format;
optionSet.RecodeVideo = recodeFormat;
if (overrideOptions != null)
{
optionSet = optionSet.OverrideOptions(overrideOptions);
}
List<string> outputFiles = new List<string>();
YoutubeDLProcess youtubeDLProcess = CreateYoutubeDLProcess();
output?.Report("Arguments: " + youtubeDLProcess.ConvertToArgs(new string[1] { url }, optionSet) + "\n");
youtubeDLProcess.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 (num, error) = await runner.RunThrottled(youtubeDLProcess, new string[1] { url }, optionSet, ct, progress);
return new RunResult<string[]>(num == 0, error, 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 optionSet = GetDownloadOptions();
optionSet.Format = "bestaudio/best";
optionSet.ExtractAudio = true;
optionSet.AudioFormat = format;
if (overrideOptions != null)
{
optionSet = optionSet.OverrideOptions(overrideOptions);
}
string outputFile = string.Empty;
new List<string>();
YoutubeDLProcess youtubeDLProcess = CreateYoutubeDLProcess();
output?.Report("Arguments: " + youtubeDLProcess.ConvertToArgs(new string[1] { url }, optionSet) + "\n");
youtubeDLProcess.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 (num, error) = await runner.RunThrottled(youtubeDLProcess, new string[1] { url }, optionSet, ct, progress);
return new RunResult<string>(num == 0, error, 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 optionSet = GetDownloadOptions();
optionSet.NoPlaylist = false;
optionSet.PlaylistStart = start;
optionSet.PlaylistEnd = end;
if (items != null)
{
optionSet.PlaylistItems = string.Join(",", items);
}
optionSet.Format = "bestaudio/best";
optionSet.ExtractAudio = true;
optionSet.AudioFormat = format;
if (overrideOptions != null)
{
optionSet = optionSet.OverrideOptions(overrideOptions);
}
YoutubeDLProcess youtubeDLProcess = CreateYoutubeDLProcess();
output?.Report("Arguments: " + youtubeDLProcess.ConvertToArgs(new string[1] { url }, optionSet) + "\n");
youtubeDLProcess.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 (num, error) = await runner.RunThrottled(youtubeDLProcess, new string[1] { url }, optionSet, ct, progress);
return new RunResult<string[]>(num == 0, error, 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),
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 processStartInfo = new ProcessStartInfo
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
StandardOutputEncoding = Encoding.UTF8,
StandardErrorEncoding = Encoding.UTF8
};
if (!string.IsNullOrEmpty(PythonPath))
{
processStartInfo.FileName = PythonPath;
processStartInfo.Arguments = "\"" + ExecutablePath + "\" " + ConvertToArgs(urls, options);
}
else
{
processStartInfo.FileName = ExecutablePath;
processStartInfo.Arguments = ConvertToArgs(urls, options);
}
process.EnableRaisingEvents = true;
process.StartInfo = processStartInfo;
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;
}
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
{
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
{
}
});
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)
{
if (y != null)
{
return x.ToString().Equals(y.ToString());
}
return false;
}
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 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> 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 MultiOption<string> pluginDirs = new MultiOption<string>("--plugin-dirs");
private Option<bool> noPluginDirs = new Option<bool>("--no-plugin-dirs");
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<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<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");
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 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 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 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 MultiValue<string> PluginDirs
{
get
{
return pluginDirs.Value;
}
set
{
pluginDirs.Value = value;
}
}
public bool NoPluginDirs
{
get
{
return noPluginDirs.Value;
}
set
{
noPluginDirs.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 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<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 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(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();
foreach (FieldInfo item in from p in overrideOptions.GetType().GetRuntimeFields()
where p.FieldType.IsGenericType && p.FieldType.GetInterfaces().Contains(typeof(IOption))
select p)
{
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 line in lines)
{
string text = line.Trim();
if (!text.StartsWith("#") && !string.IsNullOrWhiteSpace(text))
{
string[] array = text.Split(new char[1] { ' ' });
string flag = array[0];
IOption option = knownOptions.FirstOrDefault((IOption o) => o.OptionStrings.Contains(flag));
IOption option3;
if (array.Length <= 1)
{
IOption option2 = new Option<bool>(true, flag);
option3 = option2;
}
else
{
IOption option2 = new Option<string>(true, flag);
option3 = option2;
}
IOption option4 = option3;
IOption option5 = option ?? option4;
option5.SetFromString(text);
yield return option5;
}
}
}
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);
}
return (T)TypeDescriptor.GetConverter(typeof(T)).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;
return " " + ((DateTime)((obj is DateTime) ? obj : null)).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_ur