Decompiled source of YPlayBoombox v2.3.1
plugins\YPlay.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
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
The result has been truncated due to the large size, download it to view full contents!
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