この記事はニフクラ等を提供している、富士通クラウドテクノロジーズ Advent Calendar 2022の14日目の記事です。
前日は@George22eさんのヴァイオリンのヴィブラートをtartiniを使って可視化し、改善に役立てた話でした。
ヴァイオリンのヴィブラートの改善にソフトを使うという発想は今までにない気がして、とても素敵だなと思いました。
自分も学生の頃に合唱をしていたので、歌声のヴィブラートも可視化できるのか気になるのでtartiniを使ってみたいです。
はじめに
みなさんは普段音楽を聴くときにサブスクリプションサービスは利用しますか?自分はSpotifyをよく活用しています。
Spotifyでは毎年年末にSpotifyまとめというその年の利用状況を振り返る内容を見ることができ、その情報によると2022年は32,186分 = 536.433333時間 = 22.351388875日
もの時間Spotifyで音楽を聴いていたようです😯
そんなSpotifyですが、Web APIが公開されています。
https://developer.spotify.com/documentation/web-api/
(このSpotify APIを知ったのは、出身校の後輩が使っていたからでした。一度どこかで使ってみたいなとネタを考えていました。)
https://github.com/NNCT18J/over-sound-lightup
また、自分は新入社員なのですが、新人研修内の開発演習でSlackbotを作成しました。その経験を活かし、Spotify APIをSlackbotから使ってみよう!と思いました。
そこで、spotify slackbot
でGoogle検索してみると・・・
ふむふむ、よさそうな記事があるな
リンクポチー
あれ?弊社のアドベントカレンダーの記事じゃん!!!
という経緯で運命を感じたので、上記の@sasachi1231さんの記事を参考にしながら、自分が現在聴いている曲をSlackに投稿するSlackbotを作ってみようと思いました。
同じものを作るのではつまらないので
- Boltを利用する
- Slackのステータスに現在再生している曲を表示する
この2つを目標にやってみることにしました。
Bolt
Bolt is the swiftest way to start programming with the Slack Platform in JavaScript, Python, or Java.
https://api.slack.com/tools/bolt
Bolt は Slack アプリ開発のための公式フレームワークです。JavaScript (Node.js)、Python 、Java で利用することができます。
https://api.slack.com/lang/ja-jp
BoltはSlack公式のフレームワークのため、現在Slackbotを新しく作ろうとする方は主にBoltを利用されるかと思います。
また、Slack APIのページにもBoltからAPIを利用するメソッドが記述していたりします。
(BoltでAPIにアクセスするメソッドが記述している。)
https://api.slack.com/methods/users.profile.set
Slackのステータスに表示
Spotify APIとSlackの活用方法について調べていたとき、Slackのステータスに現在聴いている曲をリンクするという記事を見つけました。
https://medium.com/do-you-write-a-blog/slackのstatusにspotifyの曲-アーティスト情報をリンクする-9b94b17fb05c
Slackのステータスに表示しておけば、いつでも自分の聴いている曲をアピールできるな!と思ったので、こちらも実装したいと思いました。
botの動作フローと構成
こちらは参考にした元記事の内容をもとに書くと
Slash Commandsでbotを呼び出す → Spotifyで現在再生している曲をAPI経由で取得してくる → 取得結果から曲名とアーティスト名をPost → Slackのステータスに設定する
という形になります。botにリプライ(メンション)を飛ばす形式からスラッシュコマンド(Slash Commands)でbotを呼び出す形式にしました。
これは、Boltでスラッシュコマンドを利用するサンプルやスラッシュコマンドに関するドキュメントがしっかりあったり、利用しやすそうなのでスラッシュコマンドで呼び出してみることにしました。
botにメンションをして呼び出す方法がわからなくて変えたわけではないです。
スラッシュコマンドについて詳しくは、以下を確認してください。
https://slack.dev/bolt-python/ja-jp/concepts#commands
https://api.slack.com/interactivity/slash-commands
botはPythonで動かし、以下のパッケージを使用しています。
- slack_bolt
- 前述したBoltフレームワーク。
- spotipy
- PythonでSpotify APIを利用するためのライブラリ。
- PythonでSpotify APIを利用する記事を検索するとだいたいこれを使っている。
- Spotify APIの公式ドキュメント内にも記載がある
作り方
Slackbotの追加方法とSpotify APIの利用開始方法の詳細説明は省略します
-
Slackbotの追加方法について参考
- Bolt入門ガイドの「アプリを作成する」
-
Spotify APIの利用開始方法について参考
-
https://developer.spotify.com/dashboard/
- ここから利用開始
- 公式ドキュメント Web API Tutorialの「Set Up Your Account」と「Register Your Application」
- 元記事にも書いてあります
-
https://developer.spotify.com/dashboard/
Slackbotの事前設定
botを動かすにあたって必要な設定について記述します。
botに必要なスコープ
アプリのOAuth & Permissionsから設定します。
詳しくはBolt入門ガイドの「トークンとアプリのインストール」を参照してください。
https://slack.dev/bolt-python/ja-jp/tutorial/getting-started#tokens-and-installing-apps
ここで、User OAuth TokenとBot User OAuth Tokenを取得できるようになります。
また、Socket Modeも有効にしてください。
Bot Token Scopes
-
commands
- スラッシュコマンドを利用するために必要
User Token Scopes
-
users.profile:write
- Slackのステータスを変えるのに必要
スラッシュコマンドの作成
アプリのSlash Commandsから新しいコマンドを作成できます。コマンドをアプリを実行する前に作成しておきましょう。
詳しくはSlack APIのスラッシュコマンドに関するページの「Creating a Slash Command」を参照してください。
https://api.slack.com/interactivity/slash-commands#creating_commands
- Command
- /np
- コマンド名はお好みで大丈夫です。(今回は元記事で
@botの名前 np
で実行しているためこちらにしました)
- コマンド名はお好みで大丈夫です。(今回は元記事で
- /np
Spotify APIの事前設定
クライアントIDとクライアントシークレットを入手するためにアプリ登録をしたと思います。
https://developer.spotify.com/documentation/general/guides/authorization/app-settings/
登録したアプリのEDIT SETTINGSからRedirect URIsを次のように設定してください。
https://example.com/callback/
(このURLはユーザー認証時に利用するのですが、EDIT SETTINGSの例として挙げられていたexample.comでも問題なく動作したのでこの設定にしています。)
サーバの準備
実行環境
実行環境はPythonが動けば基本問題ないですが、Dockerだと問題が生じます(後述)
自分はニフクラコンピューティングのサーバー上のUbuntuで実行を行いました。
(.venv) student@ubuntu:~/working/spotipy$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04 LTS
Release: 20.04
Codename: focal
(.venv) student@ubuntu:~/working/spotipy$ pip3 --version
pip 20.0.2 from /home/student/working/spotipy/.venv/lib/python3.8/site-packages/pip (python 3.8)
(.venv) student@ubuntu:~/working/spotipy$ pip3 list
Package Version
------------------ ---------
slack-bolt 1.16.0
slack-sdk 3.19.5
spotipy 2.21.0
(一部省略)
Python仮想環境の準備
Bolt入門ガイドの「プロジェクトをセットアップする」を参考にしながら行います。
https://slack.dev/bolt-python/ja-jp/tutorial/getting-started#setting-up-your-project
まず、作業用のディレクトリを未作成であれば作成し、ディレクトリ内に移動します。(ディレクトリ名は任意です。)
student@ubuntu:~/working$ mkdir spotipy
student@ubuntu:~/working$ cd spotipy
次に、Python仮想環境を用いて仮想環境を作成し、アクティブにします。
student@ubuntu:~/working/spotipy$ python3 -m venv .venv
student@ubuntu:~/working/spotipy$ source .venv/bin/activate
こちらを実行すると、shellに(.venv)と表示されるようになります。
which python3
を実行すると、仮想環境がアクティブになっていることが確認できます。
(.venv) student@ubuntu:~/working/spotipy$ which python3
/home/student/working/spotipy/.venv/bin/python3
トークンの環境変数への保存
こちらもBolt入門ガイドの「プロジェクトをセットアップする」を参考にしながら行います。
https://slack.dev/bolt-python/ja-jp/tutorial/getting-started#setting-up-your-project
SlackアプリやSpotify APIの各ページから以下のトークンをコピーします
Slackアプリ
- User OAuth Token (xoxpから始まる, OAuth & Permissionsページから確認可能)
- Bot User OAuth Token (xoxbから始まる, OAuth & Permissionsページから確認可能)
- App-Level Tokens(xappから始まる, Basic Informationページから確認可能)
- User ID
- 取得方法参考: https://scheduling.help.receptionist.jp/slack-id
- 自分のユーザーIDをコピーしてください。
Spotify API
- ユーザー名(https://www.spotify.com/jp/account/overview/ から確認可能)
- Client ID(https://developer.spotify.com/dashboard/ で作成したAPP内から確認可能)
- Client Secret(Client IDと同様のページからSHOW CLIENT SECRETを押すと確認可能)
これらを環境変数に保存します。環境変数に保存することで、プログラムから安全に利用することができます。
(.venv) student@ubuntu:~/working/spotipy$ export SLACK_USER_TOKEN=(User OAuth Token)
(.venv) student@ubuntu:~/working/spotipy$ export SLACK_BOT_TOKEN=(Bot User OAuth Token)
(.venv) student@ubuntu:~/working/spotipy$ export SLACK_APP_TOKEN=(App-Level Tokens)
(.venv) student@ubuntu:~/working/spotipy$ export SLACK_USER_ID=(User ID)
(.venv) student@ubuntu:~/working/spotipy$ export SPOTIFY_USER_NAME=(ユーザー名)
(.venv) student@ubuntu:~/working/spotipy$ export SPOTIFY_CLIENT_ID=(Client ID)
(.venv) student@ubuntu:~/working/spotipy$ export SPOTIFY_CLIENT_SECRET=(Client Secret)
Pythonパッケージのインストール
こちらもBolt入門ガイドの「プロジェクトをセットアップする」を参考にしながら行います。
https://slack.dev/bolt-python/ja-jp/tutorial/getting-started#setting-up-your-project
pipを用いてBoltとspotipyのインストールを行います。
(.venv) student@ubuntu:~/working/spotipy$ pip3 install slack_bolt
(.venv) student@ubuntu:~/working/spotipy$ pip3 install spotipy
これでプログラムを動かす事前準備は完了です。
プログラム
以下がSlackbotを動かすためのPythonプログラムのソースコードです。
import os
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler
import spotipy
# ボットトークンとソケットモードハンドラーを使ってアプリを初期化します
# https://slack.dev/bolt-python/ja-jp/tutorial/getting-started#setting-up-your-projectを参照
app = App(token=os.environ.get("SLACK_BOT_TOKEN"))
@app.command("/np")
def np_command(ack, respond, command, body, client, say):
ack()
# Slackアプリ関連
my_user_id = os.environ.get("SLACK_USER_ID")
# Spotify API関連
user_name = os.environ.get("SPOTIFY_USER_NAME")
scope = "user-read-currently-playing"
client_id = os.environ.get("SPOTIFY_CLIENT_ID")
client_secret = os.environ.get("SPOTIFY_CLIENT_SECRET")
redirect_uri ="https://example.com/callback/"
token = spotipy.oauth2.SpotifyOAuth(client_id=client_id,
client_secret=client_secret,
redirect_uri=redirect_uri,
scope=scope,
username=user_name,
open_browser=False)
spotify = spotipy.Spotify(auth_manager=token)
current_track = spotify.current_user_playing_track()
if body["user_id"] == my_user_id:
if type(current_track) == dict:
# NowPlayingの内容をbotがチャンネルに投稿
say("NowPlaying: " + current_track["item"]["name"] + " - " +
current_track["item"]["artists"][0]["name"] + "\n" +
current_track["item"]["external_urls"]["spotify"] + "\n" +
current_track["item"]["album"]["images"][1]["url"]
)
# Slackのステータスを変更
client.users_profile_set(token=os.environ.get("SLACK_USER_TOKEN"), profile={
"status_text": current_track["item"]["name"] + " - " + current_track["item"]["artists"][0]["name"],
"status_emoji": ":headphones:",
"status_expiration": "0"
})
respond("ステータスに設定しました!")
else:
respond("何も再生してないよ")
else:
respond("きみ誰?")
# アプリを起動します
# https://slack.dev/bolt-python/ja-jp/tutorial/getting-started#setting-up-your-projectを参照
if __name__ == "__main__":
SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start()
実行
では、作成したプログラムを実行してみましょう。shellから以下のコマンドで実行します。
(.venv) student@ubuntu:~/working/spotipy$ python3 app.py
プログラムを実行したら、botをチャンネルに招待し、チャンネルに/np
と送信してみましょう。
初回実行時はbotからすぐレスポンスは返されず、実行したshell上にこんなメッセージが出ると思います。
(.venv) student@ubuntu:~/working/spotipy$ python3 app.py
⚡️ Bolt app is running!
Go to the following URL: https://accounts.spotify.com/authorize?・・・(以下省略)
Enter the URL you were redirected to:
「Go to the following URL」と表示されたURLにアクセスすると、以下のようなSpotifyのログイン画面が表示されると思います。
こちらにログインすると、アプリケーションの認証を行ってよいか確認されるので、自分の作成したアプリで間違いなければ同意しましょう。
すると、以下のような https://example.com/ にアクセスした時と同じ画面が表示されると思います。
このときブラウザのアドレスバーのURLが重要で、以下のような内容になっているはずです。こちらをコピーします。
https://example.com/callback/?code=・・・(以下省略)
このURLをshellにペーストし、Enterキーを押すと、spotipyのユーザー認証が成功します。
すると、app.pyと同じディレクトリ内にキャッシュが生成されます。
(.venv) student@ubuntu:~/working/spotipy$ ls -la
total 20
drwxrwxr-x 3 student student 4096 Dec 8 16:25 .
drwxrwxr-x 4 student student 4096 Dec 8 15:20 ..
-rw-rw-r-- 1 student student 2962 Dec 8 16:21 app.py
-rw-rw-r-- 1 student student 485 Dec 8 16:25 .cache-(Spotifyのユーザー名)
drwxrwxr-x 6 student student 4096 Dec 8 15:28 .venv
このキャッシュがあれば、次回からは認証は不要です。再度プログラムを実行し直し、/np
と送信してみましょう。
すると、botからレスポンスが返され・・・
自分が今Spotifyで聴いている曲が表示されました!
SlackはSpotifyのリンクを自動的にプレビューしてくれるので、それっぽく見えます。また、アルバムアートワーク(いわゆるCDジャケット)の画像URLもSpotify APIで取得して、プレビューとして表示されるのもいい感じ。
(プレビュー部分はアルバムアートワークの画像がQiitaに載せると著作権等の問題がある可能性があるためSlack上で削除しています。)
また、「ステータスに設定しました!」というメッセージがbotから返されているので、Slackの自分のステータスを確認すると・・・
ちゃんと設定できている!
これで自分の聴いている曲をいつでもアピールできますね。
(自分のSlackの表示名右横のemojiにマウスカーソルを合わせても見れます。)
(他のメンバーがダイレクトメッセージを送ろうとするときにも見れます。)
つまったところ
何箇所か開発中につまったところがあるので、参考になればと思い記載しておきます
spotipyでのユーザー認証
今回、Spotifyで今聴いている曲を取得するため、Spotify APIのユーザー認証を行う必要があります。
このユーザー認証が少し厄介で、spotipyであれば一度ブラウザに飛んでSpotifyにログインを行い、アプリを認証する必要があります。
Pythonを実機のローカル環境などで実行した場合は(WSLなど)自動的にブラウザが開くのですが、Dockerやクラウド上のサーバーなどだと自動では開きません。(これが前述したDockerだと問題が生じますと言った理由です)
もっとうまいやり方があり、Docker内でも実行できるのかも知れませんが、今回は諦めてPythonの仮想環境を用意しました。(これは今後の課題でもあります。)
解決方法についてですが、ユーザー認証の際に、spotipy.oauth2.SpotifyOAuth
というメソッドを用いています。
https://spotipy.readthedocs.io/en/2.21.0/#spotipy.oauth2.SpotifyOAuth
こちらのパラメータで、open_browser
というものがあります。ドキュメントによると
open_browser: Optional, whether or not the web browser should be opened to
authorize a user
とのことだったので、こちらの値はデフォルトでTrueですがFalseにすることで、初回実行時にshell上にSpotifyのログイン画面が表示されるURLが表示されます。
(TrueだとEnter the URL you were redirected to:
のみしか表示されない。)
users.profile.setでemojiの指定の仕方
Slackのステータス変更にSlack APIのusers.profile.set
メソッドを使用しました。
https://api.slack.com/methods/users.profile.set#status
こちらのメソッドでemojiを指定するときに、最初エラーが返されました。
slack_sdk.errors.SlackApiError: The request to the Slack API failed. (url: https://www.slack.com/api/users.profile.set)
The server responded with: {'ok': False, 'error': 'profile_status_set_failed_not_emoji_syntax'}
これはstatus_emojiの値を絵文字の名前のみにしていたことで起こりました。
"status_emoji": "headphones",
ですが、実際には
"status_emoji": ":headphones:",
emojiの名前の前後に:
が必要でした。地味にひっかかりやすい気がするので注意。
(ちなみに、記事を作成しているときにドキュメントのexampleをよく見返すと
"status_emoji": ":train:",
と指定していたので、ドキュメントをちゃんと読む重要性を再度実感しました・・・)
おわりに
Slack上にSpotifyで現在聴いている曲を簡単に共有できるようになりました。
また、Slackのステータスに現在聴いている曲を設定することで、botが参加しているチャンネルにいないメンバーに向けてもアピールできるようになりました。
現在は手動でステータスに設定していますが、定期的にSpotify APIを呼び出し、現在聴いている曲を自動で設定する機能や他のメンバーも使えるようにエンハンスしていきたいと考えています。
この記事は富士通クラウドテクノロジーズ Advent Calendar 2022 の 14日目の記事でした。
明日は @toyo_muraさんの「ブラウザからワンクリックでサーバ上にdockerコンテナを立ち上げる」です。
自分も業務でDockerをよく使うため、ブラウザからワンクリックでコンテナを立ち上げる方法があれば便利だなと思うのでとても楽しみです。