Decompiled source of BetterMediaControls v1.1.2

BepInEx/plugins/BetterMediaControls/BetterMediaControls.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BetterMediaControls.audio;
using BetterMediaControls.patches;
using BetterMediaControls.util;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.UI;

[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("BetterMediaControls")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.2.0")]
[assembly: AssemblyInformationalVersion("1.1.2+69a1d6ea6a4b377b112daf6e92964b74cc53e464")]
[assembly: AssemblyProduct("Better Media Controls")]
[assembly: AssemblyTitle("BetterMediaControls")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.2.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 BetterMediaControls
{
	[BepInPlugin("com.patty.bettermediacontrols", "BetterMediaControls", "1.1.2")]
	[BepInProcess("OnTogether.exe")]
	public class Plugin : BaseUnityPlugin
	{
		private const string PluginGUID = "com.patty.bettermediacontrols";

		private const string PluginName = "BetterMediaControls";

		private const string PluginVersion = "1.1.2";

		private const string PluginAuthor = "CutiePatooties";

		private readonly Harmony _harmony = new Harmony("com.patty.bettermediacontrols");

		private ConfigEntry<string> _configMusicDir;

		private ConfigEntry<bool> _configVanillaMusicEnabled;

		private ConfigEntry<bool> _configShuffleEnabled;

		public static Plugin Instance { get; private set; }

		public bool IsVanillaMusicEnabled => _configVanillaMusicEnabled.Value;

		public bool IsShuffleEnabled => _configShuffleEnabled.Value;

		public static ManualLogSource Log { get; private set; }

		public Sprite ShuffleOnSprite { get; private set; }

		public Sprite ShuffleOffSprite { get; private set; }

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			_configMusicDir = ((BaseUnityPlugin)this).Config.Bind<string>("General", "MusicDirectory", Path.Combine(Paths.ConfigPath, "BetterMediaControls-Music"), "Supports .wav, .ogg, and .mp3 files. Directory inside the plugin folder where custom music is stored.");
			_configVanillaMusicEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableVanillaMusic", true, "If true, the game's original music will still show up alongside custom tracks.");
			_configShuffleEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Playback", "EnableShuffle", false, "self explanatory. uses spotify shuffle (Fisher–Yates) algorithm.");
			string path = Path.Combine(Paths.PluginPath, "CutiePatooties-BetterMediaControls", "BetterMediaControls", "icons");
			ShuffleOnSprite = SpriteLoader.LoadSprite(Path.Combine(path, "Shuffle.png"));
			ShuffleOffSprite = SpriteLoader.LoadSprite(Path.Combine(path, "ShuffleUnchecked.png"));
			if ((Object)(object)ShuffleOnSprite == (Object)null || (Object)(object)ShuffleOffSprite == (Object)null)
			{
				Log.LogWarning((object)"Shuffle icons missing or failed to load");
			}
			string musicDirectory = GetMusicDirectory();
			if (!Directory.Exists(musicDirectory))
			{
				try
				{
					Directory.CreateDirectory(musicDirectory);
					Log.LogInfo((object)("Created music directory at " + musicDirectory));
				}
				catch (Exception arg)
				{
					Log.LogError((object)$"Failed to create music directory at {musicDirectory}: {arg}");
				}
			}
			string text = Path.Combine(musicDirectory, "playlist.json");
			if (!File.Exists(text))
			{
				try
				{
					File.WriteAllText(text, "{\"playlist\":[]}");
					Log.LogInfo((object)("Created empty playlist.json at " + text));
				}
				catch (Exception arg2)
				{
					Log.LogError((object)$"Failed to create playlist.json at {text}: {arg2}");
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin com.patty.bettermediacontrols is loaded!");
			_harmony.PatchAll();
		}

		public void ToggleShuffle()
		{
			_configShuffleEnabled.Value = !_configShuffleEnabled.Value;
			if (_configShuffleEnabled.Value)
			{
				ShufflePatch.ResetShuffle();
			}
			Log.LogInfo((object)("Shuffle " + (IsShuffleEnabled ? "enabled" : "disabled")));
		}

		public string GetMusicDirectory()
		{
			string value = _configMusicDir.Value;
			value = Environment.ExpandEnvironmentVariables(value);
			if (Path.IsPathRooted(value))
			{
				return value;
			}
			return Path.Combine(Paths.ConfigPath, "BetterMediaControls-Music");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "BetterMediaControls";

		public const string PLUGIN_NAME = "Better Media Controls";

		public const string PLUGIN_VERSION = "1.1.2";
	}
}
namespace BetterMediaControls.util
{
	public static class ReflectionUtils
	{
		public static object GetField(object instance, string fieldName)
		{
			if (instance != null)
			{
				return AccessTools.Field(instance.GetType(), fieldName)?.GetValue(instance);
			}
			return null;
		}

		public static T GetField<T>(object instance, string fieldName) where T : class
		{
			return GetField(instance, fieldName) as T;
		}
	}
	public static class SpriteLoader
	{
		public static Sprite LoadSprite(string path)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0077: 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)
			if (!File.Exists(path))
			{
				Plugin.Log.LogWarning((object)("Sprite not found: " + path));
				return null;
			}
			byte[] array = File.ReadAllBytes(path);
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!ImageConversion.LoadImage(val, array))
			{
				Plugin.Log.LogError((object)("Failed to load image: " + path));
				return null;
			}
			((Texture)val).filterMode = (FilterMode)1;
			((Texture)val).wrapMode = (TextureWrapMode)1;
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
		}
	}
}
namespace BetterMediaControls.patches
{
	[HarmonyPatch(typeof(SoundManager))]
	public static class MediaPatch
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass1_0
		{
			public AudioClip clip;

			internal void <InjectSong>b__0(AudioClip c)
			{
				clip = c;
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass1_1
		{
			public AudioClip clip;

			internal void <InjectSong>b__1(AudioClip c)
			{
				clip = c;
			}
		}

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

			private object <>2__current;

			public SoundManager soundManager;

			private <>c__DisplayClass1_0 <>8__1;

			private <>c__DisplayClass1_1 <>8__2;

			private ManualLogSource <log>5__2;

			private string <musicDir>5__3;

			private PlaylistFile <playlistFile>5__4;

			private IList <songs>5__5;

			private int <i>5__6;

			private PlaylistEntry <entry>5__7;

			private string <audioPath>5__8;

			private string[] <files>5__9;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>8__1 = null;
				<>8__2 = null;
				<log>5__2 = null;
				<musicDir>5__3 = null;
				<playlistFile>5__4 = null;
				<songs>5__5 = null;
				<entry>5__7 = null;
				<audioPath>5__8 = null;
				<files>5__9 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
				//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
				//IL_04ba: Unknown result type (might be due to invalid IL or missing references)
				//IL_04bf: Unknown result type (might be due to invalid IL or missing references)
				//IL_04d0: Unknown result type (might be due to invalid IL or missing references)
				//IL_04db: Unknown result type (might be due to invalid IL or missing references)
				//IL_04ec: Unknown result type (might be due to invalid IL or missing references)
				//IL_04f9: Expected O, but got Unknown
				//IL_0324: Unknown result type (might be due to invalid IL or missing references)
				//IL_034e: Unknown result type (might be due to invalid IL or missing references)
				//IL_035f: Unknown result type (might be due to invalid IL or missing references)
				//IL_038b: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					<log>5__2 = Plugin.Log;
					if (!Object.op_Implicit((Object)(object)Plugin.Instance))
					{
						<log>5__2.LogError((object)"Plugin instance is null");
						return false;
					}
					<musicDir>5__3 = Plugin.Instance.GetMusicDirectory();
					string text = Path.Combine(<musicDir>5__3, "playlist.json");
					<playlistFile>5__4 = null;
					bool flag = File.Exists(text);
					if (!flag)
					{
						<log>5__2.LogWarning((object)("No playlist.json found at " + text + ", falling back to directory scan"));
					}
					else
					{
						try
						{
							string text2 = File.ReadAllText(text);
							<playlistFile>5__4 = JsonConvert.DeserializeObject<PlaylistFile>(text2);
							if (<playlistFile>5__4?.Playlist == null)
							{
								<log>5__2.LogError((object)"playlist.json parsed, but playlist is null");
								return false;
							}
							<log>5__2.LogDebug((object)$"Parsed playlist.json with {<playlistFile>5__4.Playlist.Count} entries");
						}
						catch (Exception arg)
						{
							<log>5__2.LogError((object)$"Failed to parse playlist.json: {arg}");
							return false;
						}
					}
					object field = ReflectionUtils.GetField(soundManager, "_mixtapes");
					if (field == null)
					{
						<log>5__2.LogError((object)"_mixtapes is null");
						return false;
					}
					IList field2 = ReflectionUtils.GetField<IList>(field, "MixTapes");
					if (field2 == null || field2.Count == 0)
					{
						<log>5__2.LogError((object)"MixTapes is null or empty");
						return false;
					}
					object instance = field2[0];
					<songs>5__5 = ReflectionUtils.GetField<IList>(instance, "Songs");
					if (<songs>5__5 == null)
					{
						<log>5__2.LogError((object)"Songs is null");
						return false;
					}
					if (!Plugin.Instance.IsVanillaMusicEnabled)
					{
						<songs>5__5.Clear();
					}
					if (flag)
					{
						<i>5__6 = <playlistFile>5__4.Playlist.Count - 1;
						goto IL_03e8;
					}
					<files>5__9 = Directory.GetFiles(<musicDir>5__3);
					<i>5__6 = <files>5__9.Length - 1;
					goto IL_0543;
				}
				case 1:
					<>1__state = -1;
					if (!Object.op_Implicit((Object)(object)<>8__1.clip))
					{
						<log>5__2.LogError((object)("Failed to load audio: " + <audioPath>5__8));
					}
					else
					{
						Song val2 = new Song
						{
							Title = (string.IsNullOrEmpty(<entry>5__7.Title) ? Path.GetFileNameWithoutExtension(<entry>5__7.File) : <entry>5__7.Title),
							Artist = (string.IsNullOrEmpty(<entry>5__7.Artist) ? "Unknown" : <entry>5__7.Artist),
							Music = <>8__1.clip,
							Volume = ((<entry>5__7.Volume > 0f) ? <entry>5__7.Volume : 1f)
						};
						<songs>5__5.Insert(0, val2);
						<log>5__2.LogDebug((object)("Added song: " + val2.Title + " by " + val2.Artist));
						<>8__1 = null;
						<entry>5__7 = null;
						<audioPath>5__8 = null;
					}
					goto IL_03d6;
				case 2:
					{
						<>1__state = -1;
						if (!Object.op_Implicit((Object)(object)<>8__2.clip))
						{
							<log>5__2.LogError((object)("Failed to load audio: " + <audioPath>5__8));
						}
						else
						{
							Song val = new Song
							{
								Title = Path.GetFileNameWithoutExtension(<audioPath>5__8),
								Artist = "Unknown",
								Music = <>8__2.clip,
								Volume = 0.5f
							};
							<songs>5__5.Insert(0, val);
							<log>5__2.LogDebug((object)("Added fallback song: " + val.Title));
							<>8__2 = null;
							<audioPath>5__8 = null;
						}
						goto IL_0531;
					}
					IL_0531:
					<i>5__6--;
					goto IL_0543;
					IL_03d6:
					<i>5__6--;
					goto IL_03e8;
					IL_0543:
					if (<i>5__6 >= 0)
					{
						<>8__2 = new <>c__DisplayClass1_1();
						<audioPath>5__8 = <files>5__9[<i>5__6];
						if (AudioLoader.IsSupportedFile(<audioPath>5__8))
						{
							<>8__2.clip = null;
							<>2__current = AudioLoader.LoadAudio(<audioPath>5__8, delegate(AudioClip c)
							{
								<>8__2.clip = c;
							});
							<>1__state = 2;
							return true;
						}
						goto IL_0531;
					}
					<files>5__9 = null;
					break;
					IL_03e8:
					if (<i>5__6 < 0)
					{
						break;
					}
					<>8__1 = new <>c__DisplayClass1_0();
					<entry>5__7 = <playlistFile>5__4.Playlist[<i>5__6];
					<audioPath>5__8 = Path.Combine(<musicDir>5__3, <entry>5__7.File);
					if (!File.Exists(<audioPath>5__8))
					{
						<log>5__2.LogError((object)("Missing audio file: " + <audioPath>5__8));
						goto IL_03d6;
					}
					<log>5__2.LogDebug((object)("Loading song: " + <audioPath>5__8));
					<>8__1.clip = null;
					<>2__current = AudioLoader.LoadAudio(<audioPath>5__8, delegate(AudioClip c)
					{
						<>8__1.clip = c;
					});
					<>1__state = 1;
					return true;
				}
				<log>5__2.LogInfo((object)$"Final song count: {<songs>5__5.Count}");
				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();
			}
		}

		[HarmonyPatch("Start")]
		public static void Postfix(SoundManager __instance)
		{
			((MonoBehaviour)__instance).StartCoroutine(InjectSong(__instance));
		}

		[IteratorStateMachine(typeof(<InjectSong>d__1))]
		private static IEnumerator InjectSong(SoundManager soundManager)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <InjectSong>d__1(0)
			{
				soundManager = soundManager
			};
		}
	}
	[HarmonyPatch(typeof(SoundManager), "ChangeSong")]
	[HarmonyPatch(new Type[] { typeof(bool) })]
	public static class ShufflePatch
	{
		private static readonly List<int> ShuffledOrder = new List<int>();

		private static int _shufflePosition;

		private static int _lastMixtapeIndex = -1;

		private static readonly MethodInfo ChangeSongClipMethod = AccessTools.Method(typeof(SoundManager), "ChangeSongClip", (Type[])null, (Type[])null);

		private static void Shuffle(List<int> list)
		{
			for (int num = list.Count - 1; num > 0; num--)
			{
				int num2 = Random.Range(0, num + 1);
				int index = num;
				int index2 = num2;
				int value = list[num2];
				int value2 = list[num];
				list[index] = value;
				list[index2] = value2;
			}
		}

		[HarmonyPrefix]
		public static bool Prefix(SoundManager __instance, bool isNext)
		{
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Expected O, but got Unknown
			if (!Plugin.Instance.IsShuffleEnabled)
			{
				return true;
			}
			IList field = ReflectionUtils.GetField<IList>(ReflectionUtils.GetField(__instance, "_mixtapes"), "MixTapes");
			if (field == null || field.Count == 0)
			{
				return true;
			}
			int num = (int)ReflectionUtils.GetField(__instance, "_mixtapeIndex");
			int item = (int)ReflectionUtils.GetField(__instance, "_songIndex");
			if (num != _lastMixtapeIndex)
			{
				ShuffledOrder.Clear();
				_shufflePosition = 0;
				_lastMixtapeIndex = num;
			}
			IList field2 = ReflectionUtils.GetField<IList>(field[num], "Songs");
			if (field2 == null || field2.Count == 0)
			{
				return true;
			}
			if (ShuffledOrder.Count != field2.Count)
			{
				ShuffledOrder.Clear();
				for (int i = 0; i < field2.Count; i++)
				{
					ShuffledOrder.Add(i);
				}
				Shuffle(ShuffledOrder);
				_shufflePosition = ShuffledOrder.IndexOf(item);
				if (_shufflePosition < 0)
				{
					_shufflePosition = 0;
				}
			}
			if (isNext)
			{
				_shufflePosition++;
				if (_shufflePosition >= ShuffledOrder.Count)
				{
					_shufflePosition = 0;
				}
			}
			else
			{
				_shufflePosition--;
				if (_shufflePosition < 0)
				{
					_shufflePosition = ShuffledOrder.Count - 1;
				}
			}
			int num2 = ShuffledOrder[_shufflePosition];
			AccessTools.Field(((object)__instance).GetType(), "_songIndex").SetValue(__instance, num2);
			ChangeSongClipMethod.Invoke(__instance, null);
			MonoSingleton<UIManager>.I.UpdateSongInfo((Song)field2[num2]);
			return false;
		}

		public static void ResetShuffle()
		{
			ShuffledOrder.Clear();
			_shufflePosition = 0;
		}
	}
}
namespace BetterMediaControls.patches.ui
{
	[HarmonyPatch(typeof(UIManager), "Start")]
	public static class ShuffleUIPatch
	{
		[HarmonyPostfix]
		public static void Postfix(UIManager __instance)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Expected O, but got Unknown
			ManualLogSource log = Plugin.Log;
			Image field = ReflectionUtils.GetField<Image>(__instance, "_loopImage");
			if ((Object)(object)field == (Object)null)
			{
				log.LogError((object)"Shuffle UI: _loopImage not found");
				return;
			}
			GameObject gameObject = ((Component)field).gameObject;
			GameObject val = Object.Instantiate<GameObject>(gameObject, gameObject.transform.parent);
			((Object)val).name = "Button_Shuffle";
			Transform transform = val.transform;
			transform.localPosition += new Vector3(60f, 0f, 0f);
			Image shuffleImage = val.GetComponent<Image>();
			Button component = val.GetComponent<Button>();
			if ((Object)(object)component == (Object)null || (Object)(object)shuffleImage == (Object)null)
			{
				log.LogError((object)"Shuffle UI: missing Image or Button component");
				return;
			}
			component.onClick = new ButtonClickedEvent();
			((UnityEvent)component.onClick).AddListener((UnityAction)delegate
			{
				Plugin.Instance.ToggleShuffle();
				UpdateShuffleUI(__instance, shuffleImage);
				MonoSingleton<SFXManager>.I.PlayUIClick();
			});
			UpdateShuffleUI(__instance, shuffleImage);
			log.LogInfo((object)"Shuffle button cloned from loop button");
		}

