ラジオの録音、してる？　radiko api python ffmpeg

# はじめに

#### ラジオは生で聴いて楽しむもの

なんですが、、、

#### あの伝説の回をもう一度聴きたい！

なんてこと、よくありますよね〜

え、ない？私はありますよ。

そんな人にとっておきのサービスがあります。

#### そう、[オールナイトニッポンJAM](https://annjam.jp/ "神サービス")です。

オールナイトニッポン限定なんですが、神サービスここに爆誕って感じですね。

 **でもTBSラジオにも、TOKYOFMにも、RadioBerryにも、FMFUJIにも、後になって聞きたい番組たくさんあります。** 趣味全開ですが、、、

## ラジオを自分で録音すればいいじゃないか！！！

単純なことですね。

昔の人は、アナログラジオから直接録音する方法を熟知しているみたいです。

しかし私はアナログラジオなんて中学生のときに親からラジオ英会話を強制されたときから触っていません。

Radiko一筋なのです。

**だから、Radikoの音源をダウンロードして録音をしようではないか！**

となったわけです。

ネットサーフィンをすると、どうやらRadikoの録音、できるらしいですよ。

先人たちの知恵、すごい。

**実際に自作でコードを書いて、録音、できちゃいました**

なので、以下ではその方法をお教えします。

刮目せよ！

## なぜ自作のコードなのか？

世の中にはradikoの録音ができる非公式ライブラリが幾つか存在しています。

ただ、更新されていなかったり、自分好みに改編できないため、じれったいのです。

**自作なら、好きなように応用できます。**

ちなみに私がコードを書いたのは2021年で、ふと思い立ってこの記事を書いている2024年まで正常に作動し続けています。

是非ご参考に。

:::note warn
法的には録音は自由、ただしデータを他人に譲渡したり販売したりすることは法に抵触する可能性があるらしいので気を付けましょう。
::: 

:::note warn
通常のタイムフリーと同じように放送から一週間以内の音声しかダウンロードできません。
::: 

# 言語やモジュール

使用する言語やモジュールです

### python

単純に、プログラミング初心者でもあり簡単に使える言語がpythnだったというだけです。

そういう人は多いのでは？

### ffmpeg

:::note
以下で作成するpython fileと同フォルダにffmpegをダウンロードしておいてください！！！
:::

radikoの配信の方式はHLS方式で、m3u8というテキストファイルに書かれている情報をなんやかんやして音声データを小分けにしてダウンロードしているみたいです。

