using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using BepInEx;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using UnityEngine;
using sPEAKer.Scripts;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SpotifyModule")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Spotify Module for PEAK")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("SpotifyModule")]
[assembly: AssemblyTitle("SpotifyModule")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[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 SpotifyModule
{
[BepInPlugin("com.blockbyblock.SpotifyModule", "SpotifyModule", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class SpotifyPlugin : BaseUnityPlugin
{
internal static ManualLogSource Log;
private LibrespotController _librespot;
private AudioClip _streamingClip;
private float _updateTimer = 0f;
private bool _lastIsPlaying = false;
private bool _isBuffering = true;
private const int MinBufferSamples = 8820;
private void Awake()
{
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string text = Path.Combine(directoryName, "librespot.exe");
if (File.Exists(text))
{
_librespot = new LibrespotController(text, directoryName);
_streamingClip = AudioClip.Create("SpotifyStream", 44100, 2, 44100, true, new PCMReaderCallback(OnAudioRead));
_librespot.Start();
}
}
private void Update()
{
_updateTimer += Time.deltaTime;
if (_updateTimer >= 0.1f)
{
_updateTimer = 0f;
MonitorAndSync();
}
}
private void MonitorAndSync()
{
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Invalid comparison between Unknown and I4
if (_librespot == null || !((Object)(object)AudioMaster.MixtapeAudioSource != (Object)null))
{
return;
}
bool flag = false;
if (AudioMaster.LoadedAudioClips != null && AudioMaster.CurrentSongIndex >= 0 && AudioMaster.LoadedAudioClips.Count > AudioMaster.CurrentSongIndex)
{
AudioClip val = AudioMaster.LoadedAudioClips[AudioMaster.CurrentSongIndex];
if ((Object)(object)val != (Object)null && (((Object)val).name.Contains("Spotify Stream") || ((Object)val).name.Contains("SpotifyStream")))
{
flag = true;
}
}
bool flag2 = AudioMaster.MixtapeAudioSource.isPlaying && flag;
if (flag && (Object)(object)AudioMaster.MixtapeAudioSource.clip != (Object)(object)_streamingClip)
{
try
{
AudioMaster.MixtapeAudioSource.clip = _streamingClip;
AudioMaster.MixtapeAudioSource.loop = true;
if ((int)AudioMaster.CurrentPlaybackState == 1 && !AudioMaster.MixtapeAudioSource.isPlaying)
{
AudioMaster.MixtapeAudioSource.Play();
}
}
catch (Exception ex)
{
Log.LogError((object)ex.Message);
}
}
if (flag2 != _lastIsPlaying)
{
_lastIsPlaying = flag2;
if (!flag2)
{
_isBuffering = true;
}
}
}
private void OnAudioRead(float[] data)
{
if (_librespot == null)
{
Array.Clear(data, 0, data.Length);
return;
}
if (_isBuffering)
{
if (_librespot.AudioQueue.Count < 8820)
{
Array.Clear(data, 0, data.Length);
return;
}
_isBuffering = false;
}
for (int i = 0; i < data.Length; i++)
{
if (_librespot.AudioQueue.TryDequeue(out var result))
{
data[i] = result;
continue;
}
_isBuffering = true;
for (int j = i; j < data.Length; j++)
{
data[j] = 0f;
}
break;
}
}
private void OnDestroy()
{
if (_librespot != null)
{
_librespot.Stop();
}
}
}
public class LibrespotController
{
private Process _librespotProcess;
private Thread _readThread;
private bool _isRunning;
public ConcurrentQueue<float> AudioQueue = new ConcurrentQueue<float>();
private string _exePath;
private string _workingDir;
public LibrespotController(string exePath, string workingDir)
{
_exePath = exePath;
_workingDir = workingDir;
}
public void Start()
{
if (_isRunning)
{
return;
}
_isRunning = true;
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = _exePath,
Arguments = "--name \"sPEAKer\" --backend pipe --initial-volume 100 --enable-volume-normalisation",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
CreateNoWindow = true,
WorkingDirectory = _workingDir
};
try
{
_librespotProcess = new Process();
_librespotProcess.StartInfo = startInfo;
_librespotProcess.ErrorDataReceived += delegate
{
};
_librespotProcess.Start();
_librespotProcess.BeginErrorReadLine();
_readThread = new Thread(ReadAudioStream)
{
IsBackground = true
};
_readThread.Start();
}
catch (Exception ex)
{
SpotifyPlugin.Log.LogError((object)ex.Message);
_isRunning = false;
}
}
public void SendControlCommand(string command)
{
if (_librespotProcess != null && !_librespotProcess.HasExited)
{
try
{
_librespotProcess.StandardInput.WriteLine(command);
_librespotProcess.StandardInput.Flush();
}
catch (Exception ex)
{
SpotifyPlugin.Log.LogWarning((object)ex.Message);
}
}
}
private void ReadAudioStream()
{
try
{
using Stream stream = _librespotProcess.StandardOutput.BaseStream;
byte[] array = new byte[4096];
int num = 0;
while (_isRunning && _librespotProcess != null && !_librespotProcess.HasExited)
{
if (AudioQueue.Count > 176400)
{
Thread.Sleep(50);
continue;
}
int count = array.Length - num;
int num2 = stream.Read(array, num, count);
if (num2 <= 0)
{
Thread.Sleep(10);
continue;
}
int num3 = num + num2;
int i;
for (i = 0; i + 1 < num3; i += 2)
{
short num4 = (short)(array[i] | (array[i + 1] << 8));
float item = (float)num4 / 32768f;
AudioQueue.Enqueue(item);
}
num = num3 - i;
if (num > 0)
{
array[0] = array[i];
}
}
}
catch (Exception ex)
{
SpotifyPlugin.Log.LogError((object)ex.Message);
}
}
public void Stop()
{
_isRunning = false;
if (_librespotProcess != null && !_librespotProcess.HasExited)
{
try
{
_librespotProcess.Kill();
}
catch
{
}
}
_librespotProcess = null;
_readThread = null;
}
}
}