Spotifyの「お気に入りの曲」をプレイリストにコピーするツールを作成してみた。

Spotifyの「お気に入りの曲」はプレイリストではないので、友達と共有したり、[botから再生](https://qiita.com/katsuki_ono/items/ca491a5bdeca0c1b7b8d)出来ず、不便だと思っていました。

そこで、お気に入りの曲を全て一つのプレイリストにコピーするプログラムを作ってみました。

この記事では、下記の２つを記載します。
⒈手動で実行して、お気に入りの曲を全て一つのプレイリストにするプログラム(Google colab)
⒉自動で実行して、お気に入りの曲を全て一つのプレイリストにするプログラム(AWSのインスタンス)

この記事では、Google colab及びインスタンスイメージがubuntuのAWSのインスタンスを使用しています。
使用する言語はPythonです。

注意！！
このプログラムを実行すると「お気に入り」という名前のプレイリストが更新されるため、「お気に入り」という名前のプレイリストを使用されている場合には、プレイリストの名前を変更して頂くか、コード内の「お気に入り」を別の名前に変更して下さい。

# ⒈手動で実行して、お気に入りの曲を全て一つのプレイリストにするプログラム(Google colab) 
Google colabで新規ノートブックを開きます。

Spotifyをインストールします。
```
!pip install spotipy
```

下記のコードにSpotify APIのクライアントIDとクライアントシークレット、リダイレクトURLを設定して実行します。(クライアントIDとクライアントシークレットはSpotify APIのダッシュボードから取得します。リダイレクトURLはダッシュボードで設定したら、何でも良いです。詳しくは[こちら](https://qiita.com/katsuki_ono/items/1b56fb2d9a60a07f3777#spotify-apiの設定及び必要な情報の取得)をご覧ください。)
実行したら生成された認証URLを開き、Spotifyにログインして、同意するを押します。
同意後、リダイレクトされたURLをコピーしてAQから始まる「?code=」の後ろのコードをコピーして、フォームに入力します。
全てのコードが実行されると「お気に入り」という名前のプレイリストが作成され、全てのお気に入りの曲がコピーされます。
再度実行すると「お気に入り」のプレイリストの曲が最新のお気に入りの曲に更新されます。

注意！！
このプログラムを実行すると「お気に入り」という名前のプレイリストが更新されるため、「お気に入り」という名前のプレイリストを使用されている場合には、プレイリストの名前を変更して頂くか、コード内の「お気に入り」を別の名前に変更して下さい。

``` python
import spotipy
from spotipy.oauth2 import SpotifyOAuth

# Spotify APIのクライアントIDとシークレットを設定
client_id = ''
client_secret = ''
redirect_uri = ''

# 必要なスコープを指定
scope = 'user-read-recently-played playlist-read-private playlist-read-collaborative app-remote-control user-read-playback-state user-library-read user-modify-playback-state playlist-modify-public playlist-modify-private'

# 認証情報を取得するためのオブジェクトを作成
sp_oauth = SpotifyOAuth(client_id=client_id, client_secret=client_secret, redirect_uri=redirect_uri, scope=scope)

# ユーザーに認証を求めるために認証ページのURLを表示
auth_url = sp_oauth.get_authorize_url()
print(auth_url)

# ユーザーが認証後、自動的にアクセストークンを取得
token_info = sp_oauth.get_cached_token()
if not token_info:
    response = input("Enter the URL you were redirected to: ")
    code = sp_oauth.parse_response_code(response)
    token_info = sp_oauth.get_access_token(code)

# アクセストークンを取得し、認証オブジェクトを作成
token = token_info['access_token']
sp = spotipy.Spotify(auth=token)  # sp変数を定義


# お気に入りを移行するプレイリストを検索、作成
playlists = sp.current_user_playlists()
for playlist in playlists['items']:
    if playlist['name'] == "お気に入り":
        # 既にプレイリストが存在する場合は、プレイリストのIDを取得する
        playlist_id = playlist['id']
        break
else:
    # プレイリストが存在しない場合は、新しいフォルダを作成してプレイリストを作成する
    folder = sp.user_playlist_create(user=sp.current_user()['id'], name='お気に入り', public=False)
    playlist_id = folder['id']

# お気に入りの曲を取得
results = sp.current_user_saved_tracks()
tracks = results['items']
while results['next']:
    results = sp.next(results)
    tracks.extend(results['items'])

# 追加するプレイリストの曲を取得
p_tracks = sp.playlist_tracks(playlist_id)

# 追加するプレイリストの曲を削除する
track_ids = [track['track']['id'] for track in p_tracks['items']]
while track_ids:
    sp.playlist_remove_all_occurrences_of_items(playlist_id, track_ids[:100])
    track_ids = track_ids[100:]
    p_tracks = sp.playlist_tracks(playlist_id)
    track_ids = [track['track']['id'] for track in p_tracks['items']]

# 100曲ずつリクエストを分割してプレイリストに追加する
track_uris = [track['track']['uri'] for track in tracks]
for i in range(0, len(track_uris), 100):
    sp.playlist_add_items(playlist_id, track_uris[i:i+100])
```

実行後、Spotifyを開き、お気に入りの曲がコピーされたプレイリストを確認出来たら成功です！

# ⒉自動で実行して、お気に入りの曲を全て一つのプレイリストにするプログラム(AWSのインスタンス)
使用しているインスタンスの時間で、午前3時毎に毎日、最新のお気に入りの曲をプレイリストに更新するプログラムを実行中にします。

まず、Spotifyをインストールします。
```
sudo pip install spotipy
```

pipをインストールしていなければ、先に以下を実行します。

aptのアップデート
```
sudo apt update
```

pipのインストール
```
sudo apt install python3-pip
```

任意でインスタンスの時間を日本時間にします。

タイムゾーンをJSTに変更
```
 sudo timedatectl set-timezone Asia/Tokyo
```

システムクロックをハードウェアクロックに同期
```
sudo hwclock --systohc
```

このプログラム用のディレクトリを作成します。
```
mkdir ディレクトリ名
```

作成したディレクトリに移動します。
```
cd ディレクトリ名
```

作成したディレクトリでファイルを作成します。
```
nano ファイル名.py
```

作成したファイルの中に下記のコードを入れて、ctrl oで保存してエンターを押してから、ctrl xでファイルを閉じて下さい。 ※この際、Spotify APIのクライアントIDとクライアントシークレット、リダイレクトURLを設定して下さい。(クライアントIDとクライアントシークレットはSpotify APIのダッシュボードから取得します。リダイレクトURLはダッシュボードで設定したら、何でも良いです。詳しくは[こちら](https://qiita.com/katsuki_ono/items/1b56fb2d9a60a07f3777#spotify-apiの設定及び必要な情報の取得)をご覧ください。)

注意！！
このプログラムを実行すると「お気に入り」という名前のプレイリストが更新されるため、「お気に入り」という名前のプレイリストを使用されている場合には、プレイリストの名前を変更して頂くか、コード内の「お気に入り」を別の名前に変更して下さい。

``` python
import datetime
import requests
import base64
import sched
import time
import concurrent.futures
import threading
import spotipy
from spotipy.oauth2 import SpotifyOAuth

# Spotify APIのクライアントIDとシークレットを設定
client_id = ''
client_secret = ''
redirect_uri = ''

# 必要なスコープを指定
scope = 'user-read-recently-played playlist-read-private playlist-read-collaborative app-remote-control user-read-playback-state user-library-read user-modify-playback-state playlist-modify-public playlist-modify-private'

# 認証情報を取得するためのオブジェクトを作成
sp_oauth = SpotifyOAuth(client_id=client_id, client_secret=client_secret, redirect_uri=redirect_uri, scope=scope)

# ユーザーに認証を求めるために認証ページのURLを表示
auth_url = sp_oauth.get_authorize_url()
print(auth_url)

# ユーザーが認証後、自動的にアクセストークンを取得
token_info = sp_oauth.get_cached_token()
if not token_info:
    response = input("Enter the URL you were redirected to: ")
    code = sp_oauth.parse_response_code(response)
    token_info = sp_oauth.get_access_token(code)

# アクセストークンを取得し、認証オブジェクトを作成
token = token_info['access_token']
refresh_token = token_info['refresh_token']
sp = spotipy.Spotify(auth=token)  # sp変数を定義


def spotify_favorite():
    # お気に入りを移行するプレイリストを検索、作成
    playlists = sp.current_user_playlists()
    for playlist in playlists['items']:
        if playlist['name'] == "お気に入り":
            # 既にプレイリストが存在する場合は、プレイリストのIDを取得する
            playlist_id = playlist['id']
            break
    else:
        # プレイリストが存在しない場合は、新しいフォルダを作成してプレイリストを作成する
        folder = sp.user_playlist_create(user=sp.current_user()['id'], name='お気に入り', public=False)
        playlist_id = folder['id']

    # お気に入りの曲を取得
    results = sp.current_user_saved_tracks()
    tracks = results['items']
    while results['next']:
        results = sp.next(results)
        tracks.extend(results['items'])

    # 追加するプレイリストの曲を取得
    p_tracks = sp.playlist_tracks(playlist_id)

    # 追加するプレイリストの曲を削除する
    track_ids = [track['track']['id'] for track in p_tracks['items']]
    while track_ids:
        sp.playlist_remove_all_occurrences_of_items(playlist_id, track_ids[:100])
        track_ids = track_ids[100:]
        p_tracks = sp.playlist_tracks(playlist_id)
        track_ids = [track['track']['id'] for track in p_tracks['items']]

    # 100曲ずつリクエストを分割してプレイリストに追加する
    track_uris = [track['track']['uri'] for track in tracks]
    for i in range(0, len(track_uris), 100):
        sp.playlist_add_items(playlist_id, track_uris[i:i+100])


def refresh_spotify_token(sc):
    global refresh_token
    global client_id
    global client_secret
    global sp

    if refresh_token is not None:
        # Base64エンコードされたクライアントIDとシークレットを生成
        client_credentials = f"{client_id}:{client_secret}"
        client_credentials_b64 = base64.b64encode(client_credentials.encode()).decode()

        # POSTリクエストのパラメータを設定
        token_url = 'https://accounts.spotify.com/api/token'
        token_data = {
            'grant_type': 'refresh_token',
            'refresh_token': refresh_token
        }

        # POSTリクエストを送信して、アクセストークンを取得
        token_headers = {
            'Authorization': f'Basic {client_credentials_b64}'
        }
        response = requests.post(token_url, data=token_data, headers=token_headers)
        response_data = response.json()

        # 新しいアクセストークンを取得
        token = response_data['access_token']
        sp = spotipy.Spotify(auth=token)

        # 次回の実行を30分後にスケジュール
        s.enter(1800, 1, refresh_spotify_token, (s,))

    else:
        s.enter(0, 1, refresh_spotify_token, (s,))

# スケジュール
s = sched.scheduler(time.time, time.sleep)
# 最初の実行をスケジュール
s.enter(0, 1, refresh_spotify_token, (s,))


def function1():
    while True:
        # 現在の時刻を取得
        now = datetime.datetime.now()

        # 毎日午前3時に実行するように設定
        if now.hour == 3:
            spotify_favorite()

        # 次の日の3時まで待機
        tomorrow = now + datetime.timedelta(days=1)
        tomorrow_morning = datetime.datetime(year=tomorrow.year, month=tomorrow.month, day=tomorrow.day, hour=3)
        time.sleep((tomorrow_morning - now).seconds)

def function2():
    s.run()

if __name__ == "__main__":
    with concurrent.futures.ThreadPoolExecutor() as executor:
        future1 = executor.submit(function1)
        future2 = executor.submit(function2)

        # スレッド1~2の両方が終了するまで待機する
        concurrent.futures.wait([future1, future2])
```

一度、上手くファイルが作成されているか下記のコマンドで確認します。
```
find ~
```

上手くファイルが作成されていたら、screenを作成します。
```
screen -S スクリーン名
```

screen内でpythonで作成したファイルを実行します。
```
python3 ファイル名.py
```

実行したら生成された認証URLを開き、Spotifyにログインして、同意するを押します。
同意後、リダイレクトされたURLをコピーしてAQから始まる「?code=」の後ろのコードをコピーして、フォームに入力します。
全てのコードが実行されるとインスタンスの時間で午前3時に、「お気に入り」という名前のプレイリストが作成され、全てのお気に入りの曲がコピーされます。
次の日のインスタンスの時間で午前3時からは、「お気に入り」のプレイリストの曲が最新のお気に入りの曲に更新されます。

# 最後に
このプログラムはSpotify好きには、とても便利なのではないかなと思います。
私は重宝しています。
また何か作ってみます。