rokkonet

PC・Androidソフトウェア・アプリの開発・使い方に関するメモ

radiko(ラジコ)ライブ録音 シェル・スクリプト

swftools, libxml2-utils, rtmpdump
 
2020 Dec. 08.
2020 Nov. 14.
2019 May 16.
2018 May  03.
2016 Nov. 06.
 
2020年12月からradikoに新たな仕様変更がなされ、下記の記事では録音できなくなった。

ライブラリインストール

(ubuntu 18.04以前)
# apt install swftools libxml2-utils rtmpdump
 
 
(ubuntu 20.04以降)
# apt install build-essential module-assistant pkg-config git
# apt install libxml2-utils rtmpdump
# apt install zlib1g-dev libjpeg8-dev libgif-dev libfreetype6-dev
$ cd YOUR/WORKING/DIR
$ git clone git://github.com/matthiaskramm/swftools
$ cd ./swftools/lib/pdf
$ perl inject-xpdf.pl xpdf-3.02.tar.gz
  Hunk ... FAILED ... は無視する。
$ cd ../..
$ ./configure
$ make
$ sudo make install

録音スクリプト

( www.lifewithunix.jp/notes/2016/10/22/radiko-recording-script-for-freebsd-updated/ より)
( www.lifewithunix.jp/notes/wp-content/uploads/2016/10/radiko2016oct_sh.txt より)

rtmpdumpは同時の複数プロセス実行可能(同時複数番組録音可能)

[rec_radiko.sh]

