RaRaPla ― ダークで軽快なラジオプレイヤーをつくってみた
Windows でラジオを聴くのに、余計な重量物はいりません。Qt と FFmpeg、ちょっと賢い補助を添えて、radikoとRadio Browserを同じ画面にまとめました。名前は RaRaPla。見た目は黒くて静か、触るとキビキビ。スクロールはヌルッと、再生はカチッと。派手さより体感速度に振っています。
この記事では、リポジトリの見どころと設計の癖、そして動かし方をまとめます。
何ができるのか
radiko の現在地エリアで聴ける局を自動一覧化して、ワンクリックで再生。ついでにRadio Browser のコミュニティ局も検索・再生できます。UI は PySide6(Qt)、テーマは qdarkstyle ベースに追加スタイル。右にチャンネル、左に詳細とプレイヤー。出力デバイスの切替と音量は素直にコンボボックスとスライダーで。
radiko の地域制限は当然そのままです。無茶はしません。その代わり、ローカルで動く軽量プロキシが“再生しやすい形に整えてから”プレイヤーへ渡す 仕立てになっています。プレイリストを読み解いて、URL を手元向けに組み替える通訳係だと思ってください。再生機能とネット側の事情の間で、気まずい沈黙を埋める役です。
仕組みの中心
src/rarapla/proxy/radiko_proxy.py
が核。aiohttp で /live/{station}.m3u8
を受けたら、内部で Streamlink を使って master m3u8 を取得し、相対も絶対も含めてセグメントやサブプレイリストの URL をローカル宛てに書き換えます。Qt 側から見えるのは常にローカルの m3u8。実体のメディアは /seg
がいい感じに橋渡しします。
403 が出たら解決キャッシュを捨てて再解決。回線が気まぐれでも、数回は落ち着いてやり直す仕込みです。既定ポートは 3032、埋まっていたら空いてるポートにスライド。
UI の小技
ui/widgets/
の SmoothScrollMixin が QScrollArea と QListWidget にミックスインされ、ピクセル単位スクロール+減速アニメーションを実現。標準のガタつきは記憶の彼方へ。
チャンネルはカード表示で、英数字だらけの長い名称にはゼロ幅スペース挿入+エリプシスで折り合いを付けます。画像は QNetworkAccessManager
で読み込み、UA も指定。
詳細パネルは画像を幅 340px に整えて、テキストは HTML(リンク可)。
コントロールとワーカー
controllers/now_refresher.py
が定期で radiko の“いま放送中”を取り直し、差分だけ UI を更新。controllers/playback_controller.py
は再生の司令塔で、radiko 再生中は数分おきに解決をリフレッシュして安定を担保。Radio Browser の直 URL 再生では services/icy_watcher.py
が ICY メタデータを別スレッドで監視し、曲名などを面倒見よく面板へ反映します。
ネットワークの重い処理は ui/workers/*
の QThread 経由。UI を固めるのは悪、という価値観で設計しています。
使い方
Windows 11 での動作を主に想定しています(ほかの OS でも PySide6/QtMultimedia が動くなら挑戦可)。
まず環境作成:
setup_env.bat
中で venv 作成 → 有効化 → pip install -e .
までやります。ログは色つき、進捗表示は正義。
起動はこれだけ:
rarapla:: あるいはpython -m rarapla
初回は rb_presets.json
が生成されます。J-POP や jazz、vocaloid といったタグプリセットはここで増減・編集できます。
Windows 配布(Nuitka)
配布用のスタンドアロンは build.bat
。Qt の multimedia / platforms プラグインを明示同梱、--include-package=streamlink.plugins
なども指定済み。
build.bat
音が出ない系のトラブルは、だいたい Qt Multimedia プラグインの同梱漏れ。build.bat
を眺めてから嘆けば、嘆く量が減ります。
ディレクトリの見どころ(抜粋)
data/
は radiko と Radio Browser の薄いクライアント。radiko の番組詳細は Date API → Weekly API の順で取りに行く守備的実装。
services/
は QMediaPlayer を包む PlayerService と、ブロック長を解釈して読む IcyWatcher。
ui/
は MainWindow と各ウィジェット/コントローラ。カード選択 → 別スレッドで番組詳細取得 → プレイヤー準備、の流れが素直に追えます。
proxy/
は再掲の通訳担当。エラー時の再解決やポート回避はここ。
定数は config.py
に集約。ウィンドウ高さ、音量レンジ、各タイムアウト、ポーリング間隔までここで統一。
テストと CI
tests/
には、
- radiko クライアントの時刻固定テスト、Now/Date/Weekly の分岐
- m3u8 書き換えが 相対・絶対 URL ともに
/seg?...
へ変換されること - 既定ポートが埋まっているときの自動スライド
- Radio Browser の JSON パースと
Channel
化 - ロギングの抑制設定
が入っています。GitHub Actions の CI は Windows / Ubuntu で black / flake8 / mypy(strict) / pytest を回します。壊したらバレるやつ。
ハマりどころと回避策
音が出ない → Qt のマルチメディアプラグインを確認。 radiko が 403/404 → プロキシが自動で再解決するので、数秒待ってから再生を入れ直すのが現実的。 番組画像や説明が出ない → そもそも提供されていないケースがあります。
ライセンスと感謝
MIT ライセンスです。radiko のデータ、Radio Browser コミュニティ、Qt / PySide6 とその周辺に感謝。地域や利用条件は各自の居場所のルールに従ってください。ここはインターネット、でも現実の上に建っています。