using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Timers;
using SpotifyAPI.Local.Models;
namespace SpotifyAPI.Local
{
public class SpotifyLocalAPI
{
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
[DllImport("nircmd.dll")]
private static extern bool DoNirCmd(String nirCmdStr);
private bool _listenForEvents;
public bool ListenForEvents
{
get
{
return _listenForEvents;
}
set
{
_listenForEvents = value;
_eventTimer.Enabled = value;
}
}
private ISynchronizeInvoke _synchronizingObject;
public ISynchronizeInvoke SynchronizingObject
{
get
{
return _synchronizingObject;
}
set
{
_synchronizingObject = value;
_eventTimer.SynchronizingObject = value;
}
}
const byte VkMediaNextTrack = 0xb0;
const byte VkMediaPrevTrack = 0xb1;
const int KeyeventfExtendedkey = 0x1;
const int KeyeventfKeyup = 0x2;
readonly RemoteHandler _rh;
private readonly Timer _eventTimer;
private StatusResponse _eventStatusResponse;
public delegate void TrackChangeEventHandler(TrackChangeEventArgs e);
public delegate void PlayStateEventHandler(PlayStateEventArgs e);
public delegate void VolumeChangeEventHandler(VolumeChangeEventArgs e);
public delegate void TrackTimeChangeEventHandler(TrackTimeChangeEventArgs e);
public event TrackChangeEventHandler OnTrackChange;
public event PlayStateEventHandler OnPlayStateChange;
public event VolumeChangeEventHandler OnVolumeChange;
public event TrackTimeChangeEventHandler OnTrackTimeChange;
public SpotifyLocalAPI()
{
_rh = new RemoteHandler();
_eventTimer = new Timer
{
Interval = 50,
AutoReset = false,
Enabled = false
};
_eventTimer.Elapsed += ElapsedTick;
}
private void ElapsedTick(object sender, ElapsedEventArgs e)
{
if (_eventStatusResponse == null)
{
_eventStatusResponse = GetStatus();
_eventTimer.Start();
return;
}
StatusResponse newStatusResponse = GetStatus();
if (newStatusResponse == null)
{
_eventTimer.Start();
return;
}
if (!newStatusResponse.Running && newStatusResponse.Track == null)
{
_eventTimer.Start();
return;
}
if (newStatusResponse.Track != null && _eventStatusResponse.Track != null)
{
if (newStatusResponse.Track.TrackResource.Name != _eventStatusResponse.Track.TrackResource.Name && OnTrackChange != null)
{
OnTrackChange(new TrackChangeEventArgs()
{
OldTrack = _eventStatusResponse.Track,
NewTrack = newStatusResponse.Track
});
}
}
if (newStatusResponse.Playing != _eventStatusResponse.Playing && OnPlayStateChange != null)
{
OnPlayStateChange(new PlayStateEventArgs()
{
Playing = newStatusResponse.Playing
});
}
if (newStatusResponse.Volume != _eventStatusResponse.Volume && OnVolumeChange != null)
{
OnVolumeChange(new VolumeChangeEventArgs()
{
OldVolume = _eventStatusResponse.Volume,
NewVolume = newStatusResponse.Volume
});
}
if (newStatusResponse.PlayingPosition != _eventStatusResponse.PlayingPosition && OnTrackTimeChange != null)
{
OnTrackTimeChange(new TrackTimeChangeEventArgs()
{
TrackTime = newStatusResponse.PlayingPosition
});
}
_eventStatusResponse = newStatusResponse;
_eventTimer.Start();
}
///
/// Connects with Spotify. Needs to be called before all other SpotifyAPI functions
///
/// Returns true, if it was successful, false if not
public Boolean Connect()
{
return _rh.Init();
}
public StatusResponse GetStatus()
{
return _rh.GetNewStatus();
}
public void Mute()
{
if (File.Exists("nircmd.dll"))
DoNirCmd("muteappvolume spotify.exe 1");
}
///
/// Unmutes Spotify (Requires nircmd.dll)
///
public void UnMute()
{
if (File.Exists("nircmd.dll"))
DoNirCmd("muteappvolume spotify.exe 0");
}
///
/// Pause function
///
public void Pause()
{
_rh.SendPauseRequest();
}
///
/// Play function
///
public void Play()
{
_rh.SendPlayRequest();
}
///
/// Simulates a KeyPress
///
/// The keycode for the represented Key
internal void PressKey(byte keyCode)
{
keybd_event(keyCode, 0x45, KeyeventfExtendedkey, 0);
keybd_event(keyCode, 0x45, KeyeventfExtendedkey | KeyeventfKeyup, 0);
}
///
/// Plays a Spotify URI within an optional context.
///
/// The Spotify URI
/// The context in which to play the specified .
///
/// Contexts are basically a queue in spotify. a song can be played within a context, meaning that hitting next / previous would lead to another song. Contexts are leveraged by widgets as described in the "Multiple tracks player" section of the following documentation page: https://developer.spotify.com/technologies/widgets/spotify-play-button/
///
public void PlayURL(String uri, String context = "")
{
_rh.SendPlayRequest(uri, context);
}
///
/// Adds a Spotify URI to the Queue
///
/// The Spotify URI
[Obsolete("This method doesn't work with the current spotify version.")]
public void AddToQueue(String uri)
{
_rh.SendQueueRequest(uri);
}
///
/// Skips the current song (Using keypress simulation)
///
public void Skip()
{
PressKey(VkMediaNextTrack);
}
///
/// Emulates the "Previous" Key (Using keypress simulation)
///
public void Previous()
{
PressKey(VkMediaPrevTrack);
}
///
/// Checks if Spotify is running
///
/// True, if it's running, false if not
public static Boolean IsSpotifyRunning()
{
return Process.GetProcessesByName("spotify").Length >= 1;
}
///
/// Checks if Spotify's WebHelper is running (Needed for API Calls)
///
/// True, if it's running, false if not
public static Boolean IsSpotifyWebHelperRunning()
{
return Process.GetProcessesByName("spotifywebhelper").Length >= 1;
}
///
/// Runs Spotify
///
public static void RunSpotify()
{
if (!IsSpotifyRunning())
Process.Start(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"\spotify\spotify.exe"));
}
///
/// Runs Spotify's WebHelper
///
public static void RunSpotifyWebHelper()
{
if (!IsSpotifyWebHelperRunning())
Process.Start(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"\spotify\data\spotifywebhelper.exe"));
}
}
}