eaf-base-api 4.1.1__tar.gz → 4.2.1__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.
- {eaf_base_api-4.1.1 → eaf_base_api-4.2.1}/PKG-INFO +116 -4
- {eaf_base_api-4.1.1 → eaf_base_api-4.2.1}/README.md +115 -2
- {eaf_base_api-4.1.1 → eaf_base_api-4.2.1}/base_api/__init__.py +69 -1
- {eaf_base_api-4.1.1 → eaf_base_api-4.2.1}/base_api/base.py +396 -381
- {eaf_base_api-4.1.1 → eaf_base_api-4.2.1}/base_api/modules/config.py +58 -0
- {eaf_base_api-4.1.1 → eaf_base_api-4.2.1}/base_api/modules/errors.py +78 -1
- eaf_base_api-4.2.1/base_api/modules/ffmpeg.py +359 -0
- {eaf_base_api-4.1.1 → eaf_base_api-4.2.1}/base_api/modules/logger.py +42 -2
- eaf_base_api-4.2.1/base_api/modules/provider.py +99 -0
- {eaf_base_api-4.1.1 → eaf_base_api-4.2.1}/base_api/modules/static_functions.py +270 -3
- {eaf_base_api-4.1.1 → eaf_base_api-4.2.1}/base_api/modules/type_hints.py +1 -0
- eaf_base_api-4.2.1/pyproject.toml +48 -0
- eaf_base_api-4.1.1/pyproject.toml → eaf_base_api-4.2.1/pyproject.toml.orig +1 -3
- {eaf_base_api-4.1.1 → eaf_base_api-4.2.1}/LICENSE +0 -0
- {eaf_base_api-4.1.1 → eaf_base_api-4.2.1}/base_api/modules/__init__.py +0 -0
- {eaf_base_api-4.1.1 → eaf_base_api-4.2.1}/base_api/modules/progress_bars.py +0 -0
- {eaf_base_api-4.1.1 → eaf_base_api-4.2.1}/base_api/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: eaf_base_api
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.2.1
|
|
4
4
|
Summary: A base API for EchterAlsFake's Porn APIs
|
|
5
5
|
Author: Johannes Habel
|
|
6
6
|
Author-email: Johannes Habel <EchterAlsFake@proton.me>
|
|
@@ -11,7 +11,6 @@ Requires-Dist: cachetools>=7.0.0
|
|
|
11
11
|
Requires-Dist: curl-cffi
|
|
12
12
|
Requires-Dist: tenacity>=9.1.2
|
|
13
13
|
Requires-Dist: m3u8 ; extra == 'hls'
|
|
14
|
-
Requires-Dist: av ; python_full_version >= '3.12' and extra == 'hls'
|
|
15
14
|
Requires-Python: >=3.12
|
|
16
15
|
Project-URL: Homepage, https://github.com/EchterAlsFake/eaf_base_api
|
|
17
16
|
Project-URL: Repository, https://github.com/EchterAlsFake/eaf_base_api
|
|
@@ -34,7 +33,92 @@ support, and there was a lot of code that I would have rewritten in every API ag
|
|
|
34
33
|
package. The `BaseCore` class does all the necessary stuff like m3u8 parsing, a great caching system, network request
|
|
35
34
|
fetching with retry attempts and proxy support.
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
## Consistent errors and logging (4.2)
|
|
37
|
+
|
|
38
|
+
Configure logging once in your application to capture all 15 provider APIs and
|
|
39
|
+
the base library:
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import logging
|
|
43
|
+
from base_api import configure_app_logging, DownloadFailed
|
|
44
|
+
|
|
45
|
+
configure_app_logging(level=logging.WARNING, log_file="api-errors.log")
|
|
46
|
+
|
|
47
|
+
# Inside your async application:
|
|
48
|
+
try:
|
|
49
|
+
await video.download(configuration)
|
|
50
|
+
except DownloadFailed as error:
|
|
51
|
+
print(error.api, error.class_name, error.url)
|
|
52
|
+
# The failure and its full traceback have already been logged.
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Logs use Python module names, such as `xvideos_api.api` and `base_api.base`.
|
|
56
|
+
Request, source-loading, and download logs include the qualified class name and
|
|
57
|
+
URL in the message and in `LogRecord.class_name` / `LogRecord.url`. For example:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
ERROR xvideos_api.api [class=xvideos_api.api.Video url=https://example.test/video/123] Download failed: disk full
|
|
61
|
+
Traceback (most recent call last):
|
|
62
|
+
...
|
|
63
|
+
OSError: disk full
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Network logs identify the actual request URL, including CDN/segment URLs; media
|
|
67
|
+
errors also identify the original video page. Context stays separate for
|
|
68
|
+
concurrent downloads and follows parsing work into worker threads. Creating a
|
|
69
|
+
client/core does not install handlers or override your application's log level.
|
|
70
|
+
Without configuration, Python's fallback logging handler still prints warnings
|
|
71
|
+
and errors to stderr.
|
|
72
|
+
|
|
73
|
+
Catch common failures from `base_api`: `DownloadFailed`, `NetworkError`,
|
|
74
|
+
`NotFound`, `ProxyError`, `BotDetection`, `VideoUnavailable`, `LoginFailed`, and
|
|
75
|
+
`RegionBlocked`. Existing provider exception imports remain compatible,
|
|
76
|
+
including Pornhub's `PornhubAPIError` hierarchy. Translated exceptions preserve
|
|
77
|
+
the original exception as `__cause__`.
|
|
78
|
+
|
|
79
|
+
Ordinary download failures now raise `DownloadFailed` instead of returning
|
|
80
|
+
`False`. A stop signal raises `base_api.modules.errors.DownloadCancelled`;
|
|
81
|
+
async task cancellation propagates unchanged. Neither is logged as an error.
|
|
82
|
+
With `DownloadConfigHLS(return_report=True)`, incomplete/cancelled downloads
|
|
83
|
+
still return their explicit `DownloadReport`; unexpected exceptions still raise.
|
|
84
|
+
|
|
85
|
+
Shared request translation, download error handling, HLS preparation, and output
|
|
86
|
+
configuration live in `base_api.modules.provider`. The identical Tube8 and
|
|
87
|
+
Thumbzilla result-grid extraction lives in `base_api.modules.static_functions`.
|
|
88
|
+
Site-specific parsing, quality selection, and fallback behavior stay in each
|
|
89
|
+
provider. Updated providers require `eaf-base-api>=4.2.0`; update the base library
|
|
90
|
+
alongside them.
|
|
91
|
+
|
|
92
|
+
## FFmpeg remuxing and single-pass metadata tagging (4.3)
|
|
93
|
+
|
|
94
|
+
HLS TS→MP4 remuxing (`DownloadConfigHLS(remux=True)`) now runs directly via an
|
|
95
|
+
`ffmpeg` binary (discovered on `PATH` or configured via `RuntimeConfig.ffmpeg_path`)
|
|
96
|
+
instead of `PyAV`. You can also pass `metadata` (a provider `Video` object or `dict`)
|
|
97
|
+
and `thumbnail` (`bytes` or path) on `DownloadConfigHLS` so `eaf_base_api` embeds
|
|
98
|
+
MP4 container tags and cover art in the **same single FFmpeg remux pass** without
|
|
99
|
+
rewriting the file a second time:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from base_api import DownloadConfigHLS, write_metadata_tags
|
|
103
|
+
|
|
104
|
+
config = DownloadConfigHLS(
|
|
105
|
+
quality="best",
|
|
106
|
+
path="./downloads",
|
|
107
|
+
remux=True,
|
|
108
|
+
metadata=video, # Writes title, author, genre, date, description, url, comment
|
|
109
|
+
thumbnail=cover_bytes, # Optional JPEG/PNG cover art embedded in the same pass
|
|
110
|
+
return_report=True,
|
|
111
|
+
)
|
|
112
|
+
report = await video.download(configuration=config)
|
|
113
|
+
print(report.metadata_written) # True when single-pass metadata/cover tagging succeeded
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
For direct MP4 downloads (`DownloadConfigRAW`) or existing MP4 files, use
|
|
117
|
+
`write_metadata_tags(path, metadata=video, thumbnail=cover_bytes)` from
|
|
118
|
+
`base_api.modules.ffmpeg` (or `base_api`). If `ffmpeg` is not installed when
|
|
119
|
+
`remux=True`, `eaf_base_api` logs a warning and preserves the raw MPEG-TS stream.
|
|
120
|
+
|
|
121
|
+
# Documentation (IMPORTANT!)
|
|
38
122
|
> [!IMPORTANT]
|
|
39
123
|
> Configuring eaf_base_api is necessary if you use any of my Porn APIs, because they all depend on this project.
|
|
40
124
|
> Please read through the documentation to learn how `PROXIES`, `CACHING` and `LOGGING` etc... work!
|
|
@@ -154,7 +238,10 @@ stream = helper.iterator(
|
|
|
154
238
|
async with stream:
|
|
155
239
|
async for result in stream:
|
|
156
240
|
if not result.succeeded:
|
|
157
|
-
logger.error(
|
|
241
|
+
logger.error(
|
|
242
|
+
"%s failed for %s: %s", result.stage, result.url, result.error,
|
|
243
|
+
exc_info=(type(result.error), result.error, result.error.__traceback__),
|
|
244
|
+
)
|
|
158
245
|
continue
|
|
159
246
|
video = result.unwrap()
|
|
160
247
|
```
|
|
@@ -165,6 +252,31 @@ or `ErrorMode.RAISE`. `RetryPolicy` provides a strict maximum attempt count and
|
|
|
165
252
|
optional exponential delay; the independent page and item handlers return an
|
|
166
253
|
`ErrorAction` and cannot create an unbounded retry loop.
|
|
167
254
|
|
|
255
|
+
## Error logging
|
|
256
|
+
|
|
257
|
+
Configure logging once in the application to capture all provider and base API logs:
|
|
258
|
+
|
|
259
|
+
```python
|
|
260
|
+
import logging
|
|
261
|
+
from base_api.modules.logger import configure_app_logging
|
|
262
|
+
|
|
263
|
+
configure_app_logging(log_file="api.log", level=logging.INFO)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Failures include the operation, video/page URL, and original traceback. The default
|
|
267
|
+
formatter also shows the file, line, and function. Media source failures are logged
|
|
268
|
+
even when a caller catches the exception; iterator failures are logged even when
|
|
269
|
+
the configured policy skips or yields them. Provider CLIs configure console logging
|
|
270
|
+
automatically.
|
|
271
|
+
|
|
272
|
+
Provider request and download exceptions use the shared types in
|
|
273
|
+
`base_api.modules.errors`, preserving the original exception as `__cause__`.
|
|
274
|
+
Pornhub's existing exception classes remain catchable as `PornhubAPIError` and as
|
|
275
|
+
their shared equivalents. `ScraperException` also inherits `BaseScraperError`.
|
|
276
|
+
Download preparation errors now carry the video URL in `DownloadFailed`, and
|
|
277
|
+
explicit cancellation remains `DownloadCancelled` or `asyncio.CancelledError`.
|
|
278
|
+
Existing boolean/download-report results from the base downloader remain supported.
|
|
279
|
+
|
|
168
280
|
# Can I use this for myself?
|
|
169
281
|
Yes, you can, but I may change stuff here and there from time to time, and it would maybe break your project.
|
|
170
282
|
I would not recommend you to install and use it as a package, but just copy the code you need.
|
|
@@ -14,7 +14,92 @@ support, and there was a lot of code that I would have rewritten in every API ag
|
|
|
14
14
|
package. The `BaseCore` class does all the necessary stuff like m3u8 parsing, a great caching system, network request
|
|
15
15
|
fetching with retry attempts and proxy support.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
## Consistent errors and logging (4.2)
|
|
18
|
+
|
|
19
|
+
Configure logging once in your application to capture all 15 provider APIs and
|
|
20
|
+
the base library:
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
import logging
|
|
24
|
+
from base_api import configure_app_logging, DownloadFailed
|
|
25
|
+
|
|
26
|
+
configure_app_logging(level=logging.WARNING, log_file="api-errors.log")
|
|
27
|
+
|
|
28
|
+
# Inside your async application:
|
|
29
|
+
try:
|
|
30
|
+
await video.download(configuration)
|
|
31
|
+
except DownloadFailed as error:
|
|
32
|
+
print(error.api, error.class_name, error.url)
|
|
33
|
+
# The failure and its full traceback have already been logged.
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Logs use Python module names, such as `xvideos_api.api` and `base_api.base`.
|
|
37
|
+
Request, source-loading, and download logs include the qualified class name and
|
|
38
|
+
URL in the message and in `LogRecord.class_name` / `LogRecord.url`. For example:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
ERROR xvideos_api.api [class=xvideos_api.api.Video url=https://example.test/video/123] Download failed: disk full
|
|
42
|
+
Traceback (most recent call last):
|
|
43
|
+
...
|
|
44
|
+
OSError: disk full
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Network logs identify the actual request URL, including CDN/segment URLs; media
|
|
48
|
+
errors also identify the original video page. Context stays separate for
|
|
49
|
+
concurrent downloads and follows parsing work into worker threads. Creating a
|
|
50
|
+
client/core does not install handlers or override your application's log level.
|
|
51
|
+
Without configuration, Python's fallback logging handler still prints warnings
|
|
52
|
+
and errors to stderr.
|
|
53
|
+
|
|
54
|
+
Catch common failures from `base_api`: `DownloadFailed`, `NetworkError`,
|
|
55
|
+
`NotFound`, `ProxyError`, `BotDetection`, `VideoUnavailable`, `LoginFailed`, and
|
|
56
|
+
`RegionBlocked`. Existing provider exception imports remain compatible,
|
|
57
|
+
including Pornhub's `PornhubAPIError` hierarchy. Translated exceptions preserve
|
|
58
|
+
the original exception as `__cause__`.
|
|
59
|
+
|
|
60
|
+
Ordinary download failures now raise `DownloadFailed` instead of returning
|
|
61
|
+
`False`. A stop signal raises `base_api.modules.errors.DownloadCancelled`;
|
|
62
|
+
async task cancellation propagates unchanged. Neither is logged as an error.
|
|
63
|
+
With `DownloadConfigHLS(return_report=True)`, incomplete/cancelled downloads
|
|
64
|
+
still return their explicit `DownloadReport`; unexpected exceptions still raise.
|
|
65
|
+
|
|
66
|
+
Shared request translation, download error handling, HLS preparation, and output
|
|
67
|
+
configuration live in `base_api.modules.provider`. The identical Tube8 and
|
|
68
|
+
Thumbzilla result-grid extraction lives in `base_api.modules.static_functions`.
|
|
69
|
+
Site-specific parsing, quality selection, and fallback behavior stay in each
|
|
70
|
+
provider. Updated providers require `eaf-base-api>=4.2.0`; update the base library
|
|
71
|
+
alongside them.
|
|
72
|
+
|
|
73
|
+
## FFmpeg remuxing and single-pass metadata tagging (4.3)
|
|
74
|
+
|
|
75
|
+
HLS TS→MP4 remuxing (`DownloadConfigHLS(remux=True)`) now runs directly via an
|
|
76
|
+
`ffmpeg` binary (discovered on `PATH` or configured via `RuntimeConfig.ffmpeg_path`)
|
|
77
|
+
instead of `PyAV`. You can also pass `metadata` (a provider `Video` object or `dict`)
|
|
78
|
+
and `thumbnail` (`bytes` or path) on `DownloadConfigHLS` so `eaf_base_api` embeds
|
|
79
|
+
MP4 container tags and cover art in the **same single FFmpeg remux pass** without
|
|
80
|
+
rewriting the file a second time:
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from base_api import DownloadConfigHLS, write_metadata_tags
|
|
84
|
+
|
|
85
|
+
config = DownloadConfigHLS(
|
|
86
|
+
quality="best",
|
|
87
|
+
path="./downloads",
|
|
88
|
+
remux=True,
|
|
89
|
+
metadata=video, # Writes title, author, genre, date, description, url, comment
|
|
90
|
+
thumbnail=cover_bytes, # Optional JPEG/PNG cover art embedded in the same pass
|
|
91
|
+
return_report=True,
|
|
92
|
+
)
|
|
93
|
+
report = await video.download(configuration=config)
|
|
94
|
+
print(report.metadata_written) # True when single-pass metadata/cover tagging succeeded
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
For direct MP4 downloads (`DownloadConfigRAW`) or existing MP4 files, use
|
|
98
|
+
`write_metadata_tags(path, metadata=video, thumbnail=cover_bytes)` from
|
|
99
|
+
`base_api.modules.ffmpeg` (or `base_api`). If `ffmpeg` is not installed when
|
|
100
|
+
`remux=True`, `eaf_base_api` logs a warning and preserves the raw MPEG-TS stream.
|
|
101
|
+
|
|
102
|
+
# Documentation (IMPORTANT!)
|
|
18
103
|
> [!IMPORTANT]
|
|
19
104
|
> Configuring eaf_base_api is necessary if you use any of my Porn APIs, because they all depend on this project.
|
|
20
105
|
> Please read through the documentation to learn how `PROXIES`, `CACHING` and `LOGGING` etc... work!
|
|
@@ -134,7 +219,10 @@ stream = helper.iterator(
|
|
|
134
219
|
async with stream:
|
|
135
220
|
async for result in stream:
|
|
136
221
|
if not result.succeeded:
|
|
137
|
-
logger.error(
|
|
222
|
+
logger.error(
|
|
223
|
+
"%s failed for %s: %s", result.stage, result.url, result.error,
|
|
224
|
+
exc_info=(type(result.error), result.error, result.error.__traceback__),
|
|
225
|
+
)
|
|
138
226
|
continue
|
|
139
227
|
video = result.unwrap()
|
|
140
228
|
```
|
|
@@ -145,6 +233,31 @@ or `ErrorMode.RAISE`. `RetryPolicy` provides a strict maximum attempt count and
|
|
|
145
233
|
optional exponential delay; the independent page and item handlers return an
|
|
146
234
|
`ErrorAction` and cannot create an unbounded retry loop.
|
|
147
235
|
|
|
236
|
+
## Error logging
|
|
237
|
+
|
|
238
|
+
Configure logging once in the application to capture all provider and base API logs:
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
import logging
|
|
242
|
+
from base_api.modules.logger import configure_app_logging
|
|
243
|
+
|
|
244
|
+
configure_app_logging(log_file="api.log", level=logging.INFO)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Failures include the operation, video/page URL, and original traceback. The default
|
|
248
|
+
formatter also shows the file, line, and function. Media source failures are logged
|
|
249
|
+
even when a caller catches the exception; iterator failures are logged even when
|
|
250
|
+
the configured policy skips or yields them. Provider CLIs configure console logging
|
|
251
|
+
automatically.
|
|
252
|
+
|
|
253
|
+
Provider request and download exceptions use the shared types in
|
|
254
|
+
`base_api.modules.errors`, preserving the original exception as `__cause__`.
|
|
255
|
+
Pornhub's existing exception classes remain catchable as `PornhubAPIError` and as
|
|
256
|
+
their shared equivalents. `ScraperException` also inherits `BaseScraperError`.
|
|
257
|
+
Download preparation errors now carry the video URL in `DownloadFailed`, and
|
|
258
|
+
explicit cancellation remains `DownloadCancelled` or `asyncio.CancelledError`.
|
|
259
|
+
Existing boolean/download-report results from the base downloader remain supported.
|
|
260
|
+
|
|
148
261
|
# Can I use this for myself?
|
|
149
262
|
Yes, you can, but I may change stuff here and there from time to time, and it would maybe break your project.
|
|
150
263
|
I would not recommend you to install and use it as a package, but just copy the code you need.
|
|
@@ -15,6 +15,7 @@ __all__ = [
|
|
|
15
15
|
"FieldNotLoadableError",
|
|
16
16
|
"Helper",
|
|
17
17
|
"ItemFetchError",
|
|
18
|
+
"IteratorConfig",
|
|
18
19
|
"LoadState",
|
|
19
20
|
"LoaderConfigurationError",
|
|
20
21
|
"LoaderContractError",
|
|
@@ -35,6 +36,35 @@ __all__ = [
|
|
|
35
36
|
"errors",
|
|
36
37
|
"media_field",
|
|
37
38
|
"UnknownMediaFieldError",
|
|
39
|
+
"make_iterator_config",
|
|
40
|
+
"default_on_error",
|
|
41
|
+
"scrape_stream",
|
|
42
|
+
"stream_results",
|
|
43
|
+
"is_resource_gone",
|
|
44
|
+
"contains_resource_gone",
|
|
45
|
+
"parse_duration",
|
|
46
|
+
"parse_count",
|
|
47
|
+
"get_text_safe",
|
|
48
|
+
"get_attr_safe",
|
|
49
|
+
"build_m3u8_master",
|
|
50
|
+
"str_to_bool",
|
|
51
|
+
"ScraperException",
|
|
52
|
+
"NotFound",
|
|
53
|
+
"NetworkError",
|
|
54
|
+
"BotDetection",
|
|
55
|
+
"ProxyError",
|
|
56
|
+
"UnknownNetworkError",
|
|
57
|
+
"DownloadFailed",
|
|
58
|
+
"MetadataWriteError",
|
|
59
|
+
"VideoUnavailable",
|
|
60
|
+
"ResourceGone",
|
|
61
|
+
"LoginFailed",
|
|
62
|
+
"RegionBlocked",
|
|
63
|
+
"configure_app_logging",
|
|
64
|
+
"find_ffmpeg",
|
|
65
|
+
"has_ffmpeg",
|
|
66
|
+
"remux_ts_to_mp4",
|
|
67
|
+
"write_metadata_tags",
|
|
38
68
|
]
|
|
39
69
|
|
|
40
70
|
|
|
@@ -53,7 +83,28 @@ from base_api.modules.errors import (
|
|
|
53
83
|
RequestRetriesExhausted,
|
|
54
84
|
ScrapeOperationError,
|
|
55
85
|
UnknownMediaFieldError,
|
|
86
|
+
is_resource_gone,
|
|
87
|
+
contains_resource_gone,
|
|
88
|
+
ScraperException,
|
|
89
|
+
NotFound,
|
|
90
|
+
NetworkError,
|
|
91
|
+
BotDetection,
|
|
92
|
+
ProxyError,
|
|
93
|
+
UnknownNetworkError,
|
|
94
|
+
DownloadFailed,
|
|
95
|
+
MetadataWriteError,
|
|
96
|
+
VideoUnavailable,
|
|
97
|
+
ResourceGone,
|
|
98
|
+
LoginFailed,
|
|
99
|
+
RegionBlocked,
|
|
56
100
|
)
|
|
101
|
+
from base_api.modules.ffmpeg import (
|
|
102
|
+
find_ffmpeg,
|
|
103
|
+
has_ffmpeg,
|
|
104
|
+
remux_ts_to_mp4,
|
|
105
|
+
write_metadata_tags,
|
|
106
|
+
)
|
|
107
|
+
from base_api.modules.logger import configure_app_logging
|
|
57
108
|
from base_api.base import (
|
|
58
109
|
BaseCore,
|
|
59
110
|
BaseMedia,
|
|
@@ -74,5 +125,22 @@ from base_api.base import (
|
|
|
74
125
|
ScrapeStream,
|
|
75
126
|
SegmentCacheKey,
|
|
76
127
|
media_field,
|
|
128
|
+
scrape_stream,
|
|
129
|
+
stream_results,
|
|
130
|
+
)
|
|
131
|
+
from base_api.modules.config import (
|
|
132
|
+
config,
|
|
133
|
+
DownloadConfigHLS,
|
|
134
|
+
DownloadConfigRAW,
|
|
135
|
+
IteratorConfig,
|
|
136
|
+
make_iterator_config,
|
|
137
|
+
default_on_error,
|
|
138
|
+
)
|
|
139
|
+
from base_api.modules.static_functions import (
|
|
140
|
+
str_to_bool,
|
|
141
|
+
parse_duration,
|
|
142
|
+
parse_count,
|
|
143
|
+
get_text_safe,
|
|
144
|
+
get_attr_safe,
|
|
145
|
+
build_m3u8_master,
|
|
77
146
|
)
|
|
78
|
-
from base_api.modules.config import config, DownloadConfigHLS, DownloadConfigRAW
|