Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of XiaohaiTV Extended v1.1.0
XiaohaiTV_Extended.dll
Decompiled 5 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using XiaohaiTV_Extended.Patches; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("sasnews")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+4e4aedba538d8595258df797e1bf2ad0fabb56da")] [assembly: AssemblyProduct("XiaohaiTV_Extended")] [assembly: AssemblyTitle("XiaohaiTV_Extended")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace XiaohaiTV_Extended { [HarmonyPatch(typeof(PlayerController))] internal static class ExamplePlayerControllerPatch { [HarmonyPrefix] [HarmonyPatch("Start")] private static void Start_Prefix(PlayerController __instance) { XiaohaiTV_Extended.Logger.LogDebug((object)$"{__instance} Start Prefix"); } [HarmonyPostfix] [HarmonyPatch("Start")] private static void Start_Postfix(PlayerController __instance) { XiaohaiTV_Extended.Logger.LogDebug((object)$"{__instance} Start Postfix"); } } [BepInPlugin("sasnews.XiaohaiTV_Extended", "XiaohaiTV_Extended", "1.0")] public class XiaohaiTV_Extended : BaseUnityPlugin { [CompilerGenerated] private sealed class <WaitAndApplyPatch>d__16 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public XiaohaiTV_Extended <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WaitAndApplyPatch>d__16(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(2f); <>1__state = 1; return true; case 1: <>1__state = -1; Logger.LogInfo((object)"Attempting to apply patch to REPO_TV..."); if (<>4__this.Harmony != null) { TVScriptBilibiliPatch.ApplyPatch(<>4__this.Harmony); } else { Logger.LogError((object)"Harmony instance is null!"); } 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 XiaohaiTV_Extended Instance { get; private set; } internal static ManualLogSource Logger => Instance._logger; private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger; internal Harmony? Harmony { get; set; } private void Awake() { Instance = this; ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Patch(); Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!"); CheckYtDlpInstallation(); ((MonoBehaviour)this).StartCoroutine(WaitAndApplyPatch()); } internal void Patch() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0026: Expected O, but got Unknown if (Harmony == null) { Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); Harmony val2 = val; Harmony = val; } Logger.LogInfo((object)"Harmony instance created, waiting for REPO_TV to load..."); } private void CheckYtDlpInstallation() { try { Process process = new Process { StartInfo = new ProcessStartInfo { FileName = "yt-dlp", Arguments = "--version", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true } }; process.Start(); process.WaitForExit(3000); if (process.ExitCode == 0) { string text = process.StandardOutput.ReadToEnd().Trim(); Logger.LogInfo((object)("yt-dlp detected: v" + text)); } else { LogYtDlpWarning(); } } catch { LogYtDlpWarning(); } } private void LogYtDlpWarning() { Logger.LogWarning((object)"================================================================================"); Logger.LogWarning((object)"███████████████████████████████ WARNING ███████████████████████████████"); Logger.LogWarning((object)"================================================================================"); Logger.LogWarning((object)""); Logger.LogWarning((object)" yt-dlp is NOT installed or not found in PATH!"); Logger.LogWarning((object)""); Logger.LogWarning((object)" This MOD requires yt-dlp to be installed."); Logger.LogWarning((object)""); Logger.LogWarning((object)" Installation:"); Logger.LogWarning((object)" pip install yt-dlp"); Logger.LogWarning((object)""); Logger.LogWarning((object)" Or visit:"); Logger.LogWarning((object)" https://github.com/yt-dlp/yt-dlp#installation"); Logger.LogWarning((object)""); Logger.LogWarning((object)"================================================================================"); } [IteratorStateMachine(typeof(<WaitAndApplyPatch>d__16))] private IEnumerator WaitAndApplyPatch() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WaitAndApplyPatch>d__16(0) { <>4__this = this }; } internal void Unpatch() { Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } public static class YouTubeHelper { private static ManualLogSource Logger => XiaohaiTV_Extended.Logger; public static string? ExtractVideoId(string input) { if (string.IsNullOrEmpty(input)) { Logger.LogInfo((object)"[YouTubeHelper] Input is null or empty"); return null; } Logger.LogInfo((object)("[YouTubeHelper] Checking input: " + input)); if (IsYouTubeUrl(input)) { string[] array = new string[2] { "(?:youtube\\.com\\/watch\\?v=|youtu\\.be\\/)([a-zA-Z0-9_-]{11})", "^([a-zA-Z0-9_-]{11})$" }; string[] array2 = array; foreach (string pattern in array2) { Match match = Regex.Match(input, pattern); if (match.Success) { string value = match.Groups[1].Value; Logger.LogInfo((object)("[YouTubeHelper] YouTube video ID detected: " + value)); return value; } } } if (IsTwitterUrl(input)) { Logger.LogInfo((object)("[YouTubeHelper] Twitter/X URL detected: " + input)); return input; } Logger.LogInfo((object)("[YouTubeHelper] Not a supported video URL: " + input)); return null; } private static bool IsYouTubeUrl(string input) { return Regex.IsMatch(input, "(youtube\\.com|youtu\\.be)") || Regex.IsMatch(input, "^[a-zA-Z0-9_-]{11}$"); } private static bool IsTwitterUrl(string input) { return Regex.IsMatch(input, "(twitter\\.com|x\\.com)/.+/status/\\d+", RegexOptions.IgnoreCase); } public static async Task<string> GetYouTubeUrlAsync(string videoIdOrUrl, string quality = "best") { try { string videoId = ExtractVideoId(videoIdOrUrl); if (string.IsNullOrEmpty(videoId)) { Logger.LogWarning((object)("[YouTubeHelper] Invalid video URL: " + videoIdOrUrl)); return string.Empty; } string targetUrl = (videoId.StartsWith("http") ? videoId : ("https://www.youtube.com/watch?v=" + videoId)); Process process = new Process { StartInfo = new ProcessStartInfo { FileName = "yt-dlp", Arguments = "--get-url -f \"18/22/(mp4)[height<=720]/best[ext=mp4]/best\" \"" + targetUrl + "\"", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true, StandardOutputEncoding = Encoding.UTF8, StandardErrorEncoding = Encoding.UTF8 } }; process.StartInfo.EnvironmentVariables["PYTHONIOENCODING"] = "utf-8"; Logger.LogInfo((object)("[YouTubeHelper] Executing yt-dlp: " + videoId)); process.Start(); Task<string> outputTask = process.StandardOutput.ReadToEndAsync(); Task<string> errorTask = process.StandardError.ReadToEndAsync(); await Task.WhenAll<string>(outputTask, errorTask); await Task.Run(delegate { process.WaitForExit(); }); string output = outputTask.Result.Trim(); string error = errorTask.Result; if (process.ExitCode != 0) { Logger.LogError((object)("[YouTubeHelper] yt-dlp error: " + error)); return string.Empty; } if (string.IsNullOrEmpty(output)) { Logger.LogWarning((object)("[YouTubeHelper] 動画URLが取得できませんでした: " + videoId)); return string.Empty; } string[] lines = output.Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); string videoUrl = lines[0]; Logger.LogInfo((object)("[YouTubeHelper] Video URL retrieved successfully: " + videoId)); return videoUrl; } catch (Exception ex2) { Exception ex = ex2; Logger.LogError((object)("[YouTubeHelper] Exception occurred: " + ex.Message)); return string.Empty; } } public static string GetYouTubeUrl(string videoIdOrUrl, string quality = "best") { return GetYouTubeUrlAsync(videoIdOrUrl, quality).GetAwaiter().GetResult(); } public static async Task<string> GetVideoTitleAsync(string videoIdOrUrl) { try { string videoId = ExtractVideoId(videoIdOrUrl); if (string.IsNullOrEmpty(videoId)) { return string.Empty; } string targetUrl = (videoId.StartsWith("http") ? videoId : ("https://www.youtube.com/watch?v=" + videoId)); Process process = new Process { StartInfo = new ProcessStartInfo { FileName = "yt-dlp", Arguments = "--get-title --encoding utf-8 \"" + targetUrl + "\"", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true, StandardOutputEncoding = Encoding.UTF8, StandardErrorEncoding = Encoding.UTF8 } }; process.StartInfo.EnvironmentVariables["PYTHONIOENCODING"] = "utf-8"; process.Start(); Task<string> outputTask = process.StandardOutput.ReadToEndAsync(); await Task.Run(delegate { process.WaitForExit(); }); string title = outputTask.Result.Trim(); if (process.ExitCode != 0 || string.IsNullOrEmpty(title)) { return videoId; } return title; } catch (Exception ex2) { Exception ex = ex2; Logger.LogError((object)("[YouTubeHelper] タイトル取得例外: " + ex.Message)); return string.Empty; } } public static string GetVideoTitle(string videoIdOrUrl) { return GetVideoTitleAsync(videoIdOrUrl).GetAwaiter().GetResult(); } public static bool IsYtDlpAvailable() { try { Process process = new Process { StartInfo = new ProcessStartInfo { FileName = "yt-dlp", Arguments = "--version", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true } }; process.Start(); process.WaitForExit(5000); return process.ExitCode == 0; } catch { return false; } } } } namespace XiaohaiTV_Extended.Patches { public static class TVScriptBilibiliPatch { [CompilerGenerated] private sealed class <PlayYoutubeCoroutine>d__6 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public object tvScriptInstance; public string videoId; private Task<string> <urlTask>5__1; private Task<string> <titleTask>5__2; private string <videoUrl>5__3; private string <videoTitle>5__4; private Type <photonNetworkType>5__5; private bool <isMultiplayer>5__6; private PropertyInfo <offlineModeProperty>5__7; private bool <offlineMode>5__8; private PropertyInfo <photonViewProp>5__9; private object <photonView>5__10; private Type <rpcTargetType>5__11; private object <rpcTargetAll>5__12; private Type <photonViewType>5__13; private MethodInfo <rpcMethod>5__14; private MethodInfo <rpcMethod>5__15; private Exception <ex>5__16; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PlayYoutubeCoroutine>d__6(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <urlTask>5__1 = null; <titleTask>5__2 = null; <videoUrl>5__3 = null; <videoTitle>5__4 = null; <photonNetworkType>5__5 = null; <offlineModeProperty>5__7 = null; <photonViewProp>5__9 = null; <photonView>5__10 = null; <rpcTargetType>5__11 = null; <rpcTargetAll>5__12 = null; <photonViewType>5__13 = null; <rpcMethod>5__14 = null; <rpcMethod>5__15 = null; <ex>5__16 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; Logger.LogInfo((object)("[TVScriptBilibiliPatch] Starting Youtube playback: " + videoId)); SetBilibiliReturnInfo(tvScriptInstance, ""); <urlTask>5__1 = YouTubeHelper.GetYouTubeUrlAsync(videoId); <titleTask>5__2 = YouTubeHelper.GetVideoTitleAsync(videoId); break; case 1: <>1__state = -1; break; } if (!<urlTask>5__1.IsCompleted || !<titleTask>5__2.IsCompleted) { <>2__current = null; <>1__state = 1; return true; } <videoUrl>5__3 = <urlTask>5__1.Result; <videoTitle>5__4 = <titleTask>5__2.Result; if (string.IsNullOrEmpty(<videoUrl>5__3)) { SetBilibiliReturnInfo(tvScriptInstance, "動画URLの取得に失敗しました"); Logger.LogWarning((object)("[TVScriptBilibiliPatch] Failed to get video URL: " + videoId)); return false; } if (<videoUrl>5__3.Contains(".m3u8") || <videoUrl>5__3.Contains("manifest/hls")) { SetBilibiliReturnInfo(tvScriptInstance, "Video format not supported (HLS)"); Logger.LogWarning((object)("[TVScriptBilibiliPatch] HLS format not supported: " + <videoUrl>5__3)); return false; } if (string.IsNullOrEmpty(<videoTitle>5__4)) { <videoTitle>5__4 = videoId; } Logger.LogInfo((object)("[TVScriptBilibiliPatch] Video retrieved: " + <videoTitle>5__4)); Logger.LogInfo((object)("[TVScriptBilibiliPatch] Video URL: " + <videoUrl>5__3)); try { if (tvScriptType == null) { SetBilibiliReturnInfo(tvScriptInstance, "TVScript not found"); Logger.LogError((object)"[TVScriptBilibiliPatch] tvScriptType is null"); return false; } <photonNetworkType>5__5 = Type.GetType("Photon.Pun.PhotonNetwork, PhotonUnityNetworking"); <isMultiplayer>5__6 = false; if (<photonNetworkType>5__5 != null) { <offlineModeProperty>5__7 = <photonNetworkType>5__5.GetProperty("OfflineMode", BindingFlags.Static | BindingFlags.Public); if (<offlineModeProperty>5__7 != null) { <offlineMode>5__8 = (bool)<offlineModeProperty>5__7.GetValue(null); <isMultiplayer>5__6 = !<offlineMode>5__8; Logger.LogInfo((object)$"[TVScriptBilibiliPatch] OfflineMode: {<offlineMode>5__8}, IsMultiplayer: {<isMultiplayer>5__6}"); } else { Logger.LogError((object)"[TVScriptBilibiliPatch] OfflineMode property not found"); } <offlineModeProperty>5__7 = null; } else { Logger.LogError((object)"[TVScriptBilibiliPatch] PhotonNetwork type not found"); } if (<isMultiplayer>5__6) { Logger.LogInfo((object)"[TVScriptBilibiliPatch] Multiplayer mode - sending RPC"); <photonViewProp>5__9 = tvScriptType.BaseType?.GetProperty("photonView", BindingFlags.Instance | BindingFlags.Public); if (<photonViewProp>5__9 == null) { Logger.LogError((object)"[TVScriptBilibiliPatch] photonView property not found in base type"); return false; } <photonView>5__10 = <photonViewProp>5__9.GetValue(tvScriptInstance); if (<photonView>5__10 == null) { Logger.LogError((object)"[TVScriptBilibiliPatch] photonView is null"); return false; } Logger.LogInfo((object)$"[TVScriptBilibiliPatch] PhotonView obtained: {<photonView>5__10}"); <rpcTargetType>5__11 = Type.GetType("Photon.Pun.RpcTarget, PhotonUnityNetworking"); if (<rpcTargetType>5__11 == null) { Logger.LogError((object)"[TVScriptBilibiliPatch] RpcTarget type not found"); return false; } <rpcTargetAll>5__12 = Enum.ToObject(<rpcTargetType>5__11, 3); <photonViewType>5__13 = <photonView>5__10.GetType(); <rpcMethod>5__14 = <photonViewType>5__13.GetMethod("RPC", new Type[3] { typeof(string), <rpcTargetType>5__11, typeof(object[]) }); if (<rpcMethod>5__14 == null) { Logger.LogError((object)"[TVScriptBilibiliPatch] RPC method not found"); return false; } Logger.LogInfo((object)"[TVScriptBilibiliPatch] Invoking RPC..."); <rpcMethod>5__14.Invoke(<photonView>5__10, new object[3] { "RPC_AddPlaylistItem", <rpcTargetAll>5__12, new object[3] { <videoUrl>5__3, <videoTitle>5__4, true } }); Logger.LogInfo((object)"[TVScriptBilibiliPatch] RPC invoked successfully"); <photonViewProp>5__9 = null; <photonView>5__10 = null; <rpcTargetType>5__11 = null; <rpcTargetAll>5__12 = null; <photonViewType>5__13 = null; <rpcMethod>5__14 = null; } else { Logger.LogInfo((object)"[TVScriptBilibiliPatch] Singleplayer mode - calling directly"); <rpcMethod>5__15 = tvScriptType.GetMethod("RPC_AddPlaylistItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (<rpcMethod>5__15 == null) { Logger.LogError((object)"[TVScriptBilibiliPatch] RPC_AddPlaylistItem method not found"); return false; } <rpcMethod>5__15.Invoke(tvScriptInstance, new object[3] { <videoUrl>5__3, <videoTitle>5__4, true }); Logger.LogInfo((object)"[TVScriptBilibaliPatch] RPC_AddPlaylistItem called successfully"); <rpcMethod>5__15 = null; } SetBilibiliReturnInfo(tvScriptInstance, "Youtube動画再生成功!"); Logger.LogInfo((object)("[TVScriptBilibiliPatch] Youtube video added to playlist: " + <videoTitle>5__4)); <photonNetworkType>5__5 = null; } catch (Exception ex) { <ex>5__16 = ex; SetBilibiliReturnInfo(tvScriptInstance, "再生エラー: " + <ex>5__16.Message); Logger.LogError((object)$"[TVScriptBilibiliPatch] Playback error: {<ex>5__16}"); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static Type? tvScriptType; private static ManualLogSource Logger => XiaohaiTV_Extended.Logger; public static void ApplyPatch(Harmony harmony) { //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Expected O, but got Unknown //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Expected O, but got Unknown Logger.LogInfo((object)"[TVScriptBilibiliPatch] Searching for TVScript..."); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); Assembly[] array = assemblies; foreach (Assembly assembly in array) { try { Type[] types = assembly.GetTypes(); Type[] array2 = types; foreach (Type type in array2) { if (!(type.FullName == "REPO_TV.TVScript")) { continue; } tvScriptType = type; Logger.LogInfo((object)("[TVScriptBilibiliPatch] TVScript found in " + assembly.GetName().Name)); MethodInfo method = type.GetMethod("ExtractBVFromInput", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { Logger.LogInfo((object)"[TVScriptBilibiliPatch] ExtractBVFromInput method found"); MethodInfo method2 = typeof(TVScriptBilibiliPatch).GetMethod("ExtractBVFromInput_Postfix", BindingFlags.Static | BindingFlags.Public); if (method2 != null) { harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)"[TVScriptBilibiliPatch] ExtractBVFromInput patch applied!"); } } MethodInfo method3 = type.GetMethod("PlayBilibiliCoroutine", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method3 != null) { Logger.LogInfo((object)$"[TVScriptBilibiliPatch] PlayBilibiliCoroutine method found: {method3}"); MethodInfo method4 = typeof(TVScriptBilibiliPatch).GetMethod("PlayBilibiliCoroutine_Prefix", BindingFlags.Static | BindingFlags.Public); if (method4 != null) { harmony.Patch((MethodBase)method3, new HarmonyMethod(method4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)"[TVScriptBilibiliPatch] PlayBilibiliCoroutine patch applied!"); } else { Logger.LogError((object)"[TVScriptBilibiliPatch] Prefix method not found!"); } } else { Logger.LogWarning((object)"[TVScriptBilibiliPatch] PlayBilibiliCoroutine method not found"); } return; } } catch { } } Logger.LogWarning((object)"[TVScriptBilibiliPatch] TVScript type not found. Patch will be applied when REPO_TV loads."); } public static void ExtractBVFromInput_Postfix(string input, ref string __result) { try { if (!string.IsNullOrEmpty(__result)) { Logger.LogInfo((object)("[TVScriptBilibiliPatch] ExtractBVFromInput returned BV: " + __result)); return; } string value = YouTubeHelper.ExtractVideoId(input); if (!string.IsNullOrEmpty(value)) { Logger.LogInfo((object)("[TVScriptBilibiliPatch] ExtractBVFromInput detected Youtube URL, passing through: " + input)); __result = input; } } catch (Exception arg) { Logger.LogError((object)$"[TVScriptBilibiliPatch] ExtractBVFromInput_Postfix exception: {arg}"); } } public static bool PlayBilibiliCoroutine_Prefix(object __instance, string bv, ref IEnumerator __result) { try { Logger.LogInfo((object)("[TVScriptBilibiliPatch] Prefix called with input: " + bv)); string text = YouTubeHelper.ExtractVideoId(bv); if (!string.IsNullOrEmpty(text)) { Logger.LogInfo((object)("[TVScriptBilibiliPatch] Youtube URL detected: " + text + ", skipping original method")); __result = PlayYoutubeCoroutine(__instance, text); return false; } Logger.LogInfo((object)("[TVScriptBilibiliPatch] Bilibili BV号 detected: " + bv + ", running original method")); return true; } catch (Exception arg) { Logger.LogError((object)$"[TVScriptBilibiliPatch] Prefix exception: {arg}"); return true; } } [IteratorStateMachine(typeof(<PlayYoutubeCoroutine>d__6))] private static IEnumerator PlayYoutubeCoroutine(object tvScriptInstance, string videoId) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PlayYoutubeCoroutine>d__6(0) { tvScriptInstance = tvScriptInstance, videoId = videoId }; } private static void SetBilibiliReturnInfo(object tvScriptInstance, string message) { try { if (!(tvScriptType == null)) { FieldInfo field = tvScriptType.GetField("bilibiliReturnInfo", BindingFlags.Instance | BindingFlags.NonPublic); if (field != null) { field.SetValue(tvScriptInstance, message); } } } catch (Exception arg) { Logger.LogError((object)$"[TVScriptBilibiliPatch] Failed to set bilibiliReturnInfo: {arg}"); } } } }