radiko.jpをバッチファイルとWSHで録音する

–2020年11月27日追記–
※現在radiko.jpの仕様変更で下記の記事は実行できません。

以前の記事でradiko.jpを録音する方法を記事にした。
その時、github.comのbooskaのRadikoを録音するWSHのスプリクトを利用することで録音することを紹介していた。しかし、booskaさんのソースは公開中止になって現在Windows環境で動くスプリクトは他に見当たらなくなってしまった。

いろいろ検討した結果、booskaさんのスプリクトを参照してバッチファイルとWSHで作成した。現在動作確認中だがほぼ利用可能な状況になったのでここに紹介することにする

作成はWindows 10環境で作成しています。動作確認はWindows 7です。

利用にあたって
rtmpdump.exe
https://github.com/K-S-V/Scripts/releases

wget.exe
https://eternallybored.org/misc/wget/

swfextract.exe
http://www.swftools.org/download.html
swfextract.exeはSWFToolsをインストールしたフォルダにあります。

ffmpeg.exe
http://hp.vector.co.jp/authors/VA020429/ffmpeg/ffmpeg.html
https://ffmpeg.org/

各種実行ファイルを集めて一つのフォルダに置いてください

RadikoRec.bat

@echo off

REM rtmpdumpなどの位置のドライブ
set drive=D:

REM rtmpdumpなどの位置(最後に\を)
set DFDirectory=D:\RadikoRec\

REM 録音ファイルの保存のドライブ
set argdrive=D:

REM 録音ファイルの保存先(最後に\を)
set argDirectory=D:\RadikoRec\rec\

set RTMPDUMP=rtmpdump.exe
set AYTHKeyGet=AYTHKeyGet.vbs
set argOut = "out"
set RTMPSERVER=rtmpe://f-radiko.smartstream.ne.jp:1935

%drive%
cd %DFDirectory%

rem 録音ファイルの保存先フォルダチェックと作成
IF NOT EXIST "%argDirectory%" (md %argDirectory%)
IF NOT EXIST "%argDirectory%OLD" (md %argDirectory%OLD)

set ch=%1
if "%1"=="" goto usage
if not "%2"=="" set argSTOPSEC=%2
if "%2"=="" goto usage
if not "%3"=="" set argOut=%3

rem 録音終了日時を求める
for /f "tokens=1,2" %%i in ('CScript Time.vbs /r:%argSTOPSEC%') do (
  SET AUTHTOKEN_D=%%i
  SET AUTHTOKEN_T=%%j
)

set loopck=0

:loop

for /f %%i in ('CScript %AYTHKeyGet% %ch%') do SET AUTHTOKEN=%%i

rem 録音時間を秒に変換
for /f %%i in ('CScript Time.vbs /d:%AUTHTOKEN_D% /t:%AUTHTOKEN_T%') do SET AUTHTOKEN_END=%%i
set STOPSEC=--stop %AUTHTOKEN_END%

if "%loopck%" == "0" set FLV_loop=
if "%loopck%" geq "1" set FLV_loop=(%loopck%)

set yyyymmdd=%date: =0%
set hhmmss=%time: =0%
set YMD=%yyyymmdd:~0,4%%yyyymmdd:~5,2%%yyyymmdd:~8,2%_%hhmmss:~0,2%%hhmmss:~3,2%%hhmmss:~6,2%
set FLV=%YMD%_%ch%_%argOut%
set RADI=%RTMPDUMP% -q -flashVer "WIN 15,0,0,152" -v -r "%RTMPSERVER%" --playpath "simul-stream.stream" --app "%ch%/_definst_" -C S:"" -C S:"" -C S:"" -C S:%AUTHTOKEN% --live --timeout 10 --flv "%argDirectory%%FLV%%FLV_loop%.flv" %STOPSEC%

echo 録音開始%date%_%time%_"%~3" >> log.txt
echo 「%ch%」の「%argOut%」を録音開始、録音時間は「%argSTOPSEC%」
echo %RADI%
%RADI%
echo 録音停止%date%_%time%_"%~3" >> log.txt

for /f %%i in ('CScript Time.vbs /d:%AUTHTOKEN_D% /t:%AUTHTOKEN_T%') do SET AUTHTOKEN_EXIT=%%i
if "%AUTHTOKEN_EXIT%" == "EXIT" goto loopEXIT
if "%loopck%" geq "20" goto loopEXIT
set /a loopck=loopck+1

REM Sleep[15秒数]
set /a wtime=15*1000
echo WScript.Sleep %wtime% > tmp.vbs
cscript //NoLogo tmp.vbs
del tmp.vbs
set wtime=
REM ***

