TanaRadioの音声ファイル再生をボタンで制御できるようになり,フェーズ4が完了しました。 mpvで音声を再生し、3ボタンで制御する 今日の到達目標 今日のゴールはこれです。 Chromiumを使わずに mpvでTanaRadioの音声を再生し 3つの物理ボタンで操作する 3ボタンの役割は、これまでと同じです。 GPIO17:再生/一時停止 GPIO27:10秒戻る GPIO22:10秒進む 配線はすでに成功しているので、今日は基本的にソフトウェア側の作業です。 ステップ0:現在の成功版をバックアップする まず、今うまく動いているChromium版を保存しておきます。 cp ~/tanaradio/buttons3_playerctl.py ~/tanaradio/buttons3_playerctl_success.py 確認します。 ls ~/tanaradio buttons3_playerctl_success.py が見えればOKです。 これは保険です。 mpv版でつまずいても、Chromium版にはいつでも戻れます。 ステップ1:mpvと必要なPython部品を入れる ターミナルで次を実行します。 sudo apt update sudo apt install -y mpv python3-feedparser python3-gpiozero mpvが入ったか確認します。 mpv --version バージョン情報が出ればOKです。 mpvは、--input-ipc-server を使うことで外部プログラムからJSON IPCで操作できます。今日はPythonからこの仕組みを使います。 ステップ2:TanaRadioのRSS URLを用意する mpvは、LISTENのページそのものではなく、音声ファイルURLを再生します。 その音声ファイルURLを取得するために、今回はRSSを使います。LISTENのTanaRadioページには「RSSを開く」「LISTENのRSS URLをコピー」といった導線があります。 TanaRadioのページで、RSS URLをコピーしてください。 メモとして、ターミナルではなく紙やテキストに一度控えておくとよいです。 TanaRadio RSS URL = ここにコピーしたURL まだRSS URLがわからない場合は、ここで止まって大丈夫です。 今日の最大の山は、実は配線ではなく「mpvに渡す音声URLを取ること」です。 ステップ3:RSSから最新音声URLを取り出すスクリプトを作る 作業フォルダに移動します。 cd ~/tanaradio 新しいファイルを作ります。 nano ~/tanaradio/get_latest_audio.py 中身はこれです。 RSS_FEED_URL のところだけ、コピーしたTanaRadioのRSS URLに置き換えてください。 #!/usr/bin/env python3 import feedparser import sys RSS_FEED_URL = "ここにTanaRadioのRSS URLを貼る" feed = feedparser.parse(RSS_FEED_URL) if not feed.entries: print("RSSからエピソードを取得できませんでした。", file=sys.stderr) sys.exit(1) latest = feed.entries[0] if not latest.enclosures: print("最新エピソードに音声ファイルURLが見つかりませんでした。", file=sys.stderr) sys.exit(1) audio_url = latest.enclosures[0].href print(audio_url) 保存します。 Ctrl + O Enter Ctrl + X 実行します。 python3 ~/tanaradio/get_latest_audio.py 長いURLが表示されれば成功です。 https://...mp3 または、 https://...m4a のようなものが出るはずです。 ステップ4:mpvだけで音声を再生する まず、Pythonやボタンを使わず、mpv単体で再生できるか試します。 AUDIO_URL=$(python3 ~/tanaradio/get_latest_audio.py) mpv --no-video "$AUDIO_URL" 音声が出れば成功です。 停止するときは、 q を押します。 ここで音が出れば、Chromiumなし再生の入口を突破です。 ステップ5:mpvを外部制御できるか試す 次に、mpvを「外から操作できる状態」で起動します。 まず、もしmpvが残っていたら止めます。 pkill mpv 次に、mpvを待機状態で起動します。 mpv --no-video --idle=yes --input-ipc-server=/tmp/tanaradio-mpv.sock このターミナルはそのまま開いたままにします。 別のターミナルを開いて、次を実行します。 AUDIO_URL=$(python3 ~/tanaradio/get_latest_audio.py) python3 - EOF import socket, json sock = "/tmp/tanaradio-mpv.sock" audio_url = "$AUDIO_URL" message = json.dumps({"command": ["loadfile", audio_url, "replace"]}) + "\n" client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) client.connect(sock) client.send(message.encode("utf-8")) client.close() EOF これでmpvから音声が流れれば成功です。 このテストは少し面倒ですが、意味は単純です。 mpvを起動して待機させる ↓ 別のPythonからmpvへ命令を送る ↓ 音声を読み込ませる ここまでできれば、ボタン制御の準備は整っています。 mpvを終了するときは、mpvを起動しているターミナルで、 q を押します。 ステップ6:3ボタンmpv制御スクリプトを作る いよいよ本番です。 nano ~/tanaradio/buttons3_mpv.py 中身はこれです。 ここでも RSS_FEED_URL のところだけ置き換えてください。 #!/usr/bin/env python3 from gpiozero import Button from signal import pause import subprocess import socket import json import os import time import sys import feedparser RSS_FEED_URL = "ここにTanaRadioのRSS URLを貼る" MPV_SOCKET = "/tmp/tanaradio-mpv.sock" def get_latest_audio_url(): feed = feedparser.parse(RSS_FEED_URL) if not feed.entries: print("RSSからエピソードを取得できませんでした。") sys.exit(1) latest = feed.entries[0] if not latest.enclosures: print("最新エピソードに音声ファイルURLが見つかりませんでした。") sys.exit(1) title = latest.get("title", "No title") audio_url = latest.enclosures[0].href print("Latest episode:", title) print("Audio URL:", audio_url) return audio_url def start_mpv(): if os.path.exists(MPV_SOCKET): os.remove(MPV_SOCKET) subprocess.Popen([ "mpv", "--no-video", "--idle=yes", f"--input-ipc-server={MPV_SOCKET}" ]) for _ in range(50): if os.path.exists(MPV_SOCKET): print("mpv is ready.") return time.sleep(0.1) print("mpv socket was not created.") sys.exit(1) def send_mpv(command): message = json.dumps({"command": command}) + "\n" try: with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as client: client.connect(MPV_SOCKET) client.send(message.encode("utf-8")) except FileNotFoundError: print("mpv socket not found. Is mpv running?") except ConnectionRefusedError: print("mpv connection refused.") def load_audio(audio_url): send_mpv(["loadfile", audio_url, "replace"]) def play_pause_pressed(): print("PLAY / PAUSE") send_mpv(["cycle", "pause"]) def back_10_pressed(): print("BACK 10 seconds") send_mpv(["seek", -10, "relative"]) def forward_10_pressed(): print("FORWARD 10 seconds") send_mpv(["seek", 10, "relative"]) play_pause = Button(17, pull_up=True, bounce_time=0.08) back_10 = Button(27, pull_up=True, bounce_time=0.08) forward_10 = Button(22, pull_up=True, bounce_time=0.08) play_pause.when_pressed = play_pause_pressed back_10.when_pressed = back_10_pressed forward_10.when_pressed = forward_10_pressed audio_url = get_latest_audio_url() start_mpv() load_audio(audio_url) print("TanaRadio mpv 3 buttons are ready.") print("GPIO17: play/pause") print("GPIO27: back 10 seconds") print("GPIO22: forward 10 seconds") pause() 保存します。 Ctrl + O Enter Ctrl + X gpiozero.Button は pull_up=True を指定すると、GPIOをHigh側へ引っ張り、ボタンの反対側をGNDへつなぐ使い方になります。これは今の配線方針と合っています。 ステップ7:3ボタンmpv版を実行する 念のため、mpvが残っていたら止めます。 pkill mpv 実行します。 python3 ~/tanaradio/buttons3_mpv.py うまくいくと、ターミナルに次のような表示が出ます。 Latest episode: ... Audio URL: ... mpv is ready. TanaRadio mpv 3 buttons are ready. GPIO17: play/pause GPIO27: back 10 seconds GPIO22: forward 10 seconds そして音声が流れます。 その状態でボタンを押します。 GPIO17 → 再生/一時停止 GPIO27 → 10秒戻る GPIO22 → 10秒進む 終了するときは、 Ctrl + C です。 そのあとmpvが残っていたら、 pkill mpv で止めます。 ステップ8:うまくいかないときの確認 1. RSSからURLが取れない まずこれを確認します。 python3 ~/tanaradio/get_latest_audio.py ここでURLが出なければ、RSS URLの貼り間違いの可能性があります。 確認点はこれです。 RSS_FEED_URL の引用符が消えていないか URLの前後に余計な空白がないか LISTENのページURLではなくRSS URLを入れているか 2. mpv単体で音が出ない これを確認します。 AUDIO_URL=$(python3 ~/tanaradio/get_latest_audio.py) echo "$AUDIO_URL" mpv --no-video "$AUDIO_URL" echo でURLが表示され、mpv で音が出なければ、音声出力設定の問題か、URLがmpvから直接再生できない可能性があります。 3. mpvは鳴るがボタンが効かない まず、前に成功したGPIOテストに戻ります。 python3 ~/tanaradio/buttons3_test.py 3ボタンが反応すれば、配線はOKです。 その場合は、mpv制御スクリプト側の問題です。 4. 1回押しただけなのに何回も反応する この値を少し増やします。 bounce_time=0.08 たとえば、 bounce_time=0.15 にします。 今日の進行順まとめ 今日は、この順番で進めるのがよいです。 1. Chromium版成功スクリプトをバックアップ 2. mpvとfeedparserをインストール 3. RSS URLを用意する 4. get_latest_audio.