Spotify APIで今週リリースの新譜プレイリストを作る

この記事は[Wano Group Advent Calendar 2023](https://qiita.com/advent-calendar/2023/wano-group)の24日目の記事となります。

1つ前の記事は@nijigen_plotさんの
「Lambda コンテナイメージを使ってSlackのグラフ貼り付けBOTを作る」です。
また、私の所属するグループ会社の[EDOCODEのAdvent Calendar](https://adventar.org/calendars/8641)もありますので、
よろしければそちらもどうぞ。

## はじめに
2023年11月にWanoにジョインいたしました@tutti618と申します。
昔から好きだった音楽と新卒から続けているエンジニアの仕事がマリアージュする！
と意気揚々でしたが

3年半の温室フルリモートワークですっかりもやしっ子になっていたため
入社5日目早々にインフルでダウン🤧

~~入社早々2日連続、退勤後にライブではしゃいだせいかもしれませんが~~

そこでインフル罹患のため参加できなかった[開発合宿](https://group.wano.co.jp/blog/3167/)で実装予定だった
Spotify API利用の個人開発について記事にしました。

## きっかけ
### クイズ
突然ですが、水曜日と金曜日は何の日でしょうか？

<br><br><br><br><br>

正解は…

<br><br><br><br><br>

とても楽しみな **新譜の発売日** です！

水曜日は主に邦楽のアルバムが、
金曜日は主に洋楽のアルバムが発売されます。

### 新譜チェックの仕方
その筋の有識者の𝕏（旧Twitter）や
ブログに掲載されている、新譜を発売するArtistリストをコピペ
↓
コピペしたArtistをサブスクサービスで検索
↓
ヒットしたAlbumのうち、発売日が最新のAlbumをクリック
↓
Track1を再生

という手作業をArtistの数分繰り返しています。これは面倒…😔

ということでArtistリストから今週リリースAlbumの
Track1だけを集めたPlayListを作ります。

## 実装
### 事前準備
#### Spotify Premium会員になる
無料会員でもAPI操作が可能かは試していません。

#### Pyhton環境
手元の環境は
- Mac Ventura 13.6.1
- Python 3.12.0
- pip 23.2.1


#### Spotipy(Spotify API)インストール
Spotify APIをPythonから利用するためのライブラリです。
```

pip install spotipy

```

#### Spotify Developer
Spotifyにログイン後、[Spotify Developer](https://developer.spotify.com/dashboard/create)からCreate appします。

今回はローカルで動かすのみですので
Redirect URIは`http://localhost:8888/callback`で問題ありません。

#### Spotifyアカウント情報
下記コードのXXX部分にはSpotifyアカウント情報を記載します。
そのままコード公開するとセキュリティNGのため、実際は環境変数にしておくとよいですね。

```Python:create_playlist.py

#Spotify APIの認証部分 username, my_id, my_secret は人によって異なる
username = 'XXX' 
my_id ='XXX' 
my_secret = 'XXX' 
redirect_uri = 'http://localhost:8888/callback' 
scope = 'user-library-read user-read-playback-state playlist-read-private user-read-recently-played playlist-read-collaborative playlist-modify-public playlist-modify-private'
token = util.prompt_for_user_token(username, scope, my_id, my_secret, redirect_uri)
spotify = spotipy.Spotify(auth = token)

```

トークンとシークレットは先程のSpotify Developerからコピーできます。
![Screenshot at Dec 09 10-18-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635225/832b9c09-65ef-d265-c8db-c44fac22ba5d.png)


ユーザー名はSpotifyのアカウントページより
![Spotifyアカウント.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635225/f6ff641a-1505-3c6f-f5f0-13c7fde80560.png)

「プロフィールを編集」の「ユーザー名」を確認
![Spotifyユーザー名.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635225/4ec22c29-2847-63e1-b063-44386ec8ef25.png)

「プロフィール」の下に表示されているユーザIDは、今回は使用しません。
![Spotifyプロフィール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635225/3193e374-6c64-fcf6-946c-e1095ccdd809.png)

フォローさせていただいている方の𝕏（旧Twitter）ポストからArtistリストをコピーし、
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">こちらは6月2日金曜日に発売される注目のアルバム(その①)です。<br><br>・Foo Fighters<br>・Noel Gallagher&#39;s High Flying Birds<br>・Bob Dylan<br>・Beach Fossils<br><br>・KNOWER<br>・Speakers Corner Quartet<br>・WITCH<br><br>・Anthony Naples<br>・MUN SING(Giant Swan)<br>・Juan Wauters<br><br>・Bully<br>・Ans M<br>・Metro Boomin(OST) <a href="https://t.co/J9n7Xe3wNf">pic.twitter.com/J9n7Xe3wNf</a></p>&mdash; おすすめ音楽紹介 (@E6jLy) <a href="https://twitter.com/E6jLy/status/1663560942339375104?ref_src=twsrc%5Etfw">May 30, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

テキストファイルにペースト、「Artistリスト」としてディレクトリ直下に配置します。
2023/06/02はフジロックで圧巻のライブだったフーファイと、
先日も来日してくれたギャラガ兄の新譜が同時発売ということでアツいです。
個人的には超人Louis Cole率いるKNOWERもオススメです。


```txt:230602.txt

Foo Fighters
Noel Gallagher's High Flying Birds
Bob Dylan
Beach Fossils

KNOWER
Speakers Corner Quartet
WITCH

Anthony Naples
MUN SING(Giant Swan)
Juan Wauters

Bully
Ans M
Metro Boomin(OST)

```

### 作成処理

空のプレイリストを作成

```Python:create_playlist.py

def main():

    playlists = spotify.user_playlist_create(username, '230603New')

```

Artistリストを1行ずつ読み取り

```Python:create_playlist.py

    f = open('230603.txt', 'r')
    datalist = f.readlines()

    for name in datalist:
        if name == '\n':
            continue
        #括弧より前までをArtist名とする
        idx = name.find('(')
        name = name[:idx]

```

[Search for Item](https://developer.spotify.com/documentation/web-api/reference/search)でArtist名からArtistのIDを取得

```Python:create_playlist.py

        search_result = spotify.search(q=name, limit=10, offset=0, type='artist', market=None)
        artist_Id = search_result['artists']['items'][0]['id']

```

[Get Artist's Albums](https://developer.spotify.com/documentation/web-api/reference/get-an-artists-albums)でArtistのIDからAlbumリストを取得

🍙Spotify APIでは残念ながらparameterでsortを指定することができません。
そのため取得したAlbumリストをrelease_date降順に自力で並べ替えます。

```Python:create_playlist.py

        # artist_idからalbumデータを取得
        album_results = spotify.artist_albums(artist_Id, limit=50, album_type='album')
        album_datas = album_results['items']
        while album_results['next']:
            album_results = spotify.next(album_results)
            album_datas.extend(album_results['items'])
        
        # 発売日の降順にソート
        album_sorted = sorted(album_datas, key=lambda x:x['release_date'], reverse=True)

```

並べ替えたAlbumリストの1番目（最新のAlbum）のSpotify IDを取得し
[Get Album Tracks](https://developer.spotify.com/documentation/web-api/reference/get-an-albums-tracks)でTrackリストを取得

```Python:create_playlist.py

        # album_idからalbumのtrackデータを取得
        tracks = []
        album_tracks = spotify.album_tracks(album_sorted[0]['id'])

        for track in album_tracks['items']:
            tracks.append(track['id'])

```

取得したTrackリストの1番目のSpotify IDを取得し
先程作成したプレイリストに追加

1曲目だけで判断するなんて最近の若者は😠の場合は、お好みで曲数を増減しましょう。
ライブラリspotipyでは3つ目のparameterは配列の必要があります。

```Python:create_playlist.py

        # trackデータの1曲目をプレイリストに追加
        results = spotify.user_playlist_add_tracks(username, playlists['id'], [tracks[0]])

```

以上をArtistリストの行数分繰り返し、python create_playlist.pyを実行
無事今週リリースの新譜プレイリストが作成できました。

![20230603New.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635225/3bc2bb62-2eb8-6a36-473f-200ad600f0ba.png)


## 問題点
- 同名Artistの別情報を引っ張ってきてしまうことがある
→必要に応じてGet ArtistのReturnであるgenresなどをチェックすると良さそうです。

- アルバムを発売日の降順でソートするため、発売日にすぐ動かす必要がある
ボブ・ディランは多作で企画盤も多いため、
例では6/3発売のアルバムではなく
11/17に発売されたライブ盤の1曲目になってしまっています。
→必要に応じてrelease_dateをチェックすると良さそうです。

- 実はApple Music ユーザー
🍎のAPIはSpotifyほど公開されていないため同じことをするのは難しそうです。。

## 今後
下記のようなアレンジができるとさらに使いやすいですね。
- 作成したPlaylist内のお気に入りArtistのみを逆にテキストとしてExportする（SNS投稿用）
- 各音楽メディアのレビューを集めた[AOTY](https://www.albumoftheyear.org/releases/)などのサイトからスクレイピングしてArtistリストを自動で作成する

## まとめ
Spotify APIはrate limitや商用利用制約があるものの、個人利用としては気軽に使えました。
こちらのツールを使って2024年も良い音楽との出会いを楽しみにしています🎼

## 参考文献

今回参考にさせていただいた記事はこちらです。
- [Spotipy(Spotify API), Pythonを用いて新譜を集めたプレイリストを(ほぼ)自動で作成](https://note.com/pmteasf/n/ne11f556d8c80)
- [PythonでSpotify APIから曲をプレイリストに追加する](https://sakanaaas.hateblo.jp/entry/2017/07/02/122740)
- [PythonでSpotify API [情報の文字列検索]](https://qiita.com/EkatoPgm/items/289b2efcdb5af49843c1)
- [Spotify APIでアーティストの全楽曲を取得する](https://programdoria.com/programming/getartistalltracksbyapi/)

## 人材募集

現在、Wanoグループ / TuneCore Japan では人材募集をしています。興味のある方は下記を参照してください。
Wano | [Wano Group JOBS](https://group.wano.co.jp/jobs/)
TuneCore Japan | [TuneCore Japan JOBS](https://www.tunecore.co.jp/jobs)

## コード全体
```Python:create_playlist.py

import spotipy
import spotipy.util as util
import json

#Spotify APIの認証部分 username, my_id, my_secret は人によって異なる
username = 'XXX' 
my_id ='XXX' 
my_secret = 'XXX' 
redirect_uri = 'http://localhost:8888/callback' 
scope = 'user-library-read user-read-playback-state playlist-read-private user-read-recently-played playlist-read-collaborative playlist-modify-public playlist-modify-private'
token = util.prompt_for_user_token(username, scope, my_id, my_secret, redirect_uri)
spotify = spotipy.Spotify(auth = token)

def main():

    playlists = spotify.user_playlist_create(username, '230603New')

    f = open('230603.txt', 'r')
    datalist = f.readlines()

    for name in datalist:
        if name == '\n':
            continue
        # 括弧より前までをArtist名とする
        idx = name.find('(')
        name = name[:idx]

        search_result = spotify.search(q=name, limit=10, offset=0, type='artist', market=None)
        artist_Id = search_result['artists']['items'][0]['id']
        
        # artist_idからalbumデータを取得
        album_results = spotify.artist_albums(artist_Id, limit=50, album_type='album')
        album_datas = album_results['items']
        while album_results['next']:
            album_results = spotify.next(album_results)
            album_datas.extend(album_results['items'])
        
        # 発売日の降順にソート
        album_sorted = sorted(album_datas, key=lambda x:x['release_date'], reverse=True)

        # album_idからalbumのtrackデータを取得
        tracks = []
        album_tracks = spotify.album_tracks(album_sorted[0]['id'])

        for track in album_tracks['items']:
            tracks.append(track['id'])

        # trackデータの1曲目をプレイリストに追加
        results = spotify.user_playlist_add_tracks(username, playlists['id'], [tracks[0]])

    f.close()

if __name__ == "__main__":
    main()


```