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を残す動きになっています。時々ファイルを削除してください
このスプリクトは試験的なもので要望など、いかなるサポートも行いません。 録音失敗や何らかの、いかなる損害が発生しても、苦情などを一切受け付けません。全て自己責任で利用してください。