55通用 M3U8 下载/解密/合并工具(AES-128/CBC)。
66
77用法:
8- python m3u8_dl.py -u <m3u8_url> -o <输出.mp4> [-k <key_hex_or_url>] [-t 超时秒数]
8+ python m3u8_dl.py -u <m3u8_url> -o <输出.mp4> [-k <key_hex_or_url>] [-t 超时秒数] [-H <headers>]
99
1010示例:
1111 # 无加密
1616
1717 # key 由服务器下发
1818 python m3u8_dl.py -u https://example.com/index.m3u8 -o movie.mp4 -k https://example.com/key.bin
19+
20+ # 使用命令行直接指定 HTTP 头
21+ python m3u8_dl.py -u https://example.com/index.m3u8 -o movie.mp4 -H "Authorization:token123 User-Agent:Mozilla/5.0"
22+
23+ # 使用头文件
24+ python m3u8_dl.py -u https://example.com/index.m3u8 -o movie.mp4 -H headers.txt
1925"""
2026from __future__ import annotations
2127
@@ -39,13 +45,15 @@ def __init__(
3945 output : str ,
4046 key : Optional [str ] = None ,
4147 timeout : int = 30 ,
48+ headers : Optional [dict ] = None ,
4249 ) -> None :
4350 self .m3u8_url = m3u8_url
4451 self .output = Path (output )
4552 self .key : Optional [bytes ] = None
4653 self .iv : Optional [bytes ] = None
4754 self .timeout = timeout
4855 self .ts_urls : List [str ] = []
56+ self .headers = headers or {}
4957
5058 # 自动创建输出目录
5159 self .output .parent .mkdir (parents = True , exist_ok = True )
@@ -54,7 +62,9 @@ def __init__(
5462 def parse (self ) -> None :
5563 logger .info ("正在下载与解析 m3u8..." )
5664 try :
57- resp = requests .get (self .m3u8_url , timeout = self .timeout )
65+ resp = requests .get (
66+ self .m3u8_url , headers = self .headers , timeout = self .timeout
67+ )
5868 resp .raise_for_status ()
5969 except KeyboardInterrupt :
6070 logger .error ("用户中断" )
@@ -94,7 +104,9 @@ def _parse_key(self, line: str) -> None:
94104 # 下载 key
95105 if uri_part .startswith ("http" ):
96106 try :
97- key_bytes = requests .get (uri_part , timeout = self .timeout ).content
107+ key_bytes = requests .get (
108+ uri_part , headers = self .headers , timeout = self .timeout
109+ ).content
98110 except KeyboardInterrupt :
99111 logger .error ("用户中断" )
100112 sys .exit (130 )
@@ -124,7 +136,9 @@ def download(self) -> None:
124136 retry = 3
125137 while retry :
126138 try :
127- resp = requests .get (ts_url , timeout = self .timeout )
139+ resp = requests .get (
140+ ts_url , headers = self .headers , timeout = self .timeout
141+ )
128142 resp .raise_for_status ()
129143 break
130144 except KeyboardInterrupt :
@@ -178,6 +192,46 @@ def run(self) -> None:
178192
179193
180194# ------------------ CLI ------------------
195+ def parse_headers (headers_arg : Optional [str ]) -> dict :
196+ """
197+ 解析 headers 参数,支持:
198+ 1. 文件路径:读取文件中的每一行作为一个头部
199+ 2. 命令行参数:直接解析 "Header1:value1 Header2:value2" 格式
200+
201+ 返回一个 headers 字典
202+ """
203+ headers = {}
204+ if not headers_arg :
205+ return headers
206+
207+ # 尝试作为文件路径处理
208+ file_path = Path (headers_arg )
209+ if file_path .exists () and file_path .is_file ():
210+ try :
211+ with open (file_path , "r" , encoding = "utf-8" ) as f :
212+ for line in f :
213+ line = line .strip ()
214+ if line and ":" in line :
215+ key , value = line .split (":" , 1 )
216+ headers [key .strip ()] = value .strip ()
217+ logger .info (f"从文件 { file_path } 加载请求头" )
218+ return headers
219+ except Exception as e :
220+ logger .warning (f"读取请求头文件失败: { e } " )
221+
222+ # 作为命令行参数解析
223+ header_pairs = headers_arg .split ()
224+ for pair in header_pairs :
225+ if ":" in pair :
226+ key , value = pair .split (":" , 1 )
227+ headers [key .strip ()] = value .strip ()
228+
229+ if headers :
230+ logger .info (f"解析到 { len (headers )} 个请求头" )
231+
232+ return headers
233+
234+
181235def main () -> None :
182236 parser = argparse .ArgumentParser (description = "M3U8 下载/解密/合并工具" )
183237 parser .add_argument ("-u" , "--url" , required = True , help = "m3u8 地址" )
@@ -188,9 +242,17 @@ def main() -> None:
188242 parser .add_argument (
189243 "-t" , "--timeout" , type = int , default = 30 , help = "超时秒数,默认 30"
190244 )
245+ parser .add_argument (
246+ "-H" ,
247+ "--headers" ,
248+ help = "HTTP 请求头文件路径或直接输入的头信息(格式: Header1:value1 Header2:value2 或文件路径)" ,
249+ )
191250 args = parser .parse_args ()
192251
193- dl = M3U8Downloader (args .url , args .output , args .key , args .timeout )
252+ # 解析 headers
253+ headers = parse_headers (args .headers )
254+
255+ dl = M3U8Downloader (args .url , args .output , args .key , args .timeout , headers )
194256 dl .run ()
195257
196258
0 commit comments