シェルスクリプトで radiko タイムフリーを保存する

2020年12月6日

🔗 radikoのタイムフリーを保存する方法

上記の記事を大いに参考にさせていただき、というか重要な部分を丸パクりさせていただき、シェルスクリプトを作った。
 くれぐれも。
 ラジコのタイムフリーを保存することには、なんらかの違法性があるかもしれない。筆者がインターネットをめぐる著作権の法律を読んだ感じでは、公式が配布するコンテンツを保存することは、私的の利用に限れば問題ない、のではないかと思っている。
 しかし専門家にはいわせれば違うのかもしれない。
 確実なのは、ダウンロードしたものをどこかへ公開するのはアウトということだ。

追記 2020.12.05
—————————
 ラジコの仕様変更にともなって、スクリプトを書き直しました。
 下記のスクリプトから重要な部分をコピペさせていただき、自分なりにアレンジしたものとなります。下記スクリプトの作者さまには深く感謝いたします。

🔗 GitHub – uru2/rec_radiko_ts: Radiko timefree program recorder

 というか、上記リンク先にある、rec_radiko_ts.sh ならエリアフリーにログインできるので、そっちのほうがいいような気がする。
—————————

radiko-dl.sh

要 ffmpeg。

brew install ffmpeg

2019 年 12 月 25 日深夜 1 時から 3 時、TBS ラジオの「爆笑問題カーボーイ」を保存するとしたら、以下のように書く。

radiko-dl.sh -id TBS -ft 20191225010000 -to 20191225030000 -n 'JUNK 爆笑問題カーボーイ'

radiko-dl.sh -id 放送局ID -ft 開始時間 -to 終了時間
 必要に応じて-n '番組名'をつけると、ファイルに番組名をつける。
 -o file/to/path で保存先を指定できる。チルダをクオートで囲むと展開されないので、-o "$HOME/Downloads" という感じがいいかもしれない。
 デフォルトでは Downloads フォルダ内に radiko フォルダを生成してダウンロード先とする。必要なら一行目の dir のパスを書き直すのがいいと思う。

📝 radiko-dl.sh

#!/bin/zsh
# Copyright (c) 2017 uru (https://twitter.com/uru_2)
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal

dir=~/Downloads/radiko

readonly AUTHKEY_VALUE="bcd151073c03b352e1ef2fd66c32209da9ca0afa"

# オプションを取得
while [ $# -gt 0 ]
do
	case $1 in
		-id) shift; id="$1" ;;
		-ft) shift; ft="$1" ;;
		-to) shift; to="$1" ;;
		-n) shift; program="$1" ;;
		-o) shift; dir="$1" ;;
		*) break ;;
	esac
	shift
done

# ファイル名を決める
if test -z "$program"; then
	filename=`echo "$id"_"$ft"`
else
	ft_unix=`date -j -f "%Y%m%d%H%M%S" "$ft" +%s`
	hiduke=`date -r "$ft_unix" +"%Y-%m-%d-%H%M"`
	filename=`echo ${program}'_'${hiduke}`	
fi

# フォルダへ移動
if test -d "$dir"; then
	cd "$dir"
else
	mkdir "$dir"
	cd "$dir"
fi

# 承認ひとつめ
auth1=`curl \
    --silent \
    --header "X-Radiko-App: pc_html5" \
    --header "X-Radiko-App-Version: 0.0.1" \
    --header "X-Radiko-Device: pc" \
    --header "X-Radiko-User: dummy_user" \
    --dump-header - \
    --output /dev/null \
    "https://radiko.jp/v2/api/auth1"`

authtoken=$(echo "${auth1}" | awk 'tolower($0) ~/^x-radiko-authtoken: / {print substr($0,21,length($0)-21)}')
keyoffset=$(echo "${auth1}" | awk 'tolower($0) ~/^x-radiko-keyoffset: / {print substr($0,21,length($0)-21)}')
keylength=$(echo "${auth1}" | awk 'tolower($0) ~/^x-radiko-keylength: / {print substr($0,21,length($0)-21)}')

