🎧

Spotify APIで自分のお気に入り曲を自動で取得・表示してみた

2022/02/12に公開

はじめに

音楽サービスは何を利用していますか?私は3年ほどSpotify premiumを利用しています。月額980円と他のサービスとほぼ同じですがUIが使いやすいのもありずっと使い続けています。

3年も使っていると自分の聞いている曲がどんどん変わっていくことが読み取れます。2021年末には「My Top Songs 2021」が公開されて、昨年聴いていた曲を全然聴いていなくて衝撃でした。

個人サイトを作ったのもありますし、自分が聴いている曲やアーティストを定期的に更新して表現できたらなと思い実現しました。

完成品:https://noriyu.dev/spotify/myTopTraks

この記事では以下を目的とした手法を紹介します。

  • 自分(個人サイトを運営している本人)がSpotifyで聴いているお気に入り曲を表示
  • 定期更新(リアルタイムではない)

ここでのお気に入り曲はSpotifyのハートボタンを押したお気に入りのことではなく、聴いている頻度が高い曲だと思います。

構成

  • Next.js(個人サイト)
  • Spotify API

これだけです。Next.jsにはvercelも含んでいますが、特に新しいことは利用していません。

Spotify APIとは

Spotifyが公開しているAPIです。アーティストや曲の情報はもちろん、ユーザー固有の情報を取得したりプレイリストを作成、公開などできます。詳しくは公式サイトを参照してください。

手順

手順を記します。
まず、全体的な流れとしては以下のようになります。

  1. Spotify Developerサイトでアプリを作成
  2. Client IDとClient Secretを取得
  3. refresh_tokenを取得
  4. refresh_tokenからaccess_tokenを取得
  5. access_tokenを使って任意のAPIを実行
  6. 必要に応じて4から繰り返す

Spotify のアプリを作成

まずはSpitfyで開発用のアプリを作成しましょう。
https://developer.spotify.com/dashboard/applications

アプリ作成

Client IDとClient Secretが表示されるのでメモしておきます。後でも大丈夫です。

アプリ作成

Edit Settingsを開きます。Redirect URIsに http://localhost を入力しておきます。ただ、ここはなんでもいいです。

アプリ作成

これでSpotifyアプリの設定は完了です。


ちなみにこの時点でもAPIを試すことができます以下のサイトにアクセスしてみてください。
https://developer.spotify.com/console/get-current-user-top-artists-and-tracks/

get-current-user-top-artists-and-tracks という、私のサイトでも実際に利用しているAPIを試せます。

typeに「tracks」、OAuth Tokenは「Get Token」を押してみてください。するとスコープの説明が出るので、「user-top-read」にチェックを入れてReqest Tokenをしましょう。
準備が終わったらTry Itをすると画面の右下に結果が表示されます。

api試し

refresh_tokenの取得

その前に、refresh_tokenとaccess_tokenの違いを説明しておきます。

access_tokenはAPIを利用する際に必須となるtokenです。ただし、このtokenには 60分 という有効期限がついています。そこで登場するのがrefresh_tokenです。refresh_tokenは基本的に有効期限がありません。また、refresh_tokenを使ってaccess_tokenを取得することができます。refresh_tokenの取得は少し面倒です。

認可リクエスト

https://accounts.spotify.com/authorizeを使ってscopeの指定と認可コードを取得することができます。

以下のurlを適当なブラウザで実行してみてください。

client_id:Spotify のアプリを作成で作成したもの
redirect_uri:同上
scope:user-top-read

https://accounts.spotify.com/authorize?client_id=${client_id}&response_type=code&redirect_uri=${redirect_uri}&scope=${scope}%&state=state

するとリダイレクトに失敗すると思いますが構いません。urlが変わっていると思うのでそこからcodeを抽出してください。

また、その際にspotifyのログインを求められるかもしれません。求められた際はログインしてください。

認可コードからrefresh_tokenを取得

https://accounts.spotify.com/api/tokenをPOSTします。
ヘッダー

  • ${client_id}:${client_secret}をbase64変換したもの

リクエストボディパラメータ

  • grant_type=authorization_code
  • code=先ほど取得したcode
  • redirect_uri=アプリ作成で設定したもの

レスポンス

{
access_token:'NX....',
token_type:"Bearer"
scope:codeを作成時に指定したscope
expires_in:3600,
refresh_token:'NX...'
}

このrefresh_tokenを利用します。access_tokenはあとで再度取得するので使いません。

refresh_tokenからaccess_tokenを取得

私が記述したコードを参考にしてください。
https://github.com/y0303noki/noriyu-nextjs-app/blob/main/src/pages/api/spotifyApi.ts#L35

this.refresh_token:先ほど取得したrefresh_token
this.tokenEndpoint:https://accounts.spotify.com/api/token
encode:${client_id}:${client_secret}をbase64変換したもの

 const result: string = await axios({
      url: this.tokenEndpoint,
      method: 'post',
      params: {
        grant_type: 'refresh_token',
        refresh_token: this.refresh_token,
      },
      headers: {
        Authorization: 'Basic ' + encode,
      },
    })
      .then((response) => {
        return response.data.access_token;
      })
      .catch((error) => {
        return 'ERROR getAccsessToken';
      });

ここでようやくaccess_tokenを取得することができました。

access_token を使ってAPIを利用する

ここからは簡単です。自分の使いたいAPIにaccess_tokenを含めて利用してみてください。
私のサイトではココで利用しています。

注意

いくつか注意事項があります。

scope

scopeは利用したいAPIによって異なります。その都度ドキュメントを確認してください。また、一般公開されている情報はscopeがなくても利用できます。

access_tokenを更新するタイミング

access_tokenは1時間しか持たないので何度も更新が必要です。どのタイミングで更新するべきか、どのタイミングでAPIを利用するべきかはケースバイケースだと思います。

私のサイトでは以下の理由からビルド時に更新することにしました。

  • 個人サイトの利用者はほとんどが自分、または少数
  • ゆえに1時間以内に何度も訪れる人はほぼいない
  • お気に入り曲やアーティストはそうそんなに変わるものではない
  • ビルドするタイミング(記事の更新も含まれる)など、多くとも1日に1回で十分だと判断

これが同じ人が何度も利用するようなものだと、access_tokenを何度も更新していると負荷になると思います。多くの場合ではリフレッシュトークンとアクセストークン、有効期限をDBに保持しておいて有効期限が切れていたら更新するような仕組みなのかもしれません。

さいごに

私はまだ開発者歴が短く、間違っていることを正しいと思い込んでいることもあります。何か間違っているよ、よくない使い方しているよということがあればご指摘いただけると幸いです。

Discussion