ラジコ:タイムフリー番組録音をVisual Basic .Netで行うサンプル

前のメモで、ラジコタイムフリーの Auth1, Auth2 認証を処理するサンプルを書きました。

今回は、ffmpeg.exe コマンドを使って、番組を実際にダウンロードするサンプル。プログラムの流れは、前回 Auth2 認証を終了させたところまでは同じで、そのあとに追加します。

現時点のVisual Basic は、無料会員用の認証しか行っていませんので、ローカル局しか録音できません。また、コマンドラインから放送局ID、録音開始日時、録音終了日時 を入力する必要がありますが、デバッグ段階だといろいろ面倒なので、プログラム内で変数として与えることにします。

Auth2 認証時点のプログラムの後ろに追加したのが以下のスクリプト。

        
        ' ffmpeg.exe の場所をフルパスで指定
        Dim ffmpeg_path As String = "C:\Users\Path\to\ffmpeg_command\ffmpeg.exe"
        ' 本番では、コマンドラインから指定するパラメータですが、実験なのでプログラム内で決め打ちしておきます。
        Dim station_id As String = "TBS"
        Dim rec_from As String = "202211181000"
        Dim rec_to As String = "202211181010"
        '放送局IDと録音開始時刻からファイル名の一部を作ります。
        Dim prog_name As String = station_id & rec_from
        'ffmpegコマンドオプション、録音に必要になる時刻情報、所定のヘッダー情報、録音フォーマットなどを変数に定義
        Dim dl_para1 As String = ffmpeg_path & " -loglevel error -fflags +discardcorrupt "
        Dim dl_para2 As String = "-headers ""X-Radiko-AuthToken: " & x_token & """ "
        Dim dl_para3 As String = " -i ""https://radiko.jp/v2/api/ts/playlist.m3u8?station_id="
        Dim dl_para4 As String = station_id & "&" & "l=15&ft=" & rec_from & "00" & "&to=" & rec_to & "00" & """"
        Dim dl_para5 As String = " -acodec copy -vn -bsf:a aac_adtstoasc -y " & prog_name & ".m4a"
        '定義した変数を結合して、本番コマンドを作る
        Dim dl_com As String = dl_para1 & dl_para2 & dl_para3 & dl_para4 & dl_para5

        Console.WriteLine(dl_com)

        p.StartInfo.Arguments = "/c" & dl_com

        'トークン返信を起動
        p.Start()
        '出力を読み取る
        results = p.StandardOutput.ReadToEnd()
        'プロセス終了まで待機する
        'WaitForExitはReadToEndの後である必要がある
        '(親プロセス、子プロセスでブロック防止のため)
        p.WaitForExit()
        p.Close()

このサンプル単体では認証ができないので動きません。解説用のブロックです。

動かすためには以下のサンプルプログラムを使います。無料会員用としては、これで最低限のことはできるはず。

Imports System.Text

