Decompiled source of Sound Changer v2.0.0
Patty_SoundChanger_MOD.dll
Decompiled 2 months 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.Collections.Specialized; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using ATL; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using I2.Loc; using ShinyShoe; using ShinyShoe.Audio; using ShinyShoe.Loading; using TMPro; using UnityEngine; using UnityEngine.Networking; using UnityEngine.U2D; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Patty_SoundChanger_MOD")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Patty_SoundChanger_MOD")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("33a86151-483d-4513-8190-9fd71a0bf018")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace Patty_SoundChanger_MOD; internal sealed class ConfigurationManagerAttributes { public delegate void CustomHotkeyDrawerFunc(ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput); public bool? ShowRangeAsPercent; public Action<ConfigEntryBase> CustomDrawer; public CustomHotkeyDrawerFunc CustomHotkeyDrawer; public bool? Browsable; public string Category; public object DefaultValue; public bool? HideDefaultButton; public bool? HideSettingName; public string Description; public string DispName; public int? Order; public bool? ReadOnly; public bool? IsAdvanced; public Func<object, string> ObjToStr; public Func<string, object> StrToObj; } public interface ISoundChanger { SoundData<MusicDefinition> CreateNewMusicEntry(string entryName, string description = "", string defaultVal = ""); SoundData<SoundCueDefinition> CreateNewSFXEntry(string entryName, string description = "", string defaultVal = ""); BattleMusicTrack RegisterToBattleMusic(SoundData<MusicDefinition> musicData, bool isBoss = false); void RegisterMusicEntry(SoundData<MusicDefinition> musicData); ConfigEntry<string> GetEntry(string entryName); bool IsMusicEntry(ConfigEntryBase entry); bool IsSFXEntry(ConfigEntryBase entry); bool IsValidEntry(ConfigEntryBase entry); SoundData<MusicDefinition> GetMusicData(string entryName); SoundData<MusicDefinition> GetMusicData(ConfigEntryBase entry); SoundData<SoundCueDefinition> GetSFXData(string entryName); SoundData<SoundCueDefinition> GetSFXData(ConfigEntryBase entry); List<BattleMusicTrack> GetBattleMusicTracks(bool isBoss = false); BattleMusicTrack GetBattleMusicTrack(string trackName); SoundManager GetSoundManager(); CoreAudioSystem GetCoreAudioSystem(); CoreAudioSystemData GetCoreAudioSystemData(); MusicDefinition[] GetMusicDefinitions(); SoundCueDefinition[] GetSFXDefinitions(); MusicDefinition GetMusicDefinition(string trackName); SoundCueDefinition GetSFXDefinition(string trackName); void ChangeSound(string entryName, string filePath, bool replayMusic = true, Action<string> onPlay = null); void ChangeSound(string entryName, AudioClip audioClip, bool replayMusic = true, Action<string> onPlay = null); void ChangeSound(ConfigEntryBase entry, string filePath, bool replayMusic = true, Action<string> onPlay = null); void ChangeSound(ConfigEntryBase entry, AudioClip audioClip, bool replayMusic = true, Action<string> onPlay = null); void PlayEntry(string entryName, Action<string> onPlay = null); void PlayEntry(ConfigEntryBase entry, Action<string> onPlay = null); void PlayMusic(string entryName, bool isBattleMusic = false, float crossfadeTimeSeconds = 0.25f, string displayedName = "", Action<string> onPlay = null); void PlayMusic(ConfigEntryBase entry, bool isBattleMusic = false, float crossfadeTimeSeconds = 0.25f, string displayedName = "", Action<string> onPlay = null); void PlaySFX(string entryName, bool loop = false, Action<string> onPlay = null); void PlaySFX(ConfigEntryBase entry, bool loop = false, Action<string> onPlay = null); void LoadFileForEntry(string entryName, Action<string, AudioClip> onLoad = null, Action<string> onPlay = null); void LoadFileForEntry(ConfigEntryBase entry, Action<string, AudioClip> onLoad = null, Action<string> onPlay = null); void ResetEntry(string entryName); void ResetEntry(ConfigEntryBase entry); string GetCurrentlyPlayingMusicName(); bool HasInitializedSoundManager(); } internal class MenuPatch { [HarmonyPrefix] [HarmonyPatch(typeof(SettingsScreen), "ApplyScreenInput")] public static bool SettingsScreen_ApplyScreenInput(CoreInputControlMapping mapping, IGameUIComponent triggeredUI, Controls triggeredMappingID, ref bool __result) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)SoundDialog.Instance == (Object)null) { return true; } if (((ScreenDialog)SoundDialog.Instance).ApplyScreenInput(mapping, triggeredUI, triggeredMappingID)) { __result = true; return false; } return true; } [HarmonyPostfix] [HarmonyPatch(typeof(PauseDialog), "ApplyScreenInput")] public static void PauseDialog_ApplyScreenInput(CoreInputControlMapping mapping, IGameUIComponent triggeredUI, Controls triggeredMappingID, ref bool __result) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (!__result && (Object)(object)SoundDialog.Instance != (Object)null) { __result = ((ScreenDialog)SoundDialog.Instance).ApplyScreenInput(mapping, triggeredUI, triggeredMappingID); } } [HarmonyPrefix] [HarmonyPatch(typeof(SettingsScreen), "CloseDialog")] public static bool CloseDialog() { if ((Object)(object)SoundDialog.Instance != (Object)null && ((ScreenTransition)SoundDialog.Instance).Active) { ((ScreenDialog)SoundDialog.Instance).Close(); return false; } return true; } } internal class OrderedDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IDictionary, ICollection { [CompilerGenerated] private sealed class <GetEnumerator>d__25 : IEnumerator<KeyValuePair<TKey, TValue>>, IDisposable, IEnumerator { private int <>1__state; private KeyValuePair<TKey, TValue> <>2__current; public OrderedDictionary<TKey, TValue> <>4__this; private IDictionaryEnumerator <>s__1; private DictionaryEntry <entry>5__2; KeyValuePair<TKey, TValue> IEnumerator<KeyValuePair<TKey, TValue>>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <GetEnumerator>d__25(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(); } } <>s__1 = null; <entry>5__2 = default(DictionaryEntry); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>s__1 = <>4__this.privateDictionary.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; <entry>5__2 = default(DictionaryEntry); break; } if (<>s__1.MoveNext()) { <entry>5__2 = (DictionaryEntry)<>s__1.Current; <>2__current = new KeyValuePair<TKey, TValue>((TKey)<entry>5__2.Key, (TValue)<entry>5__2.Value); <>1__state = 1; return true; } <>m__Finally1(); <>s__1 = null; 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 (<>s__1 is IDisposable disposable) { disposable.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private readonly Hashtable privateHashtable; private readonly OrderedDictionary privateDictionary; public int Count => privateDictionary.Count; public bool IsReadOnly => false; public TValue this[int index] { get { if (index < 0 || index >= Count) { throw new ArgumentOutOfRangeException("index"); } return (TValue)privateDictionary[index]; } set { if (index < 0 || index >= Count) { throw new ArgumentOutOfRangeException("index"); } privateDictionary[index] = value; } } public TValue this[TKey key] { get { if (key == null) { throw new ArgumentNullException("key"); } if (privateDictionary.Contains(key)) { return (TValue)privateDictionary[key]; } throw new KeyNotFoundException("key not found in dictionary"); } set { if (key == null) { throw new ArgumentNullException("key"); } privateDictionary[key] = value; } } public ICollection<TKey> Keys { get { List<TKey> list = new List<TKey>(privateDictionary.Count); foreach (TKey key in privateDictionary.Keys) { list.Add(key); } return list; } } public ICollection<TValue> Values { get { List<TValue> list = new List<TValue>(privateDictionary.Count); foreach (TValue value in privateDictionary.Values) { list.Add(value); } return list; } } bool IDictionary.IsFixedSize => ((IDictionary)privateDictionary).IsFixedSize; bool IDictionary.IsReadOnly => privateDictionary.IsReadOnly; ICollection IDictionary.Keys => privateDictionary.Keys; ICollection IDictionary.Values => privateDictionary.Values; object IDictionary.this[object key] { get { return privateDictionary[key]; } set { privateDictionary[key] = value; } } int ICollection.Count => privateDictionary.Count; bool ICollection.IsSynchronized => ((ICollection)privateDictionary).IsSynchronized; object ICollection.SyncRoot => ((ICollection)privateDictionary).SyncRoot; public OrderedDictionary() { privateDictionary = new OrderedDictionary(); privateHashtable = (Hashtable)AccessTools.DeclaredProperty(typeof(OrderedDictionary), "objectsTable").GetValue(privateDictionary); } public OrderedDictionary(IDictionary<TKey, TValue> dictionary) { if (dictionary == null) { return; } foreach (KeyValuePair<TKey, TValue> item in dictionary) { privateDictionary.Add(item.Key, item.Value); } } public void Add(KeyValuePair<TKey, TValue> item) { Add(item.Key, item.Value); } public void Add(TKey key, TValue value) { if (key == null) { throw new ArgumentNullException("key"); } privateDictionary.Add(key, value); } public void Clear() { privateDictionary.Clear(); } public bool Contains(KeyValuePair<TKey, TValue> item) { if (item.Key == null || !privateDictionary.Contains(item.Key)) { return false; } return privateDictionary[item.Key].Equals(item.Value); } public bool ContainsKey(TKey key) { if (key == null) { throw new ArgumentNullException("key"); } return privateDictionary.Contains(key); } public bool ContainsValue(TValue value) { if (value == null) { throw new ArgumentNullException("value"); } return privateHashtable.ContainsValue(value); } public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { if (array == null) { throw new ArgumentNullException("array"); } if (arrayIndex < 0) { throw new ArgumentOutOfRangeException("arrayIndex"); } if (array.Rank > 1 || arrayIndex >= array.Length || array.Length - arrayIndex < privateDictionary.Count) { throw new ArgumentOutOfRangeException("array"); } int num = arrayIndex; foreach (DictionaryEntry item in privateDictionary) { array[num] = new KeyValuePair<TKey, TValue>((TKey)item.Key, (TValue)item.Value); num++; } } [IteratorStateMachine(typeof(OrderedDictionary<, >.<GetEnumerator>d__25))] public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <GetEnumerator>d__25(0) { <>4__this = this }; } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public bool Remove(KeyValuePair<TKey, TValue> item) { if (Contains(item)) { privateDictionary.Remove(item.Key); return true; } return false; } public bool Remove(TKey key) { if (key == null) { throw new ArgumentNullException("key"); } if (privateDictionary.Contains(key)) { privateDictionary.Remove(key); return true; } return false; } public bool TryGetValue(TKey key, out TValue value) { if (key == null) { throw new ArgumentNullException("key"); } bool flag = privateDictionary.Contains(key); value = (flag ? ((TValue)privateDictionary[key]) : default(TValue)); return flag; } void IDictionary.Add(object key, object value) { privateDictionary.Add(key, value); } void IDictionary.Clear() { privateDictionary.Clear(); } bool IDictionary.Contains(object key) { return privateDictionary.Contains(key); } IDictionaryEnumerator IDictionary.GetEnumerator() { return privateDictionary.GetEnumerator(); } void IDictionary.Remove(object key) { privateDictionary.Remove(key); } void ICollection.CopyTo(Array array, int index) { privateDictionary.CopyTo(array, index); } } public sealed class SoundChangerManager : ISoundChanger { public SoundData<MusicDefinition> CreateNewMusicEntry(string entryName, string description = "", string defaultVal = "") { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown //IL_00b7: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown ConfigEntryBase val = ((IEnumerable<ConfigEntryBase>)Plugin.MusicEntries.Keys).FirstOrDefault((Func<ConfigEntryBase, bool>)((ConfigEntryBase musicEntry) => musicEntry.Definition.Key == entryName)); if (val != null) { Plugin.LogSource.LogError((object)("Cannot create new music entry, Already have music with same entry name " + entryName)); return null; } ConfigEntry<string> val2 = Plugin.Config.Bind<string>(new ConfigDefinition("Basic", entryName), defaultVal, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { HideDefaultButton = true, HideSettingName = true, CustomDrawer = Plugin.MusicDrawer } })); val2.SettingChanged += Plugin.Entry_SettingChanged; Plugin.MusicEntries[(ConfigEntryBase)(object)val2] = SoundData<MusicDefinition>.Create(val2, new MusicDefinition()); return Plugin.MusicEntries[(ConfigEntryBase)(object)val2]; } public SoundData<SoundCueDefinition> CreateNewSFXEntry(string entryName, string description = "", string defaultVal = "") { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown //IL_00b7: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown ConfigEntryBase val = ((IEnumerable<ConfigEntryBase>)Plugin.SFXEntries.Keys).FirstOrDefault((Func<ConfigEntryBase, bool>)((ConfigEntryBase sfxEntry) => sfxEntry.Definition.Key == entryName)); if (val != null) { Plugin.LogSource.LogError((object)("Cannot create new sfx entry, Already have SFX with same entry name " + entryName)); return null; } ConfigEntry<string> val2 = Plugin.Config.Bind<string>(new ConfigDefinition("Basic", entryName), defaultVal, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { HideDefaultButton = true, HideSettingName = true, CustomDrawer = Plugin.MusicDrawer } })); val2.SettingChanged += Plugin.Entry_SettingChanged; Plugin.SFXEntries[(ConfigEntryBase)(object)val2] = SoundData<SoundCueDefinition>.Create(val2, new SoundCueDefinition()); return Plugin.SFXEntries[(ConfigEntryBase)(object)val2]; } public BattleMusicTrack RegisterToBattleMusic(SoundData<MusicDefinition> musicData, bool isBoss = false) { //IL_0030: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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_00d3: 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_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0106: 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_011b: Unknown result type (might be due to invalid IL or missing references) if (musicData == null) { Plugin.LogSource.LogError((object)"Cannot register to battle music, data is null"); return default(BattleMusicTrack); } if (!HasInitializedSoundManager()) { return default(BattleMusicTrack); } SoundManager soundManager = GetSoundManager(); List<BattleMusicTrack> battleMusicTracks = GetBattleMusicTracks(isBoss); if (battleMusicTracks.Exists((BattleMusicTrack track) => track.trackNameData == musicData.definition.Name)) { Plugin.LogSource.LogWarning((object)("Already registered battle music track with entry name " + musicData.definition.Name)); Plugin.LogSource.LogWarning((object)"Removing the duplicated entry..."); battleMusicTracks.RemoveAll((BattleMusicTrack track) => track.trackNameData == musicData.entryName); } BattleMusicTrack val = default(BattleMusicTrack); val.publicTrackNameKey = musicData.GetTitle(); val.trackNameData = musicData.definition.Name; BattleMusicTrack val2 = val; battleMusicTracks.Add(val2); RegisterMusicEntry(musicData); return val2; } public void RegisterMusicEntry(SoundData<MusicDefinition> musicData) { if (musicData == null) { Plugin.LogSource.LogError((object)"Cannot register music, data is null"); } else { if (!HasInitializedSoundManager()) { return; } SoundManager soundManager = GetSoundManager(); CoreAudioSystem coreAudioSystem = GetCoreAudioSystem(); CoreAudioSystemData coreAudioSystemData = GetCoreAudioSystemData(); if (coreAudioSystemData.MusicDefData.Tracks.Any((MusicDefinition definition) => definition.Name == musicData.definition.Name)) { Plugin.LogSource.LogWarning((object)("Already registered music track with entry name " + musicData.definition.Name)); Plugin.LogSource.LogWarning((object)"Removing the duplicated entry..."); List<MusicDefinition> list = coreAudioSystemData.MusicDefData.Tracks.ToList(); list.RemoveAll((MusicDefinition definition) => definition.Name == musicData.definition.Name); coreAudioSystemData.MusicDefData.Tracks = list.ToArray(); } coreAudioSystemData.MusicDefData.Tracks = CollectionExtensions.AddToArray<MusicDefinition>(coreAudioSystemData.MusicDefData.Tracks, musicData.definition); } } public ConfigEntry<string> GetEntry(string entryName) { ConfigEntryBase val = ((IEnumerable<ConfigEntryBase>)Plugin.MusicEntries.Keys).FirstOrDefault((Func<ConfigEntryBase, bool>)((ConfigEntryBase entry) => entry.Definition.Key == entryName)); if (val == null) { val = ((IEnumerable<ConfigEntryBase>)Plugin.SFXEntries.Keys).FirstOrDefault((Func<ConfigEntryBase, bool>)((ConfigEntryBase entry) => entry.Definition.Key == entryName)); } if (val == null) { Plugin.LogSource.LogError((object)("Cannot find entry named " + entryName)); } return val as ConfigEntry<string>; } public bool IsMusicEntry(ConfigEntryBase entry) { return Plugin.MusicEntries.ContainsKey(entry); } public bool IsSFXEntry(ConfigEntryBase entry) { return Plugin.SFXEntries.ContainsKey(entry); } public bool IsValidEntry(ConfigEntryBase entry) { bool flag = entry != null && (IsMusicEntry(entry) || IsSFXEntry(entry)); if (!flag) { ManualLogSource logSource = Plugin.LogSource; object obj; if (entry == null) { obj = null; } else { ConfigDefinition definition = entry.Definition; obj = ((definition != null) ? definition.Key : null); } logSource.LogError((object)((string?)obj + " is not a valid entry")); } return flag; } public SoundData<MusicDefinition> GetMusicData(string entryName) { ConfigEntry<string> entry = GetEntry(entryName); return GetMusicData((ConfigEntryBase)(object)entry); } public SoundData<MusicDefinition> GetMusicData(ConfigEntryBase entry) { if (!IsValidEntry(entry)) { return null; } if (!IsMusicEntry(entry)) { Plugin.LogSource.LogError((object)"Entry is valid but is not a music entry"); return null; } return Plugin.MusicEntries[entry]; } public SoundData<SoundCueDefinition> GetSFXData(string entryName) { ConfigEntry<string> entry = GetEntry(entryName); return GetSFXData((ConfigEntryBase)(object)entry); } public SoundData<SoundCueDefinition> GetSFXData(ConfigEntryBase entry) { if (!IsValidEntry(entry)) { return null; } if (!IsSFXEntry(entry)) { Plugin.LogSource.LogError((object)"Entry is valid but is not an SFX entry"); return null; } return Plugin.SFXEntries[entry]; } public void ChangeSound(string entryName, string filePath, bool replayMusic = true, Action<string> onPlay = null) { ConfigEntry<string> entry = GetEntry(entryName); ChangeSound((ConfigEntryBase)(object)entry, filePath, replayMusic, onPlay); } public void ChangeSound(string entryName, AudioClip audioClip, bool replayMusic = true, Action<string> onPlay = null) { ConfigEntry<string> entry = GetEntry(entryName); ChangeSound((ConfigEntryBase)(object)entry, audioClip, replayMusic, onPlay); } public void ChangeSound(ConfigEntryBase entry, string filePath, bool replayMusic = true, Action<string> onPlay = null) { if (!IsValidEntry(entry)) { return; } if (!File.Exists(filePath)) { Plugin.LogSource.LogError((object)("Cannot load " + filePath + " because its not valid path")); return; } entry.BoxedValue = filePath; ((MonoBehaviour)Plugin.Instance).StartCoroutine(Plugin.LoadAudioClip(filePath, delegate(AudioClip audioClip) { Plugin.OnAudioClipLoaded(entry, audioClip, replayMusic, onPlay); })); } public void ChangeSound(ConfigEntryBase entry, AudioClip audioClip, bool replayMusic = true, Action<string> onPlay = null) { if (IsValidEntry(entry)) { if ((Object)(object)audioClip == (Object)null) { Plugin.LogSource.LogError((object)("AudioClip is null, Cannot assign to entry " + entry.Definition.Key + " because t")); return; } entry.BoxedValue = ((Object)audioClip).name; Plugin.OnAudioClipLoaded(entry, audioClip, replayMusic, onPlay); } } public void PlayEntry(string entryName, Action<string> onPlay = null) { ConfigEntry<string> entry = GetEntry(entryName); PlayEntry((ConfigEntryBase)(object)entry, onPlay); } public void PlayEntry(ConfigEntryBase entry, Action<string> onPlay = null) { if (IsValidEntry(entry)) { if (IsMusicEntry(entry)) { Plugin.PlayMusic(entry, isBattleMusic: false, 0.25f, "", onPlay); } else if (IsSFXEntry(entry)) { Plugin.PlaySFX(entry, loop: false, onPlay); } } } public void PlayMusic(string entryName, bool isBattleMusic = false, float crossfadeTimeSeconds = 0.25f, string displayedName = "", Action<string> onPlay = null) { ConfigEntry<string> entry = GetEntry(entryName); PlayMusic((ConfigEntryBase)(object)entry, isBattleMusic, crossfadeTimeSeconds, displayedName, onPlay); } public void PlayMusic(ConfigEntryBase entry, bool isBattleMusic = false, float crossfadeTimeSeconds = 0.25f, string displayedName = "", Action<string> onPlay = null) { if (IsValidEntry(entry) && IsMusicEntry(entry)) { Plugin.PlayMusic(entry, isBattleMusic, crossfadeTimeSeconds, displayedName, onPlay); } } public void PlaySFX(string entryName, bool loop = false, Action<string> onPlay = null) { ConfigEntry<string> entry = GetEntry(entryName); PlaySFX((ConfigEntryBase)(object)entry, loop, onPlay); } public void PlaySFX(ConfigEntryBase entry, bool loop = false, Action<string> onPlay = null) { if (IsValidEntry(entry) && IsSFXEntry(entry)) { Plugin.PlaySFX(entry, loop, onPlay); } } public void LoadFileForEntry(string entryName, Action<string, AudioClip> onLoad = null, Action<string> onPlay = null) { ConfigEntry<string> entry = GetEntry(entryName); LoadFileForEntry((ConfigEntryBase)(object)entry, onLoad, onPlay); } public void LoadFileForEntry(ConfigEntryBase entry, Action<string, AudioClip> onLoad = null, Action<string> onPlay = null) { if (IsValidEntry(entry)) { Plugin.LoadFile(entry, "", existFile: false, onLoad, onPlay); } } public void ResetEntry(string entryName) { ConfigEntry<string> entry = GetEntry(entryName); ResetEntry((ConfigEntryBase)(object)entry); } public void ResetEntry(ConfigEntryBase entry) { if (IsValidEntry(entry)) { entry.BoxedValue = ""; Plugin.ResetEntryBase(entry); } } public string GetCurrentlyPlayingMusicName() { if (!HasInitializedSoundManager()) { return ""; } SoundManager soundManager = AllGameManagers.Instance.GetSoundManager(); string result = soundManager.GetCurrentMusicTrackName(); if (!string.IsNullOrWhiteSpace(soundManager.currentTrackName)) { result = soundManager.currentTrackName; } return result; } public bool HasInitializedSoundManager() { AllGameManagers instance = AllGameManagers.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.GetSoundManager() != (Object)null) { return true; } Plugin.LogSource.LogError((object)"SoundManager isn't initialized yet, try waiting a bit more before registering"); return false; } public List<BattleMusicTrack> GetBattleMusicTracks(bool isBoss) { if (!HasInitializedSoundManager()) { return null; } SoundManager soundManager = AllGameManagers.Instance.GetSoundManager(); return (!isBoss) ? Traverse.Create((object)soundManager).Field<List<BattleMusicTrack>>("battleMusicTracks").Value : Traverse.Create((object)soundManager).Field<List<BattleMusicTrack>>("bossBattleMusicTracks").Value; } public BattleMusicTrack GetBattleMusicTrack(string trackName) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) BattleMusicTrack result = default(BattleMusicTrack); if (!HasInitializedSoundManager()) { return result; } List<BattleMusicTrack> battleMusicTracks = GetBattleMusicTracks(isBoss: false); result = battleMusicTracks.Find((BattleMusicTrack track) => track.trackNameData == trackName); if (string.IsNullOrWhiteSpace(result.trackNameData)) { battleMusicTracks = GetBattleMusicTracks(isBoss: false); result = battleMusicTracks.Find((BattleMusicTrack track) => track.trackNameData == trackName); } return result; } public SoundManager GetSoundManager() { if (!HasInitializedSoundManager()) { return null; } return AllGameManagers.Instance.GetSoundManager(); } public CoreAudioSystem GetCoreAudioSystem() { if (!HasInitializedSoundManager()) { return null; } SoundManager soundManager = AllGameManagers.Instance.GetSoundManager(); return Traverse.Create((object)soundManager).Field<CoreAudioSystem>("audioSystem").Value; } public CoreAudioSystemData GetCoreAudioSystemData() { if (!HasInitializedSoundManager()) { return null; } SoundManager soundManager = AllGameManagers.Instance.GetSoundManager(); CoreAudioSystem value = Traverse.Create((object)soundManager).Field<CoreAudioSystem>("audioSystem").Value; return Traverse.Create((object)value).Field("AudioSystemData").GetValue<CoreAudioSystemData>(); } public MusicDefinition[] GetMusicDefinitions() { if (!HasInitializedSoundManager()) { return null; } return GetCoreAudioSystemData().MusicDefData.Tracks; } public SoundCueDefinition[] GetSFXDefinitions() { if (!HasInitializedSoundManager()) { return null; } return GetCoreAudioSystemData().GlobalSoundEffectData.Sounds; } public MusicDefinition GetMusicDefinition(string trackName) { if (!HasInitializedSoundManager()) { return null; } return GetMusicDefinitions().First((MusicDefinition definition) => definition.Name == trackName); } public SoundCueDefinition GetSFXDefinition(string trackName) { if (!HasInitializedSoundManager()) { return null; } return GetSFXDefinitions().First((SoundCueDefinition definition) => definition.Name == trackName); } } public enum SoundType { Unknown, Music, SFX } public class SoundData<T> : IDisposable { internal static readonly Lazy<Track> emptyTrack = new Lazy<Track>((Func<Track>)(() => new Track())); private AudioClip _audioData; public readonly SoundType type; public readonly ConfigEntry<string> entry; public readonly T definition; public readonly string entryName; public Track TrackData { get; private set; } public AudioClip AudioData { get { return _audioData; } set { _audioData = value; if (type == SoundType.Music) { SoundData<MusicDefinition> soundData = AsMusic(); for (int i = 0; i < soundData.definition.Clips.Length; i++) { soundData.definition.Clips[i].Clip = _audioData; } } else if (type == SoundType.SFX) { SoundData<SoundCueDefinition> soundData2 = AsSFX(); for (int j = 0; j < soundData2.definition.Clips.Length; j++) { soundData2.definition.Clips[j] = _audioData; } } } } public Sprite CoverSprite { get; set; } ~SoundData() { Dispose(); } public void Dispose() { entry.SettingChanged -= Entry_SettingChanged; } private SoundData(T definition, ConfigEntry<string> entry) { this.definition = definition; this.entry = entry; entryName = ((ConfigEntryBase)entry).Definition.Key; TrackData = emptyTrack.Value; if (typeof(MusicDefinition).IsAssignableFrom(typeof(T))) { type = SoundType.Music; } else if (typeof(SoundCueDefinition).IsAssignableFrom(typeof(T))) { type = SoundType.SFX; } CreateTrackInfo(); this.entry.SettingChanged += Entry_SettingChanged; } public static SoundData<T> Create(ConfigEntry<string> entry, T definition) { if (!IsValidType()) { return null; } if (entry == null) { Plugin.LogSource.LogError((object)"Cannot create SoundData with null entry"); return null; } if (definition == null) { Plugin.LogSource.LogError((object)"Cannot create SoundData with null definition"); return null; } return new SoundData<T>(definition, entry); } public static bool IsValidType() { if (typeof(MusicDefinition).IsAssignableFrom(typeof(T)) || typeof(SoundCueDefinition).IsAssignableFrom(typeof(T))) { return true; } Plugin.LogSource.LogError((object)"T must be of type CoreMusicData.MusicDefinition or CoreSoundEffectData.SoundCueDefinition"); return false; } private void CreateTrackInfo() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown if (IsFileExist()) { TrackData = new Track(GetFilePath(), (IProgress<float>)null, true); if (IEnumerableUtility.IsNullOrEmpty<PictureInfo>((IEnumerable<PictureInfo>)TrackData.EmbeddedPictures)) { return; } PictureInfo val = ((IEnumerable<PictureInfo>)TrackData.EmbeddedPictures).FirstOrDefault((Func<PictureInfo, bool>)((PictureInfo picture) => picture != null && (int)picture.PicType == 2)); if (val == null) { val = ((IEnumerable<PictureInfo>)TrackData.EmbeddedPictures).FirstOrDefault((Func<PictureInfo, bool>)((PictureInfo picture) => picture != null && (int)picture.PicType == 18)); } if (val == null) { val = ((IEnumerable<PictureInfo>)TrackData.EmbeddedPictures).FirstOrDefault((Func<PictureInfo, bool>)((PictureInfo picture) => picture != null)); } if (val != null) { AssignCover(val.PictureData); } } else { TrackData = emptyTrack.Value; } } private void Entry_SettingChanged(object sender, EventArgs e) { CreateTrackInfo(); } public SoundData<MusicDefinition> AsMusic() { return this as SoundData<MusicDefinition>; } public SoundData<SoundCueDefinition> AsSFX() { return this as SoundData<SoundCueDefinition>; } public bool AssignDefinitionToData(T definition) { //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Expected O, but got Unknown //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Expected O, but got Unknown if (!IsValidType()) { return false; } if (definition == null) { Plugin.LogSource.LogError((object)"Cannot assign data to null definition"); return false; } if (type == SoundType.Music) { SoundData<MusicDefinition> soundData = AsMusic(); object obj = definition; MusicDefinition val = (MusicDefinition)((obj is MusicDefinition) ? obj : null); if (soundData == null) { Plugin.LogSource.LogError((object)"The instance isn't SoundData<MusicDefinition> somehow despite the type is a music"); return false; } if (val == null) { Plugin.LogSource.LogError((object)"The target instance isn't MusicDefinition somehow despite the type is a music"); return false; } if (soundData.definition == null) { Plugin.LogSource.LogError((object)"Definition is null"); return false; } soundData.definition.Mixer = val.Mixer; if (!IEnumerableUtility.IsNullOrEmpty<MusicClipDefinition>((IEnumerable<MusicClipDefinition>)val.Clips)) { soundData.definition.Clips = (MusicClipDefinition[])(object)new MusicClipDefinition[val.Clips.Length]; for (int i = 0; i < val.Clips.Length; i++) { soundData.definition.Clips[i] = new MusicClipDefinition { MixerGroup = val.Clips[i]?.MixerGroup, Clip = val.Clips[i]?.Clip }; } } else { soundData.definition.Clips = (MusicClipDefinition[])(object)new MusicClipDefinition[1]; } if (!IEnumerableUtility.IsNullOrEmpty<MusicSnapshotDefinition>((IEnumerable<MusicSnapshotDefinition>)val.Snapshots)) { soundData.definition.Snapshots = (MusicSnapshotDefinition[])(object)new MusicSnapshotDefinition[val.Snapshots.Length]; for (int j = 0; j < val.Clips.Length; j++) { soundData.definition.Snapshots[j] = new MusicSnapshotDefinition { Name = val.Snapshots[j]?.Name, Snapshot = val.Snapshots[j]?.Snapshot, TransitionTimeSeconds = (val.Snapshots[j]?.TransitionTimeSeconds).Value }; } } else { soundData.definition.Snapshots = (MusicSnapshotDefinition[])(object)new MusicSnapshotDefinition[1]; } soundData.definition.Name = ((ConfigEntryBase)entry).Definition.Key; } else if (type == SoundType.SFX) { SoundData<SoundCueDefinition> soundData2 = AsSFX(); object obj2 = definition; SoundCueDefinition val2 = (SoundCueDefinition)((obj2 is SoundCueDefinition) ? obj2 : null); if (soundData2 == null) { Plugin.LogSource.LogError((object)"The instance isn't SoundData<SoundCueDefinition> somehow despite the type is an SFX"); return false; } if (val2 == null) { Plugin.LogSource.LogError((object)"The target instance isn't SoundCueDefinition somehow despite the type is an SFX"); return false; } if (soundData2.definition == null) { Plugin.LogSource.LogError((object)"Definition is null"); return false; } if (!IEnumerableUtility.IsNullOrEmpty<AudioClip>((IEnumerable<AudioClip>)val2.Clips)) { soundData2.definition.Clips = (AudioClip[])(object)new AudioClip[val2.Clips.Length]; for (int k = 0; k < val2.Clips.Length; k++) { soundData2.definition.Clips[k] = val2.Clips[k]; } } else { soundData2.definition.Clips = (AudioClip[])(object)new AudioClip[1]; } soundData2.definition.VolumeMin = val2.VolumeMin; soundData2.definition.VolumeMax = val2.VolumeMax; soundData2.definition.PitchMin = val2.PitchMin; soundData2.definition.PitchMax = val2.PitchMax; soundData2.definition.Loop = val2.Loop; if (!IEnumerableUtility.IsNullOrEmpty<string>((IEnumerable<string>)val2.Tags)) { soundData2.definition.Tags = new string[val2.Tags.Length]; for (int l = 0; l < val2.Tags.Length; l++) { soundData2.definition.Tags[l] = val2.Tags[l]; } } else { soundData2.definition.Tags = new string[1]; } soundData2.definition.Name = ((ConfigEntryBase)entry).Definition.Key; } return true; } public void AssignCover(string filePath) { if (!File.Exists(filePath)) { Plugin.LogSource.LogError((object)("Cannot create cover for entry " + entryName + " on non-existent file")); } else { AssignCover(File.ReadAllBytes(filePath)); } } public void AssignCover(byte[] data) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(0, 0); if (ImageConversion.LoadImage(val, data)) { CoverSprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), Vector2.zero, 100f, 0u, (SpriteMeshType)1); } else { Plugin.LogSource.LogError((object)("Failed creating cover image for entry " + entryName)); } } public string GetTitle() { string result = ""; if (!IsEmptyTrackData() && !string.IsNullOrWhiteSpace(TrackData.Title)) { result = TrackData.Title; } else if (File.Exists(entry.Value)) { result = Path.GetFileNameWithoutExtension(entry.Value); } else if ((Object)(object)AudioData != (Object)null) { result = Plugin.RemoveGUIDFromName(AudioData); } return result; } public string GetFilePath() { string text = entry.Value; if (!File.Exists(text)) { if (Path.IsPathRooted(text)) { Plugin.LogSource.LogError((object)("The path must not be rooted if you want to make it relative to the mod path " + text)); } text = Path.Combine(Plugin.BasePath, text); } return text; } public string GetExtension() { return Path.GetExtension(entry.Value); } public bool IsFileExist() { return File.Exists(GetFilePath()); } public bool IsEmptyTrackData() { return TrackData == emptyTrack.Value; } public int Duration() { int result = 0; if ((Object)(object)AudioData != (Object)null) { result = Mathf.RoundToInt(AudioData.length); } else if (!IsEmptyTrackData()) { result = TrackData.Duration; } return result; } } public class SoundDialog : ScreenDialog { internal Dictionary<string, ScrollRect> scrollRectsSection = new Dictionary<string, ScrollRect>(); internal Dictionary<string, SettingsTab> tabsSection = new Dictionary<string, SettingsTab>(); internal List<SoundInfo> soundList = new List<SoundInfo>(); internal GameUISelectableButton soundChangerButton; internal TextMeshProUGUI headerTitle; internal TMP_Text musicLabel; internal LayoutElement ContentLayout; public static SoundDialog Instance { get; private set; } public static SettingsScreen SettingsScreen { get; } = (SettingsScreen)AllGameManagers.Instance.GetScreenManager().GetScreen((ScreenName)18); public static PauseDialog PauseDialog { get; private set; } private void Start() { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) ((Object)this).name = "Sound Dialog"; PauseDialog = Traverse.Create((object)SettingsScreen).Field<PauseDialog>("pauseDialog").Value; headerTitle = ((Component)((Component)this).transform.Find("Header/Title")).GetComponent<TextMeshProUGUI>(); ((TMP_Text)headerTitle).enableAutoSizing = true; ((TMP_Text)headerTitle).overflowMode = (TextOverflowModes)1; ((TMP_Text)headerTitle).fontSizeMin = 20f; ((TMP_Text)headerTitle).rectTransform.sizeDelta = new Vector2(-100f, 64f); musicLabel = Traverse.Create((object)PauseDialog).Field<TMP_Text>("musicLabel").Value; musicLabel.overflowMode = (TextOverflowModes)1; ContentLayout = new GameObject("Content Layout").AddComponent<LayoutElement>(); ContentLayout.preferredHeight = 818f; ((Component)ContentLayout).transform.SetParent(((Component)this).transform.Find("Content"), false); InitializeTabs(); CreateSection("Music", tabsSection["Music"], Plugin.MusicEntries.Keys.ToList()); CreateSection("SFX", tabsSection["SFX"], Plugin.SFXEntries.Keys.ToList()); Traverse val = Traverse.Create((object)this); base._canvasGroup = ((Component)this).GetComponent<CanvasGroup>(); val.Field("_timelineTransition").SetValue((object)((Component)this).GetComponent<TimelineTransition>()); base._closeButton = ((Component)((Component)this).transform.Find("Bg container/CloseButton")).GetComponent<GameUISelectableButton>(); Traverse.Create((object)PauseDialog).Field<GameObject>("musicLabelRoot").Value.SetActive(true); Plugin.musicChanged.AddListener((Action<string>)UpdateCurrentMusicName); SetSection(Plugin.currentSectionEntry.Value, updateEntry: false); Plugin.currentSectionEntry.SettingChanged += CurrentSectionEntry_SettingChanged; Instance.UpdateCurrentMusicName(AllGameManagers.Instance.GetSoundManager().currentTrackName); } private void CurrentSectionEntry_SettingChanged(object sender, EventArgs e) { SetSection(Plugin.currentSectionEntry.Value, updateEntry: false); } private void CreateSoundChangerButton(PauseDialog pauseDialog) { GameUISelectableButton value = Traverse.Create((object)pauseDialog).Field<GameUISelectableButton>("settingsButton").Value; soundChangerButton = Object.Instantiate<GameUISelectableButton>(value, ((Component)value).transform.parent); ((Object)soundChangerButton).name = "Sound Changer button"; ((Component)soundChangerButton).transform.SetSiblingIndex(1); TMP_Text componentInChildren = ((Component)soundChangerButton).GetComponentInChildren<TMP_Text>(true); Object.DestroyImmediate((Object)(object)((Component)componentInChildren).GetComponent<Localize>()); componentInChildren.text = "Sound Changer"; } private void OnDestroy() { Plugin.musicChanged.RemoveListener((Action<string>)UpdateCurrentMusicName); Plugin.currentSectionEntry.SettingChanged -= CurrentSectionEntry_SettingChanged; } internal void UpdateCurrentMusicName(string trackName) { TextMeshProHelper.SetTextSafe(musicLabel, trackName, true); ((TMP_Text)headerTitle).text = "Currently Playing: <color=yellow>" + trackName + "</color>"; } internal void SetSection(string sectionName, bool updateEntry) { if (!scrollRectsSection.ContainsKey(sectionName)) { Plugin.LogSource.LogError((object)("Section named " + sectionName + " doesn't exist")); return; } if (updateEntry) { Plugin.SetBrowsableSection(sectionName, Plugin.currentSectionEntry.Value != sectionName); Plugin.currentSectionEntry.Value = sectionName; } foreach (KeyValuePair<string, SettingsTab> item in tabsSection) { item.Value.SetActivated(item.Key == sectionName); } } private void InitializeTabs() { Object.Destroy((Object)(object)((Component)((Component)this).transform.Find("Content/Content")).gameObject); Object.Destroy((Object)(object)((Component)headerTitle).GetComponent<Localize>()); Transform val = ((Component)this).transform.Find("Content/Tabs"); for (int i = 2; i < val.childCount - 1; i++) { Object.Destroy((Object)(object)((Component)val.GetChild(i)).gameObject); } tabsSection["Music"] = ((Component)val.GetChild(0)).GetComponent<SettingsTab>(); tabsSection["SFX"] = ((Component)val.GetChild(1)).GetComponent<SettingsTab>(); } private void CreateSection(string sectionName, SettingsTab settingsTab, List<ConfigEntryBase> entries) { //IL_000c: 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) RectTransform val = new GameObject(sectionName + " Section").AddComponent<RectTransform>(); ((Component)val).gameObject.layer = LayerMask.NameToLayer("UI"); ((Component)val).transform.SetParent(((Component)ContentLayout).transform, false); val.anchoredPosition = new Vector2(0f, 30f); scrollRectsSection[sectionName] = CreateScrollRect((Transform)(object)val); Traverse.Create((object)settingsTab).Field("sectionRoot").SetValue((object)((Component)val).gameObject); TextMeshProUGUI componentInChildren = ((Component)settingsTab).GetComponentInChildren<TextMeshProUGUI>(true); Object.DestroyImmediate((Object)(object)((Component)componentInChildren).GetComponent<Localize>()); ((TMP_Text)componentInChildren).text = sectionName; for (int i = 0; i < entries.Count; i++) { ConfigEntryBase entry = entries[i]; soundList.Add(CreateItem(entry, scrollRectsSection[sectionName], i % 2 == 1)); } CreateEmptyItem(scrollRectsSection[sectionName]); } private ScrollRect CreateScrollRect(Transform parent) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Expected O, but got Unknown //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) ScrollRect val = new GameObject("ScrollRect").AddComponent<ScrollRect>(); ((Component)val).transform.localPosition = new Vector3(0f, -20f); ((Component)val).transform.SetParent(parent, false); ((Component)val).gameObject.layer = LayerMask.NameToLayer("UI"); GameObject val2 = new GameObject("Viewport", new Type[3] { typeof(RectTransform), typeof(Image), typeof(Mask) }); val2.transform.SetParent(((Component)val).transform, false); val.viewport = val2.GetComponent<RectTransform>(); val.viewport.anchoredPosition = new Vector2(0f, 340f); val.viewport.pivot = new Vector2(0.5f, 1f); val.viewport.sizeDelta = new Vector2(1000f, 720f); val2.GetComponent<Mask>().showMaskGraphic = false; Transform val3 = ((Component)this).transform.Find("Bg container/Image bg banner"); val2.GetComponent<Image>().sprite = ((Component)val3).GetComponent<Image>().sprite; val2.GetComponent<Image>().type = (Type)1; AspectRatioFitter component = ((Component)val3).GetComponent<AspectRatioFitter>(); AspectRatioFitter val4 = val2.AddComponent<AspectRatioFitter>(); val4.aspectRatio = component.aspectRatio; val4.aspectMode = component.aspectMode; GameObject val5 = new GameObject("Content", new Type[3] { typeof(RectTransform), typeof(GridLayoutGroup), typeof(ContentSizeFitter) }); val5.transform.SetParent(val2.transform, false); RectTransform component2 = val5.GetComponent<RectTransform>(); component2.pivot = new Vector2(0.5f, 1f); val.content = component2; val.content.sizeDelta = val.viewport.sizeDelta; val.vertical = true; val.horizontal = false; val.scrollSensitivity = 80f; val.inertia = false; val.verticalScrollbarVisibility = (ScrollbarVisibility)1; val.movementType = (MovementType)2; val.decelerationRate = 0.135f; val.verticalScrollbar = CreateVerticalScrollbar(((Component)val).transform); val5.GetComponent<ContentSizeFitter>().verticalFit = (FitMode)2; GridLayoutGroup component3 = ((Component)component2).GetComponent<GridLayoutGroup>(); component3.cellSize = new Vector2(1000f, 100f); ((LayoutGroup)component3).childAlignment = (TextAnchor)1; component3.constraint = (Constraint)1; component3.constraintCount = 1; return val; } private Scrollbar CreateVerticalScrollbar(Transform parent) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0125: 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_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Expected O, but got Unknown //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Expected O, but got Unknown //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Expected O, but got Unknown //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Vertical Scrollbar", new Type[2] { typeof(Scrollbar), typeof(Image) }); Scrollbar component = val.GetComponent<Scrollbar>(); component.direction = (Direction)2; val.GetComponent<Image>().type = (Type)1; val.GetComponent<Image>().sprite = Plugin.scrollbarAtlas.GetSprite("SH_Bg_Scrollbar"); RectTransform component2 = val.GetComponent<RectTransform>(); ((Transform)component2).SetParent(parent, false); component2.anchoredPosition = new Vector2(460f, 285f); component2.anchorMin = new Vector2(1f, 0f); component2.anchorMax = new Vector2(1f, 1f); component2.pivot = new Vector2(1f, 1f); component2.sizeDelta = new Vector2(24f, 510f); GameObject val2 = new GameObject("Sliding Area", new Type[1] { typeof(RectTransform) }); RectTransform component3 = val2.GetComponent<RectTransform>(); ((Transform)component3).SetParent(val.transform, false); component3.anchorMin = Vector2.zero; component3.anchorMax = Vector2.one; component3.sizeDelta = Vector2.zero; GameObject val3 = new GameObject("Handle", new Type[1] { typeof(Image) }); RectTransform component4 = val3.GetComponent<RectTransform>(); ((Transform)component4).SetParent(val2.transform, false); component4.anchorMin = new Vector2(0f, 0.6831f); component4.anchorMax = new Vector2(1f, 0f); component4.offsetMax = Vector2.zero; component4.offsetMin = Vector2.zero; component4.pivot = new Vector2(0.5f, 0.5f); component4.sizeDelta = Vector2.zero; ((Component)component4).GetComponent<Image>().type = (Type)1; ((Component)component4).GetComponent<Image>().sprite = Plugin.scrollbarAtlas.GetSprite("CMP_Scrollbar"); GameObject val4 = new GameObject("Target Graphic", new Type[1] { typeof(Image) }); val4.transform.SetParent(((Component)component4).transform, false); Image component5 = val4.GetComponent<Image>(); ((Graphic)component5).rectTransform.sizeDelta = Vector2.one * 20f; ((Graphic)component5).rectTransform.anchorMax = Vector2.one; ((Graphic)component5).rectTransform.anchorMin = Vector2.zero; ((Graphic)component5).rectTransform.offsetMax = Vector2.one * 10f; ((Graphic)component5).rectTransform.offsetMin = Vector2.one * -10f; component5.type = (Type)1; component5.sprite = Sprite.Create(new Texture2D(0, 0), Rect.zero, Vector2.zero); Sprite sprite = Plugin.scrollbarAtlas.GetSprite("SH_Square_Border_Highlight"); component.handleRect = component4; ((Selectable)component).targetGraphic = (Graphic)(object)component5; ((Selectable)component).transition = (Transition)2; SpriteState spriteState = default(SpriteState); ((SpriteState)(ref spriteState)).pressedSprite = sprite; ((SpriteState)(ref spriteState)).highlightedSprite = sprite; ((SpriteState)(ref spriteState)).selectedSprite = sprite; ((Selectable)component).spriteState = spriteState; return component; } private GameObject CreateEmptyItem(ScrollRect scrollRect) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) ContentSizeFitter val = new GameObject("Empty", new Type[1] { typeof(RectTransform) }).AddComponent<ContentSizeFitter>(); ((Component)val).transform.SetParent((Transform)(object)scrollRect.content, false); val.horizontalFit = (FitMode)2; val.verticalFit = (FitMode)2; return ((Component)val).gameObject; } private SoundInfo CreateItem(ConfigEntryBase entry, ScrollRect scrollRect, bool createBG) { //IL_000c: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) SoundInfo soundInfo = new GameObject(entry.Definition.Key).AddComponent<SoundInfo>(); ((Component)soundInfo).transform.SetParent((Transform)(object)scrollRect.content, false); if (createBG) { Image val = new GameObject("BG").AddComponent<Image>(); ((Graphic)val).color = new Color(0f, 0f, 0f, 0.5f); ((Graphic)val).rectTransform.anchorMin = Vector2.zero; ((Graphic)val).rectTransform.anchorMax = Vector2.one; ((Component)val).transform.SetParent(((Component)soundInfo).transform, false); } soundInfo.Set(SettingsScreen, entry); return soundInfo; } public override bool ApplyScreenInput(CoreInputControlMapping mapping, IGameUIComponent triggeredUI, Controls triggeredMappingID) { //IL_0004: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) if (((ScreenDialog)this).ApplyScreenInput(mapping, triggeredUI, triggeredMappingID)) { return true; } if ((Object)(object)soundChangerButton != (Object)null && soundChangerButton.TryTrigger(mapping, triggeredUI, triggeredMappingID, false, false)) { ((ScreenDialog)this).Open(); return true; } foreach (KeyValuePair<string, SettingsTab> item in tabsSection) { if ((Object)(object)item.Value != (Object)null && item.Value.TryTrigger(mapping, triggeredUI, triggeredMappingID)) { SetSection(item.Key, updateEntry: true); return true; } } foreach (SoundInfo sound in soundList) { if (!((Component)sound).gameObject.activeInHierarchy || !sound.TryTrigger(mapping, triggeredUI, triggeredMappingID)) { continue; } return true; } return false; } public override void Close() { ((ScreenDialog)this).Close(); SoundManager.PlaySfxSignal.Dispatch("UI_Cancel"); } internal static void CreateDialog(SettingsScreen settingScreen) { if (!((Object)(object)settingScreen == (Object)null)) { Traverse val = Traverse.Create((object)settingScreen); SettingsDialog value = val.Field<SettingsDialog>("settingsDialog").Value; PauseDialog value2 = val.Field<PauseDialog>("pauseDialog").Value; SettingsDialog val2 = Object.Instantiate<SettingsDialog>(value, ((Component)value).transform.parent); GameObject gameObject = ((Component)val2).gameObject; Object.DestroyImmediate((Object)(object)val2); Instance = gameObject.AddComponent<SoundDialog>(); Instance.CreateSoundChangerButton(value2); } } } public class NativeFileDialog { [Flags] public enum OFN_Flags { OFN_ALLOWMULTISELECT = 0x200, OFN_CREATEPROMPT = 0x2000, OFN_DONTADDTORECENT = 0x2000000, OFN_ENABLEHOOK = 0x20, OFN_ENABLEINCLUDENOTIFY = 0x400000, OFN_ENABLESIZING = 0x800000, OFN_ENABLETEMPLATE = 0x40, OFN_ENABLETEMPLATEHANDLE = 0x80, OFN_EXPLORER = 0x80000, OFN_EXTENSIONDIFFERENT = 0x400, OFN_FILEMUSTEXIST = 0x1000, OFN_FORCESHOWHIDDEN = 0x10000000, OFN_HIDEREADONLY = 4, OFN_LONGNAMES = 0x200000, OFN_NOCHANGEDIR = 8, OFN_NODEREFERENCELINKS = 0x100000, OFN_NOLONGNAMES = 0x40000, OFN_NONETWORKBUTTON = 0x20000, OFN_NOREADONLYRETURN = 0x8000, OFN_NOTESTFILECREATE = 0x10000, OFN_NOVALIDATE = 0x100, OFN_OVERWRITEPROMPT = 2, OFN_PATHMUSTEXIST = 0x800, OFN_READONLY = 1, OFN_SHAREAWARE = 0x4000, OFN_SHOWHELP = 0x10 } [Flags] public enum OFN_Flags_EX { OFN_EX_NOPLACESBAR = 1 } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct OpenFileName { public int lStructSize; public IntPtr hwndOwner; public IntPtr hInstance; public string lpstrFilter; public string lpstrCustomFilter; public int nMaxCustFilter; public int nFilterIndex; public string lpstrFile; public int nMaxFile; public string lpstrFileTitle; public int nMaxFileTitle; public string lpstrInitialDir; public string lpstrTitle; public int Flags; public short nFileOffset; public short nFileExtension; public string lpstrDefExt; public IntPtr lCustData; public IntPtr lpfnHook; public string lpTemplateName; public IntPtr pvReserved; public int dwReserved; public int FlagsEx; } [DllImport("comdlg32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool GetOpenFileName(ref OpenFileName ofn); public static void OpenSingleFile(Action<string> onComplete, string title = "Open File", string filter = "All Files\0*.*\0\0", string initialDir = "", string initialFile = "") { OpenFileName ofn = default(OpenFileName); ofn.lStructSize = Marshal.SizeOf(ofn); ofn.lpstrFilter = filter; char[] array = new char[260]; if (!string.IsNullOrEmpty(initialFile)) { initialFile.CopyTo(0, array, 0, Math.Min(initialFile.Length, 259)); } ofn.lpstrFile = new string(array); ofn.nMaxFile = ofn.lpstrFile.Length; ofn.lpstrFileTitle = new string(new char[64]); ofn.nMaxFileTitle = ofn.lpstrFileTitle.Length; ofn.lpstrInitialDir = initialDir; ofn.lpstrTitle = title; ofn.Flags = 530440; if (GetOpenFileName(ref ofn)) { onComplete?.Invoke(ofn.lpstrFile); } } } internal class PatchList { [HarmonyPostfix] [HarmonyPatch(typeof(AppManager), "DoesThisBuildReportErrors")] public static void DisableErrorReportingPatch(ref bool __result) { __result = false; } [HarmonyPrefix] [HarmonyPatch(typeof(AudioClip), "LoadAudioData")] public static bool LoadAudioData(AudioClip __instance, ref bool __result) { if (((Object)__instance).name.Contains("Patty_SoundChanger_MOD")) { __result = true; return false; } return true; } [HarmonyPrefix] [HarmonyPatch(typeof(AudioClip), "UnloadAudioData")] public static bool UnloadAudioData(AudioClip __instance, ref bool __result) { if (((Object)__instance).name.Contains("Patty_SoundChanger_MOD")) { __result = true; return false; } return true; } [HarmonyPrefix] [HarmonyPatch(/*Could not decode attribute arguments.*/)] public static void CurrentTrackName_Set(SoundManager __instance, CoreAudioSystem ___audioSystem, ref string value) { string modifiedAudioName = Plugin.GetModifiedAudioName(value, ___audioSystem); if (!string.IsNullOrEmpty(modifiedAudioName)) { value = modifiedAudioName; } } [HarmonyPostfix] [HarmonyPatch(typeof(LoadScreen), "StartLoadingScreen")] public static void StartLoadingScreen(LoadScreen __instance) { Plugin.CreateEntries(); } [HarmonyPostfix] [HarmonyPatch(typeof(SoundManager), "PlayMusic")] public static void PlayMusic(SoundManager __instance, string trackName, List<BattleMusicTrack> ___battleMusicTracks, List<BattleMusicTrack> ___bossBattleMusicTracks, CoreAudioSystem ___audioSystem) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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) string text = __instance.currentTrackName; string modifiedAudioName = Plugin.GetModifiedAudioName(trackName, ___audioSystem); if (!string.IsNullOrEmpty(modifiedAudioName)) { text = modifiedAudioName; } else { IEnumerable<BattleMusicTrack> source = ___battleMusicTracks.Union(___bossBattleMusicTracks); BattleMusicTrack val = source.FirstOrDefault((Func<BattleMusicTrack, bool>)((BattleMusicTrack track) => track.trackNameData == trackName)); if (!string.IsNullOrEmpty(val.trackNameData)) { text = val.publicTrackNameKey; } } if (string.IsNullOrEmpty(text)) { text = trackName; } else if (LocalizationManager.IsTranslatableTerm(text)) { text = LocalizationManager.GetTranslation(text, true, 0, true, true, (GameObject)null, (string)null, (ILocalizationParameterContext)null); } else if (LocalizationManager.IsTranslatableTerm(trackName)) { text = LocalizationManager.GetTranslation(trackName, true, 0, true, true, (GameObject)null, (string)null, (ILocalizationParameterContext)null); } Plugin.musicChanged.Dispatch(text); } [HarmonyPostfix] [HarmonyPatch(typeof(SoundManager), "PlayBattleMusic")] public static void PlayBattleMusic(SoundManager __instance) { string text = __instance.currentTrackName; if (LocalizationManager.IsTranslatableTerm(text)) { text = LocalizationManager.GetTranslation(text, true, 0, true, true, (GameObject)null, (string)null, (ILocalizationParameterContext)null); } Plugin.musicChanged.Dispatch(text); } } [BepInPlugin("Patty_SoundChanger_MOD", "Sound Changer", "2.0.0")] public class Plugin : BaseUnityPlugin { [CompilerGenerated] private sealed class <>c__DisplayClass73_0 { public SoundManager soundManager; public bool isBattleMusic; public float crossfadeTimeSeconds; public ConfigEntryBase entry; public string displayedName; public Action<string> onPlay; } [CompilerGenerated] private sealed class <LoadAudioClip>d__75 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string filePath; public Action<AudioClip> onComplete; private UnityWebRequest <webRequest>5__1; private AudioClip <result>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadAudioClip>d__75(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(); } } <webRequest>5__1 = null; <result>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Invalid comparison between Unknown and I4 try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <webRequest>5__1 = UnityWebRequestMultimedia.GetAudioClip(filePath, GetAudioType(filePath)); <>1__state = -3; <>2__current = <webRequest>5__1.SendWebRequest(); <>1__state = 1; return true; case 1: <>1__state = -3; if ((int)<webRequest>5__1.result == 1) { <result>5__2 = DownloadHandlerAudioClip.GetContent(<webRequest>5__1); ((Object)<result>5__2).name = "Patty_SoundChanger_MOD_" + Path.GetFileNameWithoutExtension(filePath); onComplete?.Invoke(<result>5__2); <result>5__2 = null; } else { LogSource.LogError((object)<webRequest>5__1.error); onComplete?.Invoke(null); } <>m__Finally1(); <webRequest>5__1 = null; 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 (<webRequest>5__1 != null) { ((IDisposable)<webRequest>5__1).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public const string MUSIC_SECTION = "Music"; public const string SFX_SECTION = "SFX"; internal static Traverse configurationManagerTraverse; internal static Lazy<GUIStyle> centeredStyle = new Lazy<GUIStyle>((Func<GUIStyle>)(() => new GUIStyle { alignment = (TextAnchor)4 })); internal static ConfigEntry<string> currentSectionEntry; internal static MethodInfo rebuildSettings; internal static SpriteAtlas scrollbarAtlas; internal static ConfigEntry<bool> enableIngameMenu; public static readonly Signal<string> musicChanged = new Signal<string>(); public static readonly ISoundChanger soundChangerManager = new SoundChangerManager(); public static readonly Signal onInitialize = new Signal(); internal static bool Initialized { get; private set; } internal static string BasePath { get; } = Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName; internal static Plugin Instance { get; private set; } internal static ManualLogSource LogSource { get; private set; } internal static Harmony PluginHarmony { get; private set; } internal static ConfigFile Config { get; private set; } internal static OrderedDictionary<ConfigEntryBase, SoundData<MusicDefinition>> MusicEntries { get; private set; } = new OrderedDictionary<ConfigEntryBase, SoundData<MusicDefinition>>(); internal static OrderedDictionary<ConfigEntryBase, SoundData<SoundCueDefinition>> SFXEntries { get; private set; } = new OrderedDictionary<ConfigEntryBase, SoundData<SoundCueDefinition>>(); internal static OrderedDictionary<MusicDefinition, List<AudioClip>> OriginalMusics { get; private set; } = new OrderedDictionary<MusicDefinition, List<AudioClip>>(); internal static OrderedDictionary<SoundCueDefinition, List<AudioClip>> OriginalSFX { get; private set; } = new OrderedDictionary<SoundCueDefinition, List<AudioClip>>(); internal static int LeftColumnWidth { get { if (configurationManagerTraverse == null) { return 260; } Traverse val = configurationManagerTraverse.Property("LeftColumnWidth", (object[])null); if (!val.PropertyExists()) { return 260; } return val.GetValue<int>(); } } private void Awake() { //IL_003f: Expected O, but got Unknown //IL_00af: Expected O, but got Unknown //IL_0079: Expected O, but got Unknown //IL_01c4: Expected O, but got Unknown //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Expected O, but got Unknown //IL_0193: Expected O, but got Unknown //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Expected O, but got Unknown //IL_026c: Expected O, but got Unknown //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Expected O, but got Unknown //IL_02f3: Expected O, but got Unknown Instance = this; LogSource = ((BaseUnityPlugin)this).Logger; Config = ((BaseUnityPlugin)this).Config; try { PluginHarmony = Harmony.CreateAndPatchAll(typeof(PatchList), "Patty_SoundChanger_MOD"); } catch (HarmonyException val) { HarmonyException val2 = val; LogSource.LogError((object)((Exception)(((object)((Exception)(object)val2).InnerException) ?? ((object)val2))).Message); } try { PluginHarmony.PatchAll(typeof(TranspilerFix)); } catch (HarmonyException val3) { HarmonyException val4 = val3; LogSource.LogError((object)((Exception)(((object)((Exception)(object)val4).InnerException) ?? ((object)val4))).Message); try { PluginHarmony.PatchAll(typeof(TemporaryFix)); } catch (HarmonyException val5) { HarmonyException val6 = val5; LogSource.LogError((object)((Exception)(((object)((Exception)(object)val6).InnerException) ?? ((object)val6))).Message); } } if (Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out var value)) { configurationManagerTraverse = Traverse.Create((object)value.Instance); try { Type type = ((object)value.Instance).GetType().Assembly.GetType("ConfigurationManager.ConfigurationManager"); rebuildSettings = AccessTools.DeclaredMethod(type, "BuildSettingList", (Type[])null, (Type[])null); } catch (Exception ex) { LogSource.LogError((object)(ex.InnerException ?? ex).Message); } } enableIngameMenu = Config.Bind<bool>(new ConfigDefinition("Basic", "Toggle in-game menu"), true, new ConfigDescription("If enabled, then create an in-game menu (recommended to disable if future game update breaks this mod). Restart to apply", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 10001 } })); if (enableIngameMenu.Value) { try { PluginHarmony.PatchAll(typeof(MenuPatch)); } catch (HarmonyException val7) { HarmonyException val8 = val7; LogSource.LogError((object)((Exception)(((object)((Exception)(object)val8).InnerException) ?? ((object)val8))).Message); } } Config.Bind<string>(new ConfigDefinition("Basic", "Currently Playing"), "", new ConfigDescription("Only for references as to what music is currently playing in game", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 10000, CustomDrawer = CurrentlyPlayingDrawer, HideDefaultButton = true, HideSettingName = true, ReadOnly = true } })); currentSectionEntry = Config.Bind<string>(new ConfigDefinition("Basic", "Toggled Section"), "", new ConfigDescription("Only for toggling sections", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 9999, CustomDrawer = ToggleSectionDrawer, HideDefaultButton = true, HideSettingName = true, ReadOnly = true } })); if (string.IsNullOrEmpty(currentSectionEntry.Value) || (currentSectionEntry.Value != "Music" && currentSectionEntry.Value != "SFX")) { currentSectionEntry.Value = "Music"; } if (enableIngameMenu.Value) { AssetBundle val9 = AssetBundle.LoadFromFile(Path.Combine(BasePath, "scrollbar.bundle")); scrollbarAtlas = val9.LoadAsset<SpriteAtlas>("ScrollbarAtlas"); val9.Unload(false); } musicChanged.AddListener((Action<string>)OnMusicChanged); } private void OnDestroy() { musicChanged.RemoveListener((Action<string>)OnMusicChanged); } internal static void OnMusicChanged(string trackName) { SoundManager soundManager = AllGameManagers.Instance.GetSoundManager(); Traverse.Create((object)soundManager).Property("currentTrackName", (object[])null).SetValue((object)trackName); } internal static void CreateEntries() { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown if (Initialized) { return; } AllGameManagers instance = AllGameManagers.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.GetSoundManager() == (Object)null) { return; } Initialized = true; if (enableIngameMenu.Value) { SettingsScreen settingScreen = (SettingsScreen)instance.GetScreenManager().GetScreen((ScreenName)18); SoundDialog.CreateDialog(settingScreen); } SoundManager soundManager = instance.GetSoundManager(); Traverse val = Traverse.Create((object)soundManager); CoreAudioSystem value = val.Field<CoreAudioSystem>("audioSystem").Value; CoreAudioSystemData value2 = Traverse.Create((object)value).Field("AudioSystemData").GetValue<CoreAudioSystemData>(); foreach (MusicDefinition item in value2.MusicDefData.Tracks.OrderBy((MusicDefinition track) => track.Name)) { CreateEntry(item); } foreach (SoundCueDefinition item2 in value2.GlobalSoundEffectData.Sounds.OrderBy((SoundCueDefinition track) => track.Name)) { CreateEntry(item2); } SetBrowsableSection(currentSectionEntry.Value); onInitialize.Dispatch(); } internal static void CreateEntry(MusicDefinition definition) { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Expected O, but got Unknown //IL_012b: Expected O, but got Unknown if (definition == null || MusicEntries.Values.Any((SoundData<MusicDefinition> data) => data?.definition == definition)) { return; } if (!OriginalMusics.ContainsKey(definition)) { OriginalMusics[definition] = new List<AudioClip>(); MusicClipDefinition[] clips = definition.Clips; foreach (MusicClipDefinition val in clips) { OriginalMusics[definition].Add(val.Clip); } } ConfigEntry<string> entry = Config.Bind<string>(new ConfigDefinition("Basic", definition.Name), "", new ConfigDescription("", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { HideDefaultButton = true, HideSettingName = true, CustomDrawer = MusicDrawer } })); entry.SettingChanged += Entry_SettingChanged; MusicEntries[(ConfigEntryBase)(object)entry] = SoundData<MusicDefinition>.Create(entry, definition); if (MusicEntries[(ConfigEntryBase)(object)entry].IsFileExist()) { ((MonoBehaviour)Instance).StartCoroutine(LoadAudioClip(MusicEntries[(ConfigEntryBase)(object)entry].GetFilePath(), delegate(AudioClip audioClip) { OnAudioClipLoaded((ConfigEntryBase)(object)entry, audioClip); })); } } internal static void CreateEntry(SoundCueDefinition definition) { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Expected O, but got Unknown //IL_0126: Expected O, but got Unknown if (definition == null || SFXEntries.Values.Any((SoundData<SoundCueDefinition> data) => data?.definition == definition)) { return; } if (!OriginalSFX.ContainsKey(definition)) { OriginalSFX[definition] = new List<AudioClip>(); AudioClip[] clips = definition.Clips; foreach (AudioClip item in clips) { OriginalSFX[definition].Add(item); } } ConfigEntry<string> entry = Config.Bind<string>(new ConfigDefinition("Basic", definition.Name), "", new ConfigDescription("", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { HideDefaultButton = true, HideSettingName = true, CustomDrawer = MusicDrawer } })); entry.SettingChanged += Entry_SettingChanged; SFXEntries[(ConfigEntryBase)(object)entry] = SoundData<SoundCueDefinition>.Create(entry, definition); if (SFXEntries[(ConfigEntryBase)(object)entry].IsFileExist()) { ((MonoBehaviour)Instance).StartCoroutine(LoadAudioClip(SFXEntries[(ConfigEntryBase)(object)entry].GetFilePath(), delegate(AudioClip audioClip) { OnAudioClipLoaded((ConfigEntryBase)(object)entry, audioClip); })); } } internal static void Entry_SettingChanged(object sender, EventArgs e) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) ResetEntryBase(((SettingChangedEventArgs)e).ChangedSetting); } internal static void ResetEntryBase(ConfigEntryBase entryBase, Action<string> onPlay = null) { string text = entryBase.BoxedValue as string; if (!string.IsNullOrEmpty(text) && File.Exists(text)) { return; } AllGameManagers instance = AllGameManagers.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.GetSoundManager() == (Object)null) { return; } SoundManager soundManager = instance.GetSoundManager(); if (MusicEntries.TryGetValue(entryBase, out var value)) { string currentMusicTrackName = soundManager.GetCurrentMusicTrackName(); foreach (KeyValuePair<MusicDefinition, List<AudioClip>> originalMusic in OriginalMusics) { if (originalMusic.Key == value.definition) { MusicClipDefinition[] clips = originalMusic.Key.Clips; for (int i = 0; i < clips.Length; i++) { clips[i].Clip = originalMusic.Value[i]; } break; } } if (value.entryName == currentMusicTrackName) { ReplayMusic(entryBase, GetPlayingMusicName(), onPlay); } } else { if (!SFXEntries.TryGetValue(entryBase, out var value2)) { return; } foreach (KeyValuePair<SoundCueDefinition, List<AudioClip>> item in OriginalSFX) { if (item.Key == value2.definition) { AudioClip[] clips2 = item.Key.Clips; for (int j = 0; j < clips2.Length; j++) { clips2[j] = item.Value[j]; } break; } } } } internal static string GetPlayingMusicName() { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) AllGameManagers instance = AllGameManagers.Instance; if ((Object)(object)instance == (Object)null) { return ""; } if ((Object)(object)instance.GetSoundManager() == (Object)null) { return ""; } SoundManager soundManager = instance.GetSoundManager(); Traverse val = Traverse.Create((object)soundManager); List<BattleMusicTrack> value = val.Field<List<BattleMusicTrack>>("battleMusicTracks").Value; List<BattleMusicTrack> value2 = val.Field<List<BattleMusicTrack>>("bossBattleMusicTracks").Value; value.AddRange(value2); string text = ""; string musicName = soundManager.GetCurrentMusicTrackName(); BattleMusicTrack val2 = value.Find((BattleMusicTrack track) => track.trackNameData == musicName); if (!string.IsNullOrEmpty(val2.publicTrackNameKey)) { text = val2.publicTrackNameKey; if (LocalizationManager.IsTranslatableTerm(text)) { text = LocalizationExtensions.Localize(text, (ILocalizationParameterContext)null); } } return text; } internal static string GetModifiedAudioName(string trackName, CoreAudioSystem coreAudioSystem) { if (string.IsNullOrWhiteSpace(trackName)) { return ""; } Traverse val = Traverse.Create((object)coreAudioSystem).Method("GetCurrentTrack", Array.Empty<object>()); if (!val.MethodExists()) { return ""; } Traverse val2 = Traverse.Create(val.GetValue()).Field("MusicDefinition"); if (!val2.FieldExists() || val2.GetValue<MusicDefinition>() == null) { return ""; } MusicDefinition value = val2.GetValue<MusicDefinition>(); if (value == null || IEnumerableUtility.IsNullOrEmpty<MusicClipDefinition>((IEnumerable<MusicClipDefinition>)value.Clips)) { return ""; } if (value.Name != trackName) { if (!trackName.StartsWith("KEY>>") || !trackName.EndsWith("<<")) { return ""; } trackName = trackName.Substring("KEY>>".Length, trackName.Length - ("KEY>>".Length + "<<".Length)); if (value.Name != trackName) { return ""; } } MusicClipDefinition val3 = ((IEnumerable<MusicClipDefinition>)value.Clips).FirstOrDefault((Func<MusicClipDefinition, bool>)((MusicClipDefinition source) => source != null && (Object)(object)source.Clip != (Object)null && ((Object)source.Clip).name.Contains("Patty_SoundChanger_MOD"))); if (val3 != null) { return RemoveGUIDFromName(val3.Clip); } return ""; } internal static string RemoveGUIDFromName(AudioClip audioClip) { int num = "Patty_SoundChanger_MOD".Length + 1; return ((Object)audioClip).name.Substring(num, ((Object)audioClip).name.Length - num); } internal static void ToggleSectionDrawer(ConfigEntryBase entry) { bool flag = GUILayout.Button("Toggle Music", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); bool flag2 = GUILayout.Button("Toggle SFX", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); if (flag) { currentSectionEntry.Value = "Music"; SetBrowsableSection(currentSectionEntry.Value); } else if (flag2) { currentSectionEntry.Value = "SFX"; SetBrowsableSection(currentSectionEntry.Value); } } internal static void SetBrowsableSection(string section, bool updateList = true) { bool browsable = section == "Music"; bool browsable2 = section == "SFX"; SetEntriesBrowsable(SFXEntries.Keys, browsable2); SetEntriesBrowsable(MusicEntries.Keys, browsable); if (updateList && !(rebuildSettings == null)) { rebuildSettings.Invoke(configurationManagerTraverse.GetValue(), null); } } internal static void SetEntriesBrowsable(IEnumerable<object> entries, bool browsable) { foreach (object entry in entries) { ConfigEntry<string> val = (ConfigEntry<string>)entry; ConfigurationManagerAttributes configurationManagerAttributes = (ConfigurationManagerAttributes)((ConfigEntryBase)val).Description.Tags.First(); configurationManagerAttributes.Browsable = browsable; } } internal static void CurrentlyPlayingDrawer(ConfigEntryBase entry) { AllGameManagers instance = AllGameManagers.Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.GetSoundManager() == (Object)null)) { SoundManager soundManager = instance.GetSoundManager(); string text = soundManager.GetCurrentMusicTrackName(); if (!string.IsNullOrEmpty(soundManager.currentTrackName)) { text = soundManager.currentTrackName; } GUILayout.Label("<color=white>Currently playing:</color> <color=yellow>" + text + "</color>", centeredStyle.Value, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); } } internal static bool IsCurrentMusic(ConfigEntryBase entry) { bool result = false; AllGameManagers instance = AllGameManagers.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.GetSoundManager() != (Object)null && instance.GetSoundManager().GetCurrentMusicTrackName() == entry.Definition.Key) { result = true; } return result; } internal static void MusicDrawer(ConfigEntryBase entry) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown bool flag = IsCurrentMusic(entry); string text = ""; string text2 = ""; if (flag) { text = "<color=yellow>"; text2 = "</color>"; } GUILayout.Label(new GUIContent(text + entry.Definition.Key + text2, (Texture)null, entry.Description.Description), (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width((float)LeftColumnWidth - 20f), GUILayout.MaxWidth((float)LeftColumnWidth - 20f) }); string text3 = entry.BoxedValue as string; bool flag2 = File.Exists(text3); if (text3 != null && flag2) { GUILayout.Label(text + Path.GetFileName(text3) + text2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); } bool flag3 = GUILayout.Button("Load File", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); if (GUILayout.Button(" ▶ ", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) })) { if (MusicEntries.ContainsKey(entry)) { PlayMusic(entry); } else { PlaySFX(entry); } } if (flag2 && GUILayout.Button("Reset", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) })) { entry.BoxedValue = ""; ResetEntryBase(entry); } if (flag3) { LoadFile(entry, text3, flag2); } } internal static void LoadFile(ConfigEntryBase entry, string targetPath, bool existFile, Action<string, AudioClip> onComplete = null, Action<string> onPlay = null) { string filter = "Supported Files (*.wav; *.ogg; *.mp3)\0*.wav;*.ogg;*.mp3\0WAV Files (*.wav)\0*.wav\0OGG Files (*.ogg)\0*.ogg\0MP3 Files (*.mp3)\0*.mp3\0All Files\0*.*\0\0"; string initialDir = BasePath; if (existFile) { initialDir = Directory.GetParent(targetPath).FullName; } NativeFileDialog.OpenSingleFile(delegate(string filePath) { ((MonoBehaviour)Instance).StartCoroutine(LoadAudioClip(filePath, delegate(AudioClip audioClip) { if (!((Object)(object)audioClip == (Object)null)) { entry.BoxedValue = filePath; OnAudioClipLoaded(entry, audioClip, replayMusic: true, onPlay); onComplete?.Invoke(filePath, audioClip); } })); }, "Select audio to replace with", filter, initialDir, targetPath); } internal static AudioType GetAudioType(string filePath) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) return (AudioType)(Path.GetExtension(filePath)?.ToUpperInvariant() switch { ".MP3" => 13, ".OGG" => 14, ".WAV" => 20, _ => 0, }); } internal static void OnAudioClipLoaded(ConfigEntryBase entry, AudioClip audioClip, bool replayMusic = false, Action<string> onPlay = null) { try { if ((Object)(object)audioClip == (Object)null) { return; } if (MusicEntries.TryGetValue(entry, out var value)) { value.AudioData = audioClip; MusicDefinition definition = value.definition; if (definition != null) { MusicClipDefinition[] clips = definition.Clips; if (((clips != null) ? new bool?(IEnumerableUtility.IsNullOrEmpty<MusicClipDefinition>((IEnumerable<MusicClipDefinition>)clips)) : null).GetValueOrDefault()) { LogSource.LogError((object)"Definition is null, you're likely calling load before assigning a definition after creating an empty SoundData. Try to use AssignDefinitionToData before loading a file"); return; } } if (replayMusic) { ReplayMusic(entry, "", onPlay); } } else { if (!SFXEntries.TryGetValue(entry, out var value2)) { return; } value2.AudioData = audioClip; SoundCueDefinition definition2 = value2.definition; if (definition2 != null) { AudioClip[] clips2 = definition2.Clips; if (((clips2 != null) ? new bool?(IEnumerableUtility.IsNullOrEmpty<AudioClip>((IEnumerable<AudioClip>)clips2)) : null).GetValueOrDefault()) { LogSource.LogError((object)"Definition is null, you're likely calling load before assigning a definition after creating an empty SoundData. Try to use AssignDefinitionToData before loading a file"); } } } } catch (Exception ex) { LogSource.LogError((object)(ex.InnerException ?? ex).Message); LogSource.LogError((object)"You're likely loading too early before the Definition has been loaded, connect a method to Plugin.onInitialize instead"); } } internal static void ReplayMusic(ConfigEntryBase entry, string displayedName = "", Action<string> onPlay = null) { AllGameManagers instance = AllGameManagers.Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.GetSoundManager() == (Object)null)) { SoundManager soundManager = instance.GetSoundManager(); if (soundManager.GetCurrentMusicTrackName() == entry.Definition.Key) { PlayMusic(entry, isBattleMusic: false, 0.25f, "", onPlay); } } } internal static void PlayMusic(ConfigEntryBase entry, bool isBattleMusic = false, float crossfadeTimeSeconds = 0.25f, string displayedName = "", Action<string> onPlay = null) { <>c__DisplayClass73_0 CS$<>8__locals0 = new <>c__DisplayClass73_0(); CS$<>8__locals0.isBattleMusic = isBattleMusic; CS$<>8__locals0.crossfadeTimeSeconds = crossfadeTimeSeconds; CS$<>8__locals0.entry = entry; CS$<>8__locals0.displayedName = displayedName; CS$<>8__locals0.onPlay = onPlay; AllGameManagers instance = AllGameManagers.Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.GetSoundManager() == (Object)null)) { CS$<>8__locals0.soundManager = instance.GetSoundManager(); CS$<>8__locals0.soundManager.StopMusic(0.25f); ((MonoBehaviour)Instance).StartCoroutine(WaitUntilMusicStops()); } [IteratorStateMachine(typeof(<>c__DisplayClass73_0.<<PlayMusic>g__WaitUntilMusicStops|0>d))] IEnumerator WaitUntilMusicStops() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <>c__DisplayClass73_0.<<PlayMusic>g__WaitUntilMusicStops|0>d(0) { <>4__this = CS$<>8__locals0 }; } } internal static void PlaySFX(ConfigEntryBase entry, bool loop = false, Action<string> onPlay = null) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) AllGameManagers instance = AllGameManagers.Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.GetSoundManager() == (Object)null)) { SoundManager soundManager = instance.GetSoundManager(); SoundData<SoundCueDefinition> soundData = SFXEntries[entry]; bool loop2 = soundData.definition.Loop; soundData.definition.Loop = loop; soundManager.PlaySfx(entry.Definition.Key, (AudioSfxPriority)0, false); soundData.definition.Loop = loop2; onPlay?.Invoke(entry.Definition.Key); } } [IteratorStateMachine(typeof(<LoadAudioClip>d__75))] internal static IEnumerator LoadAudioClip(string filePath, Action<AudioClip> onComplete = null) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadAudioClip>d__75(0) { filePath = filePath, onComplete = onComplete }; } } public static class PluginInfo { public const string GUID = "Patty_SoundChanger_MOD"; public const string Name = "Sound Changer"; public const string Version = "2.0.0"; } public class SoundInfo : MonoBehaviour { internal ConfigEntryBase entry; internal TMP_Text titleTMP; internal TMP_Text replacementTMP; internal Dictionary<GameUISelectableButton, Action> buttons = new Dictionary<GameUISelectableButton, Action>(3); internal bool TryTrigger(CoreInputControlMapping mapping, IGameUIComponent triggeredUI, Controls triggeredMappingID) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair<GameUISelectableButton, Action> button in buttons) { if (button.Key.TryTrigger(mapping, triggeredUI, triggeredMappingID, false, false)) { button.Value(); return true; } } return false; } internal void Set(SettingsScreen settingsScreen, ConfigEntryBase entry) { //IL_0087: 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_00bf: 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_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) Traverse val = Traverse.Create((object)settingsScreen); PauseDialog value = val.Field<PauseDialog>("pauseDialog").Value; GameUISelectableButton value2 = Traverse.Create((object)value).Field<GameUISelectableButton>("settingsButton").Value; TMP_Text value3 = Traverse.Create((object)value).Field<TMP_Text>("musicLabel").Value; ContentSizeFitter val2 = ((Component)this).gameObject.AddComponent<ContentSizeFitter>(); val2.verticalFit = (FitMode)2; val2.horizontalFit = (FitMode)2; TMP_Text val3 = Object.Instantiate<TMP_Text>(value3, ((Component)val2).transform); Object.DestroyImmediate((Object)(object)((Component)val3).GetComponent<Localize>()); val3.rectTransform.anchorMin = Vector2.zero; val3.rectTransform.pivot = new Vector2(0f, 0.5f); val3.rectTransform.anchoredPosition = new Vector2(0f, 0f); val3.rectTransform.sizeDelta = new Vector2(300f, 33f); ((Object)val3).name = "Label"; val3.alignment = (TextAlignmentOptions)513; val3.overflowMode = (TextOverflowModes)1; val3.fontSizeMax = 30f; val3.fontSizeMin = 18f; val3.enableAutoSizing = true; TMP_Text val4 = Object.Instantiate<TMP_Text>(val3, ((Component)val2).transform); ((Object)val4).name = "Replacement Label"; val4.rectTransform.anchoredPosition = new Vector2(320f, 0f); GameUISelectableButton val5 = Object.Instantiate<GameUISelectableButton>(value2, ((Component)val2).transform); ((Component)val5).GetComponent<RectTransform>().anchorMax = new Vector2(1f, 0.5f); ((Component)val5).GetComponent<RectTransform>().anchorMin = new Vector2(1f, 0.5f); ((Component)val5).GetComponent<RectTransform>().anchoredPosition = new Vector2(-20f, 0f); ((Component)val5).GetComponent<RectTransform>().pivot = new Vector2(1f, 0.5f); ((Component)val5).GetComponent<RectTransform>().sizeDelta = new Vector2(100f, 64f); Object.DestroyImmediate((Object)(object)((Component)val5).GetComponentInChildren<Localize>()); ((TMP_Text)((Component)val5).GetComponentInChildren<TextMeshProUGUI>()).text = "Reset"; ((Object)val5).name = "Reset Button"; GameUISelectableButton val6 = Object.Instantiate<GameUISelectableButton>(val5, ((Component)val2).transform); ((Component)val6).GetComponent<RectTransform>().sizeDelta = new Vector2(120f, 64f); ((Component)val6).GetComponent<RectTransform>().anchoredPosition = new Vector2(-150f, 0f); ((TMP_Text)((Component)val6).GetComponentInChildren<TextMeshProUGUI>()).text = "Load File"; ((Object)val6).name = "Load File Button"; GameUISelectableButton val7 = Object.Instantiate<GameUISelectableButton>(val6, ((Component)val2).transform); ((Component)val7).GetComponent<RectTransform>().sizeDelta = new Vector2(50f, 64f); ((Component)val7).GetComponent<RectTransform>().anchoredPosition = new Vector2(-300f, 0f); ((TMP_Text)((Component)val7).GetComponentInChildren<TextMeshProUGUI>()).text = " ▶ "; ((Object)val7).name = "Play Button"; this.entry = entry; ((ConfigEntry<string>)(object)this.entry).SettingChanged += SoundInfo_SettingChanged; titleTMP = val3; replacementTMP = val4; buttons[val7] = PlayMusic; buttons[val6] = LoadFile; buttons[val5] = ResetMusic; UpdateText(); Plugin.musicChanged.AddListener((Action<string>)OnMusicChanged); } private void OnDestroy() { ((ConfigEntry<string>)(object)entry).SettingChanged -= SoundInfo_SettingChanged; Plugin.musicChanged.RemoveListener((Action<string>)OnMusicChanged); } private void OnMusicChanged(string trackName) { UpdateText(); } private void SoundInfo_SettingChanged(object sender, EventArgs e) { UpdateText(); } internal void PlayMusic() { if (Plugin.MusicEntries.ContainsKey(entry)) { Plugin.PlayMusic(entry, isBattleMusic: false, 0.25f, "", delegate { UpdateText(); }); } else { Plugin.PlaySFX(entry); } } internal void LoadFile() { string text = entry.BoxedValue as string; bool existFile = File.Exists(text); Plugin.LoadFile(entry, text, existFile, null, delegate(string trackName) { UpdateText(); SoundDialog.Instance.UpdateCurrentMusicName(trackName); }); } internal void ResetMusic() { entry.BoxedValue = ""; Plugin.ResetEntryBase(entry, delegate { UpdateText(); }); } public void UpdateText() { bool flag = Plugin.IsCurrentMusic(entry); string text = ""; string text2 = ""; if (flag) { text = "<color=yellow>"; text2 = "</color>"; } titleTMP.text = text + entry.Definition.Key + text2; replacementTMP.text = text + Path.GetFileName(entry.BoxedValue as string) + text2; } } internal class TemporaryFix { [HarmonyPrefix] [HarmonyPatch(typeof(MusicNotificationHandler), "OnBattleMusicChanged")] public static void OnBattleMusicChanged(ref string trackName) { trackName = AllGameManagers.Instance.GetSoundManager().currentTrackName; } } internal class TranspilerFix { [HarmonyTranspiler] [HarmonyPatch(typeof(Sound
ATL.dll
Decompiled 2 months 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.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Xml; using ATL; using ATL.AudioData; using ATL.AudioData.IO; using ATL.CatalogDataReaders.BinaryLogic; using ATL.Logging; using ATL.Playlist.IO; using Commons; using HashDepot; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")] [assembly: InternalsVisibleTo("ATL.test")] [assembly: AssemblyCompany("Zeugma440")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Fully managed, portable and easy-to-use C# library to read and edit audio data and metadata (tags) from various audio formats, playlists and CUE sheets")] [assembly: AssemblyFileVersion("3.25.0.0")] [assembly: AssemblyInformationalVersion("3.25")] [assembly: AssemblyProduct("Audio Tools Library (ATL) for .NET")] [assembly: AssemblyTitle("ATL")] [assembly: AssemblyVersion("3.25.0.0")] namespace Commons { public enum ImageFormat { Unsupported = 99, Undefined = 98, Jpeg = 1, Gif = 2, Png = 3, Bmp = 4, Tiff = 5 } public class ImageProperties { public ImageFormat Format = ImageFormat.Undefined; public int Width; public int Height; public int ColorDepth; public int NumColorsInPalette; } public static class ImageUtils { public static string GetMimeTypeFromImageFormat(ImageFormat imageFormat) { string text = "image/"; if (imageFormat.Equals(ImageFormat.Jpeg)) { return text + "jpeg"; } if (imageFormat.Equals(ImageFormat.Gif)) { return text + "gif"; } if (imageFormat.Equals(ImageFormat.Png)) { return text + "png"; } if (imageFormat.Equals(ImageFormat.Bmp)) { return text + "bmp"; } if (imageFormat.Equals(ImageFormat.Tiff)) { return text + "tiff"; } return text + "*"; } public static ImageFormat GetImageFormatFromMimeType(string mimeType) { ImageFormat result = ImageFormat.Jpeg; if (mimeType.Contains("gif")) { result = ImageFormat.Gif; } else if (mimeType.Contains("png")) { result = ImageFormat.Png; } else if (mimeType.Contains("bmp")) { result = ImageFormat.Bmp; } else if (mimeType.Contains("tiff")) { result = ImageFormat.Tiff; } return result; } public static ImageFormat GetImageFormatFromPictureHeader(byte[] header) { if (header.Length < 3) { throw new FormatException("Header length must be at least 3"); } if (byte.MaxValue == header[0] && 216 == header[1] && byte.MaxValue == header[2]) { return ImageFormat.Jpeg; } if (66 == header[0] && 77 == header[1]) { return ImageFormat.Bmp; } if (71 == header[0] && 73 == header[1] && 70 == header[2]) { return ImageFormat.Gif; } if (137 == header[0] && 80 == header[1] && 78 == header[2]) { return ImageFormat.Png; } if (73 == header[0] && 73 == header[1] && 42 == header[2]) { return ImageFormat.Tiff; } if (77 == header[0] && 77 == header[1] && header[2] == 0) { return ImageFormat.Tiff; } return ImageFormat.Unsupported; } public static ImageProperties GetImageProperties(byte[] imageData, ImageFormat format = ImageFormat.Undefined) { ImageProperties imageProperties = new ImageProperties(); if (ImageFormat.Undefined.Equals(format)) { format = GetImageFormatFromPictureHeader(imageData); } if (format.Equals(ImageFormat.Unsupported)) { return imageProperties; } imageProperties.NumColorsInPalette = 0; imageProperties.Format = format; using (MemoryStream memoryStream = new MemoryStream(imageData)) { using BinaryReader binaryReader = new BinaryReader(memoryStream); long limit = (long)Math.Round((double)memoryStream.Length * 0.25); switch (format) { case ImageFormat.Tiff: { bool flag = 77 == binaryReader.ReadByte(); memoryStream.Seek(3L, SeekOrigin.Current); long offset = readInt32(binaryReader, flag); memoryStream.Seek(offset, SeekOrigin.Begin); int num5 = readInt16(binaryReader, flag); int num6 = 0; int num2 = 0; int num7 = 0; for (int i = 0; i < num5; i++) { int num8 = readInt16(binaryReader, flag); readInt16(binaryReader, flag); readInt32(binaryReader, flag); byte[] array3 = binaryReader.ReadBytes(4); int num9 = (flag ? StreamUtils.DecodeBEInt32(array3) : StreamUtils.DecodeInt32(array3)); int num10 = (flag ? StreamUtils.DecodeBEInt16(array3) : StreamUtils.DecodeInt16(array3)); switch (num8) { case 256: imageProperties.Width = num9; if (array3[2] + array3[3] == 0) { imageProperties.Width = num10; } break; case 257: imageProperties.Height = num9; if (array3[2] + array3[3] == 0) { imageProperties.Height = num10; } break; case 262: num6 = num9; if (num9 < 2) { imageProperties.ColorDepth = 1; } else if (2 == num9) { imageProperties.ColorDepth = 24; } break; case 258: num2 = num10; break; case 277: num7 = num10; break; } } if (num6 < 2) { imageProperties.ColorDepth = num2; } else if (2 == num6) { imageProperties.ColorDepth = 8 * num7; } else if (3 == num6) { imageProperties.ColorDepth = 8 * num7; imageProperties.NumColorsInPalette = num2; } break; } case ImageFormat.Gif: { byte[] sequence2 = new byte[2] { 33, 249 }; imageProperties.ColorDepth = 24; memoryStream.Seek(3L, SeekOrigin.Current); string @string = Utils.Latin1Encoding.GetString(binaryReader.ReadBytes(3)); memoryStream.Seek(4L, SeekOrigin.Current); byte b2 = binaryReader.ReadByte(); if ((b2 & 0x80) >> 7 > 0) { imageProperties.NumColorsInPalette = 2 << (b2 & 7); } if ("89a".Equals(@string)) { long position = memoryStream.Position; if (StreamUtils.FindSequence(memoryStream, sequence2, 0L)) { memoryStream.Seek(6L, SeekOrigin.Current); } else { LogDelegator.GetLogDelegate()(2, "Invalid v89a GIF file; no graphic control extension block found"); memoryStream.Seek(position, SeekOrigin.Begin); if (StreamUtils.FindSequence(memoryStream, new byte[1] { 44 }, 0L)) { memoryStream.Seek(-1L, SeekOrigin.Current); } } } if (44 == binaryReader.ReadByte()) { memoryStream.Seek(4L, SeekOrigin.Current); imageProperties.Width = binaryReader.ReadInt16(); imageProperties.Height = binaryReader.ReadInt16(); if (imageProperties.NumColorsInPalette == 0) { imageProperties.NumColorsInPalette = (int)Math.Pow(2.0, ((b2 & 0xF) << 4) + 1); } } else { LogDelegator.GetLogDelegate()(2, "Error parsing GIF file; image block not found"); } break; } case ImageFormat.Bmp: memoryStream.Seek(18L, SeekOrigin.Begin); imageProperties.Width = binaryReader.ReadInt32(); imageProperties.Height = binaryReader.ReadInt32(); memoryStream.Seek(2L, SeekOrigin.Current); imageProperties.ColorDepth = binaryReader.ReadInt16(); break; case ImageFormat.Png: { byte[] array2 = new byte[4]; byte[] bytes = Utils.Latin1Encoding.GetBytes("IHDR"); byte[] bytes2 = Utils.Latin1Encoding.GetBytes("PLTE"); memoryStream.Seek(8L, SeekOrigin.Begin); if (findPngChunk(memoryStream, bytes, limit) == 0) { LogDelegator.GetLogDelegate()(2, "Invalid PNG file; no IHDR chunk found"); break; } memoryStream.Read(array2, 0, 4); imageProperties.Width = StreamUtils.DecodeBEInt32(array2); memoryStream.Read(array2, 0, 4); imageProperties.Height = StreamUtils.DecodeBEInt32(array2); imageProperties.ColorDepth = binaryReader.ReadByte(); int num3 = binaryReader.ReadByte(); if (3 == num3) { memoryStream.Seek(7L, SeekOrigin.Current); uint num4 = findPngChunk(memoryStream, bytes2, limit); if (num4 == 0) { LogDelegator.GetLogDelegate()(2, "Invalid PNG file; palette declared, but no PLTE chunk found"); } else { imageProperties.NumColorsInPalette = (int)Math.Floor((double)num4 / 3.0); } } else { imageProperties.NumColorsInPalette = 0; } break; } case ImageFormat.Jpeg: { byte[] array = new byte[2]; byte[] sequence = new byte[2] { 255, 192 }; long num = 0L; while (StreamUtils.FindSequence(memoryStream, sequence, limit)) { num = memoryStream.Position; } if (num == 0L) { LogDelegator.GetLogDelegate()(2, "Invalid JPEG file; no SOF0 frame found"); break; } memoryStream.Seek(2L, SeekOrigin.Current); int num2 = binaryReader.ReadByte(); memoryStream.Read(array, 0, 2); imageProperties.Height = StreamUtils.DecodeBEUInt16(array); memoryStream.Read(array, 0, 2); imageProperties.Width = StreamUtils.DecodeBEUInt16(array); byte b = binaryReader.ReadByte(); imageProperties.ColorDepth = num2 * b; break; } } } return imageProperties; } private static uint findPngChunk(Stream s, byte[] chunkID, long limit) { byte[] array = new byte[4]; while (s.Position < limit) { s.Read(array, 0, 4); uint num = StreamUtils.DecodeBEUInt32(array); s.Read(array, 0, 4); if (StreamUtils.ArrEqualsArr(array, chunkID)) { return num; } s.Seek(num + 4, SeekOrigin.Current); } return 0u; } private static short readInt16(BinaryReader r, bool isBigEndian) { if (!isBigEndian) { return r.ReadInt16(); } return StreamUtils.DecodeBEInt16(r.ReadBytes(2)); } private static int readInt32(BinaryReader r, bool isBigEndian) { if (!isBigEndian) { return r.ReadInt32(); } return StreamUtils.DecodeBEInt32(r.ReadBytes(4)); } } public static class Utils { public delegate void voidDelegate(); private static Encoding latin1Encoding = Encoding.GetEncoding("ISO-8859-1"); public static readonly string UNICODE_INVISIBLE_EMPTY = "\ufeff"; public static Encoding Latin1Encoding => latin1Encoding; public static string ProtectValue(string value) { if (value != null) { return value; } return ""; } public static string ProtectYear(DateTime value) { if (!(DateTime.MinValue == value)) { return value.Year.ToString(); } return ""; } public static string EncodeTimecode_ms(long milliseconds) { long num = Convert.ToInt64(Math.Floor((double)milliseconds / 1000.0)); return EncodeTimecode_s(num) + "." + (milliseconds - num * 1000); } public static string EncodeTimecode_s(long seconds) { int num = Convert.ToInt32(Math.Floor((double)seconds / 3600.0)); long num2 = Convert.ToInt64(Math.Floor(((double)seconds - 3600.0 * (double)num) / 60.0)); long num3 = seconds - 60 * num2 - 3600 * num; int num4 = Convert.ToInt32(Math.Floor((double)num / 24.0)); if (num4 > 0) { num -= 24 * num4; } string text = num.ToString(); if (1 == text.Length) { text = "0" + text; } string text2 = num2.ToString(); if (1 == text2.Length) { text2 = "0" + text2; } string text3 = num3.ToString(); if (1 == text3.Length) { text3 = "0" + text3; } if (num4 > 0) { return num4 + "d " + text + ":" + text2 + ":" + text3; } if (num > 0) { return text + ":" + text2 + ":" + text3; } return text2 + ":" + text3; } public static int DecodeTimecodeToMs(string timeCode) { int result = -1; DateTime result2 = default(DateTime); bool flag = false; if (DateTime.TryParse(timeCode, out result2)) { flag = true; result = result2.Millisecond; result += result2.Second * 1000; result += result2.Minute * 60 * 1000; result += result2.Hour * 60 * 60 * 1000; } else { int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; if (timeCode.Contains(":")) { flag = true; string[] array = timeCode.Split(new char[1] { ':' }); if (array[^1].Contains(".")) { string[] array2 = array[^1].Split(new char[1] { '.' }); array[^1] = array2[0]; num5 = int.Parse(array2[1]); } num4 = int.Parse(array[^1]); num3 = int.Parse(array[^2]); if (array.Length >= 3) { string[] array3 = array[^3].Split(new char[1] { 'd' }); if (array3.Length > 1) { num = int.Parse(array3[0].Trim()); num2 = int.Parse(array3[1].Trim()); } else { num2 = int.Parse(array3[0]); } } result = num5; result += num4 * 1000; result += num3 * 60 * 1000; result += num2 * 60 * 60 * 1000; result += num * 24 * 60 * 60 * 1000; } } if (!flag) { result = -1; } return result; } public static string StripEndingZeroChars(string iStr) { int num = iStr.Length; while (num > 0 && iStr[num - 1] == '\0') { num--; } return iStr.Substring(0, num); } public static string BuildStrictLengthString(int value, int length, char paddingChar, bool padRight = true) { return BuildStrictLengthString(value.ToString(), length, paddingChar, padRight); } public static string BuildStrictLengthString(string value, int length, char paddingChar, bool padRight = true) { string text = ((value == null) ? "" : value); if (text.Length > length) { text = text.Substring(0, length); } else if (text.Length < length) { text = ((!padRight) ? text.PadLeft(length, paddingChar) : text.PadRight(length, paddingChar)); } return text; } public static byte[] BuildStrictLengthStringBytes(string value, int targetLength, byte paddingByte, Encoding encoding, bool padRight = true) { byte[] bytes = encoding.GetBytes(value); while (bytes.Length > targetLength) { value = value.Remove(value.Length - 1); bytes = encoding.GetBytes(value); } byte[] array; if (bytes.Length < targetLength) { array = new byte[targetLength]; if (padRight) { Array.Copy(bytes, array, bytes.Length); for (int i = bytes.Length; i < array.Length; i++) { array[i] = paddingByte; } } else { Array.Copy(bytes, 0, array, array.Length - bytes.Length, bytes.Length); for (int j = 0; j < array.Length - bytes.Length; j++) { array[j] = paddingByte; } } } else { array = bytes; } return array; } public static bool ToBoolean(string value) { if (value != null) { value = value.Trim(); if (value.Length > 0) { if (float.TryParse(value, out var result)) { return result != 0f; } value = value.ToLower(); return "true".Equals(value); } } return false; } public static byte[] DecodeFrom64(byte[] encodedData) { if (encodedData.Length % 4 > 0) { throw new FormatException("Size must me multiple of 4"); } char[] array = new char[encodedData.Length]; Latin1Encoding.GetChars(encodedData, 0, encodedData.Length, array, 0); return Convert.FromBase64CharArray(array, 0, array.Length); } public static byte[] EncodeTo64(byte[] data) { long num = (long)(1.3333333333333333 * (double)data.Length); if (num % 4 != 0L) { num += 4 - num % 4; } char[] array = new char[num]; Convert.ToBase64CharArray(data, 0, data.Length, array, 0); return Latin1Encoding.GetBytes(array); } public static bool IsNumeric(string s, bool allowsOnlyIntegers = false) { if (s == null || s.Length == 0) { return false; } for (int i = 0; i < s.Length; i++) { if (s[i] == '.' || s[i] == ',') { if (allowsOnlyIntegers) { return false; } } else if (!char.IsDigit(s[i]) && s[i] != '-') { return false; } } return true; } public static bool IsDigit(char c) { if (c >= '0') { return c <= '9'; } return false; } public static bool IsHex(string s) { if (s == null || s.Length == 0) { return false; } if (s.Length % 2 > 0) { return false; } for (int i = 0; i < s.Length; i++) { char c = char.ToUpper(s[i]); if (!char.IsDigit(c) && c != 'A' && c != 'B' && c != 'C' && c != 'D' && c != 'E' && c != 'F') { return false; } } return true; } public static double ParseDouble(string s) { if (!IsNumeric(s)) { return 0.0; } string[] array = s.Split(',', '.'); if (array.Length > 2) { return 0.0; } if (1 == array.Length) { return double.Parse(s); } double num = Math.Pow(10.0, array[1].Length); double num2 = double.Parse(array[0]); if (num2 >= 0.0) { return num2 + double.Parse(array[1]) / num; } return num2 - double.Parse(array[1]) / num; } public static string GetBytesReadable(long i) { long num = ((i < 0) ? (-i) : i); string text; double num2; if (num >= 1152921504606846976L) { text = "EB"; num2 = i >> 50; } else if (num >= 1125899906842624L) { text = "PB"; num2 = i >> 40; } else if (num >= 1099511627776L) { text = "TB"; num2 = i >> 30; } else if (num >= 1073741824) { text = "GB"; num2 = i >> 20; } else if (num >= 1048576) { text = "MB"; num2 = i >> 10; } else { if (num < 1024) { return i.ToString("0 B"); } text = "KB"; num2 = i; } return (num2 / 1024.0).ToString("0.## ") + text; } } } namespace HashDepot { public static class FNV1a { public static uint Hash32(byte[] buffer) { uint num = 2166136261u; for (uint num2 = 0u; num2 < buffer.Length; num2++) { num = 16777619 * (num ^ num2); } return num; } } } namespace ATL { public static class OggCRC32 { private static readonly uint[] CRC_TABLE = new uint[256] { 0u, 79764919u, 159529838u, 222504665u, 319059676u, 398814059u, 445009330u, 507990021u, 638119352u, 583659535u, 797628118u, 726387553u, 890018660u, 835552979u, 1015980042u, 944750013u, 1276238704u, 1221641927u, 1167319070u, 1095957929u, 1595256236u, 1540665371u, 1452775106u, 1381403509u, 1780037320u, 1859660671u, 1671105958u, 1733955601u, 2031960084u, 2111593891u, 1889500026u, 1952343757u, 2552477408u, 2632100695u, 2443283854u, 2506133561u, 2334638140u, 2414271883u, 2191915858u, 2254759653u, 3190512472u, 3135915759u, 3081330742u, 3009969537u, 2905550212u, 2850959411u, 2762807018u, 2691435357u, 3560074640u, 3505614887u, 3719321342u, 3648080713u, 3342211916u, 3287746299u, 3467911202u, 3396681109u, 4063920168u, 4143685023u, 4223187782u, 4286162673u, 3779000052u, 3858754371u, 3904687514u, 3967668269u, 881225847u, 809987520u, 1023691545u, 969234094u, 662832811u, 591600412u, 771767749u, 717299826u, 311336399u, 374308984u, 453813921u, 533576470u, 25881363u, 88864420u, 134795389u, 214552010u, 2023205639u, 2086057648u, 1897238633u, 1976864222u, 1804852699u, 1867694188u, 1645340341u, 1724971778u, 1587496639u, 1516133128u, 1461550545u, 1406951526u, 1302016099u, 1230646740u, 1142491917u, 1087903418u, 2896545431u, 2825181984u, 2770861561u, 2716262478u, 3215044683u, 3143675388u, 3055782693u, 3001194130u, 2326604591u, 2389456536u, 2200899649u, 2280525302u, 2578013683u, 2640855108u, 2418763421u, 2498394922u, 3769900519u, 3832873040u, 3912640137u, 3992402750u, 4088425275u, 4151408268u, 4197601365u, 4277358050u, 3334271071u, 3263032808u, 3476998961u, 3422541446u, 3585640067u, 3514407732u, 3694837229u, 3640369242u, 1762451694u, 1842216281u, 1619975040u, 1682949687u, 2047383090u, 2127137669u, 1938468188u, 2001449195u, 1325665622u, 1271206113u, 1183200824u, 1111960463u, 1543535498u, 1489069629u, 1434599652u, 1363369299u, 622672798u, 568075817u, 748617968u, 677256519u, 907627842u, 853037301u, 1067152940u, 995781531u, 51762726u, 131386257u, 177728840u, 240578815u, 269590778u, 349224269u, 429104020u, 491947555u, 4046411278u, 4126034873u, 4172115296u, 4234965207u, 3794477266u, 3874110821u, 3953728444u, 4016571915u, 3609705398u, 3555108353u, 3735388376u, 3664026991u, 3290680682u, 3236090077u, 3449943556u, 3378572211u, 3174993278u, 3120533705u, 3032266256u, 2961025959u, 2923101090u, 2868635157u, 2813903052u, 2742672763u, 2604032198u, 2683796849u, 2461293480u, 2524268063u, 2284983834u, 2364738477u, 2175806836u, 2238787779u, 1569362073u, 1498123566u, 1409854455u, 1355396672u, 1317987909u, 1246755826u, 1192025387u, 1137557660u, 2072149281u, 2135122070u, 1912620623u, 1992383480u, 1753615357u, 1816598090u, 1627664531u, 1707420964u, 295390185u, 358241886u, 404320391u, 483945776u, 43990325u, 106832002u, 186451547u, 266083308u, 932423249u, 861060070u, 1041341759u, 986742920u, 613929101u, 542559546u, 756411363u, 701822548u, 3316196985u, 3244833742u, 3425377559u, 3370778784u, 3601682597u, 3530312978u, 3744426955u, 3689838204u, 3819031489u, 3881883254u, 3928223919u, 4007849240u, 4037393693u, 4100235434u, 4180117107u, 4259748804u, 2310601993u, 2373574846u, 2151335527u, 2231098320u, 2596047829u, 2659030626u, 2470359227u, 2550115596u, 2947551409u, 2876312838u, 2788305887u, 2733848168u, 3165939309u, 3094707162u, 3040238851u, 2985771188u }; public static uint CalculateCRC(uint CRC, byte[] data, uint size) { for (uint num = 0u; num < size; num++) { CRC = (CRC << 8) ^ CRC_TABLE[((CRC >> 24) & 0xFF) ^ data[num]]; } return CRC; } } public class ChannelsArrangements { public class ChannelsArrangement { public string Description { get; set; } public int NbChannels { get; set; } public ChannelsArrangement(int nbChannels, string description) { NbChannels = nbChannels; Description = description; } public ChannelsArrangement(int nbChannels) { NbChannels = nbChannels; Description = nbChannels + " channels"; } public override string ToString() { return Description; } } public static readonly ChannelsArrangement UNKNOWN = new ChannelsArrangement(0, "Unknown"); public static readonly ChannelsArrangement ISO_1_0_0 = new ChannelsArrangement(1, "Mono (1/0.0)"); public static readonly ChannelsArrangement MONO = ISO_1_0_0; public static readonly ChannelsArrangement ISO_2_0_0 = new ChannelsArrangement(2, "Stereo (2/0.0)"); public static readonly ChannelsArrangement STEREO = ISO_2_0_0; public static readonly ChannelsArrangement ISO_3_0_0 = new ChannelsArrangement(3, "Center - Left - Right (3/0.0)"); public static readonly ChannelsArrangement ISO_3_1_0 = new ChannelsArrangement(3, "Left - Right - Center - Center rear (3/1.0)"); public static readonly ChannelsArrangement ISO_3_2_0 = new ChannelsArrangement(5, "Center - Left - Right - Left surround - Right surround (3/2.0)"); public static readonly ChannelsArrangement ISO_3_2_1 = new ChannelsArrangement(6, "Center - Left - Right - Left surround - Right surround - Center front LFE (3/2.1) (aka 5.1)"); public static readonly ChannelsArrangement ISO_5_2_1 = new ChannelsArrangement(6, "Center - Left center - Right center - Left - Right - Left surround - Right surround - Center front LFE (5/2.1)"); public static readonly ChannelsArrangement ISO_1_1 = new ChannelsArrangement(2, "Dual Mono (1+1)"); public static readonly ChannelsArrangement DUAL_MONO = ISO_1_1; public static readonly ChannelsArrangement ISO_2_1_0 = new ChannelsArrangement(3, "Left front - Right front - Center rear (2/1.0)"); public static readonly ChannelsArrangement ISO_2_2_0 = new ChannelsArrangement(4, "Left front - Right front - Left rear - Right rear (2/2.0) (aka Quad)"); public static readonly ChannelsArrangement QUAD = ISO_2_2_0; public static readonly ChannelsArrangement ISO_3_3_1 = new ChannelsArrangement(7, "Center front - Left front - Right front - Left surround - Right surround - Center rear - Center front LFE (3/3.1) (aka 6.1)"); public static readonly ChannelsArrangement ISO_3_4_1 = new ChannelsArrangement(8, "Center front - Left front - Right front - Left surround - Right surround - Left rear - Right rear - Center front LFE (3/4.1)"); public static readonly ChannelsArrangement ISO_11_11_2 = new ChannelsArrangement(24, "Center front - Left front - Right front - Left outside front - Right outside front - Left side - Right side - Left back - Right back - Center back - Left front LFE - Right front LFE - Top center front - Top left front - Top right front - Top left side - Top right side - Center Ceiling - Top left back - Top right back - Top center back - Bottom center front - Bottom left front - Bottom right front (11/11.2)"); public static readonly ChannelsArrangement JOINT_STEREO = new ChannelsArrangement(2, "Joint Stereo"); public static readonly ChannelsArrangement JOINT_STEREO_INTENSITY = new ChannelsArrangement(2, "Joint Stereo - intensity"); public static readonly ChannelsArrangement JOINT_STEREO_LEFT_SIDE = new ChannelsArrangement(2, "Joint Stereo - left/side"); public static readonly ChannelsArrangement JOINT_STEREO_RIGHT_SIDE = new ChannelsArrangement(2, "Joint Stereo - right/side"); public static readonly ChannelsArrangement JOINT_STEREO_MID_SIDE = new ChannelsArrangement(2, "Joint Stereo - mid/side"); public static readonly ChannelsArrangement STEREO_LEFT_RIGHT_TOTAL = new ChannelsArrangement(2, "Stereo - Left & Right Total (matrix)"); public static readonly ChannelsArrangement LRCS = new ChannelsArrangement(4, "Left - Right - Center - Surround"); public static readonly ChannelsArrangement LRCLFECrLssRss = new ChannelsArrangement(7, "Left front - Right front - Center front - LFE - Center rear - Left side - Right side"); public static readonly ChannelsArrangement LRCLFELrRrLssRss = new ChannelsArrangement(8, "Left front - Right front - Center front - LFE - Left rear - Right rear - Left side - Right side"); public static readonly ChannelsArrangement LRLcRcCS = new ChannelsArrangement(6, "Left - Right - Left center - Right center - Center - Surround"); public static readonly ChannelsArrangement LRCLFE = new ChannelsArrangement(4, "Left - Right - Center - LFE"); public static readonly ChannelsArrangement STEREO_SUM_DIFFERENCE = new ChannelsArrangement(2, "Stereo - Sum & Difference"); public static readonly ChannelsArrangement CLCRLRSLSR = new ChannelsArrangement(6, "Left center - Right center - Left - Right - Left surround - Right surround"); public static readonly ChannelsArrangement CLRLRRRO = new ChannelsArrangement(6, "Center - Left - Right - Left rear - Right rear - Overhead"); public static readonly ChannelsArrangement CFCRLFRFLRRR = new ChannelsArrangement(6, "Center front - Center rear - Left front - Right front - Left rear - Right rear"); public static readonly ChannelsArrangement CLCCRLRSLSR = new ChannelsArrangement(7, "Left center - Center - Right center - Left - Right - Left surround - Right surround"); public static readonly ChannelsArrangement CLCRLRSL1SL2SR1SR2 = new ChannelsArrangement(8, "Left center - Right center - Left - Right - Left surround 1 - Left surround 2 - Right surround 1 - Right surround 2"); public static readonly ChannelsArrangement CLCCRLRSLSSR = new ChannelsArrangement(8, "Left center - Center - Right center - Left - Right - Left surround - Surround - Right surround"); public static readonly ChannelsArrangement STEREO_XY = new ChannelsArrangement(2, "Stereo - XY"); public static readonly ChannelsArrangement STEREO_BINAURAL = new ChannelsArrangement(2, "Stereo - Binaural"); public static readonly ChannelsArrangement AMBISONIC_B = new ChannelsArrangement(4, "Ambisonic B (W, X, Y, Z)"); public static readonly ChannelsArrangement PENTAGONAL = new ChannelsArrangement(5, "Left front - Right front - Left rear - Right rear - Center"); public static readonly ChannelsArrangement HEXAGONAL = new ChannelsArrangement(6, "Left - Right - Left rear - Right rear - Center - Rear"); public static readonly ChannelsArrangement OCTAGONAL = new ChannelsArrangement(8, "Left front - Right front - Left rear - Right rear - Center front - Center rear - Left side - Right side"); public static readonly ChannelsArrangement CUBE = new ChannelsArrangement(8, "Left - Right - Left rear - Right rear - Left top - Right top - Left top rear - Right top rear"); public static readonly ChannelsArrangement MPEG_6_1 = new ChannelsArrangement(7, "Left - Right - Center - LFE - Left surround - Right surround - Center surround"); public static readonly ChannelsArrangement MPEG_7_1 = new ChannelsArrangement(8, "Left - Right - Center - LFE - Left surround - Right surround - Left center - Right center"); public static readonly ChannelsArrangement SMPTE_DTV = new ChannelsArrangement(8, "Left - Right - Center - LFE - Left surround - Right surround - Left top - Right top"); public static readonly ChannelsArrangement ITU_2_1 = new ChannelsArrangement(2, "Left - Right - Center surround"); public static readonly ChannelsArrangement ITU_2_2 = new ChannelsArrangement(4, "Left - Right - Left surround - Right surround"); public static readonly ChannelsArrangement DVD_4 = new ChannelsArrangement(3, "Left - Right - LFE"); public static readonly ChannelsArrangement DVD_5 = new ChannelsArrangement(4, "Left - Right - LFE - Center surround"); public static readonly ChannelsArrangement DVD_6 = new ChannelsArrangement(5, "Left - Right - LFE - Left surround - Right surround"); public static readonly ChannelsArrangement DVD_10 = new ChannelsArrangement(4, "Left - Right - Center - LFE"); public static readonly ChannelsArrangement DVD_11 = new ChannelsArrangement(5, "Left - Right - Center - LFE - Center surround"); public static readonly ChannelsArrangement DVD_18 = new ChannelsArrangement(5, "Left - Right - Left surround - Right surround - LFE"); public static readonly ChannelsArrangement AUDIOUNIT_6_0 = new ChannelsArrangement(6, "Left - Right - Left surround - Right surround - Center - Center surround"); public static readonly ChannelsArrangement AUDIOUNIT_7_0 = new ChannelsArrangement(7, "Left - Right - Left surround - Right surround - Center - Left rear surround - Right rear surround"); public static readonly ChannelsArrangement AAC_6_0 = new ChannelsArrangement(6, "Center - Left - Right - Left surround - Right surround - Center surround"); public static readonly ChannelsArrangement AAC_6_1 = new ChannelsArrangement(7, "Center - Left - Right - Left surround - Right surround - Center surround - LFE"); public static readonly ChannelsArrangement AAC_7_0 = new ChannelsArrangement(7, "Center - Left - Right - Left surround - Right surround - Left rear surround - Right rear surround"); public static readonly ChannelsArrangement AAC_OCTAGONAL = new ChannelsArrangement(8, "Center - Left - Right - Left surround - Right surround - Left rear surround - Right rear surround - Center surround"); public static readonly ChannelsArrangement TMH_10_2_STD = new ChannelsArrangement(16, "Left - Right - Center - Vertical height center - Left surround direct - Right surround direct - Left surround - Right surround - Vertical height left - Vertical height right - Lw - Rw - Center surround direct - Center surround - LFE1 - LFE2"); public static readonly ChannelsArrangement TMH_10_2_FULL = new ChannelsArrangement(16, "Left - Right - Center - Vertical height center - Left surround direct - Right surround direct - Left surround - Right surround - Vertical height left - Vertical height right - Lw - Rw - Center surround direct - Center surround - LFE1 - LFE2 - Left center - Right center - Horizontal I - Vertical I - Haptic"); public static ChannelsArrangement GuessFromChannelNumber(int nbChannels) { return nbChannels switch { 1 => MONO, 2 => STEREO, 3 => ISO_3_0_0, 4 => QUAD, 5 => ISO_3_2_0, 6 => ISO_3_2_1, 7 => ISO_3_3_1, 8 => ISO_3_4_1, _ => new ChannelsArrangement(nbChannels), }; } } public class ChapterInfo { public class UrlInfo { public string Description { get; set; } public string Url { get; set; } public UrlInfo(UrlInfo url) { Description = url.Description; Url = url.Url; } public UrlInfo(string description, string url) { Description = description; Url = url; } public UrlInfo(string url) { Description = ""; Url = url; } public override string ToString() { string description = Description; char internalValueSeparator = Settings.InternalValueSeparator; return description + internalValueSeparator + Url; } } public uint StartTime { get; set; } public uint EndTime { get; set; } public uint StartOffset { get; set; } public uint EndOffset { get; set; } public bool UseOffset { get; set; } public string Title { get; set; } public string UniqueID { get; set; } public string Subtitle { get; set; } public UrlInfo Url { get; set; } public PictureInfo Picture { get; set; } public ChapterInfo(uint startTime = 0u, string title = "") { StartTime = startTime; EndTime = 0u; StartOffset = 0u; EndOffset = 0u; UseOffset = false; Title = title; UniqueID = ""; Subtitle = ""; Picture = null; } public ChapterInfo(ChapterInfo chapter) { StartTime = chapter.StartTime; EndTime = chapter.EndTime; StartOffset = chapter.StartOffset; EndOffset = chapter.EndOffset; Title = chapter.Title; Subtitle = chapter.Subtitle; Url = chapter.Url; UniqueID = chapter.UniqueID; if (chapter.Url != null) { Url = new UrlInfo(chapter.Url); } if (chapter.Picture != null) { Picture = new PictureInfo(chapter.Picture); } } } public class Format : IEnumerable { protected IDictionary<string, int> mimeList; protected IDictionary<string, int> extList; public string Name { get; set; } public string ShortName { get; set; } public int ID { get; set; } public bool Readable { get; set; } public ICollection<string> MimeList => mimeList.Keys; public Format(int id, string name, string shortName = "") { init(id, name, (shortName.Length == 0) ? name : shortName); } public Format(Format f) { copyFrom(f); } protected virtual void copyFrom(Format iFormat) { ID = iFormat.ID; Name = iFormat.Name; ShortName = iFormat.ShortName; mimeList = new Dictionary<string, int>(iFormat.mimeList); extList = new Dictionary<string, int>(iFormat.extList); Readable = iFormat.Readable; } protected virtual void init(int id, string name) { init(id, name, ""); } protected virtual void init(int id, string name, string shortName) { ID = id; Name = name; ShortName = ((shortName.Length == 0) ? name : shortName); Readable = true; extList = new Dictionary<string, int>(); mimeList = new Dictionary<string, int>(); } public IEnumerator GetEnumerator() { return extList.Keys.GetEnumerator(); } public void AddMimeType(string mimeType) { if (!mimeList.ContainsKey(mimeType.ToLower())) { mimeList.Add(mimeType.ToLower(), 0); } } public bool IsValidMimeType(string mimeType) { return mimeList.ContainsKey(mimeType.ToLower()); } public void AddExtension(string ext) { if (!extList.ContainsKey(ext.ToLower())) { extList.Add(ext.ToLower(), 0); } } public bool IsValidExtension(string ext) { return extList.ContainsKey(ext.ToLower()); } } public class LyricsInfo { public enum LyricsType { OTHER, LYRICS, TRANSCRIPTION, MOVEMENT_NAME, EVENT, CHORD, TRIVIA, WEBPAGE_URL, IMAGE_URL } public class LyricsPhrase { public int TimestampMs { get; set; } public string Text { get; set; } public LyricsPhrase(int timestampMs, string text) { TimestampMs = timestampMs; Text = text; } public LyricsPhrase(string timestamp, string text) { TimestampMs = Utils.DecodeTimecodeToMs(timestamp); Text = text; } } public LyricsType ContentType { get; set; } public string Description { get; set; } public string LanguageCode { get; set; } public string UnsynchronizedLyrics { get; set; } public IList<LyricsPhrase> SynchronizedLyrics { get; set; } public LyricsInfo() { Description = ""; LanguageCode = ""; UnsynchronizedLyrics = ""; ContentType = LyricsType.LYRICS; SynchronizedLyrics = new List<LyricsPhrase>(); } public LyricsInfo(LyricsInfo info) { Description = info.Description; LanguageCode = info.LanguageCode; UnsynchronizedLyrics = info.UnsynchronizedLyrics; ContentType = info.ContentType; SynchronizedLyrics = new List<LyricsPhrase>(info.SynchronizedLyrics); } } public class MetaFieldInfo { public enum ORIGIN { Unknown, Standard, UnmappedStandard, Comment, CustomStandard, Custom } public int TagType; public string NativeFieldCode; public ushort StreamNumber; public string Language; public string Value; public string Zone; public ORIGIN Origin; public object SpecificData; public bool MarkedForDeletion; public MetaFieldInfo(int tagType, string nativeFieldCode, string value = "", ushort streamNumber = 0, string language = "", string zone = "") { TagType = tagType; NativeFieldCode = nativeFieldCode; Value = value; StreamNumber = streamNumber; Language = language; Zone = zone; } public MetaFieldInfo(MetaFieldInfo info) { TagType = info.TagType; NativeFieldCode = info.NativeFieldCode; Value = info.Value; StreamNumber = info.StreamNumber; Language = info.Language; Zone = info.Zone; Origin = info.Origin; } public string ToStringWithoutZone() { return 100 + TagType + NativeFieldCode + Utils.BuildStrictLengthString(StreamNumber.ToString(), 5, '0', padRight: false) + Language; } public override string ToString() { return 100 + TagType + NativeFieldCode + Utils.BuildStrictLengthString(StreamNumber.ToString(), 5, '0', padRight: false) + Language + Zone; } public override int GetHashCode() { return (int)FNV1a.Hash32(Utils.Latin1Encoding.GetBytes(ToString())); } public bool EqualsWithoutZone(object obj) { if (obj == null) { return false; } if (this == obj) { return true; } if (obj.GetType() != GetType()) { return false; } return ToStringWithoutZone().Equals(((MetaFieldInfo)obj).ToStringWithoutZone()); } public bool EqualsApproximate(MetaFieldInfo obj) { if (obj == null) { return false; } if (this == obj) { return true; } bool flag = 99 == obj.TagType && obj.NativeFieldCode.Equals(NativeFieldCode); if (obj.StreamNumber > 0) { flag = flag && obj.StreamNumber == StreamNumber; } if (obj.Language.Length > 0) { flag = flag && obj.Language.Equals(Language); } return flag; } public override bool Equals(object obj) { if (obj == null) { return false; } if (this == obj) { return true; } if (obj.GetType() != GetType()) { return false; } return ToString().Equals(obj.ToString()); } } public class PictureInfo { public enum PIC_TYPE { Unsupported = 99, Generic = 1, Front = 2, Back = 3, CD = 4, Icon = 5, Leaflet = 6, LeadArtist = 7, Artist = 8, Conductor = 9, Band = 10, Composer = 11, Lyricist = 12, RecordingLocation = 13, DuringRecording = 14, DuringPerformance = 15, MovieCapture = 16, Fishie = 17, Illustration = 18, BandLogo = 19, PublisherLogo = 20 } public PIC_TYPE PicType; public ImageFormat NativeFormat; public int Position; public int TagType; public int NativePicCode; public string NativePicCodeStr; public string Description = ""; public uint PictureHash; public bool MarkedForDeletion; public int TransientFlag; public byte[] PictureData { get; private set; } public string MimeType => ImageUtils.GetMimeTypeFromImageFormat(NativeFormat); public static PictureInfo fromBinaryData(byte[] data, PIC_TYPE picType = PIC_TYPE.Generic, int tagType = 99, object nativePicCode = null, int position = 1) { if (data == null || data.Length < 3) { throw new ArgumentException("Data should not be null and be at least 3 bytes long"); } if (nativePicCode == null) { nativePicCode = 0; } return new PictureInfo(picType, tagType, nativePicCode, position, data); } public static PictureInfo fromBinaryData(Stream stream, int length, PIC_TYPE picType, int tagType, object nativePicCode, int position = 1) { if (stream == null || length < 3) { throw new ArgumentException("Stream should not be null and be at least 3 bytes long"); } byte[] array = new byte[length]; stream.Read(array, 0, length); return new PictureInfo(picType, tagType, nativePicCode, position, array); } public PictureInfo(PictureInfo picInfo, bool copyPictureData = true) { PicType = picInfo.PicType; NativeFormat = picInfo.NativeFormat; Position = picInfo.Position; TagType = picInfo.TagType; NativePicCode = picInfo.NativePicCode; NativePicCodeStr = picInfo.NativePicCodeStr; Description = picInfo.Description; if (copyPictureData && picInfo.PictureData != null) { PictureData = new byte[picInfo.PictureData.Length]; picInfo.PictureData.CopyTo(PictureData, 0); } else { PictureData = picInfo.PictureData; } PictureHash = picInfo.PictureHash; MarkedForDeletion = picInfo.MarkedForDeletion; TransientFlag = picInfo.TransientFlag; } private PictureInfo(PIC_TYPE picType, int tagType, object nativePicCode, int position, byte[] binaryData) { PicType = picType; TagType = tagType; Position = position; if (nativePicCode is string nativePicCodeStr) { NativePicCodeStr = nativePicCodeStr; NativePicCode = -1; } else if (nativePicCode is byte) { NativePicCode = (byte)nativePicCode; } else if (nativePicCode is int) { NativePicCode = (int)nativePicCode; } else { LogDelegator.GetLogDelegate()(2, "nativePicCode type is not supported; expected byte, int or string; found " + nativePicCode.GetType().Name); } PictureData = binaryData; NativeFormat = ImageUtils.GetImageFormatFromPictureHeader(PictureData); } public PictureInfo(PIC_TYPE picType, int position = 1) { PicType = picType; NativeFormat = ImageFormat.Undefined; Position = position; } public PictureInfo(int tagType, object nativePicCode, int position = 1) { PicType = PIC_TYPE.Unsupported; NativeFormat = ImageFormat.Undefined; TagType = tagType; Position = position; if (nativePicCode is string nativePicCodeStr) { NativePicCodeStr = nativePicCodeStr; NativePicCode = -1; } else if (nativePicCode is byte) { NativePicCode = (byte)nativePicCode; } else if (nativePicCode is int) { NativePicCode = (int)nativePicCode; } else { LogDelegator.GetLogDelegate()(2, "nativePicCode type is not supported; expected byte, int or string; found " + nativePicCode.GetType().Name); } } public uint ComputePicHash() { uint pictureHash = 0u; if (PictureData != null) { pictureHash = FNV1a.Hash32(PictureData); } PictureHash = pictureHash; return PictureHash; } public bool EqualsProper(PictureInfo picInfo) { if (Position == picInfo.Position) { if (!equalsNative(picInfo)) { return equalsGeneric(picInfo); } return true; } return false; } private bool equalsNative(PictureInfo picInfo) { if (TagType == 0 || TagType != picInfo.TagType) { return false; } if (NativePicCode > 0 && NativePicCode == picInfo.NativePicCode) { return true; } if (NativePicCodeStr != null && NativePicCodeStr.Length > 0 && NativePicCodeStr == picInfo.NativePicCodeStr) { return true; } return false; } private bool equalsGeneric(PictureInfo picInfo) { if (PIC_TYPE.Unsupported != PicType) { return PicType == picInfo.PicType; } return false; } public override string ToString() { return Utils.BuildStrictLengthString(Position.ToString(), 2, '0', padRight: false) + valueToString(); } private string valueToString() { if (NativePicCode > 0 && TagType > 0) { return (10000000 * TagType + "N" + NativePicCode).ToString(); } if (NativePicCodeStr != null && NativePicCodeStr.Length > 0 && TagType > 0) { return 10000000 * TagType + "N" + NativePicCodeStr; } if (PicType != PIC_TYPE.Unsupported) { int picType = (int)PicType; return "T" + Utils.BuildStrictLengthString(picType.ToString(), 2, '0', padRight: false); } LogDelegator.GetLogDelegate()(2, "Non-supported picture detected, but no native picture code found"); return ""; } public override int GetHashCode() { return (int)FNV1a.Hash32(Utils.Latin1Encoding.GetBytes(ToString())); } public override bool Equals(object obj) { if (obj == null) { return false; } if (this == obj) { return true; } if (obj.GetType() != GetType()) { return false; } return ToString().Equals(obj.ToString()); } } public class TagData { public const byte TAG_FIELD_GENERAL_DESCRIPTION = 0; public const byte TAG_FIELD_TITLE = 1; public const byte TAG_FIELD_ARTIST = 2; public const byte TAG_FIELD_COMPOSER = 3; public const byte TAG_FIELD_COMMENT = 4; public const byte TAG_FIELD_GENRE = 5; public const byte TAG_FIELD_ALBUM = 6; public const byte TAG_FIELD_RECORDING_YEAR = 7; public const byte TAG_FIELD_RECORDING_DATE = 8; public const byte TAG_FIELD_RECORDING_YEAR_OR_DATE = 9; public const byte TAG_FIELD_RECORDING_TIME = 10; public const byte TAG_FIELD_RECORDING_DAYMONTH = 11; public const byte TAG_FIELD_TRACK_NUMBER = 12; public const byte TAG_FIELD_DISC_NUMBER = 13; public const byte TAG_FIELD_RATING = 14; public const byte TAG_FIELD_ORIGINAL_ARTIST = 15; public const byte TAG_FIELD_ORIGINAL_ALBUM = 16; public const byte TAG_FIELD_COPYRIGHT = 17; public const byte TAG_FIELD_ALBUM_ARTIST = 18; public const byte TAG_FIELD_PUBLISHER = 19; public const byte TAG_FIELD_CONDUCTOR = 20; public const byte TAG_FIELD_TRACK_TOTAL = 21; public const byte TAG_FIELD_TRACK_NUMBER_TOTAL = 22; public const byte TAG_FIELD_DISC_TOTAL = 23; public const byte TAG_FIELD_DISC_NUMBER_TOTAL = 24; public const byte TAG_FIELD_CHAPTERS_TOC_DESCRIPTION = 25; public const byte TAG_FIELD_LYRICS_UNSYNCH = 26; public const byte TAG_FIELD_LYRICS_SYNCH = 27; public const byte TAG_FIELD_PUBLISHING_DATE = 28; public string GeneralDescription; public string Title; public string Artist; public string OriginalArtist; public string Composer; public string Comment; public string Genre; public string Album; public string OriginalAlbum; public string RecordingYear; public string RecordingDayMonth; public string RecordingTime; public string RecordingDate; public string TrackNumber; public string DiscNumber; public string Rating; public string Copyright; public string AlbumArtist; public string Publisher; public string Conductor; public string TrackTotal; public string TrackNumberTotal; public string DiscTotal; public string DiscNumberTotal; public string ChaptersTableDescription; public string PublishingDate; public IList<ChapterInfo> Chapters; public LyricsInfo Lyrics; public IList<PictureInfo> Pictures; public IList<MetaFieldInfo> AdditionalFields; public int TrackDigitsForLeadingZeroes; public int DiscDigitsForLeadingZeroes; public long DataSizeDelta; public long PaddingSize = -1L; public double DurationMs; public string this[byte index] => ToMap()[index]; public TagData() { Pictures = new List<PictureInfo>(); AdditionalFields = new List<MetaFieldInfo>(); } public TagData(TagData tagData) { Pictures = new List<PictureInfo>(); AdditionalFields = new List<MetaFieldInfo>(); IntegrateValues(tagData); } public void IntegrateValue(byte key, string value) { switch (key) { case 0: GeneralDescription = value; break; case 1: Title = value; break; case 2: Artist = value; break; case 3: Composer = value; break; case 4: Comment = value; break; case 5: Genre = value; break; case 6: Album = value; break; case 15: OriginalArtist = value; break; case 16: OriginalAlbum = value; break; case 17: Copyright = value; break; case 18: AlbumArtist = value; break; case 19: Publisher = value; break; case 20: Conductor = value; break; case 8: RecordingDate = emptyIfZero(value); break; case 7: RecordingYear = emptyIfZero(value); break; case 9: if (value != null) { if (value.Length < 5) { RecordingYear = emptyIfZero(value); } else { RecordingDate = emptyIfZero(value); } } break; case 11: RecordingDayMonth = emptyIfZero(value); break; case 10: RecordingTime = emptyIfZero(value); break; case 12: TrackNumber = emptyIfZero(value); break; case 13: DiscNumber = emptyIfZero(value); break; case 14: Rating = emptyIfZero(value); break; case 21: TrackTotal = emptyIfZero(value); break; case 22: TrackNumberTotal = emptyIfZero(value); break; case 23: DiscTotal = emptyIfZero(value); break; case 24: DiscNumberTotal = emptyIfZero(value); break; case 25: ChaptersTableDescription = emptyIfZero(value); break; case 26: if (Lyrics == null) { Lyrics = new LyricsInfo(); } Lyrics.UnsynchronizedLyrics = value; break; case 28: PublishingDate = emptyIfZero(value); break; case 27: break; } } public void IntegrateValues(TagData targetData, bool integratePictures = true, bool mergeAdditionalData = true) { IDictionary<byte, string> dictionary = targetData.ToMap(); foreach (byte key in dictionary.Keys) { IntegrateValue(key, dictionary[key]); } if (targetData.PaddingSize > -1) { PaddingSize = targetData.PaddingSize; } else { PaddingSize = -1L; } if (integratePictures && targetData.Pictures != null) { IList<PictureInfo> list = new List<PictureInfo>(); foreach (PictureInfo picture in targetData.Pictures) { picture.ComputePicHash(); int num = 0; bool flag = false; foreach (PictureInfo picture2 in Pictures) { picture2.ComputePicHash(); if (!picture2.EqualsProper(picture)) { continue; } if (picture.MarkedForDeletion) { picture2.MarkedForDeletion = true; flag = true; list.Add(picture2); continue; } num = Math.Max(num, picture2.Position); if (picture2.PictureHash == 0 || picture2.PictureHash != picture.PictureHash) { continue; } flag = true; PictureInfo pictureInfo = picture2; if (picture.Description != picture2.Description) { pictureInfo = new PictureInfo(picture2, copyPictureData: false); pictureInfo.Description = picture.Description; } list.Add(pictureInfo); break; } if (!flag) { picture.Position = num + 1; list.Add(picture); } } for (int num2 = Pictures.Count - 1; num2 >= 0; num2--) { bool flag2 = false; foreach (PictureInfo picture3 in targetData.Pictures) { if (picture3.EqualsProper(Pictures[num2])) { flag2 = true; break; } } if (!flag2) { list.Insert(0, Pictures[num2]); } } Pictures = list; } if (mergeAdditionalData) { foreach (MetaFieldInfo additionalField in targetData.AdditionalFields) { bool flag3 = false; foreach (MetaFieldInfo additionalField2 in AdditionalFields) { if (additionalField2.EqualsWithoutZone(additionalField) || additionalField2.EqualsApproximate(additionalField)) { if (!additionalField.MarkedForDeletion) { flag3 = true; additionalField2.Value = additionalField.Value; break; } additionalField2.MarkedForDeletion = true; } } if (!additionalField.MarkedForDeletion && !flag3) { AdditionalFields.Add(additionalField); } else if (additionalField.MarkedForDeletion && !flag3) { LogDelegator.GetLogDelegate()(2, "Field code " + additionalField.NativeFieldCode + " cannot be deleted because it has not been found on current TagData."); } } } else { AdditionalFields = new List<MetaFieldInfo>(targetData.AdditionalFields); } if (targetData.Chapters != null) { if (Chapters != null) { Chapters.Clear(); } else { Chapters = new List<ChapterInfo>(); } foreach (ChapterInfo chapter in targetData.Chapters) { Chapters.Add(new ChapterInfo(chapter)); } } if (targetData.Lyrics != null) { Lyrics = new LyricsInfo(targetData.Lyrics); } DurationMs = targetData.DurationMs; } public bool hasKey(byte id) { return ToMap().ContainsKey(id); } public IDictionary<byte, string> ToMap() { IDictionary<byte, string> dictionary = new Dictionary<byte, string>(); addIfConsistent(Artist, 2, dictionary); addIfConsistent(Title, 1, dictionary); addIfConsistent(Album, 6, dictionary); addIfConsistent(RecordingDate, 8, dictionary); addIfConsistent(RecordingYear, 7, dictionary); addIfConsistent(RecordingDate, 9, dictionary); addIfConsistent(RecordingYear, 9, dictionary); addIfConsistent(RecordingDayMonth, 11, dictionary); addIfConsistent(RecordingTime, 10, dictionary); addIfConsistent(Genre, 5, dictionary); addIfConsistent(Composer, 3, dictionary); addIfConsistent(AlbumArtist, 18, dictionary); addIfConsistent(TrackNumber, 12, dictionary); addIfConsistent(TrackNumberTotal, 22, dictionary); addIfConsistent(TrackTotal, 21, dictionary); addIfConsistent(DiscNumber, 13, dictionary); addIfConsistent(DiscNumberTotal, 24, dictionary); addIfConsistent(DiscTotal, 23, dictionary); addIfConsistent(Comment, 4, dictionary); addIfConsistent(Rating, 14, dictionary); addIfConsistent(OriginalArtist, 15, dictionary); addIfConsistent(OriginalAlbum, 16, dictionary); addIfConsistent(Copyright, 17, dictionary); addIfConsistent(Publisher, 19, dictionary); addIfConsistent(Conductor, 20, dictionary); addIfConsistent(GeneralDescription, 0, dictionary); addIfConsistent(ChaptersTableDescription, 25, dictionary); if (Lyrics != null) { addIfConsistent(Lyrics.UnsynchronizedLyrics, 26, dictionary); } addIfConsistent(PublishingDate, 28, dictionary); return dictionary; } public void Clear() { Pictures.Clear(); AdditionalFields.Clear(); if (Chapters != null) { Chapters.Clear(); } GeneralDescription = null; Title = null; Artist = null; OriginalArtist = null; Composer = null; Comment = null; Genre = null; Album = null; OriginalAlbum = null; RecordingYear = null; RecordingDayMonth = null; RecordingTime = null; RecordingDate = null; TrackNumber = null; DiscNumber = null; Rating = null; Copyright = null; AlbumArtist = null; Publisher = null; Conductor = null; TrackTotal = null; TrackNumberTotal = null; DiscTotal = null; DiscNumberTotal = null; ChaptersTableDescription = null; Lyrics = null; PublishingDate = null; TrackDigitsForLeadingZeroes = 0; DiscDigitsForLeadingZeroes = 0; PaddingSize = -1L; DurationMs = 0.0; } public void Cleanup() { if (TrackNumber != null) { if (TrackNumber.Contains("/")) { TrackNumberTotal = TrackNumber; string[] array = TrackNumber.Split(new char[1] { '/' }); TrackNumber = array[0]; TrackTotal = array[1]; } else if (Utils.IsNumeric(TrackNumber)) { TrackNumberTotal = TrackNumber; if (Utils.IsNumeric(TrackTotal)) { TrackNumberTotal = TrackNumberTotal + "/" + TrackTotal; } } else { TrackNumberTotal = ""; } } if (DiscNumber != null) { if (DiscNumber.Contains("/")) { DiscNumberTotal = DiscNumber; string[] array2 = DiscNumber.Split(new char[1] { '/' }); DiscNumber = array2[0]; DiscTotal = array2[1]; } else if (Utils.IsNumeric(DiscNumber)) { DiscNumberTotal = DiscNumber; if (Utils.IsNumeric(DiscTotal)) { DiscNumberTotal = DiscNumberTotal + "/" + DiscTotal; } } else { DiscNumberTotal = ""; } } if (Chapters == null || Chapters.Count <= 0) { return; } if (Chapters[0].UseOffset) { Chapters = Chapters.OrderBy((ChapterInfo chapter) => chapter.StartOffset).ToList(); } else { Chapters = Chapters.OrderBy((ChapterInfo chapter) => chapter.StartTime).ToList(); } ChapterInfo chapterInfo = null; foreach (ChapterInfo chapter in Chapters) { if (chapterInfo != null) { if (chapter.UseOffset && (chapterInfo.EndOffset == 0 || chapterInfo.EndOffset != chapter.StartOffset)) { chapterInfo.EndOffset = chapter.StartOffset; } else if (chapterInfo.EndTime == 0 || chapterInfo.EndTime != chapter.StartTime) { chapterInfo.EndTime = chapter.StartTime; } } chapterInfo = chapter; } if (chapterInfo != null && chapterInfo.EndTime == 0) { chapterInfo.EndTime = (uint)Math.Round(DurationMs); } } private void addIfConsistent(string data, byte id, IDictionary<byte, string> map) { if (data != null) { map[id] = data; } } private string emptyIfZero(string s) { string result = s; if (s != null && s.Equals("0")) { result = ""; } return result; } private IDictionary<PictureInfo, int> generatePicturePositions() { IDictionary<PictureInfo, int> dictionary = new Dictionary<PictureInfo, int>(); foreach (PictureInfo picture in Pictures) { if (dictionary.ContainsKey(picture)) { dictionary[picture] = Math.Max(dictionary[picture], picture.Position); } else { dictionary.Add(picture, picture.Position); } } return dictionary; } } public class TechnicalInfo { public long AudioDataOffset { get; } public long AudioDataSize { get; } public TechnicalInfo(long audioDataOffset, long audioDataSize) { AudioDataOffset = audioDataOffset; AudioDataSize = audioDataSize; } } public class Track { private const string InMemoryPath = "In-memory"; public readonly string Path; private ICollection<string> initialAdditionalFields; private ICollection<PictureInfo> initialEmbeddedPictures; private readonly IProgress<float> writeProgress; private readonly Stream stream; private readonly string mimeType; private AudioFileIO fileIO; public string Title { get; set; } public string Artist { get; set; } public string Composer { get; set; } public string Comment { get; set; } public string Genre { get; set; } public string Album { get; set; } public string OriginalAlbum { get; set; } public string OriginalArtist { get; set; } public string Copyright { get; set; } public string Description { get; set; } public string Publisher { get; set; } public DateTime PublishingDate { get; set; } public string AlbumArtist { get; set; } public string Conductor { get; set; } public DateTime Date { get; set; } public int Year { get { if (Date == DateTime.MinValue) { return 0; } return Date.Year; } set { if (value > 0) { Date = new DateTime(value, 1, 1); } else { Date = DateTime.MinValue; } } } public int TrackNumber { get; set; } public int TrackTotal { get; set; } public int DiscNumber { get; set; } public int DiscTotal { get; set; } public float Popularity { get; set; } public IList<PictureInfo> PictureTokens { get; set; } public string ChaptersTableDescription { get; set; } public IList<ChapterInfo> Chapters { get; set; } public LyricsInfo Lyrics { get; set; } public IDictionary<string, string> AdditionalFields { get; set; } private IList<PictureInfo> currentEmbeddedPictures { get; set; } public int Bitrate { get; internal set; } public double SampleRate { get; internal set; } public bool IsVBR { get; internal set; } public int CodecFamily { get; internal set; } public Format AudioFormat { get; internal set; } public IList<Format> MetadataFormats { get; internal set; } public int Duration => (int)Math.Round(DurationMs / 1000.0); public double DurationMs { get; internal set; } public ChannelsArrangements.ChannelsArrangement ChannelsArrangement { get; internal set; } public TechnicalInfo TechnicalInformation { get; internal set; } public IList<PictureInfo> EmbeddedPictures => getEmbeddedPictures(); public Track() { } public Track(string path, IProgress<float> writeProgress = null, bool load = true) { Path = path; stream = null; this.writeProgress = writeProgress; if (load) { Update(); } } public Track(string path, bool load) { Path = path; stream = null; writeProgress = null; if (load) { Update(); } } public Track(Stream stream, string mimeType, IProgress<float> writeProgress = null) { this.stream = stream; this.mimeType = mimeType; Path = "In-memory"; this.writeProgress = writeProgress; Update(); } private IList<PictureInfo> getEmbeddedPictures() { if (currentEmbeddedPictures == null) { currentEmbeddedPictures = new List<PictureInfo>(); initialEmbeddedPictures = new List<PictureInfo>(); Update(onlyReadEmbeddedPictures: true); } return currentEmbeddedPictures; } protected void Update(bool onlyReadEmbeddedPictures = false) { if (string.IsNullOrEmpty(Path)) { return; } if (stream == null) { fileIO = new AudioFileIO(Path, onlyReadEmbeddedPictures, Settings.ReadAllMetaFrames, writeProgress); } else { fileIO = new AudioFileIO(stream, mimeType, onlyReadEmbeddedPictures, Settings.ReadAllMetaFrames, writeProgress); } if (onlyReadEmbeddedPictures) { foreach (PictureInfo embeddedPicture in fileIO.EmbeddedPictures) { embeddedPicture.ComputePicHash(); currentEmbeddedPictures.Add(embeddedPicture); PictureInfo item = new PictureInfo(embeddedPicture, copyPictureData: false); initialEmbeddedPictures.Add(item); } return; } if (currentEmbeddedPictures != null) { currentEmbeddedPictures.Clear(); initialEmbeddedPictures.Clear(); currentEmbeddedPictures = null; initialEmbeddedPictures = null; } MetadataFormats = new List<Format>(fileIO.MetadataFormats); Title = fileIO.Title; if (Settings.UseFileNameWhenNoTitle && (Title == null || "" == Title) && Path != "In-memory") { Title = System.IO.Path.GetFileNameWithoutExtension(Path); } Artist = Utils.ProtectValue(fileIO.Artist); Composer = Utils.ProtectValue(fileIO.Composer); Comment = Utils.ProtectValue(fileIO.Comment); Genre = Utils.ProtectValue(fileIO.Genre); OriginalArtist = Utils.ProtectValue(fileIO.OriginalArtist); OriginalAlbum = Utils.ProtectValue(fileIO.OriginalAlbum); Description = Utils.ProtectValue(fileIO.GeneralDescription); Copyright = Utils.ProtectValue(fileIO.Copyright); Publisher = Utils.ProtectValue(fileIO.Publisher); PublishingDate = fileIO.PublishingDate; AlbumArtist = Utils.ProtectValue(fileIO.AlbumArtist); Conductor = Utils.ProtectValue(fileIO.Conductor); Date = fileIO.Date; Album = fileIO.Album; TrackNumber = fileIO.Track; TrackTotal = fileIO.TrackTotal; DiscNumber = fileIO.Disc; DiscTotal = fileIO.DiscTotal; ChaptersTableDescription = Utils.ProtectValue(fileIO.ChaptersTableDescription); Chapters = fileIO.Chapters; Lyrics = fileIO.Lyrics; AdditionalFields = fileIO.AdditionalFields; initialAdditionalFields = fileIO.AdditionalFields.Keys; PictureTokens = new List<PictureInfo>(fileIO.PictureTokens); Bitrate = fileIO.IntBitRate; CodecFamily = fileIO.CodecFamily; AudioFormat = fileIO.AudioFormat; DurationMs = fileIO.Duration; Popularity = fileIO.Popularity; IsVBR = fileIO.IsVBR; SampleRate = fileIO.SampleRate; ChannelsArrangement = fileIO.ChannelsArrangement; TechnicalInformation = new TechnicalInfo(fileIO.AudioDataOffset, fileIO.AudioDataSize); } private TagData toTagData() { TagData tagData = new TagData(); tagData.Title = Title; tagData.Artist = Artist; tagData.Composer = Composer; tagData.Comment = Comment; tagData.Genre = Genre; tagData.OriginalArtist = OriginalArtist; tagData.OriginalAlbum = OriginalAlbum; tagData.GeneralDescription = Description; tagData.Rating = (Popularity * 5f).ToString(); tagData.Copyright = Copyright; tagData.Publisher = Publisher; if (!PublishingDate.Equals(DateTime.MinValue)) { tagData.PublishingDate = TrackUtils.FormatISOTimestamp(PublishingDate); } else { tagData.PublishingDate = "0"; } tagData.AlbumArtist = AlbumArtist; tagData.Conductor = Conductor; if (!Date.Equals(DateTime.MinValue)) { tagData.RecordingDate = TrackUtils.FormatISOTimestamp(Date); } else { tagData.RecordingDate = "0"; } tagData.RecordingYear = Year.ToString(); tagData.Album = Album; tagData.TrackNumber = TrackNumber.ToString(); tagData.TrackTotal = TrackTotal.ToString(); tagData.DiscNumber = DiscNumber.ToString(); tagData.DiscTotal = DiscTotal.ToString(); tagData.ChaptersTableDescription = ChaptersTableDescription.ToString(); tagData.Chapters = new List<ChapterInfo>(); foreach (ChapterInfo chapter in Chapters) { tagData.Chapters.Add(new ChapterInfo(chapter)); } if (Lyrics != null) { tagData.Lyrics = new LyricsInfo(Lyrics); } foreach (string key in AdditionalFields.Keys) { tagData.AdditionalFields.Add(new MetaFieldInfo(99, key, AdditionalFields[key], 0)); } foreach (string initialAdditionalField in initialAdditionalFields) { if (!AdditionalFields.ContainsKey(initialAdditionalField)) { MetaFieldInfo metaFieldInfo = new MetaFieldInfo(99, initialAdditionalField, "", 0); metaFieldInfo.MarkedForDeletion = true; tagData.AdditionalFields.Add(metaFieldInfo); } } tagData.Pictures = new List<PictureInfo>(); if (initialEmbeddedPictures != null && currentEmbeddedPictures != null) { foreach (PictureInfo currentEmbeddedPicture in currentEmbeddedPictures) { bool flag = false; foreach (PictureInfo initialEmbeddedPicture in initialEmbeddedPictures) { if (currentEmbeddedPicture.EqualsProper(initialEmbeddedPicture)) { tagData.Pictures.Add(currentEmbeddedPicture); currentEmbeddedPicture.ComputePicHash(); if (currentEmbeddedPicture.PictureHash != initialEmbeddedPicture.PictureHash) { PictureInfo pictureInfo = new PictureInfo(initialEmbeddedPicture); pictureInfo.MarkedForDeletion = true; tagData.Pictures.Add(pictureInfo); } flag = true; break; } } if (!flag) { tagData.Pictures.Add(currentEmbeddedPicture); } } foreach (PictureInfo initialEmbeddedPicture2 in initialEmbeddedPictures) { if (!currentEmbeddedPictures.Contains(initialEmbeddedPicture2)) { PictureInfo pictureInfo2 = new PictureInfo(initialEmbeddedPicture2); pictureInfo2.MarkedForDeletion = true; tagData.Pictures.Add(pictureInfo2); } } } return tagData; } public bool Save() { bool num = fileIO.Save(toTagData()); if (num) { Update(); } return num; } public bool Remove(int tagType = 99) { bool num = fileIO.Remove(tagType); if (num) { Update(); } return num; } } public abstract class Factory { public static readonly Format UNKNOWN_FORMAT = new Format(-1, "Unknown"); protected IDictionary<string, IList<Format>> formatListByExt; protected IDictionary<string, IList<Format>> formatListByMime; protected void addFormat(Format f) { foreach (string item in f) { if (!formatListByExt.ContainsKey(item)) { IList<Format> list = new List<Format>(); list.Add(f); formatListByExt.Add(item, list); } else { IList<Format> list = formatListByExt[item]; list.Add(f); } } foreach (string mime in f.MimeList) { if (!formatListByMime.ContainsKey(mime)) { IList<Format> list = new List<Format>(); list.Add(f); formatListByMime.Add(mime, list); } else { IList<Format> list = formatListByMime[mime]; list.Add(f); } } } public IList<Format> getFormatsFromPath(string path) { IList<Format> result = null; string key = ((!path.Contains(".")) ? path : path.Substring(path.LastIndexOf('.'), path.Length - path.LastIndexOf('.')).ToLower()); if (formatListByExt.ContainsKey(key)) { IList<Format> list = formatListByExt[key]; if (list != null && list.Count > 0) { result = list; } } return result; } public IList<Format> getFormatsFromMimeType(string mimeType) { IList<Format> result = null; string key = mimeType.ToLower(); if (formatListByMime.ContainsKey(key)) { IList<Format> list = formatListByMime[key]; if (list != null && list.Count > 0) { result = list; } } return result; } public ICollection<Format> getFormats() { Dictionary<int, Format> dictionary = new Dictionary<int, Format>(); foreach (IList<Format> value in formatListByExt.Values) { foreach (Format item in value) { if (!dictionary.ContainsKey(item.ID)) { dictionary.Add(item.ID, item); } } } return dictionary.Values; } } public static class Settings { public static int FileBufferSize = 512; public static bool ForceDiskIO = false; public static bool AddNewPadding = false; public static int PaddingSize = 2048; internal static readonly char InternalValueSeparator = '\u02f5'; public static char DisplayValueSeparator = ';'; public static bool ReadAllMetaFrames = true; public static Encoding DefaultTextEncoding = Encoding.UTF8; public static int[] DefaultTagsWhenNoMetadata = new int[2] { 1, 3 }; public static bool UseFileNameWhenNoTitle = true; public static bool UseLeadingZeroes = false; public static bool OverrideExistingLeadingZeroesFormat = false; public static bool EnrichID3v1 = true; public static bool ID3v2_useExtendedHeaderRestrictions = false; public static bool ID3v2_alwaysWriteCTOCFrame = true; public static byte ID3v2_tagSubVersion = 4; public static bool ID3v2_forceAPICEncodingToLatin1 = true; public static bool ID3v2_forceUnsynchronization = false; public static bool MP4_createNeroChapters = true; public static bool MP4_createQuicktimeChapters = true; public static bool MP4_keepExistingChapters = true; public static int MP4_readChaptersExclusive = 0; public static bool ASF_keepNonWMFieldsWhenRemovingTag = false; public static int GYM_VGM_playbackRate = 0; public static bool M3U_useExtendedFormat = true; } public sealed class BufferedBinaryReader : Stream, IDisposable { private const int DEFAULT_BUFFER_SIZE = 512; private readonly Stream stream; private readonly int bufferDefaultSize; private readonly long streamSize; private byte[] buffer; private long bufferOffset; private int cursorPosition; private long streamPosition; private int bufferSize; public override long Position { get { return bufferOffset + cursorPosition; } set { Seek(value, SeekOrigin.Begin); } } public override long Length => streamSize; public override bool CanRead => true; public override bool CanSeek => true; public override bool CanWrite => false; public BufferedBinaryReader(Stream stream) { this.stream = stream; bufferDefaultSize = 512; buffer = new byte[bufferDefaultSize]; streamSize = stream.Length; streamPosition = stream.Position; bufferOffset = streamPosition; } public BufferedBinaryReader(Stream stream, int bufferSize) { this.stream = stream; bufferDefaultSize = bufferSize; buffer = new byte[bufferSize]; streamSize = stream.Length; streamPosition = stream.Position; bufferOffset = streamPosition; } private bool fillBuffer(int previousBytesToKeep = 0) { if (previousBytesToKeep > 0) { Array.Copy(buffer, cursorPosition, buffer, 0, previousBytesToKeep); } int num = (int)Math.Min(bufferDefaultSize - previousBytesToKeep, streamSize - streamPosition - previousBytesToKeep); if (num > 0) { bufferOffset = streamPosition; stream.Read(buffer, previousBytesToKeep, num); streamPosition += num; bufferSize = num; cursorPosition = 0; return true; } return false; } private void prepareBuffer(int bytesToRead) { if (bufferSize - cursorPosition < bytesToRead) { fillBuffer(Math.Max(0, bufferSize - cursorPosition)); } } public override long Seek(long offset, SeekOrigin origin) { long num = 0L; if (origin.Equals(SeekOrigin.Current)) { num = offset; } else if (origin.Equals(SeekOrigin.Begin)) { num = offset - Position; } else if (origin.Equals(SeekOrigin.End)) { num = streamSize + offset - Position; } if (num == 0L) { return Position; } if (num < 0) { if (cursorPosition + num < bufferSize && cursorPosition + num >= 0) { cursorPosition += (int)num; } else { streamPosition = bufferOffset + cursorPosition + num; stream.Position = streamPosition; fillBuffer(); } } else if (cursorPosition + num < bufferSize) { cursorPosition += (int)num; } else { streamPosition = bufferOffset + cursorPosition + num; stream.Position = streamPosition; fillBuffer(); } return Position; } public override int Read([In][Out] byte[] buffer, int offset, int count) { if (count <= bufferSize - cursorPosition) { prepareBuffer(count); Array.Copy(this.buffer, cursorPosition, buffer, offset, count); cursorPosition += count; return count; } int num = bufferSize - cursorPosition; if (num > 0) { Array.Copy(this.buffer, cursorPosition, buffer, offset, num); } else { num = 0; } int num2 = stream.Read(buffer, offset + num, count - num); streamPosition += num2; stream.Position = streamPosition; cursorPosition += num + num2; return num + num2; } public byte[] ReadBytes(int nbBytes) { byte[] result = new byte[nbBytes]; Read(result, 0, nbBytes); return result; } public new byte ReadByte() { prepareBuffer(1); byte result = buffer[cursorPosition]; cursorPosition++; return result; } public ushort ReadUInt16() { prepareBuffer(2); ushort result = (ushort)(buffer[cursorPosition] | (buffer[cursorPosition + 1] << 8)); cursorPosition += 2; return result; } public short ReadInt16() { prepareBuffer(2); short result = (short)(buffer[cursorPosition] | (buffer[cursorPosition + 1] << 8)); cursorPosition += 2; return result; } public uint ReadUInt32() { prepareBuffer(4); int result = buffer[cursorPosition] | (buffer[cursorPosition + 1] << 8) | (buffer[cursorPosition + 2] << 16) | (buffer[cursorPosition + 3] << 24); cursorPosition += 4; return (uint)result; } public int ReadInt32() { prepareBuffer(4); int result = buffer[cursorPosition] | (buffer[cursorPosition + 1] << 8) | (buffer[cursorPosition + 2] << 16) | (buffer[cursorPosition + 3] << 24); cursorPosition += 4; return result; } public ulong ReadUInt64() { prepareBuffer(8); ulong result = buffer[cursorPosition] | ((ulong)buffer[cursorPosition + 1] << 8) | ((ulong)buffer[cursorPosition + 2] << 16) | ((ulong)buffer[cursorPosition + 3] << 24) | ((ulong)buffer[cursorPosition + 4] << 32) | ((ulong)buffer[cursorPosition + 5] << 40) | ((ulong)buffer[cursorPosition + 6] << 48) | ((ulong)buffer[cursorPosition + 7] << 56); cursorPosition += 8; return result; } public long ReadInt64() { prepareBuffer(8); ulong result = buffer[cursorPosition] | ((ulong)buffer[cursorPosition + 1] << 8) | ((ulong)buffer[cursorPosition + 2] << 16) | ((ulong)buffer[cursorPosition + 3] << 24) | ((ulong)buffer[cursorPosition + 4] << 32) | ((ulong)buffer[cursorPosition + 5] << 40) | ((ulong)buffer[cursorPosition + 6] << 48) | ((ulong)buffer[cursorPosition + 7] << 56); cursorPosition += 8; return (long)result; } public new void Dispose() { Flush(); stream.Close(); } public override void Flush() { buffer = null; } public override void SetLength(long value) { throw new NotImplementedException(); } public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); } } public static class StreamUtils { public delegate void StreamHandlerDelegate(ref MemoryStream stream); public static bool StringEqualsArr(string a, char[] b) { return ArrEqualsArr(a.ToCharArray(), b); } private static bool ArrEqualsArr(char[] a, char[] b) { if (b.Length != a.Length) { return false; } for (int i = 0; i < b.Length; i++) { if (a[i] != b[i]) { return false; } } return true; } public static bool ArrEqualsArr(byte[] a, byte[] b) { if (b.Length != a.Length) { return false; } for (int i = 0; i < b.Length; i++) { if (a[i] != b[i]) { return false; } } return true; } public static void CopyStream(Stream from, Stream to, int length = 0) { byte[] buffer = new byte[Settings.FileBufferSize]; int num = 0; while (true) { int count = ((length <= 0) ? Settings.FileBufferSize : ((num + Settings.FileBufferSize >= length) ? (length - num) : Settings.FileBufferSize)); int num2 = from.Read(buffer, 0, count); if (num2 != 0) { to.Write(buffer, 0, num2); num += num2; continue; } break; } } public static void CopySameStream(Stream s, long offsetFrom, long offsetTo, int length) { CopySameStream(s, offsetFrom, offsetTo, length, Settings.FileBufferSize); } public static void CopySameStream(Stream s, long offsetFrom, long offsetTo, int length, int bufferSize) { if (offsetFrom == offsetTo) { return; } byte[] buffer = new byte[bufferSize]; int i = 0; bool flag = offsetTo > offsetFrom; int num; for (; i < length; i += num) { num = Math.Min(bufferSize, length - i); if (flag) { s.Seek(offsetFrom + length - i - num, SeekOrigin.Begin); s.Read(buffer, 0, num); s.Seek(offsetTo + length - i - num, SeekOrigin.Begin); } else { s.Seek(offsetFrom + i, SeekOrigin.Begin); s.Read(buffer, 0, num); s.Seek(offsetTo + i, SeekOrigin.Begin); } s.Write(buffer, 0, num); } } public static void ShortenStream(Stream s, long endOffset, uint delta) { CopySameStream(s, endOffset, endOffset - delta, (int)(s.Length - endOffset)); s.SetLength(s.Length - delta); } public static void LengthenStream(Stream s, long oldIndex, uint delta, bool fillZeroes = false) { long num = oldIndex + delta; CopySameStream(s, oldIndex, oldIndex + delta, (int)(s.Length - oldIndex)); if (fillZeroes) { s.Seek(oldIndex, SeekOrigin.Begin); for (long num2 = oldIndex; num2 < num; num2++) { s.WriteByte(0); } } } public static sbyte DecodeSignedByte(byte[] data) { if (data.Length < 1) { throw new InvalidDataException("Data should be at least 1 bytes long; found " + data.Length + " bytes"); } return (sbyte)data[0]; } public static byte DecodeUByte(byte[] data) { if (data.Length < 1) { throw new InvalidDataException("Data should be at least 1 bytes long; found " + data.Length + " bytes"); } return data[0]; } public static ushort DecodeBEUInt16(byte[] data) { if (data.Length < 2) { throw new InvalidDataException("Data should be at least 2 bytes long; found " + data.Length + " bytes"); } return (ushort)((data[0] << 8) | data[1]); } public static byte[] EncodeBEUInt16(ushort value) { return new byte[2] { (byte)((value & 0xFF00) >> 8), (byte)(value & 0xFFu) }; } public static ushort DecodeUInt16(byte[] data) { if (data.Length < 2) { throw new InvalidDataException("Data should be at least 2 bytes long; found " + data.Length + " bytes"); } return (ushort)(data[0] | (data[1] << 8)); } public static short DecodeInt16(byte[] data) { if (data.Length < 2) { throw new InvalidDataException("Data should be at least 2 bytes long; found " + data.Length + " bytes"); } return (short)(data[0] | (data[1] << 8)); } public static byte[] EncodeBEInt16(short value) { return new byte[2] { (byte)((value & 0xFF00) >> 8), (byte)((uint)value & 0xFFu) }; } public static short DecodeBEInt16(byte[] data) { if (data.Length < 2) { throw new InvalidDataException("Data should be at least 2 bytes long; found " + data.Length + " bytes"); } return (short)((data[0] << 8) | data[1]); } public static int DecodeBEInt24(byte[] data) { if (data.Length < 3) { throw new InvalidDataException("Data should be at least 3 bytes long; found " + data.Length + " bytes"); } return (data[0] << 16) | (data[1] << 8) | data[2]; } public static uint DecodeBEUInt24(byte[] data, int offset = 0) { if (data.Length - offset < 3) { throw new InvalidDataException("Value should at least contain 3 bytes after offset; actual size=" + (data.Length - offset) + " bytes"); } return (uint)((data[offset] << 16) | (data[offset + 1] << 8) | data[offset + 2]); } public static byte[] EncodeBEUInt24(uint value) { if (value > 16777215) { throw new InvalidDataException("Value should not be higher than " + 16777215 + "; actual value=" + value); } return new byte[3] { (byte)((value & 0xFF0000) >> 16), (byte)((value & 0xFF00) >> 8), (byte)(value & 0xFFu) }; } public static uint DecodeBEUInt32(byte[] data) { if (data.Length < 4) { throw new InvalidDataException("Data should be at least 4 bytes long; found " + data.Length + " bytes"); } return (uint)((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]); } public static uint DecodeUInt32(byte[] data) { if (data.Length < 4) { throw new InvalidDataException("Data should be at least 4 bytes long; found " + data.Length + " bytes"); } return (uint)(data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24)); } public static byte[] EncodeBEUInt32(uint value) { return new byte[4] { (byte)((value & 0xFF000000u) >> 24), (byte)((value & 0xFF0000) >> 16), (byte)((value & 0xFF00) >> 8), (byte)(value & 0xFFu) }; } public static int DecodeBEInt32(byte[] data) { if (data.Length < 4) { throw new InvalidDataException("Data should be at least 4 bytes long; found " + data.Length + " bytes"); } return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; } public static byte[] EncodeBEInt32(int value) { return new byte[4] { (byte)((value & 0xFF000000u) >> 24), (byte)((value & 0xFF0000) >> 16), (byte)((value & 0xFF00) >> 8), (byte)((uint)value & 0xFFu) }; } public static int DecodeInt32(byte[] data) { if (data.Length < 4) { throw new InvalidDataException("data should be at least 4 bytes long; found " + data.Length + " bytes"); } return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); } public static ulong DecodeUInt64(byte[] data) { if (data.Length < 8) { throw new InvalidDataException("Data should be at least 8 bytes long; found " + data.Length + " bytes"); } return data[0] | ((ulong)data[1] << 8) | ((ulong)data[2] << 16) | ((ulong)data[3] << 24) | ((ulong)data[4] << 32) | ((ulong)data[5] << 40) | ((ulong)data[6] << 48) | ((ulong)data[7] << 56); } public static long DecodeBEInt64(byte[] data) { if (data.Length < 8) { throw new InvalidDataException("Data should be at least 8 bytes long; found " + data.Length + " bytes"); } return (long)(((ulong)data[0] << 56) | ((ulong)data[1] << 48) | ((ulong)data[2] << 40) | ((ulong)data[3] << 32) | ((ulong)data[4] << 24) | ((ulong)data[5] << 16) | ((ulong)data[6] << 8) | data[7]); } public static byte[] EncodeBEUInt64(ulong value) { return new byte[8] { (byte)((value & 0xFF00000000000000uL) >> 56), (byte)((value & 0xFF000000000000L) >> 48), (byte)((value & 0xFF0000000000L) >> 40), (byte)((value & 0xFF00000000L) >> 32), (byte)((value & 0xFF000000u) >> 24), (byte)((value & 0xFF0000) >> 16), (byte)((value & 0xFF00) >> 8), (byte)(value & 0xFF) }; } public static double DecodeBEDouble(byte[] data) { if (data.Length < 8) { throw new InvalidDataException("Data should be at least 8 bytes long; found " + data.Length + " bytes"); } if (BitConverter.IsLittleEndian) { Array.Reverse((Array)data); } return BitConverter.ToDouble(data, 0); } public static int ReverseInt32(int n) { byte num = (byte)(n & 0xFF); byte b = (byte)((n & 0xFF00) >> 8); byte b2 = (byte)((n & 0xFF0000) >> 16); byte b3 = (byte)((n & 0xFF000000u) >> 24); return (num << 24) | (b << 16) | (b2 << 8) | b3; } public static Encoding GetEncodingFromFileBOM(FileStream file) { byte[] array = new byte[4]; file.Read(array, 0, 4); Encoding result = ((array[0] == 239 && array[1] == 187 && array[2] == 191) ? Encoding.UTF8 : ((array[0] == 254 && array[1] == byte.MaxValue) ? Encoding.BigEndianUnicode : ((array[0] == byte.MaxValue && array[1] == 254) ? Encoding.Unicode : ((array[0] != 0 || array[1] != 0 || array[2] != 254 || array[3] != byte.MaxValue) ? Settings.DefaultTextEncoding : Encoding.UTF32)))); file.Seek(0L, SeekOrigin.Begin); return result; } public static string ReadNullTerminatedString(BinaryReader r, Encoding encoding) { return readNullTerminatedString(r.BaseStream, encoding, 0, moveStreamToLimit: false); } public static string ReadNullTerminatedString(Stream s, Encoding encoding) { return readNullTerminatedString(s, encoding, 0, moveStreamToLimit: false); } public static string ReadNullTerminatedStringFixed(BinaryReader r, Encoding encoding, int limit) { return readNullTerminatedString(r.BaseStream, encoding, limit, moveStreamToLimit: true); } public static string ReadNullTerminatedStringFixed(BufferedBinaryReader r, Encoding encoding, int limit) { return readNullTerminatedString(r, encoding, limit, moveStreamToLimit: true); } private static string readNullTerminatedString(Stream r, Encoding encoding, int limit, bool moveStreamToLimit) { int num = ((!encoding.Equals(Encoding.BigEndianUnicode) && !encoding.Equals(Encoding.Unicode)) ? 1 : 2); byte[] array = new byte[(limit > 0) ? limit : 100]; byte[] array2 = new byte[2]; int num2 = 0; long length = r.Length; long position = r.Position; for (long num3 = position; num3 < length; num3 += num) { if (limit != 0 && num2 >= limit) { break; } r.Read(array2, 0, num); if ((1 == num && array2[0] == 0) || (2 == num && array2[0] == 0 && array2[1] == 0)) { break; } if (array.Length < num2 + num) { Array.Resize(ref array, array.Length + 100); } array[num2] = array2[0]; if (2 == num) { array[num2 + 1] = array2[1]; } num2 += num; } if (moveStreamToLimit) { r.Seek(position + limit, SeekOrigin.Begin); } return encoding.GetString(array, 0, num2); } public static int DecodeSynchSafeInt(byte[] bytes) { if (bytes.Length > 5) { throw new ArgumentException("Array too long : has to be 1 to 5 bytes; found : " + bytes.Length + " bytes"); } int num = 0; for (int i = 0; i < bytes.Length; i++) { num += bytes[i] * (int)Math.Floor(Math.Pow(2.0, 7 * (bytes.Length - 1 - i))); } return num; } public static int DecodeSynchSafeInt32(byte[] data) { if (data.Length != 4) { throw new ArgumentException("Array length has to be 4 bytes; found : " + data.Length + " bytes"); } return data[0] * 2097152 + data[1] * 16384 + data[2] * 128 + data[3]; } public static byte[] EncodeSynchSafeInt(int value, int nbBytes) { if (nbBytes < 1 || nbBytes > 5) { throw new ArgumentException("nbBytes has to be 1 to 5; found : " + nbBytes); } byte[] array = new byte[nbBytes]; for (int i = 0; i < nbBytes; i++) { int num = 7 * (nbBytes - 1 - i); array[i] = (byte)((value & (127 << num)) >> num); } return array; } public static byte[] EncodeSynchSafeInt32(int value) { return new byte[4] { (byte)((value & 0xFE00000) >> 21), (byte)((value & 0x1FC000) >> 14), (byte)((value & 0x3F80) >> 7), (byte)((uint)value & 0x7Fu) }; } public static bool FindSequence(Stream stream, byte[] sequence, long limit = 0L) { int num = 512; byte[] array = new byte[num]; int num2 = 0; int num3 = 0; long position = stream.Position; int num4 = (int)((limit > 0) ? Math.Min(stream.Length - stream.Position, limit) : (stream.Length - stream.Position)); while (num4 > 0) { int num5 = Math.Min(num4, num); stream.Read(array, 0, num5); for (int i = 0; i < num5; i++) { if (sequence[num2] == array[i]) { num2++; } else if (num2 > 0) { num2 = 0; } if (sequence.Length == num2) { stream.Position = position + num3 + i + 1; return true; } } num4 -= num5; num3 += num5; } stream.Position = position; return false; } public static uint ReadBits(BinaryReader source, int bitPosition, int bitCount) { if (bitCount < 1 || bitCount > 32) { throw new NotSupportedException("Bit count must be between 1 and 32"); } source.BaseStream.Seek(bitPosition / 8, SeekOrigin.Begin); byte[] array = source.ReadBytes(4); return (uint)((array[0] << 24) + (array[1] << 16) + (array[2] << 8) + array[3] << bitPosition % 8) >> 32 - bitCount; } public static double ExtendedToDouble(byte[] extended) { int s = extended[9] >> 7; int num = ((extended[9] & 0x7F) << 8) | extended[8]; int num2 = extended[7] >> 7; long num3 = extended[7] & 0x7F; for (int num4 = 6; num4 >= 0; num4--) { num3 = (num3 << 8) | extended[num4]; } if (num2 == 1) { switch (num) { case 0: return FromComponents(s, 0, 0L); default: num3 >>= 11; num += -15360; if (num > 2047) { return double.NaN; } if (num < 0) { if (num >= -51) { num3 |= 0x100000; num3 >>= 1 - num; return FromComponents(s, 0, num3); } return FromComponents(s, 0, 0L); } return FromComponents(s, num, num3); case 32767: if (num3 == 0L) { return FromComponents(s, 2047, 0L); } return double.NaN; } } if (num == 0) { return FromComponents(s, 0, 0L); } return double.NaN; } private static double FromComponents(int s, int e, long f) { byte[] array = new byte[8]; if (BitConverter.IsLittleEndian) { array[7] = (byte)((s << 7) | (e >> 4)); array[6] = (byte)(((e & 0xF) << 4) | (int)(f >> 48)); array[5] = (byte)((f & 0xFF0000000000L) >> 40); array[4] = (byte)((f & 0xFF00000000L) >> 32); array[3] = (byte)((f & 0xFF000000u) >> 24); array[2] = (byte)((f & 0xFF0000) >> 16); array[1] = (byte)((f & 0xFF00) >> 8); array[0] = (byte)(f & 0xFF); } else { array[0] = (byte)((s << 7) | (e >> 4)); array[1] = (byte)(((e & 0xF) << 4) | (int)(f >> 48)); array[2] = (byte)((f & 0xFF0000000000L) >> 40); array[3] = (byte)((f & 0xFF00000000L) >> 32); array[4] = (byte)((f & 0xFF000000u) >> 24); array[5] = (byte)((f & 0xFF0000) >> 16); array[6] = (byte)((f & 0xFF00) >> 8); array[7] = (byte)(f & 0xFF); } return BitConverter.ToDouble(array, 0); } public static long TraversePadding(Stream source) { byte[] array = new byte[Settings.FileBufferSize]; long position = source.Position; int num = 0; for (int num2 = source.Read(array, 0, Settings.FileBufferSize); num2 > 0; num2 = source.Read(array, 0, Settings.FileBufferSize)) { for (int i = 0; i < num2; i++) { if (array[i] > 0) { return position + num + i; } } num += num2; } return position + num; } } public static class Version { public static string getVersion() { return Assembly.GetExecutingAssembly().GetName().Version.ToString(); } } } namespace ATL.Playlist { public interface IPlaylistIO { string Path { get; set; } PlaylistFormat.LocationFormatting LocationFormatting { get; set; } PlaylistFormat.FileEncoding Encoding { get; set; } IList<string> FilePaths { get; set; } IList<Track> Tracks { get; set; } } public class PlaylistFormat : Format { public enum LocationFormatting { Undefined = -1, FilePath, Winamp_URI, MS_URI, RFC_URI } public enum FileEncoding { Undefined = -1, UTF8_BOM, UTF8_NO_BOM, ANSI } public LocationFormatting LocationFormat { get; set; } public FileEncoding Encoding { get; set; } public PlaylistFormat(int ID, string iName) : base(ID, iName) { } public PlaylistFormat(PlaylistFormat f) : base(f) { } protected override void copyFrom(Format iFormat) { base.copyFrom(iFormat); LocationFormat = ((PlaylistFormat)iFormat).LocationFormat; Encoding = ((PlaylistFormat)iFormat).Encoding; } protected override void init(int id, string name) { base.init(id, name); LocationFormat = LocationFormatting.FilePath; Encoding = FileEncoding.UTF8_BOM; } } public abstract class PlaylistIO : IPlaylistIO { public static readonly byte[] BOM_UTF8 = new byte[3] { 239, 187, 191 }; protected static readonly Encoding UTF8_NO_BOM = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); protected static readonly Encoding ANSI = Utils.Latin1Encoding; public string Path { get; set; } public PlaylistFormat.LocationFormatting LocationFormatting { get; set; } public PlaylistFormat.FileEncoding Encoding { get; set; } public IList<string> FilePaths { get { return getFiles(); } set { setFiles(value); } } public IList<Track> Tracks { get { return getTracks(); } set { setTracks(value); } } protected abstract void getFiles(FileStream fs, IList<string> result); protected abstract void setTracks(FileStream fs, IList<Track> result); public IList<string> getFiles() { IList<string> result = new List<string>(); LogDelegator.GetLocateDelegate()(Path); try { using FileStream fs = new FileStream(Path, FileMode.Open, FileAccess.Read); getFiles(fs, result); } catch (Exception ex) { Console.WriteLine(ex.StackTrace); LogDelegator.GetLogDelegate()(1, ex.Message); } return result; } public IList<Track> getTracks() { IList<Track> list = new List<Track>(); try { foreach (string file in getFiles()) { list.Add(new Track(file)); } } catch (Exception ex) { Console.WriteLine(ex.StackTrace); LogDelegator.GetLogDelegate()(1, ex.Message); } return list; } public void setFiles(IList<string> fileList) { IList<Track> list = new List<Track>(); foreach (string file in fileList) { Track item = new Track(file, null, load: false); list.Add(item); } setTracks(list); } public void setTracks(IList<Track> trackList) { LogDelegator.GetLocateDelegate()(Path); try { using FileStream fileStream = new FileStream(Path, FileMode.Create, FileAccess.ReadWrite); if (Encoding.Equals(PlaylistFormat.FileEncoding.UTF8_BOM)) { fileStream.Write(BOM_UTF8, 0, 3); } setTracks(fileStream, trackList); } catch (Exception ex) { Console.WriteLine(ex.StackTrace); LogDelegator.GetLogDelegate()(1, ex.Message); } } protected XmlWriterSettings generateWriterSettings() { XmlWriterSettings xmlWriterSettings = new XmlWriterSettings(); xmlWriterSettings.CloseOutput = true; if (Encoding == PlaylistFormat.FileEncoding.ANSI) { xmlWriterSettings.Encoding = ANSI; } else { xmlWriterSettings.Encoding = UTF8_NO_BOM; } xmlWriterSettings.OmitXmlDeclaration = true; xmlWriterSettings.ConformanceLevel = ConformanceLevel.Fragment; xmlWriterSettings.Indent = true; xmlWriterSettings.DoNotEscapeUriAttributes = false; return xmlWriterSettings; } protected string encodeLocation(string location) { switch (LocationFormatting) { case PlaylistFormat.LocationFormatting.RFC_URI: { Uri uri = new Uri(location, UriKind.RelativeOrAbsolute); if (!uri.IsAbsoluteUri) { return uri.OriginalString; } return uri.AbsoluteUri; } case PlaylistFormat.LocationFormatting.MS_URI: return "file://" + location; case PlaylistFormat.LocationFormatting.Winamp_URI: return "file:" + location; default: return location; } } protected void decodeLocation(XmlReader source, string attributeName, IList<string> result) { string text = decodeLocation(source.GetAttribute(attributeName)); if (text != null) { result.Add(text); } } protected string decodeLocation(string href) { string text = href.Replace('\\', '/'); if (text.Contains("://")) { try { Uri uri = new Uri(text); if (uri.IsFile) { if (!System.IO.Path.IsPathRooted(uri.LocalPath)) { return System.IO.Path.Combine(System.IO.Path.GetDirectoryName(Path), uri.LocalPath); } string localPath = uri.LocalPath; char directorySeparatorChar = System.IO.Path.DirectorySeparatorChar; string text2 = directorySeparatorChar.ToString(); directorySeparatorChar = System.IO.Path.DirectorySeparatorChar; string oldValue = text2 + directorySeparatorChar; directorySeparatorChar = System.IO.Path.DirectorySeparatorChar; return localPath.Replace(oldValue, directorySeparatorChar.ToString() ?? ""); } } catch (UriFormatException) { LogDelegator.GetLogDelegate()(2, text + " is not a valid URI [" + Path + "]"); } } href = href.Replace("file:///", "").Replace("file://", "").Replace("file:", ""); if (!System.IO.Path.IsPathRooted(href)) { href = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(Path), href); } return href; } } public class PlaylistIOFactory : Factory { public const int PL_M3U = 0; public const int PL_PLS = 1; public const int PL_FPL = 2; public const int PL_XSPF = 3; public const int PL_SMIL = 4; public const int PL_ASX = 5; public const int PL_B4S = 6; private static PlaylistIOFactory theFactory = null; private static readonly object _lockable = new object(); public static PlaylistIOFactory GetInstance() { lock (_lockable) { if (theFactory == null) { theFactory = new PlaylistIOFactory(); theFactory.formatListByExt = new Dictionary<string, IList<Format>>(); PlaylistFormat playlistFormat = new PlaylistFormat(0, "M3U"); playlistFormat.AddExtension(".m3u"); playlistFormat.AddExtension(".m3u8"); theFactory.addFormat(playlistFormat); playlistFormat = new PlaylistFormat(1, "PLS"); playlistFormat.AddExtension(".pls"); theFactory.addFormat(playlistFormat); playlistFormat = new PlaylistFormat(2, "FPL (experimental)"); playlistFormat.LocationFormat = PlaylistFormat.LocationFormatting.MS_URI; playlistFormat.AddExtension(".fpl"); theFactory.addFormat(playlistFormat); playlistFormat = new PlaylistFormat(3, "XSPF (spiff)"); playlistFormat.AddExtension(".xspf"); theFactory.addFormat(playlistFormat); playlistFormat = new PlaylistFormat(4, "SMIL"); playlistFormat.LocationFormat = PlaylistFormat.LocationFormatting.RFC_URI; playlistFormat.AddExtension(".smil"); playlistFormat.AddExtension(".smi"); playlistFormat.AddExtension(".zpl"); playlistFormat.AddExtension(".wpl"); theFactory.addFormat(playlistFormat); playlistFormat = new PlaylistFormat(5, "ASX"); playlistFormat.LocationFormat = PlaylistFormat.LocationFormatting.FilePath; playlistFormat.AddExtension(".asx"); playlistFormat.AddExtension(".wax"); playlistFormat.AddExtension(".wvx"); theFactory.addFormat(playlistFormat); playlistFormat = new PlaylistFormat(6, "B4S"); playlistFormat.