Python3 サイマルラジオ CSRA JCBA

Wikipediaより

SimulRadio(サイマルラジオ)は、コミュニティFMの自主制作番組をネット配信するサイト、およびそのためのプロジェクトである。

コミュニティ放送の役割の一つとして災害時の情報を提供することが挙げられます。
災害の現地に住んでいなくてもより詳しい情報を知り得たいという場面があるかもしれません。普段からもう少しサイマルラジオを聞くようにしたいと思います。
本当は各地のトーク番組などを聞きたいだけなのですが…ぼそ

聴取方法はPcのwebブラウザからやスマホのアプリケーションなどいろいろありますができるだけ良好な音でしかも軽快に利用したいためRaspberry PiなどのSBCから実行できるものとします。
CSRA、JCBAともurlがわかれば直接再生が可能です。

$ mpv "mms://hdv3.nkansai.tv/chofu"

目標は100局以上のラジオ局をエリア別に簡易なリストを作成、簡単なpythonプログラムで選局、再生するものとします。

ラジオ局リスト

自由に利用できるSimulRadioのプロジェクトにはCSRAとJCBAがあります。
現在JCBAはmusicbirdが配信しているようです。
CSRAは独自で配信している部分もありますがリスラジ(ListenRadio)に誘導されることもあります。実質配信に関してはリスラジが主体という印象があります。
どちらもまとまった形でurlリストを入手することは困難のようですが以下のサイトが参考になりました。
http://fsyublog.blog13.fc2.com/blog-entry-1214.html
JCBAインターネットサイマルラジオの仕様が変更された
CSRAは上記の記事を参考にリスラジ主体のリストを作成、JCBAはブラウザからurlを取得、取り敢えずテストに必要な分だけ揃えました。

Pi3のchromiumから取得
再生を開始
右クリック–検証–Networkタブ–Filter Boxに”m3u8″を打ち込む
chunklist_wxxx 右クリック–Copy–Copy link address

目的のurlはJCBxxxとm3u8が含まれているものです。
必要なアドレスはweb_03まで JCBxxxが固有のIDですね

https://chi-edge2-wow-relay1.leanstream.co/musicbird/_definst_/JCB019.stream/chunklist_w199142625.m3u8?args=web_03

# 追記
Filter Boxに打ち込む文字列はplaylist.m3u8ですね。基本のurlが取得できます。
JCBxxx=ラジオ局を紐付けできます。

https://musicbird-hls.leanstream.co/musicbird/JCB019.stream/playlist.m3u8?args=web_03


取得したurlをエリア別に局名とurlを1行形式で記述
エリアファイルは~/rajio/JCBA/以下に置いています。


ファイル JCB
IDと局名を記載 こちらは再生中の表示(ON AIR)に使います。

Python3 SimulRadio

pythonプログラムは前回作成したdocker container Listboxをベースに作成しました。

Listboxはエリアファイルを読み込むと局名とurlの2行で表示します。再生はurlを選択してPLAY
各エリアは瞬時に切り替えが可能です。
現在の不具合は起動時はスクロールバーが動作するのですがエリアを切り替えると動作しなくなります。但しマウスでのスクロール、及びキーボードでの操作は可能なので1エリア20〜30位の局数であれば問題ないと思います。


EDITボタンはエディタが起動して現在表示しているエリアの編集、新規追加が可能。
ON AIRボタンは再生中の局を表示、Yesでダイアログ終了、Noでファイル(JCB)の編集になります。ID以外はちょっとしたメモの追加など自由に編集できます。

python ~/bin/jcba.py

参考 jcba.py
~/bin/killall.shは前回radikoのものを使います。
Listbox
最初の方に起動時のデフォルトエリアを設定しています。

# default area
t = "/home/pi/radio/CSRA/関東"

mainでそのファイルを読み出しています。
エリアを切り替えるためにdef area_selection():で再度読み直しています。この時スクロールバー設定を引き継げないようです。

    # Listbox
    with open(t, 'r') as f:
        proc = f.read()
        currencies = (proc)
        v1 = StringVar(value=currencies)
        lb = Listbox(frame1, listvariable=v1,height=20,width=60)
        lb.grid(row=0, column=0)

# selection
def area_selection():
    global v1,lb
    with open(t, 'r') as f:
        proc = f.read()
        currencies = (proc)
        v1 = StringVar(value=currencies)
        lb = Listbox(frame1, listvariable=v1,height=20,width=60)
        lb.grid(row=0, column=0)

play
一旦killall.shを実行、Listboxで選択したurlを変数”a”にしてプレーヤー(mpv)で実行

# play
def button1_click():
    subprocess.run("~/bin/killall.sh", shell=True)
    play_selection()

# selection
def play_selection():
    for i in lb.curselection():
        a = (lb.get(i))
        command = ((("mpv ") + (a)) + (" &"))
        subprocess.run(command, shell=True)

ON AIR
ON AIRボタン(再生中の表示)はps axからurlの中のJCB+3文字を拾い出して、改行コードを削除、その値をreモジュールからファイル(JCB)を検索、読み出しています。

import re


コマンドラインから実行確認するとTypeErrorが出てしまいますが結果は正常に検索できているので取り敢えず様子を見ることにします(要調査)
TypeError: first argument must be string or compiled pattern

CSRA FM

CSRAで作成してみました。

単に再生することあればエリアリストをJCBAと共通にできるのですがプロジェクト別に管理、違いを確認したいこともあって別にしています。

まだまだエリアリストはできていないのですがCSRAで100局くらい、JCBAも同じくらいあるものと思います。
エリアリストを別にしたままCSRA,JCBA共通プログラムにしてみようと思います。