Decompiled source of YoutubeBoomBox v1.1.0

Plugins/YoutubeBoomBox.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("YoutubeBoomBox")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Streams youtube playlists and videos to ingame boombox.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+4444ff9dc260a77207078e9c5b31504859739239")]
[assembly: AssemblyProduct("YoutubeBoomBox")]
[assembly: AssemblyTitle("YoutubeBoomBox")]
[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 YoutubeBoomBox
{
	public class AudioQueue
	{
		private static readonly List<string> _inputs = new List<string>();

		private static int _ptr = 0;

		public static void Add(string input)
		{
			if (input.Length == 11 && !input.Contains(" "))
			{
				_inputs.Add("https://www.youtube.com/watch?v=" + input);
			}
			else
			{
				_inputs.Add("ytsearch:" + input);
			}
		}

		public static void Clear()
		{
			_inputs.Clear();
		}

		public static bool IsEmpty()
		{
			return _inputs.Count == 0;
		}

		public static string Next()
		{
			string result = _inputs[_ptr];
			_ptr = (_ptr + 1) % _inputs.Count;
			return result;
		}
	}
	public class AudioStreamer : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass12_0
		{
			public string audioUrl;

			internal void <StreamAudio>b__0(string aUrl)
			{
				audioUrl = aUrl;
			}
		}

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

			private object <>2__current;

			public AudioStreamer <>4__this;

			public string input;

			public string ytDlpPath;

			public Action<string> onUrlFound;

			private Process <process>5__2;

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

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

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

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

			private bool MoveNext()
			{
				int num = <>1__state;
				AudioStreamer audioStreamer = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					audioStreamer._isFound = false;
					YoutubeBoomBoxPlugin.Logger.LogInfo((object)"Finding audio url...");
					string arguments = ((!input.StartsWith("ytsearch:")) ? ("-f bestaudio --no-playlist -g -- \"" + input + "\"") : ("-f bestaudio --match-filter \"duration < 1800\" \"" + input + "\" -g"));
					<process>5__2 = new Process
					{
						StartInfo = new ProcessStartInfo
						{
							FileName = ytDlpPath,
							Arguments = arguments,
							RedirectStandardOutput = true,
							RedirectStandardError = true,
							UseShellExecute = false,
							CreateNoWindow = true
						}
					};
					<process>5__2.Start();
					break;
				}
				case 1:
					<>1__state = -1;
					break;
				}
				if (!<process>5__2.HasExited)
				{
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				string text = <process>5__2.StandardOutput.ReadToEnd().Trim();
				string arg = <process>5__2.StandardError.ReadToEnd().Trim();
				if (<process>5__2.ExitCode != 0 || string.IsNullOrEmpty(text))
				{
					YoutubeBoomBoxPlugin.Logger.LogError((object)$"yt-dlp failed (Exit Code: {<process>5__2.ExitCode}): {arg}");
					onUrlFound(null);
				}
				else
				{
					YoutubeBoomBoxPlugin.Logger.LogInfo((object)"Found!");
					onUrlFound(text);
				}
				audioStreamer._isFound = 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 <LoadAudio>d__13 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public AudioStreamer <>4__this;

			public Action<AudioClip> onLoaded;

			private UnityWebRequest <www>5__2;

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

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

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

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

			private bool MoveNext()
			{
				//IL_008b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0091: Invalid comparison between Unknown and I4
				//IL_0099: Unknown result type (might be due to invalid IL or missing references)
				//IL_009f: Invalid comparison between Unknown and I4
				bool result;
				try
				{
					int num = <>1__state;
					AudioStreamer audioStreamer = <>4__this;
					switch (num)
					{
					default:
						result = false;
						break;
					case 0:
						<>1__state = -1;
						audioStreamer._isLoading = true;
						YoutubeBoomBoxPlugin.Logger.LogInfo((object)"Loading audio...");
						<www>5__2 = UnityWebRequestMultimedia.GetAudioClip("file://" + audioStreamer._streamFilePath, (AudioType)14);
						<>1__state = -3;
						<>2__current = <www>5__2.SendWebRequest();
						<>1__state = 1;
						result = true;
						break;
					case 1:
						<>1__state = -3;
						if ((int)<www>5__2.result == 2 || (int)<www>5__2.result == 3)
						{
							YoutubeBoomBoxPlugin.Logger.LogError((object)("Error loading audio: " + <www>5__2.error));
						}
						else
						{
							YoutubeBoomBoxPlugin.Logger.LogInfo((object)"Loaded!");
							onLoaded(DownloadHandlerAudioClip.GetContent(<www>5__2));
						}
						audioStreamer._isLoading = false;
						result = false;
						<>m__Finally1();
						break;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result;
			}

			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 (<www>5__2 != null)
				{
					((IDisposable)<www>5__2).Dispose();
				}
			}

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

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

			private object <>2__current;

			public AudioStreamer <>4__this;

			public string input;

			public Action<AudioClip> onLoaded;

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

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

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

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

			private bool MoveNext()
			{
				int num = <>1__state;
				AudioStreamer audioStreamer = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = audioStreamer.StreamAudio(input);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					goto IL_006c;
				case 2:
					<>1__state = -1;
					goto IL_006c;
				case 3:
					<>1__state = -1;
					break;
				case 4:
					{
						<>1__state = -1;
						break;
					}
					IL_006c:
					if (audioStreamer._isStreaming)
					{
						<>2__current = null;
						<>1__state = 2;
						return true;
					}
					<>2__current = audioStreamer.LoadAudio(onLoaded);
					<>1__state = 3;
					return true;
				}
				if (audioStreamer._isLoading)
				{
					<>2__current = null;
					<>1__state = 4;
					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 <StreamAudio>d__12 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public AudioStreamer <>4__this;

			public string url;

			private <>c__DisplayClass12_0 <>8__1;

			private Process <process>5__2;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>8__1 = null;
				<process>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				AudioStreamer audioStreamer = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass12_0();
					audioStreamer._isStreaming = true;
					<>8__1.audioUrl = null;
					<>2__current = audioStreamer.GetYouTubeAudioUrl(audioStreamer._ytDlpPath, url, delegate(string aUrl)
					{
						<>8__1.audioUrl = aUrl;
					});
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					goto IL_009d;
				case 2:
					<>1__state = -1;
					goto IL_009d;
				case 3:
					{
						<>1__state = -1;
						break;
					}
					IL_009d:
					if (!audioStreamer._isFound)
					{
						<>2__current = null;
						<>1__state = 2;
						return true;
					}
					YoutubeBoomBoxPlugin.Logger.LogInfo((object)"Starting audio file stream...");
					if (string.IsNullOrEmpty(<>8__1.audioUrl))
					{
						YoutubeBoomBoxPlugin.Logger.LogError((object)"Failed to get YouTube audio URL.");
						return false;
					}
					<process>5__2 = new Process
					{
						StartInfo = new ProcessStartInfo
						{
							FileName = audioStreamer._ffmpegPath,
							Arguments = "-y -nostdin -loglevel error -i \"" + <>8__1.audioUrl + "\" -vn -acodec libvorbis -f ogg \"" + audioStreamer._streamFilePath + "\"",
							RedirectStandardOutput = true,
							RedirectStandardError = true,
							UseShellExecute = false,
							CreateNoWindow = true
						}
					};
					<process>5__2.Start();
					<process>5__2.BeginOutputReadLine();
					<process>5__2.BeginErrorReadLine();
					break;
				}
				if (!<process>5__2.HasExited)
				{
					<>2__current = null;
					<>1__state = 3;
					return true;
				}
				YoutubeBoomBoxPlugin.Logger.LogInfo((object)"Streamed.");
				audioStreamer._isStreaming = false;
				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 string _streamFilePath;

		private string _ytDlpPath;

		private string _ffmpegPath;

		private static AudioStreamer _instance;

		private bool _isStreaming;

		private bool _isLoading;

		private bool _isFound = true;

		public static AudioStreamer Instance
		{
			get
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_instance == (Object)null)
				{
					_instance = new GameObject("AudioStreamer").AddComponent<AudioStreamer>();
					Object.DontDestroyOnLoad((Object)(object)((Component)_instance).gameObject);
				}
				return _instance;
			}
		}

		private void Awake()
		{
			_streamFilePath = Path.Combine(Application.temporaryCachePath, "stream.ogg");
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			_ffmpegPath = Path.Combine(directoryName, "ffmpeg.exe");
			_ytDlpPath = Path.Combine(directoryName, "yt-dlp.exe");
		}

		public void Load(string input, Action<AudioClip> onLoaded)
		{
			((MonoBehaviour)this).StartCoroutine(StartStreaming(input, onLoaded));
		}

		[IteratorStateMachine(typeof(<StartStreaming>d__10))]
		private IEnumerator StartStreaming(string input, Action<AudioClip> onLoaded)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <StartStreaming>d__10(0)
			{
				<>4__this = this,
				input = input,
				onLoaded = onLoaded
			};
		}

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

		[IteratorStateMachine(typeof(<LoadAudio>d__13))]
		private IEnumerator LoadAudio(Action<AudioClip> onLoaded)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadAudio>d__13(0)
			{
				<>4__this = this,
				onLoaded = onLoaded
			};
		}

		[IteratorStateMachine(typeof(<GetYouTubeAudioUrl>d__14))]
		private IEnumerator GetYouTubeAudioUrl(string ytDlpPath, string input, Action<string> onUrlFound)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <GetYouTubeAudioUrl>d__14(0)
			{
				<>4__this = this,
				ytDlpPath = ytDlpPath,
				input = input,
				onUrlFound = onUrlFound
			};
		}
	}
	public class DirectAudioStreamer : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass10_0
		{
			public Process process;

			public DirectAudioStreamer <>4__this;

			internal void <StreamFromYt>b__0()
			{
				byte[] array = new byte[4096];
				using Stream stream = process.StandardOutput.BaseStream;
				int num;
				while ((num = stream.Read(array, 0, array.Length)) > 0)
				{
					for (int i = 0; i < num; i += 2)
					{
						short num2 = BitConverter.ToInt16(array, i);
						<>4__this._sampleBuffer.Enqueue((float)num2 / 32768f);
					}
				}
			}
		}

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

			private object <>2__current;

			public DirectAudioStreamer <>4__this;

			public string input;

			public Action<AudioClip> onStreaming;

			private <>c__DisplayClass10_0 <>8__1;

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

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

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

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

			private bool MoveNext()
			{
				//IL_010f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0119: Expected O, but got Unknown
				int num = <>1__state;
				DirectAudioStreamer directAudioStreamer = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass10_0();
					<>8__1.<>4__this = <>4__this;
					<>8__1.process = new Process
					{
						StartInfo = new ProcessStartInfo
						{
							FileName = "cmd.exe",
							Arguments = directAudioStreamer.YtDlpPath + " -q -f bestaudio $" + input + " -o - | $" + directAudioStreamer.FfmpegPath + " -hide_banner -loglevel error -i pipe: -map 0 -c copy -ac 2 -f s16le -ar 48000 pipe:",
							CreateNoWindow = true,
							UseShellExecute = false,
							RedirectStandardInput = true,
							RedirectStandardOutput = true
						}
					};
					<>8__1.process.Start();
					Task.Run(delegate
					{
						byte[] array = new byte[4096];
						using Stream stream = <>8__1.process.StandardOutput.BaseStream;
						int num2;
						while ((num2 = stream.Read(array, 0, array.Length)) > 0)
						{
							for (int i = 0; i < num2; i += 2)
							{
								short num3 = BitConverter.ToInt16(array, i);
								<>8__1.<>4__this._sampleBuffer.Enqueue((float)num3 / 32768f);
							}
						}
					});
					AudioClip obj = AudioClip.Create("Stream", int.MaxValue, 2, 48000, true, new PCMReaderCallback(directAudioStreamer.OnAudioRead));
					onStreaming(obj);
					break;
				}
				case 1:
					<>1__state = -1;
					break;
				}
				if (!<>8__1.process.HasExited)
				{
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				<>8__1.process.Close();
				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 DirectAudioStreamer _instance;

		private ConcurrentQueue<float> _sampleBuffer = new ConcurrentQueue<float>();

		public static DirectAudioStreamer Instance
		{
			get
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_instance == (Object)null)
				{
					_instance = new GameObject("DirectAudioStreamer").AddComponent<DirectAudioStreamer>();
					Object.DontDestroyOnLoad((Object)(object)((Component)_instance).gameObject);
				}
				return _instance;
			}
		}

		private string DllPath => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

		private string YtDlpPath => Path.Combine(DllPath, "yt-dlp.exe");

		private string FfmpegPath => Path.Combine(DllPath, "ffmpeg.exe");

		[IteratorStateMachine(typeof(<StreamFromYt>d__10))]
		public IEnumerator StreamFromYt(string input, Action<AudioClip> onStreaming)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <StreamFromYt>d__10(0)
			{
				<>4__this = this,
				input = input,
				onStreaming = onStreaming
			};
		}

		private void OnAudioRead(float[] data)
		{
			for (int i = 0; i < data.Length; i++)
			{
				if (!_sampleBuffer.TryDequeue(out data[i]))
				{
					data[i] = 0f;
				}
			}
		}
	}
	public static class Patches
	{
		private static AudioClip[] _defaultAudios;

		private static bool _play;

		private static bool _loading;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(HUDManager), "AddChatMessage")]
		public static void AddChatMessage_Postfix(string chatMessage, string nameOfUserWhoTyped, HUDManager __instance)
		{
			if (chatMessage.StartsWith("/add") && chatMessage.Length > 5)
			{
				string text = chatMessage.Substring(5, chatMessage.Length - 5).Trim();
				if (!string.IsNullOrEmpty(text))
				{
					AudioQueue.Add(text);
				}
			}
			else if (chatMessage.StartsWith("/clear"))
			{
				AudioQueue.Clear();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(BoomboxItem), "Start")]
		public static void Start_Postfix(BoomboxItem __instance)
		{
			_defaultAudios = __instance.musicAudios;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(BoomboxItem), "StartMusic")]
		public static bool StartMusic_Prefix(bool startMusic, bool pitchDown, BoomboxItem __instance)
		{
			if (_play)
			{
				_play = false;
				return true;
			}
			if (_loading)
			{
				return false;
			}
			if (!AudioQueue.IsEmpty() && startMusic)
			{
				HUDManager.Instance.AddChatMessage("Loading audio...", "");
				_loading = true;
				AudioStreamer.Instance.Load(AudioQueue.Next(), delegate(AudioClip clip)
				{
					__instance.musicAudios = (AudioClip[])(object)new AudioClip[1] { clip };
					HUDManager.Instance.AddChatMessage("Loaded!", "");
					_play = true;
					_loading = false;
					__instance.StartMusic(startMusic, pitchDown);
				});
				return false;
			}
			if (startMusic)
			{
				__instance.musicAudios = _defaultAudios;
			}
			return true;
		}
	}
	[BepInPlugin("YoutubeBoomBox", "YoutubeBoomBox", "1.1.0")]
	public class YoutubeBoomBoxPlugin : BaseUnityPlugin
	{
		private const string PLUGIN_GUID = "YoutubeBoomBox";

		private const string PLUGIN_NAME = "YoutubeBoomBox";

		private const string PLUGIN_VERSION = "1.1.0";

		private readonly Harmony _harmony = new Harmony("YoutubeBoomBox");

		public static ManualLogSource Logger { get; } = Logger.CreateLogSource("YoutubeBoomBox");


		private void Awake()
		{
			_harmony.PatchAll(typeof(Patches));
			Logger.LogInfo((object)"Plugin YoutubeBoomBox is loaded!");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "YoutubeBoomBox";

		public const string PLUGIN_NAME = "YoutubeBoomBox";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}