hs-m3u8 0.1.3__tar.gz → 0.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hs-m3u8
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: m3u8 下载器
5
5
  Project-URL: homepage, https://github.com/x-haose/hs-m3u8
6
6
  Project-URL: repository, https://github.com/x-haose/hs-m3u8
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "hs-m3u8"
3
- version = "0.1.3"
3
+ version = "0.1.4"
4
4
  description = "m3u8 下载器"
5
5
  authors = [
6
6
  { name = "昊色居士", email = "xhrtxh@gmail.com" }
@@ -0,0 +1,41 @@
1
+ import asyncio
2
+
3
+ from hs_m3u8 import M3u8Downloader, M3u8Key
4
+
5
+
6
+ async def main():
7
+ url = "https://r1-ndr-private.ykt.cbern.com.cn/edu_product/esp/assets/68b6bed7-d093-7c8c-9133-95cf8205d21d.t/zh-CN/1712805650284/transcode/videos/68b6bed7-d093-7c8c-9133-95cf8205d21d-1920x1080-true-47fe81c5c8d91daf25e9fffd7082f934-eed6db5a85074b6dbbe5fa71f1243b26.m3u8"
8
+ name = "ykt"
9
+ headers = {
10
+ "Accept": "*/*",
11
+ "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
12
+ "Cache-Control": "no-cache",
13
+ "Connection": "keep-alive",
14
+ "Origin": "https://basic.smartedu.cn",
15
+ "Pragma": "no-cache",
16
+ "Referer": "https://basic.smartedu.cn/",
17
+ "Sec-Fetch-Dest": "empty",
18
+ "Sec-Fetch-Mode": "cors",
19
+ "Sec-Fetch-Site": "cross-site",
20
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
21
+ "Chrome/126.0.0.0 Safari/537.36",
22
+ "X-ND-AUTH": 'MAC id="7F938B205F876FC3C7550081F114A1A4028222C3BFB978FD9B439192D004CB8EEB65E66BB'
23
+ 'C63E66FED6DD51F34F99411A6039E623E9A9D05",nonce="1742462574752:Z4IGAAV6"'
24
+ ',mac="EUr56dXrCO1YGd3Ub1fj9MyJY9NxQPi7ZI14N/GFwpQ="',
25
+ "sec-ch-ua": '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
26
+ "sec-ch-ua-mobile": "?0",
27
+ "sec-ch-ua-platform": '"Windows"',
28
+ }
29
+ key = M3u8Key(key=bytes.fromhex("34623235336163353939353834643437"))
30
+ dl = M3u8Downloader(
31
+ m3u8_url=url,
32
+ save_path=f"../../downloads/{name}",
33
+ max_workers=64,
34
+ headers=headers,
35
+ key=key,
36
+ )
37
+ await dl.run(del_hls=False, merge=True)
38
+
39
+
40
+ if __name__ == "__main__":
41
+ asyncio.run(main())
@@ -0,0 +1,14 @@
1
+ import asyncio
2
+
3
+ from hs_m3u8 import M3u8Downloader
4
+
5
+
6
+ async def main():
7
+ url = "http://1251107588.vod2.myqcloud.com/40f34e4dvodtransgzp1251107588/722ec94f387702303749471522/voddrm.token.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9~eyJ0eXBlIjoiRHJtVG9rZW4iLCJhcHBJZCI6MTI1MTEwNzU4OCwiZmlsZUlkIjoiMzg3NzAyMzAzNzQ5NDcxNTIyIiwiY3VycmVudFRpbWVTdGFtcCI6MCwiZXhwaXJlVGltZVN0YW1wIjoyMTQ3NDgzNjQ3LCJyYW5kb20iOjAsIm92ZXJsYXlLZXkiOiIiLCJvdmVybGF5SXYiOiIiLCJjaXBoZXJlZE92ZXJsYXlLZXkiOiI0NTQ2NzliYjY5Zjg1N2M3NGZjY2YxOGM1ZTk4ZjQyMjk4YTMxMzhkYjgyMTNkZThmYjA4ZDM2MzY0MjQ0NjQ3OWFhYmZlYjk0MmYzZTE1MWNkZjM2OGQ5NGEwMzhlNjI4YjlmMTM1OGM4ODkwMjlkMzcwMjZiYzQ3MTY0MGViMWI5ODExYTg5MWU1ZmYxODk3MjliNGIyOWU4ZWExZjNkZWNkZWJmYTVjZmY0N2U4YzBjYjU4OGE2MWUxZmMzNzNmZWQxYWZhOGU5MmJmMGQ4YjFmNjIwMjM4YWJjMzYyM2FlYWVjYjlkNDI3MmI2ZmMzMmRmNjBlN2VmYjc1NjkzIiwiY2lwaGVyZWRPdmVybGF5SXYiOiIwMTYxOTE2YmI5NWRjOWJlZDgyNmI5NmE0MTY1OThkM2IyZmYyYzJmM2JhZDVmNzg2NDEyMWFlYjJiMWVmNjQwNzg0NmNmZmI5YjkyN2E1YzFlMTFhMGE0MDNlMzg5MWE4Y2VkMTJhMTYyNWRlZDFlYWYwMmJkNTI2ZGFjZWE2OGRjNjc1NTE5ZmE3MjBhYTcxNGU3MGE2MjdhM2IwM2I0YzFjMWJjNjJmODYxMDAyN2M3ZjhlYzc4MTg1MDhlNDc0YTJiZmM3NTZjOTVmMWY3NGMxYWQ5NTkyNjBhZTM0NDczNDA4OWZlMGY5YWIzZmYwYzQxZTFlNGNjYWE4YjcxIiwia2V5SWQiOjEsInN0cmljdE1vZGUiOjAsInBlcnNpc3RlbnQiOiIiLCJyZW50YWxEdXJhdGlvbiI6MCwiZm9yY2VMMVRyYWNrVHlwZXMiOm51bGx9~OvCFF2x41XbwQK_C1fUE6Orr77BeCttlt6-H5Uj8izg.video_1407500_1.m3u8?encdomain=cmv1&sign=b574e853145eeb93fcec3b26d28b9665&t=7fffffff"
8
+ name = "siyuanren"
9
+ dl = M3u8Downloader(m3u8_url=url, save_path=f"../../downloads/{name}", max_workers=64)
10
+ await dl.run(del_hls=False, merge=True)
11
+
12
+
13
+ if __name__ == "__main__":
14
+ asyncio.run(main())
@@ -0,0 +1,16 @@
1
+ import asyncio
2
+
3
+ from hs_m3u8 import M3u8Downloader
4
+
5
+
6
+ async def main():
7
+ url = (
8
+ "https://video.twimg.com/ext_tw_video/1879556885663342592/pu/pl/Vcvv0UK9lOhezJt1.m3u8?variant_version=1&tag=12"
9
+ )
10
+ name = "x"
11
+ dl = M3u8Downloader(m3u8_url=url, save_path=f"../../downloads/{name}", max_workers=64)
12
+ await dl.run(del_hls=False, merge=True)
13
+
14
+
15
+ if __name__ == "__main__":
16
+ asyncio.run(main())
@@ -0,0 +1,3 @@
1
+ from hs_m3u8.main import M3u8Downloader, M3u8Key
2
+
3
+ __version__ = "0.1.4"
@@ -54,8 +54,9 @@ class M3u8Key:
54
54
  :param key: 密钥
55
55
  :param iv: 偏移
56
56
  """
57
+ iv = bytes.fromhex(iv[2:]) if iv and iv.startswith("0x") else iv
57
58
  self.key = key
58
- self.iv = iv or key
59
+ self.iv = iv
59
60
 
60
61
 
61
62
  class M3u8Downloader:
@@ -78,6 +79,7 @@ class M3u8Downloader:
78
79
  decrypt=False,
79
80
  max_workers=None,
80
81
  headers=None,
82
+ key: M3u8Key = None,
81
83
  get_m3u8_func: Callable = None,
82
84
  ):
83
85
  """
@@ -101,6 +103,7 @@ class M3u8Downloader:
101
103
  self.save_dir = Path(save_path) / "hls"
102
104
  self.save_name = Path(save_path).name
103
105
  self.key_path = self.save_dir / "key.key"
106
+ self.custom_key = key
104
107
 
105
108
  if not self.save_dir.exists():
106
109
  self.save_dir.mkdir(parents=True)
@@ -216,10 +219,16 @@ class M3u8Downloader:
216
219
 
217
220
  # 保存解密key
218
221
  if len(m3u8_obj.keys) > 0 and m3u8_obj.keys[0]:
219
- resp = await self.net.get(m3u8_obj.keys[0].absolute_uri, headers=self.headers)
220
- key_data = resp.content
222
+ iv = m3u8_obj.keys[0].iv
223
+ if not self.custom_key:
224
+ resp = await self.net.get(m3u8_obj.keys[0].absolute_uri, headers=self.headers)
225
+ key_data = resp.content
226
+ else:
227
+ key_data = self.custom_key.key
228
+ iv = self.custom_key.iv or iv
229
+
221
230
  self.save_file(key_data, self.key_path)
222
- self.ts_key = M3u8Key(key=key_data, iv=m3u8_obj.keys[0].iv)
231
+ self.ts_key = M3u8Key(key=key_data, iv=iv)
223
232
  key = m3u8_obj.segments[0].key
224
233
  key.uri = "key.key"
225
234
  m3u8_obj.segments[0].key = key
@@ -244,7 +253,7 @@ class M3u8Downloader:
244
253
  if Path(ts_path).exists():
245
254
  self.ts_path_list[index] = str(ts_path)
246
255
  return
247
- resp = await self.net.get(ts_item["uri"])
256
+ resp = await self.net.get(ts_item["uri"], self.headers)
248
257
  ts_content = resp.content
249
258
  if ts_content is None:
250
259
  return
@@ -1,3 +0,0 @@
1
- from hs_m3u8.main import M3u8Downloader
2
-
3
- __version__ = "0.1.3"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes