やりたいことだらけ

好きなことをひたすらぶちまけるだけ。

rekordboxとOBS使いがDJ配信で曲名を反映させるには

追記
いろいろ整理してgithubに公開しました。現在はこちらをメインにしております。
https://github.com/msir3316/obs-kuvo-python


最近、DJ配信をすることが増えてきました。
そこで画面レイアウトもいろいろ凝ってみようと思って、まず手元カメラを導入。
そして次に、現在流している曲の情報を表示したいと考えた。
rekordboxにはKUVOというものがあり、流している曲がリアルタイムに反映されるページができる。
OBSにはブラウザソースといって、URLで指定したページにアクセスした内容を表示させる機能があり、まずはこれを試してみた。
が、途中から表示の形が少し変わったりして、どうもこれを使うには難がある。
そこで次の案は…プログラムで制御する方法だった。

準備

Python環境
これは割愛します。とりあえず最新のやつ入れときゃ大丈夫。

・obs-websocketプラグインを入れる
ここからDLしたものをOBSのフォルダに入れます(Windowsの場合)。
その後OBSを起動すると「ツール -> Websocketサーバー設定」ってのが出るので、ここで予め好きなパスワードを設定しておきます。

・obs-websocket-pyをインストール

pip install obs-websocket-py

これでOK。

次はKUVOのページの情報を取るのに必要なPythonライブラリなどを入れます。

pip install beautifulsoup4
pip install selenium

Seleniumを動かすためのブラウザのドライバを入れます。

PhantomJSでも良かったのですが、こちらはすでにサポートが終了していたので、Chrome Driverで。

 

プログラム

まずKUVOの情報を取得するプログラム。要するにスクレイピングです。

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
import traceback

class KuvoGetter():

    def __init__(self, playlist_num):
        target = "https://kuvo.com/playlist/" + str(playlist_num)
        options = Options()
        options.binary_location = "普段使ってるChromeのパス"
        options.add_argument("--headless")  #実行時にブラウザ画面を出さないようにしている
        self.driver = webdriver.Chrome(chrome_options=options, executable_path="Chrome Driverのパス")
        self.driver.get(target)

    def refresh(self): #リロード
        self.driver.refresh()

    def close(self): #終了
        self.driver.close()

    def get_music_info(self):
        try:
            soup = BeautifulSoup(self.driver.page_source, "html.parser")
            if soup is None:
                return None

            track = soup.find_all(class_="row on")

            if track:
                title = track[0].find(class_="title")
                artist = track[0].find(class_="artist")
                #print(title.get_text(),artist.get_text())
                return title.get_text(),artist.get_text()
            else:
                #row onがないときがたまにある。多分リストの最後に居座ってる
                tracklist = soup.find_all(class_="row off")
                #print(type(tracklist))
                if tracklist:
                    title = tracklist[-1].find(class_="title")
                    artist = tracklist[-1].find(class_="artist")
                    return title.get_text(),artist.get_text()
                return "!!!情報を取得できませんでした!!!", "!!!情報を取得できませんでした!!!"


        except Exception as e:
            traceback.print_exc()
            return "!!Error Occurred!!", "!!エラーが発生しました!!"

if __name__ == "__main__":
    kuvo = KuvoGetter(149235)
    print(kuvo.get_music_info())
    kuvo.close()

コンストラクタでKUVOのプレイリストの番号を与え、URLでアクセスします。
get_music_info()で、KUVOのページを掘って現在流している曲情報を取得します。
詳細は省きますが、実際にKUVOのページを検証で見れば何してるのかわかるかと思います。

次にOBSを制御するプログラム。

from obswebsocket import obsws, requests
import getkuvo #前述のプログラム

host = "localhost"
port = 4444 #場合によってはこれも各自調整
password = "「WebSocketサーバー設定」で設定したパスワード" #各自調整

#パラメータとか
cx = 1980 #スクロールする際の表示幅。各自調整
scroll_speed = 25.0 #スクロールするスピード。各自調整
scroll_true = {'cx': cx, 'limit_cx': True, 'limit_cy': False, 'speed_x': scroll_speed}
scroll_false = {'cx': cx, 'limit_cx': False, 'limit_cy': False, 'speed_x': 0.0}

