Python Async v2.6

MissAV API

A fully asynchronous Python API wrapper and scraper for MissAV. Fetch JAV video metadata and download streams via HLS. Features Recombee-powered search with HMAC-signed API requests. 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-missav

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

bash
pip install unofficial-api-for-missav[av]
Note
Requires Python ≥ 3.12. Version 2.6 depends on eaf-base-api>=4.0.0, which is installed automatically.

🚀 Quick Start

python
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.

python
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.

python
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.

python
from missav_api import Client
client = Client()

Constructor Parameters

  • core BaseCore — Networking core instance (default: BaseCore())

Methods

Fetch Video get_video()

async
Fetches a video page and returns a populated Video object. Extracts the M3U8 playlist URL from obfuscated JavaScript embedded in the page HTML.
await client.get_video( url: str, load_html: bool = True ) -> Video

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

→ Video

Search Videos search()

async
Queries MissAV's Recombee recommendation engine to discover videos matching the search query. Generates an anonymous user ID and signs the API request with HMAC-SHA1.
async for result in client.search( query: str, video_count: int = 50, iterator_config: IteratorConfig | None = None ) -> AsyncGenerator[ScrapeResult[Video], None]

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 html source.

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

AttributeTypeDescription
urlstrThe video page URL
titlestr | NoneVideo title (from og:title)
publish_datestr | NoneRelease date (from og:video:release_date)
keywordsstr | NoneComma-separated keyword tags
lengthstr | NoneVideo duration (from og:video:duration)
m3u8_base_urlstr | NoneReconstructed HLS playlist URL from obfuscated JS
thumbnailstr | NoneCover image thumbnail URL (from og:image)

Methods

Download Video download()

async
Downloads the video via HLS streaming using the reconstructed M3U8 playlist URL. Appends the video title to the output path unless no_title=True. Ordinary failures raise DownloadFailed with full diagnostic context and chained cause.
await video.download( configuration: DownloadConfigHLS ) -> bool | DownloadReport

Parameters

  • configuration DownloadConfigHLS — HLS download configurations

Returns

→ bool | DownloadReport

⬇️ Downloading 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.

python
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.

How it works
  1. Generates an anonymous user ID (anon_<hex>)
  2. Signs the API path with HMAC-SHA1 using the public token
  3. Sends a POST request with the search query and count
  4. Parses recommendation results into video URLs
  5. Concurrently fetches full video metadata for each result
python
# 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.

MemberDescription
succeededTrue when the item was scraped successfully.
unwrap()Returns the Video, or raises the stored error.
itemThe optional Video value.
errorThe optional exception for a failed result.
stageThe 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.

ExceptionTrigger Cause
NotFoundServer returned HTTP 404 (e.g. video deleted)
NetworkErrorRequest failed due to a network error, exhausted request retries, or a non-404 HTTPStatusError
BotDetectionAnti-bot 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 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 with base_api.modules.provider (requiring eaf-base-api>=4.2.0). Failed downloads now raise DownloadFailed with 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 required safari17_2_ios impersonation profile to restore access after upstream 403 responses.

2.5 — 2026-08-11 b291d71

  • Added the py.typed marker for typed consumers and changed unset iterator retry policies to resolve from the live RuntimeConfig.
  • 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 html source 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:

bash
# 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

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