Decompiled source of BingBongBoomboxPlus v2.0.1

BingBongBoomBox.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.Networking;
using YoutubeDLSharp;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BingBongBoomBox")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+3a4bb035269eb489b8be6a93caad20fd1910a332")]
[assembly: AssemblyProduct("BingBong BoomBox")]
[assembly: AssemblyTitle("BingBongBoomBox")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BingBongBoomBox
{
	[BepInPlugin("xyz.restorerootfs.bingbongboomboxplus", "BingBongBoomBox", "1.2.0")]
	public class BingBongPlayerPlugin : BaseUnityPlugin
	{
		private enum SongLoadingState
		{
			Loaded,
			Loading,
			Error
		}

		[Serializable]
		private class SongMetadata
		{
			public string? title;
		}

		[Serializable]
		private class SongRequest
		{
			public string url = "";

			public string hash = "";

			public string requestedBy = "";

			public int requestedByActor = -1;

			public string title = "";
		}

		[Serializable]
		private class SongQueueWrapper
		{
			public List<SongRequest> items = new List<SongRequest>();
		}

		[Serializable]
		private class HostConfigPayload
		{
			public bool publicEnqueue;

			public bool globalAudio;

			public bool bypassEnv;

			public bool allowDuplicates;

			public bool autoAdvance;

			public float maxHearingDistance;

			public int maxQueueSize;

			public int perUserQueueLimit;

			public string v;
		}

		[HarmonyPatch(typeof(Item))]
		private static class ItemPatches
		{
			private static bool IsBingBong(Item it)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				if ((it.itemTags & 0x10) == 0)
				{
					ItemUIData uIData = it.UIData;
					if (uIData == null || !(uIData.itemName?.IndexOf("BingBong", StringComparison.OrdinalIgnoreCase) >= 0))
					{
						string name = ((Object)it).name;
						if (name == null)
						{
							return false;
						}
						return name.IndexOf("BingBong", StringComparison.OrdinalIgnoreCase) >= 0;
					}
				}
				return true;
			}

			[HarmonyPostfix]
			[HarmonyPatch("Awake")]
			private static void Awake_Post(Item __instance)
			{
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Invalid comparison between Unknown and I4
				if (!IsBingBong(__instance))
				{
					return;
				}
				bingBong = ((Component)__instance).transform;
				Transform transform = ((Component)__instance).transform;
				bingBongMouth = null;
				Animator[] componentsInChildren = ((Component)transform).GetComponentsInChildren<Animator>(true);
				foreach (Animator val in componentsInChildren)
				{
					try
					{
						AnimatorControllerParameter[] parameters = val.parameters;
						AnimatorControllerParameter val2 = null;
						AnimatorControllerParameter[] array = parameters;
						foreach (AnimatorControllerParameter val3 in array)
						{
							if ((int)val3.type == 1 && val3.name.IndexOf("mouth", StringComparison.OrdinalIgnoreCase) >= 0)
							{
								val2 = val3;
								break;
							}
						}
						if (val2 != null)
						{
							mouthOpenParam = val2.name;
							mouthOpenHash = val2.nameHash;
							bingBongMouth = val;
							break;
						}
					}
					catch
					{
					}
				}
			}

			[HarmonyPrefix]
			[HarmonyPatch("OnDestroy")]
			private static void OnDestroy_Pre(Item __instance)
			{
				if ((Object)(object)bingBong == (Object)(object)((Component)__instance).transform)
				{
					mouthOpenParam = null;
					mouthOpenHash = 0;
					bingBongMouth = null;
					bingBong = null;
				}
			}
		}

		private static ManualLogSource? logger;

		private static AudioSource? audioSource;

		private static PhotonView? photonView;

		private string? ytDlpPath;

		private string? ffmpegPath;

		private string? denoPath;

		private string urlInput = "";

		private Coroutine? currentPlaybackCoroutine;

		private Coroutine? debouncePlayCoroutine;

		private Coroutine? downloadCoroutine;

		private const ushort BingBongItemID = 13;

		private static string? mouthOpenParam;

		private static int mouthOpenHash = 0;

		public static Transform? bingBong = null;

		public static Animator? bingBongMouth = null;

		private ConfigEntry<float>? volumeSetting;

		private ConfigEntry<int>? maxAudioSizeMbCfg;

		private ConfigEntry<int>? maxTempFilesCfg;

		private ConfigEntry<int>? maxQueueSizeCfg;

		private ConfigEntry<int>? perUserQueueLimitCfg;

		private ConfigEntry<bool>? allowDuplicatesCfg;

		private ConfigEntry<bool>? autoAdvanceCfg;

		private ConfigEntry<int>? titleProbeTimeoutSecCfg;

		private ConfigEntry<int>? playlistProbeTimeoutSecCfg;

		private ConfigEntry<bool>? globalAudioCfg;

		private ConfigEntry<bool>? bypassEnvCfg;

		private ConfigEntry<bool>? publicEnqueueCfg;

		private ConfigEntry<float>? maxHearingDistanceCfg;

		private ConfigEntry<float>? uiScaleCfg;

		private ConfigEntry<bool>? showAdvancedCfg;

		private bool hostPublicEnqueue;

		private bool hostGlobalAudio;

		private bool hostBypassEnv;

		private bool hostAllowDuplicates;

		private bool hostAutoAdvance = true;

		private float hostMaxHearingDistance = 35f;

		private int hostMaxQueueSize = 20;

		private int hostPerUserQueueLimit = 5;

		private float syncInterval = 5f;

		private float lastSyncTime;

		private float lastConfigBroadcast = -999f;

		private bool sentInitialConfig;

		public float vocalLow = 300f;

		public float vocalHigh = 3400f;

		public int sampleSize = 256;

		public float currentVolume = 0.45f;

		public FFTWindow fftWindow = (FFTWindow)5;

		private bool lastConnectedState;

		private float[]? spectrumData;

		private string? tempAudioDir;

		private string currentSongTitle = "";

		private string currentSongHash = "";

		private string lastUsedPlayer = "";

		private string userId = Guid.NewGuid().ToString();

		private bool manualStop;

		private SongLoadingState songLoadingState;

		public static readonly string[] LoadingProgress = new string[4] { "Loading.", "Loading..", "Loading...", "Loading" };

		private bool hostHasMod = PhotonNetwork.IsMasterClient;

		private readonly List<SongRequest> queue = new List<SongRequest>();

		private Vector2 queueScroll = Vector2.zero;

		private Vector2 panelScroll = Vector2.zero;

		private readonly HashSet<string> titleFetchInProgress = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private float spectrumTimer;

		private float spectrumInterval = 0.012f;

		private GUIStyle? boxStyle;

		private GUIStyle? labelStyle;

		private GUIStyle? buttonStyle;

		private GUIStyle? sliderStyle;

		private GUIStyle? sliderThumbStyle;

		private GUIStyle? headerStyle;

		private GUIStyle? smallLabelStyle;

		private GUIStyle? toggleStyle;

		private GUIStyle? foldoutStyle;

		private Texture2D? boxBgTex;

		private Texture2D? sliderBgTex;

		private Texture2D? sliderThumbTex;

		private Texture2D? buttonNormalBgTex;

		private Texture2D? buttonHoverBgTex;

		private bool initializedStyles;

		private float appliedUiScale = -1f;

		private static readonly string[] AllowedHosts = new string[20]
		{
			"youtube.com", "www.youtube.com", "m.youtube.com", "music.youtube.com", "www.music.youtube.com", "youtu.be", "www.youtu.be", "soundcloud.com", "www.soundcloud.com", "vimeo.com",
			"www.vimeo.com", "bandcamp.com", "www.bandcamp.com", "twitch.tv", "www.twitch.tv", "clips.twitch.tv", "tiktok.com", "www.tiktok.com", "mixcloud.com", "www.mixcloud.com"
		};

		private int MaxAudioSizeMb => Mathf.Max(1, maxAudioSizeMbCfg?.Value ?? 100);

		private int MaxTempFiles => Mathf.Max(1, maxTempFilesCfg?.Value ?? 5);

		private int MaxQueueSize => Mathf.Max(1, (!ActAsHost()) ? ((hostMaxQueueSize > 0) ? hostMaxQueueSize : 20) : (maxQueueSizeCfg?.Value ?? 20));

		private int PerUserQueueLimit => Mathf.Max(1, (!ActAsHost()) ? ((hostPerUserQueueLimit > 0) ? hostPerUserQueueLimit : 5) : (perUserQueueLimitCfg?.Value ?? 5));

		private bool AllowDuplicates
		{
			get
			{
				if (!ActAsHost())
				{
					return hostAllowDuplicates;
				}
				return allowDuplicatesCfg?.Value ?? false;
			}
		}

		private bool AutoAdvance
		{
			get
			{
				if (!ActAsHost())
				{
					return hostAutoAdvance;
				}
				return autoAdvanceCfg?.Value ?? true;
			}
		}

		private int TitleProbeTimeoutSec => Mathf.Max(5, titleProbeTimeoutSecCfg?.Value ?? 20);

		private int PlaylistProbeTimeoutSec => Mathf.Max(5, playlistProbeTimeoutSecCfg?.Value ?? 30);

		private bool GlobalAudio
		{
			get
			{
				if (!ActAsHost())
				{
					return hostGlobalAudio;
				}
				return globalAudioCfg?.Value ?? false;
			}
		}

		private bool BypassEnv
		{
			get
			{
				if (!ActAsHost())
				{
					return hostBypassEnv;
				}
				return bypassEnvCfg?.Value ?? false;
			}
		}

		private bool PublicEnqueue
		{
			get
			{
				if (!ActAsHost())
				{
					return hostPublicEnqueue;
				}
				return publicEnqueueCfg?.Value ?? false;
			}
		}

		private float MaxHearingDistance => Mathf.Clamp((!ActAsHost()) ? ((hostMaxHearingDistance <= 0f) ? 35f : hostMaxHearingDistance) : (maxHearingDistanceCfg?.Value ?? 35f), 5f, 10000f);

		private float UiScale => Mathf.Clamp(uiScaleCfg?.Value ?? 1f, 0.75f, 2f);

		private bool ShowAdvanced => showAdvancedCfg?.Value ?? false;

		private bool ActAsHost()
		{
			if (!PhotonNetwork.IsMasterClient)
			{
				if (!hostHasMod)
				{
					return lastUsedPlayer == userId;
				}
				return false;
			}
			return true;
		}

		private int LocalActor()
		{
			if (PhotonNetwork.LocalPlayer == null)
			{
				return -1;
			}
			return PhotonNetwork.LocalPlayer.ActorNumber;
		}

		private int GetCurrentHolderActorNumber()
		{
			try
			{
				foreach (Player allPlayer in PlayerHandler.GetAllPlayers())
				{
					if ((Object)(object)allPlayer == (Object)null || (Object)(object)allPlayer.character == (Object)null || !allPlayer.HasInAnySlot((ushort)13))
					{
						continue;
					}
					int num = -1;
					try
					{
						Character character = allPlayer.character;
						int? obj;
						if (character == null)
						{
							obj = null;
						}
						else
						{
							PhotonView obj2 = ((MonoBehaviourPun)character).photonView;
							obj = ((obj2 != null) ? new int?(obj2.OwnerActorNr) : ((int?)null));
						}
						num = obj ?? (-1);
					}
					catch
					{
					}
					if (num <= 0)
					{
						try
						{
							PhotonView obj4 = ((MonoBehaviourPun)allPlayer).photonView;
							num = ((obj4 != null) ? obj4.OwnerActorNr : (-1));
						}
						catch
						{
						}
					}
					if (num > 0)
					{
						return num;
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? obj6 = logger;
				if (obj6 != null)
				{
					obj6.LogWarning((object)("GetCurrentHolderActorNumber failed: " + ex.Message));
				}
			}
			return -1;
		}

		private bool IsRequestorHolder(int requestorActorNumber)
		{
			int currentHolderActorNumber = GetCurrentHolderActorNumber();
			if (currentHolderActorNumber > 0)
			{
				return requestorActorNumber == currentHolderActorNumber;
			}
			return false;
		}

		private void Awake()
		{
			//IL_0437: Unknown result type (might be due to invalid IL or missing references)
			logger = ((BaseUnityPlugin)this).Logger;
			photonView = ((Component)this).gameObject.AddComponent<PhotonView>();
			photonView.ViewID = 215151321;
			spectrumData = new float[sampleSize];
			string pluginDir = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? Paths.PluginPath;
			ytDlpPath = Path.Combine(pluginDir, "yt-dlp.exe");
			ffmpegPath = Path.Combine(pluginDir, "ffmpeg.exe");
			denoPath = Path.Combine(pluginDir, "deno.exe");
			tempAudioDir = Path.Combine(Path.GetTempPath(), "BingBongAudio");
			Directory.CreateDirectory(tempAudioDir);
			CleanupOldTempFiles();
			if (!File.Exists(ytDlpPath))
			{
				ManualLogSource? obj = logger;
				if (obj != null)
				{
					obj.LogWarning((object)"yt-dlp was not found! Fetching...");
				}
				Task.Run(async delegate
				{
					await Utils.DownloadYtDlp(pluginDir);
				}).GetAwaiter().GetResult();
			}
			if (!File.Exists(ffmpegPath))
			{
				ManualLogSource? obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogWarning((object)"ffmpeg was not found! Fetching...");
				}
				Task.Run(async delegate
				{
					await Utils.DownloadFFmpeg(pluginDir);
				}).GetAwaiter().GetResult();
			}
			if (!File.Exists(denoPath))
			{
				ManualLogSource? obj3 = logger;
				if (obj3 != null)
				{
					obj3.LogWarning((object)"Deno was not found! Fetching...");
				}
				Task.Run(async delegate
				{
					await Utils.DownloadDeno(pluginDir);
				}).GetAwaiter().GetResult();
			}
			volumeSetting = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "Volume", 0.45f, "Default playback volume (0.0 to 1.0)");
			currentVolume = Mathf.Clamp01(volumeSetting.Value);
			maxAudioSizeMbCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "MaxAudioSizeMB", 100, "Max file size yt-dlp may download.");
			maxTempFilesCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "MaxTempFiles", 5, "How many cached WAVs to keep.");
			maxQueueSizeCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "MaxQueueSize", 20, "Max items allowed in queue. (Host only)");
			perUserQueueLimitCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "PerUserQueueLimit", 5, "Max items one user can have pending in the queue. (Host only)");
			allowDuplicatesCfg = ((BaseUnityPlugin)this).Config.Bind<bool>("Queue", "AllowDuplicates", false, "Allow the same URL to be enqueued multiple times. (Host only)");
			autoAdvanceCfg = ((BaseUnityPlugin)this).Config.Bind<bool>("Queue", "AutoAdvance", true, "Automatically advance to next track when one finishes. (Host only)");
			titleProbeTimeoutSecCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "TitleProbeTimeoutSec", 20, "Timeout for title probes (seconds).");
			playlistProbeTimeoutSecCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "PlaylistProbeTimeoutSec", 30, "Timeout for playlist expansion (seconds).");
			globalAudioCfg = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "GlobalAudio", false, "2D audio heard anywhere. (Host only)");
			bypassEnvCfg = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "BypassEnvironmentEffects", false, "Bypass reverb/occlusion. (Host only)");
			maxHearingDistanceCfg = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "MaxHearingDistance", 35f, "3D audio max distance. (Host only)");
			publicEnqueueCfg = ((BaseUnityPlugin)this).Config.Bind<bool>("Queue", "PublicEnqueue", false, "Non-holders may add and control playback. (Host only)");
			uiScaleCfg = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "UiScale", 1f, "Scale UI text/vertical only (client)");
			showAdvancedCfg = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowAdvanced", false, "Show Advanced section (client)");
			audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
			audioSource.spatialBlend = 1f;
			audioSource.volume = currentVolume;
			audioSource.loop = false;
			audioSource.rolloffMode = (AudioRolloffMode)1;
			audioSource.minDistance = 1f;
			audioSource.maxDistance = MaxHearingDistance;
			audioSource.bypassEffects = BypassEnv;
			audioSource.bypassListenerEffects = BypassEnv;
			audioSource.bypassReverbZones = BypassEnv;
			new Harmony("xyz.restorerootfs.bingbongboomboxplus").PatchAll();
		}

		private void OnDestroy()
		{
			if (currentPlaybackCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(currentPlaybackCoroutine);
			}
			if (debouncePlayCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(debouncePlayCoroutine);
			}
			if (downloadCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(downloadCoroutine);
			}
		}

		private void LateUpdate()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			bool flag = (int)PhotonNetwork.Server == 1;
			if (lastConnectedState && !flag)
			{
				StopAndResetSong();
				queue.Clear();
				sentInitialConfig = false;
			}
			lastConnectedState = flag;
			if ((Object)(object)audioSource == (Object)null || !PhotonNetwork.IsConnectedAndReady || (Object)(object)photonView == (Object)null)
			{
				return;
			}
			if (ActAsHost())
			{
				if (!sentInitialConfig)
				{
					BroadcastHostConfig();
					sentInitialConfig = true;
				}
				if (Time.time - lastConfigBroadcast > 15f)
				{
					BroadcastHostConfig();
				}
			}
			if (ActAsHost() && Time.time - lastSyncTime > syncInterval)
			{
				photonView.RPC("RPC_SyncPlaying", (RpcTarget)1, new object[4]
				{
					currentSongHash,
					audioSource.isPlaying,
					PhotonNetwork.IsMasterClient,
					currentSongTitle
				});
				if (audioSource.isPlaying)
				{
					photonView.RPC("RPC_SyncTime", (RpcTarget)1, new object[2] { currentSongHash, audioSource.time });
				}
				lastSyncTime = Time.time;
			}
			bool flag2 = Singleton<PeakHandler>.Instance?.isPlayingCinematic ?? false;
			Vector3? val = null;
			if ((Object)(object)bingBong != (Object)null)
			{
				val = bingBong.position;
			}
			else
			{
				Player? obj = FindPlayerWithBingBong();
				Vector3? obj2;
				if (obj == null)
				{
					obj2 = null;
				}
				else
				{
					Character character = obj.character;
					obj2 = ((character != null) ? new Vector3?(character.Center) : ((Vector3?)null));
				}
				val = obj2;
			}
			if (GlobalAudio)
			{
				audioSource.spatialBlend = 0f;
				audioSource.volume = currentVolume;
			}
			else
			{
				audioSource.spatialBlend = (flag2 ? 0f : 1f);
				audioSource.maxDistance = MaxHearingDistance;
				audioSource.volume = (val.HasValue ? currentVolume : 0f);
				if (val.HasValue)
				{
					((Component)audioSource).transform.position = val.Value;
				}
			}
			audioSource.bypassEffects = BypassEnv;
			audioSource.bypassListenerEffects = BypassEnv;
			audioSource.bypassReverbZones = BypassEnv;
			if (ActAsHost() && AutoAdvance && !manualStop && (Object)(object)audioSource.clip != (Object)null && !audioSource.isPlaying && !string.IsNullOrEmpty(currentSongHash) && songLoadingState == SongLoadingState.Loaded)
			{
				PlayNextImpl();
			}
			if (!((Object)(object)audioSource != (Object)null) || !((Object)(object)bingBongMouth != (Object)null) || mouthOpenParam == null)
			{
				return;
			}
			spectrumTimer += Time.deltaTime;
			if (!(spectrumTimer >= spectrumInterval))
			{
				return;
			}
			spectrumTimer = 0f;
			float num = 0f;
			if (audioSource.isPlaying && spectrumData != null && (Object)(object)audioSource.clip != (Object)null)
			{
				audioSource.GetSpectrumData(spectrumData, 0, fftWindow);
				float num2 = (float)AudioSettings.outputSampleRate / 2f / (float)sampleSize;
				int num3 = Mathf.FloorToInt(vocalLow / num2);
				int num4 = Mathf.CeilToInt(vocalHigh / num2);
				int num5 = Mathf.Clamp(num3, 0, sampleSize - 1);
				num4 = Mathf.Clamp(num4, 0, sampleSize - 1);
				float num6 = 0f;
				int num7 = 0;
				for (int i = num5; i <= num4; i++)
				{
					num6 += spectrumData[i];
					num7++;
				}
				num = Mathf.Clamp01(((num7 > 0) ? (num6 / (float)num7) : 0f) * 50f);
			}
			try
			{
				bingBongMouth.SetFloat(mouthOpenHash, num);
			}
			catch
			{
			}
		}

		private void BroadcastHostConfig()
		{
			lastConfigBroadcast = Time.time;
			HostConfigPayload hostConfigPayload = new HostConfigPayload
			{
				publicEnqueue = PublicEnqueue,
				globalAudio = GlobalAudio,
				bypassEnv = BypassEnv,
				allowDuplicates = AllowDuplicates,
				autoAdvance = AutoAdvance,
				maxHearingDistance = MaxHearingDistance,
				maxQueueSize = MaxQueueSize,
				perUserQueueLimit = PerUserQueueLimit,
				v = "1.2.0"
			};
			PhotonView? obj = photonView;
			if (obj != null)
			{
				obj.RPC("RPC_ConfigSync", (RpcTarget)1, new object[1] { JsonUtility.ToJson((object)hostConfigPayload) });
			}
		}

		[PunRPC]
		private void RPC_ConfigSync(string json)
		{
			try
			{
				HostConfigPayload hostConfigPayload = JsonUtility.FromJson<HostConfigPayload>(json);
				if (hostConfigPayload != null)
				{
					hostPublicEnqueue = hostConfigPayload.publicEnqueue;
					hostGlobalAudio = hostConfigPayload.globalAudio;
					hostBypassEnv = hostConfigPayload.bypassEnv;
					hostAllowDuplicates = hostConfigPayload.allowDuplicates;
					hostAutoAdvance = hostConfigPayload.autoAdvance;
					hostMaxHearingDistance = hostConfigPayload.maxHearingDistance;
					hostMaxQueueSize = hostConfigPayload.maxQueueSize;
					hostPerUserQueueLimit = hostConfigPayload.perUserQueueLimit;
				}
			}
			catch
			{
			}
		}

		private Player? FindPlayerWithBingBong()
		{
			foreach (Player allPlayer in PlayerHandler.GetAllPlayers())
			{
				if ((Object)(object)allPlayer.character != (Object)null && allPlayer.HasInAnySlot((ushort)13))
				{
					return allPlayer;
				}
			}
			return null;
		}

		private Texture2D MakeSolidColorTex(Color col)
		{
			//IL_0002: 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_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			Texture2D val = new Texture2D(1, 1);
			val.SetPixel(0, 0, col);
			val.Apply();
			return val;
		}

		private void InitStyles()
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Expected O, but got Unknown
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Expected O, but got Unknown
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Expected O, but got Unknown
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Expected O, but got Unknown
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Expected O, but got Unknown
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Expected O, but got Unknown
			//IL_024a: Expected O, but got Unknown
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Expected O, but got Unknown
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Expected O, but got Unknown
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: Expected O, but got Unknown
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_035b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_037a: Unknown result type (might be due to invalid IL or missing references)
			//IL_038b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a8: Expected O, but got Unknown
			//IL_03b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fe: Expected O, but got Unknown
			if (initializedStyles && Mathf.Abs(appliedUiScale - UiScale) < 0.001f)
			{
				return;
			}
			appliedUiScale = UiScale;
			Font val = null;
			Font[] array = Resources.FindObjectsOfTypeAll<Font>();
			foreach (Font val2 in array)
			{
				if (((Object)val2).name == "DarumaDropOne-Regular")
				{
					val = val2;
					break;
				}
			}
			if (!((Object)(object)val == (Object)null) || PhotonNetwork.IsConnectedAndReady)
			{
				boxBgTex = MakeSolidColorTex(new Color(0f, 0f, 0f, 0.8f));
				int num = Mathf.RoundToInt(12f * UiScale);
				GUIStyle val3 = new GUIStyle(GUI.skin.box)
				{
					padding = new RectOffset(12, 12, num, num),
					margin = new RectOffset(10, 10, 10, 10)
				};
				val3.normal.background = boxBgTex;
				boxStyle = val3;
				GUIStyle val4 = new GUIStyle(GUI.skin.label)
				{
					fontSize = Mathf.RoundToInt(14f * UiScale)
				};
				val4.normal.textColor = Color.white;
				val4.richText = true;
				labelStyle = val4;
				GUIStyle val5 = new GUIStyle(GUI.skin.label)
				{
					fontSize = Mathf.RoundToInt(12f * UiScale)
				};
				val5.normal.textColor = Color.white;
				val5.richText = true;
				smallLabelStyle = val5;
				GUIStyle val6 = new GUIStyle(GUI.skin.label)
				{
					fontSize = Mathf.RoundToInt(22f * UiScale)
				};
				val6.normal.textColor = Color.white;
				val6.richText = true;
				headerStyle = val6;
				toggleStyle = new GUIStyle(GUI.skin.toggle)
				{
					fontSize = Mathf.RoundToInt(13f * UiScale)
				};
				foldoutStyle = new GUIStyle(GUI.skin.button)
				{
					fontSize = Mathf.RoundToInt(13f * UiScale),
					alignment = (TextAnchor)3,
					padding = new RectOffset(8, 8, Mathf.RoundToInt(6f * UiScale), Mathf.RoundToInt(6f * UiScale))
				};
				buttonNormalBgTex = MakeSolidColorTex(new Color(0.2f, 0.2f, 0.2f, 0.95f));
				buttonHoverBgTex = MakeSolidColorTex(new Color(0.3f, 0.3f, 0.3f, 0.95f));
				GUIStyle val7 = new GUIStyle(GUI.skin.button)
				{
					fontSize = Mathf.RoundToInt(13f * UiScale),
					margin = new RectOffset(5, 5, 5, 5),
					padding = new RectOffset(8, 8, Mathf.RoundToInt(6f * UiScale), Mathf.RoundToInt(6f * UiScale))
				};
				val7.normal.background = buttonNormalBgTex;
				val7.hover.background = buttonHoverBgTex;
				buttonStyle = val7;
				sliderBgTex = MakeSolidColorTex(new Color(0.15f, 0.15f, 0.15f, 1f));
				sliderThumbTex = MakeSolidColorTex(new Color(1f, 0.6f, 0f, 1f));
				GUIStyle val8 = new GUIStyle(GUI.skin.horizontalSlider);
				val8.normal.background = sliderBgTex;
				val8.fixedHeight = Mathf.RoundToInt(12f * UiScale);
				sliderStyle = val8;
				GUIStyle val9 = new GUIStyle(GUI.skin.horizontalSliderThumb);
				val9.normal.background = sliderThumbTex;
				val9.fixedWidth = Mathf.RoundToInt(16f * UiScale);
				val9.fixedHeight = Mathf.RoundToInt(16f * UiScale);
				sliderThumbStyle = val9;
				if ((Object)(object)val != (Object)null)
				{
					labelStyle.font = val;
					smallLabelStyle.font = val;
					headerStyle.font = val;
					buttonStyle.font = val;
					toggleStyle.font = val;
					foldoutStyle.font = val;
				}
				initializedStyles = true;
			}
		}

		private void OnGUI()
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c78: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c9c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ca1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Player.localPlayer == (Object)null || (Object)(object)photonView == (Object)null)
			{
				return;
			}
			InitStyles();
			if (!initializedStyles)
			{
				return;
			}
			if (!GUIManager.InPauseMenu)
			{
				if (Player.localPlayer.HasInAnySlot((ushort)13))
				{
					GUILayout.BeginArea(new Rect(10f, 10f, 480f, (float)Mathf.RoundToInt(100f * UiScale)));
					GUILayout.Label("<b>Press [ESC] to access Music Player</b>", labelStyle, Array.Empty<GUILayoutOption>());
					GUILayout.EndArea();
				}
				return;
			}
			float num = 10f;
			float num2 = Mathf.Min(720f, (float)Screen.width - 2f * num);
			float num3 = (float)Screen.height - 2f * num;
			GUILayout.BeginArea(new Rect(num, num, num2, num3), boxStyle);
			panelScroll = GUILayout.BeginScrollView(panelScroll, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(num2 - 8f),
				GUILayout.Height(num3 - 8f)
			});
			GUILayout.Label("【BingBong Player】", headerStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Label(ActAsHost() ? "※ You are the acting host." : "※ Waiting for host…", smallLabelStyle, Array.Empty<GUILayoutOption>());
			bool flag = Player.localPlayer.HasInAnySlot((ushort)13);
			if (flag || PublicEnqueue)
			{
				GUILayout.Space(4f * UiScale);
				GUILayout.Label("URL:", labelStyle, Array.Empty<GUILayoutOption>());
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				urlInput = GUILayout.TextField(urlInput, (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(num2 - 180f),
					GUILayout.Height(26f * UiScale)
				});
				if (GUILayout.Button("Clear", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(70f),
					GUILayout.Height(26f * UiScale)
				}))
				{
					urlInput = "";
				}
				if (GUILayout.Button("Add »", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(70f),
					GUILayout.Height(26f * UiScale)
				}))
				{
					RequestEnqueue(urlInput);
				}
				GUILayout.EndHorizontal();
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUI.enabled = flag || PublicEnqueue;
				if (GUILayout.Button("Stop", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f * UiScale) }))
				{
					photonView.RPC("RPC_RequestStop", (RpcTarget)0, Array.Empty<object>());
				}
				if (GUILayout.Button("〈〈 10s", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f * UiScale) }))
				{
					photonView.RPC("RPC_RequestSeek", (RpcTarget)0, new object[1] { -10f });
				}
				if (GUILayout.Button("10s 〉〉", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f * UiScale) }))
				{
					photonView.RPC("RPC_RequestSeek", (RpcTarget)0, new object[1] { 10f });
				}
				if (GUILayout.Button("Next »", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f * UiScale) }))
				{
					photonView.RPC("RPC_RequestNext", (RpcTarget)0, Array.Empty<object>());
				}
				GUI.enabled = true;
				if (!flag && PublicEnqueue)
				{
					GUILayout.Label("※ Public enqueue is enabled.", smallLabelStyle, Array.Empty<GUILayoutOption>());
				}
				GUILayout.EndHorizontal();
			}
			GUILayout.Space(8f * UiScale);
			GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.ExpandWidth(true),
				GUILayout.Height(1f)
			});
			GUILayout.Space(8f * UiScale);
			GUILayout.Label($"Local Volume: {Mathf.RoundToInt(currentVolume * 100f)}%", labelStyle, Array.Empty<GUILayoutOption>());
			float num4 = GUILayout.HorizontalSlider(currentVolume, 0f, 1f, sliderStyle, sliderThumbStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 40f) });
			if (Mathf.Abs(num4 - currentVolume) > 0.001f)
			{
				currentVolume = num4;
				if (volumeSetting != null)
				{
					volumeSetting.Value = num4;
				}
				if ((Object)(object)audioSource != (Object)null)
				{
					audioSource.volume = currentVolume;
				}
			}
			GUILayout.Space(8f * UiScale);
			GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.ExpandWidth(true),
				GUILayout.Height(1f)
			});
			GUILayout.Space(8f * UiScale);
			bool flag2 = ShowAdvanced;
			if (GUILayout.Button(flag2 ? "▼ Advanced" : "► Advanced", foldoutStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f * UiScale) }))
			{
				flag2 = !flag2;
				if (showAdvancedCfg != null)
				{
					showAdvancedCfg.Value = flag2;
				}
			}
			if (flag2)
			{
				GUI.enabled = ActAsHost();
				bool flag3 = GUILayout.Toggle(GlobalAudio, " Global Audio (2D / Hear Anywhere)", toggleStyle, Array.Empty<GUILayoutOption>());
				bool flag4 = GUILayout.Toggle(BypassEnv, " Bypass Environment Effects", toggleStyle, Array.Empty<GUILayoutOption>());
				bool flag5 = GUILayout.Toggle(PublicEnqueue, " Allow Public Enqueue (add/controls)", toggleStyle, Array.Empty<GUILayoutOption>());
				if (flag3 != GlobalAudio)
				{
					globalAudioCfg.Value = flag3;
					BroadcastHostConfig();
				}
				if (flag4 != BypassEnv)
				{
					bypassEnvCfg.Value = flag4;
					BroadcastHostConfig();
				}
				if (flag5 != PublicEnqueue)
				{
					publicEnqueueCfg.Value = flag5;
					BroadcastHostConfig();
				}
				if (!GlobalAudio)
				{
					GUILayout.Label($"Max Hearing Distance: {Mathf.RoundToInt(MaxHearingDistance)}m", labelStyle, Array.Empty<GUILayoutOption>());
					float num5 = GUILayout.HorizontalSlider(MaxHearingDistance, 5f, 300f, sliderStyle, sliderThumbStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 40f) });
					if (Mathf.Abs(num5 - MaxHearingDistance) > 0.001f)
					{
						maxHearingDistanceCfg.Value = num5;
						BroadcastHostConfig();
					}
				}
				GUILayout.Label($"Max Queue Size: {MaxQueueSize}", smallLabelStyle, Array.Empty<GUILayoutOption>());
				int num6 = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)MaxQueueSize, 5f, 50f, sliderStyle, sliderThumbStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 40f) }));
				if (num6 != MaxQueueSize)
				{
					maxQueueSizeCfg.Value = num6;
					BroadcastHostConfig();
				}
				GUILayout.Label($"Per-User Queue Limit: {PerUserQueueLimit}", smallLabelStyle, Array.Empty<GUILayoutOption>());
				int num7 = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)PerUserQueueLimit, 1f, 15f, sliderStyle, sliderThumbStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 40f) }));
				if (num7 != PerUserQueueLimit)
				{
					perUserQueueLimitCfg.Value = num7;
					BroadcastHostConfig();
				}
				bool flag6 = GUILayout.Toggle(AllowDuplicates, " Allow Duplicate URLs", toggleStyle, Array.Empty<GUILayoutOption>());
				if (flag6 != AllowDuplicates)
				{
					allowDuplicatesCfg.Value = flag6;
					BroadcastHostConfig();
				}
				bool flag7 = GUILayout.Toggle(AutoAdvance, " Auto-Advance", toggleStyle, Array.Empty<GUILayoutOption>());
				if (flag7 != AutoAdvance)
				{
					autoAdvanceCfg.Value = flag7;
					BroadcastHostConfig();
				}
				GUI.enabled = true;
				GUILayout.Label($"UI Scale: {UiScale:0.00}x", smallLabelStyle, Array.Empty<GUILayoutOption>());
				float num8 = GUILayout.HorizontalSlider(UiScale, 0.75f, 2f, sliderStyle, sliderThumbStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 40f) });
				if (Mathf.Abs(num8 - UiScale) > 0.001f)
				{
					uiScaleCfg.Value = num8;
				}
			}
			if (songLoadingState == SongLoadingState.Loading)
			{
				GUILayout.Space(8f * UiScale);
				GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.ExpandWidth(true),
					GUILayout.Height(1f)
				});
				GUILayout.Space(8f * UiScale);
				int num9 = Mathf.FloorToInt(Time.time) % LoadingProgress.Length;
				GUILayout.Label(LoadingProgress[num9], labelStyle, Array.Empty<GUILayoutOption>());
			}
			else if (songLoadingState == SongLoadingState.Error)
			{
				GUILayout.Space(8f * UiScale);
				GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.ExpandWidth(true),
					GUILayout.Height(1f)
				});
				GUILayout.Space(8f * UiScale);
				GUILayout.Label("ERROR! Couldn't load audio.", labelStyle, Array.Empty<GUILayoutOption>());
			}
			else if (!string.IsNullOrEmpty(currentSongTitle))
			{
				AudioSource? obj = audioSource;
				if ((Object)(object)((obj != null) ? obj.clip : null) != (Object)null && (audioSource.isPlaying || audioSource.time > 0f))
				{
					GUILayout.Space(8f * UiScale);
					GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.ExpandWidth(true),
						GUILayout.Height(1f)
					});
					GUILayout.Space(8f * UiScale);
					GUILayout.Label("Now Playing: 「" + currentSongTitle + "」", labelStyle, Array.Empty<GUILayoutOption>());
					int num10 = Mathf.FloorToInt(audioSource.time / 60f);
					int num11 = Mathf.FloorToInt(audioSource.time % 60f);
					int num12 = Mathf.FloorToInt(audioSource.clip.length / 60f);
					int num13 = Mathf.FloorToInt(audioSource.clip.length % 60f);
					GUILayout.Label($"{num10:D2}:{num11:D2} / {num12:D2}:{num13:D2}", labelStyle, Array.Empty<GUILayoutOption>());
				}
			}
			GUILayout.Space(8f * UiScale);
			GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.ExpandWidth(true),
				GUILayout.Height(1f)
			});
			GUILayout.Space(8f * UiScale);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label($"【Queue】 ({queue.Count}/{MaxQueueSize})", labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			if (flag || PublicEnqueue)
			{
				if (GUILayout.Button("〜 Shuffle", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f * UiScale) }))
				{
					photonView.RPC("RPC_RequestShuffle", (RpcTarget)0, Array.Empty<object>());
				}
				if (GUILayout.Button("[ ] Clear", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f * UiScale) }))
				{
					photonView.RPC("RPC_RequestClearQueue", (RpcTarget)0, Array.Empty<object>());
				}
			}
			GUILayout.EndHorizontal();
			float num14 = 140f * UiScale;
			float num15 = Mathf.Clamp((float)Screen.height * 0.65f, 160f, (float)Screen.height - 260f);
			float num16 = 22f * UiScale;
			float num17 = Mathf.Clamp((float)queue.Count * num16 + 8f, num14, num15);
			queueScroll = GUILayout.BeginScrollView(queueScroll, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(num17),
				GUILayout.Width(num2 - 20f)
			});
			for (int i = 0; i < queue.Count; i++)
			{
				SongRequest songRequest = queue[i];
				string arg = (string.IsNullOrEmpty(songRequest.title) ? "Fetching title…" : songRequest.title);
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label($"{i + 1}. • {arg} ({ShortId(songRequest.requestedBy)})", smallLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 180f) });
				GUI.enabled = flag || PublicEnqueue || songRequest.requestedByActor == LocalActor();
				if (GUILayout.Button("Remove", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }))
				{
					photonView.RPC("RPC_RequestRemoveAt", (RpcTarget)0, new object[1] { i });
				}
				GUI.enabled = true;
				GUILayout.EndHorizontal();
			}
			GUILayout.EndScrollView();
			GUILayout.EndScrollView();
			GUILayout.EndArea();
		}

		private string ShortId(string id)
		{
			if (!string.IsNullOrEmpty(id))
			{
				if (id.Length > 6)
				{
					return id.Substring(0, 6);
				}
				return id;
			}
			return "??";
		}

		private void RequestEnqueue(string url)
		{
			if (!string.IsNullOrWhiteSpace(url) && IsSupportedMediaUrl(url))
			{
				if (debouncePlayCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(debouncePlayCoroutine);
					debouncePlayCoroutine = null;
				}
				debouncePlayCoroutine = ((MonoBehaviour)this).StartCoroutine(DebounceRequestCoroutine(0.4f, url));
			}
		}

		private IEnumerator DebounceRequestCoroutine(float delay, string url)
		{
			yield return (object)new WaitForSecondsRealtime(delay);
			PhotonView? obj = photonView;
			if (obj != null)
			{
				obj.RPC("RPC_RequestEnqueue", (RpcTarget)0, new object[2] { url, userId });
			}
		}

		[PunRPC]
		private void RPC_RequestEnqueue(string url, string requestorId, PhotonMessageInfo info)
		{
			//IL_0013: 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)
			if (!IsSupportedMediaUrl(url) || !ActAsHost())
			{
				return;
			}
			int requestorActor = ((info.Sender != null) ? info.Sender.ActorNumber : (-1));
			if (IsYouTubePlaylistUrl(url))
			{
				((MonoBehaviour)this).StartCoroutine(EnqueueYouTubePlaylist(url, requestorId, requestorActor));
				return;
			}
			SongRequest addedItem;
			bool num = TryEnqueueInternal(url, requestorId, requestorActor, out addedItem, null);
			BroadcastQueue();
			if (num && addedItem != null && string.IsNullOrEmpty(addedItem.title))
			{
				StartTitleFetchIfNeeded(addedItem.hash, addedItem.url);
			}
			if (!audioSource.isPlaying && songLoadingState != SongLoadingState.Loading)
			{
				PlayNextImpl();
			}
		}

		[PunRPC]
		private void RPC_RequestRemoveAt(int index, PhotonMessageInfo info)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (ActAsHost() && index >= 0 && index < queue.Count)
			{
				int num = ((info.Sender != null) ? info.Sender.ActorNumber : (-1));
				if (queue[index].requestedByActor == num || IsRequestorHolder(num) || PublicEnqueue)
				{
					queue.RemoveAt(index);
					BroadcastQueue();
				}
			}
		}

		[PunRPC]
		private void RPC_RequestClearQueue(PhotonMessageInfo info)
		{
			//IL_0009: 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)
			if (ActAsHost())
			{
				int requestorActorNumber = ((info.Sender != null) ? info.Sender.ActorNumber : (-1));
				if (PublicEnqueue || IsRequestorHolder(requestorActorNumber))
				{
					queue.Clear();
					BroadcastQueue();
				}
			}
		}

		[PunRPC]
		private void RPC_RequestNext(PhotonMessageInfo info)
		{
			//IL_0009: 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)
			if (ActAsHost())
			{
				int requestorActorNumber = ((info.Sender != null) ? info.Sender.ActorNumber : (-1));
				if (PublicEnqueue || IsRequestorHolder(requestorActorNumber))
				{
					PlayNextImpl();
				}
			}
		}

		[PunRPC]
		private void RPC_RequestShuffle(PhotonMessageInfo info)
		{
			//IL_0009: 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)
			if (!ActAsHost())
			{
				return;
			}
			int requestorActorNumber = ((info.Sender != null) ? info.Sender.ActorNumber : (-1));
			if (PublicEnqueue || IsRequestorHolder(requestorActorNumber))
			{
				Random random = new Random();
				for (int num = queue.Count - 1; num > 0; num--)
				{
					int num2 = random.Next(num + 1);
					List<SongRequest> list = queue;
					int index = num;
					List<SongRequest> list2 = queue;
					int index2 = num2;
					SongRequest value = queue[num2];
					SongRequest value2 = queue[num];
					list[index] = value;
					list2[index2] = value2;
				}
				BroadcastQueue();
			}
		}

		[PunRPC]
		private void RPC_RequestStop(PhotonMessageInfo info)
		{
			//IL_0009: 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)
			if (!ActAsHost())
			{
				return;
			}
			int requestorActorNumber = ((info.Sender != null) ? info.Sender.ActorNumber : (-1));
			if (PublicEnqueue || IsRequestorHolder(requestorActorNumber))
			{
				PhotonView? obj = photonView;
				if (obj != null)
				{
					obj.RPC("RPC_StopAudio", (RpcTarget)0, Array.Empty<object>());
				}
			}
		}

		[PunRPC]
		private void RPC_RequestSeek(float seconds, PhotonMessageInfo info)
		{
			//IL_0009: 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)
			if (ActAsHost())
			{
				int requestorActorNumber = ((info.Sender != null) ? info.Sender.ActorNumber : (-1));
				if ((PublicEnqueue || IsRequestorHolder(requestorActorNumber)) && !((Object)(object)audioSource == (Object)null) && !((Object)(object)audioSource.clip == (Object)null))
				{
					float num = Mathf.Clamp(audioSource.time + seconds, 0f, audioSource.clip.length);
					audioSource.time = num;
					photonView.RPC("RPC_SyncTime", (RpcTarget)1, new object[2] { currentSongHash, num });
				}
			}
		}

		private bool IsYouTubePlaylistUrl(string url)
		{
			if (!Uri.TryCreate(url, UriKind.Absolute, out Uri result))
			{
				return false;
			}
			string text = result.Host.ToLowerInvariant();
			if (!text.Contains("youtube.com") && !text.Contains("youtu.be") && !text.Contains("music.youtube.com"))
			{
				return false;
			}
			NameValueCollection nameValueCollection = HttpUtility.ParseQueryString(result.Query);
			bool num = !string.IsNullOrEmpty(nameValueCollection["list"]);
			bool flag = false;
			if (text.Contains("youtu.be"))
			{
				flag = !string.IsNullOrEmpty(result.AbsolutePath.Trim('/'));
			}
			else
			{
				if (!string.IsNullOrEmpty(nameValueCollection["v"]))
				{
					flag = true;
				}
				if (result.AbsolutePath.ToLowerInvariant().StartsWith("/shorts/"))
				{
					flag = true;
				}
			}
			if (num)
			{
				return !flag;
			}
			return false;
		}

		private IEnumerator EnqueueYouTubePlaylist(string playlistUrl, string requestorId, int requestorActor)
		{
			if (string.IsNullOrEmpty(ytDlpPath) || !File.Exists(ytDlpPath))
			{
				yield break;
			}
			int val = Math.Max(0, MaxQueueSize - queue.Count);
			int num = queue.Count((SongRequest it) => it.requestedByActor == requestorActor);
			int val2 = Math.Max(0, PerUserQueueLimit - num);
			int num2 = Math.Min(val, val2);
			if (num2 <= 0)
			{
				yield break;
			}
			ProcessStartInfo processStartInfo = new ProcessStartInfo
			{
				FileName = ytDlpPath,
				RedirectStandardOutput = true,
				RedirectStandardError = true,
				UseShellExecute = false,
				CreateNoWindow = true
			};
			processStartInfo.ArgumentList.Add("--yes-playlist");
			processStartInfo.ArgumentList.Add("--flat-playlist");
			processStartInfo.ArgumentList.Add("--ignore-errors");
			processStartInfo.ArgumentList.Add("--playlist-items");
			processStartInfo.ArgumentList.Add($"1-{num2}");
			processStartInfo.ArgumentList.Add("--print");
			processStartInfo.ArgumentList.Add("%(title)s\t%(webpage_url)s");
			processStartInfo.ArgumentList.Add("--js-runtimes");
			processStartInfo.ArgumentList.Add(denoPath);
			processStartInfo.ArgumentList.Add(playlistUrl);
			Process proc = new Process
			{
				StartInfo = processStartInfo
			};
			List<string> lines = new List<string>();
			proc.OutputDataReceived += delegate(object s, DataReceivedEventArgs e)
			{
				if (!string.IsNullOrEmpty(e.Data))
				{
					lines.Add(e.Data);
				}
			};
			proc.ErrorDataReceived += delegate
			{
			};
			bool flag = false;
			try
			{
				flag = proc.Start();
			}
			catch (Exception)
			{
			}
			if (!flag)
			{
				yield break;
			}
			proc.BeginOutputReadLine();
			proc.BeginErrorReadLine();
			float startTime = Time.realtimeSinceStartup;
			while (!proc.HasExited)
			{
				if (Time.realtimeSinceStartup - startTime > (float)PlaylistProbeTimeoutSec)
				{
					try
					{
						proc.Kill();
					}
					catch
					{
					}
					break;
				}
				yield return null;
			}
			int num3 = 0;
			foreach (string item in lines)
			{
				if (string.IsNullOrWhiteSpace(item))
				{
					continue;
				}
				int num4 = item.IndexOf('\t');
				if (num4 > 0 && num4 < item.Length - 1)
				{
					string knownTitle = item.Substring(0, num4).Trim();
					string url = item.Substring(num4 + 1).Trim();
					if (queue.Count >= MaxQueueSize || queue.Count((SongRequest it) => it.requestedByActor == requestorActor) >= PerUserQueueLimit)
					{
						break;
					}
					if ((AllowDuplicates || !queue.Any((SongRequest it) => it.url.Equals(url, StringComparison.OrdinalIgnoreCase))) && TryEnqueueInternal(url, requestorId, requestorActor, out SongRequest addedItem, knownTitle) && addedItem != null)
					{
						num3++;
					}
				}
			}
			if (num3 > 0)
			{
				BroadcastQueue();
			}
			if (num3 > 0 && !audioSource.isPlaying && songLoadingState != SongLoadingState.Loading)
			{
				PlayNextImpl();
			}
		}

		private bool TryEnqueueInternal(string url, string requestorId, int requestorActor, out SongRequest? addedItem, string? knownTitle)
		{
			addedItem = null;
			if (queue.Count >= MaxQueueSize)
			{
				return false;
			}
			if (queue.Count((SongRequest it) => it.requestedByActor == requestorActor) >= PerUserQueueLimit)
			{
				return false;
			}
			if (!AllowDuplicates && queue.Any((SongRequest it) => it.url.Equals(url, StringComparison.OrdinalIgnoreCase)))
			{
				return false;
			}
			string safeSongId = GetSafeSongId(url);
			string path = Path.Combine(tempAudioDir, "bingbong_" + safeSongId + ".json");
			string text = knownTitle ?? "";
			if (string.IsNullOrEmpty(text) && File.Exists(path))
			{
				try
				{
					text = JsonUtility.FromJson<SongMetadata>(File.ReadAllText(path))?.title ?? "";
				}
				catch
				{
					text = "";
				}
			}
			SongRequest songRequest = new SongRequest
			{
				url = url,
				hash = safeSongId,
				requestedBy = requestorId,
				requestedByActor = requestorActor,
				title = text
			};
			queue.Add(songRequest);
			addedItem = songRequest;
			if (!string.IsNullOrEmpty(text))
			{
				try
				{
					File.WriteAllText(path, JsonUtility.ToJson((object)new SongMetadata
					{
						title = text
					}));
				}
				catch
				{
				}
			}
			if (string.IsNullOrEmpty(text))
			{
				StartTitleFetchIfNeeded(safeSongId, url);
			}
			return true;
		}

		private void PlayNextImpl()
		{
			manualStop = false;
			if (queue.Count == 0)
			{
				StopAndResetSong();
				BroadcastQueue();
				return;
			}
			SongRequest songRequest = queue[0];
			queue.RemoveAt(0);
			BroadcastQueue();
			lastUsedPlayer = songRequest.requestedBy;
			PhotonView? obj = photonView;
			if (obj != null)
			{
				obj.RPC("RPC_StopAudio", (RpcTarget)0, Array.Empty<object>());
			}
			PlayAudio(songRequest.url, lastUsedPlayer);
			if (string.IsNullOrEmpty(songRequest.title))
			{
				StartTitleFetchIfNeeded(songRequest.hash, songRequest.url);
			}
		}

		private void BroadcastQueue()
		{
			string text = JsonUtility.ToJson((object)new SongQueueWrapper
			{
				items = queue
			});
			photonView.RPC("RPC_SyncQueue", (RpcTarget)1, new object[1] { text });
		}

		[PunRPC]
		private void RPC_SyncQueue(string json)
		{
			try
			{
				SongQueueWrapper songQueueWrapper = JsonUtility.FromJson<SongQueueWrapper>(json);
				if (songQueueWrapper != null && songQueueWrapper.items != null)
				{
					queue.Clear();
					queue.AddRange(songQueueWrapper.items.Take(MaxQueueSize));
				}
			}
			catch
			{
			}
		}

		private IEnumerator DebouncePlayCoroutine(float delay, string url, string userId)
		{
			yield return (object)new WaitForSecondsRealtime(delay);
			PlayAudio(url, userId);
		}

		[PunRPC]
		private void RPC_PlayAudio(string url, string userId, PhotonMessageInfo info)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			Player sender = info.Sender;
			if ((sender == null || sender.IsMasterClient || !hostHasMod) && !string.IsNullOrWhiteSpace(url) && IsSupportedMediaUrl(url))
			{
				if (debouncePlayCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(debouncePlayCoroutine);
					debouncePlayCoroutine = null;
				}
				debouncePlayCoroutine = ((MonoBehaviour)this).StartCoroutine(DebouncePlayCoroutine(1f, url, userId));
			}
		}

		private void PlayAudio(string url, string userId)
		{
			debouncePlayCoroutine = null;
			if (string.IsNullOrWhiteSpace(url) || !IsSupportedMediaUrl(url))
			{
				return;
			}
			lastUsedPlayer = userId;
			manualStop = false;
			if (ActAsHost())
			{
				AudioSource? obj = audioSource;
				if (obj != null)
				{
					obj.Stop();
				}
				PhotonView? obj2 = photonView;
				if (obj2 != null)
				{
					obj2.RPC("RPC_StopAudio", (RpcTarget)1, Array.Empty<object>());
				}
				PhotonView? obj3 = photonView;
				if (obj3 != null)
				{
					obj3.RPC("RPC_PlayAudio", (RpcTarget)1, new object[2] { url, userId });
				}
			}
			currentSongTitle = "Unknown";
			currentSongHash = GetSafeSongId(url);
			string text = Path.Combine(tempAudioDir, "bingbong_" + currentSongHash + ".wav");
			string text2 = Path.Combine(tempAudioDir, "bingbong_" + currentSongHash + ".json");
			if (File.Exists(text2))
			{
				try
				{
					SongMetadata songMetadata = JsonUtility.FromJson<SongMetadata>(File.ReadAllText(text2));
					if (!string.IsNullOrEmpty(songMetadata?.title))
					{
						currentSongTitle = songMetadata.title;
					}
				}
				catch
				{
					currentSongTitle = "Unknown";
				}
			}
			if (currentPlaybackCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(currentPlaybackCoroutine);
			}
			if (File.Exists(text))
			{
				currentPlaybackCoroutine = ((MonoBehaviour)this).StartCoroutine(LoadAndPlay(text));
				return;
			}
			if (downloadCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(downloadCoroutine);
				downloadCoroutine = null;
			}
			downloadCoroutine = ((MonoBehaviour)this).StartCoroutine(DownloadAudio(url, text, text2));
		}

		private IEnumerator DownloadAudio(string url, string outputPath, string metadataPath)
		{
			CleanupOldTempFiles();
			songLoadingState = SongLoadingState.Loading;
			string titleFromPrint = "";
			if (string.IsNullOrEmpty(ytDlpPath) || !File.Exists(ytDlpPath) || string.IsNullOrEmpty(ffmpegPath) || !File.Exists(ffmpegPath))
			{
				songLoadingState = SongLoadingState.Error;
				yield break;
			}
			ProcessStartInfo processStartInfo = new ProcessStartInfo
			{
				FileName = ytDlpPath,
				RedirectStandardOutput = true,
				RedirectStandardError = true,
				UseShellExecute = false,
				CreateNoWindow = true
			};
			processStartInfo.ArgumentList.Add("--no-playlist");
			processStartInfo.ArgumentList.Add("--max-filesize");
			processStartInfo.ArgumentList.Add($"{MaxAudioSizeMb}M");
			processStartInfo.ArgumentList.Add("--extractor-args");
			processStartInfo.ArgumentList.Add("youtube:player_client=tv_simply,default,-tv");
			processStartInfo.ArgumentList.Add("-x");
			processStartInfo.ArgumentList.Add("-f");
			processStartInfo.ArgumentList.Add("bestaudio[abr<=128]/bestaudio[abr<=160]/bestaudio");
			processStartInfo.ArgumentList.Add("--ffmpeg-location");
			processStartInfo.ArgumentList.Add(ffmpegPath);
			processStartInfo.ArgumentList.Add("--js-runtimes");
			processStartInfo.ArgumentList.Add(denoPath);
			processStartInfo.ArgumentList.Add("--audio-format");
			processStartInfo.ArgumentList.Add("wav");
			processStartInfo.ArgumentList.Add("--print");
			processStartInfo.ArgumentList.Add("title-current:%(title)s");
			processStartInfo.ArgumentList.Add("--no-simulate");
			processStartInfo.ArgumentList.Add("-o");
			processStartInfo.ArgumentList.Add(outputPath);
			processStartInfo.ArgumentList.Add(url);
			Process proc = new Process
			{
				StartInfo = processStartInfo
			};
			proc.OutputDataReceived += delegate(object s, DataReceivedEventArgs e)
			{
				if (!string.IsNullOrEmpty(e.Data) && e.Data.StartsWith("title-current:"))
				{
					titleFromPrint = e.Data.Substring("title-current:".Length).Trim();
				}
			};
			proc.ErrorDataReceived += delegate
			{
			};
			try
			{
				proc.Start();
			}
			catch (Exception)
			{
				songLoadingState = SongLoadingState.Error;
				downloadCoroutine = null;
				yield break;
			}
			proc.BeginOutputReadLine();
			proc.BeginErrorReadLine();
			float startTime = Time.realtimeSinceStartup;
			while (!proc.HasExited)
			{
				if (Time.realtimeSinceStartup - startTime > (float)(TitleProbeTimeoutSec + 60))
				{
					try
					{
						proc.Kill();
					}
					catch
					{
					}
					break;
				}
				yield return null;
			}
			if (File.Exists(outputPath))
			{
				if (!string.IsNullOrWhiteSpace(titleFromPrint))
				{
					currentSongTitle = titleFromPrint;
				}
				try
				{
					SongMetadata songMetadata = new SongMetadata
					{
						title = currentSongTitle
					};
					File.WriteAllText(metadataPath, JsonUtility.ToJson((object)songMetadata));
				}
				catch
				{
				}
				currentPlaybackCoroutine = ((MonoBehaviour)this).StartCoroutine(LoadAndPlay(outputPath));
			}
			else
			{
				songLoadingState = SongLoadingState.Error;
				if (ActAsHost())
				{
					PlayNextImpl();
				}
			}
			downloadCoroutine = null;
		}

		private string GetSafeSongId(string url)
		{
			try
			{
				Uri uri = new Uri(url);
				string text = uri.Host.ToLowerInvariant();
				if (text.Contains("youtu.be"))
				{
					string text2 = uri.AbsolutePath.Trim('/');
					if (!string.IsNullOrEmpty(text2))
					{
						return text2;
					}
				}
				if (text.Contains("youtube.com") || text.Contains("music.youtube.com"))
				{
					string text3 = HttpUtility.ParseQueryString(uri.Query)["v"];
					if (!string.IsNullOrEmpty(text3))
					{
						return text3;
					}
					string text4 = uri.AbsolutePath.Trim('/');
					if (text4.StartsWith("shorts/", StringComparison.OrdinalIgnoreCase))
					{
						string[] array = text4.Split('/');
						if (array.Length >= 2 && array[1].Length > 0)
						{
							return array[1];
						}
					}
				}
			}
			catch
			{
			}
			using SHA1 sHA = SHA1.Create();
			return BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(url)), 0, 6).Replace("-", "");
		}

		private IEnumerator LoadAndPlay(string path)
		{
			if ((Object)(object)audioSource == (Object)null)
			{
				songLoadingState = SongLoadingState.Error;
				yield break;
			}
			songLoadingState = SongLoadingState.Loaded;
			UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip("file://" + path, (AudioType)20);
			try
			{
				yield return www.SendWebRequest();
				if ((int)www.result != 1)
				{
					songLoadingState = SongLoadingState.Error;
					yield break;
				}
				AudioClip content = DownloadHandlerAudioClip.GetContent(www);
				audioSource.clip = content;
				if (ActAsHost())
				{
					audioSource.Play();
				}
			}
			finally
			{
				((IDisposable)www)?.Dispose();
			}
		}

		[PunRPC]
		private void RPC_StopAudio()
		{
			manualStop = true;
			if ((Object)(object)audioSource != (Object)null)
			{
				audioSource.Stop();
				audioSource.clip = null;
			}
		}

		[PunRPC]
		private void RPC_SyncTime(string songHash, float hostTime)
		{
			if (!ActAsHost() && (Object)(object)audioSource != (Object)null && (Object)(object)audioSource.clip != (Object)null && songHash == currentSongHash && Mathf.Abs(audioSource.time - hostTime) > 0.5f && hostTime >= 0f && hostTime <= audioSource.clip.length)
			{
				audioSource.time = hostTime;
			}
		}

		[PunRPC]
		private void RPC_SyncPlaying(string songHash, bool hostIsPlaying, bool isOwner, string hostTitle)
		{
			if (isOwner)
			{
				hostHasMod = true;
			}
			if (!string.IsNullOrEmpty(hostTitle))
			{
				currentSongTitle = hostTitle;
			}
			if (!ActAsHost() && (Object)(object)audioSource != (Object)null)
			{
				if (!audioSource.isPlaying && hostIsPlaying && (Object)(object)audioSource.clip != (Object)null && songHash == currentSongHash)
				{
					audioSource.Play();
				}
				if (audioSource.isPlaying && (!hostIsPlaying || songHash != currentSongHash))
				{
					audioSource.Stop();
				}
			}
		}

		private void StopAndResetSong()
		{
			if (currentPlaybackCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(currentPlaybackCoroutine);
			}
			AudioSource? obj = audioSource;
			if (obj != null)
			{
				obj.Stop();
			}
			if ((Object)(object)audioSource != (Object)null)
			{
				audioSource.clip = null;
			}
			songLoadingState = SongLoadingState.Loaded;
			currentSongTitle = "";
			currentSongHash = "";
			lastUsedPlayer = "";
			manualStop = false;
			hostHasMod = PhotonNetwork.IsMasterClient;
		}

		private void CleanupOldTempFiles()
		{
			if (string.IsNullOrEmpty(tempAudioDir) || !Directory.Exists(tempAudioDir))
			{
				return;
			}
			List<FileInfo> list = (from f in new DirectoryInfo(tempAudioDir).GetFiles("bingbong_*.wav")
				orderby f.LastAccessTimeUtc descending
				select f).ToList();
			for (int num = MaxTempFiles; num < list.Count; num++)
			{
				FileInfo fileInfo = list[num];
				try
				{
					fileInfo.Delete();
				}
				catch
				{
				}
				string path = Path.ChangeExtension(fileInfo.FullName, ".json");
				if (File.Exists(path))
				{
					try
					{
						File.Delete(path);
					}
					catch
					{
					}
				}
			}
		}

		private bool IsSupportedMediaUrl(string url)
		{
			if (!Uri.TryCreate(url, UriKind.Absolute, out Uri result))
			{
				return false;
			}
			string value = result.Host.ToLowerInvariant();
			if (AllowedHosts.Contains(value))
			{
				return true;
			}
			if (!(result.Scheme == Uri.UriSchemeHttp))
			{
				return result.Scheme == Uri.UriSchemeHttps;
			}
			return true;
		}

		private void StartTitleFetchIfNeeded(string hash, string url)
		{
			if (!ActAsHost() || titleFetchInProgress.Contains(hash))
			{
				return;
			}
			string path = Path.Combine(tempAudioDir, "bingbong_" + hash + ".json");
			if (File.Exists(path))
			{
				try
				{
					SongMetadata songMetadata = JsonUtility.FromJson<SongMetadata>(File.ReadAllText(path));
					if (!string.IsNullOrEmpty(songMetadata?.title))
					{
						UpdateQueueTitle(hash, songMetadata.title);
						return;
					}
				}
				catch
				{
				}
			}
			((MonoBehaviour)this).StartCoroutine(FetchTitleCoroutine(hash, url));
		}

		private IEnumerator FetchTitleCoroutine(string hash, string url)
		{
			titleFetchInProgress.Add(hash);
			if (string.IsNullOrEmpty(ytDlpPath) || !File.Exists(ytDlpPath))
			{
				titleFetchInProgress.Remove(hash);
				yield break;
			}
			string fetched = "";
			ProcessStartInfo processStartInfo = new ProcessStartInfo
			{
				FileName = ytDlpPath,
				RedirectStandardOutput = true,
				RedirectStandardError = true,
				UseShellExecute = false,
				CreateNoWindow = true
			};
			processStartInfo.ArgumentList.Add("--no-playlist");
			processStartInfo.ArgumentList.Add("--skip-download");
			processStartInfo.ArgumentList.Add("--print");
			processStartInfo.ArgumentList.Add("title-current:%(title)s");
			processStartInfo.ArgumentList.Add("--js-runtimes");
			processStartInfo.ArgumentList.Add(denoPath);
			processStartInfo.ArgumentList.Add(url);
			Process proc = new Process
			{
				StartInfo = processStartInfo
			};
			proc.OutputDataReceived += delegate(object s, DataReceivedEventArgs e)
			{
				if (!string.IsNullOrEmpty(e.Data) && e.Data.StartsWith("title-current:"))
				{
					fetched = e.Data.Substring("title-current:".Length).Trim();
				}
			};
			proc.ErrorDataReceived += delegate
			{
			};
			bool flag = false;
			try
			{
				flag = proc.Start();
			}
			catch (Exception)
			{
			}
			if (!flag)
			{
				titleFetchInProgress.Remove(hash);
				yield break;
			}
			proc.BeginOutputReadLine();
			proc.BeginErrorReadLine();
			float startTime = Time.realtimeSinceStartup;
			while (!proc.HasExited)
			{
				if (Time.realtimeSinceStartup - startTime > (float)TitleProbeTimeoutSec)
				{
					try
					{
						proc.Kill();
					}
					catch
					{
					}
					break;
				}
				yield return null;
			}
			if (!string.IsNullOrWhiteSpace(fetched))
			{
				UpdateQueueTitle(hash, fetched);
				try
				{
					File.WriteAllText(Path.Combine(tempAudioDir, "bingbong_" + hash + ".json"), JsonUtility.ToJson((object)new SongMetadata
					{
						title = fetched
					}));
				}
				catch
				{
				}
			}
			titleFetchInProgress.Remove(hash);
		}

		private void UpdateQueueTitle(string hash, string title)
		{
			bool flag = false;
			for (int i = 0; i < queue.Count; i++)
			{
				if (queue[i].hash == hash && string.IsNullOrEmpty(queue[i].title))
				{
					queue[i].title = title;
					flag = true;
				}
			}
			if (flag)
			{
				BroadcastQueue();
			}
			if (currentSongHash == hash && (string.IsNullOrEmpty(currentSongTitle) || currentSongTitle == "Unknown"))
			{
				currentSongTitle = title;
			}
		}
	}
}

