radikoで聴けるラジオ局の番組の再生や録音をWebブラウザを用いずにツールで行う。Webブラウザでサイトを訪問して聴くこともできるが、(らじる★らじると同様)CPUに負荷がかかる上に自動化に向かないため、別の方法を探す。
https://gist.github.com/ji6czd/f86440200ba286f1f7af2e103dd430ff
にあるPythonスクリプトを保存して実行属性を付けて引数にラジオ局のID1を指定して実行すると、ffplay
でその局のラジオを再生する。指定した時間経過後に自動的に終了する機能はないので、端末ではCtrl-cを押して止める必要があり、ある程度の時間再生した後で自動で終了させたい場合はkillall
などのプロセス制御コマンドを用いる。
58行目で文法エラーが出て動かない場合、57行目の波括弧がコメントアウトされているのが原因なので次の行に}
を付ける。
Pythonのバージョン3.6以上の機能に依存している関係で、Raspberry Pi OS (当時は “Raspbian”) Stretch(“2019-04-09” が最終バージョン)で最初からインストールされているPythonを使用している場合は
url = f'http(中略).m3u8'
の行でエラーが出る。これは古い書き方にすることで動くようにできる。
url = 'ht(中略).jp/{}/(中略).m3u8'.format(argv[1])
Raspberry Pi OSがBuster(“2019-06-24” 以降)であればPythonが新しいため、そのままで動作する。
ffplay
の代わりに(個人的に使いやすい)mpv
を使用し、かつ2番目の引数を再生時間(例:1:35:0
で1時間35分の指定)として解釈するようにしてみる。
末尾付近でffplay
を呼んでいる行の部分を
# Stretchではformat()を用いる
os.system( "mpv --really-quiet --no-cache --http-header-fields='X-Radiko-Authtoken: {}' --end='{}' '{}'".format(token, argv[2], m3u8) )
# Buster以降の場合ではこう書ける
os.system( f"mpv --really-quiet --no-cache --http-header-fields='X-Radiko-Authtoken: {token}' --end='{argv[2]}' '{m3u8}'" )
のどちらかにすると、指定された時間再生された後に自動的に終了するようになる(より自動化向きになる)。
ffmpeg
を録音に使用し
を指定する形としてみる。保存されるファイル名は “[録音開始日時]-[ラジオ局ID].aac” 形式で自動生成されるようにした(後述のツールのファイル名生成ルールに合わせている)。
import time
t = time.localtime()
filename = '{}{:02}{:02}{:02}{:02}{:02}-{}.aac'.format(
t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, argv[1])
outdir = argv[3] if len(argv) == 4 else os.getcwd()
os.system( "ffmpeg -loglevel quiet -headers 'X-Radiko-Authtoken:{}' -i '{}' -acodec copy -t '{}' -y '{}'".format(token, m3u8, argv[2], os.path.join(outdir, filename)))
Raspberry Pi OS Buster以降では最後の行が下のように書ける。
# Buster以降の場合の最後の行
os.system( f"ffmpeg -loglevel quiet -headers 'X-Radiko-Authtoken:{token}' -i '{m3u8}' -acodec copy -t '{argv[2]}' -y '{os.path.join(outdir, filename)}'")
ここでは前述の2つの改造が適用されたスクリプトを用意して
play-radiko.py
ffmpeg
を用いた録音用スクリプト:rec-radiko.py
という形でファイル名を付けたものとする。
放送局は地域によって異なるため、ここでは全国放送となっている局を用いている。
# 月曜から金曜の6:20からラジオNIKKEI第1を1時間20分再生する
20 6 * * mon,tue,wed,thu,fri /path/to/play-radiko.py RN1 "1:20:0"
# 8月10-17日の6:00から放送大学を1時間35分録音して /dev/shm 内に保存
0 6 10-17 8 * /path/to/rec-radiko.py HOUSOU-DAIGAKU "1:35:0" /dev/shm
radigoと呼ばれるコマンドラインツールが開発・公開されている。ライセンスはGPL-3。
このツールはradikoの現在または聴取可能期間内の過去の放送(タイムフリー)を保存することができる。再生に直接使うことはできない。
2019年夏時点では、GNU/Linuxでは現在の放送を10分以上保存しようとすると外部ツールが止まってしまい録音も停止してしまう。rtmpdump
からffmpeg
にパイプでデータを渡さないでflv形式のまま保存するようにいじると10分を超えた録音自体はできるが、一時ファイルを保存する必要が出てしまう。また、rtmpdump
を用いない再生ツール(改造で録音も可)は前述したものがあるため、このツールは過去の放送用に使うのがよい。
2020年11月末でサーバ側の変更により過去の放送の取得処理が動作しなくなったが、このソフトウェアが使用している外部プロジェクトgo-radiko
のソースがこの変更に対応しており、そちらのソースを最新に更新してradigo
を再ビルドすることで正しく動作する。なお、ffmpeg
のバージョンが古いと別の変更の影響で取得処理に失敗するようになっており、その場合はradigo
側のソースは2019年時点のものを使用してgo-radiko
のみ更新する。
使い方としては、オプションとして
-id=[ID文字列]
形式で、radigo area
を実行することで一覧が取得可能)-t=[秒数]
)または過去の放送の開始日時(-s=[YYYYMMDDhhmmss]
2)の2つを指定して実行することで、指定したラジオ局の放送に対して
が自動的に保存される。既定の保存形式はAACだが、MP3へのエンコードもできる。
作者によると、このツールは個人での(私的な)聴取目的以外には使用できない。
日付が変わった後の時刻指定は番組表(24-29時)とは異なり、翌日午前の実際の日付と時刻を指定する必要があるため、その時間帯の過去の放送を指定する場合は注意が必要。
同じ番組であっても “枠” が細かく分かれている場合があり、過去の放送の開始日時として最初の枠の開始時刻を指定しても、2つ目以降の枠は保存されない。これはradikoのサイト(放送局のサイトではない)で番組表を見て枠がどのように分かれているかを確認するしかない。
環境変数RADIGO_HOME
で保存先ディレクトリが実行時に指定できる。常に同じ保存先を指定するのであれば/etc/environment
にRADIGO_HOME=/dev/shm
のような形で記述すると再起動後に反映される。
Go言語で書かれているため、Goコンパイラが必要で、Raspberry Pi OSではgolang
パッケージが必要。
PC上のRaspberry Pi OS環境をQEMUで動かすと、このソフトウェアのビルドが正常に行えないことがある。その場合、実機でビルドする必要がある。幸いビルド時間は短めで、夏場でもSoC温度が大きく上昇する心配はない。
プロジェクトのページの説明だけを見てビルドを行おうとしたらGOPATH
やPATH
といった環境変数で問題が起きたので、下のようにした。
[~]$ mkdir -p /dev/shm/gopath/bin
[~]$ mkdir /dev/shm/gopath/src
[~]$ cd /dev/shm/gopath/src
[/dev/shm/gopath/src]$ git clone https://github.com/yyoshiki41/radigo.git
[/dev/shm/gopath/src]$ export GOPATH=/dev/shm/gopath
[/dev/shm/gopath/src]$ export PATH=$PATH:$GOPATH/bin
[/dev/shm/gopath/src]$ cd radigo
以下はホームディレクトリの下にbin
というディレクトリを作成してその中にインストールする場合の例。
[/dev/shm/gopath/src/radigo]$ make installdeps
[/dev/shm/gopath/src/radigo]$ make build
[/dev/shm/gopath/src/radigo]$ mkdir ~/bin
[/dev/shm/gopath/src/radigo]$ install -s radigo ~/bin
[/dev/shm/gopath/src/radigo]$ cd
[~]$ rm /dev/shm/gopath -fr
radigo
本体はバージョン1.7以上でビルド可能とされているが、依存する別リポジトリのパッケージがGo 1.8から追加されたos.Executable()
を使用している関係でRaspberry Pi OS (当時は “Raspbian”) StretchのGo 1.7ではビルドに失敗する。
vendor/github.com/posener/complete/cmd/install/install.go:102: undefined: os.Executable
この関数はビルドしてできた実行ファイルの絶対パスを得るためのものなので、例えば/home/pi/bin/
に置いて実行するのであれば/dev/shm/gopath/src/radigo/vendor/github.com/posener/complete/cmd/install/install.go
のgetBinaryPath()
を
func getBinaryPath() (string, error) {
return filepath.Abs("/home/pi/bin/radigo")
}
のようにいじる方法もある。ただ、実際にこの関数が呼ばれる部分がradigo
本体から使われているかは怪しい。
いずれもRaspberry Pi OSでは下のコマンド名と同名のパッケージとしてインストールできる。
ffmpeg
rtmpdump
(現在の放送を録音する場合にのみ使われるが、古い方法なので廃止される可能性がある)らじる★らじるの場合もそうだが、ダウンロードしたAACの音声ファイルをそのままエンコードせずに保存する場合はCPUの負荷が非常に低い。
残念ながら、サーバとのやりとりの中でサーバ側の一時的な問題によってエラーが発生して保存に失敗することが稀にある。
下は過去の放送を保存しようとした際のエラーメッセージの例だが、いずれも再試行したところ正常に処理が完了している。
ERROR: Failed to get playlist.m3u8: expected element type <radiko> but have <html>
ERROR: Failed to get auth_token: Post https://radiko.jp/v2/api/auth1_fms: net/http: TLS handshake timeout
録音を確実に行うために、失敗した場合に少し待機した後で数回程度を上限として再試行するようなスクリプトを別途書いて実行することにした。
下のスクリプトを通して実行すると、エラーが出て失敗した場合にコード中のretry_count
の回数まで再試行し、再試行の度にretry_wait
の秒数待機する。このコードはLuaJITを用いているが、標準のLuaでも動作する。
radigo-wrapper.lua
ライセンス:CC0#! /usr/bin/luajit
-- CC0
do
local retry_count = 5
local retry_wait = 10
local cmdline = ('"%s"'):format(arg[1])
for i = 2, #arg do
cmdline = cmdline .. ' ' .. arg[i]
end
local success = false
local sleep = ('sleep %d'):format(retry_wait)
for i = 1, retry_count do
status = os.execute(cmdline)
if status == 0 or status == true then -- 0:Lua 5.1 true:Lua 5.2+
success = true
break
end
os.execute(sleep)
end
if not success then
os.exit(false)
end
end
radigo
はラジオの再生には使用できず、現在の放送の録音にも前述した問題があるため、過去の放送の録音についてのみ設定例を下に示す。
# 日曜17:30からのラジオNIKKEI第1の放送を同日の23:45から保存
45 23 * * sun /path/to/radigo-wrapper.lua /path/to/radigo rec -id=RN1 -s=$(date "+\%Y\%m\%d")173000
# 月曜12:00からのラジオNIKKEI第2の放送を翌日である火曜の4:56から保存
56 4 * * tue /path/to/radigo-wrapper.lua /path/to/radigo rec -id=RN2 -s=$(date --date "1 day ago" "+\%Y\%m\%d")120000
このツールはリアルタイムに録音するよりも短い時間でデータをダウンロードできるが、これはWebブラウザでアクセスして聴くのと比べて大きなネットワーク負荷をradiko側に対してかけてしまうことにもなる。そのため、短時間に番組を大量にダウンロードするのは控えたほうがよい(対策される可能性もある)。月曜2-5時のような放送休止時間帯の局の多い時間帯(メンテナンスが入ることもあるので注意)またはその前後にしたり、自主的に帯域幅を絞ったりして配慮するのが望ましい。
date
コマンドの引数のパーセント記号にバックスラッシュを付けているが、これはcron
の設定ファイルの中のパーセント記号が特殊な意味を持っているために必要なもの。
当日放送分でない番組の開始日時の日付部分を得る(日付の引き算をする)には、date
コマンドで--date "2 days ago"
などのような形でずらす日数の指定を行うとよい。