響 Radio Stationの番組(iPhone向け)を録音する

 いつもはWindows Media Player向けを録音していたのですが、「神様と運命覚醒のクロステーゼ × 日本一RADIO」の2014年6月4日更新分は番組紹介ページ内のリンクが壊れているので録音出来ませんでした。

そこで、同じ番組紹介ページにあるiPhone版をどうにかして保存できないか試してみました。

取り敢えず番組紹介ページの該当部分のリンクを見てみる。

$ wget -q -O - http://hibiki-radio.jp/description/nippon1 | grep iphone | ruby -ruri -e 'puts URI.extract(ARGF.read, "http")'
http://www2.uliza.jp/IF/iphone/iPhonePlaylist.m3u8?d=910&p=2807&v=140604_nippon1-ip

そしてそのリンク先の内容は

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=110000
http://aka-hibiki-hls-vod.uliza.jp/910/140604_nippon1_140604_nippon1-ip-00000562.m3u8

m3u8プレイリストのURLでした。じゃあこのプレイリストの中身はと言うと

$ head 140604_nippon1_140604_nippon1-ip-00000562.m3u8
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXTINF:10,
140604_nippon1_140604_nippon1-ip-00000562/23889-1.ts
#EXTINF:10,
140604_nippon1_140604_nippon1-ip-00000562/23889-2.ts
#EXTINF:10,
140604_nippon1_140604_nippon1-ip-00000562/23889-3.ts
#EXTINF:10,
140604_nippon1_140604_nippon1-ip-00000562/23889-4.ts

339個のtsファイルに分割されてるっぽい!

しょうがないから全部wgetする。連番ダウンロードはcURLの方が向いてるのですが、まああんまりサーバーに負担を掛けたくないので間隔を空けてます。

$ for i in {1..339}; do
> wget http://aka-hibiki-hls-vod.uliza.jp/910/140604_nippon1_140604_nippon1-ip-00000562/23889-${i}.ts && sleep 1
> done

ファイルが全部揃ったら、連結してみる。

$ cat 23889-{1..339}.ts >140604_nippon1_140604_nippon1-ip-00000562.ts

連結したファイルはVLC.appで再生できました。あ、wgetの “–output-document” オプションで連結したほうがスマートだったかも。

RTSPストリーミングを録音

毎週聴いていた Web ラジオのストリーミング形式が MMS から RTSP に変更されました。

当初、GNU WgetcURL コマンドで試行錯誤してみたのですが、録音出来ませんでした。><

さらに少し調べてみると、マルチメディア変換ツール FFmpeg で以下のように入力ファイルに直接 URL を指定すればいいということが分かりました。(4行で表示してますが本当は1行です)

ffmpeg -i
  rtsp://qt.web-radio.biz:1935/lantisnet/mp4:maousama_13_130531_h.mp4
  -vcodec copy -acodec copy -scodec copy
  maousama_13_130531_h.mp4

これでようやく安心して Web ラジオが楽しめます。ストリーミングってなんとなく苦手なんですよねー。

響 – Hibiki Radio Station – 録音スクリプト修正

Hibiki Radio Station の番組詳細ページの Windows Media Player ファイルを保存するためのスクリプトです。
本当はTOPページで rtmpdump するのがいいんでしょうけど手っ取り早いので。
asx ファイルが変わったみたいので対応しました。

02/05追記:なんだか頻繁に録音失敗するので、一回リトライするようにしました。っていうか mimms にレジュームオプションなんてあったんですね……。

02/13追記:mimmsは途中終了してもエラーにならないらしいので ”||” 演算子の意味が無い……。どんな場合でも二回mimmsするようにしました。

#!/bin/sh -e
# hibiki.sh ver.0.5.6 (2013-02-13)
# require wget, ruby, and mimms
TMPFILE="/var/tmp/tmp.$$"
trap 'rm -f ${TMPFILE}' EXIT

