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-missav
For TS→MP4 remuxing support (recommended for HLS downloads), install with the optional av dependency:
pip install unofficial-api-for-missav[av]
eaf-base-api>=4.0.0, which is installed automatically.
Quick Start
import asyncio
from missav_api import Client, DownloadConfigHLS
async def main():
client = Client()
# Fetch video metadata
video = await client.get_video("https://missav.ws/en/abc-123")
print(video.title)
print(video.keywords)
# Download 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.
Client sets the core's impersonation profile to "safari17_2_ios" before creating its session and installs the headers required by MissAV's current media endpoints. Pass a core whose session has not already been initialized so that profile takes effect.
Please refer to the eaf_base_api Documentation for details.
from base_api import BaseCore
from base_api.modules.config import RuntimeConfig
from missav_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
search() accepts one IteratorConfig | None. MissAV's default deliberately limits page concurrency to 1, eagerly loads "html", and skips terminal page failures. Preserve those settings when customizing it.
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=1,
max_item_concurrency=10,
load_specific_sources=("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 receives the failing stage, URL, exception, attempt budget, and page/item indexes in ScrapeErrorContext; its ErrorAction decision remains bounded by the policy.
Client
Main entry point class. Provides methods to fetch individual videos and perform search queries via Recombee recommendations API.
from missav_api import Client
client = Client()
Constructor Parameters
- core BaseCore — Networking core instance (default:
BaseCore())
Methods
Fetch Video get_video()
Video object. Extracts the M3U8 playlist URL from obfuscated JavaScript embedded in the page HTML.Parameters
- url str — The MissAV video page URL (e.g.
https://missav.ws/en/abc-123) - load_html bool — Pre-load parsed properties immediately
Returns
→ VideoSearch Videos search()
Parameters
- query str — Search query (e.g. JAV code, actress name, keyword)
- video_count int — Maximum number of results to return (default:
50) - iterator_config IteratorConfig | None — Per-iterator concurrency, source loading, ordering, retry, error-mode, and custom-handler settings. MissAV defaults to one page task and the
htmlsource.
Returns
→ AsyncGenerator[ScrapeResult[Video], None]Video
dataclass Inherits from BaseMedia. Represents a single JAV video with metadata extracted from OpenGraph meta tags and obfuscated JavaScript.
Attributes
| Attribute | Type | Description |
|---|---|---|
url | str | The video page URL |
title | str | None | Video title (from og:title) |
publish_date | str | None | Release date (from og:video:release_date) |
keywords | str | None | Comma-separated keyword tags |
length | str | None | Video duration (from og:video:duration) |
m3u8_base_url | str | None | Reconstructed HLS playlist URL from obfuscated JS |
thumbnail | str | None | Cover image thumbnail URL (from og:image) |
Methods
Download Video download()
no_title=True. Ordinary failures raise DownloadFailed with full diagnostic context and chained cause.Parameters
- configuration DownloadConfigHLS — HLS download configurations
Returns
→ bool | DownloadReportDownloading Options
MissAV video streams are delivered via HLS. The scraper reconstructs the M3U8 playlist URL from obfuscated pipe-delimited JavaScript variables embedded in each video page.
from missav_api import DownloadConfigHLS, Callback
config = DownloadConfigHLS(
quality="best", # "best", "half", "worst", or height int (e.g. 720)
path="./downloads", # Destination path
no_title=False, # If False, appends title + ".mp4"
callback=Callback.custom_callback, # Optional progress callback
)
success = await video.download(configuration=config)
For more configurations, see the shared eaf_base_api Documentation.
Search Engine
MissAV uses a Recombee recommendation engine for its search functionality. The API wrapper replicates the browser's HMAC-SHA1 signed POST requests to the Recombee client API.
- Generates an anonymous user ID (
anon_<hex>) - Signs the API path with HMAC-SHA1 using the public token
- Sends a POST request with the search query and count
- Parses recommendation results into video URLs
- Concurrently fetches full video metadata for each result
# Search for JAV content by code or keyword
async for result in client.search("SSIS", video_count=25):
if result.succeeded:
video = result.unwrap()
print(f"{video.title} — {video.publish_date}")
else:
print(f"{result.stage} failed: {result.error}")
Iterator results
Every search iteration yields a ScrapeResult[Video]. Test succeeded before reading the value, use unwrap() when failure should raise, or inspect the fields directly.
| Member | Description |
|---|---|
succeeded | True when the item was scraped successfully. |
unwrap() | Returns the Video, or raises the stored error. |
item | The optional Video value. |
error | The optional exception for a failed result. |
stage | The failing iterator stage, such as page or item. |
Error Handling
Source loaders translate request failures into exceptions from missav_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 | 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 missav_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
2.6 — 2026-09-15
8c16241/6389916— Adopted shared request and download error handling withbase_api.modules.provider(requiringeaf-base-api>=4.2.0). Failed downloads now raiseDownloadFailedwith complete context. Added layout anchor validations to detect page structure changes. Implemented robust fallback selectors for title, thumbnail, publish date, and duration. Enhanced m3u8 playlist URL extraction fallbacks (JS regex, direct regex, surrit regex) and validated base URL presence in download method. Added unit tests for snippet parsing and error scenarios.
2.6 — 2026-08-14
5cce2e3/562b69c— Updated cross-site request headers and switched the client to the requiredsafari17_2_iosimpersonation profile to restore access after upstream 403 responses.
2.5 — 2026-08-11 b291d71
- Added the
py.typedmarker for typed consumers and changed unset iterator retry policies to resolve from the liveRuntimeConfig. - Updated the package version from 2.4 to 2.5.
IteratorConfig synchronization — 2026-08-08 dc52215
- Moved search iteration settings into
IteratorConfig. - Preserved MissAV's single-page concurrency and required
htmlsource loading.
Core v4 migration — 2026-08-07 9136b07
- Migrated to the eaf-base-api 4.x runtime and result model.
- Adopted policy-driven retries, structured scrape errors, and current iterator error handling.
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.
MissAV API includes a command-line interface accessible via missav_api or python -m missav_api:
# Download a single video
missav_api --download "https://missav.ai/dm132/en/sample-123" --quality best --output ./downloads --no-title False
# Or invoke via python -m
python -m missav_api --download "https://missav.ai/dm132/en/sample-123" --quality best --output ./downloads --no-title False
# Download from a line-separated file of URLs
missav_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 |