Spotify で再生中の曲を定期的に YouTube Live のチャットに書き込む Now Playing Bot を作ってみた

はじめに

テントの中から失礼します、CX 事業本部のてんとタカハシです!

YouTube Live で配信を行うことが私の日常なのですが、そんなに視聴してくれる方が多いわけでもないので、チャット欄が結構寂しいです。

そこで、Spotify で再生中の曲を定期的に書き込んでくれる Now Playing Bot を作ってチャット欄を賑わせてみました。

ソースコードは下記リポジトリに置いています。

GitHub - iam326/now-playing-bot-on-youtube-live

デモ

チャット欄がこんな感じになります。

前提条件

この Bot を動かすための前提条件は下記の通りです。

  • YouTube Live を配信可能なアカウントを所持していること
  • YouTube Data API を使用するために必要な認証情報が作成済みであること
  • Spotify Web API を使用するために必要な認証情報が作成済みであること

YouTube Data API を使用するために必要な認証情報を作成するには、下記の記事をご参照ください。

Spotify Web API を使用するために必要な認証情報を作成するには、下記の記事をご参照ください。

この記事を見て YouTube Live で配信をしてみたいと思った方は、下記の記事を参考にしてください。

環境

環境は下記の通りです。

% sw_vers
ProductName:	macOS
ProductVersion:	11.2.3
BuildVersion:	20D91

% python --version
Python 3.9.5

% pip --version
pip 21.1.1 from /Users/<USERNAME>/.anyenv/envs/pyenv/versions/3.9.5/lib/python3.9/site-packages/pip (python 3.9)

必要なパッケージのインストール

下記を実行します。

$ pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
$ pip install spotipy

実装

YouTube Data API 周り

YouTube Data API をラップするモジュールyoutube_data_api_client.pyを実装します。

このモジュールでは、API を叩くために OAuth 2.0 認証を行ったり、配信のチャット ID を取得、そのチャット ID を使ってメッセージを書き込む処理を載せています。

youtube_data_api_client.py

#!/usr/bin/env python3

import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow

from google.auth.transport.requests import Request

API_SERVICE_NAME = 'youtube'
API_VERSION = 'v3'


class YoutubeDataApiClient():

    def __init__(self, client_secrets_file, scopes):
        self.__client = self.get_authenticated_service(
            client_secrets_file, scopes)

    def get_authenticated_service(self, client_secrets_file, scopes):
        creds = None
        # The file token.pickle stores the user's access and refresh tokens, and is
        # created automatically when the authorization flow completes for the first
        # time.
        if os.path.exists('token.pickle'):
            with open('token.pickle', 'rb') as token:
                creds = pickle.load(token)
        # If there are no (valid) credentials available, let the user log in.
        if not creds or not creds.valid:
            if creds and creds.expired and creds.refresh_token:
                creds.refresh(Request())
            else:
                flow = InstalledAppFlow.from_client_secrets_file(
                    client_secrets_file, scopes)
                creds = flow.run_local_server(port=0)
            # Save the credentials for the next run
            with open('token.pickle', 'wb') as token:
                pickle.dump(creds, token)

        return build(API_SERVICE_NAME, API_VERSION, credentials=creds)

    def get_live_chat_id(self, live_id):
        live_broadcasts = self.__client.liveBroadcasts().list(
            part='snippet', id=live_id, fields='items(snippet(liveChatId))').execute()

        return live_broadcasts['items'][0]['snippet']['liveChatId']

    def send_message_to_live_chat(self, live_chat_id, message):
        self.__client.liveChatMessages().insert(part='snippet', body={
            'snippet': {
                'liveChatId': live_chat_id,
                'type': 'textMessageEvent',
                'textMessageDetails': {
                    'messageText': message
                }
            }
        }).execute()

Spotify Web API 周り

Spotify Web API をラップするモジュールspotify_api_client.pyを実装します。

このモジュールでは、API を叩くために OAuth 2.0 認証を行ったり、再生している曲の情報を取得する処理を載せています。

spotify_api_client.py

#!/usr/bin/env python3

import spotipy
from spotipy.oauth2 import SpotifyOAuth