if [ $# -eq 1 ]; then
  STR=$1

  # save asx file
  wget -q -O - http://hibiki-radio.jp/description/${STR} | grep WMV | ruby -ruri -e 'puts URI.extract(ARGF.read, "http")' | head -1 | xargs wget -q -O ${TMPFILE}
  if [ -z ${TMPFILE} ]; then
    echo "download ERROR"
    exit 1
  fi
  TITLE=`cat ${TMPFILE} | ruby -rrexml/document -e 'puts REXML::Document.new(ARGF).elements["ASX/entry/title"].text'`
  WMVFILE=`cat ${TMPFILE} | ruby -rrexml/document -e 'puts REXML::Document.new(ARGF).elements["ASX/entry/Ref"].attributes["href"]'`
  if test a"$TITLE" = a"" ; then
    echo "asx detection failed."
    exit 1
  fi

  mimms -r ${WMVFILE} "${TITLE}.asf"
  mimms -r ${WMVFILE} "${TITLE}.asf"

else
  echo "usage: `basename $0` STRING"
fi

WebRadioRecorder/hibiki.sh at master · unot/WebRadioRecorder · GitHub

crontabで隔週実行

今宵は会社の忘年会でした。自分ひとりだけ別部署に派遣されているので、普段会えない人に会えるのが嬉しいですね。

それはさておき、隔週放送のwebラジオを録音したくなりました。crontabで設定しようとしたのですが、どうもひと工夫必要なようです。曜日の項で “wed/2” とか記述すると変なタイミングで実行されてしまいました。
で、Google先生にお伺いをたてて出てきたのがこの記事。

crontabで隔週実行 – jarp,

「年末年始で破綻しそう」とありますが、どうせ盆と正月は放送日程が乱れるので結局以下のようにしました。
‘%’ はエスケープすることに注意しましょう。

59 20 * * wed expr `date +\%V` \% 2 && /path/to/aandgplus.sh 60

これで「隔週水曜日20時59分」にコマンドが実行出来るようになりました。

そういえば音泉の録音用にスクリプト書いたけど

公開してませんでした。

追記:スクリプト修正しました。

いやー、我ながら気合い入ったスクリプトですね。rubyの部分は適当ですけど。あ、opensslとwgetとrubyが必要なのでご注意を。

引数なしで実行すると本日更新分を順に録音するか聞いてきます。”q” と打ってエンターキーを押すと終了、”n” だと次の番組。

a オプション
最新更新分じゃなくても録音。
y オプション
昨日更新分を録音。
v オプション
verbose モード。wgetの様子が見えたり一時ファイルを消すか聞いてきます。
w オプション
週番号指定して録音。0から6までで0が日曜日。
#!/bin/bash -e
# onsen.sh Ver. 0.8.4 (2013.02.02)
# recording tool for onsen.ag
# require openssl, wget and ruby

# target date
GOTDATE=`date +%y%m%d`
# precode of POST data
PRECODE=onsen`date +%w%d%H`
# POST data
PDATA="code=`echo $PRECODE | openssl dgst -md5 | sed -e 's/(stdin)= //'`\&file%5Fname=regular%5F"
# week number
REGXMLNUM=`date +%w`
# onsen URL
URL="http://onsen.ag/getXML.php?`date +%s`000"
# tmp file
TMPFILE="/var/tmp/tmp.$$"

AFLAG=FALSE
WGETOPTION=-q
RMOPTION=
OPT=
while getopts ayvw: OPT
do
  case $OPT in
    a) AFLAG=TRUE
       ;; # with all programs on GOTDATE
    y) GOTDATE=`TZ=JST+15 date +%y%m%d`
       REGXMLNUM=`TZ=JST+15 date +%w`
       ;; # yesterday
    v) WGETOPTION=
       RMOPTION=-i
       ;; # verbose mode
    w) REGXMLNUM=$OPTARG
       ;; # indicate week number
    \?) echo "Usage: `basename $0` [-avy] [-w weeknumber]" 1>&2
        exit 1
        ;;
  esac
done
shift `expr $OPTIND - 1`

# download regular XML file
wget ${WGETOPTION} --post-data="${PDATA}${REGXMLNUM}" ${URL} -O ${TMPFILE}

