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-eporner
For custom CLI printing support, install with the optional cli components:
pip install unofficial-api-for-eporner[cli]
eaf-base-api>=4.2.0, which is installed automatically.
Quick Start
Run your scraping scripts inside an active event loop using async context:
import asyncio
from eporner_api import Client, DownloadConfigRAW
from eporner_api.modules.locals import Encoding
async def main():
client = Client()
# Retrieve video info
video = await client.get_video("https://www.eporner.com/video-12345/example-video")
print(video.title)
print(video.views)
# Download video in best quality using H264 encoding
config = DownloadConfigRAW(quality="best", path="./downloads")
await video.download(configuration=config, mode=Encoding.mp4_h264)
asyncio.run(main())
Configuration
Adjust timeouts, a proxy or bound interface, request retry/delay settings, cache limits, and iterator concurrency using the shared RuntimeConfig passed into BaseCore.
Please refer to the eaf_base_api Documentation for the complete reference.
from base_api import BaseCore
from base_api.modules.config import RuntimeConfig
from eporner_api import Client
my_config = RuntimeConfig()
my_config.proxy = "socks5://127.0.0.1:9050"
my_config.request_attempts = 4 # Total attempts, including the first request
core = BaseCore(configuration=my_config)
client = Client(core=core)
Iterator, retry, and error policy
All listing methods accept one IteratorConfig | None. If omitted, Eporner eagerly loads both "api" and "html", skips terminal page failures, and installs a handler that skips ResourceGone/NotFound failures (including those nested in media-load errors) while retrying other failures within the resolved budget. A supplied config replaces that complete default.
from base_api import ErrorAction, ErrorMode, ResultOrder, RetryPolicy, ScrapeErrorContext
from base_api.modules.config import IteratorConfig
async def handle_scrape_error(context: ScrapeErrorContext) -> ErrorAction:
print(context.stage, context.url, context.attempt, context.error)
return ErrorAction.RETRY
retry = RetryPolicy(
max_attempts=3, base_delay=0.5, multiplier=2.0, max_delay=8.0, jitter=0.25
)
iterator_config = IteratorConfig(
max_page_concurrency=2,
max_item_concurrency=10,
load_specific_sources=("api", "html"),
order=ResultOrder.ORIGINAL,
page_retry=retry,
item_retry=retry,
page_error_mode=ErrorMode.SKIP,
item_error_mode=ErrorMode.YIELD,
page_error_handler=handle_scrape_error,
item_error_handler=handle_scrape_error,
)
max_attempts includes the first attempt. page_error_handler and item_error_handler are routed independently. This example shares one callable because it intentionally applies the same retry decision to both stages; use separate callables when page and item policy differ. A handler may return RETRY, RAISE, YIELD, or SKIP; retrying remains capped, and a final RETRY falls back to the stage's configured ErrorMode.
Client
Scraper instance to orchestrate requests and retrieve media objects.
from eporner_api import Client
from base_api import BaseCore
client = Client()
client_custom = Client(core=BaseCore())
Constructor Parameters
- core BaseCore — Networking core instance (default:
BaseCore(RuntimeConfig()))
Methods
Fetch Video get_video()
Video object. By default, parses the JSON API endpoint first.Parameters
- url str — The Eporner video URL
- load_html bool — Parse full HTML elements for detailed fields (default:
False) - load_api bool — Fetch base properties from Eporner JSON endpoint (default:
True)
Returns
→ VideoSearch Videos search_videos()
Parameters
- query str — Search query words
- sorting_gay Gay | str — Exclude/include gay content filters (see Sorting Enums)
- sorting_order Order | str — Sort order (see Sorting Enums)
- sorting_low_quality LowQuality | str — Low quality exclusions (see Sorting Enums)
- per_page int — Number of video results per index page
- pages int — Number of search pages to parse
- iterator_config IteratorConfig | None — Concurrency, source loading, ordering, retry, and error policy; defaults to Eporner's API+HTML configuration
Returns
→ AsyncGenerator[ScrapeResult[Video], None]Fetch Category Videos get_videos_by_category()
Parameters
- category Category | str — Eporner Category enum (e.g.
Category._4K) - iterator_config IteratorConfig | None — Concurrency, source loading, ordering, retry, and error policy; defaults to Eporner's API+HTML configuration
Returns
→ AsyncGenerator[ScrapeResult[Video], None]Fetch Pornstar get_pornstar()
Parameters
- url str — The Eporner pornstar profile URL
- load_html bool — Pre-load parsed properties (default:
True)
Returns
→ PornstarFetch Channel get_channel()
Parameters
- url str — The Eporner channel profile URL
- load_html bool — Pre-load parsed properties (default:
True)
Returns
→ ChannelVideo
dataclass Inherits from BaseMedia. Represents a single video with details extracted from API endpoints and HTML elements. If a video has been deleted or removed by the platform, a ResourceGone error is raised cleanly.
Attributes
| Attribute | Type | Description |
|---|---|---|
url | str | The video page URL |
video_id | str | None | Unique video key ID |
keywords | list[str] | None | List of tags |
title | str | None | Video title (loadable from both API and HTML) |
views | int | None | Number of views (loadable from both API and HTML) |
rate | str | None | Rating representation |
publish_date | str | None | Publication / upload date string |
length_seconds | int | None | Duration in seconds |
length_minutes | str | None | Duration in minutes (e.g. 12:34) |
embed_url | str | None | Embed player path (loadable from both API and HTML) |
thumbnail | str | None | Default cover image thumbnail URL (loadable from both API and HTML) |
rating_value | str | None | Rating score value |
rating_count | str | None | Total rating votes |
parsed_urls | dict | None | Resolvable CDN paths mapped by resolution (e.g. {"720p": {"h264": "...", "av1": "..."}}) |
description | str | None | Video summary description |
encoding_format | str | None | Encoding format metadata |
is_family_friendly | str | None | Family friendly flag |
thumbnails | list[str] | None | List of alternative thumbs (loadable from both API and HTML) |
content_url | str | None | Meta content URL |
best_rating | str | None | Upper rating limits |
worst_rating | str | None | Lower rating limits |
authors_urls | list[str] | None | List of actor URLs starring in this video |
tags | list[str] | None | Tag labels parsed from the HTML page |
categories | list[str] | None | Category labels parsed from the HTML page |
uploader | str | None | Uploader name parsed from the HTML page |
Methods
Video Qualities video_qualities()
Returns
→ list[str]Get URL by Quality get_url_by_quality()
Parameters
- quality str | int — Target resolution (e.g.
1080or"1080p") - mode Encoding | str — Video codec format (e.g.
Encoding.mp4_h264or"h264")
Returns
→ strDownload Video download()
DownloadConfigRAW. Failure raises DownloadFailed with full context and chained cause.Parameters
- configuration DownloadConfigRAW — RAW download options (quality, path, etc.). See Downloading Options.
- mode Encoding | str — Video codec format (e.g.
Encoding.mp4_h264orEncoding.av1) - use_workaround bool — Enable download pipeline workarounds (default:
True)
Returns
→ boolGet Video Authors get_authors()
Parameters
- load_html bool — If
True, pre-fetches full metadata properties for the yielded pornstar
Returns
→ AsyncGenerator[Pornstar, None]Pornstar
dataclass Inherits from BaseProfile → BaseMedia. Represents an Eporner model profile with parsed statistics, bio, and video streams.
Attributes
| Attribute | Type | Description |
|---|---|---|
url | str | Profile URL |
name | str | None | Name of the pornstar (from BaseProfile) |
subscribers | str | None | Number of subscribers (from BaseProfile) |
picture | str | None | Cover avatar picture URL (from BaseProfile) |
video_amount | str | None | Number of uploaded/starring videos (from BaseProfile) |
video_views | str | None | Accumulated views on videos (from BaseProfile) |
websites | dict[str, str] | None | External links and social pages (from BaseProfile) |
pornstar_id | str | None | Unique numeric pornstar ID |
photos_amount | str | None | Number of photos |
pornstar_rank | str | None | Eporner site rank |
profile_views | str | None | Total views of this profile |
photo_views | str | None | Accumulated views on photos |
country | str | None | Country of origin |
age | str | None | Pornstar age |
ethnicity | str | None | Ethnicity metadata |
eye_color | str | None | Eye color |
hair_color | str | None | Hair color |
height | str | None | Height details |
weight | str | None | Weight details |
cup | str | None | Bra cup size |
measurements | str | None | Body measurements string (e.g. 34-24-34) |
biography | str | None | Biography paragraph description |
aliases | list[str] | None | List of alternate names |
Methods
Get Pornstar Videos videos()
BaseProfile.Parameters
- pages int — Pages to load (if
0, automatically calculates pages based on totalvideo_amount) - iterator_config IteratorConfig | None — Concurrency, source loading, ordering, retry, and error policy
Returns
→ AsyncGenerator[ScrapeResult[Video], None]Channel
dataclass Inherits from BaseProfile → BaseMedia. Represents an Eporner channel profile with rank, stats, logo, banner, and video stream pagination.
Attributes
| Attribute | Type | Description |
|---|---|---|
url | str | Channel page URL |
name | str | None | Channel name (from BaseProfile) |
subscribers | str | None | Subscriber count (from BaseProfile) |
video_amount | str | None | Total uploaded videos count (from BaseProfile) |
video_views | str | None | Accumulated video views count (from BaseProfile) |
picture | str | None | Profile/logo picture URL (from BaseProfile) |
channel_id | str | None | Unique numeric channel ID |
channel_rank | str | None | Channel platform rank |
logo | str | None | Channel logo image URL |
banner | str | None | Channel header banner image URL |
Methods
Get Channel Videos videos()
BaseProfile.Parameters
- pages int — Pages to load (if
0, automatically calculates pages based on totalvideo_amount) - iterator_config IteratorConfig | None — Concurrency, source loading, ordering, retry, and error policy
Returns
→ AsyncGenerator[ScrapeResult[Video], None]Downloading Options
Eporner serves direct MP4 media files. Download options are configured via the DownloadConfigRAW class, specifying the encoding type (AV1 or H.264):
from base_api import DownloadConfigRAW
from eporner_api.modules.locals import Encoding
config = DownloadConfigRAW(
quality="best", # "best", "half", "worst", or height (e.g. 1080)
path="./downloads", # Output directory
no_title=False, # Auto-appends title + ".mp4" if False
allow_multipart=True, # Enable multi-threaded segmented range downloads
max_workers=5 # Concurrent segment downloaders
)
# Download using H.264 codec
await video.download(configuration=config, mode=Encoding.mp4_h264)
For more configurations regarding RAW downloaders, please read the reference inside eaf_base_api Documentation.
Scraping Results
Concurrently iterated methods yield immutable ScrapeResult[Video] values. A result contains exactly one of item or error:
async for result in client.search_videos("couple", sorting_gay="0", sorting_order="latest", sorting_low_quality="1", per_page=10):
if result.succeeded:
video = result.unwrap() # Returns Video or raises the typed scrape error
print(video.title)
else:
print(f"{result.stage} error for {result.url}: {result.error}")
ScrapeResult Attributes
| Attribute | Type | Description |
|---|---|---|
url | str | The parsed video target URL |
stage | ScrapeStage | ITEM for media results or PAGE for yielded page failures |
page_index | int | Zero-based target-page index |
item_index | int | None | Extractor position, or None for a page failure |
attempts | int | Number of stage attempts used |
item | Video | None | The parsed Video when successful |
error | ScrapeOperationError | None | The typed page or item failure |
succeeded | bool | True when item is present |
unwrap() | Video | Returns the item or raises the stored typed error |
Changelog
2.4.1 (current)
- 2026-09-15 ·
3ee78ee/6b80518/f9fd944/01429e8— Updated dependency toeaf-base-api>=4.2.0and adopted centralized request/download error handling. Failed downloads now raiseDownloadFailedwith complete context. AddedBaseProfile,Pornstar, andChannelclasses with profile video scraping viavideos(). AddedClient.get_channel(). ExpandedVideometadata (dual API/HTML source loading for title, views, embed URL, and thumbnails;length_secondsinteger type; cleanResourceGoneexception when videos are deleted or removed). - 2026-08-14 ·
7f1bbac— Added HTML-backedtags,categories, anduploaderfields; renamedget_available_qualities()tovideo_qualities(); and made optional pornstar biography fields tolerant of missing page elements. - 2026-08-11 ·
c8f2974— Added typedScrapeResult[Video]annotations andpy.typed; fixed the Eporner v2 API URL/list response handling and treated packageNotFoundas a terminal resource error. Default iterator error handling now uses the structuredScrapeErrorContext/ErrorActionhandler. - 2026-08-08 ·
f862f1c— Replaced all per-method concurrency, loading, ordering, retry, and callback arguments withIteratorConfigwhile preserving eager("api", "html")loading. - 2026-08-07 ·
e3c682a— Migrated toeaf-base-api>=4.0.0: explicit request methods, source-aware media loaders, bounded scheduling, deterministic stream cleanup, structured scrape results, and validated extractors.
Sorting Enums
Search endpoints accept sorting parameters defined inside eporner_api.modules.sorting:
Gay
| Enum Member | API String Value | Filter Result |
|---|---|---|
Gay.exclude_gay_content | "0" | Exclude gay search listings |
Gay.include_gay_content | "1" | Include gay search listings |
Gay.only_gay_content | "2" | Only show gay search listings |
Order
| Enum Member | API String Value | Description |
|---|---|---|
Order.latest | "latest" | Order by upload date |
Order.longest | "longest" | Order by duration (descending) |
Order.shortest | "shortest" | Order by duration (ascending) |
Order.top_rated | "top-rated" | Order by rating score |
Order.most_popular | "most-popular" | Order by views count |
Order.top_weekly | "top-weekly" | Order by popular weekly trends |
Order.top_monthly | "top-monthly" | Order by popular monthly trends |
LowQuality
| Enum Member | API String Value | Filter Description |
|---|---|---|
LowQuality.exclude_low_quality_content | "0" | Only include high quality video files (HD) |
LowQuality.include_low_quality_content | "1" | Include both low quality (SD) and high quality (HD) video files |
LowQuality.only_low_quality_content | "2" | Only include low quality video files (SD) |
Error Handling
Source loaders translate request failures into exceptions from eporner_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.
| 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 | Bot-protection 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 eporner_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("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.
Eporner API includes a command-line interface accessible via eporner_api or python -m eporner_api:
# Download a single video
eporner_api --download "https://www.eporner.com/video-12345/sample-video/" --quality best --output ./downloads --no-title False
# Or invoke via python -m
python -m eporner_api --download "https://www.eporner.com/video-12345/sample-video/" --quality best --output ./downloads --no-title False
# Download from a line-separated file of URLs
eporner_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 |