皆さん、Spotify を使っていますか?
私はほぼ毎日使っています。レコメンドシステムがすごいですよね。
実は Spotify は様々な API を提供していて、その中には Personalization API という、自分のお気に入りのアーティストや曲の情報を取得する API もあるのです。この API を使えば、自分がどんなアーティストが好きかを自己紹介するのに使えます!
この画像を見てください。
これは私のお気に入りのアーティストから作成されたワードクラウドです。ワードクラウドとは、文章中で出現頻度が高い単語を選び出し、その頻度に応じた大きさで図示する手法です。今回は、API で取得されたアーティストのデータのうち上位にあったものをより大きな文字にしています。
というわけで、こんなワードクラウドを自動で作る Web アプリを作ってみました。↓↓↓
Spotify のアカウントでログインするだけで、自動でワードクラウドが作成されます。また、作った画像をこんな風にツイートすることもできます。
色々な人のワードクラウドが見てみたいので、是非皆さんにも使っていただければと思います。
以下、このアプリを Flask で作る上でのポイントについて述べます。ソースコードは
のようになっています。
ワードクラウドの作成は Python の word_cloud で
ワードクラウドを作るライブラリとして、Python の word_cloud モジュールを使うか、D3.js の D3-cloud というプラグインを使うかで少し悩みました。D3.js の場合、クライアントサイドの JavaScript で描画できるというメリットはありましたが、word_cloud の方が配色がきれいだと感じたので、結局サーバーサイドでワードクラウドを作成する API を立てることにしました。
ちなみに word_cloud の配色の指定は、matplotlib のカラーマップの指定と全く同じです。
ワードクラウドの作成は
data = spotify.get("/v1/me/top/artists?limit=50").json()
for i, item in enumerate(data['items']):
for k in range((50-i)//10):
text += item['name']
text += " "
wc = WordCloud(font_path='/app/.fonts/ipaexg.ttf', width=1024, height=576, colormap='cool', stopwords=set()).generate(text)
このような感じでやっています。
- 上位のアーティスト名ほど、ワードクラウドの元となる文字列により多く加えて頻度を高くする
- 日本語が文字化けしないように日本語フォントを指定してあげる
- デフォルトだと接続詞や be 動詞のような頻度が高いが意味があまりない単語(自然言語処理界隈でストップワードと呼ばれている)はワードクラウドで使わないようにされているものの、アーティスト名の中のストップワードは重要であり使用したいため、
stopwords
は空集合にする
などの工夫を入れています。
2021年1月現在、もう少し細かいロジックを加えています。詳しくはソースコードをご覧ください。
Spotify の認証は flask_dance で
そもそも Flask でウェブアプリを作るのが初めてだったのですが、この flask_dance は分かりやすい API と豊富なプロバイダが提供されており、使う上で安心しました。
例えば Spotify に関しては
にある通りにメソッドを呼び出せばよく、
app.secret_key = environ.get("SECRET_KEY")
app.config["SPOTIFY_OAUTH_CLIENT_ID"] = environ.get("SPOTIFY_OAUTH_CLIENT_ID")
app.config["SPOTIFY_OAUTH_CLIENT_SECRET"] = environ.get("SPOTIFY_OAUTH_CLIENT_SECRET")
spotify_bp = make_spotify_blueprint(scope="user-top-read")
app.register_blueprint(spotify_bp, url_prefix="/login")
このような感じになりました。
ちなみに、Spotify API を呼び出す際に注意せねばならないのはスコープです。今回使いたい、お気に入りのアーティスト・曲を取得する API では user-top-read
というスコープを指定する必要があるので
spotify_bp = make_spotify_blueprint(scope="user-top-read")
となっているのです。
画像つきツイートは tweepy で
2020年4月現在、画像付きツイートを Twitter で行う流れは、まず
POST https://upload.twitter.com/1.1/media/upload.json
で画像をアップロードして media_id
を得た後、通常のツイート投稿 API
POST https://api.twitter.com/1.1/statuses/update.json
に media_id
をパラメータで含めるという、二段構成になっています。
最初は Twitter の認証も flask_dance で行うつもりだったのですが、Twitter への画像アップロードの方が上手くいかず、断念しました。。。(エントリポイントが違うから上手くいかなかったような気がしますが、原因は謎でした)
結局、Python の Twitter API ラッパーとして昔から定評のある tweepy を使って解決しました。以下のように2行で画像付きツイートができます。
res = api.media_upload(filename)
api.update_status("Spotifyで自己紹介!\n#Spotify_Wordcloud\nhttps://spotify-wordcloud.herokuapp.com/", media_ids=[res.media_id])
余談ですが、Twitter のような変化の激しい API だと、ちょっとメンテされていない間にライブラリが陳腐化しそうなので、怖いですね。。。tweepy は現在もきちんとメンテされているようなのでよかったです。
2021年1月現在、OGP画像でツイートするようにしたため、Twitter認証は不要になりました。
セキュリティ面の対策は flask-talisman や flask-seasurf で
flask-talisman は主に HTTP ヘッダ関連のセキュリティ対策(Content Security Policy とか)を行うやつです。
といっても、CSP をあんまり強くしてしまうと Spotify の inline script とかが全部ダメになってしまうので、unsafe-inline
を入れざるを得なかったのですが。。
Flask-SeaSurf は CSRF 対策のライブラリです。今回は外部認証を経由しない POST が無いので、トークンを html 中には入れていないのですが、今後内部的な POST/DELETE を用意する際には CSRF トークンを入れてあげると良さそうです。
他にもセキュリティ的にこうした方がいいんじゃない?みたいなツッコミがあれば是非コメント欄にお願いします。
2021年1月現在、Flask-SeaSurf ではなく Flask-WTF を使っています。こちらのライブラリの方がテストが書きやすいです。
おわりに
Flask を使うのは初めてだったのですが、1日半程度で自分の欲しかったものが実現できたのでよかったです。
そもそもこのアプリを作った動機として、どんな音楽が好きなの?と尋ねられた際にいまいち上手く答えられなかった、ということがありました。このアプリを使えば、好きな音楽をビジュアルでアピールすることができます。
今後ですが、作成したワードクラウドの画像を S3 のようなストレージに保存できるようにし、これまで作ったワードクラウド一覧をDBから閲覧できるようにすることで、音楽の趣味の変遷を確認できるような機能を実装することを 検討しています。
2021年1月現在、Google Cloud Storage に画像を保存できるようにしています。