goto loop

:loopEXIT

%argdrive%
cd %argDirectory%
for %%F in (*.flv) do goto FILE_EXIST
echo エラーファイルが無い%date%_%time%_%argOut% >> %DFDirectory%log.txt
goto end

:FILE_EXIST
echo MP3変換開始%date%_%time%_"%argOut%" >> %DFDirectory%log.txt
REN *"%argOut%"*.flv *.m4a
for %%i in (*"%argOut%"*.m4a) do %DFDirectory%ffmpeg.exe  -y -i "./%%~ni.m4a" -vn -acodec libmp3lame -strict unofficial "./%%~ni.mp3"
move *"%argOut%"*.m4a OLD\ >> %DFDirectory%log.txt
echo MP3変換完了%date%_%time%_"%argOut%" >> %DFDirectory%log.txt
goto end

:usage
echo "RadikoRec.bat TBS 1:00:00 菊地成孔の粋な夜電波"
:end

D:\RadikoRec\にて実行する設定になっています
途中で回線が切断されても時間計算して再録音し最後にmp3に変換するようになっています。
-起動例-
radiko.bat TBS 1:00:00 菊地成孔の粋な夜電波
radiko.bat TBS 録音時間1時間 録音番組名(ファイル名に含まれます)

AYTHKeyGet.vbs

Option Explicit

Dim argStation,argDebug,argSilent,cookiefile,mail,pass,checkfile,loginfile,PROXY,PROXY_T

'radiko premium
mail = ""
pass = ""

PROXY = "" 'プロキシサーバー 例:xx.xx.xx.xx.xx:8080 

argStation = "TBS"    '引数1(i):radiko.jp内の放送局のid
argDebug = "no"        '"yes"なら、動作の途中経過を逐次表示する
argSilent = "yes"    '"yes"なら、外部コマンドであるwgetやrtmpdumpの実行プロンプトを表示しない
loginfile = "login.txt"
cookiefile = "cookie.txt"
checkfile = "pre_check.txt"

Dim i
Dim strCmd
Dim objFSO
Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
Dim aUnnamed
Set aUnnamed = WScript.Arguments.Unnamed
If aUnnamed.Count > 0 Then
    For i = 0 To aUnnamed.Count - 1
        Select Case i
            Case 0
                argStation = aUnnamed.Item(i)
        End Select
    Next
End If

'プロキシサーバー
If not PROXY = "" Then
    PROXY = " -e HTTP_PROXY=" & PROXY

End If

'シェル起動オブジェクトを生成
Dim WSHShell,gShellStyle
Set WSHShell = WScript.CreateObject("WScript.Shell")
If argSilent = "yes" Then
    gShellStyle = 7
Else
    gShellStyle = 10
End IF

'ファイルシステム用オブジェクトを生成(ラジコ独自認証でファイルを利用)
Dim WSHFS
Set WSHFS = CreateObject("Scripting.FileSystemObject")

    strCmd = GetRadikoCmd()

WScript.Quit(0)

