m3u8 ファイルが変わった

(2024-10-12)

最近、netTV の一つが閲覧できなくなりました。

もともとかなり怪しいサイトにある m3u8 ファイルを使って JavaScript だけで閲覧していましたが、ネットに詳細な情報をいろいろ書き込む人が出てきて、 サイトを閉鎖せざるを得なくなったのでしょう。

そうして、もう一つある netTV は今のところは閲覧できるのですが、画像サイズが落ちたにも関わらず頻繁にフリーズするようになりました。 頻繁にフリーズするようではテレビとしてはほとんど使えません。

そこでいろいろネット情報を探して、やっと NHK の地上波だけは m3u8 の在処を見つけて、フリーズすることなく閲覧できるようにはなりました。 しかし、m3u8 ファイルの構造がこれまでとはかなり変わってしまっています。

以前の m3u8 ファイルの内容

これまでは以下のような内容でした。

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:12
#EXT-X-MEDIA-SEQUENCE:421938
#EXTINF:10.010000
JP/HD/bs292_HD-421938.ts
#EXTINF:10.011000
JP/HD/bs292_HD-421939.ts
#EXTINF:10.010000
JP/HD/bs292_HD-421940.ts
#EXTINF:10.010000
JP/HD/bs292_HD-421941.ts
#EXTINF:10.011000
JP/HD/bs292_HD-421942.ts
#EXTINF:10.010000
JP/HD/bs292_HD-421943.ts
#EXTINF:10.011000
JP/HD/bs292_HD-421944.ts
#EXTINF:10.010000
JP/HD/bs292_HD-421945.ts

ts ファイルは「トランスポートストリーミング」の略で、10 秒くらいの長さの動画ファイルです。 この情報さえあれば、python でローカルにダウンロードして merge して大きな動画ファイルを作成することができます。

ところがこれが変わってしまったのでこれまでの python ではダウンロードすることができなくなりました。

新しい m3u8 ファイルの内容

新しい m3u8 はこうなりました。

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=1670291,RESOLUTION=1280x720,CODECS="avc1.4d4029,mp4a.40.2"
d074504f-ca7a-467e-a67c-a91e69461775_output_0.m3u8?session=9Cx7WJ3NUsZqCQe8gMUuCP

ts ファイルのリストではありません。 これでは一つ一つの ts ファイルをダウンロードできません。

chatGPT に訊いて以下のようなプログラムを作成しました。

import requests
import m3u8
import os
from urllib.parse import urljoin
m3u8_url = 'https://heno/moheno.m3u8'
download_dir = '/home/user/netTV/ts'
response = requests.get(m3u8_url)
if response.status_code == 200:
print("m3u8 file downloaded successfully.")
playlist = m3u8.loads(response.text)
else:
print(f"Failed to download m3u8 file. Status code: {response.status_code}")
exit()
next_m3u8_url = urljoin(m3u8_url.rsplit('/', 1)[0] + '/', playlist.playlists[0].uri)
response = requests.get(next_m3u8_url)
if response.status_code == 200:
print("Next m3u8 file downloaded successfully.")
next_playlist = m3u8.loads(response.text)
else:
print(f"Failed to download next m3u8 file. Status code: {response.status_code}")
exit()
base_url = next_m3u8_url.rsplit('/', 1)[0] + '/'
ts_urls = [urljoin(base_url, segment.uri) for segment in next_playlist.segments]
print(f"Found {len(ts_urls)} .ts files:")
for ts_url in ts_urls[:5]:
print(ts_url)
for ts_url in ts_urls:
ts_filename = ts_url.split('/')[-1].split('?')[0]
ts_filepath = os.path.join(download_dir, ts_filename)
print(f"Downloading {ts_filename} from {ts_url}...")
response = requests.get(ts_url)
if response.status_code == 200:
with open(ts_filepath, 'wb') as f:
f.write(response.content)
print(f"Saved {ts_filename} to downloaded_ts/")
else:
print(f"Failed to download {ts_filename}. Status code: {response.status_code}")
print("All .ts files downloaded!")

こうすると確かに、ts ファイルが目的のディレクトリにダウンロードされます。 ただし、ファイル名は連番ではないので脱落があるかどうかがわかりません。

そして例によってシェルスクリプトで ts ファイルを merge して大きな mp4 ファイルに結合します。

出来上がった mp4 は full High Vision で横幅は 1280 px に戻りました。

脱落する

merge して大きな動画ファイルを作成しましたが、90 分あるはずの動画が 87 分しかありません。 動画の大きさも 1.1 GB 、これまでは full High Visionでは 1.3 GB ありました。

脱落部分もあり不完全なので録画としては使えません。残念。