詳しくは[こちら](https://qiita.com/1021ky@github/items/0fc49fec62c6ab213e32#%E3%82%8F%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%93%E3%81%A8)を参考に。先人の知恵すごい。

https://qiita.com/1021ky@github/items/0fc49fec62c6ab213e32#%E3%82%8F%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%93%E3%81%A8

FFmpegは、m3u8のテキストデータからmp3などの音声データへの変換が得意みたいです。だから使います。




# 録音の実際

## 前提条件

###### radiko プレミアム会員であること

まあ、会員じゃない人が録音しようとは思わないですよね。

###### 日本からアクセスすること

radikoは海外IPアドレスからのアクセスはブロックしてしまいます。AWSやGCPで動かすとダウンロードできません。

## 番組表を取得する

必須ではありません

時間がずれたり放送が休みだったりして目的の番組が録音されないことがあるので、確認のために取得すると便利です。

[別の記事](https://qiita.com/miyama_daily/items/78408391ed2730ea777b)で番組表の取得について解説しているので参考にしてください。

https://qiita.com/miyama_daily/items/78408391ed2730ea777b

## 実際に録音する

本編はここからです。

覚悟して ~~コピペ~~ ついてきてくださいね。

録音に必要なものは、

* プレミアム会員のID(メアド),Password
* 放送局と日時

のみです。

簡単な香りがしてきました。


:::note
以下で作成するpython fileと同フォルダにffmpegをダウンロードしておいてね(n回目)
:::


```txt:requirement.txt
requests==2.31.0
```

```py:timefree.py
import os
import sys
import requests
import subprocess
from subprocess import PIPE
import base64
import json
```

## ログイン、認証
まずは **プレミアム会員のID,Password** を用いて認証を得ましょう。 **音声データにアクセスするためのauthtokenを取得**するのです。

```py:timefree.py(続き)
authkey = 'bcd151073c03b352e1ef2fd66c32209da9ca0afa'
#超重要！このままコピペしてね

email = 'おまえのメアド'
password = "おまえのパスワード" 

def auth():
    session = requests.session()
    user_data = {'mail':email, 'pass':password}

    #radiko login apiにpostして session_idとcookiesを取得します。
    response_login = session.post('https://radiko.jp/v4/api/member/login', data=user_data)
    if response_login.status_code != 200:
        print("login missed.")
        return False, "prohibited"
    session_id = json.loads(response_login.content)["radiko_session"]
    premium_cookie = session.cookies

    #取得したcookiesでarefreeのtimefreeができるかどうかをチェックするスクリプトです。プレミアム会員であるなら確認不要です。
    #res = requests.get("https://radiko.jp/ap/member/webapi/member/login/check", cookies=premium_cookie)
    #if json.loads(res.content)["areafree"] != "1":
        #print("areafree missed.")
        #return False, "prohibited"

    #auth1にgetしてauthtokenを取得します。authtokenは最終的にffmpegでm3u8から音声データを取得する際に必要です。
    #authtokenを認証させるためのpartialkeyを作成するためのkeyoffsetとkeylengthを取得します。
    headers_1 = {
    'User-Agent': 'curl/7.52.1', 
    'Accept': '*/*', 
    'x-radiko-user': 'dummy_user', 
    'x-radiko-app': 'pc_html5', 
    'x-radiko-app-version': '0.0.1', 
    'x-radiko-device': 'pc'
    }
    response_1 = requests.get('https://radiko.jp/v2/api/auth1', headers=headers_1, cookies=premium_cookie)
    if response_1.status_code != 200:
        print("auth 1 missed.")
        return False, "prohibited"
    authtoken = response_1.headers['X-Radiko-AUTHTOKEN']
    length = int(response_1.headers['X-Radiko-KeyLength'])
    offset = int(response_1.headers['X-Radiko-KeyOffset'])

    #謎の固定文字列authkeyからpartialkeyを作成します。
    partialkey = base64.b64encode(authkey[offset: offset + length].encode('utf-8')).decode('utf-8')

    #auth2にgetしてauth1で取得したauthtokenを認証します。
    headers_2 = {
        'User-Agent': 'curl/7.52.1', 
        'Accept': '*/*', 
        'x-radiko-user': 'dummy_user', 
        'X-RADIKO-AUTHTOKEN': authtoken, 
        'x-radiko-partialkey': partialkey, 
        'X-Radiko-App' : 'pc_html5',
        'X-Radiko-App-Version': '0.0.1', 
        'x-radiko-device': 'pc'
        }
    response_2 = requests.get(f'https://radiko.jp/v2/api/auth2?radiko_session={session_id}', headers=headers_2, cookies=premium_cookie)
    if response_2.status_code != 200:
        print("auth 2 missed.")
        return False, "prohibited"

    #取得したauthtokenを使って自由に音声データのダウンロードが可能になりました。
    return True, authtoken
```

## 放送局、日時を指定して録音する

**IDとPasswordでauthtokenを取得**できました。
あとは**放送局と日時を指定して録音をするだけ**です。

```py:timefree.py(続き)

def download_timefree(station_id, ft, to):
    #認証が済んだauthtokenを取得
    _, authtoken = auth()
    if authtoken == "prohibited":
        print("auth error!")
        return
    
    #ffmpegでダウンロードするためのスクリプトを文字列として用意
    #音声ファイルの拡張子はffmpegがサポートしているものならなんでもいいです。
    com = f'ffmpeg -headers "X-RADIKO-AUTHTOKEN: {authtoken}" -i "https://radiko.jp/v2/api/ts/playlist.m3u8?station_id={station_id}&l=15&ft={ft}&to={to}" -acodec copy 保存したいフォルダ/ファイル名.aac'
    
    #subprocessにてffmpegを実行
    proc = subprocess.run(com, shell=True, stdout=PIPE, stderr=PIPE, text=True)
    if proc.returncode == 0:
        print("completed!")
        return True
    else:
        print("missed!")
        return False
```

## 放送局や開始時刻の指定の仕方
station_id??　ft??　to??　どういう引数をいれればいいのか教えちゃいます。

**station_idは放送局を指定するためのID**です。
詳細は[こちら](https://qiita.com/miyama_daily/items/87c7694a10c36a11a96c)をご覧ください。

https://qiita.com/miyama_daily/items/87c7694a10c36a11a96c


**ftは録音開始時刻、toは録音終了時刻**です。

たとえば2024年5月21日13時00分00秒から2024年5月21日14時55分00秒まで録音したいときは、
**ftは 20240521130000
toは 20240521145500**
となります。
必ず**秒まで指定**してくださいね。

## 録音の一例

例としてFM TOKYOで2024年5月21日13時00分00秒から2024年5月21日14時55分00秒の間放送されていた**山崎怜奈の誰かに話したかったこと**を録音してみます。



```py:timefree.py(続き)

def main():
    args = sys.argv
    download_timefree(args[0], args[1], args[2])

if __name__ == "__main__":
    main()


```
```shell:shell
python -m timefree.py FMT 20240521130000 20240521145500
```

**これらのfunctionを走らせるだけでダウンロードできてしまいました！！！
簡単すぎる！！！**


ほんの一例であり、**上記のfunctionを応用して複数の番組を連続でダウンロードすることは可能**です。

ぜひお試しあれ。