Skip to content

Architecture

Domekologe edited this page Jun 13, 2026 · 2 revisions

Architecture

🌐 English · Deutsch

Project layout

src/aniworld/
├── __main__.py / entry.py     # Entry point: always launches the WebUI
├── arguments.py               # CLI flags (-wP, -wH, -wN, -d)
├── config.py                  # Global config, HTTP session, language/URL patterns
├── env.py                     # Legacy .env merge (only if the file exists)
├── logger.py                  # Logging setup
├── autodeps.py                # Auto-download of dependencies (Chromium, mpv, …)
├── providers.py               # Source registry (AniWorld, SerienStream, FilmPalast)
├── search.py                  # Search + browse lists (new/popular anime & series)
├── extractors/
│   └── provider/              # One module per video host (voe.py, vidoza.py, …)
├── models/
│   ├── aniworld_to/           # Series / Season / Episode for aniworld.to
│   ├── s_to/                  # Series / Season / Episode for s.to
│   ├── filmpalast_to/         # Episode (movie) for filmpalast.to
│   └── common/                # Download logic: yt-dlp + FFmpeg, progress
├── playwright/
│   └── captcha.py             # Captcha detection & interactive solving (Patchright Chromium)
├── anime4k/                   # Upscaling (mpv/libplacebo) + bundled GLSL shaders
└── web/
    ├── app.py                 # Flask app: all routes, workers, create_app()
    ├── auth.py                # Login, setup, OIDC, user management, rate limit
    ├── db.py                  # SQLite access, schema, settings (incl. encryption)
    ├── notifications.py       # Web Push, Telegram, Discord, Pushover, ntfy, WhatsApp
    ├── transcoder.py          # HLS live transcoding for the browser player
    ├── library_watcher.py     # watchdog-based library monitoring
    ├── templates/             # Jinja2 templates (one file per page)
    ├── static/                # CSS/JS (one CSS/JS file per page) + PWA assets
    └── translations/          # Flask-Babel (de)

Startup flow

  1. aniworldentry.aniworld(): terminal title, ensure_patchright_chromium() (downloads Chromium if needed), argument parsing.
  2. start_web_ui()create_app():
    • Database initialisation (all tables, migrations)
    • Setup token generation if no admin exists
    • One-time .env → DB migration, then sync of all DB settings into os.environ
    • DNS patch according to the stored setting
    • Start of the background workers (see below)
  3. Production server: Waitress (16 threads) with clean signal handling (Ctrl+C kills running FFmpeg/Chromium subprocesses); Flask dev server in debug mode.

Background workers (daemon threads)

Worker Task Cadence
Queue worker Process downloads sequentially (with watchdog) poll 3 s
AutoSync worker Run due sync jobs poll 10 s
Upscale worker Process Anime4K jobs poll 4 s
Browse prefetch Warm browse lists, posters and TMDB data every 15 min
Update checker Check GitHub releases / models branch every 24 h
MediaScan scheduler Reload Plex/Jellyfin inventory every 24 h
TMDB keyword sync Download keyword export for advanced search checked hourly
TMDB cache eviction Delete expired cache entries hourly
Calendar watcher Cache TMDB schedule data for AutoSync/Seerr/Library titles (bilingual) into calendar_media/calendar_episodes poll 10 s, 1 title/cycle
Library watcher Filesystem events → targeted rescans event-driven

All workers are started idempotently via _ensure_* functions; in Flask debug mode only in the reloader child process (prevents duplicate downloads).

Settings system

Three layers, merged by create_app() at startup:

  1. DB (app_settings) — the authoritative source, written by the UI (sensitive keys encrypted, see Database).
  2. os.environ — populated from the DB at startup (_sync_db_settings_to_env); lets older code use os.environ.get("ANIWORLD_*") everywhere.
  3. Legacy .env — only imported once (_migrate_dotenv_to_db, guarded by the env_migrated flag).

HTTP layer

  • niquests with a thread-local session pool (GLOBAL_SESSION), default DNS via DoH (Google), switchable per setting (rebuild_global_session).
  • curl_cffi (Chrome impersonation) as fallback/complement when resolving host redirects (Cloudflare bypass).
  • Availability detection: is_source_unavailable() recognises 404/410/451 plus typical "video removed" markers in the HTML.

Security (web layer)

  • Auth decorator wrapping: all routes except auth/static/v1 API automatically get login_required; a defined list (_admin_only) gets admin_required.
  • CSRF: forms via Flask-WTF; JSON APIs are exempt but Content-Type: application/json is enforced for POST/PUT/DELETE.
  • SSRF protection: user-configured server URLs (Jellyfin/Plex/Seerr) are validated against cloud metadata endpoints and link-local networks.
  • Security headers incl. CSP on every response.

Data flow of a download

UI (/api/download) ──> download_queue (SQLite)
                            │ claim_next_queued()
                            ▼
                      queue worker
                            │ resolve_provider(url) → episode class
                            ▼
                  episode.download()
                   │ provider_data → extractor (e.g. VOE) → direct link
                   │ captcha if needed (playwright/captcha.py, interactive via UI)
                   ▼
              yt-dlp + FFmpeg → .mkv according to naming template
                            │
                            ▼
   status (completed/partial/failed) → notifications → Plex/Jellyfin refresh
                                          → optional upscale queue

Clone this wiki locally