m3u8 ファイルからテレビ番組を録画する

m3u8 ファイルの URL がわかっていれば、テレビアンテナがなくてもインターネットでリアルタイムでテレビを視聴することができます。

しかしリアルタイムで視聴できても、これまでは録画をすることができませんでした。

最近になって録画をする方法がやっとわかりました。

python と cron を使います。

python

m3u8 から ts ファイルをダウンロードするのは、


import urllib.request
import m3u8

def tsdn():
    playlist = m3u8.load('https://hoge.com/live_playlist.m3u8')
    
    for i, segment in enumerate(playlist.segments):
        # tsファイルのパス
        uri = segment.absolute_uri
        object_name = '/volume1/bak/python/ts/' + uri[uri.rfind('/') + 1:]
        print(object_name)
        urllib.request.urlretrieve(uri, object_name)

if __name__ == '__main__':
    tsdn()

こうするとファイル名が連番の 10 秒間の ts ファイルが 6 個ダウンロードされます。

このプログラムでは 1 分間の ts ファイルしかダウンロードされません。
そして実行時間は 1 分以上かかるので、このプログラムをループを使って動かすと ts ファイルが連続的にダウンロードされません。

python のマルチプロセスを使うとおそらくできると思いますが、chatGPT の提示したプログラムではエラーが続出しました。

例外処理をしてエラーを吐いたらもう一度プログラムを実行するのは私にとってはとても大変なので、上のような単純な python を cron でコントロールしようと考えました。

cron の設定

12:30 から 14:00 まで 1 分ごとに python を実行する cron は、


30-59/1 12      *       *       sun     python tsdown.py > myjob.log 2>&1
*/1     13      *       *       sun     python tsdown.py > myjob.log 2>&1

こうすると、ts ファイルが 500 以上ダウンロードされます。

ts ファイルを結合する

linux では ts ファイルはそのまま閲覧できます。

でも、10 秒間と短いのでそれらを結合する必要があります。

手順としては ts ファイルのリストを作成し、そのリストにしたがって結合するようです。


cd ./ts

for i in `ls -v *.ts` ; do 
    echo file "'$i'"
done > list.txt

ffmpeg -f concat -i list.txt -c copy concated_temp.ts

ts ファイルから無劣化で mp4 へ変換

python でもできるようですが、ffmpeg の方が簡単です。


ffmpeg -i input.ts -c:v copy -c:a copy output.mp4

NAS で ts ファイルをダウンロード

synology の NAS を使っていますが、pip がインストールされていない場合は ssh ログインして次のようにします。


python -m ensurepip --upgrade
python -m pip install --upgrade pip

m3u8 を pip でインストール。


pip install m3u8

cron は、


30-59/1 12  *   *  0    root    python tsdown.py > myjob.log 2>&1
1/* 13  *   *   0   root    python tsdown.py > myjob.log 2>&1

cron の再起動は、


synosystemctl restart crond

後はこのプロセスを自動化すればいいと思います。

シェルスクリプトでちょっと自動化


#!/bin/sh

rm -r ./temp/*.*

for i in `ls -v ts/*.ts` ; do 
    echo file "'$i'"
done < list.txt

ffmpeg -f concat -i list.txt -c copy ./temp/igosyogi_`date +%Y%m%d%H%M%S`.ts

for file in ./temp/*.ts; do
    echo $file
    faname_ext="${file##*/}"
    fname="${faname_ext%.*}"
    ffmpeg -i $file -c:v copy -c:a copy ./mp4/$fname.mp4
done

作成したシェルスクリプトを cron で動かします。


16      15      *       *       *       sh ~/iptv/moheno/tsmerge.sh

すべてはダウンロードできない

上の方法である程度のことはできますが、時々 ts ファイルのダウンロードがされない場合があります。10秒単位で抜け落ちてしまうのです。

その理由はよくわかりませんが、「server error」が発生するようです。

どれくらい抜け落ちるかというと、714個の ts ファイルがダウンロードされるはずのところ、631個しかないので、83個がダウンロードされなかったことになります。ざっと1割以上ですね。
囲碁などであればこれでも使えると思いますが、ボクシングなどであればいいシーンが抜けてしまうかもしれません。

10 秒ごとにプログラムを実行する

上のような方法ではかなりの部分の動画がダウンロードできず、動画としてはほとんど役に立ちません。

そこでプログラムを分単位ではなくて10秒ごとに実行することにしました。
cron で以下のようにします。


*       12      *       *       0     for i in `seq 0 10 59`;do (sleep ${i}; ~/shell.sh) & done;

shell を別に作ります。


#!/bin/sh
python ~/tsdown.py

このようにすると、ほとんどすべてがダウンロードできます。