'Radiko.jpの独自認証を行う
Function GetRadikoCmd()

    Dim playerurl,pSwfPlayer,pKeyFile,RtnCD,auth1_fms,auth2_fms
    'playerurl = "http://radiko.jp/player/swf/player_4.0.0.00.swf"
    playerurl = "http://radiko.jp/apps/js/flash/myplayer-release.swf"

    Dim pTmpName
    pTmpName = WSHFS.GetTempName()
    pSwfPlayer = "player_" & argStation & pTmpName & ".swf"
    pKeyFile = "authkey_" & argStation & pTmpName & ".png"
    auth1_fms = "auth1_fms_" & argStation & pTmpName
    auth2_fms = "auth2_fms_" & argStation & pTmpName

    'radiko premium
    if not (mail = "") then
        RtnCD = WSHShell.run("wget.exe -q --save-cookie=" & cookiefile _
                & " --keep-session-cookies" & PROXY _
                & " --post-data=""mail=" & mail & "&pass=" & pass & """" _
                & " -O " & loginfile & PROXY _
                & " https://radiko.jp/ap/member/login/login",gShellStyle,True)
        If RtnCD <> 0 Then
            GetRadikoCmd = "error 認証ステップ0:radiko premiumの取得失敗!"
            premiumLogoutCmd()
            Exit Function
        Else
            If argDebug = "yes" Then WScript.Echo "認証ステップ0:radiko premiumの取得成功"
        End If

        WScript.Sleep 2000
        if not objFso.FileExists(cookiefile) then
            WScript.Echo "failed login1"
            premiumLogoutCmd()
            Exit Function
        End IF
    End IF


    'check login
    if not (mail = "") then
        RtnCD = WSHShell.run("wget.exe -q" _
                & " --header=""pragma: no-cache""" _
                & " --header=""Cache-Control: no-cache""" _
                & " --header=""Expires: Thu, 01 Jan 1970 00:00:00 GMT""" _
                & " --header=""Accept-Language: ja-jp""" _
                & " --header=""Accept-Encoding: gzip, deflate""" _
                & " --header=""Accept: application/json, text/javascript, */*; q=0.01""" _
                & " --header=""X-Requested-With: XMLHttpRequest""" _
                & " --no-check-certificate " _
                & " --load-cookies " & cookiefile _
                & " --save-headers " _
                & " -O " & checkfile & PROXY _
                & " https://radiko.jp/ap/member/webapi/member/login/check",gShellStyle,True)
        If RtnCD <> 0 Then
            GetRadikoCmd = "error 認証ステップ0:radiko premiumの取得失敗!"
            premiumLogoutCmd()
            Exit Function
        Else
            If argDebug = "yes" Then WScript.Echo "認証ステップ0:radiko premiumの取得成功"
        End If

        WScript.Sleep 2000 
        if not objFso.FileExists(checkfile) then
            WScript.Echo "failed login2"
            premiumLogoutCmd()
            Exit Function
        End IF
    End IF

    '認証ステップ1:Radikoのswfプレイヤーをplayer.swfというファイル名でダウンロード
    RtnCD = WSHShell.run("wget.exe -q --timeout=60 --tries=10 -O """ & pSwfPlayer & """ """ & playerurl & """" & PROXY ,gShellStyle,True)
    If RtnCD <> 0 Then
        GetRadikoCmd = "error 認証ステップ1:player.swfの取得失敗!"
        premiumLogoutCmd()
        Exit Function
    Else
        If argDebug = "yes" Then WScript.Echo "認証ステップ1:player.swfの取得成功"
    End If

    '認証ステップ2:player.swfからauthkey.pngを抜き出す
    RtnCD = WSHShell.run("swfextract.exe" & " -b 12 """ & pSwfPlayer & """ -o """ & pKeyFile & """",gShellStyle,True)
    If RtnCD <> 0 Then
        GetRadikoCmd = "error 認証ステップ2:authkey.pngの抜き出し失敗!"
        premiumLogoutCmd()
        Exit Function
    Else
        If argDebug = "yes" Then WScript.Echo "認証ステップ2:authkey.pngの抜き出し成功"
    End If

    '認証ステップ3:auth1_fmsを取得
    RtnCD = WSHShell.run("wget.exe -q --timeout=60 --tries=10" _
            & " --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" _
            & " --load-cookies " & cookiefile _
            & " --save-headers https://radiko.jp/v2/api/auth1_fms" _
            & " -O """ & auth1_fms & """" & PROXY ,gShellStyle,True)
    If RtnCD <> 0 Then
        GetRadikoCmd = "error 認証ステップ3:auth1_fmsファイルの取得失敗!"
        premiumLogoutCmd()
        Exit Function
    Else
        If argDebug = "yes" Then WScript.Echo "認証ステップ3:auth1_fmsファイルの取得成功"
    End If

    '認証ステップ4:auth1_fmsから、authtoken,length,offsetを読み取る
    Dim pFile
    Dim pLine
    Dim pAuthtoken,pLength,pOffset
    Set pFile = WSHFS.OpenTextFile(auth1_fms,1)
    Do While pFile.AtEndOfStream = False
        pLine = pFile.ReadLine
        If InStr(LCase(pLine),"x-radiko-authtoken=") <> 0 Then
            pAuthtoken = mid(pLine,InStr(pLine,"=")+1,len(pLine)-InStr(pLine,"="))
        ElseIf InStr(LCase(pLine),"x-radiko-keylength=") <> 0 Then
            pLength = mid(pLine,InStr(pLine,"=")+1,len(pLine)-InStr(pLine,"="))
        ElseIf InStr(LCase(pLine),"x-radiko-keyoffset=") <> 0 Then
            pOffset = mid(pLine,InStr(pLine,"=")+1,len(pLine)-InStr(pLine,"="))
        End If
    Loop
    pFile.Close

    If argDebug = "yes" Then WScript.Echo "認証ステップ4:x-radiko-authtoken=" & pAuthtoken & " ,x-radiko-keylength=" & pLength & " ,x-radiko-keyoffset=" & pOffset

    '認証ステップ5:authkey.pngのoffsetのlengthの内容から、base64の値であるpartialkeyを求める
    Dim pXmldom,pB64,pStream,partialkey

    Set pXmldom = CreateObject("Microsoft.XMLDOM")
    Set pB64 = pXmldom.CreateElement("work")
    pB64.DataType = "bin.base64"

    Set pStream = CreateObject("ADODB.Stream")
    pStream.Type = 1
    pStream.Open
    pStream.LoadFromFile pKeyFile
    pStream.position = pOffset
    pB64.NodeTypedValue = pStream.Read(pLength)

    partialkey = pB64.Text
    pStream.Close
    Set pStream = Nothing

    If argDebug = "yes" Then WScript.Echo "認証ステップ5:partialkey=" & partialkey

    '認証ステップ6:上記で求めたキーからauthtokenとpartialkeyをradikoに送り認証を成立させる
    Dim key
    RtnCD = WSHShell.run("wget.exe -q --timeout=60 --tries=10" _
          & " --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: " & pAuthtoken & """"_
          & " --header=""X-Radiko-Partialkey: " & partialkey & """"_
          & " --post-data=""\r\n""" _
          & " --load-cookies " & cookiefile _
          & " --no-check-certificate" _
          & " https://radiko.jp/v2/api/auth2_fms" _
          & " -O """ & auth2_fms & """" & PROXY ,gShellStyle,True)
    If RtnCD <> 0 Then
        GetRadikoCmd = "error 認証ステップ6:authtokenとpartialkeyの失敗!"
        premiumLogoutCmd()
        Exit Function
    Else
        If argDebug = "yes" Then WScript.Echo "認証ステップ6:authtokenとpartialkeyの送信成功"
    End If
    'テンポラリファイルを消す
    If argDebug <> "yes" Then
        WSHFS.DeleteFile pSwfPlayer, True
        WSHFS.DeleteFile pKeyFile, True
        WSHFS.DeleteFile auth1_fms, True
        WSHFS.DeleteFile auth2_fms, True
        if not (mail = "") then
            WSHFS.DeleteFile loginfile, True
            WSHFS.DeleteFile checkfile, True

        End If
    End If

        WScript.Echo(pAuthtoken)

    premiumLogoutCmd()

End Function

Function premiumLogoutCmd()

    Dim RtnCD
    'radiko premium Logout
    if not (mail = "") then
        RtnCD = WSHShell.run("wget -q" _
            & " --header=""pragma: no-cache""" _
            & " --header=""Cache-Control: no-cache""" _
            & " --header=""Expires: Thu, 01 Jan 1970 00:00:00 GMT""" _
            & " --header=""Accept-Language: ja-jp""" _
            & " --header=""Accept-Encoding: gzip, deflate""" _
            & " --header=""Accept: application/json, text/javascript, */*; q=0.01""" _
            & " --header=""X-Requested-With: XMLHttpRequest""" _
            & " --no-check-certificate "_
            & " --load-cookies $cookiefile "_
            & " --save-headers "_
            & " -O $logoutfile" & PROXY _
            & " https://radiko.jp/ap/member/webapi/member/logout",gShellStyle,True)
        If RtnCD <> 0 Then
            GetRadikoCmd = "error radiko premiumのLogout失敗!"
            Exit Function
        Else
            If argDebug = "yes" Then WScript.Echo "radiko premiumのLogout取得成功"
        End If
        if objFso.FileExists(cookiefile) then
            WSHFS.DeleteFile cookiefile, True
        End IF
    End IF

