Python Async v1.8

YouPorn API

A fully asynchronous high-speed Python API wrapper and scraper for YouPorn. Fetch video details, custom collections, publisher channels, user uploads, and pornstar metadata. Supports dual streaming modes (HLS and raw MP4). Powered by the eaf_base_api networking engine.

GitHub
⚡ Recommended AI Workflow Official MCP Server: https://mcp.echteralsfake.me/mcp

Supercharge your development by connecting your AI coding assistant (Cursor, VS Code / Copilot, Claude Desktop, Windsurf, Zed, Antigravity). No authentication required · No strict rate limits · Covers all 16 APIs · Always up to date · Completely anonymous (0 logs, no profiling). Connecting this MCP server to your AI assistant is absolutely the recommended way to work on and build with these APIs.

⚠️ Legal Disclaimer
This tool is an unofficial, independent project and is not affiliated with, endorsed by, or sponsored by the target website. This software is provided "as is" for educational and personal purposes only. The developer assumes no responsibility for any consequences arising from the use of this tool, including but not limited to account suspension, IP blocking, or any violation of the target website's Terms of Service. Users are solely responsible for ensuring their use complies with all applicable laws and policies. Use at your own risk.
💚 Support & Commercial Licensing
If you find this project helpful, please consider donating to support its continued development!

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:

bash
pip install unofficial-api-for-youporn

For TS→MP4 remuxing support (recommended for HLS downloads), install with the optional av dependency:

bash
pip install unofficial-api-for-youporn[av]
Note
Requires Python ≥ 3.12. Version 1.8 uses eaf_base_api ≥ 4.0.0, which is installed automatically.

🚀 Quick Start

Wrap YouPorn API calls inside an asynchronous main function:

python
import asyncio
from youporn_api import Client
from base_api import DownloadConfigHLS, DownloadConfigRAW

async def main():
    client = Client()

    # Fetch a video profile
    video = await client.get_video("https://www.youporn.com/watch/12345/example-video")
    print(video.title)
    print(video.views)

    # Download video via stream-matching HLS/RAW configurations
    hls_config = DownloadConfigHLS(quality="best", path="./downloads")
    raw_config = DownloadConfigRAW(quality="best", path="./downloads")
    await video.download(configuration=hls_config, backup_configuration=raw_config)

asyncio.run(main())

⚙️ Configuration

Proxy/interface, timeout, request-attempt/delay, bandwidth, cache, and concurrency settings are managed by RuntimeConfig inside the shared BaseCore package.

Please refer to the eaf_base_api Documentation for the complete reference.

python
from base_api import BaseCore
from base_api.modules.config import RuntimeConfig
from youporn_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 class serving as the core interface wrapper.

python
from youporn_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()

async
Fetches a video profile page and returns a populated Video object. Parses the media definition variants.
await client.get_video( url: str, load_html: bool = True ) -> Video

Parameters

  • url str — The YouPorn video page URL
  • load_html bool — Pre-load and extract properties immediately (default: True)

Returns

→ Video

Fetch Pornstar get_pornstar()

async
Fetches a model profile biography and returns a populated Pornstar object.
await client.get_pornstar( url: str, load_html: bool = True ) -> Pornstar

Parameters

  • url str — The pornstar profile page URL
  • load_html bool — Pre-load and extract properties immediately (default: True)

Returns

→ Pornstar

Fetch Channel get_channel()

async
Loads publisher channel metadata and returns a populated Channel object.
await client.get_channel( url: str, load_html: bool = True ) -> Channel

Parameters

  • url str — The publisher channel URL
  • load_html bool — Pre-load and extract properties immediately (default: True)

Returns

→ Channel

Fetch Collection get_collection()

async
Loads collection metadata and returns a populated Collection object.
await client.get_collection( url: str, load_html: bool = True ) -> Collection

Parameters

  • url str — The collection playlist URL
  • load_html bool — Pre-load and extract properties immediately (default: True)

Returns

→ Collection

Search Videos search_videos()

async
Queries search endpoints and streams video results via async generator.
async for result in client.search_videos( query: str, pages: int = 0, filter_relevance: Literal["views", "rating", "date", "duration"] | None = None, filter_duration_minimum: Literal["10", "20", "30", "40", "50", "60"] | None = None, filter_duration_maximum: Literal["10", "20", "30", "40", "50", "60"] | None = None, filter_resolution: Literal["VR", "HD"] | None = None, iterator_config: IteratorConfig | None = None ) -> AsyncGenerator[ScrapeResult[Video], None]

