hs-m3u8 0.1.6__tar.gz → 0.1.7__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.
- {hs_m3u8-0.1.6 → hs_m3u8-0.1.7}/PKG-INFO +2 -2
- {hs_m3u8-0.1.6 → hs_m3u8-0.1.7}/pyproject.toml +5 -27
- {hs_m3u8-0.1.6 → hs_m3u8-0.1.7}/src/hs_m3u8/main.py +19 -5
- hs_m3u8-0.1.6/.pre-commit-config.yaml +0 -18
- hs_m3u8-0.1.6/requirements-dev.lock +0 -209
- hs_m3u8-0.1.6/requirements.lock +0 -157
- hs_m3u8-0.1.6/src/example/__init__.py +0 -0
- hs_m3u8-0.1.6/src/example/jav_1.py +0 -14
- hs_m3u8-0.1.6/src/example/jav_2.py +0 -33
- hs_m3u8-0.1.6/src/example/jav_3.py +0 -14
- hs_m3u8-0.1.6/src/example/kyt.py +0 -43
- hs_m3u8-0.1.6/src/example/movie_1.py +0 -14
- hs_m3u8-0.1.6/src/example/movie_2.py +0 -14
- hs_m3u8-0.1.6/src/example/siyuanren.py +0 -14
- hs_m3u8-0.1.6/src/example/x.py +0 -16
- {hs_m3u8-0.1.6 → hs_m3u8-0.1.7}/.gitignore +0 -0
- {hs_m3u8-0.1.6 → hs_m3u8-0.1.7}/README.md +0 -0
- {hs_m3u8-0.1.6 → hs_m3u8-0.1.7}/src/hs_m3u8/__init__.py +0 -0
- {hs_m3u8-0.1.6 → hs_m3u8-0.1.7}/src/hs_m3u8/res/ffmpeg_win.exe.zip +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hs-m3u8
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
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
|
|
@@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
21
21
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
22
|
Requires-Python: >=3.10
|
|
23
|
-
Requires-Dist: hssp>=0.4.
|
|
23
|
+
Requires-Dist: hssp>=0.4.18
|
|
24
24
|
Requires-Dist: m3u8>=6.0.0
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
26
26
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "hs-m3u8"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.7"
|
|
4
4
|
description = "m3u8 下载器"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "昊色居士", email = "xhrtxh@gmail.com" }
|
|
@@ -26,7 +26,7 @@ requires-python = ">= 3.10"
|
|
|
26
26
|
|
|
27
27
|
dependencies = [
|
|
28
28
|
"m3u8>=6.0.0",
|
|
29
|
-
"hssp>=0.4.
|
|
29
|
+
"hssp>=0.4.18",
|
|
30
30
|
]
|
|
31
31
|
|
|
32
32
|
[project.urls]
|
|
@@ -38,26 +38,14 @@ documentation = "https://github.com/x-haose/hs-m3u8"
|
|
|
38
38
|
requires = ["hatchling"]
|
|
39
39
|
build-backend = "hatchling.build"
|
|
40
40
|
|
|
41
|
-
[tool.
|
|
42
|
-
managed = true
|
|
43
|
-
dev-dependencies = [
|
|
44
|
-
"pre-commit>=4.0.1",
|
|
45
|
-
"twine>=6.0.1",
|
|
46
|
-
]
|
|
41
|
+
[tool.hatch.build.targets.sdist]
|
|
47
42
|
include = [
|
|
48
|
-
"src/hs_m3u8
|
|
43
|
+
"src/hs_m3u8",
|
|
49
44
|
]
|
|
50
45
|
|
|
51
|
-
[tool.hatch.metadata]
|
|
52
|
-
allow-direct-references = true
|
|
53
|
-
|
|
54
46
|
[tool.hatch.build.targets.wheel]
|
|
55
47
|
packages = ["src/hs_m3u8"]
|
|
56
48
|
|
|
57
|
-
[[tool.rye.sources]]
|
|
58
|
-
name = "default"
|
|
59
|
-
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
|
60
|
-
|
|
61
49
|
[tool.bandit]
|
|
62
50
|
skips = [
|
|
63
51
|
"B404",
|
|
@@ -127,20 +115,10 @@ ignore = [
|
|
|
127
115
|
# do not perform function calls in argument defaults
|
|
128
116
|
"B008",
|
|
129
117
|
# too complex
|
|
130
|
-
"C901"
|
|
118
|
+
"C901",
|
|
131
119
|
]
|
|
132
120
|
fixable = ["ALL"]
|
|
133
121
|
unfixable = []
|
|
134
122
|
|
|
135
123
|
[tool.ruff.lint.per-file-ignores]
|
|
136
124
|
"__init__.py" = ["F401"]
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
[tool.rye.scripts]
|
|
140
|
-
publish_testpypi = { cmd = "rye run twine upload -r testpypi dist/*" }
|
|
141
|
-
publish_pypi = { cmd = "rye run twine upload dist/*" }
|
|
142
|
-
sb = { cmd = "rye build --clean" }
|
|
143
|
-
spt = { chain = ["sb", "publish_testpypi"] }
|
|
144
|
-
sp = { chain = ["sb", "publish_pypi"] }
|
|
145
|
-
check_i = { cmd = "rye run pre-commit install" }
|
|
146
|
-
check = { cmd = "rye run pre-commit run --all-files" }
|
|
@@ -17,6 +17,7 @@ from zipfile import ZipFile
|
|
|
17
17
|
import m3u8
|
|
18
18
|
from hssp import Net
|
|
19
19
|
from hssp.models.net import RequestModel
|
|
20
|
+
from hssp.network.response import Response
|
|
20
21
|
from hssp.utils import crypto
|
|
21
22
|
from loguru import logger
|
|
22
23
|
|
|
@@ -82,8 +83,11 @@ class M3u8Downloader:
|
|
|
82
83
|
key: M3u8Key = None,
|
|
83
84
|
get_m3u8_func: Callable = None,
|
|
84
85
|
m3u8_request_before: Callable[[RequestModel], RequestModel] = None,
|
|
86
|
+
m3u8_response_after: Callable[[Response], Response] = None,
|
|
85
87
|
key_request_before: Callable[[RequestModel], RequestModel] = None,
|
|
88
|
+
key_response_after: Callable[[Response], Response] = None,
|
|
86
89
|
ts_request_before: Callable[[RequestModel], RequestModel] = None,
|
|
90
|
+
ts_response_after: Callable[[Response], Response] = None,
|
|
87
91
|
):
|
|
88
92
|
"""
|
|
89
93
|
|
|
@@ -96,8 +100,11 @@ class M3u8Downloader:
|
|
|
96
100
|
get_m3u8_func: 处理m3u8情求的回调函数。适用于m3u8地址不是真正的地址,
|
|
97
101
|
而是包含m3u8内容的情求,会把m3u8_url的响应传递给get_m3u8_func,要求返回真正的m3u8内容
|
|
98
102
|
m3u8_request_before: m3u8请求前的回调函数
|
|
103
|
+
m3u8_response_after: m3u8响应后的回调函数
|
|
99
104
|
key_request_before: key请求前的回调函数
|
|
100
|
-
|
|
105
|
+
key_response_after: key响应后的回调函数
|
|
106
|
+
ts_request_before: ts请求前的回调函数
|
|
107
|
+
ts_response_after: ts响应后的回调函数
|
|
101
108
|
"""
|
|
102
109
|
|
|
103
110
|
sem = asyncio.Semaphore(max_workers) if max_workers else None
|
|
@@ -107,16 +114,22 @@ class M3u8Downloader:
|
|
|
107
114
|
self.m3u8_net = Net(sem=sem)
|
|
108
115
|
if m3u8_request_before:
|
|
109
116
|
self.m3u8_net.request_before_signal.connect(m3u8_request_before)
|
|
117
|
+
if m3u8_response_after:
|
|
118
|
+
self.m3u8_net.response_after_signal.connect(m3u8_response_after)
|
|
110
119
|
|
|
111
120
|
# 加密key的请求器
|
|
112
121
|
self.key_net = Net()
|
|
113
122
|
if key_request_before:
|
|
114
123
|
self.key_net.request_before_signal.connect(key_request_before)
|
|
124
|
+
if key_response_after:
|
|
125
|
+
self.key_net.response_after_signal.connect(key_response_after)
|
|
115
126
|
|
|
116
127
|
# ts内容的请求器
|
|
117
128
|
self.ts_net = Net()
|
|
118
129
|
if ts_request_before:
|
|
119
130
|
self.ts_net.request_before_signal.connect(ts_request_before)
|
|
131
|
+
if ts_response_after:
|
|
132
|
+
self.ts_net.response_after_signal.connect(ts_response_after)
|
|
120
133
|
|
|
121
134
|
self.decrypt = decrypt
|
|
122
135
|
self.m3u8_url = urlparse(m3u8_url)
|
|
@@ -146,6 +159,7 @@ class M3u8Downloader:
|
|
|
146
159
|
:return:
|
|
147
160
|
"""
|
|
148
161
|
mp4_path = self.save_dir.parent / f"{self.save_name}.mp4"
|
|
162
|
+
mp4_path = mp4_path.absolute()
|
|
149
163
|
if Path(mp4_path).exists():
|
|
150
164
|
self.logger.info(f"{mp4_path}已存在")
|
|
151
165
|
if del_hls:
|
|
@@ -155,7 +169,7 @@ class M3u8Downloader:
|
|
|
155
169
|
self.logger.info(
|
|
156
170
|
f"开始下载: 合并ts为mp4={merge}, "
|
|
157
171
|
f"删除hls信息={del_hls}, "
|
|
158
|
-
f"下载地址为:{self.m3u8_url.geturl()}. 保存路径为:{self.save_dir}"
|
|
172
|
+
f"下载地址为:{self.m3u8_url.geturl()}. 保存路径为:{self.save_dir.absolute()}"
|
|
159
173
|
)
|
|
160
174
|
|
|
161
175
|
await self._download()
|
|
@@ -165,7 +179,7 @@ class M3u8Downloader:
|
|
|
165
179
|
self.logger.info(f"TS应下载数量为:{count_1}, 实际下载数量为:{count_2}")
|
|
166
180
|
if count_1 == 0 or count_2 == 0:
|
|
167
181
|
self.logger.error("ts数量为0,请检查!!!")
|
|
168
|
-
return
|
|
182
|
+
return None
|
|
169
183
|
|
|
170
184
|
if count_2 != count_1:
|
|
171
185
|
self.logger.error(f"ts下载数量与实际数量不符合!!!应该下载数量为:{count_1}, 实际下载数量为:{count_2}")
|
|
@@ -282,7 +296,7 @@ class M3u8Downloader:
|
|
|
282
296
|
return
|
|
283
297
|
|
|
284
298
|
if self.ts_key and self.decrypt:
|
|
285
|
-
ts_content = crypto.
|
|
299
|
+
ts_content = crypto.decrypt_aes_256_cbc(ts_content, self.ts_key.key, self.ts_key.iv)
|
|
286
300
|
|
|
287
301
|
self.save_file(ts_content, ts_path)
|
|
288
302
|
self.logger.info(f"{ts_uri}下载成功")
|
|
@@ -321,7 +335,7 @@ class M3u8Downloader:
|
|
|
321
335
|
with open(path, "rb") as ts_file:
|
|
322
336
|
data = ts_file.read()
|
|
323
337
|
if self.ts_key:
|
|
324
|
-
data = crypto.
|
|
338
|
+
data = crypto.decrypt_aes_256_cbc(data, self.ts_key.key, self.ts_key.iv)
|
|
325
339
|
big_ts_file.write(data)
|
|
326
340
|
big_ts_file.close()
|
|
327
341
|
self.logger.info("ts文件整合完毕")
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# See https://pre-commit.com for more information
|
|
2
|
-
# See https://pre-commit.com/hooks.html for more hooks
|
|
3
|
-
repos:
|
|
4
|
-
# bandit
|
|
5
|
-
- repo: https://github.com/PyCQA/bandit
|
|
6
|
-
rev: 1.7.10
|
|
7
|
-
hooks:
|
|
8
|
-
- id: bandit
|
|
9
|
-
args: [ "-c", "pyproject.toml" ]
|
|
10
|
-
additional_dependencies: [ "bandit[toml]" ]
|
|
11
|
-
|
|
12
|
-
# ruff
|
|
13
|
-
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
14
|
-
rev: 'v0.6.9'
|
|
15
|
-
hooks:
|
|
16
|
-
- id: ruff
|
|
17
|
-
args: [ --fix, --exit-non-zero-on-fix, --show-fixes ]
|
|
18
|
-
- id: ruff-format
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
# generated by rye
|
|
2
|
-
# use `rye lock` or `rye sync` to update this lockfile
|
|
3
|
-
#
|
|
4
|
-
# last locked with the following flags:
|
|
5
|
-
# pre: false
|
|
6
|
-
# features: []
|
|
7
|
-
# all-features: false
|
|
8
|
-
# with-sources: false
|
|
9
|
-
# generate-hashes: false
|
|
10
|
-
# universal: false
|
|
11
|
-
|
|
12
|
-
-e file:.
|
|
13
|
-
aiohttp==3.9.5
|
|
14
|
-
# via hssp
|
|
15
|
-
aiosignal==1.3.1
|
|
16
|
-
# via aiohttp
|
|
17
|
-
annotated-types==0.7.0
|
|
18
|
-
# via pydantic
|
|
19
|
-
anyio==4.6.2.post1
|
|
20
|
-
# via httpx
|
|
21
|
-
apscheduler==3.10.4
|
|
22
|
-
# via hssp
|
|
23
|
-
attrs==24.2.0
|
|
24
|
-
# via aiohttp
|
|
25
|
-
blinker==1.9.0
|
|
26
|
-
# via hssp
|
|
27
|
-
certifi==2024.8.30
|
|
28
|
-
# via curl-cffi
|
|
29
|
-
# via httpcore
|
|
30
|
-
# via httpx
|
|
31
|
-
# via requests
|
|
32
|
-
cffi==1.17.1
|
|
33
|
-
# via curl-cffi
|
|
34
|
-
cfgv==3.4.0
|
|
35
|
-
# via pre-commit
|
|
36
|
-
charset-normalizer==3.4.0
|
|
37
|
-
# via requests
|
|
38
|
-
click==8.1.7
|
|
39
|
-
# via drissionpage
|
|
40
|
-
cssselect==1.2.0
|
|
41
|
-
# via drissionpage
|
|
42
|
-
# via parsel
|
|
43
|
-
curl-cffi==0.7.3
|
|
44
|
-
# via hssp
|
|
45
|
-
datarecorder==3.6.2
|
|
46
|
-
# via downloadkit
|
|
47
|
-
distlib==0.3.9
|
|
48
|
-
# via virtualenv
|
|
49
|
-
docutils==0.21.2
|
|
50
|
-
# via readme-renderer
|
|
51
|
-
downloadkit==2.0.5
|
|
52
|
-
# via drissionpage
|
|
53
|
-
drissionpage==4.1.0.12
|
|
54
|
-
# via hssp
|
|
55
|
-
et-xmlfile==2.0.0
|
|
56
|
-
# via openpyxl
|
|
57
|
-
fake-useragent==1.5.1
|
|
58
|
-
# via hssp
|
|
59
|
-
filelock==3.16.1
|
|
60
|
-
# via tldextract
|
|
61
|
-
# via virtualenv
|
|
62
|
-
frozenlist==1.5.0
|
|
63
|
-
# via aiohttp
|
|
64
|
-
# via aiosignal
|
|
65
|
-
furl==2.1.3
|
|
66
|
-
# via hssp
|
|
67
|
-
h11==0.14.0
|
|
68
|
-
# via httpcore
|
|
69
|
-
h2==4.1.0
|
|
70
|
-
# via httpx
|
|
71
|
-
hpack==4.0.0
|
|
72
|
-
# via h2
|
|
73
|
-
hssp==0.4.7
|
|
74
|
-
# via hs-m3u8
|
|
75
|
-
httpcore==1.0.6
|
|
76
|
-
# via httpx
|
|
77
|
-
httpx==0.27.2
|
|
78
|
-
# via hssp
|
|
79
|
-
hyperframe==6.0.1
|
|
80
|
-
# via h2
|
|
81
|
-
identify==2.6.2
|
|
82
|
-
# via pre-commit
|
|
83
|
-
idna==3.10
|
|
84
|
-
# via anyio
|
|
85
|
-
# via httpx
|
|
86
|
-
# via requests
|
|
87
|
-
# via tldextract
|
|
88
|
-
# via yarl
|
|
89
|
-
jaraco-classes==3.4.0
|
|
90
|
-
# via keyring
|
|
91
|
-
jaraco-context==6.0.1
|
|
92
|
-
# via keyring
|
|
93
|
-
jaraco-functools==4.1.0
|
|
94
|
-
# via keyring
|
|
95
|
-
jmespath==1.0.1
|
|
96
|
-
# via parsel
|
|
97
|
-
keyring==25.6.0
|
|
98
|
-
# via twine
|
|
99
|
-
loguru==0.7.2
|
|
100
|
-
# via hssp
|
|
101
|
-
lxml==5.3.0
|
|
102
|
-
# via drissionpage
|
|
103
|
-
# via parsel
|
|
104
|
-
m3u8==6.0.0
|
|
105
|
-
# via hs-m3u8
|
|
106
|
-
markdown-it-py==3.0.0
|
|
107
|
-
# via rich
|
|
108
|
-
mdurl==0.1.2
|
|
109
|
-
# via markdown-it-py
|
|
110
|
-
more-itertools==10.6.0
|
|
111
|
-
# via jaraco-classes
|
|
112
|
-
# via jaraco-functools
|
|
113
|
-
multidict==6.1.0
|
|
114
|
-
# via aiohttp
|
|
115
|
-
# via yarl
|
|
116
|
-
nh3==0.2.20
|
|
117
|
-
# via readme-renderer
|
|
118
|
-
nodeenv==1.9.1
|
|
119
|
-
# via pre-commit
|
|
120
|
-
openpyxl==3.1.5
|
|
121
|
-
# via datarecorder
|
|
122
|
-
orderedmultidict==1.0.1
|
|
123
|
-
# via furl
|
|
124
|
-
packaging==24.2
|
|
125
|
-
# via parsel
|
|
126
|
-
# via twine
|
|
127
|
-
parsel==1.9.1
|
|
128
|
-
# via hssp
|
|
129
|
-
pkginfo==1.12.0
|
|
130
|
-
# via twine
|
|
131
|
-
platformdirs==4.3.6
|
|
132
|
-
# via virtualenv
|
|
133
|
-
pre-commit==4.0.1
|
|
134
|
-
propcache==0.2.0
|
|
135
|
-
# via yarl
|
|
136
|
-
psutil==6.1.0
|
|
137
|
-
# via drissionpage
|
|
138
|
-
pycparser==2.22
|
|
139
|
-
# via cffi
|
|
140
|
-
pycryptodomex==3.21.0
|
|
141
|
-
# via hssp
|
|
142
|
-
pydantic==2.9.2
|
|
143
|
-
# via hssp
|
|
144
|
-
# via pydantic-settings
|
|
145
|
-
pydantic-core==2.23.4
|
|
146
|
-
# via pydantic
|
|
147
|
-
pydantic-settings==2.6.1
|
|
148
|
-
# via hssp
|
|
149
|
-
pygments==2.19.1
|
|
150
|
-
# via readme-renderer
|
|
151
|
-
# via rich
|
|
152
|
-
python-dotenv==1.0.1
|
|
153
|
-
# via pydantic-settings
|
|
154
|
-
pytz==2024.2
|
|
155
|
-
# via apscheduler
|
|
156
|
-
pyyaml==6.0.2
|
|
157
|
-
# via pre-commit
|
|
158
|
-
# via pydantic-settings
|
|
159
|
-
readme-renderer==44.0
|
|
160
|
-
# via twine
|
|
161
|
-
requests==2.32.3
|
|
162
|
-
# via downloadkit
|
|
163
|
-
# via drissionpage
|
|
164
|
-
# via hssp
|
|
165
|
-
# via requests-file
|
|
166
|
-
# via requests-toolbelt
|
|
167
|
-
# via tldextract
|
|
168
|
-
# via twine
|
|
169
|
-
requests-file==2.1.0
|
|
170
|
-
# via tldextract
|
|
171
|
-
requests-toolbelt==1.0.0
|
|
172
|
-
# via twine
|
|
173
|
-
rfc3986==2.0.0
|
|
174
|
-
# via twine
|
|
175
|
-
rich==13.9.4
|
|
176
|
-
# via twine
|
|
177
|
-
six==1.16.0
|
|
178
|
-
# via apscheduler
|
|
179
|
-
# via furl
|
|
180
|
-
# via orderedmultidict
|
|
181
|
-
sniffio==1.3.1
|
|
182
|
-
# via anyio
|
|
183
|
-
# via httpx
|
|
184
|
-
tenacity==9.0.0
|
|
185
|
-
# via hssp
|
|
186
|
-
tldextract==5.1.3
|
|
187
|
-
# via drissionpage
|
|
188
|
-
tomli==2.1.0
|
|
189
|
-
# via pydantic-settings
|
|
190
|
-
twine==6.0.1
|
|
191
|
-
typing-extensions==4.12.2
|
|
192
|
-
# via curl-cffi
|
|
193
|
-
# via pydantic
|
|
194
|
-
# via pydantic-core
|
|
195
|
-
tzlocal==5.2
|
|
196
|
-
# via apscheduler
|
|
197
|
-
urllib3==2.2.3
|
|
198
|
-
# via requests
|
|
199
|
-
# via twine
|
|
200
|
-
uvloop==0.21.0
|
|
201
|
-
# via hssp
|
|
202
|
-
virtualenv==20.27.1
|
|
203
|
-
# via pre-commit
|
|
204
|
-
w3lib==2.2.1
|
|
205
|
-
# via parsel
|
|
206
|
-
websocket-client==1.8.0
|
|
207
|
-
# via drissionpage
|
|
208
|
-
yarl==1.17.1
|
|
209
|
-
# via aiohttp
|
hs_m3u8-0.1.6/requirements.lock
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
# generated by rye
|
|
2
|
-
# use `rye lock` or `rye sync` to update this lockfile
|
|
3
|
-
#
|
|
4
|
-
# last locked with the following flags:
|
|
5
|
-
# pre: false
|
|
6
|
-
# features: []
|
|
7
|
-
# all-features: false
|
|
8
|
-
# with-sources: false
|
|
9
|
-
# generate-hashes: false
|
|
10
|
-
# universal: false
|
|
11
|
-
|
|
12
|
-
-e file:.
|
|
13
|
-
aiohttp==3.9.5
|
|
14
|
-
# via hssp
|
|
15
|
-
aiosignal==1.3.1
|
|
16
|
-
# via aiohttp
|
|
17
|
-
annotated-types==0.7.0
|
|
18
|
-
# via pydantic
|
|
19
|
-
anyio==4.6.2.post1
|
|
20
|
-
# via httpx
|
|
21
|
-
apscheduler==3.10.4
|
|
22
|
-
# via hssp
|
|
23
|
-
attrs==24.2.0
|
|
24
|
-
# via aiohttp
|
|
25
|
-
blinker==1.9.0
|
|
26
|
-
# via hssp
|
|
27
|
-
certifi==2024.8.30
|
|
28
|
-
# via curl-cffi
|
|
29
|
-
# via httpcore
|
|
30
|
-
# via httpx
|
|
31
|
-
# via requests
|
|
32
|
-
cffi==1.17.1
|
|
33
|
-
# via curl-cffi
|
|
34
|
-
charset-normalizer==3.4.0
|
|
35
|
-
# via requests
|
|
36
|
-
click==8.1.7
|
|
37
|
-
# via drissionpage
|
|
38
|
-
cssselect==1.2.0
|
|
39
|
-
# via drissionpage
|
|
40
|
-
# via parsel
|
|
41
|
-
curl-cffi==0.7.3
|
|
42
|
-
# via hssp
|
|
43
|
-
datarecorder==3.6.2
|
|
44
|
-
# via downloadkit
|
|
45
|
-
downloadkit==2.0.5
|
|
46
|
-
# via drissionpage
|
|
47
|
-
drissionpage==4.1.0.12
|
|
48
|
-
# via hssp
|
|
49
|
-
et-xmlfile==2.0.0
|
|
50
|
-
# via openpyxl
|
|
51
|
-
fake-useragent==1.5.1
|
|
52
|
-
# via hssp
|
|
53
|
-
filelock==3.16.1
|
|
54
|
-
# via tldextract
|
|
55
|
-
frozenlist==1.5.0
|
|
56
|
-
# via aiohttp
|
|
57
|
-
# via aiosignal
|
|
58
|
-
furl==2.1.3
|
|
59
|
-
# via hssp
|
|
60
|
-
h11==0.14.0
|
|
61
|
-
# via httpcore
|
|
62
|
-
h2==4.1.0
|
|
63
|
-
# via httpx
|
|
64
|
-
hpack==4.0.0
|
|
65
|
-
# via h2
|
|
66
|
-
hssp==0.4.7
|
|
67
|
-
# via hs-m3u8
|
|
68
|
-
httpcore==1.0.6
|
|
69
|
-
# via httpx
|
|
70
|
-
httpx==0.27.2
|
|
71
|
-
# via hssp
|
|
72
|
-
hyperframe==6.0.1
|
|
73
|
-
# via h2
|
|
74
|
-
idna==3.10
|
|
75
|
-
# via anyio
|
|
76
|
-
# via httpx
|
|
77
|
-
# via requests
|
|
78
|
-
# via tldextract
|
|
79
|
-
# via yarl
|
|
80
|
-
jmespath==1.0.1
|
|
81
|
-
# via parsel
|
|
82
|
-
loguru==0.7.2
|
|
83
|
-
# via hssp
|
|
84
|
-
lxml==5.3.0
|
|
85
|
-
# via drissionpage
|
|
86
|
-
# via parsel
|
|
87
|
-
m3u8==6.0.0
|
|
88
|
-
# via hs-m3u8
|
|
89
|
-
multidict==6.1.0
|
|
90
|
-
# via aiohttp
|
|
91
|
-
# via yarl
|
|
92
|
-
openpyxl==3.1.5
|
|
93
|
-
# via datarecorder
|
|
94
|
-
orderedmultidict==1.0.1
|
|
95
|
-
# via furl
|
|
96
|
-
packaging==24.2
|
|
97
|
-
# via parsel
|
|
98
|
-
parsel==1.9.1
|
|
99
|
-
# via hssp
|
|
100
|
-
propcache==0.2.0
|
|
101
|
-
# via yarl
|
|
102
|
-
psutil==6.1.0
|
|
103
|
-
# via drissionpage
|
|
104
|
-
pycparser==2.22
|
|
105
|
-
# via cffi
|
|
106
|
-
pycryptodomex==3.21.0
|
|
107
|
-
# via hssp
|
|
108
|
-
pydantic==2.9.2
|
|
109
|
-
# via hssp
|
|
110
|
-
# via pydantic-settings
|
|
111
|
-
pydantic-core==2.23.4
|
|
112
|
-
# via pydantic
|
|
113
|
-
pydantic-settings==2.6.1
|
|
114
|
-
# via hssp
|
|
115
|
-
python-dotenv==1.0.1
|
|
116
|
-
# via pydantic-settings
|
|
117
|
-
pytz==2024.2
|
|
118
|
-
# via apscheduler
|
|
119
|
-
pyyaml==6.0.2
|
|
120
|
-
# via pydantic-settings
|
|
121
|
-
requests==2.32.3
|
|
122
|
-
# via downloadkit
|
|
123
|
-
# via drissionpage
|
|
124
|
-
# via hssp
|
|
125
|
-
# via requests-file
|
|
126
|
-
# via tldextract
|
|
127
|
-
requests-file==2.1.0
|
|
128
|
-
# via tldextract
|
|
129
|
-
six==1.16.0
|
|
130
|
-
# via apscheduler
|
|
131
|
-
# via furl
|
|
132
|
-
# via orderedmultidict
|
|
133
|
-
sniffio==1.3.1
|
|
134
|
-
# via anyio
|
|
135
|
-
# via httpx
|
|
136
|
-
tenacity==9.0.0
|
|
137
|
-
# via hssp
|
|
138
|
-
tldextract==5.1.3
|
|
139
|
-
# via drissionpage
|
|
140
|
-
tomli==2.1.0
|
|
141
|
-
# via pydantic-settings
|
|
142
|
-
typing-extensions==4.12.2
|
|
143
|
-
# via curl-cffi
|
|
144
|
-
# via pydantic
|
|
145
|
-
# via pydantic-core
|
|
146
|
-
tzlocal==5.2
|
|
147
|
-
# via apscheduler
|
|
148
|
-
urllib3==2.2.3
|
|
149
|
-
# via requests
|
|
150
|
-
uvloop==0.21.0
|
|
151
|
-
# via hssp
|
|
152
|
-
w3lib==2.2.1
|
|
153
|
-
# via parsel
|
|
154
|
-
websocket-client==1.8.0
|
|
155
|
-
# via drissionpage
|
|
156
|
-
yarl==1.17.1
|
|
157
|
-
# via aiohttp
|
|
File without changes
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
|
|
3
|
-
from hs_m3u8 import M3u8Downloader
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
async def main():
|
|
7
|
-
url = "https://surrit.com/6d3bb2b2-d707-4b79-adf0-89542cb1383c/playlist.m3u8"
|
|
8
|
-
name = "SDAB-129"
|
|
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())
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
|
|
3
|
-
from hs_m3u8 import M3u8Downloader
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def get_m3u8(resp_text: str):
|
|
7
|
-
"""
|
|
8
|
-
获取m3u8真实文本
|
|
9
|
-
Args:
|
|
10
|
-
resp_text: m3u8_url 获取到的响应文本
|
|
11
|
-
|
|
12
|
-
Returns:
|
|
13
|
-
返回真正的m3u8文本
|
|
14
|
-
|
|
15
|
-
"""
|
|
16
|
-
return resp_text
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
async def main():
|
|
20
|
-
url = "https://surrit.com/6d3bb2b2-d707-4b79-adf0-89542cb1383c/playlist.m3u8"
|
|
21
|
-
name = "SDAB-129"
|
|
22
|
-
headers = {
|
|
23
|
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
|
|
24
|
-
"(KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36"
|
|
25
|
-
}
|
|
26
|
-
dl = M3u8Downloader(
|
|
27
|
-
m3u8_url=url, save_path=f"../../downloads/{name}", headers=headers, max_workers=64, get_m3u8_func=get_m3u8
|
|
28
|
-
)
|
|
29
|
-
await dl.run(del_hls=False, merge=True)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if __name__ == "__main__":
|
|
33
|
-
asyncio.run(main())
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
|
|
3
|
-
from hs_m3u8 import M3u8Downloader
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
async def main():
|
|
7
|
-
url = "https://surrit.com/85f671be-4ebc-4cad-961e-a8d339483cc6/playlist.m3u8"
|
|
8
|
-
name = "CUS-2413"
|
|
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())
|
hs_m3u8-0.1.6/src/example/kyt.py
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# pip install hs-m3u8==0.1.4
|
|
2
|
-
|
|
3
|
-
import asyncio
|
|
4
|
-
|
|
5
|
-
from hs_m3u8 import M3u8Downloader, M3u8Key
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
async def main():
|
|
9
|
-
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"
|
|
10
|
-
name = "ykt"
|
|
11
|
-
headers = {
|
|
12
|
-
"Accept": "*/*",
|
|
13
|
-
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
|
|
14
|
-
"Cache-Control": "no-cache",
|
|
15
|
-
"Connection": "keep-alive",
|
|
16
|
-
"Origin": "https://basic.smartedu.cn",
|
|
17
|
-
"Pragma": "no-cache",
|
|
18
|
-
"Referer": "https://basic.smartedu.cn/",
|
|
19
|
-
"Sec-Fetch-Dest": "empty",
|
|
20
|
-
"Sec-Fetch-Mode": "cors",
|
|
21
|
-
"Sec-Fetch-Site": "cross-site",
|
|
22
|
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
|
|
23
|
-
"Chrome/126.0.0.0 Safari/537.36",
|
|
24
|
-
"X-ND-AUTH": 'MAC id="7F938B205F876FC3C7550081F114A1A4028222C3BFB978FD9B439192D004CB8EEB65E66BB'
|
|
25
|
-
'C63E66FED6DD51F34F99411A6039E623E9A9D05",nonce="1742462574752:Z4IGAAV6"'
|
|
26
|
-
',mac="EUr56dXrCO1YGd3Ub1fj9MyJY9NxQPi7ZI14N/GFwpQ="',
|
|
27
|
-
"sec-ch-ua": '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
|
|
28
|
-
"sec-ch-ua-mobile": "?0",
|
|
29
|
-
"sec-ch-ua-platform": '"Windows"',
|
|
30
|
-
}
|
|
31
|
-
key = M3u8Key(key=bytes.fromhex("34623235336163353939353834643437"))
|
|
32
|
-
dl = M3u8Downloader(
|
|
33
|
-
m3u8_url=url,
|
|
34
|
-
save_path=f"../../downloads/{name}",
|
|
35
|
-
max_workers=64,
|
|
36
|
-
headers=headers,
|
|
37
|
-
key=key,
|
|
38
|
-
)
|
|
39
|
-
await dl.run(del_hls=False, merge=True)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if __name__ == "__main__":
|
|
43
|
-
asyncio.run(main())
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
|
|
3
|
-
from hs_m3u8 import M3u8Downloader
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
async def main():
|
|
7
|
-
url = "https://v3.dious.cc/20220422/EZWdBGuQ/index.m3u8"
|
|
8
|
-
name = "日日是好日"
|
|
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())
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
|
|
3
|
-
from hs_m3u8 import M3u8Downloader
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
async def main():
|
|
7
|
-
url = "https://v4.qrssv.com/202412/05/CCu6EzN8tR20/video/index.m3u8"
|
|
8
|
-
name = "毒液:最后一舞 HD-索尼"
|
|
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())
|
|
@@ -1,14 +0,0 @@
|
|
|
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())
|
hs_m3u8-0.1.6/src/example/x.py
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
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())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|