# number of program
PROGNUM=`grep -c '<title>' ${TMPFILE} | cut -d ":" -f2`
#echo "番組数: $PROGNUM"
# index number
i=1
while test ${PROGNUM} -gt 0
do
  PROGNUM=`expr ${PROGNUM} - 1`
  ISNEW=`cat ${TMPFILE} | ruby -rrexml/document -e "puts REXML::Document.new(ARGF).elements[\"data/regular/program/isNew[${i}]\"].text"`
  if test ${AFLAG} = TRUE -a ${ISNEW} = 0 ; then
    ISNEW=1
  fi
  TITLE=`cat ${TMPFILE} | ruby -rrexml/document -e "puts REXML::Document.new(ARGF).elements[\"data/regular/program/title[${i}]\"].text"`
  NUM=`cat ${TMPFILE} | ruby -rrexml/document -e "puts REXML::Document.new(ARGF).elements[\"data/regular/program/number[${i}]\"].text"`
  UPDATE=`cat ${TMPFILE} | ruby -rrexml/document -e "puts REXML::Document.new(ARGF).elements[\"data/regular/program/update[${i}]\"].text" | tr '/' '月' | sed -e 's/$/日配信/'`
  MP3FILE=`cat ${TMPFILE} | ruby -rrexml/document -e "puts REXML::Document.new(ARGF).elements[\"data/regular/program/fileUrlIphone[${i}]\"].text"`
  i=`expr ${i} + 1`
  if test ${ISNEW} != 1 ; then
    continue
  fi
  # Question
  echo -n "Record \"${TITLE} 第${NUM}回(${UPDATE}).mp3\"?[Yes/no/quit] "
  read ANSWER
  case `echo "$ANSWER" | tr [A-Z] [a-z]` in
  no | n ) ANSWER=no
           continue
           ;;
  quit | q ) break
             ;;
  * ) ANSWER=yes
      ;;
  esac

  wget ${WGETOPTION} -O "${TITLE} 第${NUM}回(${UPDATE}).mp3" ${MP3FILE}
done

rm ${RMOPTION} ${TMPFILE}
exit 0

参考

Webラジオ 質問掲示板 兼 ハヤテのごとく!応援同盟 雑談掲示板

radikoの仕様が変わってた

ことに、2回も録音失敗してから気付きました。

上記リンク先で

237 :まちがって名前消しちゃいました。:2012/10/24(水) 16:49:48.22 ID:???
player_2.0.1.00.swf

player_3.0.0.01.swf

swfextract -b 5

swfextract -b 14

radiko.smartstream.ne.jp

w-radiko.smartstream.ne.jp

simul-stream

simul-stream.stream

_defInst_

_definst_

これでイケた。

とあったのでちまちまスクリプトを修正してたら、下のGistでエレガントに解決してました。

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
#
# rtmpdump
#
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 \
    --flv $output

このままだとcronで予約録音できないので少々手を入れて使ってます。

rtmpdumpでNHK-FMを録音する

PC(というかMac)でNHK-FMを録音できないかと頼まれたのでやってみました。

必要なもの

  • rtmpdump

ストリーミングを保存するコマンド。ソースからビルド(後述)。

  • ffmpeg

保存したflvファイルを変換するコマンド。Homebrewでインストール。

rtmpdump のビルド

Homebrew で手に入る version 2.3 だと失敗するらしいのでソースからビルド。

git clone git://git.ffmpeg.org/rtmpdump
cd rtmpdump
make SYS=darwin
sudo make install SYS=darwin

make install のときも SYS=darwin が要るんですな。

録音スクリプト

以下のようなスクリプト (nhkfmrec.sh) を作りました。
引数なしで実行するとその時点から2時間+2分の録音が始まります。
第一引数で録音時間を分で指定することができます。念のため内部で2分追加してますが。
RTMPDUMP, FFMPEG, SAVEDIRは環境に応じて変更してください。