YoutubeDLSharp.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.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(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Bluegrams")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("© 2020-2026 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.2.0.265")]
[assembly: AssemblyInformationalVersion("1.2.0+bfe03288151c994ad64401870ab4940635576fc5")]
[assembly: AssemblyProduct("YoutubeDLSharp")]
[assembly: AssemblyTitle("YoutubeDLSharp")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Bluegrams/YoutubeDLSharp")]
[assembly: AssemblyVersion("1.2.0.265")]
namespace YoutubeDLSharp
{
	public enum DownloadState
	{
		None,
		PreProcessing,
		Downloading,
		PostProcessing,
		Error,
		Success
	}
	public class DownloadProgress
	{
		public DownloadState State { get; }

		public float Progress { get; }

		public string TotalDownloadSize { get; }

		public string DownloadSpeed { get; }

		public string ETA { get; }

		public int VideoIndex { get; }

		public string Data { get; }

		public DownloadProgress(DownloadState status, float progress = 0f, string totalDownloadSize = null, string downloadSpeed = null, string eta = null, int index = 1, string data = null)
		{
			State = status;
			Progress = progress;
			TotalDownloadSize = totalDownloadSize;
			DownloadSpeed = downloadSpeed;
			ETA = eta;
			VideoIndex = index;
			Data = data;
		}
	}
	public class RunResult<T>
	{
		public bool Success { get; }

		public string[] ErrorOutput { get; }

		public T Data { get; }

		public RunResult(bool success, string[] error, T result)
		{
			Success = success;
			ErrorOutput = error;
			Data = result;
		}
	}
	public static class Utils
	{
		internal class FFmpegApi
		{
			public class Root
			{
				[JsonProperty("version")]
				public string Version { get; set; }

				[JsonProperty("permalink")]
				public string Permalink { get; set; }

				[JsonProperty("bin")]
				public Bin Bin { get; set; }
			}

			public class Bin
			{
				[JsonProperty("windows-64")]
				public OsBinVersion Windows64 { get; set; }

				[JsonProperty("linux-64")]
				public OsBinVersion Linux64 { get; set; }

				[JsonProperty("osx-64")]
				public OsBinVersion Osx64 { get; set; }
			}

			public class OsBinVersion
			{
				[JsonProperty("ffmpeg")]
				public string Ffmpeg { get; set; }

				[JsonProperty("ffprobe")]
				public string Ffprobe { get; set; }
			}

			public enum BinaryType
			{
				[EnumMember(Value = "ffmpeg")]
				FFmpeg,
				[EnumMember(Value = "ffprobe")]
				FFprobe
			}
		}

		private static readonly Regex rgxTimestamp = new Regex("[0-9]+(?::[0-9]+)+", RegexOptions.Compiled);

		private static readonly Dictionary<char, string> accentChars = "ÂÃÄÀÁÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖŐØŒÙÚÛÜŰÝÞßàáâãäåæçèéêëìíîïðñòóôõöőøœùúûüűýþÿ".Zip(new string[68]
		{
			"A", "A", "A", "A", "A", "A", "AE", "C", "E", "E",
			"E", "E", "I", "I", "I", "I", "D", "N", "O", "O",
			"O", "O", "O", "O", "O", "OE", "U", "U", "U", "U",
			"U", "Y", "P", "ss", "a", "a", "a", "a", "a", "a",
			"ae", "c", "e", "e", "e", "e", "i", "i", "i", "i",
			"o", "n", "o", "o", "o", "o", "o", "o", "o", "oe",
			"u", "u", "u", "u", "u", "y", "p", "y"
		}, (char c, string s) => new
		{
			Key = c,
			Val = s
		}).ToDictionary(o => o.Key, o => o.Val);

		private const string DENO_VERSION_URL = "https://dl.deno.land/release-latest.txt";

		private const string DENO_DOWNLOAD_URL_TEMPLATE = "https://dl.deno.land/release/{0}/deno-{1}.zip";

		public static int TimeoutSeconds { get; set; } = 300;

		public static string YtDlpBinaryName => GetYtDlpBinaryName();

		public static string FfmpegBinaryName => GetFfmpegBinaryName();

		public static string FfprobeBinaryName => GetFfprobeBinaryName();

		public static string Sanitize(string s, bool restricted = false)
		{
			rgxTimestamp.Replace(s, (Match m) => m.Groups[0].Value.Replace(':', '_'));
			string text = string.Join("", s.Select((char c) => sanitizeChar(c, restricted)));
			text = text.Replace("__", "_").Trim(new char[1] { '_' });
			if (restricted && text.StartsWith("-_"))
			{
				text = text.Substring(2);
			}
			if (text.StartsWith("-"))
			{
				text = "_" + text.Substring(1);
			}
			text = text.TrimStart(new char[1] { '.' });
			if (string.IsNullOrWhiteSpace(text))
			{
				text = "_";
			}
			return text;
		}

		private static string sanitizeChar(char c, bool restricted)
		{
			if (restricted && accentChars.ContainsKey(c))
			{
				return accentChars[c];
			}
			if (c != '?' && c >= ' ')
			{
				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 = "", bool downloadJSRuntime = true)
		{
			if (skipExisting)
			{
				if (!File.Exists(Path.Combine(directoryPath, GetYtDlpBinaryName())))
				{
					await DownloadYtDlp(directoryPath);
				}
				if (!File.Exists(Path.Combine(directoryPath, GetFfmpegBinaryName())))
				{
					await DownloadFFmpeg(directoryPath);
				}
				if (!File.Exists(Path.Combine(directoryPath, GetFfprobeBinaryName())))
				{
					await DownloadFFprobe(directoryPath);
				}
				if (downloadJSRuntime && !File.Exists(Path.Combine(directoryPath, GetDenoBinaryName())))
				{
					await DownloadDeno(directoryPath);
				}
			}
			else
			{
				await DownloadYtDlp(directoryPath);
				await DownloadFFmpeg(directoryPath);
				await DownloadFFprobe(directoryPath);
				if (downloadJSRuntime)
				{
					await DownloadDeno(directoryPath);
				}
			}
		}

		private static string GetYtDlpBinaryName()
		{
			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");
			}
		}

		private static string GetDenoBinaryName()
		{
			switch (OSHelper.GetOSVersion())
			{
			case OSVersion.Windows:
				return "deno.exe";
			case OSVersion.OSX:
			case OSVersion.Linux:
				return "deno";
			default:
				throw new Exception("Your OS isn't supported");
			}
		}

		private static string GetYtDlpDownloadUrl()
		{
			return OSHelper.GetOSVersion() switch
			{
				OSVersion.Windows => "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe", 
				OSVersion.OSX => "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_macos", 
				OSVersion.Linux => "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp", 
				_ => throw new Exception("Your OS isn't supported"), 
			};
		}

		public static async Task DownloadYtDlp(string directoryPath = "")
		{
			string ytDlpDownloadUrl = GetYtDlpDownloadUrl();
			if (string.IsNullOrEmpty(directoryPath))
			{
				directoryPath = Directory.GetCurrentDirectory();
			}
			string downloadLocation = Path.Combine(directoryPath, Path.GetFileName(ytDlpDownloadUrl));
			File.WriteAllBytes(downloadLocation, await DownloadFileBytesAsync(ytDlpDownloadUrl));
			SetUnixExecPerms(downloadLocation);
		}

		public static async Task DownloadFFmpeg(string directoryPath = "")
		{
			await FFDownloader(directoryPath);
		}

		public static async Task DownloadFFprobe(string directoryPath = "")
		{
			await FFDownloader(directoryPath, FFmpegApi.BinaryType.FFprobe);
		}

		private static void SetUnixExecPerms(string filename)
		{
			if (OSHelper.IsWindows)
			{
				return;
			}
			throw new PlatformNotSupportedException("Setting Unix permissions is not supported on this platform.");
		}

		private static HttpClient GetHttpClient()
		{
			HttpClient httpClient = null;
			if (httpClient == null)
			{
				httpClient = new HttpClient();
				httpClient.Timeout = TimeSpan.FromSeconds(TimeoutSeconds);
			}
			return httpClient;
		}

		private static async Task FFDownloader(string directoryPath = "", FFmpegApi.BinaryType binary = FFmpegApi.BinaryType.FFmpeg)
		{
			HttpClient client = GetHttpClient();
			if (string.IsNullOrEmpty(directoryPath))
			{
				directoryPath = Directory.GetCurrentDirectory();
			}
			FFmpegApi.Root 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"), 
			};
			byte[] buffer = await DownloadFileBytesAsync((binary == FFmpegApi.BinaryType.FFmpeg) ? osBinVersion.Ffmpeg : osBinVersion.Ffprobe);
			string unixExecPerms = string.Empty;
			using (MemoryStream stream = new MemoryStream(buffer))
			{
				using ZipArchive zipArchive = new ZipArchive(stream, ZipArchiveMode.Read);
				if (zipArchive.Entries.Count > 0)
				{
					unixExecPerms = Path.Combine(directoryPath, zipArchive.Entries[0].FullName);
					zipArchive.Entries[0].ExtractToFile(Path.Combine(directoryPath, zipArchive.Entries[0].FullName), overwrite: true);
				}
			}
			SetUnixExecPerms(unixExecPerms);
			client?.Dispose();
		}

		private static async Task<byte[]> DownloadFileBytesAsync(string uri)
		{
			if (!Uri.TryCreate(uri, UriKind.Absolute, out Uri _))
			{
				throw new InvalidOperationException("URI is invalid.");
			}
			HttpClient client = GetHttpClient();
			byte[] result2 = await client.GetByteArrayAsync(uri);
			client?.Dispose();
			return result2;
		}

		public static async Task DownloadDeno(string directoryPath = "")
		{
			HttpClient client = GetHttpClient();
			if (string.IsNullOrEmpty(directoryPath))
			{
				directoryPath = Directory.GetCurrentDirectory();
			}
			string arg = (await (await client.GetAsync("https://dl.deno.land/release-latest.txt")).Content.ReadAsStringAsync()).Trim();
			byte[] buffer = await DownloadFileBytesAsync(string.Format("https://dl.deno.land/release/{0}/deno-{1}.zip", arg, OSHelper.GetOSVersion() switch
			{
				OSVersion.Windows => "x86_64-pc-windows-msvc", 
				OSVersion.OSX => "aarch64-apple-darwin", 
				OSVersion.Linux => "x86_64-unknown-linux-gnu", 
				_ => throw new NotImplementedException("Your OS isn't supported"), 
			}));
			string unixExecPerms = string.Empty;
			using (MemoryStream stream = new MemoryStream(buffer))
			{
				using ZipArchive zipArchive = new ZipArchive(stream, ZipArchiveMode.Read);
				if (zipArchive.Entries.Count > 0)
				{
					unixExecPerms = Path.Combine(directoryPath, zipArchive.Entries[0].FullName);
					zipArchive.Entries[0].ExtractToFile(Path.Combine(directoryPath, zipArchive.Entries[0].FullName), overwrite: true);
				}
			}
			SetUnixExecPerms(unixExecPerms);
			client?.Dispose();
		}

		public static void EnsureSuccess<T>(this RunResult<T> runResult)
		{
			if (!runResult.Success)
			{
				throw new Exception("Download failed:\n" + string.Join("\n", runResult.ErrorOutput));
			}
		}
	}
	public class YoutubeDL
	{
		private static readonly Regex rgxFile = new Regex("^outfile:\\s\\\"?(.*)\\\"?", RegexOptions.Compiled);

		private static Regex rgxFilePostProc = new Regex("\\[download\\] Destination: [a-zA-Z]:\\\\\\S+\\.\\S{3,}", RegexOptions.Compiled);

		protected ProcessRunner runner;

		public string YoutubeDLPath { get; set; } = Utils.YtDlpBinaryName;

		public string FFmpegPath { get; set; } = Utils.FfmpegBinaryName;

		public string OutputFolder { get; set; } = Environment.CurrentDirectory;

		public string OutputFileTemplate { get; set; } = "%(title)s [%(id)s].%(ext)s";

		public bool RestrictFilenames { get; set; }

		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),
				Progress = true,
				Print = "after_move:outfile: %(filepath)s"
			};
		}

		private YoutubeDLProcess CreateYoutubeDLProcess()
		{
			return new YoutubeDLProcess(YoutubeDLPath)
			{
				PythonPath = PythonInterpreterPath
			};
		}
	}
	public class YoutubeDLProcess
	{
		private static readonly Regex rgxPlaylist = new Regex("Downloading video (\\d+) of (\\d+)", RegexOptions.Compiled);

		private static readonly Regex rgxProgress = new Regex("\\[download\\]\\s+(?:(?<percent>[\\d\\.]+)%(?:\\s+of\\s+\\~?\\s*(?<total>[\\d\\.\\w]+))?\\s+at\\s+(?:(?<speed>[\\d\\.\\w]+\\/s)|[\\w\\s]+)\\s+ETA\\s(?<eta>[\\d\\:]+))?", RegexOptions.Compiled);

		private static readonly Regex rgxPost = new Regex("\\[(\\w+)\\]\\s+", RegexOptions.Compiled);

		public string PythonPath { get; set; }

		public string ExecutablePath { get; set; }

		public event EventHandler<DataReceivedEventArgs> OutputReceived;

		public event EventHandler<DataReceivedEventArgs> ErrorReceived;

		public YoutubeDLProcess(string executablePath = "yt-dlp.exe")
		{
			ExecutablePath = executablePath;
		}

		internal string ConvertToArgs(string[] urls, OptionSet options)
		{
			return options.ToString() + " -- " + ((urls != null) ? string.Join(" ", urls.Select((string s) => "\"" + s + "\"")) : string.Empty);
		}

		internal void RedirectToError(DataReceivedEventArgs e)
		{
			this.ErrorReceived?.Invoke(this, e);
		}

		public async Task<int> RunAsync(string[] urls, OptionSet options)
		{
			return await RunAsync(urls, options, CancellationToken.None);
		}

		public async Task<int> RunAsync(string[] urls, OptionSet options, CancellationToken ct, IProgress<DownloadProgress> progress = null)
		{
			TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
			Process process = new Process();
			ProcessStartInfo 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 obj = match.Groups["total"];
							string totalDownloadSize = (obj.Success ? obj.Value : null);
							Group obj2 = match.Groups["speed"];
							string downloadSpeed = (obj2.Success ? obj2.Value : null);
							Group obj3 = match.Groups["eta"];
							string eta = (obj3.Success ? obj3.Value : null);
							progress?.Report(new DownloadProgress(DownloadState.Downloading, progress2, totalDownloadSize, downloadSpeed, eta));
						}
						else
						{
							progress?.Report(new DownloadProgress(DownloadState.Downloading));
						}
						isDownloading = true;
					}
					else if ((match = rgxPlaylist.Match(e.Data)).Success)
					{
						int index = int.Parse(match.Groups[1].Value);
						progress?.Report(new DownloadProgress(DownloadState.PreProcessing, 0f, null, null, null, index));
						isDownloading = false;
					}
					else if (isDownloading && (match = rgxPost.Match(e.Data)).Success)
					{
						progress?.Report(new DownloadProgress(DownloadState.PostProcessing, 1f));
						isDownloading = false;
					}
					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 text = s.Substring(array[0].Length).Trim();
			if (typeof(T) != typeof(StringVals))
			{
				text = text.Trim(new char[1] { '"' });
			}
			if (!OptionStrings.Contains(array[0]))
			{
				throw new ArgumentException("Given string does not match required format.");
			}
			T val = Utils.OptionValueFromString<T>(text);
			if (!IsSet)
			{
				Value = val;
			}
			else
			{
				Value.Values.Add(val);
			}
		}

		public override string ToString()
		{
			return string.Join(" ", ToStringCollection());
		}

		public IEnumerable<string> ToStringCollection()
		{
			if (!IsSet)
			{
				return new string[1] { "" };
			}
			List<string> list = new List<string>();
			foreach (T value in Value.Values)
			{
				list.Add(DefaultOptionString + Utils.OptionValueToString(value));
			}
			return list;
		}
	}
	public class MultiValue<T>
	{
		private readonly List<T> values;

		public List<T> Values => values;

		public MultiValue(params T[] values)
		{
			this.values = values.ToList();
		}

		public static implicit operator MultiValue<T>(T value)
		{
			return new MultiValue<T>(value);
		}

		public static implicit operator MultiValue<T>(T[] values)
		{
			return new MultiValue<T>(values);
		}

		public static explicit operator T(MultiValue<T> value)
		{
			if (value.Values.Count == 1)
			{
				return value.Values[0];
			}
			throw new InvalidCastException($"Cannot cast sequence of values to {typeof(T)}.");
		}

		public static explicit operator T[](MultiValue<T> value)
		{
			return value.Values.ToArray();
		}
	}
	public class Option<T> : IOption
	{
		private T value;

		public string DefaultOptionString => OptionStrings.First();

		public string[] OptionStrings { get; }

		public bool IsSet { get; private set; }

		public T Value
		{
			get
			{
				return value;
			}
			set
			{
				IsSet = !object.Equals(value, default(T));
				this.value = value;
			}
		}

		public bool IsCustom { get; }

		public Option(params string[] optionStrings)
		{
			OptionStrings = optionStrings;
			IsSet = false;
		}

		public Option(bool isCustom, params string[] optionStrings)
		{
			OptionStrings = optionStrings;
			IsSet = false;
			IsCustom = isCustom;
		}

		public void SetFromString(string s)
		{
			string[] array = s.Split(new char[1] { ' ' });
			string text = s.Substring(array[0].Length).Trim();
			if (typeof(T) != typeof(StringVals))
			{
				text = text.Trim(new char[1] { '"' });
			}
			if (!OptionStrings.Contains(array[0]))
			{
				throw new ArgumentException("Given string does not match required format.");
			}
			Value = Utils.OptionValueFromString<T>(text);
		}

		public override string ToString()
		{
			if (!IsSet)
			{
				return string.Empty;
			}
			string text = Utils.OptionValueToString(Value);
			return DefaultOptionString + text;
		}

		public IEnumerable<string> ToStringCollection()
		{
			return new string[1] { ToString() };
		}
	}
	internal class OptionComparer : IEqualityComparer<IOption>
	{
		public bool Equals(IOption x, IOption y)
		{
			if (x != null)
			{
				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> hlsUseMpegts = new Option<bool>("--hls-use-mpegts");

		private Option<bool> noHlsUseMpegts = new Option<bool>("--no-hls-use-mpegts");

		private MultiOption<string> downloadSections = new MultiOption<string>("--download-sections");

		private MultiOption<string> downloader = new MultiOption<string>("--downloader", "--external-downloader");

		private MultiOption<string> downloaderArgs = new MultiOption<string>("--downloader-args", "--external-downloader-args");

		private Option<int?> extractorRetries = new Option<int?>("--extractor-retries");

		private Option<bool> allowDynamicMpd = new Option<bool>("--allow-dynamic-mpd", "--no-ignore-dynamic-mpd");

		private Option<bool> ignoreDynamicMpd = new Option<bool>("--ignore-dynamic-mpd", "--no-allow-dynamic-mpd");

		private Option<bool> hlsSplitDiscontinuity = new Option<bool>("--hls-split-discontinuity");

		private Option<bool> noHlsSplitDiscontinuity = new Option<bool>("--no-hls-split-discontinuity");

		private MultiOption<string> extractorArgs = new MultiOption<string>("--extractor-args");

		private Option<string> batchFile = new Option<string>("-a", "--batch-file");

		private Option<bool> noBatchFile = new Option<bool>("--no-batch-file");

		private MultiOption<string> paths = new MultiOption<string>("-P", "--paths");

		private Option<string> output = new Option<string>("-o", "--output");

		private Option<string> outputNaPlaceholder = new Option<string>("--output-na-placeholder");

		private Option<bool> restrictFilenames = new Option<bool>("--restrict-filenames");

		private Option<bool> noRestrictFilenames = new Option<bool>("--no-restrict-filenames");

		private Option<bool> windowsFilenames = new Option<bool>("--windows-filenames");

		private Option<bool> noWindowsFilenames = new Option<bool>("--no-windows-filenames");

		private Option<int?> trimFilenames = new Option<int?>("--trim-filenames");

		private Option<bool> noOverwrites = new Option<bool>("-w", "--no-overwrites");

		private Option<bool> forceOverwrites = new Option<bool>("--force-overwrites");

		private Option<bool> noForceOverwrites = new Option<bool>("--no-force-overwrites");

		private Option<bool> doContinue = new Option<bool>("-c", "--continue");

		private Option<bool> noContinue = new Option<bool>("--no-continue");

		private Option<bool> part = new Option<bool>("--part");

		private Option<bool> noPart = new Option<bool>("--no-part");

		private Option<bool> mtime = new Option<bool>("--mtime");

		private Option<bool> noMtime = new Option<bool>("--no-mtime");

		private Option<bool> writeDescription = new Option<bool>("--write-description");

		private Option<bool> noWriteDescription = new Option<bool>("--no-write-description");

		private Option<bool> writeInfoJson = new Option<bool>("--write-info-json");

		private Option<bool> noWriteInfoJson = new Option<bool>("--no-write-info-json");

		private Option<bool> writePlaylistMetafiles = new Option<bool>("--write-playlist-metafiles");

		private Option<bool> noWritePlaylistMetafiles = new Option<bool>("--no-write-playlist-metafiles");

		private Option<bool> cleanInfoJson = new Option<bool>("--clean-info-json");

		private Option<bool> noCleanInfoJson = new Option<bool>("--no-clean-info-json");

		private Option<bool> writeComments = new Option<bool>("--write-comments", "--get-comments");

		private Option<bool> noWriteComments = new Option<bool>("--no-write-comments", "--no-get-comments");

		private Option<string> loadInfoJson = new Option<string>("--load-info-json");

		private Option<string> cookies = new Option<string>("--cookies");

		private Option<bool> noCookies = new Option<bool>("--no-cookies");

		private Option<string> cookiesFromBrowser = new Option<string>("--cookies-from-browser");

		private Option<bool> noCookiesFromBrowser = new Option<bool>("--no-cookies-from-browser");

		private Option<string> cacheDir = new Option<string>("--cache-dir");

		private Option<bool> noCacheDir = new Option<bool>("--no-cache-dir");

		private Option<bool> removeCacheDir = new Option<bool>("--rm-cache-dir");

		private Option<bool> help = new Option<bool>("-h", "--help");

		private Option<bool> version = new Option<bool>("--version");

		private Option<bool> update = new Option<bool>("-U", "--update");

		private Option<bool> noUpdate = new Option<bool>("--no-update");

		private Option<string> updateTo = new Option<string>("--update-to");

		private Option<bool> ignoreErrors = new Option<bool>("-i", "--ignore-errors");

		private Option<bool> noAbortOnError = new Option<bool>("--no-abort-on-error");

		private Option<bool> abortOnError = new Option<bool>("--abort-on-error", "--no-ignore-errors");

		private Option<bool> listExtractors = new Option<bool>("--list-extractors");

		private Option<bool> extractorDescriptions = new Option<bool>("--extractor-descriptions");

		private Option<string> useExtractors = new Option<string>("--use-extractors", "--ies");

		private Option<string> defaultSearch = new Option<string>("--default-search");

		private Option<bool> ignoreConfig = new Option<bool>("--ignore-config", "--no-config");

		private Option<bool> noConfigLocations = new Option<bool>("--no-config-locations");

		private MultiOption<string> configLocations = new MultiOption<string>("--config-locations");

		private MultiOption<string> pluginDirs = new MultiOption<string>("--plugin-dirs");

		private Option<bool> noPluginDirs = new Option<bool>("--no-plugin-dirs");

		private MultiOption<string> jsRuntimes = new MultiOption<string>("--js-runtimes");

		private Option<bool> noJsRuntimes = new Option<bool>("--no-js-runtimes");

		private MultiOption<string> remoteComponents = new MultiOption<string>("--remote-components");

		private Option<bool> noRemoteComponents = new Option<bool>("--no-remote-components");

		private Option<bool> flatPlaylist = new Option<bool>("--flat-playlist");

		private Option<bool> noFlatPlaylist = new Option<bool>("--no-flat-playlist");

		private Option<bool> liveFromStart = new Option<bool>("--live-from-start");

		private Option<bool> noLiveFromStart = new Option<bool>("--no-live-from-start");

		private Option<string> waitForVideo = new Option<string>("--wait-for-video");

		private Option<bool> noWaitForVideo = new Option<bool>("--no-wait-for-video");

		private Option<bool> markWatched = new Option<bool>("--mark-watched");

		private Option<bool> noMarkWatched = new Option<bool>("--no-mark-watched");

		private MultiOption<string> color = new MultiOption<string>("--color");

		private Option<string> compatOptions = new Option<string>("--compat-options");

		private MultiOption<StringVals> alias = new MultiOption<StringVals>("--alias");

		private MultiOption<string> presetAlias = new MultiOption<string>("-t", "--preset-alias");

		private Option<string> geoVerificationProxy = new Option<string>("--geo-verification-proxy");

		private Option<string> xff = new Option<string>("--xff");

		private Option<bool> writeLink = new Option<bool>("--write-link");

		private Option<bool> writeUrlLink = new Option<bool>("--write-url-link");

		private Option<bool> writeWeblocLink = new Option<bool>("--write-webloc-link");

		private Option<bool> writeDesktopLink = new Option<bool>("--write-desktop-link");

		private Option<string> proxy = new Option<string>("--proxy");

		private Option<int?> socketTimeout = new Option<int?>("--socket-timeout");

		private Option<string> sourceAddress = new Option<string>("--source-address");

		private Option<string> impersonate = new Option<string>("--impersonate");

		private Option<bool> listImpersonateTargets = new Option<bool>("--list-impersonate-targets");

		private Option<bool> forceIPv4 = new Option<bool>("-4", "--force-ipv4");

		private Option<bool> forceIPv6 = new Option<bool>("-6", "--force-ipv6");

		private Option<bool> enableFileUrls = new Option<bool>("--enable-file-urls");

		private Option<bool> extractAudio = new Option<bool>("-x", "--extract-audio");

		private Option<AudioConversionFormat> audioFormat = new Option<AudioConversionFormat>("--audio-format");

		private Option<byte?> audioQuality = new Option<byte?>("--audio-quality");

		private Option<string> remuxVideo = new Option<string>("--remux-video");

		private Option<VideoRecodeFormat> recodeVideo = new Option<VideoRecodeFormat>("--recode-video");

		private MultiOption<string> postprocessorArgs = new MultiOption<string>("--postprocessor-args", "--ppa");

		private Option<bool> keepVideo = new Option<bool>("-k", "--keep-video");

		private Option<bool> noKeepVideo = new Option<bool>("--no-keep-video");

		private Option<bool> postOverwrites = new Option<bool>("--post-overwrites");

		private Option<bool> noPostOverwrites = new Option<bool>("--no-post-overwrites");

		private Option<bool> embedSubs = new Option<bool>("--embed-subs");

		private Option<bool> noEmbedSubs = new Option<bool>("--no-embed-subs");

		private Option<bool> embedThumbnail = new Option<bool>("--embed-thumbnail");

		private Option<bool> noEmbedThumbnail = new Option<bool>("--no-embed-thumbnail");

		private Option<bool> embedMetadata = new Option<bool>("--embed-metadata", "--add-metadata");

		private Option<bool> noEmbedMetadata = new Option<bool>("--no-embed-metadata", "--no-add-metadata");

		private Option<bool> embedChapters = new Option<bool>("--embed-chapters", "--add-chapters");

		private Option<bool> noEmbedChapters = new Option<bool>("--no-embed-chapters", "--no-add-chapters");

		private Option<bool> embedInfoJson = new Option<bool>("--embed-info-json");

		private Option<bool> noEmbedInfoJson = new Option<bool>("--no-embed-info-json");

		private Option<string> parseMetadata = new Option<string>("--parse-metadata");

		private MultiOption<StringVals> replaceInMetadata = new MultiOption<StringVals>("--replace-in-metadata");

		private Option<bool> xattrs = new Option<bool>("--xattrs");

		private Option<string> concatPlaylist = new Option<string>("--concat-playlist");

		private Option<string> fixup = new Option<string>("--fixup");

		private Option<string> ffmpegLocation = new Option<string>("--ffmpeg-location");

		private MultiOption<string> exec = new MultiOption<string>("--exec");

		private Option<bool> noExec = new Option<bool>("--no-exec");

		private Option<string> convertSubs = new Option<string>("--convert-subs");

		private Option<string> convertThumbnails = new Option<string>("--convert-thumbnails");

		private Option<bool> splitChapters = new Option<bool>("--split-chapters");

		private Option<bool> noSplitChapters = new Option<bool>("--no-split-chapters");

		private MultiOption<string> removeChapters = new MultiOption<string>("--remove-chapters");

		private Option<bool> noRemoveChapters = new Option<bool>("--no-remove-chapters");

		private Option<bool> forceKeyframesAtCuts = new Option<bool>("--force-keyframes-at-cuts");

		private Option<bool> noForceKeyframesAtCuts = new Option<bool>("--no-force-keyframes-at-cuts");

		private MultiOption<string> usePostprocessor = new MultiOption<string>("--use-postprocessor");

		private Option<string> sponsorblockMark = new Option<string>("--sponsorblock-mark");

		private Option<string> sponsorblockRemove = new Option<string>("--sponsorblock-remove");

		private Option<string> sponsorblockChapterTitle = new Option<string>("--sponsorblock-chapter-title");

		private Option<bool> noSponsorblock = new Option<bool>("--no-sponsorblock");

		private Option<string> sponsorblockApi = new Option<string>("--sponsorblock-api");

		private Option<bool> writeSubs = new Option<bool>("--write-subs");

		private Option<bool> noWriteSubs = new Option<bool>("--no-write-subs");

		private Option<bool> writeAutoSubs = new Option<bool>("--write-auto-subs", "--write-automatic-subs");

		private Option<bool> noWriteAutoSubs = new Option<bool>("--no-write-auto-subs", "--no-write-automatic-subs");

		private Option<bool> listSubs = new Option<bool>("--list-subs");

		private Option<string> subFormat = new Option<string>("--sub-format");

		private Option<string> subLangs = new Option<string>("--sub-langs");

		private Option<bool> writeThumbnail = new Option<bool>("--write-thumbnail");

		private Option<bool> noWriteThumbnail = new Option<bool>("--no-write-thumbnail");

		private Option<bool> writeAllThumbnails = new Option<bool>("--write-all-thumbnails");

		private Option<bool> listThumbnails = new Option<bool>("--list-thumbnails");

		private Option<bool> quiet = new Option<bool>("-q", "--quiet");

		private Option<bool> noQuiet = new Option<bool>("--no-quiet");

		private Option<bool> noWarnings = new Option<bool>("--no-warnings");

		private Option<bool> simulate = new Option<bool>("-s", "--simulate");

		private Option<bool> noSimulate = new Option<bool>("--no-simulate");

		private Option<bool> ignoreNoFormatsError = new Option<bool>("--ignore-no-formats-error");

		private Option<bool> noIgnoreNoFormatsError = new Option<bool>("--no-ignore-no-formats-error");

		private Option<bool> skipDownload = new Option<bool>("--skip-download", "--no-download");

		private MultiOption<string> print = new MultiOption<string>("-O", "--print");

		private MultiOption<string> printToFile = new MultiOption<string>("--print-to-file");

		private Option<bool> dumpJson = new Option<bool>("-j", "--dump-json");

		private Option<bool> dumpSingleJson = new Option<bool>("-J", "--dump-single-json");

		private Option<bool> forceWriteArchive = new Option<bool>("--force-write-archive", "--force-download-archive");

		private Option<bool> newline = new Option<bool>("--newline");

		private Option<bool> noProgress = new Option<bool>("--no-progress");

		private Option<bool> progress = new Option<bool>("--progress");

		private Option<bool> consoleTitle = new Option<bool>("--console-title");

		private Option<string> progressTemplate = new Option<string>("--progress-template");

		private Option<string> progressDelta = new Option<string>("--progress-delta");

		private Option<bool> verbose = new Option<bool>("-v", "--verbose");

		private Option<bool> dumpPages = new Option<bool>("--dump-pages");

		private Option<bool> writePages = new Option<bool>("--write-pages");

		private Option<bool> printTraffic = new Option<bool>("--print-traffic");

		private Option<string> format = new Option<string>("-f", "--format");

		private Option<string> formatSort = new Option<string>("-S", "--format-sort");

		private Option<bool> formatSortForce = new Option<bool>("--format-sort-force", "--S-force");

		private Option<bool> noFormatSortForce = new Option<bool>("--no-format-sort-force");

		private Option<bool> videoMultistreams = new Option<bool>("--video-multistreams");

		private Option<bool> noVideoMultistreams = new Option<bool>("--no-video-multistreams");

		private Option<bool> audioMultistreams = new Option<bool>("--audio-multistreams");

		private Option<bool> noAudioMultistreams = new Option<bool>("--no-audio-multistreams");

		private Option<bool> preferFreeFormats = new Option<bool>("--prefer-free-formats");

		private Option<bool> noPreferFreeFormats = new Option<bool>("--no-prefer-free-formats");

		private Option<bool> checkFormats = new Option<bool>("--check-formats");

		private Option<bool> checkAllFormats = new Option<bool>("--check-all-formats");

		private Option<bool> noCheckFormats = new Option<bool>("--no-check-formats");

		private Option<bool> listFormats = new Option<bool>("-F", "--list-formats");

		private Option<DownloadMergeFormat> mergeOutputFormat = new Option<DownloadMergeFormat>("--merge-output-format");

		private Option<string> playlistItems = new Option<string>("-I", "--playlist-items");

		private Option<string> minFilesize = new Option<string>("--min-filesize");

		private Option<string> maxFilesize = new Option<string>("--max-filesize");

		private Option<DateTime> date = new Option<DateTime>("--date");

		private Option<DateTime> dateBefore = new Option<DateTime>("--datebefore");

		private Option<DateTime> dateAfter = new Option<DateTime>("--dateafter");

		private MultiOption<string> matchFilters = new MultiOption<string>("--match-filters");

		private Option<bool> noMatchFilters = new Option<bool>("--no-match-filters");

		private Option<string> breakMatchFilters = new Option<string>("--break-match-filters");

		private Option<bool> noBreakMatchFilters = new Option<bool>("--no-break-match-filters");

		private Option<bool> noPlaylist = new Option<bool>("--no-playlist");

		private Option<bool> yesPlaylist = new Option<bool>("--yes-playlist");

		private Option<byte?> ageLimit = new Option<byte?>("--age-limit");

		private Option<string> downloadArchive = new Option<string>("--download-archive");

		private Option<bool> noDownloadArchive = new Option<bool>("--no-download-archive");

		private Option<int?> maxDownloads = new Option<int?>("--max-downloads");

		private Option<bool> breakOnExisting = new Option<bool>("--break-on-existing");

		private Option<bool> noBreakOnExisting = new Option<bool>("--no-break-on-existing");

		private Option<bool> breakPerInput = new Option<bool>("--break-per-input");

		private Option<bool> noBreakPerInput = new Option<bool>("--no-break-per-input");

		private Option<int?> skipPlaylistAfterErrors = new Option<int?>("--skip-playlist-after-errors");

		private Option<string> encoding = new Option<string>("--encoding");

		private Option<bool> legacyServerConnect = new Option<bool>("--legacy-server-connect");

		private Option<bool> noCheckCertificates = new Option<bool>("--no-check-certificates");

		private Option<bool> preferInsecure = new Option<bool>("--prefer-insecure");

		private MultiOption<string> addHeaders = new MultiOption<string>("--add-headers");

		private Option<bool> bidiWorkaround = new Option<bool>("--bidi-workaround");

		private Option<int?> sleepRequests = new Option<int?>("--sleep-requests");

		private Option<int?> sleepInterval = new Option<int?>("--sleep-interval", "--min-sleep-interval");

		private Option<int?> maxSleepInterval = new Option<int?>("--max-sleep-interval");

		private Option<int?> sleepSubtitles = new Option<int?>("--sleep-subtitles");

		public string Username
		{
			get
			{
				return username.Value;
			}
			set
			{
				username.Value = value;
			}
		}

		public string Password
		{
			get
			{
				return password.Value;
			}
			set
			{
				password.Value = value;
			}
		}

		public string TwoFactor
		{
			get
			{
				return twoFactor.Value;
			}
			set
			{
				twoFactor.Value = value;
			}
		}

		public bool Netrc
		{
			get
			{
				return netrc.Value;
			}
			set
			{
				netrc.Value = value;
			}
		}

		public string NetrcLocation
		{
			get
			{
				return netrcLocation.Value;
			}
			set
			{
				netrcLocation.Value = value;
			}
		}

		public string NetrcCmd
		{
			get
			{
				return netrcCmd.Value;
			}
			set
			{
				netrcCmd.Value = value;
			}
		}

		public string VideoPassword
		{
			get
			{
				return videoPassword.Value;
			}
			set
			{
				videoPassword.Value = value;
			}
		}

		public string ApMso
		{
			get
			{
				return apMso.Value;
			}
			set
			{
				apMso.Value = value;
			}
		}

		public string ApUsername
		{
			get
			{
				return apUsername.Value;
			}
			set
			{
				apUsername.Value = value;
			}
		}

		public string ApPassword
		{
			get
			{
				return apPassword.Value;
			}
			set
			{
				apPassword.Value = value;
			}
		}

		public bool ApListMso
		{
			get
			{
				return apListMso.Value;
			}
			set
			{
				apListMso.Value = value;
			}
		}

		public string ClientCertificate
		{
			get
			{
				return clientCertificate.Value;
			}
			set
			{
				clientCertificate.Value = value;
			}
		}

		public string ClientCertificateKey
		{
			get
			{
				return clientCertificateKey.Value;
			}
			set
			{
				clientCertificateKey.Value = value;
			}
		}

		public string ClientCertificatePassword
		{
			get
			{
				return clientCertificatePassword.Value;
			}
			set
			{
				clientCertificatePassword.Value = value;
			}
		}

		public IOption[] CustomOptions { get; set; } = new IOption[0];

		[Obsolete("Deprecated in favor of: --print description.")]
		public bool GetDescription
		{
			get
			{
				return getDescription.Value;
			}
			set
			{
				getDescription.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --print duration_string.")]
		public bool GetDuration
		{
			get
			{
				return getDuration.Value;
			}
			set
			{
				getDuration.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --print filename.")]
		public bool GetFilename
		{
			get
			{
				return getFilename.Value;
			}
			set
			{
				getFilename.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --print format.")]
		public bool GetFormat
		{
			get
			{
				return getFormat.Value;
			}
			set
			{
				getFormat.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --print id.")]
		public bool GetId
		{
			get
			{
				return getId.Value;
			}
			set
			{
				getId.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --print thumbnail.")]
		public bool GetThumbnail
		{
			get
			{
				return getThumbnail.Value;
			}
			set
			{
				getThumbnail.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --print title.")]
		public bool GetTitle
		{
			get
			{
				return getTitle.Value;
			}
			set
			{
				getTitle.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --print urls.")]
		public bool GetUrl
		{
			get
			{
				return getUrl.Value;
			}
			set
			{
				getUrl.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --match-filter \"title ~= (?i)REGEX\".")]
		public string MatchTitle
		{
			get
			{
				return matchTitle.Value;
			}
			set
			{
				matchTitle.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --match-filter \"title !~= (?i)REGEX\".")]
		public string RejectTitle
		{
			get
			{
				return rejectTitle.Value;
			}
			set
			{
				rejectTitle.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --match-filter \"view_count >=? COUNT\".")]
		public long? MinViews
		{
			get
			{
				return minViews.Value;
			}
			set
			{
				minViews.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --match-filter \"view_count <=? COUNT\".")]
		public long? MaxViews
		{
			get
			{
				return maxViews.Value;
			}
			set
			{
				maxViews.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: Use --break-match-filter.")]
		public bool BreakOnReject
		{
			get
			{
				return breakOnReject.Value;
			}
			set
			{
				breakOnReject.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --add-header \"User-Agent:UA\".")]
		public string UserAgent
		{
			get
			{
				return userAgent.Value;
			}
			set
			{
				userAgent.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --add-header \"Referer:URL\".")]
		public string Referer
		{
			get
			{
				return referer.Value;
			}
			set
			{
				referer.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: -I NUMBER:.")]
		public int? PlaylistStart
		{
			get
			{
				return playlistStart.Value;
			}
			set
			{
				playlistStart.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: -I :NUMBER.")]
		public int? PlaylistEnd
		{
			get
			{
				return playlistEnd.Value;
			}
			set
			{
				playlistEnd.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: -I ::-1.")]
		public bool PlaylistReverse
		{
			get
			{
				return playlistReverse.Value;
			}
			set
			{
				playlistReverse.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --color no_color.")]
		public bool NoColors
		{
			get
			{
				return noColors.Value;
			}
			set
			{
				noColors.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --ies generic,default.")]
		public bool ForceGenericExtractor
		{
			get
			{
				return forceGenericExtractor.Value;
			}
			set
			{
				forceGenericExtractor.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --exec \"before_dl:CMD\".")]
		public string ExecBeforeDownload
		{
			get
			{
				return execBeforeDownload.Value;
			}
			set
			{
				execBeforeDownload.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --no-exec.")]
		public bool NoExecBeforeDownload
		{
			get
			{
				return noExecBeforeDownload.Value;
			}
			set
			{
				noExecBeforeDownload.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: -f all.")]
		public bool AllFormats
		{
			get
			{
				return allFormats.Value;
			}
			set
			{
				allFormats.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --sub-langs all --write-subs.")]
		public bool AllSubs
		{
			get
			{
				return allSubs.Value;
			}
			set
			{
				allSubs.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: -j --no-simulate.")]
		public bool PrintJson
		{
			get
			{
				return printJson.Value;
			}
			set
			{
				printJson.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: Use string formatting, e.g. %(autonumber)03d.")]
		public string AutonumberSize
		{
			get
			{
				return autonumberSize.Value;
			}
			set
			{
				autonumberSize.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: Use internal field formatting like %(autonumber+NUMBER)s.")]
		public int? AutonumberStart
		{
			get
			{
				return autonumberStart.Value;
			}
			set
			{
				autonumberStart.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: -o \"%(id)s.%(ext)s\".")]
		public bool Id
		{
			get
			{
				return id.Value;
			}
			set
			{
				id.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --parse-metadata \"%(title)s:FORMAT\".")]
		public string MetadataFromTitle
		{
			get
			{
				return metadataFromTitle.Value;
			}
			set
			{
				metadataFromTitle.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --downloader \"m3u8:native\".")]
		public bool HlsPreferNative
		{
			get
			{
				return hlsPreferNative.Value;
			}
			set
			{
				hlsPreferNative.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --downloader \"m3u8:ffmpeg\".")]
		public bool HlsPreferFfmpeg
		{
			get
			{
				return hlsPreferFfmpeg.Value;
			}
			set
			{
				hlsPreferFfmpeg.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --compat-options list-formats (Alias: --no-list-formats-as-table).")]
		public bool ListFormatsOld
		{
			get
			{
				return listFormatsOld.Value;
			}
			set
			{
				listFormatsOld.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --compat-options -list-formats [Default] (Alias: --no-list-formats-old).")]
		public bool ListFormatsAsTable
		{
			get
			{
				return listFormatsAsTable.Value;
			}
			set
			{
				listFormatsAsTable.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --extractor-args \"youtube:skip=dash\" (Alias: --no-youtube-include-dash-manifest).")]
		public bool YoutubeSkipDashManifest
		{
			get
			{
				return youtubeSkipDashManifest.Value;
			}
			set
			{
				youtubeSkipDashManifest.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --extractor-args \"youtube:skip=hls\" (Alias: --no-youtube-include-hls-manifest).")]
		public bool YoutubeSkipHlsManifest
		{
			get
			{
				return youtubeSkipHlsManifest.Value;
			}
			set
			{
				youtubeSkipHlsManifest.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --xff \"default\".")]
		public bool GeoBypass
		{
			get
			{
				return geoBypass.Value;
			}
			set
			{
				geoBypass.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --xff \"never\".")]
		public bool NoGeoBypass
		{
			get
			{
				return noGeoBypass.Value;
			}
			set
			{
				noGeoBypass.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --xff CODE.")]
		public string GeoBypassCountry
		{
			get
			{
				return geoBypassCountry.Value;
			}
			set
			{
				geoBypassCountry.Value = value;
			}
		}

		[Obsolete("Deprecated in favor of: --xff IP_BLOCK.")]
		public string GeoBypassIpBlock
		{
			get
			{
				return geoBypassIpBlock.Value;
			}
			set
			{
				geoBypassIpBlock.Value = value;
			}
		}

		public int? ConcurrentFragments
		{
			get
			{
				return concurrentFragments.Value;
			}
			set
			{
				concurrentFragments.Value = value;
			}
		}

		public long? LimitRate
		{
			get
			{
				return limitRate.Value;
			}
			set
			{
				limitRate.Value = value;
			}
		}

		public long? ThrottledRate
		{
			get
			{
				return throttledRate.Value;
			}
			set
			{
				throttledRate.Value = value;
			}
		}

		public int? Retries
		{
			get
			{
				return retries.Value;
			}
			set
			{
				retries.Value = value;
			}
		}

		public int? FileAccessRetries
		{
			get
			{
				return fileAccessRetries.Value;
			}
			set
			{
				fileAccessRetries.Value = value;
			}
		}

		public int? FragmentRetries
		{
			get
			{
				return fragmentRetries.Value;
			}
			set
			{
				fragmentRetries.Value = value;
			}
		}

		public MultiValue<string> RetrySleep
		{
			get
			{
				return retrySleep.Value;
			}
			set
			{
				retrySleep.Value = value;
			}
		}

		public bool SkipUnavailableFragments
		{
			get
			{
				return skipUnavailableFragments.Value;
			}
			set
			{
				skipUnavailableFragments.Value = value;
			}
		}

		public bool AbortOnUnavailableFragments
		{
			get
			{
				return abortOnUnavailableFragments.Value;
			}
			set
			{
				abortOnUnavailableFragments.Value = value;
			}
		}

		public bool KeepFragments
		{
			get
			{
				return keepFragments.Value;
			}
			set
			{
				keepFragments.Value = value;
			}
		}

		public bool NoKeepFragments
		{
			get
			{
				return noKeepFragments.Value;
			}
			set
			{
				noKeepFragments.Value = value;
			}
		}

		public long? BufferSize
		{
			get
			{
				return bufferSize.Value;
			}
			set
			{
				bufferSize.Value = value;
			}
		}

		public bool ResizeBuffer
		{
			get
			{
				return resizeBuffer.Value;
			}
			set
			{
				resizeBuffer.Value = value;
			}
		}

		public bool NoResizeBuffer
		{
			get
			{
				return noResizeBuffer.Value;
			}
			set
			{
				noResizeBuffer.Value = value;
			}
		}

		public long? HttpChunkSize
		{
			get
			{
				return httpChunkSize.Value;
			}
			set
			{
				httpChunkSize.Value = value;
			}
		}

		public bool PlaylistRandom
		{
			get
			{
				return playlistRandom.Value;
			}
			set
			{
				playlistRandom.Value = value;
			}
		}

		public bool LazyPlaylist
		{
			get
			{
				return lazyPlaylist.Value;
			}
			set
			{
				lazyPlaylist.Value = value;
			}
		}

		public bool NoLazyPlaylist
		{
			get
			{
				return noLazyPlaylist.Value;
			}
			set
			{
				noLazyPlaylist.Value = value;
			}
		}

		public bool HlsUseMpegts
		{
			get
			{
				return hlsUseMpegts.Value;
			}
			set
			{
				hlsUseMpegts.Value = value;
			}
		}

		public bool NoHlsUseMpegts
		{
			get
			{
				return noHlsUseMpegts.Value;
			}
			set
			{
				noHlsUseMpegts.Value = value;
			}
		}

		public MultiValue<string> DownloadSections
		{
			get
			{
				return downloadSections.Value;
			}
			set
			{
				downloadSections.Value = value;
			}
		}

		public MultiValue<string> Downloader
		{
			get
			{
				return downloader.Value;
			}
			set
			{
				downloader.Value = value;
			}
		}

		public MultiValue<string> DownloaderArgs
		{
			get
			{
				return downloaderArgs.Value;
			}
			set
			{
				downloaderArgs.Value = value;
			}
		}

		public int? ExtractorRetries
		{
			get
			{
				return extractorRetries.Value;
			}
			set
			{
				extractorRetries.Value = value;
			}
		}

		public bool AllowDynamicMpd
		{
			get
			{
				return allowDynamicMpd.Value;
			}
			set
			{
				allowDynamicMpd.Value = value;
			}
		}

		public bool IgnoreDynamicMpd
		{
			get
			{
				return ignoreDynamicMpd.Value;
			}
			set
			{
				ignoreDynamicMpd.Value = value;
			}
		}

		public bool HlsSplitDiscontinuity
		{
			get
			{
				return hlsSplitDiscontinuity.Value;
			}
			set
			{
				hlsSplitDiscontinuity.Value = value;
			}
		}

		public bool NoHlsSplitDiscontinuity
		{
			get
			{
				return noHlsSplitDiscontinuity.Value;
			}
			set
			{
				noHlsSplitDiscontinuity.Value = value;
			}
		}

		public MultiValue<string> ExtractorArgs
		{
			get
			{
				return extractorArgs.Value;
			}
			set
			{
				extractorArgs.Value = value;
			}
		}

		public string BatchFile
		{
			get
			{
				return batchFile.Value;
			}
			set
			{
				batchFile.Value = value;
			}
		}

		public bool NoBatchFile
		{
			get
			{
				return noBatchFile.Value;
			}
			set
			{
				noBatchFile.Value = value;
			}
		}

		public MultiValue<string> Paths
		{
			get
			{
				return paths.Value;
			}
			set
			{
				paths.Value = value;
			}
		}

		public string Output
		{
			get
			{
				return output.Value;
			}
			set
			{
				output.Value = value;
			}
		}

		public string OutputNaPlaceholder
		{
			get
			{
				return outputNaPlaceholder.Value;
			}
			set
			{
				outputNaPlaceholder.Value = value;
			}
		}

		public bool RestrictFilenames
		{
			get
			{
				return restrictFilenames.Value;
			}
			set
			{
				restrictFilenames.Value = value;
			}
		}

		public bool NoRestrictFilenames
		{
			get
			{
				return noRestrictFilenames.Value;
			}
			set
			{
				noRestrictFilenames.Value = value;
			}
		}

		public bool WindowsFilenames
		{
			get
			{
				return windowsFilenames.Value;
			}
			set
			{
				windowsFilenames.Value = value;
			}
		}

		public bool NoWindowsFilenames
		{
			get
			{
				return noWindowsFilenames.Value;
			}
			set
			{
				noWindowsFilenames.Value = value;
			}
		}

		public int? TrimFilenames
		{
			get
			{
				return trimFilenames.Value;
			}
			set
			{
				trimFilenames.Value = value;
			}
		}

		public bool NoOverwrites
		{
			get
			{
				return noOverwrites.Value;
			}
			set
			{
				noOverwrites.Value = value;
			}
		}

		public bool ForceOverwrites
		{
			get
			{
				return forceOverwrites.Value;
			}
			set
			{
				forceOverwrites.Value = value;
			}
		}

		public bool NoForceOverwrites
		{
			get
			{
				return noForceOverwrites.Value;
			}
			set
			{
				noForceOverwrites.Value = value;
			}
		}

		public bool Continue
		{
			get
			{
				return doContinue.Value;
			}
			set
			{
				doContinue.Value = value;
			}
		}

		public bool NoContinue
		{
			get
			{
				return noContinue.Value;
			}
			set
			{
				noContinue.Value = value;
			}
		}

		public bool Part
		{
			get
			{
				return part.Value;
			}
			set
			{
				part.Value = value;
			}
		}

		public bool NoPart
		{
			get
			{
				return noPart.Value;
			}
			set
			{
				noPart.Value = value;
			}
		}

		public bool Mtime
		{
			get
			{
				return mtime.Value;
			}
			set
			{
				mtime.Value = value;
			}
		}

		public bool NoMtime
		{
			get
			{
				return noMtime.Value;
			}
			set
			{
				noMtime.Value = value;
			}
		}

		public bool WriteDescription
		{
			get
			{
				return writeDescription.Value;
			}
			set
			{
				writeDescription.Value = value;
			}
		}

		public bool NoWriteDescription
		{
			get
			{
				return noWriteDescription.Value;
			}
			set
			{
				noWriteDescription.Value = value;
			}
		}

		public bool WriteInfoJson
		{
			get
			{
				return writeInfoJson.Value;
			}
			set
			{
				writeInfoJson.Value = value;
			}
		}

		public bool NoWriteInfoJson
		{
			get
			{
				return noWriteInfoJson.Value;
			}
			set
			{
				noWriteInfoJson.Value = value;
			}
		}

		public bool WritePlaylistMetafiles
		{
			get
			{
				return writePlaylistMetafiles.Value;
			}
			set
			{
				writePlaylistMetafiles.Value = value;
			}
		}

		public bool NoWritePlaylistMetafiles
		{
			get
			{
				return noWritePlaylistMetafiles.Value;
			}
			set
			{
				noWritePlaylistMetafiles.Value = value;
			}
		}

		public bool CleanInfoJson
		{
			get
			{
				return cleanInfoJson.Value;
			}
			set
			{
				cleanInfoJson.Value = value;
			}
		}

		public bool NoCleanInfoJson
		{
			get
			{
				return noCleanInfoJson.Value;
			}
			set
			{
				noCleanInfoJson.Value = value;
			}
		}

		public bool WriteComments
		{
			get
			{
				return writeComments.Value;
			}
			set
			{
				writeComments.Value = value;
			}
		}

		public bool NoWriteComments
		{
			get
			{
				return noWriteComments.Value;
			}
			set
			{
				noWriteComments.Value = value;
			}
		}

		public string LoadInfoJson
		{
			get
			{
				return loadInfoJson.Value;
			}
			set
			{
				loadInfoJson.Value = value;
			}
		}

		public string Cookies
		{
			get
			{
				return cookies.Value;
			}
			set
			{
				cookies.Value = value;
			}
		}

		public bool NoCookies
		{
			get
			{
				return noCookies.Value;
			}
			set
			{
				noCookies.Value = value;
			}
		}

		public string CookiesFromBrowser
		{
			get
			{
				return cookiesFromBrowser.Value;
			}
			set
			{
				cookiesFromBrowser.Value = value;
			}
		}

		public bool NoCookiesFromBrowser
		{
			get
			{
				return noCookiesFromBrowser.Value;
			}
			set
			{
				noCookiesFromBrowser.Value = value;
			}
		}

		public string CacheDir
		{
			get
			{
				return cacheDir.Value;
			}
			set
			{
				cacheDir.Value = value;
			}
		}

		public bool NoCacheDir
		{
			get
			{
				return noCacheDir.Value;
			}
			set
			{
				noCacheDir.Value = value;
			}
		}

		public bool RemoveCacheDir
		{
			get
			{
				return removeCacheDir.Value;
			}
			set
			{
				removeCacheDir.Value = value;
			}
		}

		public bool Help
		{
			get
			{
				return help.Value;
			}
			set
			{
				help.Value = value;
			}
		}

		public bool Version
		{
			get
			{
				return version.Value;
			}
			set
			{
				version.Value = value;
			}
		}

		public bool Update
		{
			get
			{
				return update.Value;
			}
			set
			{
				update.Value = value;
			}
		}

		public bool NoUpdate
		{
			get
			{
				return noUpdate.Value;
			}
			set
			{
				noUpdate.Value = value;
			}
		}

		public string UpdateTo
		{
			get
			{
				return updateTo.Value;
			}
			set
			{
				updateTo.Value = value;
			}
		}

		public bool IgnoreErrors
		{
			get
			{
				return ignoreErrors.Value;
			}
			set
			{
				ignoreErrors.Value = value;
			}
		}

		public bool NoAbortOnError
		{
			get
			{
				return noAbortOnError.Value;
			}
			set
			{
				noAbortOnError.Value = value;
			}
		}

		public bool AbortOnError
		{
			get
			{
				return abortOnError.Value;
			}
			set
			{
				abortOnError.Value = value;
			}
		}

		public bool ListExtractors
		{
			get
			{
				return listExtractors.Value;
			}
			set
			{
				listExtractors.Value = value;
			}
		}

		public bool ExtractorDescriptions
		{
			get
			{
				return extractorDescriptions.Value;
			}
			set
			{
				extractorDescriptions.Value = value;
			}
		}

		public string UseExtractors
		{
			get
			{
				return useExtractors.Value;
			}
			set
			{
				useExtractors.Value = value;
			}
		}

		public string DefaultSearch
		{
			get
			{
				return defaultSearch.Value;
			}
			set
			{
				defaultSearch.Value = value;
			}
		}

		public bool IgnoreConfig
		{
			get
			{
				return ignoreConfig.Value;
			}
			set
			{
				ignoreConfig.Value = value;
			}
		}

		public bool NoConfigLocations
		{
			get
			{
				return noConfigLocations.Value;
			}
			set
			{
				noConfigLocations.Value = value;
			}
		}

		public MultiValue<string> ConfigLocations
		{
			get
			{
				return configLocations.Value;
			}
			set
			{
				configLocations.Value = value;
			}
		}

		public MultiValue<string> PluginDirs
		{
			get
			{
				return pluginDirs.Value;
			}
			set
			{
				pluginDirs.Value = value;
			}
		}

		public bool NoPluginDirs
		{
			get
			{
				return noPluginDirs.Value;
			}
			set
			{
				noPluginDirs.Value = value;
			}
		}

		public MultiValue<string> JsRuntimes
		{
			get
			{
				return jsRuntimes.Value;
			}
			set
			{
				jsRuntimes.Value = value;
			}
		}

		public bool NoJsRuntimes
		{
			get
			{
				return noJsRuntimes.Value;
			}
			set
			{
				noJsRuntimes.Value = value;
			}
		}

		public MultiValue<string> RemoteComponents
		{
			get
			{
				return remoteComponents.Value;
			}
			set
			{
				remoteComponents.Value = value;
			}
		}

		public bool NoRemoteComponents
		{
			get
			{
				return noRemoteComponents.Value;
			}
			set
			{
				noRemoteComponents.Value = value;
			}
		}

		public bool FlatPlaylist
		{
			get
			{
				return flatPlaylist.Value;
			}
			set
			{
				flatPlaylist.Value = value;
			}
		}

		public bool NoFlatPlaylist
		{
			get
			{
				return noFlatPlaylist.Value;
			}
			set
			{
				noFlatPlaylist.Value = value;
			}
		}

		public bool LiveFromStart
		{
			get
			{
				return liveFromStart.Value;
			}
			set
			{
				liveFromStart.Value = value;
			}
		}

		public bool NoLiveFromStart
		{
			get
			{
				return noLiveFromStart.Value;
			}
			set
			{
				noLiveFromStart.Value = value;
			}
		}

		public string WaitForVideo
		{
			get
			{
				return waitForVideo.Value;
			}
			set
			{
				waitForVideo.Value = value;
			}
		}

		public bool NoWaitForVideo
		{
			get
			{
				return noWaitForVideo.Value;
			}
			set
			{
				noWaitForVideo.Value = value;
			}
		}

		public bool MarkWatched
		{
			get
			{
				return markWatched.Value;
			}
			set
			{
				markWatched.Value = value;
			}
		}

		public bool NoMarkWatched
		{
			get
			{
				return noMarkWatched.Value;
			}
			set
			{
				noMarkWatched.Value = value;
			}
		}

		public MultiValue<string> Color
		{
			get
			{
				return color.Value;
			}
			set
			{
				color.Value = value;
			}
		}

		public string CompatOptions
		{
			get
			{
				return compatOptions.Value;
			}
			set
			{
				compatOptions.Value = value;
			}
		}

		public MultiValue<StringVals> Alias
		{
			get
			{
				return alias.Value;
			}
			set
			{
				alias.Value = value;
			}
		}

		public MultiValue<string> PresetAlias
		{
			get
			{
				return presetAlias.Value;
			}
			set
			{
				presetAlias.Value = value;
			}
		}

		public string GeoVerificationProxy
		{
			get
			{
				return geoVerificationProxy.Value;
			}
			set
			{
				geoVerificationProxy.Value = value;
			}
		}

		public string Xff
		{
			get
			{
				return xff.Value;
			}
			set
			{
				xff.Value = value;
			}
		}

		public bool WriteLink
		{
			get
			{
				return writeLink.Value;
			}
			set
			{
				writeLink.Value = value;
			}
		}

		public bool WriteUrlLink
		{
			get
			{
				return writeUrlLink.Value;
			}
			set
			{
				writeUrlLink.Value = value;
			}
		}

		public bool WriteWeblocLink
		{
			get
			{
				return writeWeblocLink.Value;
			}
			set
			{
				writeWeblocLink.Value = value;
			}
		}

		public bool WriteDesktopLink
		{
			get
			{
				return writeDesktopLink.Value;
			}
			set
			{
				writeDesktopLink.Value = value;
			}
		}

		public string Proxy
		{
			get
			{
				return proxy.Value;
			}
			set
			{
				proxy.Value = value;
			}
		}

		public int? SocketTimeout
		{
			get
			{
				return socketTimeout.Value;
			}
			set
			{
				socketTimeout.Value = value;
			}
		}

		public string SourceAddress
		{
			get
			{
				return sourceAddress.Value;
			}
			set
			{
				sourceAddress.Value = value;
			}
		}

		public string Impersonate
		{
			get
			{
				return impersonate.Value;
			}
			set
			{
				impersonate.Value = value;
			}
		}

		public bool ListImpersonateTargets
		{
			get
			{
				return listImpersonateTargets.Value;
			}
			set
			{
				listImpersonateTargets.Value = value;
			}
		}

		public bool ForceIPv4
		{
			get
			{
				return forceIPv4.Value;
			}
			set
			{
				forceIPv4.Value = value;
			}
		}

		public bool ForceIPv6
		{
			get
			{
				return forceIPv6.Value;
			}
			set
			{
				forceIPv6.Value = value;
			}
		}

		public bool EnableFileUrls
		{
			get
			{
				return enableFileUrls.Value;
			}
			set
			{
				enableFileUrls.Value = value;
			}
		}

		public bool ExtractAudio
		{
			get
			{
				return extractAudio.Value;
			}
			set
			{
				extractAudio.Value = value;
			}
		}

		public AudioConversionFormat AudioFormat
		{
			get
			{
				return audioFormat.Value;
			}
			set
			{
				audioFormat.Value = value;
			}
		}

		public byte? AudioQuality
		{
			get
			{
				return audioQuality.Value;
			}
			set
			{
				audioQuality.Value = value;
			}
		}

		public string RemuxVideo
		{
			get
			{
				return remuxVideo.Value;
			}
			set
			{
				remuxVideo.Value = value;
			}
		}

		public VideoRecodeFormat RecodeVideo
		{
			get
			{
				return recodeVideo.Value;
			}
			set
			{
				recodeVideo.Value = value;
			}
		}

		public MultiValue<string> PostprocessorArgs
		{
			get
			{
				return postprocessorArgs.Value;
			}
			set
			{
				postprocessorArgs.Value = value;
			}
		}

		public bool KeepVideo
		{
			get
			{
				return keepVideo.Value;
			}
			set
			{
				keepVideo.Value = value;
			}
		}

		public bool NoKeepVideo
		{
			get
			{
				return noKeepVideo.Value;
			}
			set
			{
				noKeepVideo.Value = value;
			}
		}

		public bool PostOverwrites
		{
			get
			{
				return postOverwrites.Value;
			}
			set
			{
				postOverwrites.Value = value;
			}
		}

		public bool NoPostOverwrites
		{
			get
			{
				return noPostOverwrites.Value;
			}
			set
			{
				noPostOverwrites.Value = value;
			}
		}

		public bool EmbedSubs
		{
			get
			{
				return embedSubs.Value;
			}
			set
			{
				embedSubs.Value = value;
			}
		}

		public bool NoEmbedSubs
		{
			get
			{
				return noEmbedSubs.Value;
			}
			set
			{
				noEmbedSubs.Value = value;
			}
		}

		public bool EmbedThumbnail
		{
			get
			{
				return embedThumbnail.Value;
			}
			set
			{
				embedThumbnail.Value = value;
			}
		}

		public bool NoEmbedThumbnail
		{
			get
			{
				return noEmbedThumbnail.Value;
			}
			set
			{
				noEmbedThumbnail.Value = value;
			}
		}

		public bool EmbedMetadata
		{
			get
			{
				return embedMetadata.Value;
			}
			set
			{
				embedMetadata.Value = value;
			}
		}

		public bool NoEmbedMetadata
		{
			get
			{
				return noEmbedMetadata.Value;
			}
			set
			{
				noEmbedMetadata.Value = value;
			}
		}

		public bool EmbedChapters
		{
			get
			{
				return embedChapters.Value;
			}
			set
			{
				embedChapters.Value = value;
			}
		}

		public bool NoEmbedChapters
		{
			get
			{
				return noEmbedChapters.Value;
			}
			set
			{
				noEmbedChapters.Value = value;
			}
		}

		public bool EmbedInfoJson
		{
			get
			{
				return embedInfoJson.Value;
			}
			set
			{
				embedInfoJson.Value = value;
			}
		}

		public bool NoEmbedInfoJson
		{
			get
			{
				return noEmbedInfoJson.Value;
			}
			set
			{
				noEmbedInfoJson.Value = value;
			}
		}

		public string ParseMetadata
		{
			get
			{
				return parseMetadata.Value;
			}
			set
			{
				parseMetadata.Value = value;
			}
		}

		public MultiValue<StringVals> ReplaceInMetadata
		{
			get
			{
				return replaceInMetadata.Value;
			}
			set
			{
				replaceInMetadata.Value = value;
			}
		}

		public bool Xattrs
		{
			get
			{
				return xattrs.Value;
			}
			set
			{
				xattrs.Value = value;
			}
		}

		public string ConcatPlaylist
		{
			get
			{
				return concatPlaylist.Value;
			}
			set
			{
				concatPlaylist.Value = value;
			}
		}

		public string Fixup
		{
			get
			{
				return fixup.Value;
			}
			set
			{
				fixup.Value = value;
			}
		}

		public string FfmpegLocation
		{
			get
			{
				return ffmpegLocation.Value;
			}
			set
			{
				ffmpegLocation.Value = value;
			}
		}

		public MultiValue<string> Exec
		{
			get
			{
				return exec.Value;
			}
			set
			{
				exec.Value = value;
			}
		}

		public bool NoExec
		{
			get
			{
				return noExec.Value;
			}
			set
			{
				noExec.Value = value;
			}
		}

		public string ConvertSubs
		{
			get
			{
				return convertSubs.Value;
			}
			set
			{
				convertSubs.Value = value;
			}
		}

		public string ConvertThumbnails
		{
			get
			{
				return convertThumbnails.Value;
			}
			set
			{
				convertThumbnails.Value = value;
			}
		}

		public bool SplitChapters
		{
			get
			{
				return splitChapters.Value;
			}
			set
			{
				splitChapters.Value = value;
			}
		}

		public bool NoSplitChapters
		{
			get
			{
				return noSplitChapters.Value;
			}
			set
			{
				noSplitChapters.Value = value;
			}
		}

		public MultiValue<string> RemoveChapters
		{
			get
			{
				return removeChapters.Value;
			}
			set
			{
				removeChapters.Value = value;
			}
		}

		public bool NoRemoveChapters
		{
			get
			{
				return noRemoveChapters.Value;
			}
			set
			{
				noRemoveChapters.Value = value;
			}
		}

		public bool ForceKeyframesAtCuts
		{
			get
			{
				return forceKeyframesAtCuts.Value;
			}
			set
			{
				forceKeyframesAtCuts.Value = value;
			}
		}

		public bool NoForceKeyframesAtCuts
		{
			get
			{
				return noForceKeyframesAtCuts.Value;
			}
			set
			{
				noForceKeyframesAtCuts.Value = value;
			}
		}

		public MultiValue<string> UsePostprocessor
		{
			get
			{
				return usePostprocessor.Value;
			}
			set
			{
				usePostprocessor.Value = value;
			}
		}

		public string SponsorblockMark
		{
			get
			{
				return sponsorblockMark.Value;
			}
			set
			{
				sponsorblockMark.Value = value;
			}
		}

		public string SponsorblockRemove
		{
			get
			{
				return sponsorblockRemove.Value;
			}
			set
			{
				sponsorblockRemove.Value = value;
			}
		}

		public string SponsorblockChapterTitle
		{
			get
			{
				return sponsorblockChapterTitle.Value;
			}
			set
			{
				sponsorblockChapterTitle.Value = value;
			}
		}

		public bool NoSponsorblock
		{
			get
			{
				return noSponsorblock.Value;
			}
			set
			{
				noSponsorblock.Value = value;
			}
		}

		public string SponsorblockApi
		{
			get
			{
				return sponsorblockApi.Value;
			}
			set
			{
				sponsorblockApi.Value = value;
			}
		}

		public bool WriteSubs
		{
			get
			{
				return writeSubs.Value;
			}
			set
			{
				writeSubs.Value = value;
			}
		}

		public bool NoWriteSubs
		{
			get
			{
				return noWriteSubs.Value;
			}
			set
			{
				noWriteSubs.Value = value;
			}
		}

		public bool WriteAutoSubs
		{
			get
			{
				return writeAutoSubs.Value;
			}
			set
			{
				writeAutoSubs.Value = value;
			}
		}

		public bool NoWriteAutoSubs
		{
			get
			{
				return noWriteAutoSubs.Value;
			}
			set
			{
				noWriteAutoSubs.Value = value;
			}
		}

		public bool ListSubs
		{
			get
			{
				return listSubs.Value;
			}
			set
			{
				listSubs.Value = value;
			}
		}

		public string SubFormat
		{
			get
			{
				return subFormat.Value;
			}
			set
			{
				subFormat.Value = value;
			}
		}

		public string SubLangs
		{
			get
			{
				return subLangs.Value;
			}
			set
			{
				subLangs.Value = value;
			}
		}

		public bool WriteThumbnail
		{
			get
			{
				return writeThumbnail.Value;
			}
			set
			{
				writeThumbnail.Value = value;
			}
		}

		public bool NoWriteThumbnail
		{
			get
			{
				return noWriteThumbnail.Value;
			}
			set
			{
				noWriteThumbnail.Value = value;
			}
		}

		public bool WriteAllThumbnails
		{
			get
			{
				return writeAllThumbnails.Value;
			}
			set
			{
				writeAllThumbnails.Value = value;
			}
		}

		public bool ListThumbnails
		{
			get
			{
				return listThumbnails.Value;
			}
			set
			{
				listThumbnails.Value = value;
			}
		}

		public bool Quiet
		{
			get
			{
				return quiet.Value;
			}
			set
			{
				quiet.Value = value;
			}
		}

		public bool NoQuiet
		{
			get
			{
				return noQuiet.Value;
			}
			set
			{
				noQuiet.Value = value;
			}
		}

		public bool NoWarnings
		{
			get
			{
				return noWarnings.Value;
			}
			set
			{
				noWarnings.Value = value;
			}
		}

		public bool Simulate
		{
			get
			{
				return simulate.Value;
			}
			set
			{
				simulate.Value = value;
			}
		}

		public bool NoSimulate
		{
			get
			{
				return noSimulate.Value;
			}
			set
			{
				noSimulate.Value = value;
			}
		}

		public bool IgnoreNoFormatsError
		{
			get
			{
				return ignoreNoFormatsError.Value;
			}
			set
			{
				ignoreNoFormatsError.Value = value;
			}
		}

		public bool NoIgnoreNoFormatsError
		{
			get
			{
				return noIgnoreNoFormatsError.Value;
			}
			set
			{
				noIgnoreNoFormatsError.Value = value;
			}
		}

		public bool SkipDownload
		{
			get
			{
				return skipDownload.Value;
			}
			set
			{
				skipDownload.Value = value;
			}
		}

		public MultiValue<string> Print
		{
			get
			{
				return print.Value;
			}
			set
			{
				print.Value = value;
			}
		}

		public MultiValue<string> PrintToFile
		{
			get
			{
				return printToFile.Value;
			}
			set
			{
				printToFile.Value = value;
			}
		}

		public bool DumpJson
		{
			get
			{
				return dumpJson.Value;
			}
			set
			{
				dumpJson.Value = value;
			}
		}

		public bool DumpSingleJson
		{
			get
			{
				return dumpSingleJson.Value;
			}
			set
			{
				dumpSingleJson.Value = value;
			}
		}

		public bool ForceWriteArchive
		{
			get
			{
				return forceWriteArchive.Value;
			}
			set
			{
				forceWriteArchive.Value = value;
			}
		}

		public bool Newline
		{
			get
			{
				return newline.Value;
			}
			set
			{
				newline.Value = value;
			}
		}

		public bool NoProgress
		{
			get
			{
				return noProgress.Value;
			}
			set
			{
				noProgress.Value = value;
			}
		}

		public bool Progress
		{
			get
			{
				return progress.Value;
			}
			set
			{
				progress.Value = value;
			}
		}

		public bool ConsoleTitle
		{
			get
			{
				return consoleTitle.Value;
			}
			set
			{
				consoleTitle.Value = value;
			}
		}

		public string ProgressTemplate
		{
			get
			{
				return progressTemplate.Value;
			}
			set
			{
				progressTemplate.Value = value;
			}
		}

		public string ProgressDelta
		{
			get
			{
				return progressDelta.Value;
			}
			set
			{
				progressDelta.Value = value;
			}
		}

		public bool Verbose
		{
			get
			{
				return verbose.Value;
			}
			set
			{
				verbose.Value = value;
			}
		}

		public bool DumpPages
		{
			get
			{
				return dumpPages.Value;
			}
			set
			{
				dumpPages.Value = value;
			}
		}

		public bool WritePages
		{
			get
			{
				return writePages.Value;
			}
			set
			{
				writePages.Value = value;
			}
		}

		public bool PrintTraffic
		{
			get
			{
				return printTraffic.Value;
			}
			set
			{
				printTraffic.Value = value;
			}
		}

		public string Format
		{
			get
			{
				return format.Value;
			}
			set
			{
				format.Value = value;
			}
		}

		public string FormatSort
		{
			get
			{
				return formatSort.Value;
			}
			set
			{
				formatSort.Value = value;
			}
		}

		public bool FormatSortForce
		{
			get
			{
				return formatSortForce.Value;
			}
			set
			{
				formatSortForce.Value = value;
			}
		}

		public bool NoFormatSortForce
		{
			get
			{
				return noFormatSortForce.Value;
			}
			set
			{
				noFormatSortForce.Value = value;
			}
		}

		public bool VideoMultistreams
		{
			get
			{
				return videoMultistreams.Value;
			}
			set
			{
				videoMultistreams.Value = value;
			}
		}

		public bool NoVideoMultistreams
		{
			get
			{
				return noVideoMultistreams.Value;
			}
			set
			{
				noVideoMultistreams.Value = value;
			}
		}

		public bool AudioMultistreams
		{
			get
			{
				return audioMultistreams.Value;
			}
			set
			{
				audioMultistreams.Value = value;
			}
		}

		public bool NoAudioMultistreams
		{
			get
			{
				return noAudioMultistreams.Value;
			}
			set
			{
				noAudioMultistreams.Value = value;
			}
		}

		public bool PreferFreeFormats
		{
			get
			{
				return preferFreeFormats.Value;
			}
			set
			{
				preferFreeFormats.Value = value;
			}
		}

		public bool NoPreferFreeFormats
		{
			get
			{
				return noPreferFreeFormats.Value;
			}
			set
			{
				noPreferFreeFormats.Value = value;
			}
		}

		public bool CheckFormats
		{
			get
			{
				return checkFormats.Value;
			}
			set
			{
				checkFormats.Value = value;
			}
		}

		public bool CheckAllFormats
		{
			get
			{
				return checkAllFormats.Value;
			}
			set
			{
				checkAllFormats.Value = value;
			}
		}

		public bool NoCheckFormats
		{
			get
			{
				return noCheckFormats.Value;
			}
			set
			{
				noCheckFormats.Value = value;
			}
		}

		public bool ListFormats
		{
			get
			{
				return listFormats.Value;
			}
			set
			{
				listFormats.Value = value;
			}
		}

		public DownloadMergeFormat MergeOutputFormat
		{
			get
			{
				return mergeOutputFormat.Value;
			}
			set
			{
				mergeOutputFormat.Value = value;
			}
		}

		public string PlaylistItems
		{
			get
			{
				return playlistItems.Value;
			}
			set
			{
				playlistItems.Value = value;
			}
		}

		public string MinFilesize
		{
			get
			{
				return minFilesize.Value;
			}
			set
			{
				minFilesize.Value = value;
			}
		}

		public string MaxFilesize
		{
			get
			{
				return maxFilesize.Value;
			}
			set
			{
				maxFilesize.Value = value;
			}
		}

		public DateTime Date
		{
			get
			{
				return date.Value;
			}
			set
			{
				date.Value = value;
			}
		}

		public DateTime DateBefore
		{
			get
			{
				return dateBefore.Value;
			}
			set
			{
				dateBefore.Value = value;
			}
		}

		public DateTime DateAfter
		{
			get
			{
				return dateAfter.Value;
			}
			set
			{
				dateAfter.Value = value;
			}
		}

		public MultiValue<string> MatchFilters
		{
			get
			{
				return matchFilters.Value;
			}
			set
			{
				matchFilters.Value = value;
			}
		}

		public bool NoMatchFilters
		{
			get
			{
				return noMatchFilters.Value;
			}
			set
			{
				noMatchFilters.Value = value;
			}
		}

		public string BreakMatchFilters
		{
			get
			{
				return breakMatchFilters.Value;
			}
			set
			{
				breakMatchFilters.Value = value;
			}
		}

		public bool NoBreakMatchFilters
		{
			get
			{
				return noBreakMatchFilters.Value;
			}
			set
			{
				noBreakMatchFilters.Value = value;
			}
		}

		public bool NoPlaylist
		{
			get
			{
				return noPlaylist.Value;
			}
			set
			{
				noPlaylist.Value = value;
			}
		}

		public bool YesPlaylist
		{
			get
			{
				return yesPlaylist.Value;
			}
			set
			{
				yesPlaylist.Value = value;
			}
		}

		public byte? AgeLimit
		{
			get
			{
				return ageLimit.Value;
			}
			set
			{
				ageLimit.Value = value;
			}
		}

		public string DownloadArchive
		{
			get
			{
				return downloadArchive.Value;
			}
			set
			{
				downloadArchive.Value = value;
			}
		}

		public bool NoDownloadArchive
		{
			get
			{
				return noDownloadArchive.Value;
			}
			set
			{
				noDownloadArchive.Value = value;
			}
		}

		public int? MaxDownloads
		{
			get
			{
				return maxDownloads.Value;
			}
			set
			{
				maxDownloads.Value = value;
			}
		}

		public bool BreakOnExisting
		{
			get
			{
				return breakOnExisting.Value;
			}
			set
			{
				breakOnExisting.Value = value;
			}
		}

		public bool NoBreakOnExisting
		{
			get
			{
				return noBreakOnExisting.Value;
			}
			set
			{
				noBreakOnExisting.Value = value;
			}
		}

		public bool BreakPerInput
		{
			get
			{
				return breakPerInput.Value;
			}
			set
			{
				breakPerInput.Value = value;
			}
		}

		public bool NoBreakPerInput
		{
			get
			{
				return noBreakPerInput.Value;
			}
			set
			{
				noBreakPerInput.Value = value;
			}
		}

		public int? SkipPlaylistAfterErrors
		{
			get
			{
				return skipPlaylistAfterErrors.Value;
			}
			set
			{
				skipPlaylistAfterErrors.Value = value;
			}
		}

		public string Encoding
		{
			get
			{
				return encoding.Value;
			}
			set
			{
				encoding.Value = value;
			}
		}

		public bool LegacyServerConnect
		{
			get
			{
				return legacyServerConnect.Value;
			}
			set
			{
				legacyServerConnect.Value = value;
			}
		}

		public bool NoCheckCertificates
		{
			get
			{
				return noCheckCertificates.Value;
			}
			set
			{
				noCheckCertificates.Value = value;
			}
		}

		public bool PreferInsecure
		{
			get
			{
				return preferInsecure.Value;
			}
			set
			{
				preferInsecure.Value = value;
			}
		}

		public MultiValue<string> AddHeaders
		{
			get
			{
				return addHeaders.Value;
			}
			set
			{
				addHeaders.Value = value;
			}
		}

		public bool BidiWorkaround
		{
			get
			{
				return bidiWorkaround.Value;
			}
			set
			{
				bidiWorkaround.Value = value;
			}
		}

		public int? SleepRequests
		{
			get
			{
				return sleepRequests.Value;
			}
			set
			{
				sleepRequests.Value = value;
			}
		}

		public int? SleepInterval
		{
			get
			{
				return sleepInterval.Value;
			}
			set
			{
				sleepInterval.Value = value;
			}
		}

		public int? MaxSleepInterval
		{
			get
			{
				return maxSleepInterval.Value;
			}
			set
			{
				maxSleepInterval.Value = value;
			}
		}

		public int? SleepSubtitles
		{
			get
			{
				return sleepSubtitles.Value;
			}
			set
			{
				sleepSubtitles.Value = value;
			}
		}

		public void WriteConfigFile(string path)
		{
			File.WriteAllLines(path, GetOptionFlags());
		}

		public override string ToString()
		{
			return " " + string.Join(" ", GetOptionFlags());
		}

		public IEnumerable<string> GetOptionFlags()
		{
			return from value in GetKnownOptions().Concat(CustomOptions).SelectMany((IOption opt) => opt.ToStringCollection())
				where !string.IsNullOrWhiteSpace(value)
				select value;
		}

		internal IEnumerable<IOption> GetKnownOptions()
		{
			return (from p in GetType().GetRuntimeFields()
				where p.FieldType.IsGenericType && p.FieldType.GetInterfaces().Contains<Type>(typeof(IOption))
				select p.GetValue(this)).Cast<IOption>();
		}

		public OptionSet OverrideOptions(OptionSet overrideOptions, bool forceOverride = false)
		{
			OptionSet optionSet = (OptionSet)Clone();
			optionSet.CustomOptions = optionSet.CustomOptions.Concat(overrideOptions.CustomOptions).Distinct(Comparer).ToArray();
			foreach (FieldInfo item in from p in overrideOptions.GetType().GetRuntimeFields()
				where p.FieldType.IsGenericType && p.FieldType.GetInterfaces().Contains<Type>(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)