使用Spotify API构建一个网页音乐播放器
当你学习新概念时,拥有实际的例子和项目来进行实践总是很有帮助。Spotify API 是一个很好的 Web API 入门介绍。通过它,你可以轻松构建执行各种音乐相关任务的简单工具。
关于API
所有API都受到其拥有者选择提供的功能和数据的限制。但任何东西总比没有好,而且Spotify API或许出乎意料地开放且易于使用。
API 有两个主要组成部分:
- 一个提供有关艺术家、曲目和播放列表的元数据的网络API。
- 一个Web播放SDK,可以让你在网页中嵌入Spotify播放器。
一般来说,这些是相当受限的;例如,Spotify声称你不能使用Playback SDK来开发商业流媒体应用。但仍然有一些有趣的项目可以供你自己使用,Spotify API是网络API的一个很好的范例,非常适合学习和实践。
设置事务
我将讨论的两个演示位于一个GitHub仓库中。
构建这些示例应用最明显的需求是一个Spotify账户。使用它,您可以登录Spotify开发者仪表板并开始创建应用。
您还需要一个本地网络服务器,您可能已经设置好了。如果没有,这很简单。为您的 Spotify 开发选择一个合适的位置,例如 localhost/spotify 或 localhost:8080。
同时,在Spotify网站上,完成“创建应用程序”表单。确保选择“Web API”和“Web Playback SDK”选项,并选择重定向URI。例如,我将“top”演示托管在名为top.html的文件中,该文件在http://localhost:8080/top.html提供服务,因此这是我的重定向URI之一。如果你对你的演示使用类似的架构,请记得将每个新文件添加为重定向URI。
一旦您创建了应用,请注意客户端 ID 和客户端密钥,这两者都显示在您应用的“基本信息”页面上。
对于生产应用程序,您需要采取措施确保您的客户端密钥保持隐藏。对于这个本地演示,我只是将值嵌入到我的JavaScript文件中,但您不应该向任何人透露您的客户端密钥。
在这一点上,您可能想要下载示例文件,将它们移动到本地文档根目录,并开始实验。我只能在本文中覆盖代码的一小部分,因此这样做将使您能够跟随该过程。
通过API授权
创建应用程序的第一步是使用OAuth进行授权。这是一种流行的网络应用程序授权标准,因此了解它是非常有价值的。
OAuth通过在HTTP上发送访问令牌来工作,这个过程已经建立得足够成熟,以至于有了帮助库。不过,对于我们基本的用途来说,自己处理一切也很简单。
我已经将这段代码隔离在 access.js 文件中。第一步是重定向到 Spotify 的授权 URL,即 https://accounts.spotify.com/authorize。您需要提供一些参数以请求用户授予使用您应用程序的权限:
- 响应类型:对于我们正在构建的样本应用程序类型,只需使用代码。
- client_id: 这是您在应用程序设置中记下的客户端ID。
- 范围:一个以空格分隔的字符串,用于授予权限。对于我将在这里介绍的两个示例,“streaming user-top-read”就足够了,但如果您尝试其他端点,请确保查阅完整的范围列表。
- redirect_uri:您已添加到应用程序的有效重定向 URI。
出于安全原因,你也应该使用state参数,但在这些演示中可以省略它。
在 access.js 中,authorize 函数看起来是这样的:
function authorize() {
let base = "https://accounts.spotify.com/authorize",
params = {
response_type: "code",
client_id: CLIENT_ID,
scope: "streaming ...",
redirect_uri: REDIRECT_URI,
};
window.location.assign(base + "?" + new URLSearchParams(params));
}
这会将浏览器重定向到带有相关参数的Spotify URL。当您查看此URL时,您将看到类似以下内容:
用户只需要授予权限一次,除非您更改范围。授予权限后,他们将被发送到 redirect_uri,并附带一个代码参数。因此,他们最终会到达类似 http://localhost:8080/top.html?code=... 的位置。您的脚本应检查此参数,如果存在,则继续下一步:
let p = new URLSearchParams(window.location.search);
if (p.has("code")) {
get_access_token(p.get("code"));
}
第二步是将您刚获得的代码发送回 Spotify,以换取访问令牌。然后,您将在所有后续请求中使用此访问令牌来访问 API。
本文中的代码经过简化以减少长度。有关更多详情,请查阅GitHub库中的完整代码。特别是,当令牌过期时,您还需要刷新它。
async function get_access_token(code) {
let url = "https://accounts.spotify.com/api/token",
data = {
grant_type: "authorization_code",
code: code,
redirect_uri: REDIRECT_URI,
},
headers = {
"content-type": "application/x-www-form-urlencoded",
Authorization: "Basic " + btoa(CLIENT_ID + ":" + CLIENT_SECRET),
};
let opts = {
method: "post",
headers: headers,
body: get_post_data(data),
};
const response = await fetch(url, opts),
token = await response.json();
if (token.access_token) {
localStorage.setItem("access-token", token.access_token);
} else {
console.error("Some kind of error getting access token", token);
}
}
您可以使用本地存储 API 记录访问令牌,并在将来获取它:
let token = localStorage.getItem("access-token");
您现在应该在所有Spotify API请求中通过Authorization头发送访问令牌:
async function spotify_api_get(url) {
let headers = {
Authorization: "Bearer " + at.access_token,
};
let opts = { headers: headers, method: "GET" };
const response = await fetch(url, opts);
return await response.json();
}
这个功能占用了整个 spotify.js 文件,仅处理 GET 请求。当你需要使用的端点需要它们时,你可以扩展这个文件,编写类似的函数用于 PUT 和 POST 方法。
OAuth 是一个相当复杂的主题,超出了本文的范围。您可以使用一个简单版本进行实验;只需记住,如果令牌过期,您需要手动重置它(参见 localStorage.removeItem)。
获取元数据资讯
一切准备就绪且客户已授权,您终于可以开始使用 API 了。获取元数据稍微简单一些,所以我将从“top”示例(top.html)开始,它会显示您最喜欢的艺术家以及关于他们的一些信息。
首先查阅Spotify API文档,了解如何使用/me/top/artists端点。您可以通过避免附加参数并专注于响应对象来保持简单,该对象在其items属性中包含您最喜欢的艺术家的详细信息。
在 top.js 中,run() 函数包含获取和显示这些数据的代码。这非常简单:首先,它调用 API 端点并存储返回的对象:
let top_artists = await spotify_api_get(
"https://api.spotify.com/v1/me/top/artists",
at.access_token,
);
接下来,它遍历响应中的项目:
top_artists.items.forEach(function (artist) {
// ...
});
在那个循环中,它添加了一个表格行,包含每个项目的数据:
tr = tbody.appendChild(document.createElement("tr"));
td = tr.appendChild(document.createElement("td"));
td.appendChild(document.createTextNode(artist.name));
// ...
结果是一个简单的表格,列出了您最喜欢的艺术家及其相关流派;我的看起来是这样的:
使用 Spotify 播放器
元数据很有趣,但一个正常运作的Spotify播放器可能更有用。虽然存在一些限制,但API基本上确实让你可以完全控制播放,因此——经过一些努力——你可以构建自己的客户端。
最大的问题在于API坚持要求你同时运行Spotify和你自己的客户端。这对你的开发来说应该不是太大的问题,但可能会限制你可以开发的潜在应用。你需要将Spotify应用明确连接到你的API客户端,作为一个设备:
更重要的是,每次刷新您的网络应用时您都需要这样做,这可能会很烦人。我在演示中添加了一个错误消息,提醒您这样做;这稍微减轻了痛苦!
player.html 文件展示了一个简单的客户端,具有专辑封面、播放控制和一个让你可以寻址的进度指示器。大部分相关功能存在于 player.js 中。
第一步是插入Spotify的SDK脚本:
<script src="https://sdk.scdn.co/spotify-player.js"></script>
在演示中,我动态注入这个。这确保了脚本可以首先检查访问令牌,如果必要的话获取一个。如果没有有效的访问令牌,SDK 脚本可能会产生错误。
接下来,脚本创建一个新的玩家实例并尝试连接到它。
window.onSpotifyWebPlaybackSDKReady = () => {
player = new Spotify.Player({
name: "bobbykjack spotify client",
getOAuthToken: (cb) => {
cb(at.access_token);
},
volume: 0.5,
});
setup_player_state_event();
player.connect().then((success) => {
if (success) {
check_device_connected();
} else {
console.error("Oops, failed to connect to spotify");
}
});
};
请注意,玩家需要提供一个有效的访问令牌,以及一个将在 Spotify 应用中作为要连接的设备出现的名称。check_device_connected 和 check_player_state 方法会轮询设备连接;如果没有连接,脚本将显示我之前提到的 "请连接" 错误。
当播放器对象被设置并连接后,您可以在其上调用其他方法来加载曲目和控制播放。这些方法在 Web 播放 SDK 参考文档中有详细说明。示例播放器使用了其中几个方法:暂停、定位、继续、切换播放和获取当前状态。
某些功能只需将页面上的按钮连接到相应的SDK方法。 例如,这里是播放按钮的代码:
play.addEventListener("click", function (ev) {
player.resume().then(() => {
play.setAttribute("disabled", "1");
pause.removeAttribute("disabled");
});
});
点击后,按钮会调用 Player.resume 方法,然后禁用自身并启用暂停按钮。
某些功能稍微复杂一些。当曲目改变时,player_state_changed 事件会调用同名的方法,这个方法更新显示,例如更改专辑封面:
let src = get_image(arg.track_window.current_track.album.images, 300),
//...
set_attr("#currently_playing div.track-meta img", "src", src);
为了显示当前曲目的进度,代码调用 Player.getCurrentState 方法。这将返回一个包含有关播放的各种细节的对象,包括当前曲目位置:
function check_player_state(state) {
//...
update_time(".position", state.position);
//...
}
最后,进度输入可以通过拖动来改变轨迹位置:
document
.querySelector("#track-progress")
.addEventListener("input", handle_seek_input);
function handle_seek_input(ev) {
if (seek_timer) {
window.clearTimeout(seek_timer);
}
seek_timer = window.setTimeout(function () {
seek_to_ms(ev.target.value);
}, 200);
}
function seek_to_ms(position) {
player.pause().then(function () {
player.seek(position).then(function () {
player.resume();
update_time(".position", position);
});
});
}
请注意,在调用 Player.seek 方法之前,会使用计时器注入一个人为的——但很小——延迟。如果没有这个延迟,拖动进度条一小段时间可能会导致对 API 的数百次调用;最好避免这种情况。
与许多API一样,Spotify使用速率限制来确保您不会以过多请求压倒服务。不过,它非常宽容,您在使用这些示例时不应该遇到任何问题;如果出现任何问题,请检查您的控制台以查看是否有429错误。
最终的应用展示了一个与Spotify同步的基本播放器:
希望您可以从这些简单的演示中学习,并开始编写自己的代码以使用 Spotify API。它可能看起来有限,但您可以对简单客户端进行许多调整,以改善您的 Spotify 体验。
我一直觉得播放列表应该能够包含完整的专辑,所以这是我肯定会尽快着手开发的一个功能。你也可以调查其他API,例如YouTube,以便将数据与Spotify播放器或元数据结合起来,构建一个展示两者最佳内容的应用程序。