#!/bin/sh
XDATE=`date -v+1M +"%Y-%m%d-%H%M"`
STOPMINS=${1:-120}
STOPSECS=`expr ${STOPMINS} \* 60 + 120`
RTMPDUMP=/usr/local/bin/rtmpdump
FFMPEG=/usr/local/bin/ffmpeg
AFCONVERT=/usr/bin/afconvert
SAVEDIR=/Users/hoge
FLVFILE=${SAVEDIR}/NHK-FM_${XDATE}.flv
AACFILE=${FLVFILE%.flv}.aac
${RTMPDUMP} --rtmp "rtmpe://netradio-fm-flash.nhk.jp" \
    --playpath 'NetRadio_FM_flash@63343' \
    --app "live" \
    -W http://www3.nhk.or.jp/netradio/files/swf/rtmpe.swf \
    --live \
    -B $STOPSECS \
    -o ${FLVFILE}
${FFMPEG} -i ${FLVFILE} -vn -acodec copy ${AACFILE}
if [ $? != 0 ]; then
    ${FFMPEG} -i ${FLVFILE} ${AACFILE}
fi
${AFCONVERT} -f m4af -d aach -b 48000 ${AACFILE}
#rm ${FLVFILE} ${AACFILE}
exit 0

rtmpdumpコマンドで録音したファイルを flv → aac → m4a と変換してます。
--rtmp--playpath の値を変えればNHK第一や第二も録音できるはずです。

タイマー録音

Mac は完全に launchd に移行してるのかと思ったら cron も動いてるので cron で予約録音しました。launchdのためにXML書くの面倒臭いです。
crontab -e を実行して以下のように入力します。ZZコマンドで保存して終了。

59 20 * * 0 /path/to/nhkfmrec.sh 120

この設定だと「毎週日曜日20時59分に /path/to/nhkfmrec.sh 120 を実行」という意味になります。

参考

ストリーミングについての拘り

またもこの weblog システムにログインできず……一週間振りの更新となりました。あーもう!

 ところで Lantis-net とかメディアファクトリーの Web ラジオのストリーミングは Mac OS X 環境で録音しようとしても一筋縄ではいきません。音泉とか animate.tv とかは素直なのに……。素直にストリーミングで聴けと?或いはキャッシュからサルベージしろと。

 lantis は特に被害甚大。ねぶらとか超自然災害対策室とか大好きなのにー。ストリーミングの定義ファイルが他所の様に asx じゃなくて wsx になってます。asx だと直接、音声データの在り処が書いてあるのに、wsx だとループしてしまいます。

 結局、VMware Fusion で Windows 7 β を立ち上げて、そこから GetASFStream というソフトで録音しています。このソフト、Wine じゃ碌に動かないんですよねえー。

 メディファクラジオは……最近 asx に記述する形から JavaScript で新たなページに誘導する形になりました。まあ、その新たなページに一応 asx の情報が書かれてあるので、そこから mimms に食わせています。面倒臭いですが、これくらいなら何とか。

Macports を 1.7 にしてみました

昨年にリリースされていたみたいですね。

で、何故かまた mimms のアップグレードでエラー発生。環境変数QMAKESPECが設定されていないとか何とか。

しょうがないので mimms が依存している qt4-mac パッケージからインストールしなおしました。mimms自体は小さいのにqt4-macが巨大なので、インストールに何時間もかかるんですよねー。


% sudo port uninstall qt4-mac
% sudo port install mimms +qt4_mac

運良く(?)これでちゃんとインストールできました。原因がよく分かりませんねえ。

外付けHDDが壊れたー!

姉さん、事件です。iMac に繫いで Time Machine でバックアップ中に暴走した外付けHDD (Maxtor OneTouch III) が認識されなくなってしまいました。電源落とす方が稀だったからなあ……。バックアップは兎も角(大事ですが)、外付けHDDにしか保存していないファイル(Webラジオの録音したのとか)にアクセスできないのが痛手です。ドライブ本体ではなく、ケースのチップがいかれたのだと祈って、ケースだけ買い換えようと思います。ドライブ本体が壊れてしまったのなら……内蔵HDDを追加で買って入れ込みましょう。

  iMac の Firewire (IEEE1394a) ポートが空いているので Firewire 接続できるケースがいいのですが、USB のものより 5000 円くらい高くなるようです。うーん。しかし iMac の USB ポートに余裕はないし……。