Slackに投稿したアーティストの最新アルバムをSpotifyのプレイリストへ自動登録する

普段、TV・ラジオ・CDショップ・音楽雑誌・店頭BGMなどで発売されたばかりの良い音楽に出会った際に、メモに残しておいて後からSpotifyで検索して聞いています。しかし、メモに残したアーティスト名を1つ1つ検索していくのは面倒だなあと感じていました。

ということで、Slackにアーティスト名を投稿するだけで、入力したアーティストの最新アルバムがSpotifyのプレイリストに追加されるようにします。

前提

  • 実行環境にAmazon Web ServiceのLambdaを利用します。
  • Pythonのバージョンは3.6を利用しています。

1. 準備

Amazon Web Service(AWS)

SlackからAPI Gatewayに対してPOSTしたアーティスト名を、Lambdaで処理する構成とします。勉強がてら、取得した最新のtokenをDynamoDBに保管する構成としています。
構成概要.png

以下を参考としました。LambdaやAPI Gatewayの設定方法は、本稿では割愛します。
* 【AWS】Lambdaでpipしたいと思ったときにすべきこと
* SlackからAWS API Gatewayを通してLambdaを起動するまで
* Python で DynamoDBを使う

Spotify

  • https://developer.spotify.com/my-applications でCREATE AN APPを行い、CLIENT_IDCLIENT_PWを取得します。
  • 楽曲を追加するプレイリストのPLAYLIST_IDを取得します。プレイリストURLの{playlist_id}の部分です。
    • https://open.spotify.com/user/{user_id}/playlist/{playlist_id}
  • pip install spotipy でPython用のSpotifyライブラリを取得しておきます。

Slack

  • 利用するチャンネルに対して、Outgoing Webhooksを適用します。URL(s)にはPOSTを受け取ることができるよう設定したAPI GatewayのAPIエンドポイントを入力します。
  • アーティスト名を検索して見つからなかった際に、チャンネルに「見つかりませんでした。」のメッセージを返すためのAppを作っておき、Webhook URLを取得します。
  • pip install slackweb でPython用のSlackライブラリを取得しておきます。

2. token取得とDB格納

Spotifyのプレイリスト操作を行うために、access_tokenを取得する必要があります。Spotifyのaccess_tokenは1時間でリセットされてしまうため、Slackでアーティスト名を投稿をする度に、新しいaccess_tokenを取得するような設計にします。

tokenの取得

初めてのtoken取得時には、確認画面が立ち上がり確認を求められるため、最初だけローカル環境でOAuth認証を通します。以後はtoken再発行用の文字列であるrefresh_tokenが与えられるため、こちらを利用してaccess_tokenを再取得します。

先ずは、以下をローカル環境にて実行します。

gettoken.py
import spotipy.util as util


# SpotifyTokenに必要となるパラメータ情報を全て格納します
class SpotifyToken(object):
    def __init__(self):
        self.username = 'username'  # Spotifyに登録しているユーザーネーム
        self.client_id = 'CLIENT_ID'
        self.client_secret = 'CLIENT_PW'
        self.redirect_url = 'http://localhost:8080/'
        self.scope = 'playlist-modify-public'
        self.playlist_id = 'PLAYLIST_ID'
        self.slack_channel_url = "https://hooks.slack.com/services/XXX~" # Slackに「見つかりませんでした」を返すためのWebhook URL


user = SpotifyToken()
token = util.prompt_for_user_token(username=user.username, scope=user.scope,
                                   client_id=user.client_id, client_secret=user.client_secret,
                                   redirect_uri=uesr.redirect_uri)

上記を実施後、確認画面が立ち上がるので、OKをクリックしてください。

tokenをDynamoDBに格納

その後、tokenの内容を確認します。

token.json
{
  "access_token": "XXXXXX",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": null,
  "expires_at": XXXXXX,
  "refresh_token": "XXXXXXX"
}

tokenの再取得に必要となるのは、refresh_tokenだけなので、DBを利用する必要はないのですが、今回は勉強のためDynamoDBにtokenを格納してみます。

プライマリパーテションキーをtokenと定め、"token":'key'を要素の1つとして加えて、jsonファイル内のデータを1つずつ1行でAWSコンソールから格納していきます。