Module auth
    Sub Main(args As String())

        'まず、Auth1ようのレスポンスを処理する文字列と入れ物を準備
        ' radiko.jp にアクセスするためのカギが含まれている固定文字列
        Dim _authkey As String = "bcd151073c03b352e1ef2fd66c32209da9ca0afa"
        ' Auth1を行うとレスポンスに含まれる文字列名と、それを小文字で処理するための定義
        Dim str_token As String = "X-Radiko-AuthToken:"
        ' l_ は lower という意味で、変数名の頭に付けています。中身は、x-radiko-authtoken:
        Dim l_str_token As String = str_token.ToLower()
        Dim str_length As String = "X-Radiko-KeyLength:"
        Dim l_str_length As String = str_length.ToLower()
        Dim str_offset As String = "X-Radiko-KeyOffset:"
        Dim l_str_offset As String = str_offset.ToLower()
        '最終的に Auth1 からトークンと、長さとオフセット情報が必要になるので、次の3つの入れ物を準備しておく
        Dim x_token As String = ""
        Dim x_length As Integer = 0
        Dim x_offset As Integer = 0

        Dim auth1_para1 As String = "curl.exe -s -c cookie.txt "
        Dim auth1_para2 As String = "-H ""X-Radiko-App: pc_html5"" "
        Dim auth1_para3 As String = "-H ""X-Radiko-App-Version: 0.0.1"" "
        Dim auth1_para4 As String = "-H ""X-Radiko-User: dummy_user"" "
        Dim auth1_para5 As String = "-H ""X-Radiko-Device: pc"" "
        Dim auth1_para6 As String = "-I -L https://radiko.jp/v2/api/auth1"
        Dim auth1_curl As String = auth1_para1 & auth1_para2 & auth1_para3 & auth1_para4 & auth1_para5 & auth1_para6

        Dim p As New Process()
        'Windows環境変数から ComSpec(cmd.exe)のパスを取得して、FileNameにセット
        p.StartInfo.FileName = System.Environment.GetEnvironmentVariable("ComSpec")
        '出力を読み取れるようにする
        p.StartInfo.UseShellExecute = False
        p.StartInfo.RedirectStandardOutput = True
        p.StartInfo.RedirectStandardInput = False
        'ウィンドウを表示しないようにする
        p.StartInfo.CreateNoWindow = True

        'コマンドラインを指定("/c"は実行後閉じるために必要)
        p.StartInfo.Arguments = "/c" & auth1_curl
        'デバッグ用ライン、どんなコマンドが発行されたかを表示して一行開ける。
        Console.WriteLine(auth1_curl)
        Console.WriteLine()

        '起動
        p.Start()
        'コマンド実行結果を読み取る
        Dim results = p.StandardOutput.ReadToEnd()

        Console.WriteLine(results)

        'ラジコから返ってくるレスポンスを取り込む配列を準備する
        '改行コードまでを一つに文字列とするためにデリミターを vbCr に設定。vbCr はラジコ側の文字コードによります
        'レスポンスを順番に配列に取り込みます。
        Dim heads() As String = results.Split(vbCr)
        '配列内の値を1個ずつチェックして、必要なヘッダーか不要なものかを判断します。不要なものは捨てる。
        For Each head As String In heads
            If head.ToLower.Contains(l_str_token) = True Then
                'Auth1のトークンは、このあと何回も使うので、変数に取り込んで再利用する
                x_token = head.Remove(0, 21)
                Console.WriteLine("Authtoken: " & x_token)
            ElseIf head.ToLower.Contains(l_str_length) = True Then
                x_length = head.Remove(0, 21)
                Console.WriteLine("KeyLength: " & x_length)
            ElseIf head.ToLower.Contains(l_str_offset) = True Then
                x_offset = head.Remove(0, 21)
                Console.WriteLine("KeyOffset: " & x_offset)
            End If
        Next
        '
        Dim partial_key As String = Convert.ToBase64String(Encoding.UTF8.GetBytes(_authkey.Substring(x_offset, x_length)))
        Console.WriteLine("PartialKey: " & partial_key)
        Console.WriteLine()

        'Auth1同様、curlコマンドから引き渡すパラメータをいったん分解して定義し、あとで組み立てるようにします。
        'Auth1とパラメータが共通なオプションは、ここでは定義せず、Auth1で定義したものを再利用します。
        Dim auth2_para1 As String = "curl.exe -c cookie.txt -H ""X-Radiko-AuthToken: " & x_token & """ "
        Dim auth2_para2 As String = "-H ""X-Radiko-PartialKey: " & partial_key & """ "
        Dim auth2_para4 As String = "-L https://radiko.jp/v2/api/auth2"
        Dim auth2_curl As String = ""

        auth2_curl = auth2_para1 & auth2_para2 & auth1_para4 & auth1_para5 & auth2_para4

        p.StartInfo.Arguments = "/c" & auth2_curl

        'トークン返信を起動
        p.Start()
        '出力を読み取る
        results = p.StandardOutput.ReadToEnd()
        'デバッグ用出力
        Console.WriteLine(auth2_curl)
        Console.WriteLine()
        Console.WriteLine(results)
        Console.WriteLine()

        ' ffmpeg.exe の場所をフルパスで指定
        Dim ffmpeg_path As String = "C:\Users\user\source\repos\consCurlVB\consCurlVB\bin\Debug\netcoreapp3.1\ffmpeg.exe"
        ' 本番では、コマンドラインから指定するパラメータですが、実験なのでプログラム内で決め打ちしておきます。
        Dim station_id As String = "TBS"
        Dim rec_from As String = "202211181000"
        Dim rec_to As String = "202211181010"
        '放送局IDと録音開始時刻からファイル名の一部を作ります。
        Dim prog_name As String = station_id & rec_from
        'ffmpegコマンドオプション、録音に必要になる時刻情報、所定のヘッダー情報、録音フォーマットなどを変数に定義
        Dim dl_para1 As String = ffmpeg_path & " -loglevel error -fflags +discardcorrupt "
        Dim dl_para2 As String = "-headers ""X-Radiko-AuthToken: " & x_token & """ "
        Dim dl_para3 As String = " -i ""https://radiko.jp/v2/api/ts/playlist.m3u8?station_id="
        Dim dl_para4 As String = station_id & "&" & "l=15&ft=" & rec_from & "00" & "&to=" & rec_to & "00" & """"
        Dim dl_para5 As String = " -acodec copy -vn -bsf:a aac_adtstoasc -y " & prog_name & ".m4a"
        '定義した変数を結合して、本番コマンドを作る
        Dim dl_com As String = dl_para1 & dl_para2 & dl_para3 & dl_para4 & dl_para5

        Console.WriteLine(dl_com)

        p.StartInfo.Arguments = "/c" & dl_com

        'トークン返信を起動
        p.Start()
        '出力を読み取る
        results = p.StandardOutput.ReadToEnd()
        'プロセス終了まで待機する
        'WaitForExitはReadToEndの後である必要がある
        '(親プロセス、子プロセスでブロック防止のため)
        p.WaitForExit()
        p.Close()

    End Sub
End Module

動作確認できたら、ffmpegの場所、放送局ID、録音開始時刻、録音終了時刻 などを、設定ファイルやコマンドラインから読み込む個所を追加作成すると、利用範囲が広がります。

以上で、無料会員用のVisual Basicサンプルプログラムは終了。

続いて、エリアフリー対応できるようにプログラムを修正します。

コメントを残す