Parameters

  • query str — Search query words
  • pages int — Pages to fetch
  • filter_relevance str — Sort criteria (e.g. "views", "rating")
  • filter_duration_minimum str — Min minutes duration
  • filter_duration_maximum str — Max minutes duration
  • filter_resolution str — Video resolution category (e.g. "HD", "VR")
  • iterator_config IteratorConfig | None — Concurrency, ordering, source loading, retry, and terminal-error policy. The package default loads the html source.

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

AttributeTypeDescription
urlstrThe video page URL
titlestr | NoneVideo title
publish_datestr | NoneUpload / publish date string
lengthstr | NoneDuration string (e.g. 12:34)
ratingstr | NoneLike percentage value
viewsstr | NoneTotal views count
thumbnailstr | NoneCover image thumbnail URL
categorieslist[str] | NoneList of category labels
m3u8_base_urlstr | NoneConstructed HLS master playlist URL or direct MP4 URL depending on availability
author_linkstr | NoneUploader profile URL
pornstars_urlslist[str] | NoneStarring pornstar relative profile paths
uploader_idstr | NoneUploader identifier
uploader_statusstr | NoneUploader status
uploader_typestr | NoneUploader type
uploader_namestr | NoneUploader profile name
video_idstr | NoneUnique video key ID
is_hlsbool | NoneBoolean indicating stream delivery type (True: HLS, False: Raw MP4)

Methods

Get Video Pornstars pornstars

@property async
An async-generator property yielding fully loaded pornstar profiles starring in this video. Unlike concurrent listing methods, it yields Pornstar objects directly rather than ScrapeResult.
async for star in video.pornstars: ... # AsyncGenerator[Pornstar, None]

Returns

→ AsyncGenerator[Pornstar, None]

Download Video download()

async
Downloads the video. If the video uses HLS streaming, processes it via configuration. If it falls back to raw MP4, processes it via backup_configuration.
await video.download( configuration: DownloadConfigHLS, backup_configuration: DownloadConfigRAW | None = None ) -> bool | DownloadReport

Parameters

  • configuration DownloadConfigHLS — Main HLS download config
  • backup_configuration DownloadConfigRAW | None — Backup direct file download config (required if is_hls=False)

Returns

→ bool | DownloadReport

Fetch Video Author author()

async
Fetches the uploader profile, automatically returning either a Pornstar or Channel object.
await video.author( load_html: bool = True ) -> Pornstar | Channel

Parameters

  • load_html bool — Pre-load uploader properties (default: True)

Returns

→ Pornstar | Channel

👤 BaseProfile, Channel, Pornstar, & Collection

BaseProfile inherits from BaseMedia and provides the common header properties (name, avatar, banner, and description) shared by both Channel and Pornstar profiles. Scrapers representing publisher channels, custom collections, and pornstar profile pages provide listing iterators via videos().

BaseProfile Attributes

AttributeTypeDescription
urlstrProfile page URL
namestr | NoneProfile display name
avatarstr | NoneAvatar image URL
bannerstr | NoneProfile header banner image URL
descriptionstr | NoneProfile bio description

Methods

Fetch Profile Videos videos()

async
Yields videos uploaded by or featuring this object.
async for result in obj.videos( pages: int = 2, iterator_config: IteratorConfig | None = None ) -> AsyncGenerator[ScrapeResult[Video], None]

Parameters

  • pages int — Pages to load
  • iterator_config IteratorConfig | None — Complete iterator policy. The package default loads the html source.

Returns

→ AsyncGenerator[ScrapeResult[Video], None]

👤 User

dataclass Inherits from BaseMedia. Represents a registered user account profile page.

Attributes

AttributeTypeDescription
urlstrProfile page URL
namestr | NoneUsername display name
collection_urlslist[str] | NoneList of relative collection paths created by the user

Methods

Get User Collections get_collections()

async
Yields playlist collections created by this user.
async for collection in user.get_collections( load_html: bool = True ) -> AsyncGenerator[Collection, None]

Parameters

  • load_html bool — Pre-load full collection metadata (default: True)

Returns

→ AsyncGenerator[Collection, None]

⬇️ Downloading Options

YouPorn serves videos as both HLS playlists and raw MP4 direct links. In order to handle both cases securely, provide a backup RAW configuration along with the HLS options:

python
from base_api import DownloadConfigHLS, DownloadConfigRAW

