Skip to content

Extractors

TheMRX13 edited this page Jun 12, 2026 · 1 revision

Extractors

🌐 English · Deutsch

Extractors resolve a video host's embed URL into a direct stream link (usually HLS/MP4) that yt-dlp/FFmpeg can download.

Host status

Enabled (SUPPORTED_PROVIDERS in config.py):

Host Module Notes
VOE voe.py Multi-stage deobfuscation (ROT13, junk patterns, Base64), captcha support
Vidmoly vidmoly.py Requires referer https://vidmoly.biz
Vidoza vidoza.py
VeeV veev.py Custom headers (referer/origin veev.to), availability check via /api/veev/check

Present but disabled (commented out in SUPPORTED_PROVIDERS): Doodstream, Filemoon, LoadX, Luluvdo, Streamtape, Vidara.

Auto-discovery

extractors/__init__.py imports all modules from extractors/provider/ and registers every function whose name starts with get_direct_link_from_ or get_preview_image_link_from_ in the provider_functions dict:

provider_functions["get_direct_link_from_voe"](embed_url)

At app startup, _get_working_providers() (web/app.py) probes each entry from SUPPORTED_PROVIDERS with an empty URL string: if the extractor raises NotImplementedError it counts as not implemented; any other exception means "implemented" (it correctly rejected the empty URL). Only functional providers appear in the UI (WORKING_PROVIDERS).

Adding a new extractor

  1. Create the file: src/aniworld/extractors/provider/<host>.py
  2. Implement the function (mind the naming convention — <host> lowercase):
import logging
logger = logging.getLogger(__name__)

try:
    from ...config import GLOBAL_SESSION, is_source_unavailable
except ImportError:
    from aniworld.config import GLOBAL_SESSION, is_source_unavailable


def get_direct_link_from_<host>(embed_url: str) -> str:
    if not embed_url:
        raise ValueError("Empty URL")
    resp = GLOBAL_SESSION.get(embed_url)
    if is_source_unavailable(resp.text, resp.status_code):
        raise ValueError("Source removed")
    # ... parse HTML/JS, extract the stream URL ...
    return direct_link
  1. Enable the provider: add its name to SUPPORTED_PROVIDERS (config.py) — spelling must match func_name = f"get_direct_link_from_{p.lower()}".
  2. Define headers: if the host needs special headers, add them to PROVIDER_HEADERS_D (download) and possibly PROVIDER_HEADERS_W (watch) in config.py — these are passed to yt-dlp/FFmpeg.
  3. Optional: get_preview_image_link_from_<host>() for preview images.

Helpers from config.py

Function Purpose
GLOBAL_SESSION Thread-safe niquests session with realistic headers and DoH DNS
is_source_unavailable(html, status) Detects removed videos (404/410/451 + HTML markers) without an extra request
check_redirect_available(url) Follows the streaming site's redirect and checks whether the host still has the video (curl_cffi with Chrome impersonation against Cloudflare)
resolve_redirect_url(url) Returns the final host URL behind a redirect

Captcha integration

When an extractor detects a captcha page (is_captcha_page from playwright/captcha.py), it can call solve_captcha(...). If the call runs inside the queue worker, the queue_id is set via thread-local — which makes the solving interactive in the WebUI (live screenshot + click forwarding). Chromium runs with stealth patches, network ad blocking and protection against ad overlays.

Clone this wiki locally