SpotifyのAPIを使ってみる

本記事は、[めんどい太郎の Advent Calendar 2023](https://qiita.com/advent-calendar/2023/mendoitarou_first_calendar) 12日目の記事です。

# はじめに

この記事は初心者が書いています。

皆さんはSpotify、使ってますか？

私は以前Spotifyを使っていました。

今回はSpotifyのAPIを使ってみようと思います。

Spotifyもドキュメントがわかりやすいので、読むのをおすすめします。

なんなら、ここで試すこともできます。

https://developer.spotify.com/documentation/web-api

:::note alert
この記事で紹介するコードは不完全であり、テストのためにセキュリティ面を考慮してない実装があります。
:::

# SpotifyのAPI

SpotifyのAPIでは楽曲の検索やプレイヤーの操作など様々なことができます。

個人的にはプレイヤーの操作が気になります。

それでは早速使ってみましょう。

# 試す
## アプリの登録とClient ID,secretの取得

Spotifyはデベロッパー向けサイトがあります。

まずはそこにアクセスし、APIキーなどを取得します。

[Home | Spotify for Developers](https://developer.spotify.com/)

右上にログインボタンがあるので押してログインします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388444/52325a66-8fa7-7bb9-bcff-3cb36c346891.png)

ログインすると、先程のボタンがユーザー名に変わるのでクリックしダッシュボードを開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388444/c94c4716-87a9-f4ab-8316-a49540b45478.png)

``Create App``をクリックし、アプリを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388444/08e4c2a8-5c7c-8b77-78a4-7d83342afe8e.png)

アプリの名前や概要、サイトのURLなどを入力します。

そして、リダイレクトURIと使用する予定のAPI/SDKを選択します。

今回はWeb APIだけを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388444/6722f276-ad46-d92e-828a-5c644e7776cb.png)

(自分のWebサイトにSpotifyのプレイヤーを実装できちゃうんですね...便利。)

``Save``を押してアプリを作成すると、アプリのホームに移動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388444/6cbab7b5-4865-681e-fba7-eeb2b20c962a.png)

ホームでアプリの利用者数などの様々な情報を見ることができます。

右上の``Settings``を押して、設定に移動します。

ここで表示される``Client ID``と``Client secret``をメモしておきます。

(``Client secret``はView Client secretを押すことで表示されます。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388444/6765d4f3-1ff0-e232-35c1-bb589d826561.png)

## トークン取得

それでは早速APIを使ってみます。

SpotifyのAPIではまず``Client ID``と``Client secret``を用いてトークンを取得する必要があります。

トークンの取得は``https://accounts.spotify.com/api/token``にPOSTを送ります。

curlでやってみましょう。

```Shell
curl -X POST "https://accounts.spotify.com/api/token" -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=client_credentials&client_id={Client id}&client_secret={Client secret}"
```

こんな感じで行います。

ヘッダーに``Content-Type: application/x-www-form-urlencoded``を指定し、送るデータに``grant_type``と``client_id``、``client_secret``を指定します。

実行するとトークンが返ってきます。

以下はドキュメント記載のサンプルです。

```JSON
{
  "access_token": "BQDBKJ5eo5jxbtpWjVOj7ryS84khybFpP_lTqzV7uV-T_m0cTfwvdn5BnBSKPxKgEb11",
  "token_type": "Bearer",
  "expires_in": 3600
}
```

これでトークンの取得ができました。

トークンは1時間有効です。

## 検索

検索に使用するURLは``https://api.spotify.com/v1/search``です。

先程入手したトークンを使います。

```Shell
curl "https://api.spotify.com/v1/searchq={search_text}&type={album,track,artist}&market=JP&limit={contents_limit}" -H "Authorization: Bearer {Token}"
```

こんな感じです。

GETリクエストを送信します。

ヘッダーに``Authorization: Bearer ``でトークンを送ります。

データは下の図に載せます。

|項目名|概要|
|:-:|:-|
|q|検索文字列 URLエンコードする必要あり。|
|type|検索する対象の種類 album,track,artistなど|
|market|検索する対象の国 JPなど|
|limit|返してもらう検索結果の数|

このように指定します。

それでは実際にやってみます。

```Shell
curl "https://api.spotify.com/v1/search?q=FutureBase&type=track&market=JP&limit=1" -H "Authorization: Bearer {Token}"
```

