Redtube API
A fully asynchronous Python API wrapper and scraper for Redtube. Fetch video details, custom playlists, publishers channels, users, and pornstars. Stream downloads via HLS. Powered by the eaf_base_api networking engine.
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-redtube
For TS→MP4 remuxing support (recommended for HLS downloads), install with the optional av dependency:
pip install unofficial-api-for-redtube[av]
eaf_base_api ≥ 4.0.0 is installed automatically.
Quick Start
Every scraper operation is asynchronous. Wrap calls in a running event loop:
import asyncio
from redtube_api import Client
from base_api import DownloadConfigHLS
async def main():
client = Client()
# Fetch video metadata
video = await client.get_video("https://www.redtube.com/12345")
print(video.title)
print(video.author_name)
# Download video via HLS streaming
config = DownloadConfigHLS(quality="best", path="./downloads")
await video.download(configuration=config)
asyncio.run(main())
Configuration
Redtube API uses eaf_base_api ≥ 4.0.0. Its singular proxy, request attempts, timeouts, and other networking behavior are configured through 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 redtube_api import Client
my_config = RuntimeConfig()
my_config.proxy = "socks5://127.0.0.1:9050"
my_config.request_attempts = 3
core = BaseCore(configuration=my_config)
client = Client(core=core)
Client
Main entry point class to execute searches and load resource models.
from redtube_api import Client
from base_api import BaseCore
client = Client()
client_custom = Client(core=BaseCore())
Constructor Parameters
- core BaseCore — Networking core instance (default:
BaseCore())
Methods
Fetch Video get_video()
Video object. Parses the configuration script embedded inside the HTML.Parameters
- url str — The Redtube 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 Redtube 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
→ AmateurFetch User get_user()
Parameters
- url str — The user profile page URL
- load_html bool — Pre-load parsed properties
Returns
→ UserSearch Videos search()
Parameters
- query str — Search query words
- pages int — Number of search pages to parse
- iterator_config IteratorConfig | None — Optional v4 concurrency, ordering, eager-source, retry, and error-handling policy. The package default eagerly loads
html.
Returns
→ AsyncGenerator[ScrapeResult[Video], None]Video
dataclass Inherits from BaseMedia. Represents a single video with details extracted from JavaScript parameters 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 | int | str | None | Video duration supplied by the page player data |
thumbnail | str | None | Thumbnail cover image URL |
embed_code | str | None | Embed code for web players |
locale | str | None | Locale code identifier |
media_definitions | list[dict] | None | Raw media definitions from the player configuration |
is_auto_play_enabled | bool | None | Autoplay status |
is_vr | bool | None | VR video flag |
author_url | str | None | The author's profile page URL |
m3u8_source_url | str | None | The raw HLS playlists URL source path |
mp4_url | str | None | Raw MP4 direct download link (if available) |
action_tags_raw | object | Raw action-tag payload (currently a string or mapping at runtime) |
action_tags | dict | None | Decoded action tags mapped by keyword and timestamp |
m3u8_base_url | str | None | Constructed HLS master playlist string |
author_name | str | None | Name of the video author |
uploader_id | str | None | Uploader identifier |
uploader_type | str | None | Uploader type |
preview_video_url | str | None | Preview clip path |
pornstars_names | list[str] | None | Names of starring pornstars |
pornstars_urls | list[str] | None | starring pornstar profile links |
Methods
Download Video download()
no_title=True on the config.Parameters
- configuration DownloadConfigHLS — HLS download configurations
Returns
→ bool | DownloadReportFetch Video Author author()
Amateur, Pornstar, or Channel object.Parameters
- load_html bool — If
True, pre-fetches full author metadata immediately
Returns
→ Amateur | Pornstar | ChannelPlaylist
dataclass Inherits from BaseMedia. Represents a user-curated playlist.
Attributes
| Attribute | Type | Description |
|---|---|---|
url | str | The playlist URL |
title | str | None | Playlist title |
author_url | str | None | Author's relative profile path |
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 |
video_count | str | None | Total videos count |
updated_at | str | None | Last updated timestamp string |
status | str | None | Status description |
Methods
Fetch Playlist Author get_author()
User object representing the owner of this playlist.Parameters
- load_html bool — If
True, pre-fetches full user metadata immediately
Returns
→ UserGet Playlist Videos get_videos()
Parameters
- pages int — Pages to load
- iterator_config IteratorConfig | None — Optional v4 iterator policy. The default eagerly loads each video's
htmlsource.
Returns
→ AsyncGenerator[ScrapeResult[Video], None]User / Pornstar / Amateur
Scraper objects representing creators, actors, and registered users share metadata hierarchies (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 — Optional v4 iterator policy. The default eagerly loads each video's
htmlsource.
Returns
→ AsyncGenerator[ScrapeResult[Video], None]Get User Playlists get_playlists()
Parameters
- pages int — Pages to load
- iterator_config IteratorConfig | None — Optional v4 iterator policy. The default eagerly loads each playlist's
htmlsource.
Returns
→ AsyncGenerator[ScrapeResult[Playlist], None]Channel
dataclass Inherits from BaseMedia. 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 |
subscribers_count | str | None | Total channel subscribers count |
Methods
Get Channel Videos get_videos()
Parameters
- pages int — Pages to load
- iterator_config IteratorConfig | None — Optional v4 iterator policy. The default eagerly loads each video's
htmlsource.
Returns
→ AsyncGenerator[ScrapeResult[Video], None]Downloading Options
Redtube serves video files via HLS streaming. 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"
)
success = await video.download(configuration=config)
For more configurations regarding downloading setups, please refer to the shared eaf_base_api Documentation.
Scraping Results
Iterator methods yield a typed ScrapeResult[T] wrapper. Use succeeded to branch safely or unwrap() to return the item and raise its terminal error on failure:
async for result in client.search("beach", pages=2):
if result.succeeded:
video = result.unwrap()
print(video.title)
else:
print(result.stage, result.url, result.error)
ScrapeResult Attributes
| Attribute | Type | Description |
|---|---|---|
stage | ScrapeStage | Whether the result came from the page or item stage |
url | str | The parsed video target URL |
page_index | int | Zero-based source page index |
item_index | int | None | Zero-based item index, or None for a page failure |
attempts | int | Number of attempts used by the yielding stage |
item | T | None | The parsed Video or Playlist on success |
error | ScrapeOperationError | None | The typed terminal page or item error on failure |
succeeded | bool | True when error is None |
IteratorConfig, bounded retries, and custom handlers
All iterator-only controls now live in one IteratorConfig. Redtube's package default uses ErrorMode.SKIP for terminal page failures; a supplied config replaces that behavior, and a bare IteratorConfig instead defaults to ErrorMode.YIELD. A retry policy's max_attempts includes the initial attempt, so this example makes at most three stage attempts per failed page or item. Each stage attempt may itself perform the request retries configured on BaseCore. Fully populated results require the html source.
Leave page_retry or item_retry as None to derive that stage's bounded policy from the active RuntimeConfig request-attempt and backoff settings; an explicit RetryPolicy overrides it per stage.
from base_api import ErrorAction, RetryPolicy, ScrapeErrorContext
from base_api.modules.config import IteratorConfig
async def handle_scrape_error(context: ScrapeErrorContext) -> ErrorAction:
if context.attempt < context.max_attempts:
return ErrorAction.RETRY
return ErrorAction.YIELD
retry = RetryPolicy(
max_attempts=3, base_delay=0.5, multiplier=2.0,
max_delay=4.0, jitter=0.2
)
iterator_config = IteratorConfig(
max_page_concurrency=2,
max_item_concurrency=8,
max_pending_items=16,
load_specific_sources=("html",),
page_retry=retry,
item_retry=retry,
page_error_handler=handle_scrape_error,
item_error_handler=handle_scrape_error,
)
async for result in client.search(
"beach", pages=2, iterator_config=iterator_config
):
if result.succeeded:
print(result.unwrap().title)
else:
print(result.stage, result.error)
ScrapeErrorContext supplies stage, url, error, attempt, max_attempts, page_index, and item_index. A handler returns ErrorAction.RETRY, RAISE, YIELD, or SKIP.
The core routes page-stage failures to page_error_handler and item-stage failures to item_error_handler. Assign the same callable to both fields only when both stages should use the same policy; otherwise configure either handler independently.
Error Handling
Source loaders translate request failures into exceptions from redtube_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.
| Exception | Trigger Cause |
|---|---|
NotFound | Server returned HTTP 404 (e.g. video deleted) |
NetworkError | Request failed due to HTTP connection problems |
BotDetection | Cloudflare challenge block detected |
ProxyError | Proxy configuration failed or proxy is down |
UnknownNetworkError | Unexpected network errors |
DownloadFailed | HLS segmented stream download failed |
from base_api import MediaLoadError
from redtube_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
Changelog
1.4 — 2026-08-11
8fcf5ec— Added genericScrapeResulttyping and the PEP 561py.typedmarker, left iterator retry policies unset so they resolve fromRuntimeConfig, and released 1.4.
1.3 — 2026-08-08
eb45470— Consolidated playlist, user, channel, and search iterator concurrency, ordering, source loading, retry, and error controls intoIteratorConfig.
1.3 migration — 2026-08-07
46fc0fd— Migrated to the eaf_base_api v4 request and scraping model:fetch_text()/request(), structured exceptions, source-aware media loading, typed scrape streams/results, and bounded retries.
Supported Platforms
| Platform | Architecture | Status |
|---|---|---|
| Windows 11 | x64 | ✅ Tested |
| macOS Sequoia | x86_64 / arm64 | ✅ Tested |
| Linux (Arch) | x86_64 | ✅ Tested |
| Android 16 | aarch64 | ✅ Tested |