蛇ノ目の記

技術のことも。そうでないことも。

PyCon mini Sapporo 2019で登壇した - Simple-Spotify: Pythonでシンプルに楽曲データを扱うライブラリ

5月11日に札幌で開催されたPyCon mini Sapporo 2019で登壇した。

写真撮る人がめっちゃ上手くて影とかいい感じになっててすごい。正装(オサカナTシャツ)もばっちり写っている。

テーマは3ヶ月くらい前から作っていたSpotify Web APIのラッパーライブラリSimple-Spotify。懇親会ではUKロック好きな@shinyorkeとSimple-Spotifyのいい感じな使い方の話で盛り上がった。興味を持ってもらえてとても嬉しかった。

github.com

developer.spotify.com

Spotify Web APIのラッパーライブラリとしてはSpotipyがあるが、requestsに依存しているそれとは異なりSimple-SpotifyはPure Pythonで実装している。 また、SpotipyがAPIのレスポンスを辞書形式で扱っているのに対してSimple-Spotifyではクラスとして扱っている。

Simple-SpotifyとSpotipyの違いを見比べてみる。ここからは発表にはない話になる。

Spotipy

import spotipy
sp = spotipy.Spotify()

results = sp.search(q='weezer', limit=20)
for i, t in enumerate(results['tracks']['items']):
    print ' ', i, t['name']

Simple-Spotify

from simple_spotify.api import Spotify
from simple_spotify.authorization import ClientCredentialsFlow

res = ClientCredentialsFlow.token_request(CLIENT ID, CLIENT_SECRET)
auth = ClientCredentialsFlow(**res)
sp = Spotify(auth)

results = sp.search(q='sora tob sakana', market='JP')
for album in results.albums.items:
    print(album.name)
sora tob sakana
World Fragment Tour
New Stranger
alight ep
cocoon ep
魔法の言葉
夜空を全部
アルファルド

sora tob sakanaはいいぞ。

Spotipyでは認証を行っていないんだけど、Web APIのドキュメントにはすべてのリクエストは認証が必要、と書いてあるのでサンプルコードが古い可能性がある。

Authentication

All requests to Web API require authentication.

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

認証を含めなければ行数はほぼ同じ。 検索結果(results)オブジェクトにアルバム(albums)属性があって、さらにそれぞれのアルバム(items)がある、というのはそこそこ直感的でないかと思っている。

認証について言えば、認証用のエンドポイントからのレスポンスを一度受け取ってから、それをアンパックして認証クラスに渡すというのはちょっとわかりにくい流れになってしまった。 本当のところを言えば、認証用クラスにClient IDとClient Secretを渡せばOKという風にしたかったのだけど、もう一つの認証をWebアプリ上で使えるようにする関係でそれと同じ流れにした。

これがFlaskで作成したSimple-Spotifyを使った簡単なWebアプリ。

@app.route('/')
def top():
    if 'response' in session.keys():
        auth = AuthorizationCodeFlow(**session['response'])
        sp = Spotify(auth)
        user = sp.get_current_user_profile()
        top_artists = sp.get_users_top('artists', time_range='medium_term')
        artists = top_artists.items
        top_tracks = sp.get_users_top('tracks', time_range='medium_term')
        tracks = top_tracks.items

        return render_template('index.html', name=user.display_name, artists=artists, tracks=tracks)
    else:
        seed = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
        url = access_authorize_page(CLIENT_ID, REDIRECT_URI, SCOPES, seed)
        return render_template('index.html', auth_url=url)


@app.route('/callback/')
def callback():
    """
    callback
    """
    session['response'] = AuthorizationCodeFlow.token_request(
        CLIENT_ID, CLIENT_SECRET, REDIRECT_URI, request.args['code'])
    return redirect(url_for('top'))

Spotifyへのログインをしてからアクセストークンを受け取るのだけど、アクセストークンの取得をtop()で行ってしまうとリロードやページ遷移の度にトークンを取りに行こうとしてAPIからエラーが返ってきてしまった。これを避けるためにコールバックでアクセストークンなどを受け取って、セッションに格納。top()でそれを使うという流れにした。 これには認証方法によってSimple-Spotifyの使い方に違いが出てしまうのを避けたかったという思いがある。

と言い訳めいたことを書いてから、実際にSimple-Spotifyの使い方などを書きたいと思うのだけど寒いのでしばらくしてから続きを書く。 なにしろこんなところで書いているので風が冷たい。