#!/bin/bash

  # set variables
  pid=$$
  date=`date '+%Y-%m-%d-%H:%M'`
  radiodate=`TZ=RST-9 date +%Y%m%d%H%M`
  playerurl=http://radiko.jp/apps/js/flash/myplayer-release.swf
  playerfile="/tmp/player.swf"
  keyfile="/tmp/authkey.png"

  cmdname=`basename $0`
 
  DURATION='2'
  outdir="./"
  channel1='FMO'
  channel2='FMT'
  channel3='HFM'

  if [ $# -eq 3 ]; then
    DURATION=`expr $1 \* 60`
    outdir=$2
    channel1=$3
    channel2=$3
    channel3=$3
  elif [ $# -eq 4 ]; then
    DURATION=`expr $1 \* 60`
    outdir=$2
    channel1=$3
    channel2=$4
    channel3=$4
  elif [ $# -eq 5 ]; then
    DURATION=`expr $1 \* 60`
    outdir=$2
    channel1=$3
    channel2=$4
    channel3=$5
  else
    echo "usage : $cmdname duration(minuites) output-directory channel1 [channel2 channel3]" >&2
    exit 1
  fi

  if [ ! -d "${outdir}" ]; then
    echo "${outdir} does not exist." >&2
    exit 1
  fi
  outdir="${outdir%/}"

#####################
# function                              #
#   prepare for rtmpdump  #
#####################
function prepareRtmpdump(){
  # Syntax: prepareRtmpdump CHANNEL PID DATE RADIODATE PLAYERURL PLAYERFILE KEYFILE

  local channel=$1
  local pid=$2
  local date=$3
  local radiodate=$4
  local playerurl=$5
  local playerfile=$6
  local keyfile=$7

  #
  # get player
  #
  if [ ! -f $playerfile ]; then
    wget -q -O $playerfile $playerurl
 
    if [ $? -ne 0 ]; then
      echo "failed get player" >&2
      exit 1
    fi
  fi
 

  echo 'Got player' >&2

  #
  # get keydata (need swftool)
  #
  if [ ! -f $keyfile ]; then
    # swfextract -b 14 $playerfile -o $keyfile
    swfextract -b 12 $playerfile -o $keyfile
 
    if [ ! -f $keyfile ]; then
      echo "failed get keydata" >&2
      exit 1
    fi
  fi

  if [ -f auth1_fms_${pid} ]; then
    rm -f auth1_fms_${pid}
  fi
 
  echo 'Got keydata' >&2

  #
  # 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_${pid} \
       https://radiko.jp/v2/api/auth1_fms
 
  if [ $? -ne 0 ]; then
    echo "failed auth1 process" >&2
    exit 1
  fi

  echo 'Accessed auth1_fms' >&2

  #
  # get partial key
  #
  authtoken=`perl -ne 'print $1 if(/x-radiko-authtoken: ([\w-]+)/i)' auth1_fms_${pid}`
  offset=`perl -ne 'print $1 if(/x-radiko-keyoffset: (\d+)/i)' auth1_fms_${pid}`
  length=`perl -ne 'print $1 if(/x-radiko-keylength: (\d+)/i)' auth1_fms_${pid}`
 
  partialkey=`dd if=$keyfile bs=1 skip=${offset} count=${length} 2> /dev/null | base64`
 
  echo "authtoken: ${authtoken} \noffset: ${offset} length: ${length} \npartialkey: $partialkey"

 
  rm -f auth1_fms_${pid}
 
  if [ -f auth2_fms_${pid} ]; then
    rm -f auth2_fms_${pid}
  fi
 
  echo 'Got partial key' >&2

  #
  # 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 \
    https://radiko.jp/v2/api/auth2_fms

  if [ $? -ne 0 -o ! -f auth2_fms ]; then
    echo "failed auth2 process"
    exit 1
  fi
 
  echo 'Accessed auth2_fms' >&2
  echo "authentication success" >&2
 
  areaid=`perl -ne 'print $1 if(/^([^,]+),/i)' auth2_fms_${pid}`
  echo "areaid: $areaid" >&2
 
  rm -f auth2_fms_${pid}
 
  #
  # get stream-url
  #
 
  if [ -f ${channel}.xml ]; then
    rm -f ${channel}.xml
  fi
 
  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

  echo 'Got stream-url' >&2
}


#######
# main  #
# main  #
#######
#
# check 1st channel
#
channel=${channel1}
prepareRtmpdump $channel1 $pid $date $radiodate $playerurl $playerfile $keyfile

#
# check "ERROR: " in output of 1st channel 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 \
         --stop 5\
         --flv "/tmp/${radiodate}${channel1}" \
         2> /tmp/${radiodate}${channel1}.log

grep -q 'ERROR: ' /tmp/${radiodate}${channel1}.log

# in case of outside of channel1 area
if [ $? -eq 0 ]; then
  echo "Cannot find channel: ${channel1}" >&2

  # check variable channel2 definition
  if [ -z "${channel2+x}" ] ; then
    echo "no variable: channel2" >&2
    exit 1
  fi

  #
  # check 2nd channel
  #
  channel=${channel2}
  prepareRtmpdump $channel2 $pid $date $radiodate $playerurl $playerfile $keyfile

  #
  # check "ERROR: " in output of 2nd channel 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 \
           --stop 5\
           --flv "/tmp/${radiodate}${channel2}" \
           2> /tmp/${radiodate}${channel2}.log

  grep -q 'ERROR: ' /tmp/${radiodate}${channel2}.log

  # in case of outside of channel2 area
  if [ $? -eq 0 ]; then
    echo "Cannot find channel: ${channel2}" >&2

    # check variable channel3 definition
    if [ -z "${channel3+x}" ] ; then
      echo "no variable: channel3" >&2
      exit 1
    fi

    #
    # check 3rd channel
    #
    channel=${channel3}
    prepareRtmpdump $channel3 $pid $date $radiodate $playerurl $playerfile $keyfile

    #
    # check "ERROR: " in output of 3rd channel 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 \
             --stop 5\
             --flv "/tmp/${radiodate}${channel3}" \
             2> /tmp/${radiodate}${channel3}.log

    grep -q 'ERROR: ' /tmp/${radiodate}${channel3}.log
    if [ $? -eq 0 ]; then
      echo "Cannot find channel: ${channel3}" >&2
      exit 1
    fi
  fi
fi

#
# recording
#
echo "Recording ${channel}..." >&2
prepareRtmpdump $channel $pid $date $radiodate $playerurl $playerfile $keyfile
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 ${DURATION} \
         --flv "${outdir}/${radiodate}${channel}.m4a"

exit 0


[rec_some-program.sh]

#!/bin/sh

# shell script for recording radiko through ethernet-lan
# Sunday 14:00-15:55 FM-Osaka

SCRIPTLOG="${HOME}/var/log/rec-some-program4lan.log"
duration='55'
  # duration unit : minute
dstdir='radio/recorded/'
channel1='FMO'
channel2='FMT'
channel3='HFM'

# Set IP-address to which is sent test-ICMP-packet.
DEST_ADDRESS='www.yahoo.co.jp'

#####################
# function                              #
#   check LAN connection  #
#####################
check_lan() {
  mes_stdout=`ping -c 1 $DEST_ADDRESS`
  echo $mes_stdout | grep 'received, 0% packet loss' | grep -q -v 'grep'
  if [ $? -eq 0 ]; then
    echo 'LAN connected.' >> ${SCRIPTLOG}
    return 1
  else
    echo 'LAN not connected.' >> ${SCRIPTLOG}
    return 2
  fi
}


###############
## main routine  ##
## main routine  ##
###############

echo        >> ${SCRIPTLOG}
echo `date` >> ${SCRIPTLOG}

# check internet-connection
check_lan_result=0
cnt_try_connect=0
until [ $check_lan_result -eq 1 ]
do
  if [ ${cnt_try_connect} -gt 3 ]; then
    echo 'No internet connection. Abort.' >> ${SCRIPTLOG}
    exit 1
  fi
  check_lan
  check_lan_result=$?

  if [ ${check_lan_result} -ne 1 ]; then
    cnt_try_connect=`expr $cnt_try_connect + 1`
  fi
done

sleep 35s

rec_radiko.sh $duration $dstdir $channel1 $channel2 $channel3 2>> ${SCRIPTLOG}