Raspberry Pi 3でRadikoを録音・再生できるようにする。
録音に必要なパッケージをインストール
$ sudo apt-get install rtmpdump swftools libxml2-utils libav-tools
再生もしたい場合はmplayer
もインストール
$ sudo apt-get install mplayer
以前ODROID-U2でArchLinuxを使ってやったときはswftoolsを自分でmakeしたけど、Raspbianさんにはパッケージが提供されてるので楽ちん。
で、以前作ったラジコの再生・録音スクリプトをそのまま使おうとしたらエラーが出て使えなくなってた・・・
なので、修正。(参考)
playerurl
swfextract
X-Radiko-App
X-Radiko-App-Version
あたりを変更。
あと、ffmpeg
の代わりにをavconv
を使うように変更。
$ cat radiko.sh
#!/bin/bash pid=$$ wkdir='/var/tmp' playerurl=http://radiko.jp/apps/js/flash/myplayer-release.swf playerfile="${wkdir}/player.swf" keyfile="${wkdir}/authkey.png" auth1_fms="${wkdir}/auth1_fms_${pid}" auth2_fms="${wkdir}/auth2_fms_${pid}" date=`date +%Y%m%d_%H%M` stream_url="" url_parts="" # Usage show_usage() { echo 'Usage:' echo ' RECORD MODE' 1>&2 echo " `basename $0` [-d out_dir] [-f file_name]" 1>&2 echo ' [-t rec_minute] [-s Starting_position] channel' 1>&2 echo ' -d Default out_dir = $HOME' 1>&2 echo ' a/b/c = $HOME/a/b/c' 1>&2 echo ' /a/b/c = /a/b/c' 1>&2 echo ' ./a/b/c = $PWD/a/b/c' 1>&2 echo ' -f Default file_name = channel_YYYYMMDD_HHMM_PID' 1>&2 echo ' -t Default rec_minute = 1' 1>&2 echo ' 60 = 1 hour, 0 = go on recording until stopped(control-C)' 1>&2 echo ' -s Default starting_position = 00:00:00' 1>&2 echo ' PLAY MODE' 1>&2 echo " `basename $0` -p [-t play_minute] channel" 1>&2 echo ' -p Plya mode. No recording.' 1>&2 echo ' -t Default play_minute = 0' 1>&2 echo ' 60 = 1 hour, 0 = go on recording until stopped(control-C)' 1>&2 } # authorize authorize() { # # get player # if [ ! -f ${playerfile} ]; then wget -q -O ${playerfile} ${playerurl} if [ $? -ne 0 ]; then echo "[stop] failed get player (${playerfile})" 1>&2 ; exit 1 fi fi # # get keydata (need swftool) # if [ ! -f ${keyfile} ]; then swfextract -b 12 ${playerfile} -o ${keyfile} if [ ! -f ${keyfile} ]; then echo "[stop] failed get keydata (${keyfile})" 1>&2 ; exit 1 fi fi # # access auth1_fms # wget -q \ --header="pragma: no-cache" \ --header="X-Radiko-App: pc_ts" \ --header="X-Radiko-App-Version: 4.0.0" \ --header="X-Radiko-User: test-stream" \ --header="X-Radiko-Device: pc" \ --post-data='\r\n' \ --no-check-certificate \ --save-headers \ -O ${auth1_fms} \ https://radiko.jp/v2/api/auth1_fms if [ $? -ne 0 ]; then echo "[stop] failed auth1 process (${auth1_fms})" 1>&2 ; exit 1 fi # # get partial key # authtoken=`perl -ne 'print $1 if(/x-radiko-authtoken: ([\w-]+)/i)' ${auth1_fms}` offset=`perl -ne 'print $1 if(/x-radiko-keyoffset: (\d+)/i)' ${auth1_fms}` length=`perl -ne 'print $1 if(/x-radiko-keylength: (\d+)/i)' ${auth1_fms}` partialkey=`dd if=${keyfile} bs=1 skip=${offset} count=${length} 2> /dev/null | base64` #echo "authtoken: ${authtoken} 1>&2 #echo "offset: ${offset} 1>&2 #echo "length: ${length} 1>&2 #echo "partialkey: ${partialkey}" 1>&2 rm -f ${auth1_fms} # # access auth2_fms # wget -q \ --header="pragma: no-cache" \ --header="X-Radiko-App: pc_ts" \ --header="X-Radiko-App-Version: 4.0.0" \ --header="X-Radiko-User: test-stream" \ --header="X-Radiko-Device: pc" \ --header="X-Radiko-Authtoken: ${authtoken}" \ --header="X-Radiko-Partialkey: ${partialkey}" \ --post-data='\r\n' \ --no-check-certificate \ -O ${auth2_fms} \ https://radiko.jp/v2/api/auth2_fms if [ $? -ne 0 -o ! -f ${auth2_fms} ]; then echo "[stop] failed auth2 process (${auth2_fms})" 1>&2 ; exit 1 fi #echo "authentication success" 1>&2 areaid=`perl -ne 'print $1 if(/^([^,]+),/i)' ${auth2_fms}` #echo "areaid: ${areaid}" 1>&2 rm -f ${auth2_fms} # # get stream-url # wget -q -O ${ch_xml} \ "http://radiko.jp/v2/station/stream/${channel}.xml" if [ $? -ne 0 -o ! -f ${ch_xml} ]; then echo "[stop] failed stream-url process (channel=${channel})" rm -f ${ch_xml} ; show_usage ; exit 1 fi stream_url=`echo "cat /url/item[1]/text()" | \ xmllint --shell ${ch_xml} | tail -2 | head -1` url_parts=(`echo ${stream_url} | \ perl -pe 's!^(.*)://(.*?)/(.*)/(.*?)$/!$1://$2 $3 $4!'`) rm -f ${ch_xml} } # Record record() { # rtmpdump rtmpdump -r ${url_parts[0]} \ --app ${url_parts[1]} \ --playpath ${url_parts[2]} \ -W ${playerurl} \ -C S:"" -C S:"" -C S:"" -C S:${authtoken} \ --live \ --stop ${duration} \ --flv "${wkdir}/${tempname}.flv" avconv -ss ${starting} -i "${wkdir}/${tempname}.flv" \ -acodec copy "${wkdir}/${tempname}.m4a" && \ rm -f "${wkdir}/${tempname}.flv" mv -b "${wkdir}/${tempname}.m4a" "${outdir}/${filename}.m4a" if [ $? -ne 0 ]; then echo "[stop] failed move file (${wkdir}/${tempname}.m4a to \ ${outdir}/${filename}.m4a)" 1>&2 ; exit 1 fi } # Play play() { # rtmpdump rtmpdump -r ${url_parts[0]} \ --app ${url_parts[1]} \ --playpath ${url_parts[2]} \ -W $playerurl \ -C S:"" -C S:"" -C S:"" -C S:$authtoken \ --live \ --stop ${duration} | \ mplayer - } # debug debug() { echo "-p : ${OPTION_p}" echo "-d : ${OPTION_d} value: \"${VALUE_d}\"" echo "-f : ${OPTION_f} value: \"${VALUE_f}\"" echo "-t : ${OPTION_t} value: \"${VALUE_t}\"" echo "-s : ${OPTION_s} value: \"${VALUE_s}\"" echo '' echo "channel : \"${channel}\"" echo "outdir : \"${outdir}\"" echo "filename: \"${filename}\"" echo "duration: \"${duration}\"" echo "starting: \"${starting}\"" echo '' } # Get Option while getopts pd:f:t:s: OPTION do case $OPTION in p ) OPTION_p=true ;; d ) OPTION_d=true VALUE_d="$OPTARG" ;; f ) OPTION_f=ture VALUE_f="$OPTARG" ;; t ) OPTION_t=true VALUE_t="$OPTARG" if ! expr "${VALUE_t}" : '[0-9]*' > /dev/null ; then show_usage ; exit 1 fi ;; s ) OPTION_s=ture VALUE_s="$OPTARG" ;; * ) show_usage ; exit 1 ;; esac done # Get Channel shift $(($OPTIND - 1)) if [ $# -ne 1 ]; then show_usage ; exit 1 fi channel=$1 ch_xml="${wkdir}/${channel}${pid}.xml" # # RECORD Mode # if [ ! "${OPTION_p}" ]; then # Get Directory if [ ! "$OPTION_d" ]; then cd ${HOME} else if echo ${VALUE_d}|grep -q -v -e '^./\|^/'; then mkdir -p "${HOME}/${VALUE_d}" if [ $? -ne 0 ]; then echo "[stop] failed make directory (${HOME}/${VALUE_d})" 1>&2 ; exit 1 fi cd "${HOME}/${VALUE_d}" else mkdir -p ${VALUE_d} if [ $? -ne 0 ]; then echo "[stop] failed make directory (${VALUE_d})" 1>&2 ; exit 1 fi cd ${VALUE_d} fi fi outdir=${PWD} # Get File Name filename=${VALUE_f:=${channel}_${date}_${pid}} tempname=${channel}_${pid} # Get Minute min=${VALUE_t:=1} duration=`expr ${min} \* 60` # Get Starting Position starting=${VALUE_s:='00:00:00'} # debug authorize && record # # PLAY Mode # else # Get Minute duration=`expr ${VALUE_t:=0} \* 60` # debug authorize && play fi
録音の場合、録音用のデータがテンポラリーファイルを含め大きくなるので、保存先、ワークディレクトリが置かれているパーティションサイズ(容量)に気おつけてください。
ワークディレクトリの場所は/var/tmp
になってます。/var/tmp
をtmpfs
にしていて容量が小さいとパンクしちゃいます。別のディレクトリを指定してください。
例)ワークディレクトリを/home/hoge/tmp
に変更
# wkdir='/var/tmp' # ワークディレクトリを/var/tmp以外のところに変更 wkdir='/home/hoge/tmp'
ちなみに、2時間の録音で45MBくらい、2.5時間で58MBくらいのtmpファイル(flvファイル)が作られます。
使い方は同じまま。昔の記事の「録音したいとき/再生したいとき」の箇所を見てね。
例)
./radiko.sh -d /mnt/nas/media -f テスト -t 1 TBS
保存先:/mnt/nas/media
ファイル名:テスト
録音時間:1分
チャンネル:TBS
保存先にm4aファイルができていれば成功。
$ ls /mnt/nas/media
テスト.m4a
あとはcronでスケジューリングしておけば勝手に録音してくれる。
$ crontab -e
MAILTO="" 30 6 * * 1-5 /home/hoge/radiko.sh -d /mnt/nas/radiko -f スタンバイ -t 120 TBS > /dev/null 2>&1
自分はradiko.sh
を直接呼び出すのではなく、番組ごとにスクリプトを書いておいて、それをcronで呼び出すようにしてる。
番組用スクリプトはこんな感じ。
$ cat tbs-ijyuin.sh
#!/bin/bash ch="TBS" # チャンネル rectime="150" # 録音時間 title="伊集院とらじおと" # 番組名(ファイル名用) dat=`date '+%Y%m%d'` # 日付(ファイル名用) cmddir="/home/hoge" # radiko.sh、prowl.pl、apikeyの場所 outdir="/mnt/nas/radiko" # 保存先(自分はNAS上の共有フォルダ) # Prowl通知(開始) ${cmddir}/prowl.pl -apikeyfile=${cmddir}/apikey \ -priority=0 \ -application="RaspberryPi3" \ -event="Radiko" \ -notification="録音を開始:"${title} & # 録音開始 ${cmddir}/radiko.sh -d ${outdir} -f "${title} ${dat}" -t ${rectime} ${ch} # Prowl通知(終了) ${cmddir}/prowl.pl -apikeyfile=${cmddir}/apikey \ -priority=0 \ -application="RaspberryPi3" \ -event="Radiko" \ -notification="録音を終了:"${title}
ch
(チャンネル)、rectime
(録音時間)、title
(番組名)を変えるだけで番組専用のスクリプトになるので、録音したい番組ごとに作っておけば便利。
※cmddir
とoutdir
は適宜変更を。
cronの記述もスッキリ。
$ crontab -e
MAILTO="" 30 8 * * 1-4 /home/hoge/tbs-ijyuin.sh >/dev/null 2>&1
[…] いろいろネットで調べてみた結果、”Raspberry Pi 3でRadikoの録音&再生“に掲載しているコードで無事に実行できるようになりました。 […]