class SpotifyApiClient():
    def __init__(
            self,
            username,
            client_id,
            client_secret,
            redirect_uri,
            scope):

        self.__auth_manager = SpotifyOAuth(
            username=username,
            client_id=client_id,
            client_secret=client_secret,
            redirect_uri=redirect_uri,
            scope=scope)
        self.__client = spotipy.Spotify(auth_manager=self.__auth_manager)

    def get_client(self):
        self.__auth_manager.get_access_token(as_dict=False)
        return self.__client

    def get_now_playing_track(self):
        track = self.get_client().current_user_playing_track()
        if track is None:
            return None

        title = track['item']['name']
        singer = track['item']['artists'][0]['name']

        return {
            'title': title, 'singer': singer
        }

メインの処理

毎分 Spotify で再生している曲の情報を取得して、YouTube Live のチャットに書き込みます。

main.py

#!/usr/bin/env python3

import os
import urllib.parse
from time import sleep

from spotify_api_client import SpotifyApiClient
from youtube_data_api_client import YoutubeDataApiClient

SPOTIFY_USERNAME = os.environ['SPOTIPY_USERNAME']
SPOTIFY_CLIENT_ID = os.environ['SPOTIPY_CLIENT_ID']
SPOTIFY_CLIENT_SECRET = os.environ['SPOTIPY_CLIENT_SECRET']
SPOTIFY_REDIRECT_URI = os.environ['SPOTIPY_REDIRECT_URI']
SPOTIFY_API_CLIENT_SCOPE = 'user-read-currently-playing'

YOUTUBE_DATA_API_CLIENT_SCOPES = [
    'https://www.googleapis.com/auth/youtube.force-ssl']
YOUTUBE_DATA_CLIENT_SECRETS_FILE = "client_secrets.json"

WAIT_SEC = 60


def main():
    spotify = SpotifyApiClient(
        SPOTIFY_USERNAME,
        SPOTIFY_CLIENT_ID,
        SPOTIFY_CLIENT_SECRET,
        SPOTIFY_REDIRECT_URI,
        SPOTIFY_API_CLIENT_SCOPE)

    youtube = YoutubeDataApiClient(
        YOUTUBE_DATA_CLIENT_SECRETS_FILE,
        YOUTUBE_DATA_API_CLIENT_SCOPES)

    url = input('YouTube Live URL: ')
    live_id = urllib.parse.urlparse(url).path[1:]
    live_chat_id = youtube.get_live_chat_id(live_id)
    prev_track = None

    try:
        while True:
            track = spotify.get_now_playing_track()
            if track is not None and track != prev_track:
                message = '♪ {} / {} #nowplaying'.format(
                    track['title'], track['singer'])
                youtube.send_message_to_live_chat(live_chat_id, message)

                print(message)
                prev_track = track

            sleep(WAIT_SEC)
    except KeyboardInterrupt:
        pass


if __name__ == '__main__':
    main()

実行

YouTube Data API を使用するために必要な認証情報のファイル名をclient_secrets.jsonにして、プログラムと同じディレクトリに格納してください。

また、Spotify Web API を叩くために下記の情報を環境変数として設定してください。

% export SPOTIPY_USERNAME="<USER_NAME>"
% export SPOTIPY_CLIENT_ID="<CLIENT_ID>"
% export SPOTIPY_CLIENT_SECRET="<CLIENT_SECRET>"
% export SPOTIPY_REDIRECT_URI="<REDIRECT_URL>"

main.pyを実行します。

% python main.py

初めて実行した際は、ブラウザが起動して、Google アカウントへのアクセスを同意する画面が表示されます。YouTube Live で配信を行っているアカウント、チャンネルを選択して許可をしてください。

下記記事の「プログラムを実行する」が参考になります。

アクセスを許可すると、YouTube Live の URL を入力するように求められます。

% python main.py

...

YouTube Live URL:

配信画面下部にあるシェアボタンをクリックして共有画面を出します。

動画リンクをコピーして貼り付けてください。

続いて、Spotify のログイン画面が表示されますのでログインしてください。

ログインすると、Spotify で再生している曲が表示される & チャットに書き込まれます。

% python main.py

...

YouTube Live URL: https://youtu.be/xxxxxxxxxxx
♪ Love potion / BuZZ #nowplaying

おわりに

チャット欄は少し賑やかになりましたが、やはり視聴者さんからコメント頂ける方が楽しい嬉しいです。。。

今回は YouTube Live のチャットに書き込むようにしていますが、これを他の SNS に書き込むよう改造すれば、色んな Now Playing Bot が作れそうです。

今回は以上になります。最後まで読んで頂きありがとうございました!