Nodejs - Spotify API 检查曲目是否存在于播放列表中

Nodejs - Spotify API check if track exists in playlist

我正在 Discord 中创建一个机器人,它可以在特定频道中添加共享歌曲并将其添加到相应的播放列表中。该函数按预期工作,因此我将那部分代码省略了。但如果需要我可以添加。

使用下面的代码,我希望能够评估播放列表是否已包含共享歌曲,如果包含则不要添加。 基本上跳过重复。

const playlists = new Map();
    
const spectrumPlaylist = {
  channelid: '948177541414404116',
  name: 'spectrum',
  id: '2SDsHpVc7yfQhGg0tS0RQ0'
}
playlists.set('948177541414404116', {
  name: 'spectrum',
  id: '2SDsHpVc7yfQhGg0tS0RQ0'
})
playlists.set('948185709037121566', {
  name: 'indie',
  id: '0JxWP48wGTRJrijEzg41fD'
})
playlists.set('948185876909936661', {
  name: 'instrumental',
  id: '37IIwZg5ek7mEYa2Ulmy85'
})

client.on('messageCreate', async message => {
  const playlist = playlists.get(message.channel.id);
  
  spotifyApi.getPlaylistTracks(playlist.id, {
    offset: 0,
    limit: 20,
    fields: 'items'
  })
  .then(
    function(data) {
      console.log('The playlist contains these tracks', data.body.items);
    },
    function(err) {
      console.log('Something went wrong!', err);
    }
  );
});

上面的代码记录了以下内容:

    The playlist contains these tracks [
  {
    added_at: '2022-04-18T20:25:51Z',
    added_by: {
      external_urls: [Object],
      href: 'https://api.spotify.com/v1/users/<userid>',
      id: '<userid>',
      type: 'user',
      uri: 'spotify:user:<userid>'
    },
    is_local: false,
    primary_color: null,
    track: {
      album: [Object],
      artists: [Array],
      available_markets: [Array],
      disc_number: 1,
      duration_ms: 285122,
      episode: false,
      explicit: false,
      external_ids: [Object],
      external_urls: [Object],
      href: 'https://api.spotify.com/v1/tracks/04wZnll09OSLNgvOEpWNHF',
      id: '04wZnll09OSLNgvOEpWNHF',
      is_local: false,
      name: 'Pacifica (Sultan + Shepard Remix)',
      popularity: 53,
      preview_url: 'https://p.scdn.co/mp3-preview/0fc9fadef348ded977208eea4a16135f497ecaa6?cid=d447a9a0d3d14fab83523430649b6c39',
      track: true,
      track_number: 1,
      type: 'track',
      uri: 'spotify:track:04wZnll09OSLNgvOEpWNHF'
    },
    video_thumbnail: { url: null }
  },
  {
    added_at: '2022-04-18T20:25:57Z',
    added_by: {
      external_urls: [Object],
      href: 'https://api.spotify.com/v1/users/<userid>',
      id: '<userid>',
      type: 'user',
      uri: 'spotify:user:<userid>'
    },
    is_local: false,
    primary_color: null,
    track: {
      album: [Object],
      artists: [Array],
      available_markets: [Array],
      disc_number: 1,
      duration_ms: 265506,
      episode: false,
      explicit: false,
      external_ids: [Object],
      external_urls: [Object],
      href: 'https://api.spotify.com/v1/tracks/5pEmeoMUW38w1oU3kPelvR',
      id: '5pEmeoMUW38w1oU3kPelvR',
      is_local: false,
      name: 'Spectrum',
      popularity: 46,
      preview_url: 'https://p.scdn.co/mp3-preview/5d9104b4cb82e3879867e2dc65997ab19b0f501b?cid=d447a9a0d3d14fab83523430649b6c39',
      track: true,
      track_number: 3,
      type: 'track',
      uri: 'spotify:track:5pEmeoMUW38w1oU3kPelvR'
    },
    video_thumbnail: { url: null }
  },
  {
    added_at: '2022-04-18T20:26:04Z',
    added_by: {
      external_urls: [Object],
      href: 'https://api.spotify.com/v1/users/<userid>',
      id: '<userid>',
      type: 'user',
      uri: 'spotify:user:<userid>'
    },
    is_local: false,
    primary_color: null,
    track: {
      album: [Object],
      artists: [Array],
      available_markets: [Array],
      disc_number: 1,
      duration_ms: 244186,
      episode: false,
      explicit: false,
      external_ids: [Object],
      external_urls: [Object],
      href: 'https://api.spotify.com/v1/tracks/1AA3ZjLo9tD2iSZAs2svyj',
      id: '1AA3ZjLo9tD2iSZAs2svyj',
      is_local: false,
      name: 'Chinatown (feat. Bruce Springsteen)',
      popularity: 54,
      preview_url: 'https://p.scdn.co/mp3-preview/993c6eecf44d181f50146c9cbf0d9e316d5c6cf8?cid=d447a9a0d3d14fab83523430649b6c39',
      track: true,
      track_number: 2,
      type: 'track',
      uri: 'spotify:track:1AA3ZjLo9tD2iSZAs2svyj'
    },
    video_thumbnail: { url: null }
  }
]

我想检索每个曲目的 ID,看看是否有任何匹配已解析为 ID 的 message.content。 另外,不确定如何处理限制,因为我不能将它设置得太高。

我正在使用 spotify-web-api-node