partialkey=$(echo "${AUTHKEY_VALUE}" | dd bs=1 "skip=${keyoffset}" "count=${keylength}" 2> /dev/null | base64)

# 承認ふたつめ
curl \
    --silent \
    --insecure \
    --header "X-Radiko-Device: pc" \
    --header "X-Radiko-User: dummy_user" \
    --header 'X-Radiko-AuthToken: '${authtoken} \
    --header 'X-Radiko-PartialKey: '${partialkey} \
    --output /dev/null \
    "https://radiko.jp/v2/api/auth2"

# オプションがそろっているかチェック
if test -z "$id" || test -z "$ft" || test -z "$to"; then
	echo '-id 放送局ID -ft 開始時間(20190430133000) -to 終了時間'
	exit 1
fi

# 放送済みかどうかチェック
to_unix=`date -j -f "%Y%m%d%H%M%S" "$to" +%s`
now=`date +%s`
if test $to_unix -ge $now; then
	echo '放送終了前です'
	exit 0
fi

# ダウンロード
ffmpeg \
    -loglevel error \
    -fflags +discardcorrupt \
    -headers 'X-Radiko-Authtoken: '${authtoken} \
    -i 'https://radiko.jp/v2/api/ts/playlist.m3u8?station_id='$id'&l=15&ft='$ft'&to='$to \
    -bsf:a aac_adtstoasc -acodec copy "${filename}".m4a

# 通知など出してみる
osascript -e 'display notification "'"$filename"' 完了しました" with title "radiko-dl.sh" sound name "Glass"'

開始時刻、終了時刻、番組名

このスクリプトだと開始時刻、終了時刻とかを調べるのがダルい。
 なので番組表から検索するスクリプトも書いてみた。
 radiko-dl.sh へ渡すオプションを生成することを目的としている。

追記 2020.12.05
————————–
 ラジコの仕様変更にあわせて書き直しました。
 以前はダウンロードしたファイルからエリアを調べていましたが、今回は自分でエリアを調べる必要があります。

🔗 都道府県コード

下記スクリプトの冒頭にある、area='13'の数字をお住いの都道府県の数字に書き換えてください。
—————————

📝 findradiko.sh

#!/bin/zsh

# https://nlftp.mlit.go.jp/ksj/gml/codelist/PrefCd.html
# 上記ページなどを参照にして、都道府県コードを入力する。
# 東京なら「13」
area='13'

# 作業場のフォルダへ移動する。dl-radiko.sh の作業場とあわせる
cd ~/Downloads/radiko
quick='off'
day='today'

# オプションの取得
while [ $# -gt 0 ]
do
	case $1 in
		-i) shift; id="$1" ;;
		-k) shift; keyword="$1" ;;
		-d) shift; day="$1" ;;
		-q) quick='on' ;;
		*) break ;;
	esac
	shift
done

# 放送局ID を表示する関数
function showStID() {
	curl -s https://radiko.jp/v2/station/list/JP"${1}".xml | grep -E '<\/id>|<\/name>' | sed -e 's/ //g' | perl -pe 's/<\/id>\n/ /g' | sed -e 's/<id>//g' | perl -pe 's/<name>//g' | perl -pe 's/<\/name>\n/\n/g'
}

# オプションのチェック
if test -z "$id" || test -z "$keyword"; then
	echo '-i 放送局ID -k キーワード'
	echo 'エリアコード:'$area
	echo '------------------------------'
	showStID $area
	exit 1
fi

# 日付のチェック
if ! test "$day" = 'today'; then;
	if test `echo "${#day}"` -eq 8; then;
		day='date/'"$day"
	else
		echo '日付は8桁で。(2019年10月3日 → 20191003 みたいな)'
		exit 0
	fi
fi

# 番組表の取得
prog=`curl -s https://radiko.jp/v3/program/"${day}"/JP"${area}".xml | grep -B 1 "${keyword}" | grep -E 'prog id=|master_id=|title'`