hls_config = DownloadConfigHLS(
    quality="best",
    path="./downloads",
    no_title=False
)

raw_config = DownloadConfigRAW(
    quality="best",
    path="./downloads",
    no_title=False
)

# Will download via HLS if is_hls=True, or fall back to raw direct file downloader if false
success = await video.download(configuration=hls_config, backup_configuration=raw_config)

For more configurations, see references in eaf_base_api Documentation.

📊 Scraping Results

Concurrent search and profile listing methods accept one IteratorConfig policy and yield immutable ScrapeResult[Video] values. The package default loads html, skips terminal page failures, and resolves its unset retry policies from the active RuntimeConfig.request_* settings. A supplied configuration replaces that default, so preserve the HTML source and page error mode explicitly; the example below deliberately opts into yielding page failures. The Video.pornstars and User.get_collections() generators remain direct object iterators.

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.

python
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 client.search_videos(
    "milf", 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)
Independent page and item handlers
Page and item handlers are routed independently. Assign the same callable to both fields, as above, only when both stages should use the same policy. A handler receives 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.

ScrapeResult Attributes

AttributeTypeDescription
stageScrapeStagePAGE or ITEM
urlstrThe page or item target URL
page_indexintZero-based source-page index
item_indexint | NoneZero-based item index; None for page failures
attemptsintNumber of attempts consumed
itemVideo | NoneThe loaded item on success
errorScrapeOperationError | NoneThe typed terminal error on failure
succeededboolTrue when the result contains an item
unwrap()VideoReturns the item or raises its terminal error

⚠️ Error Handling

Source loaders translate request failures into exceptions from youporn_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. Direct unresolved-field access raises base_api.DataNotLoadedError, while operations outside media loading may 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.

The provider-specific RegionBlocked and legacy youporn_api.modules.errors.DataNotLoadedError now derive from ScraperException. The legacy class is distinct from base_api.DataNotLoadedError, which is raised for unresolved media fields.

See Logging & Cleanup for application logging setup.

ExceptionTrigger Cause
VideoUnavailableThe server returned HTTP 404, or the requested video is deleted or unavailable
RegionBlockedVideo content is blocked in user's geographic region
NetworkErrorRequest failed due to a network error, exhausted request retries, or a non-404 HTTPStatusError
BotDetectionBot-protection challenge block detected
ProxyErrorProxy configuration failed or proxy is down
UnknownNetworkErrorUnexpected network errors
DownloadFailedDownload preparation or transfer failed; the video URL is included and __cause__ retains the original exception
python
from base_api import MediaLoadError
from youporn_api.modules.errors import RegionBlocked

try:
    video = await client.get_video(url)
except MediaLoadError as error:
    if isinstance(error.original_error, RegionBlocked):
        print("This video is blocked in your country! Try a permitted proxy if appropriate.")
    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.

YouPorn API includes a command-line interface accessible via youporn_api or python -m youporn_api:

bash
# Download a single video
youporn_api --download "https://www.youporn.com/watch/1234567/sample-title/" --quality best --output ./downloads --no-title False

# Or invoke via python -m
python -m youporn_api --download "https://www.youporn.com/watch/1234567/sample-title/" --quality best --output ./downloads --no-title False

# Download from a line-separated file of URLs
youporn_api --file urls.txt --quality best --output ./downloads --no-title False

CLI Options

FlagDescription
--download URLVideo URL to download
--file FILEText file with URLs (separated by newlines)
--quality QUALITYVideo quality: best, half, worst
--output DIRDestination directory or output file path
--no-title True/FalseSkip auto-appending video title to output filename (default: False)

🖥️ Supported Platforms

PlatformArchitectureStatus
Windows 11x64✅ Tested
macOS Sequoiax86_64 / arm64✅ Tested
Linux (Arch)x86_64✅ Tested
Android 16aarch64✅ Tested

📝 Changelog

DateCommitChanges
2026-09-158144589 / 874e7ab / f4272beAdopted 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. Added BaseProfile class for common header attributes (name, avatar, banner, description) across Channel and Pornstar. Added complete public type-hint coverage across the API.
2026-08-116c2af7fCompleted additional public type-hint coverage.
2026-08-11b7c2cb3Released 1.8 with typing improvements and the py.typed marker.
2026-08-0836a06feCentralized concurrent scraping on IteratorConfig and forwarded package source/retry defaults.
2026-08-07f163c07Migrated source-aware media, explicit loading, bounded retries, and structured scrape results to eaf v4.