eaf_base_api 4.1.0__tar.gz → 4.2.0__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.0 → eaf_base_api-4.2.0}/PKG-INFO +87 -3
- {eaf_base_api-4.1.0 → eaf_base_api-4.2.0}/README.md +86 -2
- {eaf_base_api-4.1.0 → eaf_base_api-4.2.0}/base_api/__init__.py +57 -1
- {eaf_base_api-4.1.0 → eaf_base_api-4.2.0}/base_api/base.py +359 -167
- {eaf_base_api-4.1.0 → eaf_base_api-4.2.0}/base_api/modules/config.py +54 -0
- {eaf_base_api-4.1.0 → eaf_base_api-4.2.0}/base_api/modules/errors.py +72 -1
- {eaf_base_api-4.1.0 → eaf_base_api-4.2.0}/base_api/modules/logger.py +42 -2
- eaf_base_api-4.2.0/base_api/modules/provider.py +99 -0
- {eaf_base_api-4.1.0 → eaf_base_api-4.2.0}/base_api/modules/static_functions.py +270 -3
- {eaf_base_api-4.1.0 → eaf_base_api-4.2.0}/pyproject.toml +1 -1
- {eaf_base_api-4.1.0 → eaf_base_api-4.2.0}/LICENSE +0 -0
- {eaf_base_api-4.1.0 → eaf_base_api-4.2.0}/base_api/modules/__init__.py +0 -0
- {eaf_base_api-4.1.0 → eaf_base_api-4.2.0}/base_api/modules/progress_bars.py +0 -0
- {eaf_base_api-4.1.0 → eaf_base_api-4.2.0}/base_api/modules/type_hints.py +0 -0
- {eaf_base_api-4.1.0 → eaf_base_api-4.2.0}/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.0
|
|
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>
|
|
@@ -34,7 +34,63 @@ support, and there was a lot of code that I would have rewritten in every API ag
|
|
|
34
34
|
package. The `BaseCore` class does all the necessary stuff like m3u8 parsing, a great caching system, network request
|
|
35
35
|
fetching with retry attempts and proxy support.
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
## Consistent errors and logging (4.2)
|
|
38
|
+
|
|
39
|
+
Configure logging once in your application to capture all 15 provider APIs and
|
|
40
|
+
the base library:
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
import logging
|
|
44
|
+
from base_api import configure_app_logging, DownloadFailed
|
|
45
|
+
|
|
46
|
+
configure_app_logging(level=logging.WARNING, log_file="api-errors.log")
|
|
47
|
+
|
|
48
|
+
# Inside your async application:
|
|
49
|
+
try:
|
|
50
|
+
await video.download(configuration)
|
|
51
|
+
except DownloadFailed as error:
|
|
52
|
+
print(error.api, error.class_name, error.url)
|
|
53
|
+
# The failure and its full traceback have already been logged.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Logs use Python module names, such as `xvideos_api.api` and `base_api.base`.
|
|
57
|
+
Request, source-loading, and download logs include the qualified class name and
|
|
58
|
+
URL in the message and in `LogRecord.class_name` / `LogRecord.url`. For example:
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
ERROR xvideos_api.api [class=xvideos_api.api.Video url=https://example.test/video/123] Download failed: disk full
|
|
62
|
+
Traceback (most recent call last):
|
|
63
|
+
...
|
|
64
|
+
OSError: disk full
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Network logs identify the actual request URL, including CDN/segment URLs; media
|
|
68
|
+
errors also identify the original video page. Context stays separate for
|
|
69
|
+
concurrent downloads and follows parsing work into worker threads. Creating a
|
|
70
|
+
client/core does not install handlers or override your application's log level.
|
|
71
|
+
Without configuration, Python's fallback logging handler still prints warnings
|
|
72
|
+
and errors to stderr.
|
|
73
|
+
|
|
74
|
+
Catch common failures from `base_api`: `DownloadFailed`, `NetworkError`,
|
|
75
|
+
`NotFound`, `ProxyError`, `BotDetection`, `VideoUnavailable`, `LoginFailed`, and
|
|
76
|
+
`RegionBlocked`. Existing provider exception imports remain compatible,
|
|
77
|
+
including Pornhub's `PornhubAPIError` hierarchy. Translated exceptions preserve
|
|
78
|
+
the original exception as `__cause__`.
|
|
79
|
+
|
|
80
|
+
Ordinary download failures now raise `DownloadFailed` instead of returning
|
|
81
|
+
`False`. A stop signal raises `base_api.modules.errors.DownloadCancelled`;
|
|
82
|
+
async task cancellation propagates unchanged. Neither is logged as an error.
|
|
83
|
+
With `DownloadConfigHLS(return_report=True)`, incomplete/cancelled downloads
|
|
84
|
+
still return their explicit `DownloadReport`; unexpected exceptions still raise.
|
|
85
|
+
|
|
86
|
+
Shared request translation, download error handling, HLS preparation, and output
|
|
87
|
+
configuration live in `base_api.modules.provider`. The identical Tube8 and
|
|
88
|
+
Thumbzilla result-grid extraction lives in `base_api.modules.static_functions`.
|
|
89
|
+
Site-specific parsing, quality selection, and fallback behavior stay in each
|
|
90
|
+
provider. Updated providers require `eaf-base-api>=4.2.0`; update the base library
|
|
91
|
+
alongside them.
|
|
92
|
+
|
|
93
|
+
# Documentation (IMPORTANT!)
|
|
38
94
|
> [!IMPORTANT]
|
|
39
95
|
> Configuring eaf_base_api is necessary if you use any of my Porn APIs, because they all depend on this project.
|
|
40
96
|
> Please read through the documentation to learn how `PROXIES`, `CACHING` and `LOGGING` etc... work!
|
|
@@ -154,7 +210,10 @@ stream = helper.iterator(
|
|
|
154
210
|
async with stream:
|
|
155
211
|
async for result in stream:
|
|
156
212
|
if not result.succeeded:
|
|
157
|
-
logger.error(
|
|
213
|
+
logger.error(
|
|
214
|
+
"%s failed for %s: %s", result.stage, result.url, result.error,
|
|
215
|
+
exc_info=(type(result.error), result.error, result.error.__traceback__),
|
|
216
|
+
)
|
|
158
217
|
continue
|
|
159
218
|
video = result.unwrap()
|
|
160
219
|
```
|
|
@@ -165,6 +224,31 @@ or `ErrorMode.RAISE`. `RetryPolicy` provides a strict maximum attempt count and
|
|
|
165
224
|
optional exponential delay; the independent page and item handlers return an
|
|
166
225
|
`ErrorAction` and cannot create an unbounded retry loop.
|
|
167
226
|
|
|
227
|
+
## Error logging
|
|
228
|
+
|
|
229
|
+
Configure logging once in the application to capture all provider and base API logs:
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
import logging
|
|
233
|
+
from base_api.modules.logger import configure_app_logging
|
|
234
|
+
|
|
235
|
+
configure_app_logging(log_file="api.log", level=logging.INFO)
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Failures include the operation, video/page URL, and original traceback. The default
|
|
239
|
+
formatter also shows the file, line, and function. Media source failures are logged
|
|
240
|
+
even when a caller catches the exception; iterator failures are logged even when
|
|
241
|
+
the configured policy skips or yields them. Provider CLIs configure console logging
|
|
242
|
+
automatically.
|
|
243
|
+
|
|
244
|
+
Provider request and download exceptions use the shared types in
|
|
245
|
+
`base_api.modules.errors`, preserving the original exception as `__cause__`.
|
|
246
|
+
Pornhub's existing exception classes remain catchable as `PornhubAPIError` and as
|
|
247
|
+
their shared equivalents. `ScraperException` also inherits `BaseScraperError`.
|
|
248
|
+
Download preparation errors now carry the video URL in `DownloadFailed`, and
|
|
249
|
+
explicit cancellation remains `DownloadCancelled` or `asyncio.CancelledError`.
|
|
250
|
+
Existing boolean/download-report results from the base downloader remain supported.
|
|
251
|
+
|
|
168
252
|
# Can I use this for myself?
|
|
169
253
|
Yes, you can, but I may change stuff here and there from time to time, and it would maybe break your project.
|
|
170
254
|
I would not recommend you to install and use it as a package, but just copy the code you need.
|
|
@@ -14,7 +14,63 @@ 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
|
+
# Documentation (IMPORTANT!)
|
|
18
74
|
> [!IMPORTANT]
|
|
19
75
|
> Configuring eaf_base_api is necessary if you use any of my Porn APIs, because they all depend on this project.
|
|
20
76
|
> Please read through the documentation to learn how `PROXIES`, `CACHING` and `LOGGING` etc... work!
|
|
@@ -134,7 +190,10 @@ stream = helper.iterator(
|
|
|
134
190
|
async with stream:
|
|
135
191
|
async for result in stream:
|
|
136
192
|
if not result.succeeded:
|
|
137
|
-
logger.error(
|
|
193
|
+
logger.error(
|
|
194
|
+
"%s failed for %s: %s", result.stage, result.url, result.error,
|
|
195
|
+
exc_info=(type(result.error), result.error, result.error.__traceback__),
|
|
196
|
+
)
|
|
138
197
|
continue
|
|
139
198
|
video = result.unwrap()
|
|
140
199
|
```
|
|
@@ -145,6 +204,31 @@ or `ErrorMode.RAISE`. `RetryPolicy` provides a strict maximum attempt count and
|
|
|
145
204
|
optional exponential delay; the independent page and item handlers return an
|
|
146
205
|
`ErrorAction` and cannot create an unbounded retry loop.
|
|
147
206
|
|
|
207
|
+
## Error logging
|
|
208
|
+
|
|
209
|
+
Configure logging once in the application to capture all provider and base API logs:
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
import logging
|
|
213
|
+
from base_api.modules.logger import configure_app_logging
|
|
214
|
+
|
|
215
|
+
configure_app_logging(log_file="api.log", level=logging.INFO)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Failures include the operation, video/page URL, and original traceback. The default
|
|
219
|
+
formatter also shows the file, line, and function. Media source failures are logged
|
|
220
|
+
even when a caller catches the exception; iterator failures are logged even when
|
|
221
|
+
the configured policy skips or yields them. Provider CLIs configure console logging
|
|
222
|
+
automatically.
|
|
223
|
+
|
|
224
|
+
Provider request and download exceptions use the shared types in
|
|
225
|
+
`base_api.modules.errors`, preserving the original exception as `__cause__`.
|
|
226
|
+
Pornhub's existing exception classes remain catchable as `PornhubAPIError` and as
|
|
227
|
+
their shared equivalents. `ScraperException` also inherits `BaseScraperError`.
|
|
228
|
+
Download preparation errors now carry the video URL in `DownloadFailed`, and
|
|
229
|
+
explicit cancellation remains `DownloadCancelled` or `asyncio.CancelledError`.
|
|
230
|
+
Existing boolean/download-report results from the base downloader remain supported.
|
|
231
|
+
|
|
148
232
|
# Can I use this for myself?
|
|
149
233
|
Yes, you can, but I may change stuff here and there from time to time, and it would maybe break your project.
|
|
150
234
|
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,30 @@ __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
|
+
"VideoUnavailable",
|
|
59
|
+
"ResourceGone",
|
|
60
|
+
"LoginFailed",
|
|
61
|
+
"RegionBlocked",
|
|
62
|
+
"configure_app_logging",
|
|
38
63
|
]
|
|
39
64
|
|
|
40
65
|
|
|
@@ -53,7 +78,21 @@ from base_api.modules.errors import (
|
|
|
53
78
|
RequestRetriesExhausted,
|
|
54
79
|
ScrapeOperationError,
|
|
55
80
|
UnknownMediaFieldError,
|
|
81
|
+
is_resource_gone,
|
|
82
|
+
contains_resource_gone,
|
|
83
|
+
ScraperException,
|
|
84
|
+
NotFound,
|
|
85
|
+
NetworkError,
|
|
86
|
+
BotDetection,
|
|
87
|
+
ProxyError,
|
|
88
|
+
UnknownNetworkError,
|
|
89
|
+
DownloadFailed,
|
|
90
|
+
VideoUnavailable,
|
|
91
|
+
ResourceGone,
|
|
92
|
+
LoginFailed,
|
|
93
|
+
RegionBlocked,
|
|
56
94
|
)
|
|
95
|
+
from base_api.modules.logger import configure_app_logging
|
|
57
96
|
from base_api.base import (
|
|
58
97
|
BaseCore,
|
|
59
98
|
BaseMedia,
|
|
@@ -74,5 +113,22 @@ from base_api.base import (
|
|
|
74
113
|
ScrapeStream,
|
|
75
114
|
SegmentCacheKey,
|
|
76
115
|
media_field,
|
|
116
|
+
scrape_stream,
|
|
117
|
+
stream_results,
|
|
118
|
+
)
|
|
119
|
+
from base_api.modules.config import (
|
|
120
|
+
config,
|
|
121
|
+
DownloadConfigHLS,
|
|
122
|
+
DownloadConfigRAW,
|
|
123
|
+
IteratorConfig,
|
|
124
|
+
make_iterator_config,
|
|
125
|
+
default_on_error,
|
|
126
|
+
)
|
|
127
|
+
from base_api.modules.static_functions import (
|
|
128
|
+
str_to_bool,
|
|
129
|
+
parse_duration,
|
|
130
|
+
parse_count,
|
|
131
|
+
get_text_safe,
|
|
132
|
+
get_attr_safe,
|
|
133
|
+
build_m3u8_master,
|
|
77
134
|
)
|
|
78
|
-
from base_api.modules.config import config, DownloadConfigHLS, DownloadConfigRAW
|