# 番組名、開始時刻、終了時刻の取得
title=`echo "${prog}" | grep -o "<title>[^<]*</title>" | sed -e 's/<[^>]*>//g'`
ft=`echo "$prog" | tr '"' '\n' | grep -A 1 'ft=' | grep -vE 'ft=|--'`
to=`echo "$prog" | tr '"' '\n' | grep -A 1 'to=' | grep -vE 'to=|--'`

# 複数の番組が見つかった場合を想定して for ループで表示。
# -q オプションがついている場合は、そのまま保存に入る。
# あんまり連続したら怒られそうなので「sleep 60」で一分間を置く。必要ないかも。
wl=`echo $title | wc | awk '{print $1}'`

for num in `seq $wl`
do           
	namae=`echo $title | sed -n "$num"p`
	hajimari=`echo $ft | sed -n "$num"p`
	owari=`echo $to | sed -n "$num"p`
	
	if test "$quick" = 'off'; then
		echo  '-n '\'"${namae}"\'' -id '"${id}"' -ft '"${hajimari}"' -to '"${owari}"
	else
		sh radiko-dl.sh -id "${id}" -ft "${hajimari}" -to "${owari}" -n "${namae}"
		if test $wl -gt $num; then
			sleep 60
		fi
	fi
done

使い方としては、
findradiko.sh -i 放送局ID -k キーワード
 で、きょうの番組表から検索する。
 2019 年 12 月 24 日 に「爆笑問題」というキーワードでこのスクリプトを実行すると、以下のような結果が返ってくる。

$ findradiko.sh -i TBS -k '爆笑問題'
-n 'JUNK 爆笑問題カーボーイ' -id TBS -ft 20191225010000 -to 20191225030000

という感じ。
 この結果をコピペして radiko-dl.sh に渡せばダウンロードがはじまる。

検索範囲はその日の放送に限る。しかし 0 時をすぎた深夜の番組もヒットする。
 日にちを指定する場合は -d オプションを使用する。「西暦月日」を 8 桁の数字にして渡
す。2019 年 12 月 22 日なら、-d 20191222。
 なお、ラジコのタイムフリーで聞ける過去の放送は、一週間前までだ。
 検索の対象となるのは番組名だけだ。パーソナリティーやゲストの名前で検索してもヒットしない。

$ findradiko.sh -i FMGUNMA -k '有吉弘行の' -d 20191222
-n '有吉弘行のSUNDAY NIGHT DREAMER' -id FMGUNMA -ft 20191222200000 -to 20191222205500
-n '有吉弘行のSUNDAY NIGHT DREAMER' -id FMGUNMA -ft 20191222210000 -to 20191222215500

このようにひとつの番組がわかれていて複数見つかったりもする。
 -q オプションをつけると自動で radiko-dl.sh にデータを渡して自動でダウンロードをはじめる。
(下から 6 行目の「sh radiko-dl.sh」を正確なパスに書き換える必要がある。デスクトップに radiko-dl.sh があるとしたら sh ~/Desktop/radiko-dl.sh という感じ)。

複数の番組がある場合、ひとつのダウンロードが終わってから一分待ち、次のダウンロードをはじめる。あんまり連続してダウンロードすると怒られそうなのでそうした。

crontab に登録する

cron はスリープ復帰してくれないが、タイムフリーのダウンロードなら時間はあまり関係ない。いつでも、Mac が起きている時間に cron をセットしておけばいいはず。

3 3 * * wed /パス/findradiko.sh -i TBS -k 'JUNK 爆笑問題カーボーイ' -q

こんな感じで-qオプションをつけておけば、番組終了の 3 分後、つまり水曜の 3 時 3 分に自動で番組が保存されて、いいと思う。

【Mac】定期的にスクリプトを実行する crontab | 林檎コンピュータ

Catalina で crontab を動かす場合は、下記の記事を参考。
macOS 10.15 catalina にしたら crontab が動かない | 林檎コンピュータ