El otro día empecé a explicar cómo crear una extensión para nuestro Visual Studio con la cual manejar Spotify. La primera parte la dejamos con el proyecto creado y ejecutándose, en esta segunda voy a explicar cómo podemos saber qué está sonando en nuestro Spotify y cómo manejarlo desde nuestro Visual Studio.

Lo primero que haremos será cambiar nuestro xaml para que incluya la carátula, el artista y el título de la canción así como los principales botones que tiene un reproductor de música. Para los botones utilizaremos la fuente Segoe UI Symbol en lugar de imágenes, con esto conseguiremos de una forma cómoda que siempre se vean bien independientemente de la resolución.

<Grid>  
    <TextBlock x:Name="TrackName" Grid.Row="0" Grid.Column="2" FontSize="13" VerticalAlignment="Center"/>
    <TextBlock x:Name="ArtistName" Grid.Row="1" Grid.Column="2" FontSize="13" VerticalAlignment="Center"/>
    <Image x:Name="AlbumCover" Grid.Row="0" Grid.RowSpan="2" Grid.Column="0" Width="50" Height="50"/>
</Grid>

<StackPanel Orientation="Horizontal" Grid.Row="2">
    <Button Content="&#xE100;" FontFamily="Segoe UI Symbol" FontSize="16" Click="PreviousTrackClick" Width="28" Height="28" Name="PreviousButton" Margin="0 0 10 0"/>
    <Button Content="&#xE102;" FontFamily="Segoe UI Symbol" FontSize="16" Click="PlayPauseClick" Width="28" Height="28" Name="PlayPauseButton" Margin="0 0 10 0"/>
    <Button Content="&#xE101;" FontFamily="Segoe UI Symbol" FontSize="16" Click="NextTrackClick" Width="28" Height="28" Name="NextButton" Margin="0 0 30 0"/>

    <Button Content="&#x1f509;" FontFamily="Segoe UI Symbol" FontSize="16" Click="VolumeDownClick" Width="28" Height="28" Name="VolumeDownButton" Margin="0 0 10 0"/>
    <Button Content="&#x1f50a;" FontFamily="Segoe UI Symbol" FontSize="16" Click="VolumeUpClick" Width="28" Height="28" Name="VolumeUpButton" Margin="0 0 10 0"/>
    <Button Content="&#x1f507;" FontFamily="Segoe UI Symbol" FontSize="16" Click="MuteClick" Width="28" Height="28" Name="MuteButton" Margin="0 0 10 0"/>
</StackPanel>

Lo siguiente que tendremos que hacer será comunicarnos con el cliente de Spotify que está instalado en nuestro ordenador. Para ello utilizaremos una funcionalidad escondida que tiene, si te fijas en tu administrador de tareas podrás ver un proceso llamado SpotifyWebHelper el cual no es más que un servidor web local con una api que es utilizado para que las páginas web se puedan comunicar con tu Spotify local cuando quieren reproducir una canción en él, sabiendo de esta forma si ya hay una canción sonando en ese momento y otra serie de cosas. Si buscas un poco por Google podrás encontrar información más detallada sobre ello.