```JSON
{
  "tracks" : {
    "href" : "https://api.spotify.com/v1/search?query=FutureBase&type=track&market=JP&offset=0&limit=1",
    "items" : [ {
      "album" : {
        "album_type" : "single",
        "artists" : [ {
          "external_urls" : {
            "spotify" : "https://open.spotify.com/artist/2nKGmC5Mc13ct02xAY8ccS"
          },
          "href" : "https://api.spotify.com/v1/artists/2nKGmC5Mc13ct02xAY8ccS",
          "id" : "2nKGmC5Mc13ct02xAY8ccS",
          "name" : "Kizuna AI",
          "type" : "artist",
          "uri" : "spotify:artist:2nKGmC5Mc13ct02xAY8ccS"
        } ],
        "external_urls" : {
          "spotify" : "https://open.spotify.com/album/4EXNitbM0G8ligJXUodkGE"
        },
        "href" : "https://api.spotify.com/v1/albums/4EXNitbM0G8ligJXUodkGE",
        "id" : "4EXNitbM0G8ligJXUodkGE",
        "images" : [ {
          "height" : 640,
          "url" : "https://i.scdn.co/image/ab67616d0000b27375c00310c13c39dfcc103044",
          "width" : 640
        }, {
          "height" : 300,
          "url" : "https://i.scdn.co/image/ab67616d00001e0275c00310c13c39dfcc103044",
          "width" : 300
        }, {
          "height" : 64,
          "url" : "https://i.scdn.co/image/ab67616d0000485175c00310c13c39dfcc103044",
          "width" : 64
        } ],
        "is_playable" : true,
        "name" : "future base",
        "release_date" : "2018-10-26",
        "release_date_precision" : "day",
        "total_tracks" : 1,
        "type" : "album",
        "uri" : "spotify:album:4EXNitbM0G8ligJXUodkGE"
      },
      "artists" : [ {
        "external_urls" : {
          "spotify" : "https://open.spotify.com/artist/2nKGmC5Mc13ct02xAY8ccS"
        },
        "href" : "https://api.spotify.com/v1/artists/2nKGmC5Mc13ct02xAY8ccS",
        "id" : "2nKGmC5Mc13ct02xAY8ccS",
        "name" : "Kizuna AI",
        "type" : "artist",
        "uri" : "spotify:artist:2nKGmC5Mc13ct02xAY8ccS"
      } ],
      "disc_number" : 1,
      "duration_ms" : 183500,
      "explicit" : false,
      "external_ids" : {
        "isrc" : "TCJPI1801999"
      },
      "external_urls" : {
        "spotify" : "https://open.spotify.com/track/6n6Kf8A4uKIpRNCm68yYBw"
      },
      "href" : "https://api.spotify.com/v1/tracks/6n6Kf8A4uKIpRNCm68yYBw",
      "id" : "6n6Kf8A4uKIpRNCm68yYBw",
      "is_local" : false,
      "is_playable" : true,
      "linked_from" : {
        "external_urls" : {
          "spotify" : "https://open.spotify.com/track/4NtdvYIPuCu7rGVryVgTWG"
        },
        "href" : "https://api.spotify.com/v1/tracks/4NtdvYIPuCu7rGVryVgTWG",
        "id" : "4NtdvYIPuCu7rGVryVgTWG",
        "type" : "track",
        "uri" : "spotify:track:4NtdvYIPuCu7rGVryVgTWG"
      },
      "name" : "future base",
      "popularity" : 24,
      "preview_url" : "https://p.scdn.co/mp3-preview/f85c348040c1072b3832a0fccb5c81d34dfefcfb?cid=44c653a8530b4cd387663a68dac0fde0",
      "track_number" : 1,
      "type" : "track",
      "uri" : "spotify:track:6n6Kf8A4uKIpRNCm68yYBw"
    } ],
    "limit" : 1,
    "next" : "https://api.spotify.com/v1/search?query=FutureBase&type=track&market=JP&offset=1&limit=1",
    "offset" : 0,
    "previous" : null,
    "total" : 860
  }
}
```

こんな感じで返ってきました。

様々な情報が返ってきました。

SpotifyのAPIでは取得することのできる情報が非常に多いです。

ですので今回は詳しく解説しません()

