Raspberry Pi 3でRadikoの録音&再生

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/tmptmpfsにしていて容量が小さいとパンクしちゃいます。別のディレクトリを指定してください。

例)ワークディレクトリを/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(番組名)を変えるだけで番組専用のスクリプトになるので、録音したい番組ごとに作っておけば便利。
cmddiroutdirは適宜変更を。

cronの記述もスッキリ。

$ crontab -e
MAILTO=""
30 8 * * 1-4 /home/hoge/tbs-ijyuin.sh >/dev/null 2>&1

 

<<iPhoneへ通知を送れるようにする

広告
タグ: , , , , , ,
カテゴリー: Radiko, RaspberryPi, Raspbian

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。