7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

富士通クラウドテクノロジーズAdvent Calendar 2022

Day 14

SpotifyのNowPlayingを投稿しステータスに設定もしてくれるSlackbotを作ってみた

Last updated at Posted at 2022-12-13

この記事はニフクラ等を提供している、富士通クラウドテクノロジーズ 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検索してみると・・・
image.png

ふむふむ、よさそうな記事があるな
リンクポチー
image.png
あれ?弊社のアドベントカレンダーの記事じゃん!!!

という経緯で運命を感じたので、上記の@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を利用するメソッドが記述していたりします。
image.png
(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で動かし、以下のパッケージを使用しています。

作り方

Slackbotの追加方法とSpotify APIの利用開始方法の詳細説明は省略します

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

スラッシュコマンドの作成

アプリのSlash Commandsから新しいコマンドを作成できます。コマンドをアプリを実行する前に作成しておきましょう。
詳しくはSlack APIのスラッシュコマンドに関するページの「Creating a Slash Command」を参照してください。
https://api.slack.com/interactivity/slash-commands#creating_commands

  • Command
    • /np
      • コマンド名はお好みで大丈夫です。(今回は元記事で@botの名前 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仮想環境を用いて仮想環境を作成し、アクティブにします。

Python仮想環境を作成
student@ubuntu:~/working/spotipy$ python3 -m venv .venv
student@ubuntu:~/working/spotipy$ source .venv/bin/activate

こちらを実行すると、shellに(.venv)と表示されるようになります。
which python3を実行すると、仮想環境がアクティブになっていることが確認できます。

Python仮想環境がアクティブであるか確認
(.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

Spotify API

これらを環境変数に保存します。環境変数に保存することで、プログラムから安全に利用することができます。

トークンを環境変数に保存
(.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プログラムのソースコードです。

app.py
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のログイン画面が表示されると思います。
image.png

こちらにログインすると、アプリケーションの認証を行ってよいか確認されるので、自分の作成したアプリで間違いなければ同意しましょう。
すると、以下のような https://example.com/ にアクセスした時と同じ画面が表示されると思います。
image.png

このときブラウザのアドレスバーのURLが重要で、以下のような内容になっているはずです。こちらをコピーします。

ユーザー認証用の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と送信してみましょう。
image.png

すると、botからレスポンスが返され・・・

image.png
自分が今Spotifyで聴いている曲が表示されました!
SlackはSpotifyのリンクを自動的にプレビューしてくれるので、それっぽく見えます。また、アルバムアートワーク(いわゆるCDジャケット)の画像URLもSpotify APIで取得して、プレビューとして表示されるのもいい感じ。
(プレビュー部分はアルバムアートワークの画像がQiitaに載せると著作権等の問題がある可能性があるためSlack上で削除しています。)

また、「ステータスに設定しました!」というメッセージがbotから返されているので、Slackの自分のステータスを確認すると・・・
image.png
ちゃんと設定できている!
これで自分の聴いている曲をいつでもアピールできますね。
image.png
(自分のSlackの表示名右横のemojiにマウスカーソルを合わせても見れます。)
image.png
(他のメンバーがダイレクトメッセージを送ろうとするときにも見れます。)

つまったところ

何箇所か開発中につまったところがあるので、参考になればと思い記載しておきます

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を指定するときに、最初エラーが返されました。

users.profile.set API methodを使用したときのエラー
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の指定方法
"status_emoji": "headphones",

ですが、実際には

正しいstatus_emojiの指定方法
"status_emoji": ":headphones:",

emojiの名前の前後に:が必要でした。地味にひっかかりやすい気がするので注意。
(ちなみに、記事を作成しているときにドキュメントのexampleをよく見返すと
"status_emoji": ":train:",と指定していたので、ドキュメントをちゃんと読む重要性を再度実感しました・・・)

おわりに

Slack上にSpotifyで現在聴いている曲を簡単に共有できるようになりました。
また、Slackのステータスに現在聴いている曲を設定することで、botが参加しているチャンネルにいないメンバーに向けてもアピールできるようになりました。
現在は手動でステータスに設定していますが、定期的にSpotify APIを呼び出し、現在聴いている曲を自動で設定する機能や他のメンバーも使えるようにエンハンスしていきたいと考えています。

この記事は富士通クラウドテクノロジーズ Advent Calendar 2022 の 14日目の記事でした。

明日は @toyo_muraさんの「ブラウザからワンクリックでサーバ上にdockerコンテナを立ち上げる」です。
自分も業務でDockerをよく使うため、ブラウザからワンクリックでコンテナを立ち上げる方法があれば便利だなと思うのでとても楽しみです。

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?