Spotify APIを使ってウェブ音楽プレーヤーを作る
新しい概念を学ぶとき、実用的な例やプロジェクトを持つことは常に役に立ちます。Spotify APIは、一般的なWeb APIの素晴らしい入門編です。これを使えば、さまざまな音楽関連のタスクを実行する簡単なユーティリティを簡単に構築できます。
APIについて
すべてのAPIは、その所有者が利用可能にする機能とデータによって制限されています。しかし、何もないよりは何かがある方が良く、Spotify APIは意外にもオープンで使いやすいです。
APIには2つの主要なコンポーネントがあります:
- アーティスト、トラック、プレイリストに関するメタデータを提供するWeb API。
- ウェブページ内にSpotifyプレーヤーを埋め込むことができるWeb再生SDKです。
一般的に、これらはかなり制限されています。たとえば、Spotifyは、商業ストリーミングアプリを開発するためにPlayback SDKを使用してはいけないと述べています。しかし、あなた自身の使用のために作成できる興味深いプロジェクトもありますし、Spotify APIは一般的なWeb APIの良い例であり、学ぶことや練習するために最適です。
設定すること
私が議論する2つのデモは、GitHubリポジトリにあります。
これらのサンプルアプリを構築するために最も明白な必要なものはSpotifyアカウントです。それを使用して、Spotify for Developers Dashboardにログインし、アプリを作成することから始めることができます。
ローカルウェブサーバーも必要になりますが、すでにセットアップしているかもしれません。まだの場合は、設定するのはとても簡単です。Spotifyの開発に適切な場所を選択してください。例えば、localhost/spotify や localhost:8080 のように。
その間、Spotifyのウェブサイトに戻って、「アプリの作成」フォームを完了させてください。「Web API」と「Web Playback SDK」の両方のオプションを選択し、リダイレクトURIを選んでください。例えば、私は「top」というデモをtop.htmlというファイルにホスティングしていて、http://localhost:8080/top.html で提供されていますので、それが私のリダイレクトURIの1つです。デモに似たアーキテクチャを使用している場合は、新しいファイルをリダイレクトURIとして追加するのを忘れないでください。
アプリを作成したら、アプリの「基本情報」ページに表示されているクライアントIDとクライアントシークレットをメモしておいてください。
商用アプリの場合、クライアントシークレットを隠しておくための手順を踏む必要があります。このローカルデモでは、JavaScriptファイルに値を埋め込んでいますが、クライアントシークレットを誰にも開示してはいけません。
この時点で、サンプルファイルをダウンロードし、ローカルのドキュメントルートに移動して実験を始めることをお勧めします。この文章ではコードの一部しかカバーできないため、そうすることでプロセスに沿って進むことができます。
APIを使用して認証する
アプリを作成する最初のステップは、OAuthを使用して認証することです。これはウェブアプリの認証において一般的な標準であり、学ぶ価値があります。
OAuthは、HTTPを介してアクセストークンを送信することで機能し、そのプロセスは十分に確立されているため、ヘルパーライブラリが利用可能です。それでも、私たちの基本的な目的のためには、すべてを自分たちで簡単に扱うことができます。
私はこのコードを access.js ファイルに隔離しました。最初のステップは、Spotify の認証 URL にリダイレクトすることです。それは https://accounts.spotify.com/authorize です。アプリの使用に対するユーザーの許可を要求するために、いくつかのパラメータを供給する必要があります。
- 応答タイプ: 私たちが構築しているサンプルアプリのタイプについては、ただコードを使用してください。
- client_id: これはアプリ設定中にメモしたクライアントIDです。
- スコープ:権限を付与するためのスペース区切りのスコープの文字列。ここで扱う2つのデモでは「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を表示すると、次のようなものが見えるでしょう:
ユーザーは、スコープを変更しない限り、一度だけ権限を付与する必要があります。権限が付与されると、リダイレクトURIにコードパラメータと共に送信されます。したがって、彼らは http://localhost:8080/top.html?code=... のようなURLに到達します。あなたのスクリプトは、このパラメータをチェックし、存在する場合は次のステップに進む必要があります。
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.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を実行することを強く求めることです。これはあなたの開発にとってそれほど問題ではないはずですが、開発できるアプリの可能性を制限するかもしれません。あなたのAPIクライアントにSpotifyアプリを明示的に接続する必要があります、デバイスとして:
さらに、ウェブアプリをリフレッシュするたびにこれを行う必要があり、煩わしい場合があります。デモにはエラーメッセージを追加し、これを行うように促しています。それは少しだけ痛みを和らげます!
player.htmlファイルは、アルバムアートワーク、再生コントロール、およびシークを可能にする進行状況インジケーターを持つシンプルなクライアントを提供します。関連機能のほとんどはplayer.jsにあります。
まず最初に行うべきことは、SpotifyのSDKスクリプトを挿入することです。
<script src="https://sdk.scdn.co/spotify-player.js"></script>
デモでは、これを動的に挿入します。これにより、スクリプトは最初にアクセストークンを確認し、必要に応じて取得することができます。有効なアクセストークンがないと、SDKスクリプトはエラーを生成する可能性があります。
次に、スクリプトは新しいPlayerインスタンスを作成し、それに接続しようとします:
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 Playback SDKリファレンスのドキュメントに詳細があります。サンプルプレーヤーはいくつかのこれらのメソッドを使用しています:pause、seek、resume、togglePlay、getCurrentState。
機能の一部は、ページ上のボタンを対応する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の体験を向上させるための多くの工夫ができます。
私は常にプレイリストがフルアルバムを含むべきだと感じていたので、その機能に関してはすぐに取り組むつもりです。また、データをSpotifyプレイヤーやメタデータと組み合わせるためにYouTubeのような他のAPIを調査し、両方のベストを提供するアプリを構築してみても良いでしょう。





