物理ボタンでプレイリスト再生の制御ができるようになりました(フェーズ5D完了)。
*以下のtanaradio_5d.pyのコードは,修正済みのものです(この収録後も1回修正しました)。
フェーズ5D 詳細マニュアル
既存3ボタンでRSSプレイリストを操作する
0. 今回の目標
今回やることは、これです。
フェーズ5Cで playlist.m3u を作る
↓
mpvで playlist.m3u を再生する
↓
GPIOの3ボタンでmpvを操作する
3つのボタンの役割は、今回は次のようにします。
再生/一時停止ボタン:再生・一時停止
戻るボタン:前のエピソードへ
次へボタン:次のエピソードへ
mpvへの命令は次の3つです。
再生/一時停止:cycle pause
戻る:playlist-prev
次へ:playlist-next
構想メモでは、戻るボタンに「1回押し=先頭へ、2回押し=前へ、長押し=10秒戻る」という発展案があります。
ただし、5Dではまだ入れません。ここで欲張ると、ボタン判定の沼に入ります。沼は楽しいですが、今日はまだ岸辺でお茶を飲みます。
ステップ1:作業フォルダへ移動する
Raspberry Piでターミナルを開きます。
cd ~/tanaradio5
確認します。
pwd
次のような表示になればOKです。
/home/ユーザー名/tanaradio5
ステップ2:5Cまでのファイルを確認する
ls
少なくとも、次のようなファイルがあるはずです。
feeds.txt
make_playlist_5c.py
playlist.m3u
スクリプト名は、たなさんが5Cで作った名前に合わせてください。
以下では、5Cのスクリプト名を make_playlist_5c.py として進めます。
ステップ3:5Cのプレイリストをもう一度作る
まず、5Cのスクリプトを実行して、最新の playlist.m3u を作ります。
./make_playlist_5c.py
または、実行権限を付けていない場合は、
python3 make_playlist_5c.py
うまくいけば、たとえば次のような表示になります。
playlist.m3u を作成しました。
音声URL数: 12 件
完了しました。
確認します。
ls -l playlist.m3u
playlist.m3u が存在し、サイズが0でなければOKです。
中身も少し見ます。
head playlist.m3u
次のように、音声URLが入っていればOKです。
#EXTM3U
# エピソードタイトル
https://...
ステップ4:mpvだけで再生できるか確認する
ボタン操作に入る前に、まず普通に再生します。
mpv playlist.m3u
音が出ればOKです。
この状態では、キーボードで操作できます。
スペースキー:一時停止/再開
Enter:次へ
q:終了
確認できたら、q を押してmpvを終了します。
ここで音が出ない場合は、5Dには進まず、音声出力側を先に確認してください。
ステップ5:GPIOライブラリを確認する
今回はPythonからGPIOボタンを読むために gpiozero を使います。
まず確認します。
python3 -c "import gpiozero; print('gpiozero OK')"
次のように出ればOKです。
gpiozero OK
もしエラーが出たら、次を実行します。
sudo apt update
sudo apt install -y python3-gpiozero python3-lgpio
インストール後、もう一度確認します。
python3 -c "import gpiozero; print('gpiozero OK')"
ステップ6:GPIO番号を確認する
今回のコードでは、フェーズ4で使ってきた3つのGPIOを次のように使います。
GPIO17:再生/一時停止
GPIO27:戻る、つまり前のエピソードへ
GPIO22:次へ、つまり次のエピソードへ
配線はこれまで通り、基本形は次です。構想メモでも、ボタン入力には保険として抵抗を残す方針になっています。
GPIO ─ 1kΩ程度の抵抗 ─ ボタン ─ GND
つまり、ボタンを押すとGPIOがGNDにつながる形です。
Python側では pull_up=True にします。
ステップ7:5D用スクリプトを作る
新しいファイルを作ります。
nano tanaradio_5d.py
次のコードをそのまま貼り付けます。
#!/usr/bin/env python3
from gpiozero import Button
from signal import pause
import json
import os
import signal
import socket
import subprocess
import sys
import time
from pathlib import Path
# ===== 設定ここから =====
BASE_DIR = Path(__file__).resolve().parent
PLAYLIST_FILE = BASE_DIR / "playlist.m3u"
SOCKET_PATH = "/tmp/tanaradio-mpv.sock"
# フェーズ4で使った既存3ボタンのGPIO番号
PIN_PLAY_PAUSE = 17 # 再生/一時停止
PIN_BACK = 27 # 戻る:前のエピソードへ
PIN_NEXT = 22 # 次へ:次のエピソードへ
# ===== 設定ここまで =====
mpv_process = None
def check_playlist():
if not PLAYLIST_FILE.exists():
print(f"{PLAYLIST_FILE} が見つかりません。")
print("先にフェーズ5Cのスクリプトを実行して playlist.m3u を作ってください。")
sys.exit(1)
text = PLAYLIST_FILE.read_text(encoding="utf-8", errors="ignore").strip()
if not text:
print(f"{PLAYLIST_FILE} は空です。")
sys.exit(1)
def start_mpv():
global mpv_process
if os.path.exists(SOCKET_PATH):
os.remove(SOCKET_PATH)
print("mpvを起動します。")
print(f"プレイリスト: {PLAYLIST_FILE}")
mpv_process = subprocess.Popen(
[
"mpv",
"--no-video",
f"--input-ipc-server={SOCKET_PATH}",
str(PLAYLIST_FILE),
],
cwd=str(BASE_DIR),
)
# mpvのIPCソケットができるまで少し待つ
for _ in range(50):
if os.path.exists(SOCKET_PATH):
print("mpv操作用ソケットを確認しました。")
return
time.sleep(0.1)
print("mpv操作用ソケットが見つかりません。")
print("mpvが起動できていない可能性があります。")
def send_mpv_command(command):
payload = json.dumps({"command": command}).encode("utf-8") + b"\n"
try:
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as client:
client.settimeout(1.0)
client.connect(SOCKET_PATH)
client.sendall(payload)
# mpvからの返事を少し読む。
# これをしないと、mpv側に Broken pipe が出ることがある。
try:
client.recv(4096)
except socket.timeout:
pass
except FileNotFoundError:
print("mpvのソケットが見つかりません。mpvが終了している可能性があります。")
except ConnectionRefusedError:
print("mpvに接続できませんでした。")
except Exception as e:
print("mpvへの命令送信でエラーが出ました。")
print(e)
def play_pause():
print("ボタン: 再生/一時停止")
send_mpv_command(["cycle", "pause"])
def back_episode():
print("ボタン: 戻る:前のエピソードへ")
send_mpv_command(["playlist-prev"])
def next_episode():
print("ボタン: 次へ")
send_mpv_command(["playlist-next"])
def setup_buttons():
print("GPIOボタンを準備します。")
print(f"再生/一時停止: GPIO{PIN_PLAY_PAUSE}")
print(f"戻る: GPIO{PIN_BACK}")
print(f"次へ: GPIO{PIN_NEXT}")
play_button = Button(PIN_PLAY_PAUSE, pull_up=True, bounce_time=0.08)
back_button = Button(PIN_BACK, pull_up=True, bounce_time=0.08)
next_button = Button(PIN_NEXT, pull_up=True, bounce_time=0.08)
play_button.when_pressed = play_pause
back_button.when_pressed = back_episode
next_button.when_pressed = next_episode
# main側で保持するために返す
return play_button, back_button, next_button
def cleanup(signum=None, frame=None):
global mpv_process
print("\n終了します。")
if mpv_process is not None and mpv_process.poll() is None:
mpv_process.terminate()
try:
mpv_process.wait(timeout=5)
except subprocess.TimeoutExpired:
mpv_process.kill()
if os.path.exists(SOCKET_PATH):
try:
os.remove(SOCKET_PATH)
except OSError:
pass
sys.exit(0)
def main():
signal.signal(signal.SIGINT, cleanup)
signal.signal(signal.SIGTERM, cleanup)
check_playlist()
start_mpv()
# 重要:
# setup_buttons() の戻り値を変数に入れて保持する。
# これをしないと、環境によってはボタンが反応しなくなることがある。
buttons = setup_buttons()
print("準備完了です。")
print("3つの物理ボタンで操作できます。終了は Ctrl + C です。")
pause()
if __name__ == "__main__":
main()
保存します。
Ctrl + O
Enter
Ctrl + X
ステップ8:実行権限を付ける
chmod +x tanaradio_5d.py
ステップ9:5Dを実行する
./tanaradio_5d.py
うまくいくと、次のような表示になります。
mpvを起動します。
プレイリスト: /home/ユーザー名/tanaradio5/playlist.m3u
mpv操作用ソケットを確認しました。
GPIOボタンを準備します。
再生/一時停止: GPIO17
戻る: GPIO27
次へ: GPIO22
準備完了です。
3つの物理ボタンで操作できます。終了は Ctrl + C です。
この状態で、音声が流れ始めます。
ステップ10:3つのボタンを試す
10-1. 再生/一時停止ボタン
GPIO17につながっているボタンを押します。
ターミナルに次のように出ればOKです。
ボタン: 再生/一時停止
音声が一時停止します。
もう一度押すと再開します。
10-2. 次へボタン
GPIO22につながっているボタンを押します。
ボタン: 次へ
次のエピソードへ進めばOKです。
10-3. 戻るボタン
GPIO27につながっているボタンを押します。
ボタン: 戻る:前のエピソードへ
前のエピソードへ戻ればOKです。
ただし、プレイリストの最初のエピソードを再生しているときは、それ以上前へ戻れないので、動きがわかりにくい場合があります。
その場合は、先に「次へ」を1〜2回押してから「戻る」を試してください。
ステップ11:終了する
終了するときは、ターミナルで次を押します。
Ctrl + C
次のように出ればOKです。
終了します。
mpvも一緒に終了します。
ステップ12:今回の成功条件
フェーズ5Dの成功条件は、次の4つです。
1. フェーズ5Cの playlist.m3u が作れている
2. tanaradio_5d.py を実行すると mpv が起動する
3. 再生/一時停止ボタンで pause / resume ができる
4. 戻る・次へボタンで playlist-prev / playlist-next ができる
ここまでできれば、5Dは成功です。
これはかなり大きいです。
5Cまでは「RSSから音声を集める仕組み」でしたが、5Dでついに「物理ボタンで声の流れを操る装置」になります。ラジオ感が、ぐっと前に出てきます。
サマリー
TanaRadio Pi製作シリーズのフェーズ5Dでは、既存の3つの物理ボタンでRSSプレイリストを操作することを目指しました。まず作業環境を整え、過去3日間のエピソードを含むプレイリストを作成し、音声再生を確認。次にGPIOライブラリとボタン配線をチェックし、ChatGPTが生成したスクリプトを導入しましたが、当初ボタンが機能しませんでした。ChatGPTの助けを借りてコードの一部を修正した結果、再生・一時停止、戻る、次へといった全てのボタン機能が正常に動作することを確認し、フェーズ5Dは無事成功しました。これにより、物理ボタンで音声の流れを操る「ラジオ感」が実現し、次フェーズ5EではRSSのグループ化「棚」の導入が予定されています。
コメント
このエピソードのトピック
すべてのトピック →それぞれのトピックから、ほかの番組の会話も探せます。
似ているエピソード
タイトル・AI要約・文字起こしの話題をもとにおすすめしています。
-
375 日記 | 棚を選択してプレイリストを作成
TanaRadio
共通する話題: TanaRadio Pi · TanaRadio
TanaRadio Pi製作シリーズのフェーズ5Eでは、ポッドキャストのグループである「棚」を作成し、コマンドで切り替える機能の実装を...
-
366 日記 | 3ボタンの実験
TanaRadio
共通する話題: TanaRadio Pi · TanaRadio · Raspberry Pi
Raspberry Piで3ボタンの物理的な配線と接続を完了し、Pythonスクリプトを用いて各ボタンの動作を個別にテストすることに成功し...
-
370 日記 | RSSからプレイリストを作る
TanaRadio
共通する話題: TanaRadio Pi · TanaRadio · Raspberry Pi
本エピソードでは、TanaRadio Piのフェーズ5Aとして、RSSフィードからプレイリストを作成し、mpvで連続再生する手順が実行されま...
-
369 日記 | フェーズ5の計画を立てる
TanaRadio
共通する話題: TanaRadio Pi · TanaRadio
TanaRadioPiのフェーズ5計画について、AI「チャッピー」と対話しながら詳細を決定しました。物理ボタンやツマミを増やし、ラジオ...
-
368 日記 | TanaRadioの音声ファイル再生をボタンで制御
TanaRadio
共通する話題: TanaRadio · Raspberry Pi · ChatGPT
本エピソードでは、TanaRadioの音声再生システムをChromiumブラウザからmpvアプリケーションへ移行し、3つの物理ボタンで制御す...
-
暴走ボタンを止めろ!type設定の基本
神経質やせ男チャンネル
\ 4/17 新刊発売! / 『会社公認・爆速仕事術:管理者権限なしでできるPC魔改造』 [https://www.amazon.co.jp/dp/B0GWWHFV6L/]...
-
2026/07/08 三食のきろく と 色々
クルマの中からこんにちは
ひろひろしは、録音機の忘れ物とiPhoneショートカットでの録音失敗により、本エピソードを再録音したと説明します。まず、7月3日...
-
#068 【Macユーザ向け】garage bandで Podcast番組を作ってみよう③
Video Arts Labo〜伝える力を育てるメディア
ガレージバンド
-
#067 【Macユーザ向け】garage bandで Podcast番組を作ってみよう②
Video Arts Labo〜伝える力を育てるメディア
ガレージバンド
-
#206 おもちゃのせんばんの公式HPを作ろう!!
ものづくりnoラジオ-しぶちょー技術研究所
共通する話題: ChatGPT
しぶちょーは、展示会での機会損失を解消するため、お盆の限られた時間で「おもちゃのせんばん」の公式ホームページを制作する実...