確実に[ドキュメント](https://developer.spotify.com/documentation/web-api/reference/search)見たほうがわかりやすいです。

ですので、一部だけ紹介します。

``preview_url``は視聴用音声へのリンクです。

``audio``とかでこのURLを指定してあげると、視聴用音声が聞けちゃいます。

便利。

``images``はアルバムアートやアーティスト画像なのですが、サイズが大きいです。

そのため比較的きれいな画像が取得できます。

## 認可コード

プレイヤーの操作をする前に、認可コードを取得する必要があります。

Spotifyへのログインが求められますので、PHPでやってみます。

といってもLINEログインとほぼ同じようです。

とゆことで[10日の記事](https://qiita.com/mendoitarou_/items/b82e58fb4d76651ef5cb)からほぼほぼ持ってきます。

```PHP
<?php
function rand_str_gene($length) {
    return substr(str_shuffle("ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz0123456789"), 0, $length);
}

$client_id = '';//メモしたClient ID
$redirect_uri = 'https://example.com/callback/';
$redirect_uri = urlencode($redirect_uri);
$state = rand_str_gene(32);
$scope = urlencode('user-read-currently-playing user-read-playback-state user-modify-playback-state');

$login_url = 'https://accounts.spotify.com/authorize?response_type=code&client_id=' . $client_id . '&redirect_uri=' . $redirect_uri . '&state=' . $state . '&scope=' . $scope;

file_put_contents("csrf_token.txt", $state);

?>
```

スコープは`` ``(半角スペース)で区切るようです。

スコープは多すぎるので[ドキュメント](https://developer.spotify.com/documentation/web-api/concepts/scopes)を見てください。

今回は後ほど必要なスコープを指定しています。

リダイレクト先の方もサクッと書きます

```PHP
<?php

$client_id = '';//メモしたクライアントID
$redirect_uri = 'https://example.com/callback/';
$scope = urlencode('user-read-currently-playing user-read-playback-state user-modify-playback-state');
$client_secret = '';//メモしたクライアントシークレット

if(!empty($_GET['error'])) {
    $error_code = $_GET['error'];
} else {
    // GET_CODE
    $get_code = $_GET['code'];
    $get_state = $_GET['state'];
    // GET_GENERATE_TOKEN
    $contents = file("../csrf_token.txt");
    $before_login_gene_token = $contents[0];

    // GET_TOKEN
    // GET_Token(POST)
    $CURLERR = NULL;

    $data = array(
        'grant_type' => 'authorization_code',
        'code' => $get_code,
        'redirect_uri' => $redirect_uri,
        "client_id" => $client_id,
        "client_secret" => $client_secret
    );

    $headers = array(
        'Content-Type' => 'application/x-www-form-urlencoded',
    );

    $url = 'https://accounts.spotify.com/api/token';

    $ch = curl_init($url);

    curl_setopt($ch, CURLOPT_POST, TRUE);                            //POSTで送信
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));    //データをセット
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);                    //受け取ったデータを変数に
    $token_response = curl_exec($ch);

    if(curl_errno($ch)){        //curlでエラー発生
        $CURLERR .= 'curl_errno：' . curl_errno($ch) . "\n";
        $CURLERR .= 'curl_error：' . curl_error($ch) . "\n";
        $CURLERR .= '▼curl_getinfo' . "\n";
        foreach(curl_getinfo($ch) as $key => $val){
            $CURLERR .= '■' . $key . '：' . $val . "\n";
        }
        echo nl2br($CURLERR);
    }
    curl_close($ch);

    //echo $token_response.'<br>';
    
    $json_token_response = json_decode($token_response, true);
    print_r($json_token_response);

    //Error Check
    if(!empty($json_token_response['error'])){
        echo 'Error: <br>';
        echo $json_token_response['error'] . '<br>';
        echo $json_token_response['error_description'] . '<br>';
        exit();
    }
}
?>
```

公式ドキュメントの方法でやるとうまく行かなかったので、少し方法を変えています。

がしかし、ほぼ同じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388444/7c4c918b-121e-5ca3-7ff7-633a5a7fa4c7.png)

ログインURLへ行くと...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388444/3e23cb9f-476e-3f5e-9473-ccf65be5e6cd.png)

大丈夫そうですね。

そしてリダイレクト先にトークンが表示されます。OK!

## プレイヤー操作

次はプレイヤーの操作をしてみます。

まずはテキトーにスマホなどのSpotifyで音楽を再生します。

そしたらなんの音楽を聞いているのかを取得してみたいと思います。

```Shell
curl POST 'https://api.spotify.com/v1/me/player' --header 'Authorization: Bearer {Token}'
```

トークンは先程ログインして入手したものを用います。

レスポンスが返ってきましたが、詳細は念のため公開しないでおきます。

ここで、``device``の``id``や再生中の音楽の詳細など様々な情報が入手できます。

それでは、曲を変えてみたいと思います。

```Shell
curl POST 'https://api.spotify.com/v1/me/player/queue?uri={music_uri}&device_id={device_id}' --header 'Authorization: Bearer {Token}'
```

``music_uri``は楽曲情報を入手した際に記載されていたものです。

``spotify:{track,album}:{id}``といった形式のようです。

URLエンコード必須です。

``device_id``は先程入手した``id``を指定します。

それではやってみます。

```JSON
{
  "error" : {
    "status" : 403,
    "message" : "Player command failed: Premium required",
    "reason" : "PREMIUM_REQUIRED"
  }
}
```

SpotifyPremiumが必要だよ！と怒られてしまいました。

**おわり**

Spotifyのプレイヤー関連はSpotifyPremiumに加入しないとだめなものが多いです。

残念ながらPremiumに加入する財力がないので試せません。残念。

まぁほかも同じようにすることでできるので大丈夫でしょう()

# 終わりに

SpotifyのAPIはできることが多く、非常に便利ですね。

ですが、APIを使うユーザーがPremiumに加入していないと色々制限されます。

SpotifyPremiumが必要だよ！と怒られたときの対処を考えないとですね。

また雑な記事になっちゃいました...