DynamoDB.png

次に、DynamoDBからrefresh_tokenを読み込み、新しいaccess_tokenを取得するコードを記述します。また、DynamoDBに格納されている内容も、新しいtokenの内容に書き換えます。

addtracks.py(1)
import boto3
from spotipy.oauth2 import SpotifyOAuth


# AWSコンソールから作成したテーブルを指定します。
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('your_table_name')


class SpotifyToken(object):
    # --- getToken.pyと同内容のため省略 ---


def lambda_handler(event, context):
    user = SpotifyToken()
    oauth = SpotifyOAuth(client_id=user.client_id, client_secret=user.client_secret,
                        redirect_uri=None)
    access_token = get_new_access_token(oauth)


# 新しいtokenを取得する関数
def get_new_access_token(oauth):
    refresh_token = load_dynamodb()
    new_token = oauth.refresh_access_token(refresh_token)
    update_dynamodb(new_token)
    access_token = new_token['access_token']
    return access_token


# DynamoDBからrefresh_token読み込む関数
def load_dynamodb():
    response = table.scan()
    refresh_token = response['Items'][0]['refresh_token']
    return refresh_token


# DynamoDBの内容を更新する関数
def update_dynamodb(new_token):
    table.put_item(
        Item={
            'token':'key',
            'access_token': new_token['access_token'],
            'token_type': new_token['token_type'],
            'expires_in': new_token['expires_in'],
            'scope': new_token['scope'],
            'expires_at': new_token['expires_at'],
            'refresh_token': new_token['refresh_token']
        })

3. プレイリスト操作

ここからは、本題のプレイリストへ楽曲を登録する操作の部分です。

Slackから投稿されたアーティスト名は、API Gatewayを経由して、lambda_handler関数の引数であるeventに渡されます。

event['text']に格納されたアーティスト名をSpotifyで検索を行い、アーティストの最新作を取得して、プレイリストへ加えます。

また、該当のアーティストが見つからない場合は、Slackへ「見つかりませんでした」と投稿します。

addtracks.py(2)
import spotipy
import slackweb


def lambda_handler(event, context):
    # --- (1)の内容は省略 ---
    # (1)で取得したaccess_tokenからSporifyオブジェクトを生成
    sp = spotipy.Spotify(auth=access_token)
    sp.trace = False
    # API Gatewayから渡されたアーティスト名を取り出す
    search_word = event['text']
    add_tracks(sp, user.username, user.playlist_id, user.slack_channel_url, search_word)


# アーティストの最新のアルバムをプレイリストに投稿する関数
def add_tracks(sp, username, playlist_id, slack_channel_url, search_word):
    # アーティスト名で検索を実施
    try:
        result = sp.search(q='artist:' + search_word, type='artist')
        # アーティストIDの取得
        artist_id = result['artists']['items'][0]['id']
        # アーティストの最新のアルバムを取得
        albums = sp.artist_albums(artist_id)
        most_latest_album = albums['items'][0]['id']
        # 最新アルバムに収録されている全曲のURIを取得
        album_tracks = sp.album_tracks(most_latest_album)
        track_uris =[]
        for i in range(len(album_tracks['items'])):
            track_id = album_tracks['items'][i]['uri']
            track_uris.append(track_id)
        # プレイリストへ楽曲を登録
        sp.user_playlist_add_tracks(username, playlist_id, track_uris)
    # アーティスト名が見つからない場合、Slackへ通知
    except:
        post_to_slack(slack_channel_url)


# Slackに「見つかりませんでした」を投稿する関数
def post_to_slack(slack_channel_url):
    slack = slackweb.Slack(url=slack_channel_uri)
    slack.notify(text="見つかりませんでした")

4. 完成

出来上がったコードを利用するライブラリと一緒に、zip形式でLambdaにアップロードしたら完成です。

Slackからアーティスト名を投稿すると、
slack1.png

プレイリストに反映されています。
spotifyplaylist.png

アーティスト名が見つからない場合、「見つかりませんでした」と帰ってきます。
slack2.png

これで、お出掛け中に街で出会った新しい音楽をSlackから投稿しておくだけで、帰りの電車の中で既に出来あがったプレイリストを楽しむことができます。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.