		private static void UpdateShuffleUI(UIManager uiManager, Image shuffleImage)
		{
			bool isShuffleEnabled = Plugin.Instance.IsShuffleEnabled;
			Sprite val = Plugin.Instance.ShuffleOnSprite ?? ReflectionUtils.GetField<Sprite>(uiManager, "_loopCheckedSprite");
			Sprite val2 = Plugin.Instance.ShuffleOffSprite ?? ReflectionUtils.GetField<Sprite>(uiManager, "_loopUncheckedSprite");
			shuffleImage.sprite = (isShuffleEnabled ? val : val2);
		}
	}
}
namespace BetterMediaControls.audio
{
	public static class AudioLoader
	{
		[CompilerGenerated]
		private sealed class <LoadAudio>d__2 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string path;

			public Action<AudioClip> onLoaded;

			private UnityWebRequest <request>5__2;

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

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

			[DebuggerHidden]
			public <LoadAudio>d__2(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();
					}
				}
				<request>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//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_004d: 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_00a3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a9: Invalid comparison between Unknown and I4
				bool result;
				try
				{
					switch (<>1__state)
					{
					default:
						result = false;
						break;
					case 0:
					{
						<>1__state = -1;
						string text = "file:///" + path.Replace("\\", "/");
						AudioType audioType = GetAudioType(path);
						<request>5__2 = UnityWebRequestMultimedia.GetAudioClip(text, audioType);
						<>1__state = -3;
						((DownloadHandlerAudioClip)<request>5__2.downloadHandler).streamAudio = true;
						<>2__current = <request>5__2.SendWebRequest();
						<>1__state = 1;
						result = true;
						break;
					}
					case 1:
						<>1__state = -3;
						if ((int)<request>5__2.result != 1)
						{
							Plugin.Log.LogError((object)("Failed to load audio " + path + ": " + <request>5__2.error));
							onLoaded(null);
							result = false;
							<>m__Finally1();
						}
						else
						{
							AudioClip content = DownloadHandlerAudioClip.GetContent(<request>5__2);
							((Object)content).name = Path.GetFileNameWithoutExtension(path);
							onLoaded(content);
							<>m__Finally1();
							<request>5__2 = null;
							result = false;
						}
						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 (<request>5__2 != null)
				{
					((IDisposable)<request>5__2).Dispose();
				}
			}

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

		private static readonly string[] SupportedExtensions = new string[3] { ".wav", ".ogg", ".mp3" };

		public static bool IsSupportedFile(string path)
		{
			string extension = Path.GetExtension(path);
			string[] supportedExtensions = SupportedExtensions;
			foreach (string b in supportedExtensions)
			{
				if (string.Equals(extension, b, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		[IteratorStateMachine(typeof(<LoadAudio>d__2))]
		public static IEnumerator LoadAudio(string path, Action<AudioClip> onLoaded)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadAudio>d__2(0)
			{
				path = path,
				onLoaded = onLoaded
			};
		}

		private static AudioType GetAudioType(string path)
		{
			return (AudioType)(Path.GetExtension(path)?.ToLowerInvariant() switch
			{
				".ogg" => 14, 
				".mp3" => 13, 
				".wav" => 20, 
				_ => 0, 
			});
		}
	}
	public class PlaylistFile
	{
		public List<PlaylistEntry> Playlist;
	}
	public class PlaylistEntry
	{
		public string File;

		public string Title;

		public string Artist;

		public float Volume = 1f;
	}
}