Para implementar la comunicación con este servicio web local nos basaremos en la librería spotify-local-api la cual está abandonada y no funciona directamente, pero que con unos pocos cambios conseguiremos que se comunique correctamente con el cliente local de Spotify. El código se compone de una sóla clase llamada SpotifyAPI la cual tiene una serie de métodos públicos como Play, PauseGetCurrentStatus. Para poder utilizar esta clase deberemos de añadir la librería Newtonsoft Json la cual podremos añadir a nuestro proyecto a través de Nuget. (El código completo de la clase lo puedes encontrar en mi GitHub.

public class SpotifyAPI  
{
    public Status Play(string uri)
    {
        var response = SendRequest("remote/play.json?uri=" + uri, true, true, -1);
        var status = ((List)JsonConvert.DeserializeObject(response, typeof(List)))[0];
        return status;
    }

    public Status Pause()
    {
        var response = SendRequest("remote/pause.json?pause=true", true, true, -1);
        var status = ((List)JsonConvert.DeserializeObject(response, typeof(List)))[0];
        return status;
    }
}

Una vez que hemos conseguido tener lista la comunicación con el cliente de Spotify deberemos de empezar a añadir código en el code behind de nuestra vista. Lo primero que haremos será instanciar SpotifyAPI en el constructor y comprobar si no ha devuelto ningún error, en ese caso refrescaremos la vista con el estado actual e inicializaremos un timer para comprobar el estado cada segundo puesto que la única opción que tenemos para saber que ha cambiado algo es hacer pulling.

public MyControl()  
{
    InitializeComponent();

    _spotifyApi = new SpotifyAPI.SpotifyAPI();
    var cfid = _spotifyApi.GenerateCfid();
    if (cfid.error  null)
    {
        RefreshCurrentStatus();
        SetTimer();
    }
    else
    {
        TrackName.Text = "Unable connect to Spotify";
    }
}

private void SetTimer()  
{
    _timer = new Timer();
    _timer.Elapsed += OnTimedEvent;
    _timer.Interval = 1000;
    _timer.Enabled = true;
}

La vista la tendremos que refrescar la primera vez que abramos la ventana y cada vez que nos avise el timer, para ello tendremos un método llamado RefreshCurrentStatus que se encargará de pedir el estado actual al cliente de Spotify y si algo ha cambiado con respecto al anterior estado, rellenar la información de la canción, el artista, la caratula del álbum y el icono correcto del botón play/pause.

private void RefreshCurrentStatus()
{
    var previousStatus = _currentStatus;
    try
    {
        _currentStatus = _spotifyApi.GetCurrentStatus();
    }
    catch (Exception e)
    {
        Error();
    }
    if (_currentStatus.error != null)
    {
        Error();
    }

    if (previousStatus != null && previousStatus.Equals(_currentStatus))
        return;
    if (_currentStatus != null && _currentStatus.error == null)
    {
        if (_currentStatus.track != null)
        {
            var albumCover = _spotifyApi.GetAlbumCover(_currentStatus.track.album_resource.uri);
            var albumCoverUri = String.IsNullOrEmpty(albumCover) ? new Uri("http://127.0.0.1", UriKind.Absolute) : new Uri(albumCover, UriKind.Absolute);

            Dispatcher.Invoke(() =>
            {
                if (_currentStatus.playing)
                {
                    SetPauseIcon();
                }
                else
                {
                    SetPlayIcon();
                }
                TrackName.Text = _currentStatus.track.track_resource.name;
                ArtistName.Text = _currentStatus.track.artist_resource.name;
                AlbumCover.Source = new BitmapImage(albumCoverUri);
            });
        }
        else
        {
            Dispatcher.Invoke(SetPlayIcon);
        }
    }
}

Por último deberemos de controlar los eventos de los botones de nuestro player, algunos de ellos los podremos controlar directamente sobre el reproductor de Spotify, pero otros tendremos que simular las teclas multimedia de un teclado como si una persona las estuviese pulsando.

En el caso del botón play/pause podremos llamar directamente al reproductor de Spotify para que la música empiece a sonar o se pause.

private void PlayPauseClick(object sender, RoutedEventArgs e)
{
    if (_currentStatus.playing)
    {
        _currentStatus = _spotifyApi.Pause();
    }
    else
    {
        _currentStatus = _spotifyApi.Resume();
    }
}

En el resto de los casos (siguiente, anterior, mute, subir o bajar volumen) deberemos de utilizar la simulación de las teclas multimedia para conseguir nuestro objetivo ya que la api local del cliente de Spotify hasta donde yo se no dispone de estos métodos. Para simular la pulsación de las teclas utilizaremos la librería Windows Input Simulator la cual nos permite hacerlo de una manera cómoda y sencilla.

private void PreviousTrackClick(object sender, RoutedEventArgs e)
{
    var inputSimulator = new InputSimulator();
    inputSimulator.Keyboard.KeyPress(VirtualKeyCode.MEDIA_PREV_TRACK);
}

private void MuteClick(object sender, RoutedEventArgs e)
{
    var inputSimulator = new InputSimulator();
    inputSimulator.Keyboard.KeyPress(VirtualKeyCode.VOLUME_MUTE);
}

Con esto tendremos nuestra extensión de Visual Studio para manejar Spotify terminada y lista para empezar a utilizarla. El código completo del ejemplo está disponible en mi GitHub desde donde lo puedes descargar y modificar sin ningún problema.

Si deseas ejecutar directamente el proyecto que está en GitHub, deberás modificar un par de configuraciones para que al ejecutarse lo haga en un nuevo Visual Studio. Para ello en las propiedades del proyecto, dentro de la pestaña de Debug, deberás de indicar en StartAction que se va a ejecutar en un programa externo, en este caso será el Visual Studio y deberás de indicar la ruta donde se encuentra: C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\devenv.exe. También deberás de insertar dentro de Command line arguments lo siguiente: /rootsuffix Exp

Si tienes cualquier duda o sugerencia no dudes en dejar un comentario.