Decompiled source of YPlayBoombox v2.3.1

plugins\YPlay.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using DamienG.Security.Cryptography;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using YPlay.NetcodePatcher;
using YPlay.controller;
using YPlay.cruiser;
using YPlayUtil;
using YPlayUtil.Helpers;
using YPlayUtil.Metadata;
using YPlayUtil.Options;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("YPlay")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("YPlay")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("a9e02c48-30aa-4cf0-bbce-b71de7f55747")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
internal class <Module>
{
	static <Module>()
	{
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace DamienG.Security.Cryptography
{
	public sealed class Crc32 : HashAlgorithm
	{
		public const uint DefaultPolynomial = 3988292384u;

		public const uint DefaultSeed = uint.MaxValue;

		private static uint[] defaultTable;

		private readonly uint seed;

		private readonly uint[] table;

		private uint hash;

		public override int HashSize => 32;

		public Crc32()
			: this(3988292384u, uint.MaxValue)
		{
		}

		public Crc32(uint polynomial, uint seed)
		{
			if (!BitConverter.IsLittleEndian)
			{
				throw new PlatformNotSupportedException("Not supported on Big Endian processors");
			}
			table = InitializeTable(polynomial);
			this.seed = (hash = seed);
		}

		public override void Initialize()
		{
			hash = seed;
		}

		protected override void HashCore(byte[] array, int ibStart, int cbSize)
		{
			hash = CalculateHash(table, hash, array, ibStart, cbSize);
		}

		protected override byte[] HashFinal()
		{
			return HashValue = UInt32ToBigEndianBytes(~hash);
		}

		public static uint Compute(byte[] buffer)
		{
			return Compute(uint.MaxValue, buffer);
		}

		public static uint Compute(uint seed, byte[] buffer)
		{
			return Compute(3988292384u, seed, buffer);
		}

		public static uint Compute(uint polynomial, uint seed, byte[] buffer)
		{
			return ~CalculateHash(InitializeTable(polynomial), seed, buffer, 0, buffer.Length);
		}

		private static uint[] InitializeTable(uint polynomial)
		{
			if (polynomial == 3988292384u && defaultTable != null)
			{
				return defaultTable;
			}
			uint[] array = new uint[256];
			for (int i = 0; i < 256; i++)
			{
				uint num = (uint)i;
				for (int j = 0; j < 8; j++)
				{
					num = (((num & 1) != 1) ? (num >> 1) : ((num >> 1) ^ polynomial));
				}
				array[i] = num;
			}
			if (polynomial == 3988292384u)
			{
				defaultTable = array;
			}
			return array;
		}

		private static uint CalculateHash(uint[] table, uint seed, IList<byte> buffer, int start, int size)
		{
			uint num = seed;
			for (int i = start; i < start + size; i++)
			{
				num = (num >> 8) ^ table[buffer[i] ^ (num & 0xFF)];
			}
			return num;
		}

		private static byte[] UInt32ToBigEndianBytes(uint uint32)
		{
			byte[] bytes = BitConverter.GetBytes(uint32);
			if (BitConverter.IsLittleEndian)
			{
				Array.Reverse((Array)bytes);
			}
			return bytes;
		}
	}
}
namespace YPlay
{
	internal class AudioLoader : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <GetAudioClip>d__4 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public string path;

			public bool resync;

			public Controller controller;

			public int requestId;

			private string <filenameId>5__2;

			private bool <success>5__3;

			private AudioClip <audioClip>5__4;

			private UnityWebRequest <unityWebRequest>5__5;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <GetAudioClip>d__4(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 2)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<filenameId>5__2 = null;
				<audioClip>5__4 = null;
				<unityWebRequest>5__5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_017b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0181: Invalid comparison between Unknown and I4
				//IL_0111: Unknown result type (might be due to invalid IL or missing references)
				//IL_0116: Unknown result type (might be due to invalid IL or missing references)
				//IL_011f: Unknown result type (might be due to invalid IL or missing references)
				//IL_013e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0143: Unknown result type (might be due to invalid IL or missing references)
				//IL_0147: Invalid comparison between Unknown and I4
				try
				{
					bool flag;
					bool flag2;
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<filenameId>5__2 = Path.GetFileNameWithoutExtension(path);
						flag = false;
						<success>5__3 = false;
						if (FilenameIdAudioClips.ContainsKey(<filenameId>5__2))
						{
							<audioClip>5__4 = FilenameIdAudioClips[<filenameId>5__2];
							if (AudioClipLoadedInMemory(<audioClip>5__4))
							{
								<>2__current = null;
								<>1__state = 1;
								return true;
							}
							FilenameIdAudioClips.Remove(<filenameId>5__2);
							goto IL_00bf;
						}
						goto IL_00c6;
					case 1:
						<>1__state = -1;
						SetAudio(<filenameId>5__2, <audioClip>5__4);
						flag = true;
						<success>5__3 = true;
						goto IL_00bf;
					case 2:
						{
							<>1__state = -3;
							if ((int)<unityWebRequest>5__5.result == 1)
							{
								AudioClip content = DownloadHandlerAudioClip.GetContent(<unityWebRequest>5__5);
								if (AudioClipLoadedInMemory(content))
								{
									((Object)content).name = (AudioDownloader.AudioIdTitles.ContainsKey(<filenameId>5__2) ? AudioDownloader.AudioIdTitles[<filenameId>5__2] : null);
									SetAudio(<filenameId>5__2, content);
									<success>5__3 = true;
								}
							}
							<>m__Finally1();
							<unityWebRequest>5__5 = null;
							break;
						}
						IL_00c6:
						flag2 = AudioDownloader.IsFilenameIdDownloaded(<filenameId>5__2);
						if (!flag && flag2)
						{
							if (FilenameIdsDownloaded.Contains(<filenameId>5__2))
							{
								FilenameIdsDownloaded.Remove(<filenameId>5__2);
							}
							FilenameIdsDownloaded.Insert(0, <filenameId>5__2);
							AudioType audioType = AudioDownloader.AudioType;
							<unityWebRequest>5__5 = UnityWebRequestMultimedia.GetAudioClip(path, audioType);
							<>1__state = -3;
							((DownloadHandlerAudioClip)<unityWebRequest>5__5.downloadHandler).streamAudio = (int)audioType == 13;
							<>2__current = <unityWebRequest>5__5.SendWebRequest();
							<>1__state = 2;
							return true;
						}
						break;
						IL_00bf:
						<audioClip>5__4 = null;
						goto IL_00c6;
					}
					if (!<success>5__3)
					{
						string text = "Error " + (resync ? "resyncing" : "loading") + " request " + AudioDownloader.GetFilenameIdString(<filenameId>5__2);
						YPlay.LogWarning(text);
						Patch.AddChatMessage(text);
					}
					controller.SendLoadedServerDelegate(requestId, <success>5__3, resync);
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<unityWebRequest>5__5 != null)
				{
					((IDisposable)<unityWebRequest>5__5).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		internal static readonly Dictionary<string, AudioClip> FilenameIdAudioClips = new Dictionary<string, AudioClip>();

		internal static readonly List<string> FilenameIdsDownloaded = new List<string>();

		private static AudioLoader Instance;

		internal void Start(IEnumerator routine)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = new GameObject(typeof(AudioLoader).Name).AddComponent<AudioLoader>();
				Object.DontDestroyOnLoad((Object)(object)Instance);
			}
			((MonoBehaviour)Instance).StartCoroutine(routine);
		}