嗯,您有一个播放列表中所有曲目的数据数组。您的用户将 Spotify link 发送到您的频道,以便将它们添加到播放列表中。曲目的 Spotify link 在其 URL 中肯定有曲目的 ID,正如您在曲目数据数组中所见,曲目数据中提供了曲目 ID。让我们以播放列表中的第一首歌曲 'Pacifica (Sultan + Shepard Remix)' 为例。这就是那首歌的曲目数据的相关部分:

{
   track: {
      album: [Object],
      artists: [Array],
      available_markets: [Array],
      disc_number: 1,
      duration_ms: 285122,
      episode: false,
      explicit: false,
      external_ids: [Object],
      external_urls: [Object],
      href: 'https://api.spotify.com/v1/tracks/04wZnll09OSLNgvOEpWNHF',
      id: '04wZnll09OSLNgvOEpWNHF', // <- Notice this
      is_local: false,
      name: 'Pacifica (Sultan + Shepard Remix)',
      popularity: 53,
      preview_url: 'https://p.scdn.co/mp3-preview/0fc9fadef348ded977208eea4a16135f497ecaa6?cid=d447a9a0d3d14fab83523430649b6c39',
      track: true,
      track_number: 1,
      type: 'track',
      uri: 'spotify:track:04wZnll09OSLNgvOEpWNHF'
   }
}

这就是 user-sent Spotify link 的样子:

"https://open.spotify.com/track/04wZnll09OSLNgvOEpWNHF?si=FEomY7F6T_WAXwgLqIhhEw"

如您所见,ID "04wZnll09OSLNgvOEpWNHF" 存在于 link 和曲目数据中。这是我们可以用来确定曲目是否已经在播放列表中的东西。首先,让我们从 link:

中解析 ID
// Replace 'url' with the actual link from the message content
const url = "https://open.spotify.com/track/04wZnll09OSLNgvOEpWNHF?si=FEomY7F6T_WAXwgLqIhhEw";

const trackId = url.split("/").slice(-1)[0].split("?")[0];

以上示例的作用如下。首先,它将 url 拆分为 "/" 之间所有字符串的数组,如下所示:["https:", "", "open.spotify.com", "track", "04wZnll09OSLNgvOEpWNHF?si=FEomY7F6T_WAXwgLqIhhEw"]。然后我们使用 .slice(-1) 来获取数组的“切片”,特别是数组的最后一个切片(.slice() 接受索引作为参数,而 returns 所有元素的新数组在索引和数组末尾之间;如果给它一个负索引,它将从数组末尾向后移动;因此 -1 表示从数组末尾向后移动 1 项,即只是数组中的最后一项).完成此切片后,我们通过 [0] 获得切片数组的第一个元素,现在剩下以下字符串:"04wZnll09OSLNgvOEpWNHF?si=FEomY7F6T_WAXwgLqIhhEw"。现在,我们使用 .split("?") 将数组拆分为问号之间的字符串,并获取这些字符串中的第一个(即曲目 ID:"04wZnll09OSLNgvOEpWNHF")。希望这解释了它是如何工作的。这是基本的 javascript 字符串解析。

现在我们有了曲目 ID,我们需要看看是否可以在曲目数据项数组中的某处找到曲目 ID。我们可以使用 Array.some() 来实现这一点。该方法循环遍历数组,并且 returns true 如果您将回调函数作为其参数 returns true 传递给数组中的任何项目。以下是它在您的情况下的工作方式:

const hasTrack = data.body.items.some(item => item.track.id == trackId);

if (hasTrack) {
    // Track is already in playlist
}
else {
    // Add track to playlist
}

再加上之前解析曲目 ID 的代码片段,就是您的答案的解决方案。请记住,每个单独的跟踪数据项如下所示:

{
    added_at: '2022-04-18T20:25:51Z',
    added_by: {
      external_urls: [Object],
      href: 'https://api.spotify.com/v1/users/<userid>',
      id: '<userid>',
      type: 'user',
      uri: 'spotify:user:<userid>'
    },
    is_local: false,
    primary_color: null,
    track: {
      album: [Object],
      artists: [Array],
      available_markets: [Array],
      disc_number: 1,
      duration_ms: 285122,
      episode: false,
      explicit: false,
      external_ids: [Object],
      external_urls: [Object],
      href: 'https://api.spotify.com/v1/tracks/04wZnll09OSLNgvOEpWNHF',
      id: '04wZnll09OSLNgvOEpWNHF',
      is_local: false,
      name: 'Pacifica (Sultan + Shepard Remix)',
      popularity: 53,
      preview_url: 'https://p.scdn.co/mp3-preview/0fc9fadef348ded977208eea4a16135f497ecaa6?cid=d447a9a0d3d14fab83523430649b6c39',
      track: true,
      track_number: 1,
      type: 'track',
      uri: 'spotify:track:04wZnll09OSLNgvOEpWNHF'
    },
    video_thumbnail: { url: null }
}

因此我们需要执行 item.track.id 才能在 .some() 回调中获取曲目的 ID。此解决方案应该适合您。如果您对我以任何方式使用的流程、逻辑或代码感到困惑,请随时发表评论。

至于你提到的最后一件事:

not sure how to handle the limit as I couldn't set it too high

如果您无法从 Spotify 检索播放列表中的所有歌曲,请考虑在您自己的数据库中跟踪每个播放列表的歌曲列表(在将每首歌曲添加到播放列表时添加到数据库) , 而不是从那里检索数据。这可能比试图绕过限制更容易。