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-tube8
For TS→MP4 remuxing support (recommended for HLS downloads), install with the optional av dependency:
pip install unofficial-api-for-tube8[av]
eaf_base_api ≥ 4.0.0, which is installed automatically.
Quick Start
import asyncio
from tube8_api import Client
from base_api import DownloadConfigHLS
async def main():
client = Client()
# Fetch video metadata
video = await client.get_video("https://www.tube8.com/porn-video/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 tube8_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 tube8_api import Client
client = Client()
Constructor Parameters
- core BaseCore — Networking core instance (default:
BaseCore())
Methods
Fetch Video get_video()
Video object. Parses LD+JSON structured data and media definitions.Parameters
- url str — The Tube8 video URL
- load_html bool — Pre-load parsed properties immediately
Returns
→ VideoFetch Pornstar get_pornstar()
Pornstar object with sidebar biography stats.Parameters
- url str — The pornstar profile URL
- load_html bool — Pre-load parsed properties
Returns
→ PornstarFetch 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_config IteratorConfig | None — Concurrency, ordering, source loading, retry, and terminal-error policy. The package default loads
htmland permits three attempts for both stages.
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 embedded in the page.
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 on the config.Parameters
- configuration DownloadConfigHLS — HLS download configurations
Returns
→ bool | DownloadReportUser / 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_config IteratorConfig | None — Complete iterator policy. The package default loads
htmland permits three attempts for pages and items.
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
Tube8 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", # "best", "half", "worst", or height int (e.g. 720)
path="./downloads", # Destination path
no_title=False, # If False, automatically appends title + ".mp4"
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. Tube8's package default loads the html source, skips terminal page failures, and uses RetryPolicy(max_attempts=3) for both page and item stages. A supplied configuration replaces that default, so preserve the HTML source, page error mode, and desired retry policies explicitly; 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=3, base_delay=0.5),
item_retry=RetryPolicy(max_attempts=3, base_delay=0.5),
page_error_mode=ErrorMode.YIELD,
item_error_mode=ErrorMode.YIELD,
page_error_handler=handle_error,
item_error_handler=handle_error,
)
async for result in client.search(
"beach", pages=2, iterator_config=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 stage operation, so the Tube8 default is at most three stage attempts; each may itself perform the request retries configured on BaseCore.
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 tube8_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 tube8_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.
Tube8 API includes a command-line interface accessible via tube8_api or python -m tube8_api:
# Download a single video
tube8_api --download "https://www.tube8.com/video/12345/sample" --quality best --output ./downloads --no-title False
# Or invoke via python -m
python -m tube8_api --download "https://www.tube8.com/video/12345/sample" --quality best --output ./downloads --no-title False
# Download from a line-separated file of URLs
tube8_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 | b4e8cd3 / 8d881f9 | Adopted shared request and download error handling from base_api.modules.provider (requiring eaf-base-api>=4.2.0). Failed downloads now raise DownloadFailed with complete diagnostic context. Exported Amateur, User, and UserHelper in __all__. Adopted centralized extract_video_grid from base_api.modules.static_functions. Added layout anchors and resilient fallback selectors for video, channel, amateur, and pornstar pages with offline unit tests. |
| 2026-08-11 | d999d7a | Completed public type hints and added the py.typed marker. |
| 2026-08-11 | 7e67e0e | Released 1.3 and corrected search-result URLs that incorrectly targeted thumbzilla.com instead of tube8.com. |
| 2026-08-08 | aaa2784 | Centralized concurrent scraping on IteratorConfig and the package's three-attempt page/item defaults. |
| 2026-08-07 | 30618cb | Migrated source-aware models, explicit loading, bounded retries, and structured results to eaf v4. |