spotify

Detect end of a track's playback with Spotify Web API / Playback SDK


Working with Spotify Web API and Web Playback SDK, does anybody know a good way to detect when a track's playback has finished, i.e. the song is over?

I know about some event named player_state_changed in Web Playback SDK, but the data provided in the event doesn't seem to be very helpful to me.

In my web app, the next song to be played is determined pretty spontaneously. It would be nice, if I could determine it only, when the current track has reached its end. Hence, there is no playlist. Instead, the app plays single tracks in series and should determine the next song, when the current one has ended.

Meanwhile I try it with this code here:

var bCallingNextSong = false;

player.addListener('player_state_changed', state => { 
    if (state != null && 
        state.position == 0 && 
        state.duration == 0 && 
        state.paused == true) { 

        if (!bCallingNextSong) {
            playNextSong();
        }
    }
});


function playNextSong() {
   $.ajax({
            url:"playback.php", //the page containing php script
            type: "post", //request type,
            dataType: 'json',
            data: {action: "next", device: deviceId},
            success: function(result) {
                bCallingNextSong = false;
            },
            error: function(XMLHttpRequest, textStatus, errorThrown) {  
                bCallingNextSong = false;
            } 
    });     
}

and in playback.php:

switch ($action) {

    case "next":
        //some blackbox magic here to determine next song, do logging etc.
        //but for now just play the same song over and over

        $api->play($deviceId, ['uris' => "spotify:track:0eGsygTp906u18L0Oimnem"],]);

        echo json_encode(array("answer"=>"played next"));
        break;  

// more code
}

However, this will often (but not always) throw an InvalidStateError (I haven't found out where exactly yet nor why). Stack says dequeueUpdates / tryUpdate / _processUpdate / _appendUpdate. Yet, I'm a beginner and I've gotta learn how to cope with Firefox Debugger first.. :)


Solution

  • My last answer got broken so I will now add new solution which work for now.

    this.player.addListener('player_state_changed', (state) => {
        console.log(state);
        if (
          this.state
          && state.track_window.previous_tracks.find(x => x.id === state.track_window.current_track.id)
          && !this.state.paused
          && state.paused
          ) {
          console.log('Track ended');
          this.setTrackEnd(true);
        }
        this.state = state;
      });
    

    So what is different from last solution? I check that current_track is in previous track list. But there was problem now with position check because it seems that current track appears to previous track list before track is completely end. But that wasn't problem in my app because there is always small delays with commands.