#何文字以上でスクロールさせるかの閾値。各自調整
title_limit_length = 40
artist_limit_length = 50

#曲情報変更
def setMusicInfo(title, artist):
     if title and artist:
            #一定文字数以上ならスクロールさせる
            if len(title) > title_limit_length:
                title = title + "  " #見やすいようにスクロール用のスペースを開ける
                title_scroll = scroll_true
            else:
                title_scroll  = scroll_false
            if len(artist) > artist_limit_length:
                artist = artist + "  " #見やすいようにスクロール用のスペースを開ける
                artist_scroll = scroll_true
            else:
                artist_scroll  = scroll_false

            #各種セット
            ws.call(requests.SetTextGDIPlusProperties("title", text=title))
            ws.call(requests.SetSourceFilterSettings("title","scroll",title_scroll))
            ws.call(requests.SetTextGDIPlusProperties("artist", text=artist))
            ws.call(requests.SetSourceFilterSettings("artist","scroll",artist_scroll))
            #これでテキストの内容の変更ができる

#ソースの表示非表示
def setVisible(item,visible):
    return requests.SetSceneItemProperties(item,visible=visible)

#OBSに接続
ws = obsws(host, port, password)
ws.connect()


#初期化
ws.call(requests.SetTextGDIPlusProperties("title", text="ここに曲名が出るよ"))
ws.call(requests.SetTextGDIPlusProperties("artist", text="ここにアーティスト名が出るよ"))

ws.call(requests.SetSourceFilterSettings("title","scroll",scroll_false))
ws.call(requests.SetSourceFilterSettings("artist","scroll",scroll_false))

#プレイリスト番号を入力する
playlist_num = input("KUVOのプレイリストの番号を入力:")
kuvo = getkuvo.KuvoGetter(playlist_num)
title, artist = kuvo.get_music_info()

#曲情報をセット
setMusicInfo(title, artist)

#終了命令来るまでリロードでループさせる
while True:
    command = input("enterでリロード, zで終了:")
    if command == "":
        kuvo.refresh()
        title, artist = kuvo.get_music_info()

        setMusicInfo(title, artist)

    if command == "z":
        kuvo.close()
        break

ws.disconnect()

使う前に:

  1. OBSにて、「title」「artist」という名前のテキストソースをそれぞれ作成する。
  2. テキストソースにスクロールのフィルタを「scroll」という名前で作っておく
  3. 前者のプログラムの、「パス」を自分が置いたドライバの場所に書き換える
  4. 後者のプログラムの、「各自調整」と書いてあるところの数値を自分の配信画面構成に合わせて書き換える

使い方:

  1. ターミナル等で後者のプログラムを実行。環境を構築していれば.pyのファイルを直接ダブルクリックでも実行できると思う
  2. rekordboxで、KUVOをONにした状態でなんらかの曲を再生。これでKUVOに新しいプレイリストのページができるのでURLに書いてある番号をチェック
  3. 「KUVOのプレイリストの番号を入力:」と出るので、先程チェックした番号を入力
  4. 再生している曲の情報がOBS上に表示されればOK。あとはコンソール上でENTER叩くたびにリロードされる

動作についての細かいことはドキュメントを読んで欲しいのですが、
SetTextGDIPlusPropertiesでOBSのテキストオブジェクトの設定を行っています。引数は対象のオブジェクト名と、テキストの内容。
Macの方はこれをSetTextFreetype2Propertiesに変えてください。
SetSourceFilterSettingsではテキストのフィルタ設定を行ってスクロールさせるかを変えています。
後はCUIで操作できるように整えただけ。
とりあえず自分が使えればいいと思って書いたので例外処理とか雑です許して。

自動で更新かけられればと思ったけど、それで想定外の表示されるよりはマシという意味も含めてそこは妥協しました。

できた配信画面がこんな感じ。
www.twitch.tv