Step2.トークン認証
ここはちょっと面倒くさいです。
トークン認証するには、https://radiko.jp/v2/api/auth2 に以下のHeaderでGETします。
X-Radiko-AuthToken: Step1で取得したX-Radiko-AuthToken X-Radiko-PartialKey: 何らかのデータ X-Radiko-Device: pc X-Radiko-User: dummy_user
さて、ここで問題となるのが”X-Radiko-PartialKey”で、これがないとトークン認証できません
X-Radiko-PartialKeyを求めるには、http://radiko.jp/apps/js/radikoJSPlayer.jsとhttp://radiko.jp/apps/js/playerCommon.jsにヒントが隠されています。
playerCommon.jsをよく見てみると…送っているHeader情報が見えますね
(Step1も同じファイルに情報があります)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | function (t, e, n) { "use strict" ; Object.defineProperty(e, "__esModule" , { value: !0 }), n(90); var r = n(243), a = function () { function t(t, e) { this ._authenticated = !1, this ._appId = t, this ._authKey = e, this ._device = r. default .getDevice() } return t.prototype.auth1 = function () { var t = new Headers({ "X-Radiko-App" : this ._appId, "X-Radiko-App-Version" : "0.0.1" , "X-Radiko-User" : "dummy_user" , "X-Radiko-Device" : this ._device }); headers: t, method: "get" , credentials: "include" }). catch ( function () { console.log( "auth1 error" ) }) }, t.prototype.auth2 = function () { var t = new Headers({ "X-Radiko-AuthToken" : this ._token, "X-Radiko-Partialkey" : <strong> this ._partialKey</strong>, "X-Radiko-User" : "dummy_user" , "X-Radiko-Device" : this ._device }); headers: t, method: "get" , credentials: "include" }). catch ( function () { console.log( "auth2 error" ) }) }, t.createPartialkey = function (t, e, n) { for ( var r = new Uint8Array(t, e, n), a = "" , i = 0; i < r.length; i++) a += String.fromCharCode(r[i]); return btoa(a) }, Object.defineProperty(t.prototype, "areaId" , { get: function () { return this ._areaId }, enumerable: !0, configurable: !0 }), Object.defineProperty(t.prototype, "areaNameKanji" , { get: function () { return this ._areaNameKanji }, enumerable: !0, configurable: !0 }), Object.defineProperty(t.prototype, "areaNameEn" , { get: function () { return this ._areaNameEn }, enumerable: !0, configurable: !0 }), Object.defineProperty(t.prototype, "authenticated" , { get: function () { return this ._authenticated }, enumerable: !0, configurable: !0 }), Object.defineProperty(t.prototype, "token" , { get: function () { return this ._token }, enumerable: !0, configurable: !0 }), t.prototype.request = function () { var e = this ; return this .auth1().then( function (n) { var a = n.headers.get( "x-radiko-authtoken" ), i = n.headers.get( "x-radiko-keyoffset" ), s = n.headers.get( "x-radiko-keylength" ); return null == a || null == i || null == s ? void console.log( "not found playlist_create_url" ) : (e._token = a, e._partialKey = t.createPartialkey(r. default .str2Buffer(e._authKey), +i, +s), e.auth2()) }).then( function (t) { return t.text() }).then( function (t) { t = t.trim(); var n = t.split( "," ), r = n[0], a = n[1], i = n[2]; return e._areaId = r, e._areaNameKanji = a, e._areaNameEn = i, e._authenticated = !0, !0 }) }, t } (); e. default = a }, |
必要なところだけ抜き出すと、
1 2 3 4 5 6 7 8 9 10 11 | i = n.headers.get( "x-radiko-keyoffset" ); s = n.headers.get( "x-radiko-keylength" ); e._partialKey = t.createPartialkey(r. default .str2Buffer(e._authKey), +i, +s); t.createPartialkey = function (t, e, n) { for ( var r = new Uint8Array(t, e, n), a = "" , i = 0; i < r.length; i++) a += String.fromCharCode(r[i]); return btoa(a); } } |
“_authKey”のi文字目からs文字を抜き出して、Base64エンコードしていることがわかります
※なんでわざわざ文字列をバイト列にして抜き出し(Uint8Array)てから、再度文字列に戻してる(String.fromCharCode)んですかね???
じゃあ、肝心の_authkeyはというと、playerCommon.jsに答えがあります
1 2 3 4 5 6 7 8 9 10 11 | player = new RadikoJSPlayer($audio[0], 'pc_html5' , 'bcd151073c03b352e1ef2fd66c32209da9ca0afa' , { onPlayStateChange: onPlayStateChange, onCurrentTimeChange: onCurrentTimeChange, onFragmentPlaying: onFragmentPlaying, onLoadStateReady: onLoadStateReady, onLoadStateError: onLoadStateError, onAuthFailure: onAuthFailure, isRadikoAreafree: isRadikoAreafree, isStationInArea: isStationInArea, onHLSPlaybackComplete: onHLSPlaybackComplete }); |
_authkeyは’bcd151073c03b352e1ef2fd66c32209da9ca0afa’です!
Step1で取得した、X-Radiko-KeyLength: 16、X-Radiko-KeyOffset: 22から、
X-Radiko-PartialKeyは、’d66c32209da9ca0a’をBASE64エンコードした、’ZDY2YzMyMjA5ZGE5Y2EwYQ==’となりました。
curlでGETすると、
curl -c cookie.txt -H 'X-Radiko-AuthToken: Zv-wZAx3hMCFEQ7dz-okdA' -H 'X-Radiko-PartialKey: ZDY2YzMyMjA5ZGE5Y2EwYQ==' -H 'X-Radiko-User: dummy_user' -H 'X-Radiko-Device: pc' -I -L https://radiko.jp/v2/api/auth2
トークン認証成功すれば、HTTP200が帰ってきます(失敗は401)
HTTP/1.1 200 OK Server: nginx Date: Sat, 23 Jun 2018 08:31:55 GMT Content-Type: text/plain Connection: keep-alive Access-Control-Expose-Headers: X-Radiko-AuthToken, X-Radiko-Partialkey, X-Radiko-AppType, X-Radiko-AuthWait, X-Radiko-Delay, X-Radiko-KeyLength, X-Radiko-KeyOffset Access-Control-Allow-Credentials: true
とりあえずここまで
次はダウンロードです。