【Python脚本系列】PyCryptodome库解决网盘内.m3u8视频文件无法播放的问题(三)
网盘内的.m3u8视频无法播放,这时可以利用python脚本下载video.json文件中的视频流文件,然后利用PyCryptodome解密,最后合成一个outvideo.mp4文件。
PyCryptodome是 Python 的一个加密库,功能类似 PyCrypto
,但是更现代、维护更活跃、支持更多加密算法。它提供对 AES、RSA、SHA、HMAC 等加密算法的实现,可以进行加密、解密、哈希、签名等操作。
安装方式(在 Windows 或 Linux 上):
pip install pycryptodome
在代码里使用时通常写成:
from Crypto.Cipher import AES
“Cryptodome” 这个单词可以拆开理解成两个部分:
Crypto → 来自 cryptography(密码学),表示与加密、加密技术相关。
Dome → 英文中是“圆顶、穹顶”,在这里更像是一个象征,表示“加密的保护层”或“安全的外壳”。
合起来,“Cryptodome” 可以理解为 “加密的穹顶/保护层”,也就是提供安全加密功能的库的意思。
1.现有如下m3u8的video.json文件,代码如下:
{"m3u8": "http://123.net/123/0/123_1.m3u8","m3u8BaseUri": "http://123.net/123/0/","updateTime": "2022-09-06T19:54:19.1641875+08:00","m3u8Info": {"originalCount": 39,"count": 39,"vod": true,"targetDuration": 26,"totalDuration": 953.90000000000009,"segments": [[{"index": 0,"method": "AES-128","key": "3ovxbGvr123soUt4V123xA==","iv": "0x9c12362db50c148d1234f08b759d4123","duration": 25.2,"segUri": "http://hw-mts.videocc.net/4ffae39b72/0/1234567890123/0/ff/b6/80_1/123_1_0.ts"},{"index": 1,"method": "AES-128","key": "3ovxbGvr123soUt4V123xA==","iv": "0x9c12362db50c148d1234f08b759d4123","duration": 25.0,"segUri": "http://hw-mts.videocc.net/4ffae39b72/0/1234567890123/0/ff/b6/80_1/123_1_1.ts"},{"index": 2,"method": "AES-128","key": "3ovxbGvr123soUt4V123xA==","iv": "0x9c12362db50c148d1234f08b759d4123","duration": 25.0,"segUri": "http://hw-mts.videocc.net/4ffae39b72/0/1234567890123/0/ff/b6/80_1/123_1_2.ts"}]]}
}
2.编写一段python脚本,该脚本通过读取m3u8视频的video.json文件,下载分段的ts文件,然后利用PyCryptodome库(from Crypto.Cipher import AES)解密ts文件,最后合并成output.mp4,然后就可以观看视频了。其中解密时会用到video.json里的 两个参数:
"key": "3ovxbGvr123soUt4V123xA==",
"iv": "0x9c12362db50c148d1234f08b759d4123"
具体python脚本如下:
import os
import json
import base64
import requests
from Crypto.Cipher import AES# =========================
# 配置
# =========================
json_file = "video.json" # JSON 文件路径
output_file = "output.mp4" # 最终视频输出文件
ts_dir = "ts_files" # TS 文件临时保存目录# 创建 TS 保存目录
os.makedirs(ts_dir, exist_ok=True)# =========================
# 读取 JSON
# =========================
with open(json_file, "r", encoding="utf-8") as f:data = json.load(f)# 新 JSON 格式
ts_list = data["m3u8Info"]["segments"][0]# =========================
# 下载并解密 TS
# =========================
decrypted_files = []for index, ts_item in enumerate(ts_list):ts_url = ts_item["segUri"]ts_name = os.path.join(ts_dir, f"{index}.ts")decrypted_name = os.path.join(ts_dir, f"{index}_dec.ts")# 下载 TSprint(f"Downloading {ts_url} ...")r = requests.get(ts_url, stream=True)with open(ts_name, "wb") as f:for chunk in r.iter_content(1024 * 1024):f.write(chunk)# AES Keykey = base64.b64decode(ts_item["key"])# IViv_hex = ts_item.get("iv", "").replace("0x", "")iv = bytes.fromhex(iv_hex) if iv_hex else index.to_bytes(16, byteorder='big')# 解密 TScipher = AES.new(key, AES.MODE_CBC, iv)with open(ts_name, "rb") as f_in, open(decrypted_name, "wb") as f_out:encrypted_data = f_in.read()decrypted_data = cipher.decrypt(encrypted_data)# 去掉 PKCS7 填充pad_len = decrypted_data[-1]if 1 <= pad_len <= 16:decrypted_data = decrypted_data[:-pad_len]f_out.write(decrypted_data)decrypted_files.append(decrypted_name)# =========================
# 合并 TS 文件
# =========================
with open(output_file, "wb") as f_out:for file in decrypted_files:with open(file, "rb") as f_in:f_out.write(f_in.read())print(f"Video saved as {output_file}")
以上python代码适用于网盘里无法直接观看的m3u8视频,通常有两个文件,一个是video.json,另一个是raw.m3u8,直接下载raw.m3u8得到的是video.json,所以直接对video.json里的.ts视频文件进行下载然后解密。