End Function

radiko.batと同じ場所においてください
この部分はbooskaさんのスプリクトを参考しました

修正しました
radiko.jpのラジコプレミアムに対応した
投稿日: 2017年2月2日
http://hanpen.lsv.jp/blog.hanpen.net/radiko-jp%e3%81%ae%e3%83%a9%e3%82%b8%e3%82%b3%e3%83%97%e3%83%ac%e3%83%9f%e3%82%a2%e3%83%a0%e3%81%ab%e5%af%be%e5%bf%9c%e3%81%97%e3%81%9f/

Time.vbs

' CScript Time.vbs /r:0:01:00
' CScript Time.vbs /d:2016/12/14 /t:18:47:44

Option Explicit
Dim argRecTime
Dim value
dim gRecTime
dim argDay
dim argTime
Dim aNamed
Set aNamed = WScript.Arguments.Named

argRecTime = WScript.Arguments.Named.Item("r")
argDay = WScript.Arguments. Named.Item("d")
argTime = WScript.Arguments. Named.Item("t")

if not (argRecTime = "") Then

    '引数で指定の録音時間を日時属性に変換
    gRecTime = TimeValue(argRecTime)

    '録音終了日時を求める
    Dim gEndDate
    gEndDate = Now() + gRecTime
    WScript.Echo gEndDate

