使用 Spotify Web API / Playback SDK 检测曲目的播放结束

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

使用 Spotify Web API 和 Web Playback SDK,有人知道检测曲目播放何时结束(即歌曲结束)的好方法吗?

我知道 Web Playback SDK 中有一个名为 player_state_changed 的事件,但事件中提供的数据似乎对我帮助不大。

在我的网络应用程序中,下一首要播放的歌曲是自发确定的。如果我只能在当前曲目结束时确定它,那就太好了。因此,没有播放列表。相反,该应用会连续播放单首曲目,并应在当前歌曲结束时确定下一首歌曲。

与此同时,我在这里尝试使用此代码:

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;
            } 
    });     
}

并在 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
}

然而,这经常(但不总是)抛出 InvalidStateError(我还没有找到确切的位置和原因)。 Stack 表示 dequeueUpdates / tryUpdate / _processUpdate / _appendUpdate。然而,我是初学者,我必须先学习如何处理 Firefox Debugger.. :)

您应该使用 player_state_changed 事件并查看正在播放的曲目是否已更改。您可以在 playerStateObject.track_window.current_track.

中找到当前曲目

一个可能的实现可能是这样的:

let currentTrack = '';

player.on('player_state_changed', state => {
    if( state.track_window.current_track.id != currentTrack ) {
        // The track changed!
        currentTrack = state.track_window.current_track.id;
    }
});

编辑:由于某种原因,这不再有效。检查我现在可以使用的其他答案。

这是我的解决方案。它大部分时间都有效。事实上,在我能想象到的任何情况下,我都没有把它弄坏。所以保持最后一个状态并检查它是否进入暂停状态。希望 Spotify 将简化我们在跟踪结束事件方面的工作。如果他们这样做会很棒。这仍然比每 1 秒左右轮询他们的 /me/player/currently-playing 端点要好。

this.player.addListener(
    'player_state_changed',
    state => 
    {
      console.log(state);
      if(this.state && !this.state.paused && state.paused && state.position === 0) {
        console.log('Track ended');
        this.setTrackEnd(true);
      }
      this.state = state;
    }
  );

我的上一个答案被破坏了,所以我现在将添加目前有效的新解决方案。

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;
  });

那么与上一个解决方案有何不同?我检查 current_track 是否在之前的曲目列表中。但是现在位置检查有问题,因为似乎当前曲目在曲目完全结束之前出现在上一个曲目列表中。但这在我的应用程序中不是问题,因为命令总是有小的延迟。

我遇到了同样的问题,我就是这样解决的。

歌曲播放完毕后,它会添加到 state.track_window.previous_tracks 列表

state.track_window.previous_tracks 只有在有下一首曲目并开始播放时才会填充

但是每次调用 api 播放新曲目时,它都会清除 state.track_window.previous_tracks & state.track_window.next_tracks 列表。

如果有下一首曲目,我想停下来选择我自己的下一首曲目,然后调用 api

var alreadyPlayed = state.track_window.previous_tracks

if(alreadyPlayed.length > 0) {
  player.pause()
}

如果没有下一首曲目,播放器将在歌曲结束时暂停

if(state.paused && state.position === 0) {
  //song ended
  ChooseNextSong()
}

state 回调被触发了很多次,但我想调用 ChooseNextSong() 只有一次,所以每次触发时我都会增加 startCheck

if(state.paused && state.position === 0) {
  //song ended
  startCheck++
  if(startCheck === 1) {
    ChooseNextSong()
  }
}

检查歌曲是否开始

if(state.position === 0 && alreadyPlayed.length === 0 && !state.paused) 
{
  //song started
  startCheck = 0
}