再びradikoで録音したい!

かつてradikoは、radikoro2.1.1+rtmpdumpで録音することができた。

ところが、「かつて」というのは2010年の話で、今となっては当時のradikoro2.1.1では番組の視聴さえできなくなってしまっていた...。(たぶんradikoの仕様が変わったから)最新のradikoro4.0b27を使えば、ちゃんと視聴できる。それに、視聴だけならWebブラウザradikoにアクセスするだけでOK。でも録音しようとすると、radikoro4.0b27ではAudio Hijack Pro($32のシェアウェア)が必要になってくる。


Before purchase, noise is overlaid on all hijackings lasting longer than ten minutes.
To unlock the full version, purchase a license key for just $32.

      • ダウンロードはフリーなのだが、購入前は10分以上のハイジャックにはノイズが被さるようだ。

MacBookのスピーカーを鳴らす、あらゆる音を録音可能なAudio Hijack Proは素晴らしいソフトウェアなのかもしれないが、やはり自分はソースコードからビルドして自由に利用できるrtmpdumpが好き。rtmpdumpで録音する方法を模索してみた。

Web検索

模索と書いたが、radiko rtmpdump 録音でWeb検索してみると、一瞬にして先達の素晴らしい情報がヒットする。(感謝!)

そこから辿れる情報を精読していくと、あっという間にradikoの録音が可能になる。読み始めるとワクワク感が高揚して、自分でもすぐに試してみたくなる。早速、やってみた。

事前の環境作り

  • Xcode4 インストール済み
    • Xcode >> Preferences... >> Downloads >> Components >> Command Line Tools インストール済み

f:id:zariganitosh:20130120091713p:image:w450

  • Homebrew*1インストール済み
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
==> This script will install:
/usr/local/bin/brew
/usr/local/Library/...
/usr/local/share/man/man1/brew.1
==> The following directories will be made group writable:
/usr/local/.
/usr/local/bin
/usr/local/etc
/usr/local/lib
==> The following directories will have their group set to admin:
/usr/local/.
/usr/local/bin
/usr/local/etc
/usr/local/lib

Press ENTER to continue or any other key to abort
==> /usr/bin/sudo /bin/chmod g+rwx /usr/local/. /usr/local/bin /usr/local/etc /usr/local/lib
Password:
==> /usr/bin/sudo /usr/bin/chgrp admin /usr/local/. /usr/local/bin /usr/local/etc /usr/local/lib
==> Downloading and Installing Homebrew...
Warning: Now install Xcode: https://developer.apple.com/xcode/
==> Installation successful!
You should run `brew doctor' *before* you install anything.
Now type: brew help

rec_radiko.shに必要な環境作り

  • 簡易radiko録音ツールrec_radiko.shを実行すれば、radikoの録音は開始されるのだけど、そのためには以下の環境が必要。
$ brew install wget
$ brew install swftools
$ brew install rtmpdump
  • それから、後々録音した番組をiTunesiPhoneで視聴することを考えて、その変換に必要なffmpegもインストールしておいた。
$ brew install ffmpeg
  • それから、rec_radiko.shに実行権限を付与しておくのも忘れずに。
$ chmod +x rec_radiko,sh
  • 以上で、rec_radiko.shを起動すると、radikoの録音が始まった!
$ cd ~/Downloads
$ rec_radiko.sh FMJ
  • ダウンロードフォルダにFMJ.flvが保存された!(終了はcontrol-Cで)

自分好みに改良する

  • ところで、rec_radiko.shをAppleScriptのdo shell script経由で実行すると、残念ながらうまく動かない...。
  • 理由は簡単で、do shell scriptの実行環境では、rec_radiko.shに必要なコマンドサーチパスが設定されていないため。
  • そこで、さきほどインストールしたwget・swfextract・rtmpdumpコマンドはすべてフルパスで指定するように変更した。
  • さらに、オプション設定を可能な仕様にして、録音時間の指定もできるようにしてみた。
  • それから、必要な認証ファイルや録音ファイルをダウンロードする作業フォルダを~/Downloads フォルダを指定してみた。
  • 録音ファイルのファイル名は、デフォルトで「放送局名_録音開始日時.flv」とした。
    • 例えば、J-WAVEを指定して本日の17時から録音を開始すると、「J-WAVE_20130120-1700.flv」といったファイル名で保存するのだ。
#!/bin/sh

wd=$HOME/Downloads
mkdir -p $wd
cd $wd

# playerurl=http://radiko.jp/player/swf/player_2.0.1.00.swf <---radiko仕様変更点
playerurl=http://radiko.jp/player/swf/player_3.0.0.01.swf
playerfile=./player.swf
keyfile=./authkey.jpg

# 使い方
show_usage() {
  echo "Usage: $COMMAND [-o output_path] [-t recording_seconds] station_ID" 1>&2
}

# オプション解析
COMMAND=`basename $0`
while getopts o:t: OPTION
do
  case $OPTION in
    o ) OPTION_o="TRUE" ; VALUE_o="$OPTARG" ;;
    t ) OPTION_t="TRUE" ; VALUE_t="$OPTARG" ;;
    * ) show_usage ; exit 1 ;;
  esac
done

shift $(($OPTIND - 1)) #残りの非オプションな引数のみが、$@に設定される

if [ $# = 0 ]; then
  show_usage ; exit 1
fi

# オプション設定
channel=$1
station_name=`curl -s http://radiko.jp/v2/api/program/station/today?station_id=$1|xpath //station/name 2>/dev/null|sed -e 's/^<name>//' -e 's/<\/name>$//'`