End If

if not (argDay = "") Then

    '引数で指定の録音時間を日時属性に変換

    argDay = DateValue(argDay)

    if (argTime = "") Then
        argRecTime = argDay
    Else
        argRecTime = TimeValue(argTime)
        argRecTime = argDay + argRecTime
    End If

    '録音秒数をrtmpdumpの引数形式(秒数)にする
    gRecTime = argRecTime - Now()
    if (gRecTime > 0) Then
        gRecTime = Hour(gRecTime) * 60 * 60 + Minute(gRecTime) * 60 + Second(gRecTime) + 20
        '20秒ほどマージンを設けることで録音終了時の誤差でリトライにいってしまうことを防止する。
    Else
        gRecTime ="EXIT"
    End If
    WScript.Echo gRecTime

End If

録音時間計算のスプリクトです。バッチファイルで時間計算は大変なのでWSHで処理します

2016年12月28日 修正しました
http://hanpen.lsv.jp/blog.hanpen.net/time-vbs%e3%81%ab%e3%83%90%e3%82%b0%e3%81%8c%e3%81%82%e3%82%8a%e3%81%be%e3%81%97%e3%81%9f/

TBS_schtasks.bat

goto kome

/sc 種類 	スケジュールの種類を指定する。指定できる種類は次の通り。
種類 	内容
MINUTE 	分単位でスケジュールを指定
HOURLY 	時間単位でスケジュールを指定
DAILY 	日単位でスケジュールを指定
WEEKLY 	週単位でスケジュールを指定
MONTHLY 	月単位でスケジュールを指定
ONCE 	指定した日時に一回限り実行
ONSTART 	システム起動ごとに実行
ONLOGON 	ログオンごとに実行
ONIDLE 	アイドル状態が一定時間続いた場合に実行

/d 日 	曜日または日にちを指定する。 スケジュールの種類が「WEEKLY」、または「MONTHLY」の場合に有効。
曜日は以下のように3文字で表す。
値 	内容
MON 	月曜日
TUE 	火曜日
WED 	水曜日
THU 	木曜日
FRI 	金曜日
SAT 	土曜日
SUN 	日曜日
MON,TUE,WED,THU,FRI,SAT,SUN
スケジュールの種類と指定できる値は次の通り。
WEEKLYの場合 MON~SUN、あるいは「*(毎日)」。 省略時は「/d MON」を指定したとみなされる。
MONTHLYの場合 1~31の数字。省略時は「/d 1」 を指定したとみなされる。「/mo」オプションに
FIRST、SECOND、THIRD、FOURTH、LAST が指定されている場合は、必ず「/d」オプションで曜日を指定する。

TBS
QRR
LFR
RN1
RN2
INT
FMT
FMJ
JORF
BAYFM78
NACK5
YFM
HOUSOU-DAIGAKU

:kome

SCHTASKS /CREATE /TN "TBS_菊地成孔の粋な夜電波" /TR "D:\RadikoRec\RadikoRec.bat TBS 1:01:00 菊地成孔の粋な夜電波" /SC WEEKLY /d FRI /ST 23:59

pause

タスクスケジューラを使って予約する為のバッチファイル
(schtasks.batは管理者として実行してください)

以上4つの実行ファイルと2つのバッチファイルと2つのvbsファイルと同じフォルダに置いて(上記の例ではD:\RadikoRec)
TBS_schtasks.batに録音したい番組を記入してタスクスケジューラに登録して実行する形になります。
タスクスケジューラにて実行するため後日動作確認する時用に実行フォルダにLOGを残す動きになっています。時々ファイルを削除してください

このスプリクトは試験的なもので要望など、いかなるサポートも行いません。 録音失敗や何らかの、いかなる損害が発生しても、苦情などを一切受け付けません。全て自己責任で利用してください。

関連記事
http://hanpen.lsv.jp/blog.hanpen.net/%e3%82%89%e3%81%98%e3%82%8b%e2%98%85%e3%82%89%e3%81%98%e3%82%8b%e3%82%92%e3%83%90%e3%83%83%e3%83%81%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%81%a8wsh%e3%81%a7%e9%8c%b2%e9%9f%b3%e3%81%99%e3%82%8b/

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)