		[IteratorStateMachine(typeof(<GetAudioClip>d__4))]
		internal IEnumerator GetAudioClip(Controller controller, int requestId, string path, bool resync)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <GetAudioClip>d__4(0)
			{
				controller = controller,
				requestId = requestId,
				path = path,
				resync = resync
			};
		}

		internal static void UnloadAudioClips()
		{
			foreach (KeyValuePair<string, AudioClip> item in new Dictionary<string, AudioClip>(FilenameIdAudioClips))
			{
				AudioClip value = item.Value;
				string key = item.Key;
				value.UnloadAudioData();
				FilenameIdAudioClips.Remove(key);
			}
		}

		private static bool AudioClipLoadedInMemory(AudioClip audioClip)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			if (Object.op_Implicit((Object)(object)audioClip) && audioClip.LoadAudioData())
			{
				return (int)audioClip.loadState == 2;
			}
			return false;
		}

		private static void SetAudio(string filenameId, AudioClip audioClip)
		{
			FilenameIdAudioClips[filenameId] = audioClip;
			Patch.AddChatMessage("Loaded " + AudioDownloader.GetFilenameIdString(filenameId));
		}
	}
	internal class AudioDownloader
	{
		[CompilerGenerated]
		private Controller <controller>P;

		internal static bool CanChangeSync = Patch.IsHost;

		internal static HashSet<string> FilenameIdsResyncing = new HashSet<string>();

		internal static readonly Dictionary<string, string> AudioIdTitles = new Dictionary<string, string>();

		private static readonly Dictionary<string, int> AudioIdDurations = new Dictionary<string, int>();

		internal int lastDownloadRequestId;

		internal string lastDownloadRequestFilenameId;

		private readonly AudioLoader audioLoader;

		private AudioAction audioAction;

		internal static AudioType AudioType = (AudioType)13;

		internal static readonly OptionSet OverrideOptions;

		public AudioDownloader(Controller controller)
		{
			<controller>P = controller;
			lastDownloadRequestId = -1;
			audioLoader = new AudioLoader();
			base..ctor();
		}

		internal async void DownloadTask(int requestId, string filenameId, string title, int duration, string url, float time, bool resync = false)
		{
			if (CanChangeSync)
			{
				CanChangeSync = false;
			}
			if (string.IsNullOrEmpty(filenameId?.Trim()) || string.IsNullOrEmpty(title?.Trim()) || string.IsNullOrEmpty(url?.Trim()))
			{
				Patch.AddChatMessage("Invalid " + (resync ? "resync" : "download") + " request");
				return;
			}
			if (resync)
			{
				FilenameIdsResyncing.Add(filenameId);
			}
			lastDownloadRequestId = requestId;
			lastDownloadRequestFilenameId = filenameId;
			time = Mathf.Max(time, 0f);
			REQUEST_STATUS requestStatusError = REQUEST_STATUS.NONE;
			string error = null;
			AudioIdTitles[filenameId] = title;
			AudioIdDurations[filenameId] = duration;
			string filenameIdString = GetFilenameIdString(filenameId);
			await Task.Run(delegate
			{
				string outputFileLocationForId = GetOutputFileLocationForId(filenameId);
				CancelCurrentProcess();
				if (IsFilenameLoaded(filenameId))
				{
					requestStatusError = LoadFile(filenameId, outputFileLocationForId, requestId, resync);
				}
				else if (!YPlay.IsYPlayUtilValid())
				{
					requestStatusError = REQUEST_STATUS.ERROR_UTIL_MISSING_DEPENDENCY;
					error = "Missing dependency, please try reinstalling YPlayBoombox";
				}
				else if (YPlay.IsDownloadingTools())
				{
					requestStatusError = REQUEST_STATUS.ERROR_UTIL_DOWNLOADING_TOOLS;
					error = "Downloading tools...";
				}
				else if (!YPlay.IsToolsExistAndNonEmpty())
				{
					requestStatusError = REQUEST_STATUS.ERROR_INVALID_TOOLS;
					error = "Invalid tools, please try /yp reset-tools";
				}
				else
				{
					audioAction = new AudioAction(this, requestId, filenameId, outputFileLocationForId, url);
					requestStatusError = audioAction.Start(resync);
					switch (requestStatusError)
					{
					case REQUEST_STATUS.ERROR_CLIENT_DOWNLOAD:
						error = "Error downloading request " + filenameIdString;
						break;
					case REQUEST_STATUS.ERROR_CLIENT_DOWNLOAD_EXCEPTION:
						error = "Error downloading request (exception) " + filenameIdString;
						break;
					case REQUEST_STATUS.ERROR_CLIENT_LOAD:
						error = "Error loading request " + filenameIdString;
						break;
					case REQUEST_STATUS.ERROR_METADATA_AGE_RESTRICTED:
						error = "Error downloading request (no access - age restricted) " + filenameIdString;
						break;
					case REQUEST_STATUS.ERROR_METADATA_BOT:
						error = "Error downloading request (no access - bot) " + filenameIdString;
						break;
					case REQUEST_STATUS.ERROR_METADATA_SIGN_IN:
						error = "Error downloading request (no access) " + filenameIdString;
						break;
					case REQUEST_STATUS.ERROR_METADATA_VIDEO_UNAVAILABLE:
						error = "Error downloading request (video unavailable) " + filenameIdString;
						break;
					}
				}
			});
			if (requestStatusError != 0)
			{
				<controller>P.SendLoadedServerDelegate(requestId, loaded: false, resync, requestStatusError);
				if (string.IsNullOrEmpty(error))
				{
					error = "Error downloading request " + filenameIdString;
				}
				YPlay.LogError(error);
				Patch.AddChatMessage(error);
			}
			FilenameIdsResyncing.Remove(filenameId);
		}

		internal void CancelCurrentProcess()
		{
			if (audioAction != null && audioAction.actionState == ACTION_STATE.PROCESSING)
			{
				audioAction.KillProcess();
				Patch.AddChatMessage("Previous process canceled " + GetFilenameIdString(audioAction.filenameId));
			}
		}

		internal void KillRequestId(int requestId)
		{
			if (audioAction != null && audioAction.requestId == requestId)
			{
				CancelCurrentProcess();
			}
		}

		internal async Task DownloadMetadata(RequestMetadata requestMetadata, string url, string filenameId, float time)
		{
			await Task.Run(delegate
			{
				REQUEST_STATUS rEQUEST_STATUS = REQUEST_STATUS.NONE;
				if (string.IsNullOrEmpty(url?.Trim()) || string.IsNullOrEmpty(filenameId?.Trim()))
				{
					rEQUEST_STATUS = REQUEST_STATUS.ERROR_METADATA;
				}
				else if (!YPlay.IsYPlayUtilValid())
				{
					rEQUEST_STATUS = REQUEST_STATUS.ERROR_UTIL_MISSING_DEPENDENCY;
				}
				else if (YPlay.IsDownloadingTools())
				{
					rEQUEST_STATUS = REQUEST_STATUS.ERROR_UTIL_DOWNLOADING_TOOLS;
				}
				else if (!YPlay.IsToolsExistAndNonEmpty())
				{
					rEQUEST_STATUS = REQUEST_STATUS.ERROR_INVALID_TOOLS;
				}
				if (rEQUEST_STATUS != 0)
				{
					requestMetadata.requestStatus = rEQUEST_STATUS;
				}
				else
				{
					string text = (AudioIdTitles.ContainsKey(filenameId) ? AudioIdTitles[filenameId] : null);
					int num = (AudioIdDurations.ContainsKey(filenameId) ? AudioIdDurations[filenameId] : 0);
					if (!IsMetadataLoadedForFilenameId(filenameId))
					{
						REQUEST_STATUS rEQUEST_STATUS2;
						(text, num, rEQUEST_STATUS2) = GetAudioTitleDuration(url);
						if (rEQUEST_STATUS2 != 0)
						{
							requestMetadata.requestStatus = rEQUEST_STATUS2;
							return;
						}
						if (string.IsNullOrEmpty(text?.Trim()) || num == 0)
						{
							requestMetadata.requestStatus = REQUEST_STATUS.ERROR_METADATA;
							return;
						}
						AudioIdTitles[filenameId] = text;
						AudioIdDurations[filenameId] = num;
					}
					int num2 = num / 60;
					if (num2 > 12)
					{
						requestMetadata.requestStatus = REQUEST_STATUS.ERROR_METADATA_MAX_DURATION;
					}
					else if (string.IsNullOrEmpty(text?.Trim()) || num == 0)
					{
						requestMetadata.requestStatus = REQUEST_STATUS.ERROR_METADATA;
					}
					else
					{
						requestMetadata.filenameId = filenameId;
						requestMetadata.url = url;
						requestMetadata.time = time;
						requestMetadata.title = text;
						requestMetadata.duration = num;
						if (requestMetadata.requestStatus != REQUEST_STATUS.REQUEST_CANCELED)
						{
							requestMetadata.requestStatus = REQUEST_STATUS.REQUEST_VALID;
						}
					}
				}
			});
		}

		private (string title, int duration, REQUEST_STATUS requestStatus) GetAudioTitleDuration(string url)
		{
			YoutubeDL val = YPlay.NewYoutubeDl();
			string text = "";
			int item = 0;
			REQUEST_STATUS rEQUEST_STATUS = REQUEST_STATUS.NONE;
			try
			{
				OptionSet overrideOptions = OverrideOptions;
				RunResult<VideoData> result = val.RunVideoDataFetch(url, default(CancellationToken), true, false, overrideOptions).GetAwaiter().GetResult();
				if (result != null)
				{
					string[] errorOutput = result.ErrorOutput;
					if (errorOutput != null && errorOutput.Length != 0)
					{
						string[] errorOutput2 = result.ErrorOutput;
						foreach (string text2 in errorOutput2)
						{
							YPlay.LogError("[yt-dlp] " + text2);
							rEQUEST_STATUS = GetRequestStatusDownloadError(text2);
							if (rEQUEST_STATUS != 0)
							{
								break;
							}
						}
						if (rEQUEST_STATUS == REQUEST_STATUS.NONE)
						{
							Patch.AddChatMessage("Metadata error, please check the console");
							rEQUEST_STATUS = REQUEST_STATUS.ERROR_METADATA;
						}
					}
					else
					{
						VideoData data = result.Data;
						text = data.Title;
						item = (int)data.Duration.GetValueOrDefault();
					}
				}
			}
			catch (Exception ex)
			{
				REQUEST_STATUS item2;
				if (Patch.StringContainsLowerCase(ex.Message, "canceled"))
				{
					item2 = REQUEST_STATUS.REQUEST_CANCELED;
				}
				else
				{
					YPlay.LogError("[yt-dlp] " + ex.Message);
					Patch.AddChatMessage("Metadata exception, please check the console");
					item2 = REQUEST_STATUS.ERROR_METADATA_EXCEPTION;
				}
				return ("", 0, item2);
			}
			if (string.IsNullOrEmpty(text?.Trim()))
			{
				text = GetFilenameIdFromUrl(url);
			}
			return (text, item, rEQUEST_STATUS);
		}

		internal REQUEST_STATUS LoadFile(string filenameId, string outputFileLocation, int requestId, bool resync)
		{
			if (IsFilenameLoaded(filenameId))
			{
				audioLoader.Start(audioLoader.GetAudioClip(<controller>P, requestId, outputFileLocation, resync));
				return REQUEST_STATUS.NONE;
			}
			return REQUEST_STATUS.ERROR_CLIENT_LOAD;
		}

		private bool IsFilenameLoaded(string filenameId)
		{
			if (!string.IsNullOrEmpty(filenameId?.Trim()))
			{
				if (!IsFilenameIdDownloaded(filenameId))
				{
					return AudioLoader.FilenameIdAudioClips.ContainsKey(filenameId);
				}
				return true;
			}
			return false;
		}

		internal static bool IsFilenameIdDownloaded(string filenameId)
		{
			if (!string.IsNullOrEmpty(filenameId?.Trim()))
			{
				return IsFileValid(GetOutputFileLocationForId(filenameId));
			}
			return false;
		}

		internal static bool IsFileValid(string path)
		{
			if (File.Exists(path))
			{
				return new FileInfo(path).Length > 0;
			}
			return false;
		}

		internal static bool IsMetadataLoadedForFilenameId(string filenameId)
		{
			if (!string.IsNullOrEmpty(filenameId?.Trim()) && AudioIdTitles.ContainsKey(filenameId))
			{
				return AudioIdDurations.ContainsKey(filenameId);
			}
			return false;
		}

		internal static string GetFilenameIdFromUrl(string url)
		{
			if (string.IsNullOrEmpty(url?.Trim()))
			{
				return null;
			}
			url = url.Replace("https://", "").Replace("http://", "").Replace("www.", "");
			string text = null;
			int num = url.IndexOf("?v=", StringComparison.OrdinalIgnoreCase);
			int num2 = url.IndexOf("&v=", StringComparison.OrdinalIgnoreCase);
			int num3 = url.IndexOf("/shorts/", StringComparison.OrdinalIgnoreCase);
			int num4 = url.IndexOf("/", StringComparison.OrdinalIgnoreCase);
			if (num > -1)
			{
				text = url.Substring(num + "?v=".Length);
			}
			else if (num2 > -1)
			{
				text = url.Substring(num2 + "&v=".Length);
			}
			else if (num3 > -1)
			{
				text = url.Substring(num3 + "/shorts/".Length);
			}
			else if (num4 > -1)
			{
				text = url.Substring(num4 + "/".Length);
			}
			if (!string.IsNullOrEmpty(text?.Trim()))
			{
				int num5 = text.IndexOf("&", StringComparison.OrdinalIgnoreCase);
				if (num5 > -1)
				{
					text = text.Substring(0, num5);
				}
				int num6 = text.IndexOf("?", StringComparison.OrdinalIgnoreCase);
				if (num6 > -1)
				{
					text = text.Substring(0, num6);
				}
			}
			if (text == null)
			{
				return null;
			}
			string text2 = text.Trim();
			if (text2.Length == 11)
			{
				return text2;
			}
			return null;
		}

		internal static void KillAllBoomboxDownloaderProcesses()
		{
			foreach (KeyValuePair<ulong, BoomboxController> item in new Dictionary<ulong, BoomboxController>(BoomboxController.BoomboxControllers))
			{
				BoomboxController value = item.Value;
				value.audioDownloader.CancelCurrentProcess();
			}
		}

		internal static string GetOutputFileLocationWithoutExtensionForId(string id)
		{
			return YPlay.AudioDirectory + "\\" + id;
		}

		internal static string GetOutputFileLocationTempForId(string id)
		{
			return GetOutputFileLocationWithoutExtensionForId(id) + ".part";
		}

		internal static string GetOutputFileLocationForId(string id)
		{
			return GetOutputFileLocationWithoutExtensionForId(id) + "." + GetFileExtension();
		}

		internal static string GetFilenameIdString(string filenameId)
		{
			if (string.IsNullOrEmpty(filenameId?.Trim()))
			{
				return null;
			}
			return "[" + filenameId + "]";
		}

		internal static string GetFileExtension()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)AudioType != 20)
			{
				return "mp3";
			}
			return "wav";
		}

		internal static REQUEST_STATUS GetRequestStatusDownloadError(string s)
		{
			if (s != null)
			{
				if (Patch.StringContainsLowerCase(s, "sign in"))
				{
					if (Patch.StringContainsLowerCase(s, "age"))
					{
						return REQUEST_STATUS.ERROR_METADATA_AGE_RESTRICTED;
					}
					if (Patch.StringContainsLowerCase(s, "bot"))
					{
						return REQUEST_STATUS.ERROR_METADATA_BOT;
					}
					return REQUEST_STATUS.ERROR_METADATA_SIGN_IN;
				}
				if (Patch.StringContainsLowerCase(s, "video unavailable"))
				{
					return REQUEST_STATUS.ERROR_METADATA_VIDEO_UNAVAILABLE;
				}
			}
			return REQUEST_STATUS.NONE;
		}

		static AudioDownloader()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			OptionSet val = new OptionSet();
			val.FfmpegLocation = YPlay.FfmpegLocation;
			val.NoPlaylist = true;
			val.ForceIPv4 = true;
			val.NoRestrictFilenames = true;
			val.WindowsFilenames = true;
			val.Format = "140";
			val.PostprocessorArgs = MultiValue<string>.op_Implicit(new string[1] { "ffmpeg:-filter:a dynaudnorm" });
			OverrideOptions = val;
		}
	}
	internal class AudioAction
	{
		internal ACTION_STATE actionState;

		private readonly AudioDownloader audioDownloader;

		internal int requestId;

		internal string filenameId;

		private readonly string outputFileLocation;

		private readonly string url;

		private readonly string tmpFile;

		private readonly string tmpFileWithExt;

		private readonly YoutubeDL youtubeDL;

		private readonly CancellationTokenSource cancellationTokenSource;

		internal AudioAction(AudioDownloader audioDownloader, int requestId, string filenameId, string outputFileLocation, string url)
		{
			this.audioDownloader = audioDownloader;
			this.requestId = requestId;
			this.filenameId = filenameId;
			this.outputFileLocation = outputFileLocation;
			this.url = url;
			tmpFile = YPlay.GetRandomTempFileLocation();
			tmpFileWithExt = tmpFile + "." + AudioDownloader.GetFileExtension();
			youtubeDL = YPlay.NewYoutubeDl();
			youtubeDL.OutputFileTemplate = tmpFile;
			cancellationTokenSource = new CancellationTokenSource();
		}

		internal REQUEST_STATUS Start(bool resync)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Invalid comparison between Unknown and I4
			if (resync)
			{
				Patch.AddChatMessage("Resyncing...");
			}
			Patch.AddChatMessage("Downloading " + AudioDownloader.GetFilenameIdString(filenameId) + "...");
			REQUEST_STATUS requestStatusError = REQUEST_STATUS.NONE;
			bool progressError = false;
			Progress<DownloadProgress> progress = new Progress<DownloadProgress>(delegate(DownloadProgress p)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Invalid comparison between Unknown and I4
				if ((int)p.State == 4 && p.Data != null && p.Data.Contains("ERROR") && !p.Data.Contains("Error opening output files") && !p.Data.Contains("Function not implemented"))
				{
					if (requestStatusError == REQUEST_STATUS.NONE)
					{
						requestStatusError = AudioDownloader.GetRequestStatusDownloadError(p.Data);
					}
					YPlay.LogError("[yt-dlp] " + p.Data);
					progressError = true;
				}
			});
			if (progressError)
			{
				Patch.AddChatMessage("Download error, please check the console");
			}
			try
			{
				RunResult<string> result = youtubeDL.RunAudioDownload(url, (AudioConversionFormat)(((int)AudioDownloader.AudioType == 20) ? 7 : 3), cancellationTokenSource.Token, (IProgress<DownloadProgress>)progress, (IProgress<string>)null, AudioDownloader.OverrideOptions).GetAwaiter().GetResult();
			}
			catch (Exception ex)
			{
				if (Patch.StringContainsLowerCase(ex.Message, "canceled"))
				{
					requestStatusError = REQUEST_STATUS.ERROR_CLIENT_DOWNLOAD_CANCELED;
				}
				else
				{
					YPlay.LogError("[yt-dlp] " + ex.Message);
					Patch.AddChatMessage("Download exception, please check the console");
					requestStatusError = REQUEST_STATUS.ERROR_CLIENT_DOWNLOAD_EXCEPTION;
				}
			}
			bool flag = actionState == ACTION_STATE.PROCESSING && audioDownloader.lastDownloadRequestId == requestId;
			if (flag && requestStatusError != 0)
			{
				KillProcess();
				DeleteRequestFiles();
				return requestStatusError;
			}
			try
			{
				if (flag)
				{
					if (!File.Exists(outputFileLocation))
					{
						if (!AudioDownloader.IsFileValid(tmpFileWithExt))
						{
							throw new Exception("Invalid temp file");
						}
						YPlay.CreateParentDirectory(outputFileLocation);
						File.Move(tmpFileWithExt, outputFileLocation);
					}
					actionState = ACTION_STATE.FINISHED;
					return audioDownloader.LoadFile(filenameId, outputFileLocation, requestId, resync);
				}
			}
			catch (Exception ex2)
			{
				YPlay.LogError(ex2.Message);
				KillProcess();
				return REQUEST_STATUS.ERROR_CLIENT_DOWNLOAD;
			}
			finally
			{
				DeleteRequestFiles();
			}
			return REQUEST_STATUS.NONE;
		}

		internal void KillProcess()
		{
			if (actionState == ACTION_STATE.PROCESSING)
			{
				actionState = ACTION_STATE.KILLED;
				try
				{
					cancellationTokenSource?.Cancel();
				}
				catch (Exception)
				{
				}
			}
			DeleteRequestFiles();
		}

		private void DeleteRequestFiles()
		{
			Task.Delay(3000).ContinueWith(delegate
			{
				YPlay.DeleteFile(tmpFile);
				YPlay.DeleteFile(tmpFileWithExt);
			});
		}
	}
	internal class BoomboxController : Controller
	{
		[CompilerGenerated]
		private sealed class <ColorPatternRainbow>d__32 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public BoomboxController <>4__this;

			private Color <color>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ColorPatternRainbow>d__32(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				//IL_007d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0087: Expected O, but got Unknown
				int num = <>1__state;
				BoomboxController boomboxController = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					boomboxController.colorPattern = COLOR_PATTERN.RAINBOW;
					<color>5__2 = boomboxController.GetBoomboxBodyColor();
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (boomboxController.colorPattern == COLOR_PATTERN.RAINBOW && boomboxController.IsItemActive())
				{
					<color>5__2 = ColorShift(<color>5__2, 0.2f * Time.deltaTime);
					boomboxController.ChangeBoomboxColor(<color>5__2.r, <color>5__2.g, <color>5__2.b);
					<>2__current = (object)new WaitForSeconds(0.05f);
					<>1__state = 1;
					return true;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <ColorPatternRandomLoop>d__31 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public BoomboxController <>4__this;

			public ulong clientId;

			private bool <msg>5__2;

			private int <i>5__3;

			private bool <randomTextColorsSent>5__4;

			private string <colorPatternString>5__5;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ColorPatternRandomLoop>d__31(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<colorPatternString>5__5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
				//IL_0130: Unknown result type (might be due to invalid IL or missing references)
				//IL_013a: Expected O, but got Unknown
				//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				BoomboxController boomboxController = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					boomboxController.colorPattern = COLOR_PATTERN.RANDOM_LOOP;
					<msg>5__2 = true;
					<i>5__3 = 0;
					<randomTextColorsSent>5__4 = false;
					boomboxController.colorPatternRandomTextColors = new List<Color>();
					string text = "RANDOM";
					foreach (char c in text)
					{
						boomboxController.colorPatternRandomTextColors.Add(GetRandomBoomboxColor());
					}
					<colorPatternString>5__5 = boomboxController.GetColorPatternString(boomboxController.colorPattern);
					break;
				}
				case 1:
					<>1__state = -1;
					break;
				}
				if (boomboxController.colorPattern == COLOR_PATTERN.RANDOM_LOOP && boomboxController.IsItemActive())
				{
					if (!<randomTextColorsSent>5__4 && boomboxController.colorPatternRandomTextColors.Count > 0)
					{
						boomboxController.SyncBoomboxColor(boomboxController.colorPatternRandomTextColors[<i>5__3++], boomboxController.colorPattern, <colorPatternString>5__5, clientId, <msg>5__2);
						if (<i>5__3 >= boomboxController.colorPatternRandomTextColors.Count)
						{
							<randomTextColorsSent>5__4 = true;
						}
					}
					else
					{
						boomboxController.SyncBoomboxColor(GetRandomBoomboxColor(), boomboxController.colorPattern, <colorPatternString>5__5, clientId);
					}
					<colorPatternString>5__5 = null;
					<msg>5__2 = false;
					<>2__current = (object)new WaitForSeconds(1f);
					<>1__state = 1;
					return true;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		internal static readonly Dictionary<ulong, BoomboxController> BoomboxControllers = new Dictionary<ulong, BoomboxController>();

		internal BoomboxItem boomboxItem;

		private COLOR_PATTERN colorPattern;

		private IEnumerator colorPatternCoroutine;

		private const string colorPatternRandomText = "RANDOM";

		private List<Color> colorPatternRandomTextColors = new List<Color>();

		private readonly Dictionary<string, string> colorPatternRainbowDict = new Dictionary<string, string>
		{
			{ "R", "red" },
			{ "A", "orange" },
			{ "I", "yellow" },
			{ "N", "green" },
			{ "B", "lightblue" },
			{ "O", "mediumpurple" },
			{ "W", "violet" }
		};

		internal override void Awake()
		{
			base.Awake();
			boomboxItem = ((Component)this).GetComponent<BoomboxItem>();
			((GrabbableObject)boomboxItem).itemProperties.requiresBattery = false;
			if (Patch.MuteAlways)
			{
				boomboxItem.boomboxAudio.mute = true;
			}
		}

		internal void Start()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			BoomboxControllers[((NetworkBehaviour)this).NetworkObjectId] = this;
			if (Config.BoomboxRandomColor && IsHostOrIsOffline())
			{
				SyncBoomboxColor(GetRandomBoomboxColor(), colorPattern, GetColorPatternString(colorPattern), ((NetworkBehaviour)this).NetworkManager.LocalClientId);
			}
		}

		internal void SyncBoomboxColorRequestServerDelegate(float r, float g, float b, COLOR_PATTERN colorPattern = COLOR_PATTERN.NONE)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if (Patch.IsOffline())
			{
				if (!ApplyColorPattern(colorPattern, ((NetworkBehaviour)this).NetworkManager.LocalClientId))
				{
					SyncBoomboxColorRequestClientShared(r, g, b, colorPattern, null, ((NetworkBehaviour)this).NetworkManager.LocalClientId, msg: true);
				}
			}
			else
			{
				SyncBoomboxColorRequestServerRpc(r, g, b, colorPattern);
			}
		}

		private void SyncBoomboxColor(Color color, COLOR_PATTERN colorPattern, string colorPatternString, ulong clientId, bool msg = false)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (((NetworkBehaviour)this).IsHost)
			{
				SyncBoomboxColorRequestClientRpc(color.r, color.g, color.b, colorPattern, colorPatternString, clientId, msg);
			}
			else
			{
				SyncBoomboxColorRequestClientShared(color.r, color.g, color.b, colorPattern, colorPatternString, clientId, msg);
			}
		}

		[ServerRpc(RequireOwnership = false)]
		internal void SyncAllRequestServerRpc(ulong clientId)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				ServerRpcParams val = default(ServerRpcParams);
				FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendServerRpc(4064489894u, val, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val2, clientId);
				((NetworkBehaviour)this).__endSendServerRpc(ref val2, 4064489894u, val, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost) && !IsInvalidServerCall())
			{
				Request request = GetRequest(((NetworkBehaviour)this).NetworkObjectId);
				if (request != null)
				{
					ClientRpcParams clientRpcParamsForClient = Controller.GetClientRpcParamsForClient(clientId);
					SyncVolumeRequestClientRpc(request.volume, 0uL, msg: false, clientRpcParamsForClient);
					Color boomboxBodyColor = GetBoomboxBodyColor();
					SyncBoomboxColorRequestClientRpc(boomboxBodyColor.r, boomboxBodyColor.g, boomboxBodyColor.b, colorPattern, null, 0uL, msg: false, clientRpcParamsForClient);
					SyncRequestVerifyClientCall(request, clientRpcParamsForClient);
				}
			}
		}

		[ServerRpc(RequireOwnership = false)]
		private void SyncBoomboxColorRequestServerRpc(float r, float g, float b, COLOR_PATTERN colorPattern, ServerRpcParams serverRpcParams = default(ServerRpcParams))
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(2959672043u, serverRpcParams, (RpcDelivery)0);
				((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref r, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref g, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref b, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe<COLOR_PATTERN>(ref colorPattern, default(ForEnums));
				((NetworkBehaviour)this).__endSendServerRpc(ref val, 2959672043u, serverRpcParams, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost) && !IsInvalidServerCall())
			{
				ulong senderClientId = serverRpcParams.Receive.SenderClientId;
				if (!ApplyColorPattern(colorPattern, senderClientId))
				{
					SyncBoomboxColorRequestClientRpc(r, g, b, colorPattern, null, senderClientId, msg: true);
				}
			}
		}

		[ClientRpc]
		internal void SyncBoomboxColorRequestClientRpc(float r, float g, float b, COLOR_PATTERN colorPattern, string colorPatternString, ulong clientId, bool msg = false, ClientRpcParams clientRpcParams = default(ClientRpcParams))
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost))
			{
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2185452183u, clientRpcParams, (RpcDelivery)0);
				((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref r, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref g, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref b, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe<COLOR_PATTERN>(ref colorPattern, default(ForEnums));
				bool flag = colorPatternString != null;
				((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref flag, default(ForPrimitives));
				if (flag)
				{
					((FastBufferWriter)(ref val)).WriteValueSafe(colorPatternString, false);
				}
				BytePacker.WriteValueBitPacked(val, clientId);
				((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref msg, default(ForPrimitives));
				((NetworkBehaviour)this).__endSendClientRpc(ref val, 2185452183u, clientRpcParams, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 2 && (networkManager.IsClient || networkManager.IsHost) && !IsInvalidClientCall())
			{
				SyncBoomboxColorRequestClientShared(r, g, b, colorPattern, colorPatternString, clientId, msg);
			}
		}

		internal override void StartAudio(float forceTime = 0f)
		{
			if (IsItemActive())
			{
				StartAudioTime(forceTime);
				boomboxItem.boomboxAudio.pitch = 1f;
				boomboxItem.boomboxAudio.Play();
				boomboxItem.isPlayingMusic = (((GrabbableObject)boomboxItem).isBeingUsed = true);
			}
		}

		internal override void StopAudio(float forceTime = 0f, bool syncTime = true)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (IsItemActive())
			{
				StopAudioTime(forceTime);
				if (((NetworkBehaviour)this).IsHost && syncTime)
				{
					SyncTimeRequestServerRpc(timeSaved, REQUEST_TYPE.STOP);
				}
				bool isPlayingMusic = boomboxItem.isPlayingMusic;
				boomboxItem.boomboxAudio.Stop();
				if (isPlayingMusic)
				{
					boomboxItem.boomboxAudio.PlayOneShot(boomboxItem.stopAudios[Random.Range(0, boomboxItem.stopAudios.Length)]);
				}
				boomboxItem.isPlayingMusic = (((GrabbableObject)boomboxItem).isBeingUsed = false);
			}
		}

		internal override REQUEST_STATE Sync(bool request, string filenameId, string url, string title, int duration, float time, AudioClip audioClip, bool isPlaying)
		{
			serverFilenameId = filenameId;
			serverUrl = url;
			serverTitle = title;
			serverDuration = duration;
			serverTime = time;
			if (!IsItemActive())
			{
				return REQUEST_STATE.FAILURE;
			}
			if (Object.op_Implicit((Object)(object)audioClip))
			{
				base.filenameId = filenameId;
				base.url = url;
				base.title = title;
				base.duration = duration;
				boomboxItem.boomboxAudio.clip = audioClip;
				boomboxItem.boomboxAudio.time = (timeSaved = Controller.ClampAudioSource(boomboxItem.boomboxAudio, time));
			}
			else
			{
				ResetController();
				time = 0f;
			}
			if (request)
			{
				if (((GrabbableObject)boomboxItem).isHeld)
				{
					if (isPlaying)
					{
						ResetAudio(time);
					}
					return REQUEST_STATE.SUCCESS;
				}
				StartAudio();
				return REQUEST_STATE.AUTO_PLAY;
			}
			if (isPlaying)
			{
				StartAudio(time);
			}
			else
			{
				StopAudio(time, syncTime: false);
			}
			return REQUEST_STATE.SUCCESS;
		}

		internal override void ResetController()
		{
			AudioSource audioSource = GetAudioSource();
			audioSource.clip = GetDefaultAudioClip();
			audioSource.time = 0f;
			ResetControllerBase();
		}

		internal override Controller GetControllerForItemId(ulong itemId)
		{
			if (!BoomboxControllers.ContainsKey(itemId))
			{
				return null;
			}
			return BoomboxControllers[itemId];
		}

		internal override bool IsPlaying()
		{
			return boomboxItem.isPlayingMusic;
		}

		internal override bool IsResettable()
		{
			if (IsBoomboxHeldByUsOrUnattended(boomboxItem))
			{
				return base.IsResettable();
			}
			return false;
		}

		internal static bool IsBoomboxHeldByUsOrUnattended(BoomboxItem boomboxItem)
		{
			if (Object.op_Implicit((Object)(object)boomboxItem))
			{
				if (!IsBoomboxHeldByUs(boomboxItem))
				{
					return !((GrabbableObject)boomboxItem).isHeld;
				}
				return true;
			}
			return false;
		}

		internal static void ToggleMuteBoomboxItems(List<BoomboxItem> boomboxItems)
		{
			if (boomboxItems != null && boomboxItems.Count == 0)
			{
				return;
			}
			bool flag = Object.op_Implicit((Object)(object)boomboxItems.Find((BoomboxItem boomboxItem) => !boomboxItem.boomboxAudio.mute));
			foreach (BoomboxItem boomboxItem in boomboxItems)
			{
				boomboxItem.boomboxAudio.mute = flag;
			}
			bool flag2 = boomboxItems.Count == 1;
			string text = (flag2 ? "boombox" : "boomboxes");
			string text2 = (flag2 ? "it" : "them");
			string text3 = (flag ? Patch.GetMutedString() : Patch.GetUnmutedString());
			string text4 = (flag ? "unmute" : "mute");
			Patch.AddChatMessage($"{boomboxItems.Count} {text} {text3} locally, to {text4} {text2} press [{Patch.TealColorString(((object)(KeyboardShortcut)(ref Config.KeyboardShortcutMute)).ToString())}]");
		}

		internal static bool IsBoomboxHeldByUs(BoomboxItem boomboxItem)
		{
			if (Object.op_Implicit((Object)(object)boomboxItem) && Object.op_Implicit((Object)(object)Patch.LocalPlayerController) && Object.op_Implicit((Object)(object)((GrabbableObject)boomboxItem).playerHeldBy))
			{
				return (Object)(object)((GrabbableObject)boomboxItem).playerHeldBy == (Object)(object)Patch.LocalPlayerController;
			}
			return false;
		}

		internal static bool IsBoomboxHeldBySomeoneElse(BoomboxItem boomboxItem)
		{
			if (Object.op_Implicit((Object)(object)boomboxItem) && Object.op_Implicit((Object)(object)Patch.LocalPlayerController) && Object.op_Implicit((Object)(object)((GrabbableObject)boomboxItem).playerHeldBy))
			{
				return (Object)(object)((GrabbableObject)boomboxItem).playerHeldBy != (Object)(object)Patch.LocalPlayerController;
			}
			return false;
		}

		internal static bool IsBoomboxHeldBySomeoneElseOrUnattended(BoomboxItem boomboxItem)
		{
			if (Object.op_Implicit((Object)(object)boomboxItem))
			{
				if (!IsBoomboxHeldBySomeoneElse(boomboxItem))
				{
					return !((GrabbableObject)boomboxItem).isHeld;
				}
				return true;
			}
			return false;
		}

		internal static Color GetRandomBoomboxColor()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			float num = Random.Range(0f, 1f);
			float num2 = Random.Range(0f, 1f);
			float num3 = Random.Range(0f, 1f);
			return new Color(num, num2, num3);
		}

		internal static BoomboxItem GetHeldBoomboxItem(PlayerControllerB playerControllerB)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)playerControllerB))
			{
				return null;
			}
			if (playerControllerB.currentItemSlot >= playerControllerB.ItemSlots.Length)
			{
				return null;
			}
			object obj = playerControllerB.ItemSlots[playerControllerB.currentItemSlot];
			if (obj == null)
			{
				return null;
			}
			if (!(obj.GetType() == typeof(BoomboxItem)))
			{
				return null;
			}
			return (BoomboxItem)obj;
		}

		internal static List<BoomboxItem> GetHeldBoomboxItems(PlayerControllerB playerControllerB)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)playerControllerB))
			{
				return new List<BoomboxItem>();
			}
			List<BoomboxItem> list = new List<BoomboxItem>();
			GrabbableObject[] array = playerControllerB.ItemSlots.ToArray();
			foreach (object obj in array)
			{
				if (obj != null && obj.GetType() == typeof(BoomboxItem))
				{
					list.Add((BoomboxItem)obj);
				}
			}
			return list;
		}

		internal void ToggleMutePlayer()
		{
			if (LookingPatch.LookingAtPlayerBoomboxItems.Count > 1)
			{
				ToggleMuteBoomboxItems(LookingPatch.LookingAtPlayerBoomboxItems.ToList());
			}
			else
			{
				ToggleMute();
			}
		}

		private bool ApplyColorPattern(COLOR_PATTERN colorPattern, ulong clientId)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (colorPatternCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(colorPatternCoroutine);
			}
			switch (colorPattern)
			{
			case COLOR_PATTERN.RANDOM_LOOP:
				((MonoBehaviour)this).StartCoroutine(colorPatternCoroutine = ColorPatternRandomLoop(clientId));
				return true;
			case COLOR_PATTERN.RAINBOW:
				SyncBoomboxColor(GetBoomboxBodyColor(), colorPattern, GetColorPatternString(colorPattern), clientId, msg: true);
				return true;
			default:
				return false;
			}
		}

		[IteratorStateMachine(typeof(<ColorPatternRandomLoop>d__31))]
		private IEnumerator ColorPatternRandomLoop(ulong clientId)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ColorPatternRandomLoop>d__31(0)
			{
				<>4__this = this,
				clientId = clientId
			};
		}

		[IteratorStateMachine(typeof(<ColorPatternRainbow>d__32))]
		private IEnumerator ColorPatternRainbow(ulong clientId)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ColorPatternRainbow>d__32(0)
			{
				<>4__this = this
			};
		}

		private static Color ColorShift(Color color, float amount)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			float num2 = default(float);
			float num3 = default(float);
			float num = default(float);
			Color.RGBToHSV(color, ref num, ref num2, ref num3);
			num += amount;
			return Color.HSVToRGB(num, 1f, 1f);
		}

		private string GetColorPatternString(COLOR_PATTERN colorPattern)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			switch (colorPattern)
			{
			case COLOR_PATTERN.RANDOM_LOOP:
			{
				string text2;
				if (colorPatternRandomTextColors.Count > 0)
				{
					List<string> list3 = new List<string>();
					int num = 0;
					string text = "RANDOM";
					for (int i = 0; i < text.Length; i++)
					{
						string str = text[i].ToString();
						string color2 = Patch.ColorToHex(colorPatternRandomTextColors[num++]);
						list3.Add(Patch.ColorString(str, color2));
					}
					text2 = string.Concat(list3);
				}
				else
				{
					text2 = "RANDOM";
				}
				return text2 + " loop";
			}
			case COLOR_PATTERN.RAINBOW:
			{
				List<string> list = colorPatternRainbowDict.Keys.ToList();
				List<string> list2 = new List<string>();
				foreach (string item in list)
				{
					Color value = Patch.ParseColor(colorPatternRainbowDict[item]).Value;
					string color = Patch.ColorToHex(value);
					list2.Add(Patch.ColorString(item, color));
				}
				return string.Concat(string.Concat(list2), "!");
			}
			default:
				return null;
			}
		}

		internal override void SyncAllRequestServer(ulong clientId)
		{
			SyncAllRequestServerRpc(clientId);
		}

		internal override AudioSource GetAudioSource()
		{
			return boomboxItem.boomboxAudio;
		}

		internal override string GetSetTimeString(float time)
		{
			return string.Format("{0} set to {1} seconds", IsBoomboxHeldByUs(boomboxItem) ? "Your boombox playback time was" : "Boombox playback time", Math.Round(time, 1));
		}

		internal override AudioClip GetDefaultAudioClip()
		{
			if (boomboxItem.musicAudios.Length == 0)
			{
				return null;
			}
			return boomboxItem.musicAudios[boomboxItem.musicRandomizer.Next(0, boomboxItem.musicAudios.Length)];
		}

		internal Color GetBoomboxBodyColor()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			return ((Renderer)((Component)boomboxItem).gameObject.GetComponent<MeshRenderer>()).materials[3].color;
		}

		internal bool ShouldResyncColor(float r, float g, float b)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Color boomboxBodyColor = GetBoomboxBodyColor();
			if (r == boomboxBodyColor.r && g == boomboxBodyColor.g)
			{
				return b != boomboxBodyColor.b;
			}
			return true;
		}

		internal void SyncBoomboxColorRequestClientShared(float r, float g, float b, COLOR_PATTERN colorPattern, string colorPatternString, ulong clientId, bool msg = false)
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			if (!IsItemActive())
			{
				return;
			}
			Color? val = ChangeBoomboxColor(r, g, b);
			if (!val.HasValue)
			{
				if (msg)
				{
					Patch.AddChatMessage("Failed to change boombox color.");
				}
				return;
			}
			if (colorPatternCoroutine != null && this.colorPattern != colorPattern)
			{
				((MonoBehaviour)this).StopCoroutine(colorPatternCoroutine);
			}
			if (colorPattern == COLOR_PATTERN.RAINBOW)
			{
				((MonoBehaviour)this).StartCoroutine(colorPatternCoroutine = ColorPatternRainbow(clientId));
			}
			this.colorPattern = colorPattern;
			if (msg && IsClientIdLocal(clientId))
			{
				string text = (IsBoomboxHeldByUs(boomboxItem) ? "Your boombox color was" : "Boombox color");
				if (colorPatternString == null)
				{
					colorPatternString = Patch.ColorToString(val.Value);
				}
				Patch.AddChatMessage(text + " set to " + colorPatternString);
			}
		}

		internal Color? ChangeBoomboxColor(float r, float g, float b)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			if (!IsItemActive())
			{
				return null;
			}
			r = Mathf.Clamp(r, 0f, 1f);
			g = Mathf.Clamp(g, 0f, 1f);
			b = Mathf.Clamp(b, 0f, 1f);
			Color val = default(Color);
			((Color)(ref val))..ctor(r, g, b);
			MeshRenderer component = ((Component)boomboxItem).gameObject.GetComponent<MeshRenderer>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return null;
			}
			((Renderer)component).materials[1].color = val;
			((Renderer)component).materials[3].color = val;
			return val;
		}

		internal override ITEM_TYPE GetItemType()
		{
			return ITEM_TYPE.BOOMBOX;
		}

		internal override string GetItemName()
		{
			return "Boombox";
		}

		internal override bool IsItemActive()
		{
			return IsBoomboxItemActive(boomboxItem);
		}

		internal static bool IsBoomboxItemActive(BoomboxItem boomboxItem)
		{
			return Controller.IsNetworkBehaviourActive((NetworkBehaviour)(object)boomboxItem);
		}

		internal override bool IsBeingUsedByUs()
		{
			return IsBoomboxHeldByUs(boomboxItem);
		}

		protected override void __initializeVariables()
		{
			base.__initializeVariables();
		}

		[RuntimeInitializeOnLoadMethod]
		internal static void InitializeRPCS_BoomboxController()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			NetworkManager.__rpc_func_table.Add(4064489894u, new RpcReceiveHandler(__rpc_handler_4064489894));
			NetworkManager.__rpc_func_table.Add(2959672043u, new RpcReceiveHandler(__rpc_handler_2959672043));
			NetworkManager.__rpc_func_table.Add(2185452183u, new RpcReceiveHandler(__rpc_handler_2185452183));
		}

		private static void __rpc_handler_4064489894(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				ulong clientId = default(ulong);
				ByteUnpacker.ReadValueBitPacked(reader, ref clientId);
				target.__rpc_exec_stage = (__RpcExecStage)1;
				((BoomboxController)(object)target).SyncAllRequestServerRpc(clientId);
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		private static void __rpc_handler_2959672043(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: 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)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				float r = default(float);
				((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref r, default(ForPrimitives));
				float g = default(float);
				((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref g, default(ForPrimitives));
				float b = default(float);
				((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref b, default(ForPrimitives));
				COLOR_PATTERN cOLOR_PATTERN = default(COLOR_PATTERN);
				((FastBufferReader)(ref reader)).ReadValueSafe<COLOR_PATTERN>(ref cOLOR_PATTERN, default(ForEnums));
				ServerRpcParams server = rpcParams.Server;
				target.__rpc_exec_stage = (__RpcExecStage)1;
				((BoomboxController)(object)target).SyncBoomboxColorRequestServerRpc(r, g, b, cOLOR_PATTERN, server);
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		private static void __rpc_handler_2185452183(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				float r = default(float);
				((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref r, default(ForPrimitives));
				float g = default(float);
				((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref g, default(ForPrimitives));
				float b = default(float);
				((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref b, default(ForPrimitives));
				COLOR_PATTERN cOLOR_PATTERN = default(COLOR_PATTERN);
				((FastBufferReader)(ref reader)).ReadValueSafe<COLOR_PATTERN>(ref cOLOR_PATTERN, default(ForEnums));
				bool flag = default(bool);
				((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref flag, default(ForPrimitives));
				string colorPatternString = null;
				if (flag)
				{
					((FastBufferReader)(ref reader)).ReadValueSafe(ref colorPatternString, false);
				}
				ulong clientId = default(ulong);
				ByteUnpacker.ReadValueBitPacked(reader, ref clientId);
				bool msg = default(bool);
				((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref msg, default(ForPrimitives));
				ClientRpcParams client = rpcParams.Client;
				target.__rpc_exec_stage = (__RpcExecStage)2;
				((BoomboxController)(object)target).SyncBoomboxColorRequestClientRpc(r, g, b, cOLOR_PATTERN, colorPatternString, clientId, msg, client);
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		protected internal override string __getTypeName()
		{
			return "BoomboxController";
		}
	}
	internal enum ACTION_STATE
	{
		PROCESSING,
		KILLED,
		FINISHED
	}
	internal enum REQUEST_TYPE
	{
		TIME,
		STOP
	}
	internal enum REQUEST_STATE
	{
		FAILURE,
		AUTO_PLAY,
		SUCCESS
	}
	internal enum REQUEST_STATUS
	{
		NONE,
		REQUEST_INITIALIZING,
		REQUEST_VALID,
		REQUEST_CANCELED,
		REQUEST_TIMEOUT,
		REQUEST_NEW_REQUEST,
		ERROR_CLIENT_DOWNLOAD,
		ERROR_CLIENT_DOWNLOAD_CANCELED,
		ERROR_CLIENT_DOWNLOAD_EXCEPTION,
		ERROR_CLIENT_LOAD,
		ERROR_CLIENT_TIMEOUT,
		ERROR_CLIENT_DISCONNECT,
		ERROR_CLIENT_OFFLINE,
		ERROR_UTIL_MISSING_DEPENDENCY,
		ERROR_UTIL_DOWNLOADING_TOOLS,
		ERROR_INVALID_TOOLS,
		ERROR_INVALID_ITEM,
		ERROR_INVALID_URL,
		ERROR_METADATA,
		ERROR_METADATA_EXCEPTION,
		ERROR_METADATA_AGE_RESTRICTED,
		ERROR_METADATA_BOT,
		ERROR_METADATA_SIGN_IN,
		ERROR_METADATA_VIDEO_UNAVAILABLE,
		ERROR_METADATA_MAX_DURATION
	}
	internal enum MUTE
	{
		NONE,
		SINGLE,
		ALL,
		ALWAYS
	}
	internal enum NETWORK_MODE
	{
		OFFLINE,
		ONLINE
	}
	internal enum COLOR_PATTERN
	{
		NONE,
		RANDOM_LOOP,
		RAINBOW
	}
	internal enum TOOLS_STATUS
	{
		NONE,
		DOWNLOADING
	}
	internal enum ITEM_TYPE
	{
		BOOMBOX,
		CRUISER
	}
	internal enum CRUISER_COMPONENT
	{
		NONE,
		TURN_ON_RADIO,
		CHANGE_CHANNEL
	}
	internal class Request
	{
		internal float volume;

		internal bool isPlaying;

		internal string filenameId;

		internal string url;

		internal string title;

		internal int duration;

		internal float time;

		public Request(float volume, bool isPlaying, string filenameId, string url, string title, int duration, float time)
		{
			this.volume = volume;
			this.isPlaying = isPlaying;
			this.filenameId = filenameId;
			this.url = url;
			this.title = title;
			this.duration = duration;
			this.time = time;
			base..ctor();
		}
	}
	internal class Config
	{
		internal static string BindingCategorySettings = "Settings";

		internal static string BindingCategoryKeybinds = "Keybinds";

		private static ConfigEntry<bool> ConfigEntrySync;

		private static ConfigEntry<bool> ConfigEntryPocketPlay;

		private static ConfigEntry<bool> ConfigEntryBoomboxRandomColor;

		public static bool Sync;

		public static bool PocketPlay;

		public static bool BoomboxRandomColor;

		internal static ConfigEntry<KeyboardShortcut> KeyboardShortcutSync;

		internal static ConfigEntry<KeyboardShortcut> KeyboardShortcutReset;

		internal static KeyboardShortcut KeyboardShortcutMute;

		internal static ConfigEntry<KeyboardShortcut> KeyboardShortcutVolumeUp;

		internal static ConfigEntry<KeyboardShortcut> KeyboardShortcutVolumeDown;

		internal static ConfigEntry<KeyboardShortcut> KeyboardShortcutHistoryNext;

		internal static ConfigEntry<KeyboardShortcut> KeyboardShortcutHistoryPrevious;

		internal Config(ConfigFile configFile)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: 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_0143: Unknown result type (might be due to invalid IL or missing references)
			ConfigEntrySync = configFile.Bind<bool>(BindingCategorySettings, "Sync", false, "[HOST] Copy the audio and time of another boombox or cruiser, and allow them to play the same audio. NOTE: This is resource intensive but offers more features and accurate syncing.");
			ConfigEntryPocketPlay = configFile.Bind<bool>(BindingCategorySettings, "Pocket play", false, "[HOST] Allows the boombox to continue playing in the inventory.");
			ConfigEntryBoomboxRandomColor = configFile.Bind<bool>(BindingCategorySettings, "Boombox random color", false, "[HOST] Boomboxes are spawned with a random color!");
			KeyboardShortcutSync = configFile.Bind<KeyboardShortcut>(BindingCategoryKeybinds, "Sync keybind", new KeyboardShortcut((KeyCode)113, Array.Empty<KeyCode>()), "Sync to another boombox or cruiser, or resync (redownload) the audio.");
			KeyboardShortcutReset = configFile.Bind<KeyboardShortcut>(BindingCategoryKeybinds, "Reset keybind", new KeyboardShortcut((KeyCode)114, Array.Empty<KeyCode>()), "Reset the playback time to 0 and stop playback.");
			KeyboardShortcutMute = new KeyboardShortcut((KeyCode)8, Array.Empty<KeyCode>());
			KeyboardShortcutVolumeUp = configFile.Bind<KeyboardShortcut>(BindingCategoryKeybinds, "Boombox volume up keybind", new KeyboardShortcut((KeyCode)280, Array.Empty<KeyCode>()), "Increase the boombox volume.");
			KeyboardShortcutVolumeDown = configFile.Bind<KeyboardShortcut>(BindingCategoryKeybinds, "Boombox volume down keybind", new KeyboardShortcut((KeyCode)281, Array.Empty<KeyCode>()), "Decrease the boombox volume.");
			KeyboardShortcutHistoryNext = configFile.Bind<KeyboardShortcut>(BindingCategoryKeybinds, "Play history next keybind", new KeyboardShortcut((KeyCode)275, Array.Empty<KeyCode>()), "Navigate to the next page in your play history.");
			KeyboardShortcutHistoryPrevious = configFile.Bind<KeyboardShortcut>(BindingCategoryKeybinds, "Play history previous keybind", new KeyboardShortcut((KeyCode)276, Array.Empty<KeyCode>()), "Navigate to the previous page in your play history.");
			MigrateAndClearOrphanedEntries(configFile);
			Sync = ConfigEntrySync.Value;
			PocketPlay = ConfigEntryPocketPlay.Value;
			BoomboxRandomColor = ConfigEntryBoomboxRandomColor.Value;
		}

		private void MigrateAndClearOrphanedEntries(ConfigFile configFile)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			Dictionary<ConfigDefinition, ConfigEntryBase> dictionary = new Dictionary<ConfigDefinition, ConfigEntryBase>
			{
				{
					new ConfigDefinition(BindingCategorySettings, "Boombox sync"),
					(ConfigEntryBase)(object)ConfigEntrySync
				},
				{
					new ConfigDefinition(BindingCategorySettings, "Boombox pocket play"),
					(ConfigEntryBase)(object)ConfigEntryPocketPlay
				},
				{
					new ConfigDefinition(BindingCategoryKeybinds, "Sync boombox keybind"),
					(ConfigEntryBase)(object)KeyboardShortcutSync
				},
				{
					new ConfigDefinition(BindingCategoryKeybinds, "Reset boombox keybind"),
					(ConfigEntryBase)(object)KeyboardShortcutReset
				}
			};
			PropertyInfo property = ((object)configFile).GetType().GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic);
			Dictionary<ConfigDefinition, string> dictionary2 = (Dictionary<ConfigDefinition, string>)property.GetValue(configFile, null);
			foreach (KeyValuePair<ConfigDefinition, string> item in dictionary2)
			{
				if (dictionary.TryGetValue(item.Key, out var value))
				{
					value.SetSerializedValue(item.Value);
					YPlay.LogInfo("Config migrated: [" + item.Key.Key + "] > [" + value.Definition.Key + "]: " + item.Value);
				}
			}
			dictionary2.Clear();
			configFile.Save();
		}

		internal static void SetConfigEntrySync(bool b)
		{
			ConfigEntrySync.Value = b;
		}

		internal static void SetConfigEntryPocketPlay(bool b)
		{
			ConfigEntryPocketPlay.Value = b;
		}

		internal static void SetConfigEntryBoomboxRandomColor(bool b)
		{
			ConfigEntryBoomboxRandomColor.Value = b;
		}
	}
	internal class RequestMetadata
	{
		private static int GlobalRequestId;

		internal HashSet<ulong> originalClientIdRequests = new HashSet<ulong>();

		internal HashSet<ulong> pendingClientIdRequests = new HashSet<ulong>();

		internal REQUEST_STATUS requestStatus = REQUEST_STATUS.REQUEST_INITIALIZING;

		internal int requestId = GlobalRequestId++;

		internal string filenameId;

		internal string title;

		internal string url;

		internal float time;

		internal int duration;
	}
	internal class CommandBuilder
	{
		internal string url;

		internal float time;

		internal float volume = 1f;

		internal string historyUrl;

		internal Color color;

		internal COLOR_PATTERN colorPattern;

		internal MUTE muteMode = MUTE.SINGLE;

		internal bool urlUrlSet;

		internal bool urlSet;

		internal bool offlineSet;

		internal bool historySet;

		internal bool muteSet;

		internal bool timeSet;

		internal bool actionsSet;

		internal bool helpSet;

		internal bool statusSet;

		internal bool resetToolsSet;

		internal bool settingsSet;

		internal bool syncSet;

		internal bool pocketPlaySet;

		internal bool boomboxRandomColorSet;

		internal bool volumeSet;

		internal bool colorSet;

		internal bool urlSuccess;

		internal bool timeSuccess;

		internal bool volumeSuccess;

		internal bool colorSuccess;

		internal bool historyUrlIndexFailed;
	}
	internal static class YPlayConfig
	{
		internal const int MaxChatCharacters = 50;

		internal const int PlayHistoryResultsPerPage = 3;

		internal const int PlayHistoryResultsMax = 15;

		internal const int MaxClips = 15;

		internal const int MaxAudioLengthMinutes = 12;

		internal const float MinVolume = 0f;

		internal const float MaxVolume = 1f;

		internal const int DownloadMetadataTimeoutMs = 15000;

		internal const int DownloadAudioTimeoutBaseMs = 27000;

		internal const int DownloadRequestWaitMs = 5000;
	}
	internal static class Patch
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__MessageHandlerPocketPlayClient;

			public static HandleNamedMessageDelegate <1>__MessageHandlerSyncEnabledClient;

			public static HandleNamedMessageDelegate <2>__MessageHandlerBoomboxRandomColorClient;

			public static HandleNamedMessageDelegate <3>__MessageHandlerMessageClient;

			public static HandleNamedMessageDelegate <4>__MessageHandlerSyncRequestServer;

			public static HandleNamedMessageDelegate <5>__MessageHandlerModEnabledServer;

			public static HandleNamedMessageDelegate <6>__MessageHandlerModeServer;

			public static HandleNamedMessageDelegate <7>__MessageHandlerSyncRequestClient;
		}

		internal static NETWORK_MODE NetworkMode = NETWORK_MODE.OFFLINE;

		private static readonly HashSet<string> ConflictingBoomboxModNames = new HashSet<string>();

		internal static readonly HashSet<ulong> ModEnabledForClientIds = new HashSet<ulong>();

		internal static bool MuteAlways;

		internal static string MuteAlwaysSymbol = PinkColorString("*");

		internal const string InvalidYouTubeURLString = "Invalid YouTube URL, please check it is valid";

		private const string VersionMismatchErrorString = "Host does not have YPlayBoombox installed or has an outdated version, running in offline mode";

		private const string ClientOnlyCommandString = "Sorry, hosts can't use this command!";

		private const string HostOnlyCommandString = "Sorry, this command can only be used by the host";

		private const string HostOrOfflineOnlyCommandString = "Sorry, this command can only be used by the host or while in offline mode";

		private static readonly Type TypeAddChatMessage = typeof(HUDManager);

		private static readonly MethodInfo MethodInfoAddChatMessage = TypeAddChatMessage.GetMethod("AddChatMessage", BindingFlags.Instance | BindingFlags.NonPublic);

		private const string ConfigTag = "[CONFIG]";

		private static readonly string[] InvalidFilenameIds = new string[3] { "results", "search", "search_query" };

		private static CancellationTokenSource syncedCancellationTokenSource;

		private static string serverModVersion;

		private static readonly string MessageHandlerModEnabledS = GetMessageHandlerKey("MessageHandlerModEnabledS");

		private static readonly string MessageHandlerModeS = GetMessageHandlerKey("MessageHandlerModeS");

		private static readonly string MessageHandlerPocketPlayC = GetMessageHandlerKey("MessageHandlerPocketPlayC");

		private static readonly string MessageHandlerSyncEnabledC = GetMessageHandlerKey("MessageHandlerSyncEnabledC");

		private static readonly string MessageHandlerBoomboxRandomColorC = GetMessageHandlerKey("MessageHandlerBoomboxRandomColorC");

		private static readonly string MessageHandlerSyncRequestS = GetMessageHandlerKey("MessageHandlerSyncRequestS");

		private static readonly string MessageHandlerSyncRequestC = GetMessageHandlerKey("MessageHandlerSyncRequestC");

		private static readonly string MessageHandlerMessageHandlerC = GetMessageHandlerKey("MessageHandlerMessageHandlerC");

		internal static readonly HashSet<VehicleController> VehicleControllers = new HashSet<VehicleController>();

		private static string LastChatCommandMessage;

		private static float LastChatMessageTime;

		private const float SameChatMessageTimeMin = 0.1f;

		private static readonly List<string> PlayHistoryUrls = new List<string>();

		private static bool InPlayHistory;

		private static int PlayHistoryPage;

		private static string PlayHistoryNavigatePreviousString;

		private static string PlayHistoryNavigateNextString;

		private static CustomMessagingManager CustomMessageManager => NetworkManager.Singleton.CustomMessagingManager;

		internal static bool IsHost => NetworkManager.Singleton.IsHost;

		internal static PlayerControllerB LocalPlayerController => StartOfRound.Instance.localPlayerController;

		private static string GetMessageHandlerKey(string name)
		{
			return "YPlayBoombox_" + name;
		}

		[HarmonyPatch(typeof(GameNetworkManager), "Start")]
		[HarmonyPrefix]
		internal static void GameNetworkManager_Start_Patch(GameNetworkManager __instance)
		{
			bool flag = false;
			bool flag2 = false;
			foreach (NetworkPrefab prefab in ((Component)__instance).GetComponent<NetworkManager>().NetworkConfig.Prefabs.Prefabs)
			{
				if (!flag && Object.op_Implicit((Object)(object)prefab.Prefab.GetComponent<BoomboxItem>()))
				{
					prefab.Prefab.AddComponent<BoomboxController>();
					flag = true;
				}
				else if (!flag2 && Object.op_Implicit((Object)(object)prefab.Prefab.GetComponent<VehicleController>()))
				{
					prefab.Prefab.AddComponent<CruiserController>();
					flag2 = true;
				}
				if (flag && flag2)
				{
					break;
				}
			}
			CheckConflictingBoomboxMods();
		}

		[HarmonyPatch(typeof(StartOfRound), "OnClientConnect")]
		[HarmonyPostfix]
		internal static void OnClientConnect_Patch(StartOfRound __instance, ulong clientId)
		{
			Controller.shouldVerify = true;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
		[HarmonyPrefix]
		internal static void PlayerControllerB_ConnectClientToPlayerObject_Patch(PlayerControllerB __instance)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Expected O, but got Unknown
			//IL_01a1: 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_01ac: Expected O, but got Unknown
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Expected O, but got Unknown
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Expected O, but got Unknown
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Expected O, but got Unknown
			NetworkMode = (IsHost ? NETWORK_MODE.ONLINE : NETWORK_MODE.OFFLINE);
			serverModVersion = (IsHost ? "2.3.1" : null);
			SetPocketPlay(Config.PocketPlay);
			SetSyncEnabled(Config.Sync);
			SetBoomboxRandomColor(Config.BoomboxRandomColor);
			CustomMessagingManager customMessageManager = CustomMessageManager;
			string messageHandlerPocketPlayC = MessageHandlerPocketPlayC;
			object obj = <>O.<0>__MessageHandlerPocketPlayClient;
			if (obj == null)
			{
				HandleNamedMessageDelegate val = MessageHandlerPocketPlayClient;
				<>O.<0>__MessageHandlerPocketPlayClient = val;
				obj = (object)val;
			}
			customMessageManager.RegisterNamedMessageHandler(messageHandlerPocketPlayC, (HandleNamedMessageDelegate)obj);
			CustomMessagingManager customMessageManager2 = CustomMessageManager;
			string messageHandlerSyncEnabledC = MessageHandlerSyncEnabledC;
			object obj2 = <>O.<1>__MessageHandlerSyncEnabledClient;
			if (obj2 == null)
			{
				HandleNamedMessageDelegate val2 = MessageHandlerSyncEnabledClient;
				<>O.<1>__MessageHandlerSyncEnabledClient = val2;
				obj2 = (object)val2;
			}
			customMessageManager2.RegisterNamedMessageHandler(messageHandlerSyncEnabledC, (HandleNamedMessageDelegate)obj2);
			CustomMessagingManager customMessageManager3 = CustomMessageManager;
			string messageHandlerBoomboxRandomColorC = MessageHandlerBoomboxRandomColorC;
			object obj3 = <>O.<2>__MessageHandlerBoomboxRandomColorClient;
			if (obj3 == null)
			{
				HandleNamedMessageDelegate val3 = MessageHandlerBoomboxRandomColorClient;
				<>O.<2>__MessageHandlerBoomboxRandomColorClient = val3;
				obj3 = (object)val3;
			}
			customMessageManager3.RegisterNamedMessageHandler(messageHandlerBoomboxRandomColorC, (HandleNamedMessageDelegate)obj3);
			CustomMessagingManager customMessageManager4 = CustomMessageManager;
			string messageHandlerMessageHandlerC = MessageHandlerMessageHandlerC;
			object obj4 = <>O.<3>__MessageHandlerMessageClient;
			if (obj4 == null)
			{
				HandleNamedMessageDelegate val4 = MessageHandlerMessageClient;
				<>O.<3>__MessageHandlerMessageClient = val4;
				obj4 = (object)val4;
			}
			customMessageManager4.RegisterNamedMessageHandler(messageHandlerMessageHandlerC, (HandleNamedMessageDelegate)obj4);
			if (IsHost)
			{
				CustomMessagingManager customMessageManager5 = CustomMessageManager;
				string messageHandlerSyncRequestS = MessageHandlerSyncRequestS;
				object obj5 = <>O.<4>__MessageHandlerSyncRequestServer;
				if (obj5 == null)
				{
					HandleNamedMessageDelegate val5 = MessageHandlerSyncRequestServer;
					<>O.<4>__MessageHandlerSyncRequestServer = val5;
					obj5 = (object)val5;
				}
				customMessageManager5.RegisterNamedMessageHandler(messageHandlerSyncRequestS, (HandleNamedMessageDelegate)obj5);
				CustomMessagingManager customMessageManager6 = CustomMessageManager;
				string messageHandlerModEnabledS = MessageHandlerModEnabledS;
				object obj6 = <>O.<5>__MessageHandlerModEnabledServer;
				if (obj6 == null)
				{
					HandleNamedMessageDelegate val6 = MessageHandlerModEnabledServer;
					<>O.<5>__MessageHandlerModEnabledServer = val6;
					obj6 = (object)val6;
				}
				customMessageManager6.RegisterNamedMessageHandler(messageHandlerModEnabledS, (HandleNamedMessageDelegate)obj6);
				CustomMessagingManager customMessageManager7 = CustomMessageManager;
				string messageHandlerModeS = MessageHandlerModeS;
				object obj7 = <>O.<6>__MessageHandlerModeServer;
				if (obj7 == null)
				{
					HandleNamedMessageDelegate val7 = MessageHandlerModeServer;
					<>O.<6>__MessageHandlerModeServer = val7;
					obj7 = (object)val7;
				}
				customMessageManager7.RegisterNamedMessageHandler(messageHandlerModeS, (HandleNamedMessageDelegate)obj7);
				SetModEnabled(__instance.actualClientId, "2.3.1");
			}
			else
			{
				CustomMessagingManager customMessageManager8 = CustomMessageManager;
				string messageHandlerSyncRequestC = MessageHandlerSyncRequestC;
				object obj8 = <>O.<7>__MessageHandlerSyncRequestClient;
				if (obj8 == null)
				{
					HandleNamedMessageDelegate val8 = MessageHandlerSyncRequestClient;
					<>O.<7>__MessageHandlerSyncRequestClient = val8;
					obj8 = (object)val8;
				}
				customMessageManager8.RegisterNamedMessageHandler(messageHandlerSyncRequestC, (HandleNamedMessageDelegate)obj8);
				InitializeClient();
			}
			YPlay.LogInfo("Successfully initialized");
		}

		[HarmonyPatch(typeof(NetworkObject), "Spawn")]
		[HarmonyPrefix]
		internal static void NetworkObject_Spawn_Patch(NetworkObject __instance)
		{
			ApplyControllers(((Component)__instance).gameObject);
		}

		[HarmonyPatch(typeof(BoomboxItem), "StartMusic")]
		[HarmonyPrefix]
		internal static bool BoomboxItem_StartMusic_Patch(BoomboxItem __instance, bool startMusic, bool pitchDown)
		{
			ulong networkObjectId = ((NetworkBehaviour)__instance).NetworkObjectId;
			if (startMusic && BoomboxController.IsBoomboxHeldByUs(__instance))
			{
				if (__instance.boomboxAudio.mute)
				{
					__instance.boomboxAudio.mute = false;
					AddChatMessage("Your boombox was " + GetUnmutedString() + " locally automatically");
					Controller.VolumeZeroHint(__instance);
				}
				else
				{
					Controller.MutedVolumeZeroHint(__instance);
				}
			}
			if (!Object.op_Implicit((Object)(object)__instance.boomboxAudio.clip))
			{
				return true;
			}
			if (!BoomboxController.BoomboxControllers.ContainsKey(networkObjectId))
			{
				return true;
			}
			BoomboxController boomboxController = BoomboxController.BoomboxControllers[networkObjectId];
			if (!boomboxController.IsAudioLoadedInMemory())
			{
				if (startMusic && !string.IsNullOrEmpty(boomboxController.serverFilenameId?.Trim()))
				{
					boomboxController.StopControllersIfStealable();
				}
				return true;
			}
			if (startMusic)
			{
				boomboxController.StartAudio();
			}
			else if (__instance.isPlayingMusic)
			{
				boomboxController.StopAudio();
			}
			return false;
		}

		[HarmonyPatch(typeof(VehicleController), "SetRadioValues")]
		[HarmonyPrefix]
		internal static void VehicleController_SetRadioValues_Patch(VehicleController __instance)
		{
			__instance.radioAudio.volume = 1f;
			__instance.radioInterference.volume = 0f;
			CruiserController.FieldInfoRadioSignalQuality.SetValue(__instance, 3);
		}

		[HarmonyPatch(typeof(VehicleController), "SetRadioOnLocalClient")]
		[HarmonyPrefix]
		internal static void VehicleController_SetRadioOnLocalClient_Patch(VehicleController __instance, bool on, bool setClip)
		{
			float f = (__instance.radioAudio.time = 0f);
			CruiserController.SetCurrentSongTime(__instance, f);
			ulong networkObjectId = ((NetworkBehaviour)__instance).NetworkObjectId;
			CruiserController cruiserController = null;
			if (CruiserController.CruiserControllers.ContainsKey(networkObjectId))
			{
				cruiserController = CruiserController.CruiserControllers[networkObjectId];
			}
			if (on && Object.op_Implicit((Object)(object)cruiserController))
			{
				if (cruiserController.IsOnValidFirstClip())
				{
					cruiserController.StopControllersIfStealable();
					f = (__instance.radioAudio.time = Controller.ClampAudioSource(__instance.radioAudio, cruiserController.timeSaved));
					CruiserController.SetCurrentSongTime(__instance, f);
				}
				else if (CruiserController.IsFirstClip(__instance) && !string.IsNullOrEmpty(cruiserController.serverFilenameId?.Trim()))
				{
					cruiserController.StopControllersIfStealable();
				}
			}
		}

		[HarmonyPatch(typeof(VehicleController), "SetRadioStationClientRpc")]
		[HarmonyPostfix]
		[ClientRpc]
		internal static void VehicleController_SetRadioStation_Postfix_ClientRpc(VehicleController __instance, int radioStation, int signalQuality)
		{
			__instance.radioAudio.clip = __instance.radioClips[radioStation];
			ulong networkObjectId = ((NetworkBehaviour)__instance).NetworkObjectId;
			CruiserController cruiserController = null;
			if (CruiserController.CruiserControllers.ContainsKey(networkObjectId))
			{
				cruiserController = CruiserController.CruiserControllers[networkObjectId];
			}
			if (CruiserController.IsRadioOn(__instance) && Object.op_Implicit((Object)(object)cruiserController) && cruiserController.IsOnValidFirstClip())
			{
				float f = (__instance.radioAudio.time = Controller.ClampAudioSource(__instance.radioAudio, cruiserController.timeSaved));
				CruiserController.SetCurrentSongTime(__instance, f);
			}
			else
			{
				float f = (__instance.radioAudio.time = 0f);
				CruiserController.SetCurrentSongTime(__instance, f);
			}
			__instance.radioAudio.Play();
		}

		[HarmonyPatch(typeof(VehicleController), "ChangeRadioStation")]
		[HarmonyPrefix]
		internal static void VehicleController_ChangeRadioStation_Patch(VehicleController __instance)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			float f = (__instance.radioAudio.time = 0f);
			CruiserController.SetCurrentSongTime(__instance, f);
			ulong networkObjectId = ((NetworkBehaviour)__instance).NetworkObjectId;
			CruiserController cruiserController = null;
			if (CruiserController.CruiserControllers.ContainsKey(networkObjectId))
			{
				cruiserController = CruiserController.CruiserControllers[networkObjectId];
			}
			if (!Object.op_Implicit((Object)(object)cruiserController) || !cruiserController.IsFirstClipLoaded())
			{
				return;
			}
			bool flag = CruiserController.IsRadioOn(__instance);
			int currentRadioStation = CruiserController.GetCurrentRadioStation(__instance);
			int num2 = (currentRadioStation + 1) % __instance.radioClips.Length;
			bool flag2 = cruiserController.IsOnValidFirstClip();
			bool flag3 = num2 == 0;
			if (!(flag2 || flag3))
			{
				return;
			}
			if (flag)
			{
				if (flag2)
				{
					cruiserController.SyncTimeRequestServerRpc(cruiserController.timeSaved = 0f, REQUEST_TYPE.STOP);
				}
			}
			else
			{
				CruiserController.FieldInfoRadioOn.SetValue(__instance, true);
				__instance.radioInterference.Play();
			}
			if ((flag3 && __instance.radioClips.Length > 1) || __instance.radioClips.Length == 1)
			{
				cruiserController.StopControllersIfStealable();
			}
		}

		[HarmonyPatch(typeof(VehicleController), "SwitchRadio")]
		[HarmonyPrefix]
		internal static bool VehicleController_SwitchRadio_Patch(VehicleController __instance)
		{
			ulong networkObjectId = ((NetworkBehaviour)__instance).NetworkObjectId;
			CruiserController cruiserController = null;
			if (CruiserController.CruiserControllers.ContainsKey(networkObjectId))
			{
				cruiserController = CruiserController.CruiserControllers[networkObjectId];
			}
			if (!Object.op_Implicit((Object)(object)cruiserController) || !cruiserController.IsOnValidFirstClip())
			{
				return true;
			}
			CruiserController.FieldInfoRadioOn.SetValue(__instance, !CruiserController.IsRadioOn(__instance));
			if (CruiserController.IsRadioOn(__instance))
			{
				__instance.radioAudio.clip = __instance.radioClips[CruiserController.GetCurrentRadioStation(__instance)];
				float f = (__instance.radioAudio.time = Controller.ClampAudioSource(__instance.radioAudio, cruiserController.timeSaved));
				CruiserController.SetCurrentSongTime(__instance, f);
				cruiserController.StartAudio();
				__instance.radioInterference.Play();
			}
			else
			{
				cruiserController.StopAudio();
				__instance.radioInterference.Stop();
			}
			return false;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Update")]
		[HarmonyPostfix]
		internal static void PlayerControllerB_Update_Patch(PlayerControllerB __instance)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_033e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0383: Unknown result type (might be due to invalid IL or missing references)
			//IL_0388: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance != (Object)(object)LocalPlayerController || !PlayerCanInteract(__instance))
			{
				return;
			}
			KeyboardShortcut value;
			if (InPlayHistory && PlayHistoryUrls.Count > 0)
			{
				if (!string.IsNullOrEmpty(PlayHistoryNavigatePreviousString?.Trim()))
				{
					value = Config.KeyboardShortcutHistoryPrevious.Value;
					if (((KeyboardShortcut)(ref value)).IsDown())
					{
						ShowPlayHistory(PlayHistoryPage - 1);
						return;
					}
				}
				if (!string.IsNullOrEmpty(PlayHistoryNavigateNextString?.Trim()))
				{
					value = Config.KeyboardShortcutHistoryNext.Value;
					if (((KeyboardShortcut)(ref value)).IsDown())
					{
						ShowPlayHistory(PlayHistoryPage + 1);
						return;
					}
				}
			}
			BoomboxController boomboxController = null;
			BoomboxItem heldBoomboxItem = BoomboxController.GetHeldBoomboxItem(__instance);
			if (Object.op_Implicit((Object)(object)heldBoomboxItem))
			{
				ulong networkObjectId = ((NetworkBehaviour)heldBoomboxItem).NetworkObjectId;
				if (BoomboxController.BoomboxControllers.ContainsKey(networkObjectId))
				{
					boomboxController = BoomboxController.BoomboxControllers[networkObjectId];
				}
			}
			BoomboxController boomboxController2 = null;
			BoomboxItem lookingAtBoomboxItem = LookingPatch.LookingAtBoomboxItem;
			if (Object.op_Implicit((Object)(object)lookingAtBoomboxItem))
			{
				ulong networkObjectId2 = ((NetworkBehaviour)lookingAtBoomboxItem).NetworkObjectId;
				if (BoomboxController.BoomboxControllers.ContainsKey(networkObjectId2))
				{
					boomboxController2 = BoomboxController.BoomboxControllers[networkObjectId2];
				}
			}
			BoomboxController boomboxController3 = null;
			BoomboxItem lookingAtPlayerBoomboxItem = LookingPatch.LookingAtPlayerBoomboxItem;
			if (Object.op_Implicit((Object)(object)lookingAtPlayerBoomboxItem))
			{
				ulong networkObjectId3 = ((NetworkBehaviour)lookingAtPlayerBoomboxItem).NetworkObjectId;
				if (BoomboxController.BoomboxControllers.ContainsKey(networkObjectId3))
				{
					boomboxController3 = BoomboxController.BoomboxControllers[networkObjectId3];
				}
			}
			BoomboxController boomboxController4 = boomboxController3 ?? boomboxController2;
			CruiserController cruiserController = null;
			VehicleController playerVehicleController = CruiserController.GetPlayerVehicleController(__instance);
			if (Object.op_Implicit((Object)(object)playerVehicleController))
			{
				ulong networkObjectId4 = ((NetworkBehaviour)playerVehicleController).NetworkObjectId;
				if (CruiserController.CruiserControllers.ContainsKey(networkObjectId4))
				{
					cruiserController = CruiserController.CruiserControllers[networkObjectId4];
				}
			}
			CruiserController cruiserController2 = null;
			VehicleController lookingAtVehicleController = LookingPatch.LookingAtVehicleController;
			if (Object.op_Implicit((Object)(object)lookingAtVehicleController))
			{
				ulong networkObjectId5 = ((NetworkBehaviour)lookingAtVehicleController).NetworkObjectId;
				if (CruiserController.CruiserControllers.ContainsKey(networkObjectId5))
				{
					cruiserController2 = CruiserController.CruiserControllers[networkObjectId5];
				}
			}
			value = Config.KeyboardShortcutSync.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				if (Object.op_Implicit((Object)(object)lookingAtPlayerBoomboxItem) && LookingPatch.LookingAtPlayerBoomboxItems.Count > 1)
				{
					bool flag = false;
					foreach (BoomboxItem item in LookingPatch.LookingAtPlayerBoomboxItems.ToList())
					{
						ulong networkObjectId6 = ((NetworkBehaviour)item).NetworkObjectId;
						if (BoomboxController.BoomboxControllers.ContainsKey(networkObjectId6))
						{
							BoomboxController boomboxController5 = BoomboxController.BoomboxControllers[networkObjectId6];
							if (boomboxController5.IsResyncable())
							{
								boomboxController5.Resync();
								flag = true;
							}
						}
					}
					if (flag)
					{
						return;
					}
				}
				Controller controller = (Controller)(((object)boomboxController4) ?? ((object)cruiserController2));
				if (Object.op_Implicit((Object)(object)controller) && controller.IsResyncable())
				{
					controller.Resync();
					return;
				}
				Controller controller2 = (Controller)(((object)cruiserController) ?? ((object)boomboxController));
				if (Object.op_Implicit((Object)(object)controller2) && (Object)(object)controller2 != (Object)(object)controller && Object.op_Implicit((Object)(object)control

plugins\dep\YPlayUtil.dll

Decompiled 2 weeks 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 YPlayUtil.Converters;
using YPlayUtil.Helpers;
using YPlayUtil.Metadata;
using YPlayUtil.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,kerotein")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("© 2020-2024 Bluegrams")]
[assembly: AssemblyDescription("A 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\r\nModified by kerotein for YPlayBoombox.")]
[assembly: AssemblyFileVersion("1.1.1.24278")]
[assembly: AssemblyInformationalVersion("1.1.1+8863d5327ce0a6cf747b294977161b224c066434")]
[assembly: AssemblyProduct("YPlayUtil")]
[assembly: AssemblyTitle("YPlayUtil")]
[assembly: AssemblyVersion("1.1.1.24278")]
namespace YPlayUtil
{
	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 static class FFmpegApi
		{
			public class Root
			{
				[JsonProperty("version")]
				public string Version { get; set; }

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

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

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

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

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

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

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

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

		private static readonly HttpClient _client = new HttpClient();

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

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

		public static string YtDlpBinaryName => GetYtDlpBinaryName();

		public static string FfmpegBinaryName => GetFfmpegBinaryName();

		public static string FfprobeBinaryName => GetFfprobeBinaryName();

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

		private static string sanitizeChar(char c, bool restricted)
		{
			if (restricted && accentChars.ContainsKey(c))
			{
				return accentChars[c];
			}
			if (c != '?' && c >= ' ')
			{
				switch (c)
				{
				case '\u007f':
					break;
				case '"':
					if (!restricted)
					{
						return "'";
					}
					return "";
				case ':':
					if (!restricted)
					{
						return " -";
					}
					return "_-";
				default:
					if (Enumerable.Contains("\\/|*<>", c))
					{
						return "_";
					}
					if (restricted && Enumerable.Contains("!&'()[]{}$;`^,# ", c))
					{
						return "_";
					}
					if (restricted && c > '\u007f')
					{
						return "_";
					}
					return c.ToString();
				}
			}
			return "";
		}

		public static string GetFullPath(string fileName)
		{
			if (File.Exists(fileName))
			{
				return Path.GetFullPath(fileName);
			}
			string[] array = Environment.GetEnvironmentVariable("PATH").Split(new char[1] { Path.PathSeparator });
			for (int i = 0; i < array.Length; i++)
			{
				string text = Path.Combine(array[i], fileName);
				if (File.Exists(text))
				{
					return text;
				}
			}
			return null;
		}

		public static async Task DownloadBinaries(string ytDlpReleaseDate, bool skipExisting = true, string directoryPath = "")
		{
			if (skipExisting)
			{
				if (!File.Exists(Path.Combine(directoryPath, GetYtDlpBinaryName())))
				{
					await DownloadYtDlp(directoryPath);
				}
				if (!File.Exists(Path.Combine(directoryPath, GetFfmpegBinaryName())))
				{
					await DownloadFFmpeg(directoryPath);
				}
				if (!File.Exists(Path.Combine(directoryPath, GetFfprobeBinaryName())))
				{
					await DownloadFFprobe(directoryPath);
				}
			}
			else
			{
				await DownloadYtDlp(directoryPath);
				await DownloadFFmpeg(directoryPath);
				await DownloadFFprobe(directoryPath);
			}
		}

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

		private static string GetSevenZipDownloadUrl()
		{
			return "https://www.7-zip.org/a/7zr.exe";
		}

		private static string GetFFmpegEssentialsDownloadUrl(string version, bool sevenZip)
		{
			return "https://github.com/GyanD/codexffmpeg/releases/download/" + version + "/ffmpeg-" + version + "-essentials_build." + (sevenZip ? "7z" : "zip");
		}

		private static string GetYtDlpBinaryName()
		{
			string ytDlpDownloadUrl = GetYtDlpDownloadUrl(null);
			switch (OSHelper.GetOSVersion())
			{
			case OSVersion.Windows:
				return "yt-dlp.exe";
			case OSVersion.OSX:
			case OSVersion.Linux:
				return Path.GetFileName(ytDlpDownloadUrl);
			default:
				throw new Exception("Your OS isn't supported");
			}
		}

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

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

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

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

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

		public static async Task DownloadSevenZip(string path = "")
		{
			File.WriteAllBytes(path, await DownloadFileBytesAsync(GetSevenZipDownloadUrl()));
		}

		public static async Task DownloadFFmpegEssentials7zArchive(string version, string path = "")
		{
			File.WriteAllBytes(path, await DownloadFileBytesAsync(GetFFmpegEssentialsDownloadUrl(version, sevenZip: true)));
		}

		public static async Task DownloadFFmpegEssentials(string version, string directoryPath = "")
		{
			using MemoryStream stream = new MemoryStream(await DownloadFileBytesAsync(GetFFmpegEssentialsDownloadUrl(version, sevenZip: false)));
			using ZipArchive zipArchive = new ZipArchive(stream, ZipArchiveMode.Read);
			if (zipArchive.Entries.Count <= 0)
			{
				return;
			}
			string ffmpegBinaryName = GetFfmpegBinaryName();
			foreach (ZipArchiveEntry entry in zipArchive.Entries)
			{
				if (entry.Name.Equals(ffmpegBinaryName, StringComparison.OrdinalIgnoreCase))
				{
					entry.ExtractToFile(Path.Combine(directoryPath, entry.Name), overwrite: true);
					break;
				}
			}
		}

		public static async Task Extract7z(string sevenZipExePath, string path, string workingDirectory = "")
		{
			await Task.Run(delegate
			{
				string ffmpegBinaryName = GetFfmpegBinaryName();
				try
				{
					using Process process = new Process();
					process.StartInfo.FileName = sevenZipExePath;
					process.StartInfo.UseShellExecute = false;
					process.StartInfo.Arguments = "e \"" + path + "\" *" + ffmpegBinaryName + " -r -aoa";
					process.StartInfo.WorkingDirectory = workingDirectory;
					process.StartInfo.CreateNoWindow = true;
					process.StartInfo.RedirectStandardOutput = true;
					process.Start();
					process.WaitForExit();
				}
				catch (Exception)
				{
				}
			});
		}

		public static async Task ExtractZip(string path, string workingDirectory = "")
		{
			await Task.Run(delegate
			{
				string ffmpegBinaryName = GetFfmpegBinaryName();
				using ZipArchive zipArchive = ZipFile.OpenRead(path);
				foreach (ZipArchiveEntry entry in zipArchive.Entries)
				{
					if (entry.Name.Equals(ffmpegBinaryName, StringComparison.OrdinalIgnoreCase))
					{
						entry.ExtractToFile(Path.Combine(workingDirectory, ffmpegBinaryName));
						break;
					}
				}
			});
		}

		private static async Task FFDownloader(string version, string directoryPath = "", FFmpegApi.BinaryType binary = FFmpegApi.BinaryType.FFmpeg)
		{
			if (string.IsNullOrEmpty(directoryPath))
			{
				directoryPath = Directory.GetCurrentDirectory();
			}
			string requestUri = "https://ffbinaries.com/api/v1/version/" + version;
			FFmpegApi.Root root = JsonConvert.DeserializeObject<FFmpegApi.Root>(await (await _client.GetAsync(requestUri)).Content.ReadAsStringAsync());
			FFmpegApi.OsBinVersion osBinVersion = OSHelper.GetOSVersion() switch
			{
				OSVersion.Windows => root?.Bin.Windows64, 
				OSVersion.OSX => root?.Bin.Osx64, 
				OSVersion.Linux => root?.Bin.Linux64, 
				_ => throw new NotImplementedException("Your OS isn't supported"), 
			};
			using MemoryStream stream = new MemoryStream(await DownloadFileBytesAsync((binary == FFmpegApi.BinaryType.FFmpeg) ? osBinVersion.Ffmpeg : osBinVersion.Ffprobe));
			using ZipArchive zipArchive = new ZipArchive(stream, ZipArchiveMode.Read);
			if (zipArchive.Entries.Count > 0)
			{
				zipArchive.Entries[0].ExtractToFile(Path.Combine(directoryPath, zipArchive.Entries[0].FullName), overwrite: true);
			}
		}

		public static async Task<byte[]> DownloadFileBytesAsync(string uri)
		{
			if (!Uri.TryCreate(uri, UriKind.Absolute, out Uri _))
			{
				throw new InvalidOperationException("URI is invalid.");
			}
			return await _client.GetByteArrayAsync(uri);
		}

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

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

		protected ProcessRunner runner;

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


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


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


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


		public bool RestrictFilenames { get; set; }

		public bool OverwriteFiles { get; set; } = true;


		public bool IgnoreDownloadErrors { get; set; } = true;


		public string PythonInterpreterPath { get; set; }

		public string Version => FileVersionInfo.GetVersionInfo(Utils.GetFullPath(YoutubeDLPath)).FileVersion;

		public YoutubeDL(byte maxNumberOfProcesses = 4)
		{
			runner = new ProcessRunner(maxNumberOfProcesses);
		}

		public async Task SetMaxNumberOfProcesses(byte count)
		{
			await runner.SetTotalCount(count);
		}

		public async Task<RunResult<string[]>> RunWithOptions(string[] urls, OptionSet options, CancellationToken ct)
		{
			List<string> output = new List<string>();
			YoutubeDLProcess youtubeDLProcess = CreateYoutubeDLProcess();
			youtubeDLProcess.OutputReceived += delegate(object o, DataReceivedEventArgs e)
			{
				output.Add(e.Data);
			};
			var (num, error) = await runner.RunThrottled(youtubeDLProcess, urls, options, ct);
			return new RunResult<string[]>(num == 0, error, output.ToArray());
		}

		public async Task<RunResult<string>> RunWithOptions(string url, OptionSet options, CancellationToken ct = default(CancellationToken), IProgress<DownloadProgress> progress = null, IProgress<string> output = null, bool showArgs = true)
		{
			string outFile = string.Empty;
			YoutubeDLProcess youtubeDLProcess = CreateYoutubeDLProcess();
			if (showArgs)
			{
				output?.Report("Arguments: " + youtubeDLProcess.ConvertToArgs(new string[1] { url }, options) + "\n");
			}
			else
			{
				output?.Report("Starting Download: " + url);
			}
			youtubeDLProcess.OutputReceived += delegate(object o, DataReceivedEventArgs e)
			{
				Match match = rgxFilePostProc.Match(e.Data);
				if (match.Success)
				{
					outFile = match.Groups[0].ToString().Replace("[download] Destination:", "").Replace(" ", "");
					progress?.Report(new DownloadProgress(DownloadState.Success, 0f, null, null, null, 1, outFile));
				}
				output?.Report(e.Data);
			};
			var (num, error) = await runner.RunThrottled(youtubeDLProcess, new string[1] { url }, options, ct, progress);
			return new RunResult<string>(num == 0, error, outFile);
		}

		public async Task<string> RunUpdate()
		{
			string output = string.Empty;
			YoutubeDLProcess youtubeDLProcess = CreateYoutubeDLProcess();
			youtubeDLProcess.OutputReceived += delegate(object o, DataReceivedEventArgs e)
			{
				output = e.Data;
			};
			await youtubeDLProcess.RunAsync(null, new OptionSet
			{
				Update = true
			});
			return output;
		}

		public async Task<RunResult<VideoData>> RunVideoDataFetch(string url, CancellationToken ct = default(CancellationToken), bool flat = true, bool fetchComments = false, OptionSet overrideOptions = null)
		{
			OptionSet optionSet = GetDownloadOptions();
			optionSet.DumpSingleJson = true;
			optionSet.FlatPlaylist = flat;
			optionSet.WriteComments = fetchComments;
			if (overrideOptions != null)
			{
				optionSet = optionSet.OverrideOptions(overrideOptions);
			}
			VideoData videoData = null;
			YoutubeDLProcess process = CreateYoutubeDLProcess();
			process.OutputReceived += delegate(object o, DataReceivedEventArgs e)
			{
				try
				{
					videoData = JsonConvert.DeserializeObject<VideoData>(e.Data);
				}
				catch (JsonSerializationException)
				{
					process.RedirectToError(e);
				}
			};
			var (num, error) = await runner.RunThrottled(process, new string[1] { url }, optionSet, ct);
			return new RunResult<VideoData>(num == 0, error, videoData);
		}

		public async Task<RunResult<string>> RunVideoDownload(string url, string format = "bestvideo+bestaudio/best", DownloadMergeFormat mergeFormat = DownloadMergeFormat.Unspecified, VideoRecodeFormat recodeFormat = VideoRecodeFormat.None, CancellationToken ct = default(CancellationToken), IProgress<DownloadProgress> progress = null, IProgress<string> output = null, OptionSet overrideOptions = null)
		{
			OptionSet optionSet = GetDownloadOptions();
			optionSet.Format = format;
			optionSet.MergeOutputFormat = mergeFormat;
			optionSet.RecodeVideo = recodeFormat;
			if (overrideOptions != null)
			{
				optionSet = optionSet.OverrideOptions(overrideOptions);
			}
			string outputFile = string.Empty;
			YoutubeDLProcess youtubeDLProcess = CreateYoutubeDLProcess();
			output?.Report("Arguments: " + youtubeDLProcess.ConvertToArgs(new string[1] { url }, optionSet) + "\n");
			youtubeDLProcess.OutputReceived += delegate(object o, DataReceivedEventArgs e)
			{
				Match match = rgxFile.Match(e.Data);
				if (match.Success)
				{
					outputFile = match.Groups[1].ToString().Trim(new char[1] { '"' });
					progress?.Report(new DownloadProgress(DownloadState.Success, 0f, null, null, null, 1, outputFile));
				}
				output?.Report(e.Data);
			};
			var (num, error) = await runner.RunThrottled(youtubeDLProcess, new string[1] { url }, optionSet, ct, progress);
			return new RunResult<string>(num == 0, error, outputFile);
		}

		public async Task<RunResult<string[]>> RunVideoPlaylistDownload(string url, int? start = 1, int? end = null, int[] items = null, string format = "bestvideo+bestaudio/best", VideoRecodeFormat recodeFormat = VideoRecodeFormat.None, CancellationToken ct = default(CancellationToken), IProgress<DownloadProgress> progress = null, IProgress<string> output = null, OptionSet overrideOptions = null)
		{
			OptionSet optionSet = GetDownloadOptions();
			optionSet.NoPlaylist = false;
			optionSet.PlaylistStart = start;
			optionSet.PlaylistEnd = end;
			if (items != null)
			{
				optionSet.PlaylistItems = string.Join(",", items);
			}
			optionSet.Format = format;
			optionSet.RecodeVideo = recodeFormat;
			if (overrideOptions != null)
			{
				optionSet = optionSet.OverrideOptions(overrideOptions);
			}
			List<string> outputFiles = new List<string>();
			YoutubeDLProcess youtubeDLProcess = CreateYoutubeDLProcess();
			output?.Report("Arguments: " + youtubeDLProcess.ConvertToArgs(new string[1] { url }, optionSet) + "\n");
			youtubeDLProcess.OutputReceived += delegate(object o, DataReceivedEventArgs e)
			{
				Match match = rgxFile.Match(e.Data);
				if (match.Success)
				{
					string text = match.Groups[1].ToString().Trim(new char[1] { '"' });
					outputFiles.Add(text);
					progress?.Report(new DownloadProgress(DownloadState.Success, 0f, null, null, null, 1, text));
				}
				output?.Report(e.Data);
			};
			var (num, error) = await runner.RunThrottled(youtubeDLProcess, new string[1] { url }, optionSet, ct, progress);
			return new RunResult<string[]>(num == 0, error, outputFiles.ToArray());
		}

		public async Task<RunResult<string>> RunAudioDownload(string url, AudioConversionFormat format = AudioConversionFormat.Best, CancellationToken ct = default(CancellationToken), IProgress<DownloadProgress> progress = null, IProgress<string> output = null, OptionSet overrideOptions = null)
		{
			OptionSet optionSet = GetDownloadOptions();
			optionSet.Format = "bestaudio/best";
			optionSet.ExtractAudio = true;
			optionSet.AudioFormat = format;
			if (overrideOptions != null)
			{
				optionSet = optionSet.OverrideOptions(overrideOptions);
			}
			string outputFile = string.Empty;
			new List<string>();
			YoutubeDLProcess youtubeDLProcess = CreateYoutubeDLProcess();
			output?.Report("Arguments: " + youtubeDLProcess.ConvertToArgs(new string[1] { url }, optionSet) + "\n");
			youtubeDLProcess.OutputReceived += delegate(object o, DataReceivedEventArgs e)
			{
				Match match = rgxFile.Match(e.Data);
				if (match.Success)
				{
					outputFile = match.Groups[1].ToString().Trim(new char[1] { '"' });
					progress?.Report(new DownloadProgress(DownloadState.Success, 0f, null, null, null, 1, outputFile));
				}
				output?.Report(e.Data);
			};
			var (num, error) = await runner.RunThrottled(youtubeDLProcess, new string[1] { url }, optionSet, ct, progress);
			return new RunResult<string>(num == 0, error, outputFile);
		}

		public async Task<RunResult<string[]>> RunAudioPlaylistDownload(string url, int? start = 1, int? end = null, int[] items = null, AudioConversionFormat format = AudioConversionFormat.Best, CancellationToken ct = default(CancellationToken), IProgress<DownloadProgress> progress = null, IProgress<string> output = null, OptionSet overrideOptions = null)
		{
			List<string> outputFiles = new List<string>();
			OptionSet optionSet = GetDownloadOptions();
			optionSet.NoPlaylist = false;
			optionSet.PlaylistStart = start;
			optionSet.PlaylistEnd = end;
			if (items != null)
			{
				optionSet.PlaylistItems = string.Join(",", items);
			}
			optionSet.Format = "bestaudio/best";
			optionSet.ExtractAudio = true;
			optionSet.AudioFormat = format;
			if (overrideOptions != null)
			{
				optionSet = optionSet.OverrideOptions(overrideOptions);
			}
			YoutubeDLProcess youtubeDLProcess = CreateYoutubeDLProcess();
			output?.Report("Arguments: " + youtubeDLProcess.ConvertToArgs(new string[1] { url }, optionSet) + "\n");
			youtubeDLProcess.OutputReceived += delegate(object o, DataReceivedEventArgs e)
			{
				Match match = rgxFile.Match(e.Data);
				if (match.Success)
				{
					string text = match.Groups[1].ToString().Trim(new char[1] { '"' });
					outputFiles.Add(text);
					progress?.Report(new DownloadProgress(DownloadState.Success, 0f, null, null, null, 1, text));
				}
				output?.Report(e.Data);
			};
			var (num, error) = await runner.RunThrottled(youtubeDLProcess, new string[1] { url }, optionSet, ct, progress);
			return new RunResult<string[]>(num == 0, error, outputFiles.ToArray());
		}

		protected virtual OptionSet GetDownloadOptions()
		{
			return new OptionSet
			{
				IgnoreErrors = IgnoreDownloadErrors,
				IgnoreConfig = true,
				NoPlaylist = true,
				Downloader = "m3u8:native",
				DownloaderArgs = "ffmpeg:-nostats -loglevel 0",
				Output = Path.Combine(OutputFolder, OutputFileTemplate),
				RestrictFilenames = RestrictFilenames,
				ForceOverwrites = OverwriteFiles,
				NoOverwrites = !OverwriteFiles,
				NoPart = true,
				FfmpegLocation = Utils.GetFullPath(FFmpegPath),
				Exec = "echo outfile: {}"
			};
		}

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

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

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

		public string PythonPath { get; set; }

		public string ExecutablePath { get; set; }

		public bool UseWindowsEncodingWorkaround { get; set; } = true;


		public event EventHandler<DataReceivedEventArgs> OutputReceived;

		public event EventHandler<DataReceivedEventArgs> ErrorReceived;

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

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

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

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

		public async Task<int> RunAsync(string[] urls, OptionSet options, CancellationToken ct, IProgress<DownloadProgress> progress = null)
		{
			TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
			Process process = new Process();
			ProcessStartInfo processStartInfo = new ProcessStartInfo
			{
				CreateNoWindow = true,
				UseShellExecute = false,
				RedirectStandardOutput = true,
				RedirectStandardError = true,
				StandardOutputEncoding = Encoding.UTF8,
				StandardErrorEncoding = Encoding.UTF8
			};
			if (OSHelper.IsWindows && UseWindowsEncodingWorkaround)
			{
				processStartInfo.FileName = "cmd.exe";
				string text = (string.IsNullOrEmpty(PythonPath) ? ("\"" + ExecutablePath + "\" " + ConvertToArgs(urls, options)) : ("\"" + PythonPath + "\" \"" + ExecutablePath + "\" " + ConvertToArgs(urls, options)));
				processStartInfo.Arguments = "/C chcp 65001 >nul 2>&1 && " + text;
			}
			else if (!string.IsNullOrEmpty(PythonPath))
			{
				processStartInfo.FileName = PythonPath;
				processStartInfo.Arguments = "\"" + ExecutablePath + "\" " + ConvertToArgs(urls, options);
			}
			else
			{
				processStartInfo.FileName = ExecutablePath;
				processStartInfo.Arguments = ConvertToArgs(urls, options);
			}
			process.EnableRaisingEvents = true;
			process.StartInfo = processStartInfo;
			TaskCompletionSource<bool> tcsOut = new TaskCompletionSource<bool>();
			bool isDownloading = false;
			process.OutputDataReceived += delegate(object o, DataReceivedEventArgs e)
			{
				if (e.Data == null)
				{
					tcsOut.SetResult(result: true);
				}
				else
				{
					Match match;
					if ((match = rgxProgress.Match(e.Data)).Success)
					{
						if (match.Groups.Count > 1 && match.Groups[1].Length > 0)
						{
							float progress2 = float.Parse(match.Groups[1].ToString(), CultureInfo.InvariantCulture) / 100f;
							Group group = match.Groups["total"];
							string totalDownloadSize = (group.Success ? group.Value : null);
							Group group2 = match.Groups["speed"];
							string downloadSpeed = (group2.Success ? group2.Value : null);
							Group group3 = match.Groups["eta"];
							string eta = (group3.Success ? group3.Value : null);
							progress?.Report(new DownloadProgress(DownloadState.Downloading, progress2, totalDownloadSize, downloadSpeed, eta));
						}
						else
						{
							progress?.Report(new DownloadProgress(DownloadState.Downloading));
						}
						isDownloading = true;
					}
					else if ((match = rgxPlaylist.Match(e.Data)).Success)
					{
						int index = int.Parse(match.Groups[1].Value);
						progress?.Report(new DownloadProgress(DownloadState.PreProcessing, 0f, null, null, null, index));
						isDownloading = false;
					}
					else if (isDownloading && (match = rgxPost.Match(e.Data)).Success)
					{
						progress?.Report(new DownloadProgress(DownloadState.PostProcessing, 1f));
						isDownloading = false;
					}
					this.OutputReceived?.Invoke(this, e);
				}
			};
			TaskCompletionSource<bool> tcsError = new TaskCompletionSource<bool>();
			process.ErrorDataReceived += delegate(object o, DataReceivedEventArgs e)
			{
				if (e.Data == null)
				{
					tcsError.SetResult(result: true);
				}
				else
				{
					progress?.Report(new DownloadProgress(DownloadState.Error, 0f, null, null, null, 1, e.Data));
					this.ErrorReceived?.Invoke(this, e);
				}
			};
			process.Exited += async delegate
			{
				await tcsOut.Task;
				await tcsError.Task;
				tcs.TrySetResult(process.ExitCode);
				process.Dispose();
			};
			ct.Register(delegate
			{
				if (!tcs.Task.IsCompleted)
				{
					tcs.TrySetCanceled();
				}
				try
				{
					if (!process.HasExited)
					{
						process.KillTree();
					}
				}
				catch
				{
				}
			});
			if (!(await Task.Run(() => process.Start())))
			{
				tcs.TrySetException(new InvalidOperationException("Failed to start yt-dlp process."));
			}
			process.BeginOutputReadLine();
			process.BeginErrorReadLine();
			progress?.Report(new DownloadProgress(DownloadState.PreProcessing));
			return await tcs.Task;
		}
	}
}
namespace YPlayUtil.Options
{
	public enum DownloadMergeFormat
	{
		Unspecified,
		Mp4,
		Mkv,
		Ogg,
		Webm,
		Flv
	}
	public enum AudioConversionFormat
	{
		Best,
		Aac,
		Flac,
		Mp3,
		M4a,
		Opus,
		Vorbis,
		Wav
	}
	public enum VideoRecodeFormat
	{
		None,
		Mp4,
		Mkv,
		Ogg,
		Webm,
		Flv,
		Avi
	}
	public interface IOption
	{
		string DefaultOptionString { get; }

		string[] OptionStrings { get; }

		bool IsSet { get; }

		bool IsCustom { get; }

		void SetFromString(string s);

		IEnumerable<string> ToStringCollection();
	}
	public class MultiOption<T> : IOption
	{
		private MultiValue<T> value;

		public string DefaultOptionString => OptionStrings.Last();

		public string[] OptionStrings { get; }

		public bool IsSet { get; private set; }

		public bool IsCustom { get; }

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

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

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

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

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

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

		public List<T> Values => values;

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

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

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

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

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

		public string DefaultOptionString => OptionStrings.First();

		public string[] OptionStrings { get; }

		public bool IsSet { get; private set; }

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

		public bool IsCustom { get; }

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

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

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

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

		public IEnumerable<string> ToStringCollection()
		{
			return new string[1] { ToString() };
		}
	}
	internal class OptionComparer : IEqualityComparer<IOption>
	{
		public bool Equals(IOption x, IOption y)
		{
			if (x != null)
			{
				if (y != null)
				{
					return x.ToString().Equals(y.ToString());
				}
				return false;
			}
			return y == null;
		}

		public int GetHashCode(IOption obj)
		{
			return obj.ToString().GetHashCode();
		}
	}
	public class OptionSet : ICloneable
	{
		private Option<string> username = new Option<string>("-u", "--username");

		private Option<string> password = new Option<string>("-p", "--password");

		private Option<string> twoFactor = new Option<string>("-2", "--twofactor");

		private Option<bool> netrc = new Option<bool>("-n", "--netrc");

		private Option<string> netrcLocation = new Option<string>("--netrc-location");

		private Option<string> netrcCmd = new Option<string>("--netrc-cmd");

		private Option<string> videoPassword = new Option<string>("--video-password");

		private Option<string> apMso = new Option<string>("--ap-mso");

		private Option<string> apUsername = new Option<string>("--ap-username");

		private Option<string> apPassword = new Option<string>("--ap-password");

		private Option<bool> apListMso = new Option<bool>("--ap-list-mso");

		private Option<string> clientCertificate = new Option<string>("--client-certificate");

		private Option<string> clientCertificateKey = new Option<string>("--client-certificate-key");

		private Option<string> clientCertificatePassword = new Option<string>("--client-certificate-password");

		private static readonly OptionComparer Comparer = new OptionComparer();

		public static readonly OptionSet Default = new OptionSet();

		private Option<bool> getDescription = new Option<bool>("--get-description");

		private Option<bool> getDuration = new Option<bool>("--get-duration");

		private Option<bool> getFilename = new Option<bool>("--get-filename");

		private Option<bool> getFormat = new Option<bool>("--get-format");

		private Option<bool> getId = new Option<bool>("--get-id");

		private Option<bool> getThumbnail = new Option<bool>("--get-thumbnail");

		private Option<bool> getTitle = new Option<bool>("-e", "--get-title");

		private Option<bool> getUrl = new Option<bool>("-g", "--get-url");

		private Option<string> matchTitle = new Option<string>("--match-title");

		private Option<string> rejectTitle = new Option<string>("--reject-title");

		private Option<long?> minViews = new Option<long?>("--min-views");

		private Option<long?> maxViews = new Option<long?>("--max-views");

		private Option<bool> breakOnReject = new Option<bool>("--break-on-reject");

		private Option<string> userAgent = new Option<string>("--user-agent");

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

		private Option<int?> playlistStart = new Option<int?>("--playlist-start");

		private Option<int?> playlistEnd = new Option<int?>("--playlist-end");

		private Option<bool> playlistReverse = new Option<bool>("--playlist-reverse");

		private Option<bool> noColors = new Option<bool>("--no-colors");

		private Option<bool> forceGenericExtractor = new Option<bool>("--force-generic-extractor");

		private Option<string> execBeforeDownload = new Option<string>("--exec-before-download");

		private Option<bool> noExecBeforeDownload = new Option<bool>("--no-exec-before-download");

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

		private Option<bool> allSubs = new Option<bool>("--all-subs");

		private Option<bool> printJson = new Option<bool>("--print-json");

		private Option<string> autonumberSize = new Option<string>("--autonumber-size");

		private Option<int?> autonumberStart = new Option<int?>("--autonumber-start");

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

		private Option<string> metadataFromTitle = new Option<string>("--metadata-from-title");

		private Option<bool> hlsPreferNative = new Option<bool>("--hls-prefer-native");

		private Option<bool> hlsPreferFfmpeg = new Option<bool>("--hls-prefer-ffmpeg");

		private Option<bool> listFormatsOld = new Option<bool>("--list-formats-old", "--no-list-formats-as-table");

		private Option<bool> listFormatsAsTable = new Option<bool>("--list-formats-as-table", "--no-list-formats-old");

		private Option<bool> youtubeSkipDashManifest = new Option<bool>("--youtube-skip-dash-manifest", "--no-youtube-include-dash-manifest");

		private Option<bool> youtubeSkipHlsManifest = new Option<bool>("--youtube-skip-hls-manifest", "--no-youtube-include-hls-manifest");

		private Option<bool> geoBypass = new Option<bool>("--geo-bypass");

		private Option<bool> noGeoBypass = new Option<bool>("--no-geo-bypass");

		private Option<string> geoBypassCountry = new Option<string>("--geo-bypass-country");

		private Option<string> geoBypassIpBlock = new Option<string>("--geo-bypass-ip-block");

		private Option<int?> concurrentFragments = new Option<int?>("-N", "--concurrent-fragments");

		private Option<long?> limitRate = new Option<long?>("-r", "--limit-rate");

		private Option<long?> throttledRate = new Option<long?>("--throttled-rate");

		private Option<int?> retries = new Option<int?>("-R", "--retries");

		private Option<int?> fileAccessRetries = new Option<int?>("--file-access-retries");

		private Option<int?> fragmentRetries = new Option<int?>("--fragment-retries");

		private MultiOption<string> retrySleep = new MultiOption<string>("--retry-sleep");

		private Option<bool> skipUnavailableFragments = new Option<bool>("--skip-unavailable-fragments", "--no-abort-on-unavailable-fragments");

		private Option<bool> abortOnUnavailableFragments = new Option<bool>("--abort-on-unavailable-fragments", "--no-skip-unavailable-fragments");

		private Option<bool> keepFragments = new Option<bool>("--keep-fragments");

		private Option<bool> noKeepFragments = new Option<bool>("--no-keep-fragments");

		private Option<long?> bufferSize = new Option<long?>("--buffer-size");

		private Option<bool> resizeBuffer = new Option<bool>("--resize-buffer");

		private Option<bool> noResizeBuffer = new Option<bool>("--no-resize-buffer");

		private Option<long?> httpChunkSize = new Option<long?>("--http-chunk-size");

		private Option<bool> playlistRandom = new Option<bool>("--playlist-random");

		private Option<bool> lazyPlaylist = new Option<bool>("--lazy-playlist");

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

		private Option<bool> xattrSetFilesize = new Option<bool>("--xattr-set-filesize");

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		private Option<bool> dumpUserAgent = new Option<bool>("--dump-user-agent");

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public bool XattrSetFilesize
		{
			get
			{
				return xattrSetFilesize.Value;
			}
			set
			{
				xattrSetFilesize.Value = value;
			}
		}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public bool DumpUserAgent
		{
			get
			{
				return dumpUserAgent.Value;
			}
			set
			{
				dumpUserAgent.Value = value;
			}
		}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public OptionSet OverrideOptions(OptionSet overrideOptions, bool forceOverride = false)
		{
			OptionSet optionSet = (OptionSet)Clone();
			optionSet.CustomOptions = optionSet.CustomOptions.Concat(overrideOptions.CustomOptions).Distinct(Comparer).ToArray();
			foreach (FieldInfo item in from p in overrideOptions.GetType().GetRuntimeFields()
				where p.FieldType.IsGenericType && p.FieldType.GetInterfaces().Contains(typeof(IOption))
				select p)
			{
				IOption option = (IOption)item.GetValue(overrideOptions);
				if (forceOverride || option.IsSet)
				{
					optionSet.GetType().GetField(item.Name, BindingFlags.Instance | BindingFlags.NonPublic).SetValue(optionSet, option);
				}
			}
			return optionSet;
		}

		public static OptionSet FromString(IEnumerable<string> lines)
		{
			OptionSet optionSet = new OptionSet();
			IOption[] customOptions = (from option in GetOptions(lines, optionSet.GetKnownOptions())
				where option.IsCustom
				select option).ToArray();
			optionSet.CustomOptions = customOptions;
			return optionSet;
		}

		private static IEnumerable<IOption> GetOptions(IEnumerable<string> lines, IEnumerable<IOption> options)
		{
			IEnumerable<IOption> knownOptions = options.ToList();
			foreach (string line in lines)
			{
				string text = line.Trim();
				if (!text.StartsWith("#") && !string.IsNullOrWhiteSpace(text))
				{
					string[] array = text.Split(new char[1] { ' ' });
					string flag = array[0];
					IOption option = knownOptions.FirstOrDefault((IOption o) => o.OptionStrings.Contains(flag));
					IOption option3;
					if (array.Length <= 1)
					{
						IOption option2 = new Option<bool>(true, flag);
						option3 = option2;
					}
					else
					{
						IOption option2 = new Option<string>(true, flag);
						option3 = option2;
					}
					IOption option4 = option3;
					IOption option5 = option ?? option4;
					option5.SetFromString(text);
					yield return option5;
				}
			}
		}

		public static OptionSet LoadConfigFile(string path)
		{
			return FromString(File.ReadAllLines(path));
		}

		public object Clone()
		{
			return FromString(GetOptionFlags());
		}

		public void AddCustomOption<T>(string optionString, T value)
		{
			Option<T> option = new Option<T>(true, optionString);
			option.Value = value;
			CustomOptio