Other Options:
• PayPal
• Ko-Fi
For extended features, enterprise integrations, or custom commercial licensing, please contact EchterAlsFakeBS@proton.me.
Installation
Install from PyPI using pip:
pip install unofficial-api-for-thumbzilla
For TS→MP4 remuxing support (recommended for HLS downloads), install with the optional av dependency:
pip install unofficial-api-for-thumbzilla[av]
eaf_base_api ≥ 4.0.0, which is installed automatically.
Quick Start
import asyncio
from thumbzilla_api import Client
from base_api import DownloadConfigHLS
async def main():
client = Client()
# Fetch video metadata
video = await client.get_video("https://www.thumbzilla.com/watch/12345")
print(video.title)
print(video.views)
# Download video via HLS
config = DownloadConfigHLS(quality="best", path="./downloads")
await video.download(configuration=config)
asyncio.run(main())
Configuration
Proxy/interface, timeout, request-attempt/delay, cache, and concurrency settings are handled via RuntimeConfig passed to BaseCore.
Please refer to the eaf_base_api Documentation for details.
from base_api import BaseCore
from base_api.modules.config import RuntimeConfig
from thumbzilla_api import Client
my_config = RuntimeConfig()
my_config.proxy = "socks5://127.0.0.1:9050"
my_config.request_attempts = 4
my_config.videos_concurrency = 8
my_config.pages_concurrency = 2
core = BaseCore(configuration=my_config)
client = Client(core=core)
Client
Main entry point class to execute searches and load resource models.
from thumbzilla_api import Client
client = Client()
Constructor Parameters
- core BaseCore — Networking core instance (default:
BaseCore())
Methods
Fetch Video get_video()
Video object.Parameters
- url str — The Thumbzilla video URL
- load_html bool — Pre-load parsed properties immediately
Returns
→ VideoFetch Pornstar get_pornstar()
Pornstar object.Parameters
- url str — The pornstar profile URL
- load_html bool — Pre-load parsed properties
Returns
→ PornstarFetch Playlist get_playlist()
Playlist object.Parameters
- url str — The Thumbzilla playlist URL
- load_html bool — Pre-load parsed properties
Returns
→ PlaylistFetch Channel get_channel()
Parameters
- url str — The channel page URL
- load_html bool — Pre-load parsed properties
Returns
→ ChannelFetch Amateur get_amateur()
Parameters
- url str — The amateur profile page URL
- load_html bool — Pre-load parsed properties
Returns
→ AmateurSearch Videos search()
Parameters
- query str — Search query words
- pages int — Number of search pages to parse
- iterator_configuration IteratorConfig | None — Concurrency, ordering, source loading, retry, and terminal-error policy. The package default loads the
htmlsource.
Returns
→ AsyncGenerator[ScrapeResult[Video], None]Video
dataclass Inherits from BaseMedia. Represents a single video with metadata extracted from LD+JSON structured data and JavaScript media definitions.
Attributes
| Attribute | Type | Description |
|---|---|---|
url | str | The video page URL |
video_id | str | None | Unique video key ID |
title | str | None | Video title |
duration | str | int | None | Video duration in seconds |
thumbnail | str | None | Thumbnail cover image URL |
embed_url | str | None | Embeddable player URL |
views | str | None | View count |
publish_date | str | None | Upload date |
publish_date_thumbnail | str | None | Thumbnail publication date |
description | str | None | Video description |
author_name | str | None | Name of the uploader |
m3u8_url | str | None | External HLS variants JSON source URL |
m3u8_base_url | str | None | Auto-constructed HLS master playlist string |
media_definitions | list[dict] | None | Raw media definition configurations |
preview_video_url | str | None | Preview clip path |
performers | list[str] | None | Featured performer names |
uploader_url | str | None | Uploader profile URL |
Methods
Download Video download()
no_title=True.Parameters
- configuration DownloadConfigHLS — HLS download configurations
Returns
→ bool | DownloadReportPlaylist
dataclass Inherits from BaseMedia. Represents a user-curated playlist.
Attributes
| Attribute | Type | Description |
|---|---|---|
url | str | The playlist URL |
title | str | None | Playlist title |
author_name | str | None | Name of the author |
rating_percent | str | None | User rating percentage |
rating_count | str | None | Total rating count |
views | str | None | Number of playlist views |
videos_count | str | None | Total videos count |
Methods
Get Playlist Videos get_videos()
Parameters
- pages int — Pages to load
- iterator_config IteratorConfig | None — Complete iterator policy. The package default loads the
htmlsource.
Returns
→ AsyncGenerator[ScrapeResult[Video], None]User / Pornstar / Amateur
Scraper objects representing creators, actors, and registered users share a common base class (UserHelper).
Attributes
| Attribute | Type | Description |
|---|---|---|
url | str | Profile page URL |
name | str | None | Username / profile display name |
pornstar_information | dict | None | Sidebar stat parameters (only populated for Pornstar objects) |
Methods
Get Profile Videos get_videos()
Parameters
- pages int — Pages to load
- iterator_configuration IteratorConfig | None — Complete iterator policy. The package default loads the
htmlsource.
Returns
→ AsyncGenerator[ScrapeResult[Video], None]Channel
dataclass Inherits from UserHelper. Represents a publisher studio channel page.
Attributes
| Attribute | Type | Description |
|---|---|---|
url | str | Channel page URL |
name | str | None | Studio/channel display name |
rank | str | None | Channel ranking score |
views | str | None | Total channel views count |
videos_count | str | None | Total uploaded videos count |
Methods
Get Channel Videos get_videos()
UserHelper.get_videos().Returns
→ AsyncGenerator[ScrapeResult[Video], None]Downloading Options
Thumbzilla serves video files via HLS streaming. The scraper auto-constructs a master M3U8 playlist from the JSON media definitions. Configure stream downloading parameters via the DownloadConfigHLS class:
from base_api import DownloadConfigHLS
config = DownloadConfigHLS(
quality="best",
path="./downloads",
no_title=False,
return_report=True
)
report = await video.download(configuration=config)
For more configurations, see the shared eaf_base_api Documentation.
Scraping Results
A missing main video container raises ValueError instead of returning an empty successful extraction. During iteration, Helper logs the page URL and traceback, then applies the page retry/error policy; a terminal failure is a PageFetchError when raised or yielded. An existing container with no matching videos can still produce an empty result.
All concurrently iterated methods accept one IteratorConfig policy and yield immutable ScrapeResult[Video] values. The package default loads html and skips terminal page failures. A supplied configuration replaces that default, so include load_specific_sources=("html",) and page_error_mode=ErrorMode.SKIP when preserving both behaviors; the example below deliberately opts into yielding page failures.
The public configuration fields are max_page_concurrency, max_item_concurrency, max_pending_items, extract_in_thread, order, both *_error_mode, both *_retry, both *_error_handler, load_specific_fields, and load_specific_sources.
from base_api import ErrorAction, ErrorMode, ResultOrder, RetryPolicy, ScrapeErrorContext
from base_api.modules.config import IteratorConfig
async def handle_error(context: ScrapeErrorContext) -> ErrorAction:
if context.attempt < context.max_attempts:
return ErrorAction.RETRY
return ErrorAction.YIELD
iterator_config = IteratorConfig(
max_page_concurrency=2,
max_item_concurrency=8,
order=ResultOrder.ORIGINAL,
load_specific_sources=("html",),
page_retry=RetryPolicy(max_attempts=4, base_delay=0.5, jitter=0.25),
item_retry=RetryPolicy(max_attempts=4, base_delay=0.5, jitter=0.25),
page_error_mode=ErrorMode.YIELD,
item_error_mode=ErrorMode.YIELD,
page_error_handler=handle_error,
item_error_handler=handle_error,
)
async for result in pornstar.get_videos(
pages=3, iterator_configuration=iterator_config
):
if result.succeeded:
video = result.unwrap()
print(video.title)
else:
print(result.stage, result.url, result.attempts, result.error)
ScrapeErrorContext(stage, url, error, attempt, max_attempts, page_index, item_index) and returns ErrorAction.RETRY, RAISE, YIELD, or SKIP. RetryPolicy exposes max_attempts, base_delay, multiplier, max_delay, jitter, and retry_for; attempts include the first call. If no retry policy is supplied, it is resolved from RuntimeConfig.request_* values.
ScrapeResult Attributes
| Attribute | Type | Description |
|---|---|---|
stage | ScrapeStage | PAGE or ITEM |
url | str | The page or item target URL |
page_index | int | Zero-based source-page index |
item_index | int | None | Zero-based item index; None for page failures |
attempts | int | Number of attempts consumed |
item | Video | None | The loaded item on success |
error | ScrapeOperationError | None | The typed terminal error on failure |
succeeded | bool | True when the result contains an item |
unwrap() | Video | Returns the item or raises its terminal error |
Error Handling
Source loaders translate request failures into exceptions from thumbzilla_api.modules.errors. Calls that load media expose ordinary loader failures through base_api.MediaLoadError (or MediaLoadErrors for several sources); inspect original_error/errors as shown. Operations outside media loading may still raise package or core exceptions directly.
Request and download failures are logged with the operation, target URL, and full original traceback. Translated exceptions retain the original error in __cause__. Download preparation failures (including metadata loading, quality selection, and output path setup) are also wrapped in DownloadFailed; inspect its cause when diagnosing a failure. The specific availability exceptions listed below remain supported. An explicit DownloadCancelled or asyncio.CancelledError propagates without being wrapped in DownloadFailed. Base downloader False and DownloadReport results remain supported; inspect the result as well as handling exceptions.
The common provider errors NotFound, NetworkError, BotDetection, ProxyError, UnknownNetworkError, and DownloadFailed are catchable through base_api.modules.errors. They derive from ScraperException, which now derives from BaseScraperError. Existing provider import paths remain valid.
See Logging & Cleanup for application logging setup.
A missing main video container raises ValueError instead of returning an empty successful extraction. During iteration, Helper logs the page URL and traceback, then applies the page retry/error policy; a terminal failure is a PageFetchError when raised or yielded. An existing container with no matching videos can still produce an empty result.
| Exception | Trigger Cause |
|---|---|
NotFound | Server returned HTTP 404 (e.g. video deleted) |
NetworkError | Request failed due to a network error, exhausted request retries, or a non-404 HTTPStatusError |
BotDetection | Anti-bot challenge block detected |
ProxyError | Proxy configuration failed or proxy is down |
UnknownNetworkError | Unexpected network errors |
DownloadFailed | Download preparation or transfer failed; the video URL is included and __cause__ retains the original exception |
from base_api import MediaLoadError
from thumbzilla_api.modules.errors import NotFound, BotDetection
try:
video = await client.get_video(url)
except MediaLoadError as error:
if isinstance(error.original_error, NotFound):
print("This video does not exist!")
elif isinstance(error.original_error, BotDetection):
print("Scraper was blocked by anti-bot measures.")
else:
raise
CLI Usage
The CLI entry point configures console logging at INFO level. Caught per-URL failures include the URL and full traceback; the default log format shows the logger, file, line, and function. Library applications should configure logging once at startup.
Thumbzilla API includes a command-line interface accessible via thumbzilla_api or python -m thumbzilla_api:
# Download a single video
thumbzilla_api --download "https://www.thumbzilla.com/video/ph123456789/sample-title" --quality best --output ./downloads --no-title False
# Or invoke via python -m
python -m thumbzilla_api --download "https://www.thumbzilla.com/video/ph123456789/sample-title" --quality best --output ./downloads --no-title False
# Download from a line-separated file of URLs
thumbzilla_api --file urls.txt --quality best --output ./downloads --no-title False
CLI Options
| Flag | Description |
|---|---|
--download URL | Video URL to download |
--file FILE | Text file with URLs (separated by newlines) |
--quality QUALITY | Video quality: best, half, worst |
--output DIR | Destination directory or output file path |
--no-title True/False | Skip auto-appending video title to output filename (default: False) |
Supported Platforms
| Platform | Architecture | Status |
|---|---|---|
| Windows 11 | x64 | ✅ Tested |
| macOS Sequoia | x86_64 / arm64 | ✅ Tested |
| Linux (Arch) | x86_64 | ✅ Tested |
| Android 16 | aarch64 | ✅ Tested |
Changelog
| Date | Commit | Changes |
|---|---|---|
| 2026-09-15 | d39ab9e / 6d20c49 | Adopted shared request and download error handling with base_api.modules.provider (requiring eaf-base-api>=4.2.0). Failed downloads now raise DownloadFailed with complete diagnostic context. Adopted centralized extract_video_grid from base_api.modules.static_functions. Added layout anchors and resilient fallback selectors for video, channel, and pornstar pages with offline extraction unit tests. |
| 2026-08-11 | 0d65160 | Released 1.4 with complete type hints and the py.typed marker. |
| 2026-08-08 | b495027 | Centralized iterator behavior on IteratorConfig, forwarded source/retry defaults, and aligned download-test behavior. |
| 2026-08-08 | e91bdf3 | Synchronized the package with the local eaf v4 source and released 1.3. |
| 2026-08-07 | b2c7678 | Migrated models, explicit source loading, structured retries, and iterator results to eaf v4. |