Decompiled source of YoutubeVideoPlayer v1.2.1

Mods/YoutubeVideoPlayer.dll

Decompiled 2 days ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading.Tasks;
using BoneLib;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Marrow.Pool;
using LabFusion.Network;
using LabFusion.Network.Serialization;
using LabFusion.Safety;
using MelonLoader;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Video;
using YoutubeVideoPlayer;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonOptionalDependencies(new string[] { "LabFusion" })]
[assembly: MelonInfo(typeof(Core), "YoutubeVideoPlayer", "1.1.2", "larkos", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("YoutubeVideoPlayer")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("YoutubeVideoPlayer")]
[assembly: AssemblyTitle("YoutubeVideoPlayer")]
[assembly: NeutralResourcesLanguage("en-US")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace YoutubeVideoPlayer
{
	public class UrlResolver
	{
		private static readonly string YtDlpPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UserData", "YoutubeVideoPlayer", "yt-dlp.exe");

		public static bool NeedsResolution(string url)
		{
			if (string.IsNullOrEmpty(url))
			{
				return false;
			}
			return url.Contains("youtube.com") || url.Contains("youtu.be") || url.Contains("twitch.tv") || url.Contains("vimeo.com");
		}

		public string Resolve(string url)
		{
			if (!NeedsResolution(url))
			{
				return url;
			}
			if (!File.Exists(YtDlpPath))
			{
				MelonLogger.Msg("[YoutubeVideoPlayer] yt-dlp.exe is not found, please download at Github and place it in UserData/YoutubeVideoPlayer.");
			}
			if (!File.Exists(YtDlpPath))
			{
				MelonLogger.Error("[YoutubeVideoPlayer] yt-dlp.exe is not found, please download at Github and place it in UserData/YoutubeVideoPlayer.");
				return null;
			}
			try
			{
				ProcessStartInfo startInfo = new ProcessStartInfo
				{
					FileName = YtDlpPath,
					Arguments = "-g -f \"best[ext=mp4][vcodec^=avc1]/best[ext=mp4]/best\" \"" + url + "\"",
					RedirectStandardOutput = true,
					UseShellExecute = false,
					CreateNoWindow = true
				};
				using Process process = Process.Start(startInfo);
				string text = process.StandardOutput.ReadToEnd();
				process.WaitForExit();
				string text2 = text.Split('\n')[0].Trim();
				if (string.IsNullOrEmpty(text2))
				{
					MelonLogger.Error("[YoutubeVideoPlayer] yt-dlp returned empty output.");
					return null;
				}
				return text2;
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[YoutubeVideoPlayer] Exception: " + ex.Message);
				return null;
			}
		}
	}
	public class YoutubeSyncMessage : NativeMessageHandler
	{
		public override byte Tag => 225;

		public static void BroadcastLink(string link)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(link))
			{
				return;
			}
			MelonLogger.Msg("[YoutubeVideoPlayer] Broadcasting video to clients...");
			if (NetworkInfo.HasServer)
			{
				NetWriter val = NetWriter.Create();
				try
				{
					val.Write(link);
					RelayType val2 = (RelayType)((!NetworkInfo.IsHost) ? 1 : 3);
					NetMessage val3 = NetMessage.Create((byte)225, val, new MessageRoute(val2, (NetworkChannel)0), (byte?)null);
					try
					{
						if (NetworkInfo.IsHost)
						{
							MessageSender.BroadcastMessageExceptSelf((NetworkChannel)0, val3);
						}
						else
						{
							MessageSender.SendToServer((NetworkChannel)0, val3);
						}
					}
					finally
					{
						((IDisposable)val3)?.Dispose();
					}
				}
				finally
				{
					((IDisposable)val)?.Dispose();
				}
			}
			ProcessLink(link);
		}

		protected override void OnHandleMessage(ReceivedMessage received)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			string text = string.Empty;
			try
			{
				NetReader val = NetReader.Create(((ReceivedMessage)(ref received)).Bytes);
				try
				{
					text = val.ReadString();
				}
				finally
				{
					((IDisposable)val)?.Dispose();
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[YoutubeVideoPlayer] Failed to read network message: " + ex.Message);
				return;
			}
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			MelonLogger.Msg("[YoutubeVideoPlayer] Network received link: " + text);
			if (NetworkInfo.IsHost)
			{
				NetWriter val2 = NetWriter.Create();
				try
				{
					val2.Write(text);
					NetMessage val3 = NetMessage.Create((byte)225, val2, new MessageRoute((RelayType)3, (NetworkChannel)0), (byte?)null);
					try
					{
						MessageSender.BroadcastMessageExcept(((ReceivedMessage)(ref received)).Sender.GetValueOrDefault(), (NetworkChannel)0, val3, false);
					}
					finally
					{
						((IDisposable)val3)?.Dispose();
					}
				}
				finally
				{
					((IDisposable)val2)?.Dispose();
				}
			}
			ProcessLink(text);
		}

		private static void ProcessLink(string originalUrl)
		{
			Task.Run(delegate
			{
				string resolved = VideoManager.ResolveUrl(originalUrl);
				Core.MainThreadQueue.Enqueue(delegate
				{
					VideoManager.ScanScene();
					MelonLogger.Msg($"[YoutubeVideoPlayer] ProcessLink firing, {VideoManager._players.Count} players registered.");
					foreach (VideoPlayer player in VideoManager._players)
					{
						if ((Object)(object)player != (Object)null && !string.IsNullOrEmpty(resolved))
						{
							MelonLogger.Msg("[YoutubeVideoPlayer] Applying MP4 to player...");
							VideoPlayerEarlyPatch.IsRPCProcessing = true;
							player.url = resolved;
							player.Play();
							VideoPlayerEarlyPatch.IsRPCProcessing = false;
						}
					}
				});
			});
		}
	}
	[HarmonyPatch(typeof(URLWhitelistManager), "IsURLWhitelisted")]
	public static class WhitelistBypassPatch
	{
		private static bool Prefix(string url, ref bool __result)
		{
			if (!string.IsNullOrEmpty(url) && url.Contains("googlevideo.com"))
			{
				__result = true;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	[HarmonyPriority(800)]
	public static class VideoPlayerEarlyPatch
	{
		public static bool IsRPCProcessing;

		public static string GuardedUrl;

		private static string _lastTriggeredUrl;

		private static float _lastTriggerTime;

		private const float DebounceSeconds = 1f;

		private static bool Prefix(VideoPlayer __instance, ref string value)
		{
			if (IsRPCProcessing)
			{
				GuardedUrl = value;
				return true;
			}
			string text = value;
			string systemCopyBuffer = GUIUtility.systemCopyBuffer;
			if (!UrlResolver.NeedsResolution(text) && UrlResolver.NeedsResolution(systemCopyBuffer))
			{
				text = systemCopyBuffer;
			}
			if (UrlResolver.NeedsResolution(text))
			{
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				if (text == _lastTriggeredUrl && realtimeSinceStartup - _lastTriggerTime < 1f)
				{
					return false;
				}
				_lastTriggeredUrl = text;
				_lastTriggerTime = realtimeSinceStartup;
				MelonLogger.Msg("[YoutubeVideoPlayer] Link found: " + text);
				YoutubeSyncMessage.BroadcastLink(text);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	[HarmonyPriority(0)]
	public static class VideoPlayerLatePatch
	{
		private static void Prefix(ref string value)
		{
			if (VideoPlayerEarlyPatch.IsRPCProcessing && VideoPlayerEarlyPatch.GuardedUrl != null && value != VideoPlayerEarlyPatch.GuardedUrl)
			{
				MelonLogger.Msg("[YoutubeVideoPlayer] Restoring guarded URL.");
				value = VideoPlayerEarlyPatch.GuardedUrl;
			}
		}
	}
	[HarmonyPatch(typeof(VideoPlayer), "Prepare")]
	public static class VideoPlayerPreparePatch
	{
		private static bool Prefix(VideoPlayer __instance)
		{
			return !string.IsNullOrEmpty(__instance.url);
		}
	}
	[HarmonyPatch(typeof(VideoPlayer), "Play")]
	public static class VideoPlayerPlayPatch
	{
		private static bool Prefix(VideoPlayer __instance)
		{
			return !string.IsNullOrEmpty(__instance.url);
		}
	}
	public static class VideoManager
	{
		public static readonly List<VideoPlayer> _players = new List<VideoPlayer>();

		public static void ScanScene()
		{
			_players.Clear();
			Il2CppArrayBase<VideoPlayer> val = Object.FindObjectsOfType<VideoPlayer>();
			foreach (VideoPlayer item in val)
			{
				RegisterVideoPlayer(item);
			}
			MelonLogger.Msg($"[YoutubeVideoPlayer] Found {_players.Count} VideoPlayer(s) in scene.");
		}

		public static void RegisterVideoPlayer(VideoPlayer vp)
		{
			if (!((Object)(object)vp == (Object)null) && !_players.Contains(vp))
			{
				_players.Add(vp);
				SetupVideoPlayer(vp);
				MelonLogger.Msg("[YoutubeVideoPlayer] Registered: " + ((Object)((Component)vp).gameObject).name);
			}
		}

		private static void SetupVideoPlayer(VideoPlayer vp)
		{
			MeshRenderer component = ((Component)vp).gameObject.GetComponent<MeshRenderer>();
			if ((Object)(object)component != (Object)null && (Object)(object)((Renderer)component).material != (Object)null)
			{
				vp.renderMode = (VideoRenderMode)3;
				vp.targetMaterialRenderer = (Renderer)(object)component;
				if (((Renderer)component).material.HasProperty("_BaseMap"))
				{
					vp.targetMaterialProperty = "_BaseMap";
				}
				else if (((Renderer)component).material.HasProperty("_MainTex"))
				{
					vp.targetMaterialProperty = "_MainTex";
				}
			}
		}

		public static string ResolveUrl(string url)
		{
			if (string.IsNullOrEmpty(url))
			{
				return url;
			}
			return new UrlResolver().Resolve(url);
		}
	}
	public class Core : MelonMod
	{
		public static readonly ConcurrentQueue<Action> MainThreadQueue = new ConcurrentQueue<Action>();

		public static Core Instance { get; private set; }

		public override void OnInitializeMelon()
		{
			Instance = this;
			Hooking.OnLevelLoaded += OnLevelLoaded;
			((MelonBase)this).HarmonyInstance.PatchAll();
			if (MelonTypeBase<MelonMod>.RegisteredMelons.Any((MelonMod m) => ((MelonBase)m).Info.Name == "LabFusion"))
			{
				NativeMessageHandler.RegisterHandler<YoutubeSyncMessage>();
			}
		}

		public override void OnUpdate()
		{
			Action result;
			while (MainThreadQueue.TryDequeue(out result))
			{
				result?.Invoke();
			}
		}

		private void OnLevelLoaded(LevelInfo levelInfo)
		{
			VideoManager.ScanScene();
		}
	}
	[HarmonyPatch(typeof(Poolee), "OnSpawn")]
	public static class PooleeOnSpawnPatch
	{
		[HarmonyPostfix]
		public static void Postfix(Poolee __instance)
		{
			GameObject gameObject = ((Component)__instance).gameObject;
			if (!((Object)(object)gameObject == (Object)null))
			{
				VideoPlayer componentInChildren = gameObject.GetComponentInChildren<VideoPlayer>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					VideoManager.RegisterVideoPlayer(componentInChildren);
				}
			}
		}
	}
}