if [ "$OPTION_o" = "TRUE" ]; then
  output=$VALUE_o
fi

if [ "$OPTION_t" = "TRUE" ]; then
  rectime=$VALUE_t
fi

#
# get player
#
if [ ! -f $playerfile ]; then
  /usr/local/bin/wget -q -O $playerfile $playerurl

  if [ $? -ne 0 ]; then
    echo "failed get player"
    exit 1
  fi
fi

#
# get keydata (need swftool)
#
if [ ! -f $keyfile ]; then
  # /usr/local/bin/swfextract -b 5 $playerfile -o $keyfile <---radiko仕様変更点
  /usr/local/bin/swfextract -b 14 $playerfile -o $keyfile

  if [ ! -f $keyfile ]; then
    echo "failed get keydata"
    exit 1
  fi
fi

#
# access auth1_fms
#
rm -f auth1_fms

/usr/local/bin/wget -q \
     --header="pragma: no-cache" \
     --header="X-Radiko-App: pc_1" \
     --header="X-Radiko-App-Version: 2.0.1" \
     --header="X-Radiko-User: test-stream" \
     --header="X-Radiko-Device: pc" \
     --post-data='\r\n' \
     --no-check-certificate \
     --save-headers \
     https://radiko.jp/v2/api/auth1_fms

if [ $? -ne 0 ]; then
  echo "failed auth1 process"
  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} \noffset: ${offset} \nlength: ${length} \npartialkey: $partialkey"

rm -f auth1_fms

#
# access auth2_fms
#
rm -f auth2_fms

/usr/local/bin/wget -q \
     --header="pragma: no-cache" \
     --header="X-Radiko-App: pc_1" \
     --header="X-Radiko-App-Version: 2.0.1" \
     --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 \
     https://radiko.jp/v2/api/auth2_fms

if [ $? -ne 0 -o ! -f auth2_fms ]; then
  echo "failed auth2 process"
  exit 1
fi

echo "authentication success"

areaid=`perl -ne 'print $1 if(/^([^,]+),/i)' auth2_fms`
echo "areaid: $areaid"

rm -f auth2_fms

#
# get stream-url
#
rm -f ${channel}.xml

/usr/local/bin/wget -q "http://radiko.jp/v2/station/stream/${channel}.xml"

stream_url=`echo "cat /url/item[1]/text()" | xmllint --shell ${channel}.xml | tail -2 | head -1`
url_parts=(`echo ${stream_url} | perl -pe 's!^(.*)://(.*?)/(.*)/(.*?)$/!$1://$2 $3 $4!'`)

rm -f ${channel}.xml

#
# /usr/local/bin/rtmpdump
#
/usr/local/bin/rtmpdump -v \
         -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 "${rectime}" \
         --flv "${output:=$HOME/Downloads/${station_name}_`date +%Y%m%d-%H%M`.flv}"

使い方

  • これで、J-WAVEを1時間録音したい場合は、以下のようにコマンド入力すればいいのだ。
$ rec_radiko.sh -t 3600 FMJ
  • すると1時間後には、~/Downloads/J-WAVE_20130120-1700.flvが保存され、サウージ・サウダージを楽しめるはず。
  • 録音時間の-tオプションは、秒数で指定する。
  • ちなみに、録音時間を指定しない場合、あるいは -t 0 を指定した場合は、control-Cで中止するまで録音を継続すると思う。
  • radikoは、IPアドレスによって47都道府県のエリアIPを判定する。
    • 場合によっては、現実の都道府県と異なるエリアに判定される場合もあるかもしれない。
  • 例えばJP13 東京エリアで視聴可能なラジオ局は以下のようになる。
    • こちらは、人に優しい放送局名リスト。
$ curl -s http://radiko.jp/v2/station/list/JP13.xml|xpath //name 2>/dev/null|sed -e 's///g' -e 's/<\/name>/|/g'|tr "|" "\n"
TBSラジオ
文化放送
ニッポン放送
ラジオNIKKEI第1 
ラジオNIKKEI第2
InterFM
TOKYO FM
J-WAVE
ラジオ日本 
bayfm78
NACK5
FMヨコハマ 
放送大学
    • rec_radko.shで必要になるのは、上記に対応する放送局IDリスト。
$ curl -s http://radiko.jp/v2/station/list/JP13.xml|xpath //id 2>/dev/null|sed -e 's///g' -e 's/<\/id>/|/g'|tr "|" "\n"
TBS
QRR
LFR
RN1
RN2
INT
FMT
FMJ
JORF
BAYFM78
NACK5
YFM
HOUSOU-DAIGAKU
  • 上記の放送局IDと録音時間(秒)を指定すれば、どうにか録音することができるはず。
  • ただし、まだ時間を指定したタイマー予約録音ができない...。
  • 録音したい番組が始まる時間ちょうどに、rec_radiko.shを実行する必要があるのだ。
  • せっかく録音ができるようになっても、これでは不便すぎる。
  • よって、タイマー予約できるようにしようと考えたのだが、お手軽かつ、確実にタイマー予約するためには、いくつもの関門を超える必要があった。
  • たかがタイマー予約なのだけど、タイマー予約もまた奥が深い。
  • このまま書き続けるには内容がありすぎるので、次回に続く...。

*1:Macportのようなパッケージ管理システム