Decompiled source of NetRadio v2.2.0
plugins/NetRadio/NetRadio.dll
Decompiled a week 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.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using CSCore; using CSCore.Ffmpeg; using CSCore.Ffmpeg.Interops; using CSCore.SoundOut; using CSCore.Streams; using CSCore.Streams.SampleConverter; using CommonAPI; using CommonAPI.Phone; using CommonAPI.UI; using HarmonyLib; using Microsoft.CodeAnalysis; using NetRadio.Apps; using NetRadio.Metadata; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Reptile; using Reptile.Phone; using TMPro; using UnityEngine; 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: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")] [assembly: AssemblyCompany("NetRadio")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Radio app for Bomb Rush Cyberfunk")] [assembly: AssemblyFileVersion("2.2.0.0")] [assembly: AssemblyInformationalVersion("2.2.0+08c5ae34f402805e6ddbb05fc934a241786598af")] [assembly: AssemblyProduct("NetRadio")] [assembly: AssemblyTitle("NetRadio")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.2.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace NetRadio { [BepInPlugin("goatgirl.NetRadio", "NetRadio", "2.2.0")] [BepInProcess("Bomb Rush Cyberfunk.exe")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class NetRadioPlugin : BaseUnityPlugin { internal static Harmony Harmony = new Harmony("goatgirl.NetRadio"); public static bool hasBRR = false; public static bool hasMusicCurator = false; public static NetRadioPlugin Instance { get; private set; } public string Directory => Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); private void Awake() { Instance = this; NetRadio.Log = ((BaseUnityPlugin)this).Logger; Harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin NetRadio is loaded!"); NetRadio.GlobalRadio = NetRadioManager.CreateRadio(((Component)this).transform); NetRadio.GlobalRadio.volume = 1f; AppNetRadio.Initialize(); AppSelectedStation.Initialize(); Settings.BindSettings(((BaseUnityPlugin)this).Config); foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos) { if (pluginInfo.Value.Metadata.GUID.Contains("BombRushRadio")) { hasBRR = true; } if (pluginInfo.Value.Metadata.GUID.Contains("MusicCurator")) { hasMusicCurator = true; } if (pluginInfo.Value.Metadata.GUID.Contains("LiveRadioPOC")) { NetRadio.Log.LogError((object)"Development version of goatgirl.NetRadio detected! Please delete the development version (goatgirl.LiveRadioPOC)!"); } } if (Debugger.IsAttached) { FfmpegUtils.LogToDefaultLogger = false; FfmpegUtils.FfmpegLogReceived += delegate(object s, FfmpegLogReceivedEventArgs e) { ((BaseUnityPlugin)this).Logger.LogError((object)("CSCORE FFMPEG: " + e.Message)); }; } } private void OnDestroy() { Harmony.UnpatchSelf(); } private void Update() { NetRadio.Update(); } } public class NetRadio { public static Random rando = new Random(); public static ManualLogSource Log; public static NetRadioManager GlobalRadio; public const string PluginName = "NetRadio"; public const string PluginGUID = "goatgirl.NetRadio"; public const string PluginVersion = "2.2.0"; public static bool gameStarted = false; public static Color LabelSelectedColorDefault = Color32.op_Implicit(new Color32((byte)49, (byte)90, (byte)165, byte.MaxValue)); public static Color LabelUnselectedColorDefault = Color.white; public static int waveOutLatency = 50; public static List<string> hasRedir = new List<string>(); public static NetRadioPlugin PluginInstance => NetRadioPlugin.Instance; public static MusicPlayer musicPlayer { get { IMusicPlayer obj = Core.Instance.AudioManager.MusicPlayer; return (MusicPlayer)(object)((obj is MusicPlayer) ? obj : null); } } public static Player player { get { WorldHandler instance = WorldHandler.instance; return (instance != null) ? instance.GetCurrentPlayer() : null; } } public static AudioSubSystem audioSubSystem { get { IAudioSubSystem obj = Core.Instance.AudioManager.audioSubSystem; return (AudioSubSystem)(object)((obj is AudioSubSystem) ? obj : null); } } public static AudioManager audioManager => Core.Instance.AudioManager; public static float radioMusicVolume => audioSubSystem.GetChannelVolumeScale((AudioChannelID)4, audioManager.musicAudioMaxVolume01Clamped) * audioSubSystem.GetChannelVolumeScale((AudioChannelID)0, audioManager.masterAudioMaxVolume01Clamped) * Settings.streamVolume.Value; public static float sfxVolume => audioSubSystem.GetChannelVolumeScale((AudioChannelID)0, audioManager.masterAudioMaxVolume01Clamped) * audioSubSystem.GetChannelVolumeScale((AudioChannelID)1, audioManager.masterAudioMaxVolume01Clamped); public static float bufferTimeInSeconds => Settings.extraBufferSec.Value; public static string customSFXpath => Path.Combine(Paths.ConfigPath, "NetRadio", "CustomSFXPacks"); public static void Update() { if (GlobalRadio == null) { return; } if (GlobalRadio.playing) { UpdateGlobalRadioVolume(); if (musicPlayer.IsPlaying) { musicPlayer.ForcePaused(); } } if (AppNetRadio.waveOut == null || !AppNetRadio.playing) { return; } if (PlayerUsingApp(typeof(AppNetRadio))) { if (GlobalRadio.failedToLoad) { ((MonoBehaviour)PluginInstance).StartCoroutine(AppNetRadio.Instance.HandleFailedConnection()); } else if (GlobalRadio.playing) { AppNetRadio.PlaySFX("success"); ((MonoBehaviour)PluginInstance).StartCoroutine(AppNetRadio.Instance.StopIn(0f)); } } else if (GlobalRadio.playing || GlobalRadio.failedToLoad) { GlobalRadio.failedToLoad = false; AppNetRadio.waveOut.Stop(); AppNetRadio.playing = false; } } public static bool PlayerUsingMusicApp() { return PlayerUsingApp(typeof(AppMusicPlayer)); } public static bool PlayerUsingApp(Type checkAppType) { if ((Object)(object)player == (Object)null || (Object)(object)player.phone == (Object)null) { return false; } try { Type type = ((object)player.phone.m_CurrentApp).GetType(); bool flag = player.phone.IsOn && player.phoneLayerWeight >= 1f; return type == checkAppType && flag; } catch (Exception) { return false; } } public static bool pressedAnyButtonIn(List<KeyCode> keybinds) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) foreach (KeyCode keybind in keybinds) { if (Input.GetKeyUp(keybind)) { return true; } } return false; } public static Sprite LoadSprite(string path) { Sprite val = TextureUtility.LoadSprite(path); ((Texture)val.texture).filterMode = (FilterMode)1; ((Texture)val.texture).wrapMode = (TextureWrapMode)1; return val; } public static async Task MuteUntilRadioPlaying() { while (!GlobalRadio.playing) { musicPlayer.ForcePaused(); await Task.Yield(); } AppNetRadio.waveOut.Stop(); AppNetRadio.playing = false; AppNetRadio.PlaySFX("success"); } public static bool IsStationButton(SimplePhoneButton button) { if ((Object)(object)button == (Object)null || (Object)(object)button.Label == (Object)null) { return false; } int childCount = ((Component)button.Label).gameObject.transform.childCount; bool flag = ((TMP_Text)button.Label).text.Contains("Custom Station") || ((TMP_Text)button.Label).text == "NetRadio" || Settings.streamTitles.Contains(((TMP_Text)button.Label).text); return childCount > 2 && flag; } public static bool IsHeaderButton(SimplePhoneButton button) { if ((Object)(object)button == (Object)null || (Object)(object)button.Label == (Object)null) { return false; } int childCount = ((Component)button.Label).gameObject.transform.childCount; if (childCount < 1) { return false; } return ((Object)((Component)((Component)button.Label).gameObject.transform.GetChild(0)).gameObject).name.Contains("Header"); } public static string StandardizeURL(string originalURL) { return originalURL.Replace("https://", "").Replace("http://", "").Trim() .ToLower() .TrimEnd(new char[1] { '/' }); } public static string ReadIcyHeader(HttpResponseMessage response, string header) { string text = (header.StartsWith("icy-") ? header : ("icy-" + header)); IEnumerable<string> source = default(IEnumerable<string>); if (((HttpHeaders)response.Headers).TryGetValues(text, ref source)) { return source.First(); } return null; } public static string GetRedirectedURL(string url) { try { HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url); httpWebRequest.Method = "POST"; httpWebRequest.AllowAutoRedirect = true; httpWebRequest.Timeout = 2000; WebResponse response = httpWebRequest.GetResponse(); string text = response.ResponseUri.AbsoluteUri.ToString(); hasRedir.Add(text); if (!text.Equals(url)) { Log.LogInfo((object)("Updating internal station URL " + url + " - redirects to " + text)); } return text; } catch (Exception) { return null; } } public static string GetParentUriString(Uri uri) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(uri.Scheme); stringBuilder.Append("://"); stringBuilder.Append(uri.Host); if (uri.Port != -1) { stringBuilder.Append(":"); stringBuilder.Append(uri.Port); } for (int i = 0; i < uri.Segments.Length - 1; i++) { stringBuilder.Append(uri.Segments[i]); } return stringBuilder.ToString(); } public static void UpdateGlobalRadioVolume() { string key = StandardizeURL(GlobalRadio.currentStationURL); float num = (SaveData.stationSettingsByURL.ContainsKey(key) ? ((float)SaveData.stationSettingsByURL[key].volume) : 1f); GlobalRadio.radioVolume = radioMusicVolume * num; } public static void UpdateCurrentSong(bool skipCheck = false) { if (GlobalRadio.playing && (skipCheck || PlayerUsingMusicApp())) { App currentApp = player.phone.m_CurrentApp; AppMusicPlayer val = (AppMusicPlayer)(object)((currentApp is AppMusicPlayer) ? currentApp : null); MusicTrack val2 = ScriptableObject.CreateInstance<MusicTrack>(); val2.AudioClip = null; val2.Artist = GlobalRadio.GetStationTitle(); val2.Title = GlobalRadio.currentSong; val.m_StatusPanel.OnNewTrack(val2); } } public static Source GetSource(IcecastStatus icecastStatus, string url = "") { List<Source> source = icecastStatus.icestats.source; if (source.Count != 1 && !string.IsNullOrWhiteSpace(url)) { try { string value = url.Split(new string[1] { "/" }, StringSplitOptions.RemoveEmptyEntries).Last().Trim(); foreach (Source item in source) { if (item.listenurl.Contains(value)) { return item; } } } catch (Exception) { } } return source[0]; } public static string ShortenNumber(int number) { if (number < 1000) { return number.ToString(); } if (number < 100000) { double num = (double)number / 1000.0; return (num < 10.0) ? (num.ToString("0.#") + "k") : (num.ToString("0") + "k"); } double num2 = (double)number / 1000000.0; return (num2 < 10.0) ? (num2.ToString("0.#") + "M") : (num2.ToString("0") + "M"); } } public class NetRadioManager : MonoBehaviour { public List<string> streamURLs = new List<string>(); public float volume = 1f; private bool stopped = false; private Thread playURLThread; private Thread playURLChildThread; public bool useThread = true; public bool failedToLoad = false; private static HttpClient m_httpClient = null; private float connectionTime = 0f; private float metadataTimeOffset = 0f; private Task trackingMetadataTask; private long oldPosition = -100L; private bool startTrackingPosition = false; private int amountOfTimesFoundAtSamePosition = 0; private Dictionary<string, string> knownStatusXSLs = new Dictionary<string, string>(); private bool disabling = false; public FfmpegDecoder ffmpegReader { get; private set; } public DirectSoundOut directSoundOut { get; private set; } public VolumeSource volumeSource { get; private set; } public PeakMeter meter { get; private set; } public float radioVolume { get { return (volumeSource != null) ? volumeSource.Volume : 0f; } set { if (volumeSource != null) { volumeSource.Volume = Mathf.Clamp01(value) * volume; } } } public float streamSampleVolume { get; private set; } = 0f; public bool playing { get { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 return directSoundOut != null && (int)directSoundOut.PlaybackState == 1; } set { if (value) { Resume(); } else { Stop(); } } } public int currentStation { get; private set; } = -1; public int previousStation { get; private set; } = -1; public string currentStationURL => streamURLs[currentStation]; public bool threadRunning => playURLThread != null && playURLThread.IsAlive; public IcecastStatus currentMetadata { get; private set; } public string currentSong { get; private set; } public static bool enableMetadataTracking { get; private set; } = true; public bool trackingMetadata { get; private set; } = false; public bool skipDisposal { get; private set; } = false; private void Start() { if ((Object)(object)NetRadio.GlobalRadio == (Object)(object)this) { Settings.LoadURLs(); new SaveData(); } NetRadio.Log.LogInfo((object)"Loaded radio manager"); } private void FixedUpdate() { if (directSoundOut == null || ffmpegReader == null) { return; } if (playing) { if (ffmpegReader.Position <= oldPosition && startTrackingPosition) { int num = (int)Mathf.Round(NetRadio.bufferTimeInSeconds * 30f); amountOfTimesFoundAtSamePosition++; if (amountOfTimesFoundAtSamePosition > num) { StopRadio(); AppNetRadio.PlaySFX("lost"); amountOfTimesFoundAtSamePosition = 0; skipDisposal = true; } } else { amountOfTimesFoundAtSamePosition = 0; if (ffmpegReader.Position > 10000) { startTrackingPosition = true; } } oldPosition = ffmpegReader.Position; } else { startTrackingPosition = false; oldPosition = 0L; } } private void OnDisable() { disabling = true; skipDisposal = false; CleanUp(); } public void CleanUp() { StopRadio(); stopped = true; try { StopTrackingMetadata(); DisposeOfReaders(); } catch (Exception) { } } public void ResetMetadata() { currentSong = "Unknown Track"; currentMetadata = null; } public void StopTrackingMetadata(bool wait = true) { trackingMetadata = false; if (trackingMetadataTask != null && wait) { trackingMetadataTask.Wait(); trackingMetadataTask.Dispose(); } } private void DisposeOfReaders() { try { if (ffmpegReader != null) { ffmpegReader.Dispose(); } } catch (Exception ex) { NetRadio.Log.LogError((object)ex); } ffmpegReader = null; try { if (directSoundOut != null) { directSoundOut.Dispose(); } } catch (Exception ex2) { NetRadio.Log.LogError((object)ex2); } directSoundOut = null; if (m_httpClient != null) { ((HttpMessageInvoker)m_httpClient).Dispose(); } } public void Play(int streamIndex = -999) { PlayRadioStation((streamIndex == -999) ? currentStation : streamIndex); } public void Stop() { StopRadio(); } public void Resume() { if (directSoundOut != null) { directSoundOut.Play(); } } public void Pause() { stopped = true; if (directSoundOut != null) { directSoundOut.Pause(); } } public static void ReloadAllStations() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 Settings.LoadURLs(); Settings.RefreshMusicApp(); NetRadioManager globalRadio = NetRadio.GlobalRadio; if ((Object)(object)globalRadio != (Object)null && globalRadio.currentStation >= 0 && (int)globalRadio.directSoundOut.PlaybackState > 0) { globalRadio.PlayRadioStation(globalRadio.currentStation); } } public void PlayRandomStation() { int streamIndex = NetRadio.rando.Next(0, streamURLs.Count); PlayRadioStation(streamIndex); } public void PlayRadioStation(int streamIndex) { failedToLoad = false; if (streamIndex < 0 || streamIndex >= streamURLs.Count) { NetRadio.Log.LogError((object)"PlayRadioStation: Invalid stream index!"); failedToLoad = true; return; } if (playURLThread != null && playURLThread.IsAlive) { playURLThread.Join(); playURLChildThread.Join(); } StopRadio(); previousStation = currentStation; currentStation = streamIndex; if (useThread && !Settings.noThreads.Value) { playURLThread = new Thread(StartPlayURL); playURLThread.Start(); } else { PlayURL(); } } private void StartPlayURL() { ThreadStart start = PlayURL; playURLChildThread = new Thread(start); playURLChildThread.Start(); if (!playURLChildThread.Join(new TimeSpan(0, 0, 15))) { failedToLoad = true; playURLChildThread.Abort(); } } private void CheckForRedirection() { try { if (!NetRadio.hasRedir.Contains(currentStationURL)) { string redirectedURL = NetRadio.GetRedirectedURL(currentStationURL); if (redirectedURL != null) { streamURLs[currentStation] = redirectedURL; } } } catch (Exception) { } } private void PlayURL() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown CheckForRedirection(); try { if (!skipDisposal) { DisposeOfReaders(); } m_httpClient = CreateHTTPClient(); float realtimeSinceStartup = Time.realtimeSinceStartup; ffmpegReader = new FfmpegDecoder(currentStationURL); connectionTime = Time.realtimeSinceStartup - realtimeSinceStartup; int num = (int)Mathf.Round((float)ffmpegReader.WaveFormat.BytesPerSecond * NetRadio.bufferTimeInSeconds); BufferSource val = new BufferSource((IWaveSource)(object)ffmpegReader, num); meter = new PeakMeter(WaveToSampleBase.CreateConverter((IWaveSource)(object)val)); meter.Interval = 50; if ((Object)(object)NetRadio.GlobalRadio == (Object)(object)this) { meter.PeakCalculated += delegate { streamSampleVolume = meter.PeakValue; }; } volumeSource = new VolumeSource((ISampleSource)(object)meter); directSoundOut = InitializeSoundOut((ISampleSource)(object)volumeSource); NetRadio.UpdateGlobalRadioVolume(); directSoundOut.Play(); connectionTime = Time.realtimeSinceStartup - realtimeSinceStartup; skipDisposal = false; } catch (Exception ex) { if (currentStationURL.StartsWith("http://")) { streamURLs[currentStation] = currentStationURL.Replace("http://", "https://"); PlayURL(); return; } failedToLoad = true; NetRadio.Log.LogError((object)("Error playing radio: " + ex.Message)); NetRadio.Log.LogError((object)ex.StackTrace); } if ((Object)(object)NetRadio.GlobalRadio == (Object)(object)this && !failedToLoad && !trackingMetadata) { StartTrackingMetadata(); } stopped = false; } public void StartTrackingMetadata(bool overrideCancel = false) { if (trackingMetadataTask != null) { trackingMetadataTask.Wait(); } trackingMetadataTask = TrackMetadata(overrideCancel); } private async Task OutputStopped(PlaybackStoppedEventArgs args) { NetRadio.Log.LogWarning((object)"Stopped DirectSound output"); if (((StoppedEventArgs)args).HasError) { Exception exception = ((StoppedEventArgs)args).Exception; NetRadio.Log.LogWarning((object)exception.Message); } if (!stopped && !AppNetRadio.playing && !threadRunning && !disabling) { NetRadio.Log.LogWarning((object)"Output device changed?"); await Task.Delay(500); if (!playing && !threadRunning && !AppNetRadio.playing) { NetRadio.Log.LogWarning((object)"Reconnecting?"); PlayRadioStation(currentStation); AppNetRadio.PlayNoise(); } } } private DirectSoundOut InitializeSoundOut(ISampleSource source, DirectSoundOut original = null) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown return InitializeSoundOut((IWaveSource)new SampleToIeeeFloat32(source), original); } private DirectSoundOut InitializeSoundOut(IWaveSource source, DirectSoundOut original = null) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) DirectSoundOut val = (DirectSoundOut)((original != null) ? ((object)original) : ((object)new DirectSoundOut(NetRadio.waveOutLatency))); val.Stopped += delegate(object a, PlaybackStoppedEventArgs b) { OutputStopped(b); }; val.Initialize(source); return val; } public void StopRadio() { stopped = true; trackingMetadata = false; ResetMetadata(); if (directSoundOut != null) { directSoundOut.Stop(); } } public string GetStationTitle(int streamIndex = -999) { if ((Object)(object)NetRadio.GlobalRadio != (Object)(object)this) { return "LocalRadio"; } int num = ((streamIndex == -999) ? currentStation : streamIndex); if (num < 0 || num >= streamURLs.Count || num >= Settings.streamTitles.Count) { return "NetRadio"; } return Settings.streamTitles[num]; } public async Task<IcecastStatus> GetMetadata(string url = "") { if (m_httpClient == null) { m_httpClient = CreateHTTPClient(); } if (url == "") { url = currentStationURL; } return await GetMetaDataFromIceCastStream(url); } public async Task TrackMetadata(bool overrideCancel = false) { string urlForCurrent = NetRadio.StandardizeURL(Settings.configURLs[currentStation]); bool cancelTracking = SaveData.stationSettingsByURL.ContainsKey(urlForCurrent) && SaveData.stationSettingsByURL[urlForCurrent].metadataMode == 0; if (!overrideCancel && (!enableMetadataTracking || cancelTracking)) { return; } trackingMetadata = true; IcecastStatus oldMetadata = null; _ = currentStation; bool looped = false; while (trackingMetadata && playing) { int awaitTime = 1000; if (!string.IsNullOrWhiteSpace(currentStationURL)) { try { float realtimeAtStart = Time.realtimeSinceStartup; currentMetadata = await GetMetaDataFromIceCastStream(currentStationURL); _ = Time.realtimeSinceStartup - realtimeAtStart; if (currentMetadata == null) { NetRadio.Log.LogError((object)"Null metadata. Cancelling tracking"); trackingMetadata = false; return; } if (oldMetadata == null || NetRadio.GetSource(currentMetadata, currentStationURL).title != NetRadio.GetSource(oldMetadata, currentStationURL).title) { decimal savedTime = (SaveData.stationSettingsByURL.ContainsKey(urlForCurrent) ? SaveData.stationSettingsByURL[urlForCurrent].metadataTimeOffsetSeconds : 0m); metadataTimeOffset = (float)savedTime; if (metadataTimeOffset > 0f && looped) { awaitTime = (int)Mathf.Clamp((float)awaitTime - metadataTimeOffset * 1000f, 20f, 2000f); await DelayTrackingInSteps((int)(metadataTimeOffset * 1000f)); } looped = true; HandleMetadata(currentMetadata); oldMetadata = currentMetadata; } } catch (Exception ex) { Exception exception = ex; NetRadio.Log.LogError((object)("Error tracking metadata: " + exception.Message)); NetRadio.Log.LogError((object)exception.StackTrace); trackingMetadata = false; } } await DelayTrackingInSteps(awaitTime); } trackingMetadata = false; } private void HandleMetadata(IcecastStatus originalMetadata) { if (!playing) { return; } Source source = NetRadio.GetSource(originalMetadata, currentStationURL); currentSong = source.title; if (!string.IsNullOrWhiteSpace(source.artist)) { currentSong = source.artist + " - " + source.title; currentSong = currentSong.Trim(); if (currentSong.StartsWith("- " + source.title)) { currentSong = source.title; } } NetRadio.Log.LogInfo((object)("Metadata updated for station " + GetStationTitle() + ": " + currentSong)); NetRadio.UpdateCurrentSong(); if (NetRadio.PlayerUsingApp(typeof(AppSelectedStation)) && AppSelectedStation.isStation) { AppSelectedStation.Instance.UpdateStationMetadata(originalMetadata); } } private HttpClient CreateHTTPClient() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown HttpClient val = new HttpClient(); ((HttpHeaders)val.DefaultRequestHeaders).Add("Icy-MetaData", "1"); val.DefaultRequestHeaders.UserAgent.ParseAdd("C# App (BRC NetRadio)"); val.Timeout = TimeSpan.FromSeconds(10.0); return val; } private async Task<IcecastStatus> GetMetaDataFromIceCastStream(string url) { if (url == null) { return null; } bool connected = false; string responseString = ""; string prevStatusURL = ""; Uri uri = new Uri(url); string statusUrl; do { string baseUrl = NetRadio.GetParentUriString(uri); if (knownStatusXSLs.ContainsKey(url)) { statusUrl = knownStatusXSLs[url]; } else { if (!baseUrl.EndsWith("/")) { baseUrl += "/"; } statusUrl = baseUrl + "status-json.xsl"; NetRadio.Log.LogInfo((object)("Checking for status-json.xsl: " + statusUrl)); if (statusUrl == prevStatusURL) { NetRadio.Log.LogWarning((object)"Already checked!"); return null; } } try { HttpResponseMessage response = await m_httpClient.GetAsync(statusUrl); if (!response.IsSuccessStatusCode) { if (response.StatusCode == HttpStatusCode.Forbidden) { NetRadio.Log.LogWarning((object)("403 Forbidden: " + statusUrl)); NetRadio.Log.LogWarning((object)"Force disabling metadata tracking for station..."); string urlForCurrent = NetRadio.StandardizeURL(Settings.configURLs[currentStation]); if (SaveData.stationSettingsByURL.ContainsKey(urlForCurrent)) { SaveData.stationSettingsByURL[urlForCurrent].metadataMode = 0; ((CustomSaveData)SaveData.Instance).Save(); } return null; } throw new HttpRequestException(); } responseString = await response.Content.ReadAsStringAsync(); connected = true; } catch (Exception exception2) { if (!(exception2 is HttpRequestException)) { if (exception2.Message.Contains("task was canceled")) { NetRadio.Log.LogWarning((object)("Error getting metadata: " + exception2.Message)); } else { NetRadio.Log.LogError((object)("Error getting metadata: " + exception2.Message)); NetRadio.Log.LogError((object)exception2.StackTrace); } return null; } if (knownStatusXSLs.ContainsKey(url)) { knownStatusXSLs.Remove(url); } if (uri.ToString() == baseUrl || statusUrl == prevStatusURL) { return null; } uri = new Uri(baseUrl); } prevStatusURL = statusUrl; } while (!connected); try { IcecastStatus icecastStatus = JsonConvert.DeserializeObject<IcecastStatus>(responseString); if (!knownStatusXSLs.ContainsKey(url)) { knownStatusXSLs.Add(url, statusUrl); } return icecastStatus; } catch (Exception exception) { NetRadio.Log.LogError((object)("Error getting metadata: " + exception.Message)); NetRadio.Log.LogError((object)exception.StackTrace); } return null; } public static NetRadioManager CreateRadio(Transform parent) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown GameObject val = new GameObject(); NetRadioManager result = val.AddComponent<NetRadioManager>(); val.transform.parent = parent; return result; } public async Task DelayTrackingInSteps(int delayTime, int step = 20) { int i = 0; while (i * step < delayTime) { await Task.Delay(step); i++; if (!trackingMetadata) { NetRadio.Log.LogWarning((object)("Delay ending early (" + i * step + "/" + delayTime + ")")); break; } } } } public class SaveData : CustomSaveData { public static readonly int saveVersion = 1; private static int readSaveVersion = 0; public static Dictionary<string, StationSettings> stationSettingsByURL = new Dictionary<string, StationSettings>(); public static SaveData Instance { get; private set; } public SaveData() : base("NetRadio", "Slot{0}.data", (SaveLocations)2) { Instance = this; base.AutoSave = false; } public override void Initialize() { stationSettingsByURL = new Dictionary<string, StationSettings>(); Settings.LoadURLs(); foreach (string configURL in Settings.configURLs) { if (!stationSettingsByURL.ContainsKey(NetRadio.StandardizeURL(configURL))) { stationSettingsByURL.Add(NetRadio.StandardizeURL(configURL), new StationSettings(configURL)); } } } public override void Read(BinaryReader reader) { stationSettingsByURL.Clear(); readSaveVersion = reader.ReadByte(); int num = reader.ReadInt32(); if (readSaveVersion == 0) { for (int i = 0; i < num; i++) { string text = reader.ReadString(); decimal volume = reader.ReadDecimal(); foreach (string previousFUFMurl in Settings.previousFUFMurls) { if (text.Contains(previousFUFMurl)) { text = NetRadio.StandardizeURL("https://funkyunclefm.net:8443/fufm"); } } StationSettings stationSettings = new StationSettings(text); stationSettings.volume = volume; if (!stationSettingsByURL.ContainsKey(text)) { stationSettingsByURL.Add(text, stationSettings); } else { stationSettingsByURL[text] = stationSettings; } } } else if (readSaveVersion == 1) { for (int j = 0; j < num; j++) { StationSettings stationSettings2 = new StationSettings(); string key = reader.ReadString(); stationSettings2.volume = reader.ReadDecimal(); stationSettings2.metadataMode = reader.ReadInt32(); stationSettings2.metadataTimeOffsetSeconds = reader.ReadDecimal(); stationSettingsByURL.Add(key, stationSettings2); } } } public override void Write(BinaryWriter writer) { if (saveVersion == 0) { writer.Write((byte)saveVersion); writer.Write(stationSettingsByURL.Count); { foreach (string key in stationSettingsByURL.Keys) { writer.Write(key); writer.Write(stationSettingsByURL[key].volume); } return; } } if (saveVersion != 1) { return; } writer.Write((byte)saveVersion); writer.Write(stationSettingsByURL.Count); foreach (string key2 in stationSettingsByURL.Keys) { writer.Write(key2); writer.Write(stationSettingsByURL[key2].volume); writer.Write(stationSettingsByURL[key2].metadataMode); writer.Write(stationSettingsByURL[key2].metadataTimeOffsetSeconds); } } } public class StationSettings { public decimal volume = 1m; public int metadataMode = 1; public decimal metadataTimeOffsetSeconds = default(decimal); public StationSettings() { } public StationSettings(string associatedURL) : this() { foreach (string item in Settings.partneredStations.Keys.ToList()) { if (item.Contains(associatedURL)) { StationSettings stationSettings = Settings.partneredStations[item]; volume = stationSettings.volume; metadataMode = stationSettings.metadataMode; metadataTimeOffsetSeconds = stationSettings.metadataTimeOffsetSeconds; } } foreach (string item2 in Settings.extraStations.Keys.ToList()) { if (item2.Contains(associatedURL)) { StationSettings stationSettings2 = Settings.extraStations[item2]; volume = stationSettings2.volume; metadataMode = stationSettings2.metadataMode; metadataTimeOffsetSeconds = stationSettings2.metadataTimeOffsetSeconds; } } } } internal class Settings { public static ConfigEntry<string> streamURLsUnsplit; public static ConfigEntry<float> streamVolume; public static ConfigEntry<bool> playOnStartup; public static ConfigEntry<int> startupIndex; public static ConfigEntry<bool> configureRequireConnection; public static ConfigEntry<float> extraBufferSec; public static ConfigEntry<bool> noThreads; public static ConfigEntry<bool> restartMusic; public static ConfigEntry<string> sfxPack; public static List<string> streamTitles = new List<string>(); public const string FUFMurl = "https://funkyunclefm.net:8443/fufm"; public static readonly List<string> previousFUFMurls = new List<string> { "fancynoise.net:8443/fufm.mp3" }; public static readonly Dictionary<string, StationSettings> partneredStations = new Dictionary<string, StationSettings> { { "(FunkyUncleFM)https://funkyunclefm.net:8443/fufm,", new StationSettings { metadataTimeOffsetSeconds = 7m } } }; public static Dictionary<string, StationSettings> extraStations = new Dictionary<string, StationSettings>(); public static List<string> configURLs; public static void BindSettings(ConfigFile Config) { //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown streamURLsUnsplit = Config.Bind<string>("Settings", "Custom Stream URLs", "", "List of custom radio station URLs, separated by commas. To add a display name, format your link like: (StationName)https://stationlink.com/stream.mp3"); streamURLsUnsplit.SettingChanged += UpdateSettingsEvent; streamVolume = Config.Bind<float>("Settings", "Radio Volume", 1f, "Relative volume of all radio streams compared to in-game music. Note that you can set individual stations' volumes in the NetRadio app."); extraBufferSec = Config.Bind<float>("Settings", "Buffer Time", 0.5f, "The length of the station's buffer in seconds. A longer buffer delays audio playback, but reduces stuttering."); playOnStartup = Config.Bind<bool>("Settings", "Play Radio on Startup", false, "Whether or not a radio station should automatically play upon loading a save."); startupIndex = Config.Bind<int>("Settings", "Startup Radio Station", 0, "The index of the station to play automatically if Play Radio on Startup is enabled (the first station in the NetRadio app is at index 0). If set to -1, the station will be chosen randomly."); configureRequireConnection = Config.Bind<bool>("Settings", "Configuring Stations Requires Connection", false, "Whether it is possible to change a station's settings within the NetRadio app without connecting to the station."); restartMusic = Config.Bind<bool>("Settings", "Restart Interrupted Music", true, "Whether to either restart the in-game music or reconnect to a previous station when disconnecting from (or failing to connect to) a radio station."); sfxPack = Config.Bind<string>("Settings", "App SFX Pack", "Default", new ConfigDescription("The sound effect pack to use within the NetRadio app. Affects sound effects for tuning into a station, connecting, disconnecting, failing to connect, and losing connection mid-stream. Custom SFX packs placed in /RadioApp-res/sfx are also supported.", (AcceptableValueBase)(object)GetSFXFolders(), Array.Empty<object>())); noThreads = Config.Bind<bool>("Settings", "Disable Multithreading", false, "EXPERIMENTAL! Prevent multithreading for radio streaming, causing the game to freeze when starting a radio. Not recommended."); } public static void UpdateSettingsEvent(object sender, EventArgs args) { LoadURLs(); RefreshMusicApp(); } public static void RefreshMusicApp() { if ((Object)(object)NetRadio.player != (Object)null && (Object)(object)NetRadio.player.phone != (Object)null && NetRadio.player.phone.m_CurrentApp is AppNetRadio && NetRadio.player.phone.IsOn && NetRadio.player.phoneLayerWeight >= 1f) { AppNetRadio.Instance.ReloadButtons(); } } public static void LoadURLs() { string text = string.Concat(partneredStations.Keys.ToArray()); string text2 = string.Concat(extraStations.Keys.ToArray()); string input = text + streamURLsUnsplit.Value + text2; List<string> list = SplitStringByCommas(input).Distinct().ToList(); List<string> list2 = new List<string>(); streamTitles.Clear(); foreach (string item in list) { if (!string.IsNullOrWhiteSpace(item)) { string[] array = item.Split(new string[1] { ")" }, StringSplitOptions.RemoveEmptyEntries); string text3 = ((array.Length > 1) ? array[0].Split(new string[1] { "(" }, StringSplitOptions.None)[1] : "NetRadio"); string text4 = ((array.Length > 1) ? array[1].Trim() : item.Trim()); if (!text4.StartsWith("https://") && !text4.StartsWith("http://")) { NetRadio.Log.LogInfo((object)("adding HTTP to stream " + text4)); text4 = "http://" + text4; } list2.Add(text4); streamTitles.Add(text3.Trim()); NetRadio.Log.LogInfo((object)("Added stream " + text4)); } } NetRadio.GlobalRadio.streamURLs = list2; configURLs = list2; AppNetRadio.originalURLLabelText.Clear(); AppNetRadio.urlWrapOffsets.Clear(); AppNetRadio.urlIsTooLong.Clear(); } public static List<string> SplitStringByCommas(string input) { return input.Replace("\n", "").Replace("\r", "").Replace("\t", "") .Replace(", ", ",") .Replace(", ", ",") .Split(new string[1] { "," }, StringSplitOptions.RemoveEmptyEntries) .ToList(); } public static KeyCode StringToKeyCode(string input) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (Enum.TryParse<KeyCode>(input, ignoreCase: true, out KeyCode result)) { return result; } return (KeyCode)0; } public static List<KeyCode> KeyCodeListFromList(List<string> input) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) List<KeyCode> list = new List<KeyCode>(); foreach (string item in input) { list.Add(StringToKeyCode(item)); } return list; } public static AcceptableValueList<string> GetSFXFolders() { if (!Directory.Exists(NetRadio.customSFXpath)) { NetRadio.Log.LogInfo((object)("Creating custom SFX folder: " + NetRadio.customSFXpath)); Directory.CreateDirectory(NetRadio.customSFXpath); } List<string> list = new List<string>(new <>z__ReadOnlyArray<string>(new string[8] { "Default", "Legacy", "Dial-up", "Skype", "Discord", "Wii", "3DS", "Vita" })); try { string[] first = Directory.GetDirectories(Path.Combine(AppNetRadio.dataDirectory, "sfx/")).ToArray(); string[] second = Directory.GetDirectories(NetRadio.customSFXpath).ToArray(); string[] array = first.Union(second).ToArray(); string[] array2 = array; foreach (string text in array2) { string text2 = text.Split(new string[2] { "/", "\\" }, StringSplitOptions.RemoveEmptyEntries).Last().Trim(); bool flag = true; foreach (string item in list) { if (item.ToLower() == text2.ToLower()) { flag = false; } } if (flag) { if (text2 == text2.ToLower()) { TextInfo textInfo = new CultureInfo("en-US", useUserOverride: false).TextInfo; text2 = textInfo.ToTitleCase(text2); } list.Add(text2); } } return new AcceptableValueList<string>(list.ToArray()); } catch (Exception) { return new AcceptableValueList<string>(list.ToArray()); } } } public static class PluginInfo { public const string PLUGIN_GUID = "NetRadio"; public const string PLUGIN_NAME = "NetRadio"; public const string PLUGIN_VERSION = "2.2.0"; } } namespace NetRadio.Patches { [HarmonyPatch(typeof(BaseModule))] internal class ReloadMainMenu { [HarmonyPatch("LoadMainMenuScene")] [HarmonyPostfix] private static void LoadingMenu_ResetVars() { NetRadio.gameStarted = false; NetRadio.GlobalRadio.CleanUp(); } } [HarmonyPatch(typeof(BaseModule))] internal class StartupPatch { [HarmonyPostfix] [HarmonyPatch(typeof(BaseModule), "StartGameFromSaveSlot")] [HarmonyPatch(typeof(BaseModule), "StartGameFromCurrentSaveSlotToStage")] public static void StartupRadio() { if (NetRadio.gameStarted) { return; } NetRadio.gameStarted = true; if (Settings.playOnStartup.Value && !NetRadio.GlobalRadio.playing) { NetRadio.MuteUntilRadioPlaying(); if (Settings.startupIndex.Value == -1) { NetRadio.GlobalRadio.PlayRandomStation(); } else { NetRadio.GlobalRadio.PlayRadioStation(Settings.startupIndex.Value); } AppNetRadio.PlayNoise(); AppNetRadio.musicPlayerWasInterrupted = false; } } } [HarmonyPatch(typeof(FfmpegCalls))] internal class CSCorePatches { [HarmonyPrefix] [HarmonyPatch(typeof(FfmpegCalls), "AvformatOpenInput")] [HarmonyPatch(new Type[] { typeof(AVFormatContext**), typeof(string) })] public unsafe static bool Prefix(AVFormatContext** formatContext, string url) { string text = "NetRadio/2.2.0 Lavf/57.56.100"; AVDictionary* ptr = null; ffmpeg.av_dict_set(&ptr, "user-agent", text, 0); int num = ffmpeg.avformat_open_input(formatContext, url, (AVInputFormat*)null, &ptr); FfmpegException.Try(num, "avformat_open_input"); return false; } } [HarmonyPatch(typeof(AppHomeScreen))] internal class HomeAppPatches { [HarmonyPostfix] [HarmonyPatch("OpenApp")] public static void Postfix_StartupSound(HomescreenButton appToOpen, AppHomeScreen __instance) { if (Type.GetType("Reptile.Phone." + appToOpen.AssignedApp.AppName) == typeof(AppNetRadio) && AppNetRadio.HasSFX("start", AppNetRadio.currentSFXPack)) { ((App)__instance).m_AudioManager.audioSources[3].Stop(); AppNetRadio.PlaySFXFromPack("start", AppNetRadio.currentSFXPack); } } } [HarmonyPatch(typeof(MusicPlayerStatusPanel))] internal class MusicAppPanelPatches { [HarmonyPostfix] [HarmonyPatch("StatusIconUpdate")] public static void UpdateStatusIcon(MusicPlayerStatusPanel __instance) { //IL_0030: 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) //IL_0054: 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_007e: Unknown result type (might be due to invalid IL or missing references) if (NetRadio.GlobalRadio.playing) { __instance.m_StatusImage.sprite = __instance.m_StatusIcons[0]; float num = 1f; float num2 = 1f; Vector3 val = Vector3.one * (1f + NetRadio.GlobalRadio.streamSampleVolume * num - 0.5f * num); ((Transform)((Graphic)__instance.m_StatusImage).rectTransform).localScale = Vector3.Lerp(((Transform)((Graphic)__instance.m_StatusImage).rectTransform).localScale, val, 30f * num2 * Time.deltaTime); } } [HarmonyPostfix] [HarmonyPatch("ProgressbarUpdate")] public static void UpdateProgress(MusicPlayerStatusPanel __instance) { if (NetRadio.GlobalRadio.playing) { __instance.m_ProgressBar.fillAmount = NetRadio.GlobalRadio.streamSampleVolume; } } [HarmonyPostfix] [HarmonyPatch("OnNewTrack")] public static void OnNewTrack_RadioUpdate(MusicPlayerStatusPanel __instance) { if (!(__instance.m_CurrentTrack.Artist == NetRadio.GlobalRadio.GetStationTitle()) && NetRadio.GlobalRadio.playing) { NetRadio.UpdateCurrentSong(); } } } [HarmonyPatch(typeof(AppMusicPlayer))] internal class MusicAppPatches { [HarmonyPrefix] [HarmonyPatch("OnReleaseRight")] public static bool OnReleaseRight_ClearCurrent(AppMusicPlayer __instance) { if (NetRadio.GlobalRadio.playing && !__instance.shuffleControlSelected) { NetRadio.GlobalRadio.Stop(); __instance.m_StatusPanel.m_CurrentTrack = null; IMusicPlayer gameMusicPlayer = __instance.GameMusicPlayer; ((MusicPlayer)((gameMusicPlayer is MusicPlayer) ? gameMusicPlayer : null)).musicTrackQueue.currentTrackIndex = -1; ? val = __instance.m_StatusPanel; AUnlockable assignedContent = ((PhoneScrollUnlockableButton)/*isinst with value type is only supported in some contexts*/).AssignedContent; ((MusicPlayerStatusPanel)val).OnNewTrack((MusicTrack)(object)((assignedContent is MusicTrack) ? assignedContent : null)); } return true; } [HarmonyPostfix] [HarmonyPatch("OnAppEnable")] public static void OnEnable_Refresh() { NetRadio.UpdateCurrentSong(skipCheck: true); } } [HarmonyPatch(typeof(SimplePhoneButton))] internal class ButtonPatches { private static IEnumerable<MethodBase> TargetMethods() { Type type = typeof(SimplePhoneButton); yield return AccessTools.Method(type, "PlayHoldAnimation", (Type[])null, (Type[])null); yield return AccessTools.Method(type, "PlayHighlightAnimation", (Type[])null, (Type[])null); yield return AccessTools.Method(type, "PlayDeselectAnimation", (Type[])null, (Type[])null); yield return AccessTools.Method(type, "CacheResources", (Type[])null, (Type[])null); } public static void Postfix(SimplePhoneButton __instance) { //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: 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_0113: Unknown result type (might be due to invalid IL or missing references) if ((!(NetRadio.player.phone.m_CurrentApp is AppNetRadio) || !AppNetRadio.runPrefix) && !(NetRadio.player.phone.m_CurrentApp is AppSelectedStation)) { return; } if (NetRadio.IsHeaderButton(__instance)) { __instance.ButtonImage.sprite = AppNetRadio.BlankButtonSprite; } if (!NetRadio.IsStationButton(__instance)) { return; } Sprite sprite = __instance.ButtonImage.sprite; bool flag = (Object)(object)sprite == (Object)(object)__instance.SelectedButtonSprite; TextMeshProUGUI component = ((Component)((Component)__instance.Label).gameObject.transform.GetChild(0)).gameObject.GetComponent<TextMeshProUGUI>(); if (!((Object)(object)component == (Object)null)) { ((TMP_Text)component).faceColor = Color32.op_Implicit(flag ? __instance.LabelUnselectedColor : __instance.LabelSelectedColor); __instance.ButtonImage.sprite = (flag ? AppNetRadio.SelectedButtonSprite : AppNetRadio.UnselectedButtonSprite); GameObjectExtensions.RectTransform(((Component)__instance.ButtonImage).gameObject).sizeDelta = new Vector2(1104f, 304f); AppNetRadio.time = -1f; Image component2 = ((Component)((Component)__instance.Label).gameObject.transform.GetChild(2)).gameObject.GetComponent<Image>(); if ((Object)(object)component2 == (Object)null || ((Object)((Component)component2).gameObject).name.Contains("Logo")) { component2.sprite = AppNetRadio.GetStationLogo(((TMP_Text)__instance.Label).text, flag); } } } } } namespace NetRadio.Metadata { [Serializable] public class Icestats { public string admin; public string host; public string location; public string server_id; public string server_start; public string server_start_iso8601; [JsonConverter(typeof(SingleOrArrayConverter<Source>))] public List<Source> source; } [Serializable] public class IcecastStatus { public Icestats icestats; } [Serializable] public class Source { public string artist; public string audio_info; public int bitrate; public int channels; public string genre; public int listener_peak; public int listeners; public string listenurl; public int samplerate; public string server_description; public string server_name; public string server_type; public string stream_start; public string stream_start_iso8601; public string title; public object dummy; } public class SingleOrArrayConverter<T> : JsonConverter { public override bool CanWrite => false; public override bool CanConvert(Type objectType) { return objectType == typeof(List<T>); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 JToken val = JToken.Load(reader); if ((int)val.Type == 2) { return val.ToObject<List<T>>(); } if ((int)val.Type == 10) { return null; } return new List<T> { val.ToObject<T>() }; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } } } namespace NetRadio.Apps { public class AppNetRadio : NetRadioCustomApp { private static Sprite IconSprite = null; public const string appName = "NetRadio"; public static AppNetRadio Instance; private static bool justCleared = false; public static bool playing = false; public static bool runPrefix = true; private static VolumeSource tuningSource; private static FfmpegDecoder lastFfmpeg; private static BufferSource lastBuffer; public static DirectSoundOut waveOut; public static Sprite SelectedButtonSprite; public static Sprite UnselectedButtonSprite; public static List<Sprite> SelectedAntennaSprites = new List<Sprite>(); public static List<Sprite> UnselectedAntennaSprites = new List<Sprite>(); public static Dictionary<string, List<Sprite>> StationIcons = new Dictionary<string, List<Sprite>>(); public static List<Sprite> ConnectingSprites = new List<Sprite>(); public static Image connectIcon; public static Sprite BlankButtonSprite; public static float time = -1f; public static float realTime = 0f; public static List<int> urlWrapOffsets = new List<int>(); public static List<string> originalURLLabelText = new List<string>(); public static List<bool> urlIsTooLong = new List<bool>(); public static string dataDirectory = Path.Combine(NetRadioPlugin.Instance.Directory, "RadioApp-res/"); public const float urlOffsetX = 680f; public const float urlOffsetY = -80f; public const float titleOffsetX = 230f; public const float titleOffsetY = 50f; public const float arrowOffsetX = 40f; public const float arrowOffsetY = 80f; public const float discOffsetX = -260f; public const float discOffsetY = 0f; public const float stationOffsetX = 525f; public const float stationOffsetY = 27.5f; public const float stationLogoSize = 220f; public const float stationLogoOpacity = 0.5f; public const float iconSize = 400f; public const float iconOffsetX = 250f; public const float iconOffsetY = 170f; public static List<SimplePhoneButton> filteredButtons = new List<SimplePhoneButton>(); public static bool musicPlayerWasInterrupted = false; public static bool globalRadioWasInterrupted = false; public static int musicPlayerInterruptSamples = 0; public static PhoneButton lastSelectedButton; public static bool loaded = false; public static string currentNowPlayingText = "Now playing"; public static float currentNowPlayingHeight = 100f; public static float currentNowPlayingPosition = -475f; public static string currentSFXPack => Settings.sfxPack.Value.ToLower(); public static void Initialize() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown IconSprite = NetRadio.LoadSprite(Path.Combine(dataDirectory, "icon.png")); PhoneAPI.RegisterApp<AppNetRadio>("NetRadio", IconSprite); waveOut = new DirectSoundOut(NetRadio.waveOutLatency); SelectedButtonSprite = NetRadio.LoadSprite(Path.Combine(dataDirectory, "SimpleButton-Selected.png")); UnselectedButtonSprite = NetRadio.LoadSprite(Path.Combine(dataDirectory, "SimpleButton.png")); BlankButtonSprite = NetRadio.LoadSprite(Path.Combine(dataDirectory, "BlankButton.png")); string text = dataDirectory + "Antenna-"; string[] array = new string[2] { "Selected", "Unselected" }; foreach (string text2 in array) { for (int j = 0; j <= 3; j++) { string path = text + text2 + j + ".png"; Sprite item = NetRadio.LoadSprite(path); if (text2 == "Selected") { SelectedAntennaSprites.Add(item); } else { UnselectedAntennaSprites.Add(item); } } if (text2 == "Selected") { SelectedAntennaSprites.Add(NetRadio.LoadSprite(text + text2 + "2.png")); } else { UnselectedAntennaSprites.Add(NetRadio.LoadSprite(text + text2 + "2.png")); } } for (int k = 0; k <= 3; k++) { string path2 = dataDirectory + "Connecting" + (k + 1) + ".png"; ConnectingSprites.Add(NetRadio.LoadSprite(path2)); } string text3 = dataDirectory + "StationLogos/"; List<string> list = Directory.GetFiles(text3).ToList(); foreach (string item4 in list) { if (!item4.Contains("-Selected")) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(item4); Sprite item2 = NetRadio.LoadSprite(text3 + fileNameWithoutExtension + ".png"); Sprite item3 = NetRadio.LoadSprite(text3 + fileNameWithoutExtension + "-Selected.png"); List<Sprite> value = new List<Sprite> { item2, item3 }; StationIcons.Add(fileNameWithoutExtension, value); } } } public override void OnReleaseLeft() { ((App)this).MyPhone.ReturnToHome(); currentNowPlayingPosition = -475f; } public override void OnAppInit() { Instance = this; loaded = false; ((CustomApp)this).OnAppInit(); ((CustomApp)this).CreateTitleBar("NetRadio", IconSprite, 80f); ((CustomApp)this).ScrollView = PhoneScrollView.Create((CustomApp)(object)this, 275f, 1600f); AddURLButtons(); } public override void OnAppEnable() { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) Instance = this; if ((Object)(object)overlayInstance != (Object)null) { Object.Destroy((Object)(object)((Component)overlayInstance).gameObject); overlayInstance = null; } if (!NetRadio.GlobalRadio.threadRunning) { AddURLButtons(); } else { ((MonoBehaviour)this).StartCoroutine(Instance.ClearButtons()); } if ((Object)(object)connectIcon != (Object)null) { Object.Destroy((Object)(object)((Component)connectIcon).gameObject); } GameObject val = new GameObject("Connecting Icon"); connectIcon = val.AddComponent<Image>(); connectIcon.sprite = ConnectingSprites[0]; ((Component)connectIcon).transform.SetParent(((Component)((CustomApp)this).ScrollView).gameObject.transform.parent, false); ComponentExtensions.RectTransform((Component)(object)connectIcon).sizeDelta = new Vector2(400f, 400f); RectTransform obj = ComponentExtensions.RectTransform((Component)(object)connectIcon); ((Transform)obj).localPosition = ((Transform)obj).localPosition + new Vector3(250f, 170f, 0f); RectTransform obj2 = ComponentExtensions.RectTransform((Component)(object)connectIcon); ((Transform)obj2).localPosition = ((Transform)obj2).localPosition - new Vector3(200f, 200f, 0f); ((Behaviour)connectIcon).enabled = false; PhoneButton obj3 = ((CustomApp)this).ScrollView.Buttons[0]; ((Component)((SimplePhoneButton)((obj3 is SimplePhoneButton) ? obj3 : null)).Label).gameObject.transform.localPosition = new Vector3(currentNowPlayingPosition, 0f, 0f); ((App)this).OnAppEnable(); loaded = true; } public override void OnAppUpdate() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown if (!((CustomApp)this).ScrollView.Buttons.Any() || ((CustomApp)this).ScrollView.SelectedIndex < 0) { return; } if (NetRadio.IsHeaderButton((SimplePhoneButton)((CustomApp)this).ScrollView.Buttons[((CustomApp)this).ScrollView.SelectedIndex])) { ((App)this).m_AudioManager.audioSources[3].Stop(); int num = ((CustomApp)this).ScrollView.Buttons.IndexOf(lastSelectedButton); if (num < ((CustomApp)this).ScrollView.SelectedIndex) { ((CustomApp)this).ScrollView.OnPressUp(); } else { ((CustomApp)this).ScrollView.OnPressDown(); } } lastSelectedButton = ((CustomApp)this).ScrollView.Buttons[((CustomApp)this).ScrollView.SelectedIndex]; } public override void OnAppLateUpdate() { //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Expected O, but got Unknown //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Invalid comparison between Unknown and I4 if ((Object)(object)connectIcon != (Object)null) { ((Behaviour)connectIcon).enabled = !((CustomApp)this).ScrollView.Buttons.Any(); } if (!((CustomApp)this).ScrollView.Buttons.Any()) { if (!NetRadio.GlobalRadio.threadRunning && !justCleared && !NetRadio.GlobalRadio.failedToLoad) { ((MonoBehaviour)this).StartCoroutine(Instance.RestoreButtons()); justCleared = true; } if ((Object)(object)connectIcon != (Object)null) { float num = realTime * 5f % 3f; if ((Object)(object)connectIcon.sprite != (Object)(object)ConnectingSprites[3]) { connectIcon.sprite = ConnectingSprites[(int)num]; } } } if (tuningSource != null) { tuningSource.Volume = NetRadio.radioMusicVolume; } realTime += Time.deltaTime; foreach (SimplePhoneButton button in ((CustomApp)this).ScrollView.Buttons) { SimplePhoneButton val = button; if (!NetRadio.IsStationButton(val)) { filteredButtons.Remove(val); if (NetRadio.IsHeaderButton(val)) { if (((CustomApp)this).ScrollView.Buttons.IndexOf((PhoneButton)(object)val) == 0) { UpdateNowPlayingButton(val, ((CustomApp)this).ScrollView); } ((PhoneButton)val).PlayDeselectAnimation(true); continue; } if (((CustomApp)this).ScrollView.Buttons.IndexOf((PhoneButton)(object)val) == ((CustomApp)this).ScrollView.SelectedIndex) { time += Time.deltaTime; } if ((int)((Texture)val.ButtonImage.sprite.texture).wrapMode != 1) { ((Texture)val.ButtonImage.sprite.texture).wrapMode = (TextureWrapMode)1; } continue; } int num2 = filteredButtons.IndexOf(val); if ((Object)(object)val == (Object)null || num2 < 0 || num2 >= filteredButtons.Count) { continue; } bool flag = ((CustomApp)this).ScrollView.Buttons.IndexOf((PhoneButton)(object)val) == ((CustomApp)this).ScrollView.SelectedIndex; TextMeshProUGUI component = ((Component)((Component)val.Label).gameObject.transform.GetChild(0)).gameObject.GetComponent<TextMeshProUGUI>(); if ((Object)(object)component == (Object)null) { continue; } if (num2 >= urlWrapOffsets.Count) { urlWrapOffsets.Add(0); } if (flag && urlIsTooLong[num2]) { time += Time.deltaTime; if (time > 0.3f) { time = 0f; urlWrapOffsets[num2] += ((!(((TMP_Text)component).text.Substring(0, 1) == " ")) ? 1 : 2); } } else { urlWrapOffsets[num2] = 0; } if (num2 >= originalURLLabelText.Count) { originalURLLabelText.Add(((TMP_Text)component).text); } string text = originalURLLabelText[num2]; if (((TMP_Text)component).text == text && urlWrapOffsets[num2] > 3) { urlWrapOffsets[num2] = 0; time = -1f; } ((TMP_Text)component).text = text.Remove(0, urlWrapOffsets[num2]) + text.Substring(0, urlWrapOffsets[num2]); bool value = ((TMP_Text)component).fontSize <= ((TMP_Text)component).fontSizeMin; if (((TMP_Text)component).text == text) { urlIsTooLong[num2] = value; } Image component2 = ((Component)((Component)val.Label).gameObject.transform.GetChild(1)).gameObject.GetComponent<Image>(); if (!((Object)(object)component2 == (Object)null) && ((Object)((Component)component2).gameObject).name.Contains("Icon")) { bool flag2 = num2 == NetRadio.GlobalRadio.currentStation && NetRadio.GlobalRadio.playing; List<Sprite> list = (flag ? SelectedAntennaSprites : UnselectedAntennaSprites); float num3 = realTime * 5f % 4f; int index = (flag2 ? Mathf.Clamp((int)num3 + 1, 0, list.Count - 1) : 0); component2.sprite = list[index]; } } ((App)this).OnAppLateUpdate(); } public override void OnAppDisable() { loaded = false; if ((Object)(object)connectIcon != (Object)null) { Object.Destroy((Object)(object)((Component)connectIcon).gameObject); connectIcon = null; } ((App)this).OnAppDisable(); } private void AddURLButtons() { if (((CustomApp)this).ScrollView.Buttons.Count > 0) { return; } lastSelectedButton = null; realTime = 0f; filteredButtons.Clear(); SimplePhoneButton val = CreateHeaderButton(currentNowPlayingText, currentNowPlayingHeight, 10000f); ((CustomApp)this).ScrollView.AddButton((PhoneButton)(object)val); UpdateNowPlayingButton(val, ((CustomApp)this).ScrollView); int num = -1; int num2 = 0; foreach (string configURL in Settings.configURLs) { num++; string text = NetRadio.GlobalRadio.GetStationTitle(num); if (text == "NetRadio") { num2++; text = "Custom Station " + num2; } SimplePhoneButton nextButton = CreateStationButton(text, configURL); SimplePhoneButton obj = nextButton; ((PhoneButton)obj).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj).OnConfirm, (Action)delegate { if (!NetRadio.GlobalRadio.threadRunning) { if ((NetRadio.GlobalRadio.playing && filteredButtons.IndexOf(nextButton) == NetRadio.GlobalRadio.currentStation) || !Settings.configureRequireConnection.Value) { AppSelectedStation.currentStationIndex = filteredButtons.IndexOf(nextButton); ((App)this).MyPhone.OpenApp(typeof(AppSelectedStation)); } else { AttemptConnection(filteredButtons.IndexOf(nextButton)); } } }); ((CustomApp)this).ScrollView.AddButton((PhoneButton)(object)nextButton); filteredButtons.Add(nextButton); if (num >= urlIsTooLong.Count) { urlIsTooLong.Add(item: false); } else { urlIsTooLong[num] = false; } } if ((Object)(object)connectIcon != (Object)null) { connectIcon.sprite = ConnectingSprites[0]; ((Behaviour)connectIcon).enabled = false; } } private IEnumerator ClearButtons() { lastSelectedButton = null; realTime = 0f; justCleared = true; ((CustomApp)this).ScrollView.RemoveAllButtons(); CreateAndSaveIconlessTitleBar("Connecting..."); yield return (object)new WaitForSeconds(0.5f); justCleared = false; } public void ReloadButtons() { if (((CustomApp)this).ScrollView.Buttons.Any()) { ((CustomApp)this).ScrollView.RemoveAllButtons(); AddURLButtons(); } } private IEnumerator RestoreButtons() { yield return (object)new WaitForSeconds(0.5f); AddURLButtons(); if ((Object)(object)overlayInstance != (Object)null) { Object.Destroy((Object)(object)((Component)overlayInstance).gameObject); overlayInstance = null; } justCleared = false; waveOut.Stop(); playing = false; } public void AttemptConnection(int index) { musicPlayerWasInterrupted = NetRadio.musicPlayer.IsPlaying; if (musicPlayerWasInterrupted) { musicPlayerInterruptSamples = NetRadio.musicPlayer.CurrentTrackSamples; } globalRadioWasInterrupted = NetRadio.GlobalRadio.playing && !NetRadio.GlobalRadio.failedToLoad; NetRadio.musicPlayer.ForcePaused(); NetRadio.GlobalRadio.Play(index); PlayNoise(); ((MonoBehaviour)this).StartCoroutine(Instance.ClearButtons()); } public IEnumerator StopIn(float sec) { playing = false; if (sec > 0f) { yield return (object)new WaitForSeconds(sec); } waveOut.Stop(); } public IEnumerator HandleFailedConnection() { playing = false; waveOut.Stop(); PlaySFX("fail"); if ((Object)(object)overlayInstance != (Object)null) { Object.Destroy((Object)(object)((Component)overlayInstance).gameObject); overlayInstance = null; } CreateAndSaveIconlessTitleBar("Connection failed!"); if ((Object)(object)connectIcon != (Object)null) { connectIcon.sprite = ConnectingSprites[3]; } ResumePreviousMusic(includeSamples: true); yield return (object)new WaitForSeconds(1f); NetRadio.GlobalRadio.failedToLoad = false; } public static void ResumePreviousMusic(bool includeSamples = false) { if (Settings.restartMusic.Value) { int num = (includeSamples ? musicPlayerInterruptSamples : 0); if (musicPlayerWasInterrupted) { musicPlayerWasInterrupted = false; NetRadio.musicPlayer.PlayFrom(NetRadio.musicPlayer.CurrentTrackIndex, num); } else if (globalRadioWasInterrupted) { NetRadio.GlobalRadio.Play(NetRadio.GlobalRadio.previousStation); globalRadioWasInterrupted = false; } else { NetRadio.musicPlayer.PlayFrom(0, 0); } } } public static void PlayNoise() { PlaySFX("tuning", startedByPlayNoise: true); playing = true; } public static void PlaySFX(string sfxName, bool startedByPlayNoise = false) { PlaySFXFromPack(sfxName, currentSFXPack, startedByPlayNoise); } public static void PlaySFXFromPack(string sfxName, string sfxPack = "default", bool startedByPlayNoise = false) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown sfxPack = sfxPack.ToLower(); sfxName = sfxName.ToLower(); waveOut.Stop(); if (sfxName == "tuning" && !startedByPlayNoise) { PlayNoise(); return; } try { if (!HasSFX(sfxName, sfxPack, out var files)) { throw new ArgumentException("Sound effect does not exist"); } string text = files[0]; FfmpegDecoder val = new FfmpegDecoder(text); val.Position = 0L; int num = (int)Mathf.Round((float)val.WaveFormat.BytesPerSecond * 0.25f); BufferSource val2 = new BufferSource((IWaveSource)(object)val, num); VolumeSource val3 = new VolumeSource(WaveToSampleBase.CreateConverter((IWaveSource)(object)val2)); if (sfxName == "tuning") { tuningSource = val3; } val3.Volume = NetRadio.radioMusicVolume; waveOut.Initialize((IWaveSource)new SampleToIeeeFloat32((ISampleSource)(object)val3)); waveOut.Play(); if (lastFfmpeg != null) { ((WaveAggregatorBase)lastBuffer).Dispose(); lastFfmpeg.Dispose(); } lastFfmpeg = val; lastBuffer = val2; } catch (Exception ex) { if (sfxPack != "default") { NetRadio.Log.LogWarning((object)("Error playing app SFX (" + sfxName + " from pack " + sfxPack + "): " + ex.Message)); PlaySFXFromPack(sfxName, "default", startedByPlayNoise); } else { NetRadio.Log.LogError((object)("Error playing app SFX (" + sfxName + " from pack " + sfxPack + "): " + ex.Message)); NetRadio.Log.LogError((object)ex.StackTrace); } } } public static bool HasSFX(string sfxName, string sfxPack, out string[] files) { List<string> first = new List<string>(); List<string> second = new List<string>(); if (Directory.Exists(Path.Combine(NetRadio.customSFXpath, sfxPack + "/"))) { second = Directory.EnumerateFiles(Path.Combine(NetRadio.customSFXpath, sfxPack + "/"), sfxName + ".*").ToList(); } else if (Directory.Exists(Path.Combine(dataDirectory, "sfx/", sfxPack + "/"))) { first = Directory.EnumerateFiles(Path.Combine(dataDirectory, "sfx/", sfxPack + "/"), sfxName + ".*").ToList(); } files = first.Union(second).ToArray(); return files.Any(); } public static bool HasSFX(string sfxName, string sfxPack = "default") { string[] files; return HasSFX(sfxName, sfxPack, out files); } public static SimplePhoneButton CreateSimpleButton(string label) { return PhoneUIUtility.CreateSimpleButton(label); } public static SimplePhoneButton CreateHeaderButton(string label, float height = 100f, float width = 850f) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) runPrefix = false; SimplePhoneButton val = PhoneUIUtility.CreateSimpleButton(label); TextMeshProUGUI label2 = val.Label; GameObject val2 = new GameObject("Header"); val2.transform.SetParent(((Component)label2).gameObject.transform, false); GameObjectExtensions.RectTransform(((Component)val.ButtonImage).gameObject).sizeDelta = new Vector2(1060f, height); Transform transform = ((TMP_Text)label2).transform; transform.localPosition += new Vector3(-70f, 0f, 0f); GameObjectExtensions.RectTransform(((Component)val.Label).gameObject).sizeDelta = new Vector2(width, 100f); runPrefix = true; return val; } public static void UpdateNowPlayingButton(SimplePhoneButton button, PhoneScrollView scrollView, bool skipCheck = false) { //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: 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_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0264: 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_026d: Unknown result type (might be due to invalid IL or missing references) string text = ((TMP_Text)button.Label).text; if (!NetRadio.GlobalRadio.playing && !NetRadio.musicPlayer.IsPlaying) { ((TMP_Text)button.Label).text = ""; } else { string text2 = (NetRadio.GlobalRadio.playing ? NetRadio.GlobalRadio.currentSong : (NetRadio.musicPlayer.musicTrackQueue.CurrentMusicTrack.Artist + " - " + NetRadio.musicPlayer.musicTrackQueue.CurrentMusicTrack.Title)); ((TMP_Text)button.Label).text = "Now playing " + text2; if (NetRadio.GlobalRadio.playing) { ((TMP_Text)button.Label).text = NetRadio.GlobalRadio.GetStationTitle() + ": " + ((TMP_Text)button.Label).text; } ((TMP_Text)button.Label).alignment = (TextAlignmentOptions)514; } currentNowPlayingText = ((TMP_Text)button.Label).text; if (GameObjectExtensions.RectTransform(((Component)button.Label).gameObject).sizeDelta.x >= 10000f) { Transform transform = ((Component)button.Label).gameObject.transform; transform.localPosition -= new Vector3(Core.dt * 60f * 4f, 0f, 0f); ((TMP_Text)button.Label).alignment = (TextAlignmentOptions)513; ((TMP_Text)button.Label).text = " " + ((TMP_Text)button.Label).text; if (!string.IsNullOrWhiteSpace(((TMP_Text)button.Label).text)) { Bounds textBounds = ((TMP_Text)button.Label).textBounds; if (((Bounds)(ref textBounds)).size.x > 0f) { float x = ((Component)button.Label).gameObject.transform.localPosition.x; textBounds = ((TMP_Text)button.Label).textBounds; if (x <= -475f - ((Bounds)(ref textBounds)).size.x - 1200f) { ((Component)button.Label).gameObject.transform.localPosition = new Vector3(-475f, 0f, 0f); ManualLogSource log = NetRadio.Log; textBounds = ((TMP_Text)button.Label).textBounds; log.LogError((object)((Bounds)(ref textBounds)).size.x); } } } } UpdateDynamicButtonHeight(button, scrollView, skipCheck); if (GameObjectExtensions.RectTransform(((Component)button.ButtonImage).gameObject).sizeDelta.y > 0f) { currentNowPlayingHeight = ((PhoneButton)button).Height; } currentNowPlayingPosition = ((Component)button.Label).gameObject.transform.localPosition.x; } public static void UpdateDynamicButtonHeight(SimplePhoneButton button, PhoneScrollView scrollView, bool skipCheck = false) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) RectTransform val = GameObjectExtensions.RectTransform(((Component)button.ButtonImage).gameObject); float y = val.sizeDelta.y; float x = val.sizeDelta.x; float num = ((TMP_Text)button.Label).fontSizeMin * (float)((TMP_Text)button.Label).textInfo.lineCount; if (num == 0f) { num -= scrollView.Separation; } val.sizeDelta = new Vector2(x, num); if (num != y && !skipCheck) { scrollView.UpdateButtons(); } } private static SimplePhoneButton CreateStationButton(string label, string url) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_00d5: 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_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0193: 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_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: 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_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Expected O, but got Unknown //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_026c: 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_0283: Expected O, but got Unknown //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) runPrefix = false; SimplePhoneButton val = PhoneUIUtility.CreateSimpleButton(label); Transform val2 = ((Component)val).gameObject.transform.Find("Animation Parent"); url = NetRadio.StandardizeURL(url); url += " "; GameObject val3 = new GameObject("URLLabel"); TextMeshProUGUI val4 = val3.AddComponent<TextMeshProUGUI>(); ((TMP_Text)val4).text = url; ((TMP_Text)val4).alignment = (TextAlignmentOptions)513; ((TMP_Text)val4).font = AppUtility.GetAppFont(); ((TMP_Text)val4).fontSize = 55f; ((TMP_Text)val4).fontSizeMax = 55f; ((TMP_Text)val4).fontSizeMin = 50f; ((TMP_Text)val4).enableAutoSizing = true; ((TMP_Text)val4).enableWordWrapping = false; TextMeshProUGUI label2 = val.Label; val3.transform.SetParent(((Component)label2).gameObject.transform, false); val3.transform.localPosition = new Vector3(680f, -80f, 0f); RectTransform val5 = GameObjectExtensions.RectTransform(val3); RectTransformExtensions.SetAnchorAndPivot(val5, 0f, 0.5f); val5.sizeDelta = new Vector2(850f, 100f); Vector3 val6 = default(Vector3); ((Vector3)(ref val6))..ctor(230f, 50f, 0f); Transform transform = ((TMP_Text)label2).transform; transform.localPosition += val6; Transform transform2 = val3.transform; transform2.localPosition -= val6; val5.sizeDelta -= new Vector2(135f, 0f); RectTransform obj = ComponentExtensions.RectTransform((Component)(object)label2); obj.sizeDelta -= new Vector2(180f, 0f); RectTransform obj2 = GameObjectExtensions.RectTransform(val.ConfirmArrow); ((Transform)obj2).localPosition = ((Transform)obj2).localPosition + new Vector3(40f, -9999f, 0f); GameObject val7 = new GameObject("Station Icon"); Image val8 = val7.AddComponent<Image>(); val7.transform.SetParent(((Component)label2).gameObject.transform, false); RectTransform obj3 = GameObjectExtensions.RectTransform(val7); ((Transform)obj3).localPosition = ((Transform)obj3).localPosition - val6; val8.sprite = UnselectedAntennaSprites[0]; GameObjectExtensions.RectTransform(val7).sizeDelta = new Vector2(280f, 280f); RectTransform obj4 = GameObjectExtensions.RectTransform(val7); ((Transform)obj4).localPosition = ((Transform)obj4).localPosition + new Vector3(-260f, 0f, 0f); GameObject val9 = new GameObject("Station Logo"); Image val10 = val9.AddComponent<Image>(); val9.transform.SetParent(((Component)label2).gameObject.transform, false); RectTransform obj5 = GameObjectExtensions.RectTransform(val9); ((Transform)obj5).localPosition = ((Transform)obj5).localPosition - val6; val10.sprite = GetStationLogo(label, selected: false); GameObjectExtensions.RectTransform(val9).sizeDelta = new Vector2(220f, 220f); RectTransform obj6 = GameObjectExtensions.RectTransform(val9); ((Transform)obj6).localPosition = ((Transform)obj6).localPosition + new Vector3(525f, 27.5f, 0f); Color color = ((Graphic)val10).color; color.a = 0.5f; ((Graphic)val10).color = color; runPrefix = true; return val; } public static Sprite GetStationLogo(string requestedStation, bool selected) { int index = (selected ? 1 : 0); string key = (StationIcons.ContainsKey(requestedStation) ? requestedStation : "Custom"); return StationIcons[key][index]; } } public class AppSelectedStation : NetRadioCustomApp { public static AppSelectedStation Instance; public static PhoneButton lastSelectedButton; public static int currentStationIndex; public static float time = 0f; public static bool justCopied = false; public static bool justFailedCopy = false; public static int volumeInPercent = 100; public static readonly string[] metadataModeDisplay = new string[3] { "Disabled", "Enabled", "Alternate" }; public static int currentMetadataMode = 1; public static int metadataOffsetInMS = 0; public static bool changingVolume = false; public static bool changingMetadataMode = false; public static bool changingMetadataOffset = false; public static List<Sprite> MetadataIcons = new List<Sprite>(); public static bool changingAny { get { return changingVolume || changingMetadataMode || changingMetadataOffset; } set { changingVolume = false; changingMetadataMode = false; changingMetadataOffset = false; } } public override bool Available => false; public static string urlForCurrent => NetRadio.StandardizeURL(Settings.configURLs[currentStationIndex]); public static bool isStation => NetRadio.GlobalRadio.playing && NetRadio.GlobalRadio.currentStation == currentStationIndex; public static void Initialize() { PhoneAPI.RegisterApp<AppSelectedStation>("selected station", (Sprite)null); MetadataIcons.Clear(); MetadataIcons.Add(NetRadio.LoadSprite(Path.Combine(AppNetRadio.dataDirectory, "Metadata-Listeners.png"))); MetadataIcons.Add(NetRadio.LoadSprite(Path.Combine(AppNetRadio.dataDirectory, "Metadata-Peak.png"))); MetadataIcons.Add(NetRadio.LoadSprite(Path.Combine(AppNetRadio.dataDirectory, "Metadata-Location.png"))); } public void SetVariables() { float num = (SaveData.stationSettingsByURL.ContainsKey(urlForCurrent) ? ((float)SaveData.stationSettingsByURL[urlForCurrent].volume) : 1f); float num2 = num * 100f; volumeInPercent = 5 * (int)Math.Round((double)num2 / 5.0); currentMetadataMode = ((!SaveData.stationSettingsByURL.ContainsKey(urlForCurrent)) ? 1 : SaveData.stationSettingsByURL[urlForCurrent].metadataMode); metadataOffsetInMS = (SaveData.stationSettingsByURL.ContainsKey(urlForCurrent) ? ((int)(SaveData.stationSettingsByURL[urlForCurrent].metadataTimeOffsetSeconds * 1000m)) : 0); } public override void OnAppInit() { //IL_007c: Unknown result type (might be due to invalid IL or missing references) ((CustomApp)this).OnAppInit(); Instance = this; ((CustomApp)this).ScrollView = PhoneScrollView.Create((CustomApp)(object)this, 275f, 1600f); SimplePhoneButton val = AppNetRadio.CreateHeaderButton(AppNetRadio.currentNowPlayingText, 70f, 10000f); ((CustomApp)this).ScrollView.AddButton((PhoneButton)(object)val); AppNetRadio.UpdateNowPlayingButton(val, ((CustomApp)this).ScrollView); ((CustomApp)this).ScrollView.AddButton((PhoneButton)(object)CreateMetadataStack()); SimplePhoneButton val2 = AppNetRadio.CreateHeaderButton("Genre: ", 75f); SetLabelColor(val2, Color.clear); ((CustomApp)this).ScrollView.AddButton((PhoneButton)(object)val2); AddUsualButtons(); } public override void OnAppUpdate() { //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Expected O, but got Unknown //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_037d: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) time += Time.deltaTime; if (justCopied && (double)time > 1.0) { justCopied = false; } if (((CustomApp)this).ScrollView.Buttons.Any() && ((CustomApp)this).ScrollView.SelectedIndex >= 0) { if (NetRadio.IsHeaderButton((SimplePhoneButton)((CustomApp)this).ScrollView.Buttons[((CustomApp)this).ScrollView.SelectedIndex])) { ((App)this).m_AudioManager.audioSources[3].Stop(); int num = ((CustomApp)this).ScrollView.Buttons.IndexOf(lastSelectedButton); if (num < ((CustomApp)this).ScrollView.SelectedIndex) { ((CustomApp)this).ScrollView.OnPressUp(); } else { ((CustomApp)this).ScrollView.OnPressDown(); } } lastSelectedButton = ((CustomApp)this).ScrollView.Buttons[((CustomApp)this).ScrollView.SelectedIndex]; } foreach (SimplePhoneButton button in ((CustomApp)this).ScrollView.Buttons) { SimplePhoneButton val = button; if (NetRadio.IsHeaderButton(val)) { if (((CustomApp)this).ScrollView.Buttons.IndexOf((PhoneButton)(object)val) == 0) { AppNetRadio.UpdateNowPlayingButton(val, ((CustomApp)this).ScrollView); } if (((CustomApp)this).ScrollView.Buttons.IndexOf((PhoneButton)(object)val) > 1) { AppNetRadio.UpdateDynamicButtonHeight(val, ((CustomApp)this).ScrollView); } ((PhoneButton)val).PlayDeselectAnimation(true); } else if (((TMP_Text)val.Label).text.EndsWith("nnect...")) { ((TMP_Text)val.Label).text = (isStation ? "Disconnect..." : "Connect..."); } else if (((TMP_Text)val.Label).text.Contains("Volume:")) { ((TMP_Text)val.Label).text = "Volume: " + volumeInPercent + "%"; SetLabelColor(val, changingVolume ? Color.green : Color.white); } else if (((TMP_Text)val.Label).text.Contains("Metadata:")) { ((TMP_Text)val.Label).text = "Metadata: " + metadataModeDisplay[currentMetadataMode]; SetLabelColor(val, changingMetadataMode ? Color.green : Color.white); } else if (((TMP_Text)val.Label).text.Contains("Metadata offset:")) { ((TMP_Text)val.Label).text = "Metadata offset: +" + metadataOffsetInMS + "ms"; SetLabelColor(val, changingMetadataOffset ? Color.green : Color.white); } else if (((TMP_Text)val.Label).text.Contains("clipboard")) { ((TMP_Text)val.Label).text = (justFailedCopy ? "Copy to clipboard failed!" : (justCopied ? "Copied to clipboard!" : "Copy URL to clipboard")); SetLabelColor(val, justFailedCopy ? Color.red : (justCopied ? Color.green : Color.white)); } } if (changingVolume) { string key = NetRadio.StandardizeURL(Settings.configURLs[currentStationIndex]); decimal volume = (decimal)volumeInPercent / 100m; if (SaveData.stationSettingsByURL.ContainsKey(key)) { SaveData.stationSettingsByURL[key].volume = volume; return; } StationSettings stationSettings = new StationSettings(); stationSettings.volume = volume; SaveData.stationSettingsByURL.Add(key, stationSettings); } else if (changingMetadataMode) { string key2 = NetRadio.StandardizeURL(Settings.configURLs[currentStationIndex]); int metadataMode = currentMetadataMode; if (SaveData.stationSettingsByURL.ContainsKey(key2)) { SaveData.stationSettingsByURL[key2].metadataMode = metadataMode; return; } StationSettings stationSettings2 = new StationSettings(); stationSettings2.metadataMode = metadataMode; SaveData.stationSettingsByURL.Add(key2, stationSettings2); } else if (changingMetadataOffset) { string key3 = NetRadio.StandardizeURL(Settings.configURLs[currentStationIndex]); decimal metadataTimeOffsetSeconds = (decimal)metadataOffsetInMS * 0.001m; if (SaveData.stationSettingsByURL.ContainsKey(key3)) { SaveData.stationSettingsByURL[key3].metadataTimeOffsetSeconds = metadataTimeOffsetSeconds; return; } StationSettings stationSettings3 = new StationSettings(); stationSettings3.metadataTimeOffsetSeconds = metadataTimeOffsetSeconds; SaveData.stationSettingsByURL.Add(key3, stationSettings3); } } public override void OnAppEnable() { //IL_0086: Unknown result type (might be due to invalid IL or missing references) lastSelectedButton = null; CreateAndSaveTitleBar(NetRadio.GlobalRadio.GetStationTitle(currentStationIndex), AppNetRadio.UnselectedAntennaSprites[2]); justCopied = false; changingAny = false; time = 0f; SetVariables(); GetStationMetadata(); PhoneButton obj = ((CustomApp)this).ScrollView.Buttons[0]; ((Component)((SimplePhoneButton)((obj is SimplePhoneButton) ? obj : null)).Label).gameObject.transform.localPosition = new Vector3(AppNetRadio.currentNowPlayingPosition, 0f, 0f); ((App)this).OnAppEnable(); } public override void OnAppDisable() { ((App)this).OnAppDisable(); Object.Destroy((Object)(object)((Component)overlayInstance).gameObject); justCopied = false; changingAny = false; time = 0f; ((CustomSaveData)SaveData.Instance).Save(); } public override void OnPressUp() { if (changingVolume) { volumeInPercent = Mathf.Clamp(volumeInPercent + 5, 0, 200); } else if (changingMetadataMode) { currentMetadataMode = ((currentMetadataMode != 1) ? 1 : 0); UpdateGlobalRadioMetaMode(); } else if (changingMetadataOffset) { metadataOffsetInMS = Mathf.Clamp(metadataOffsetInMS + 250, 0, 99000); } if (!changingAny) { base.OnPressUp(); } else { ((CustomApp)this).PlaySelectSFX(); } } public override void OnPressDown() { if (changingVolume) { volumeInPercent = Mathf.Clamp(volumeInPercent - 5, 0, 200); } else if (changingMetadataMode) { currentMetadataMode = ((currentMetadataMode != 1) ? 1 : 0); UpdateGlobalRadioMetaMode(); } else if (changingMetadataOffset) { metadataOffsetInMS = Mathf.Clamp(metadataOffsetInMS - 250, 0, 99000); } if (!changingAny) { base.OnPressDown(); } else { ((CustomApp)this).PlaySelectSFX(); } } public override void OnHoldUp() { if (!changingAny) { ((CustomApp)this).OnHoldUp(); } } public override void OnHoldDown() { if (!changingAny) { ((CustomApp)this).OnHoldDown(); } } public void AddUsualButtons() { SetVariables(); SimplePhoneButton val = PhoneUIUtility.CreateSimpleButton(isStation ? "Disconnect..." : "Connect..."); ((PhoneButton)val).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val).OnConfirm, (Action)delegate { NetRadio.GlobalRadio.ResetMetadata(); if (NetRadio.GlobalRadio.playing && NetRadio.GlobalRadio.currentStation == currentStationIndex) { NetRadio.GlobalRadio.Stop(); AppNetRadio.PlaySFX("disconnect"); AppNetRadio.globalRadioWasInterrupted = false; AppNetRadio.ResumePreviousMusic(); ((App)this).MyPhone.OpenApp(typeof(AppNetRadio)); } else { ((MonoBehaviour)this).StartCoroutine(Instance.ConnectToStation()); } }); ((CustomApp)this).ScrollView.AddButton((PhoneButton)(object)val); SimplePhoneButton val2 = PhoneUIUtility.CreateSimpleButton("Volume: "); SimplePhoneButton obj = val2; ((PhoneButton)obj).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj).OnConfirm, (Action)delegate { changingVolume = !changingVolume; }); ((CustomApp)this).ScrollView.AddButton((PhoneButton)(object)val2); val2 = PhoneUIUtility.CreateSimpleButton("Metadata: "); SimplePhoneButton obj2 = val2; ((PhoneButton)obj2).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj2).OnConfirm, (Action)delegate { changingMetadataMode = !changingMetadataMode; }); ((CustomApp)this).ScrollView.AddButton((PhoneButton)(object)val2); val2 = PhoneUIUtility.CreateSimpleButton("Metadata offset: "); SimplePhoneButton obj3 = val2; ((PhoneButton)obj3).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj3).OnConfirm, (Action)delegate { changingMetadataOffset = !changingMetadataOffset; }); ((CustomApp)this).ScrollView.AddButton((PhoneButton)(object)val2); val2 = PhoneUIUtility.CreateSimpleButton("Copy URL to clipboard"); SimplePhoneButton obj4 = val2; ((PhoneButton)obj4).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj4).OnConfirm, (Action)delegate { time = 0f; try { GUIUtility.systemCopyBuffer = Settings.configURLs[currentStationIndex]; justCopied = true; } catch (Exception ex) { NetRadio.Log.LogError((object)("Error copying to clipboard: " + ex.Message)); NetRadio.Log.LogError((object)ex.StackTrace); justFailedCopy = true; } }); ((CustomApp)this).ScrollView.AddButton((PhoneButton)(object)val2); } public IEnumerator ConnectToStation() { int station = currentStationIndex; AppNetRadio.loaded = false; ((App)this).MyPhone.OpenApp(typeof(AppNetRadio)); while (!AppNetRadio.loaded) { yield return null; } AppNetRadio.Instance.AttemptConnection(station); } public async Task GetStationMetadata() { SimplePhoneButton metadataStack = GetMetadataStack(); foreach (Transform item in ((Component)metadataStack).transform) { Transform child = item; ((Component)child).gameObject.SetActive(false); } foreach (SimplePhoneButton button2 in ((CustomApp)this).ScrollView.Buttons) { SimplePhoneButton button = button2; if (NetRadio.IsHeaderButton(button) && ((TMP_Text)button.Label).text.Contains("Genre:")) { ((TMP_Text)button.Label).text = "Genre: "; SetLabelColor(button, Color.clear); } } if (!SaveData.stationSettingsByURL.ContainsKey(urlForCurrent) || SaveData.stationSettingsByURL[urlForCurrent].metadataMode != 0) { await Task.Delay(200); IcecastStatus icecastStatus = ((NetRadio.GlobalRadio.playing && NetRadio.GlobalRadio.currentStation == currentStationIndex) ? NetRadio.GlobalRadio.currentMetadata : (await NetRadio.GlobalRadio.GetMetadata(NetRadio.GlobalRadio.streamURLs[currentStationIndex]))); IcecastStatus currentInfo = icecastStatus; if (currentInfo != null) { UpdateStationMetadata(currentInfo); } } } public void UpdateStationMetadata(IcecastStatus stationStatus) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_0132: Unknown result type (might be due to invalid IL or missing references) Source source = NetRadio.GetSource(stationStatus, urlForCurrent); SimplePhoneButton metadataStack = GetMetadataStack(); foreach (Transform item in ((Component)metadataStack).transform) { Transform val = item; ((Component)val).gameObject.SetActive(true); } ((TMP_Text)((Component)((Component)metadataStack).transform.GetChild(1)).GetComponentInChildren<TextMeshProUGUI>()).text = NetRadio.ShortenNumber(source.listeners); ((TMP_Text)((Component)((Component)metadataStack).transform.GetChild(2)).GetComponentInChildren<TextMeshProUGUI>()).text = NetRadio.ShortenNumber(source.listener_peak); ((TMP_Text)((Component)((Component)metadataStack).transform.GetChild(3)).GetComponentInChildren<TextMeshProUGUI>()).text = stationStatus.icestats.location; foreach (SimplePhoneButton button in ((CustomApp)this).ScrollView.Buttons) { SimplePhoneButton val2 = button; if (NetRadio.IsHeaderButton(val2) && ((TMP_Text)val2.Label).text.Contains("Genre:")) { ((TMP_Text)val2.Label).text = "Genre: " + source.genre; SetLabelColor(val2, Color.white); } } } public void SetLabelColor(SimplePhoneButton nextButton, Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result t