config_version: 3 # API authentication credentials are stored in `auth.credentials.json` next to this file. # To reset credentials, stop the server, delete that file, then restart `javinizer web`. # # Setup endpoint protection (first-arriver takeover prevention): # Set JAVINIZER_SETUP_SECRET environment variable to require a bootstrap secret # for the /auth/setup endpoint. If not set, setup is only available from localhost. # Example: export JAVINIZER_SETUP_SECRET="my-secret-key" # When set, include X-Setup-Secret: my-secret-key header in the setup request. # # To allow setup from additional networks (e.g. Docker bridge), set # JAVINIZER_SETUP_TRUSTED_CIDRS to a comma-separated list of CIDRs. # Example: export JAVINIZER_SETUP_TRUSTED_CIDRS="172.16.0.0/12" # This adds the given networks to the default loopback-only allowlist. # Interface language (i18n) preference shared by the Web UI and TUI. # - "auto" (default): Web UI uses browser preference, TUI uses OS locale. # - A BCP 47 tag such as "en", "ja", "zh-Hans", or "pt-BR" applies to both. # Unsupported but valid tags fall back to English at runtime. ui: language: auto server: host: localhost port: 8765 api: security: # CORS allowed origins for API and WebSocket connections # - Specific origins only (wildcard "*" is NOT supported for security reasons) # - Empty array [] means same-origin only # - Add frontend origins if using a separate web server (e.g., "http://localhost:5173" for Vite dev server) allowed_origins: - http://localhost:8765 - http://localhost:5173 - http://localhost:5174 - http://127.0.0.1:8765 - http://127.0.0.1:5173 - http://127.0.0.1:5174 # Allowed directories for API file operations (organize, preview, etc.) # Empty list = deny-by-default until you choose a specific folder. # Example entries: ~/Videos, /media, /mnt/nas/movies allowed_directories: [] # Explicitly deny specific directories (optional) denied_directories: [] # Maximum number of files to return in a scan max_files_per_scan: 10000 # Timeout for scan operations (seconds) scan_timeout_seconds: 30 # Rate limiting for write endpoints (per IP, requests per minute) # Set to 0 to disable. Default: 60 rate_limit: requests_per_minute: 60 # Trusted reverse proxy IPs for X-Forwarded-Proto header validation. # When configured, session cookies get the Secure flag if a request from # a trusted proxy has X-Forwarded-Proto: https. # Example: ["172.16.0.1"] for a Docker reverse proxy trusted_proxies: [] # Force Secure flag on session cookies regardless of TLS detection. # Use when TLS termination happens upstream and proxy IPs are dynamic. force_secure_cookies: false system: # File creation mask (umask) for created files and directories # 002 = rwxrwxr-x (owner and group can write, others can read) # 022 = rwxr-xr-x (only owner can write, others can read) # Can be overridden with UMASK environment variable umask: "002" # Enable automatic version checking (notifications only, no auto-update) version_check_enabled: true # Interval between version checks in hours (default: 24) version_check_interval_hours: 24 # Restrict update notifications to stable releases only (default: false). # When false, notifications also surface prereleases (e.g. v1.1.0-rc1) so # users tracking release candidates are alerted. Set to true to be # notified only about stable releases. version_check_stable_only: false # Base directory for temporary files (posters, etc.) # Can be overridden with JAVINIZER_TEMP_DIR environment variable temp_dir: data/temp image_cache_enabled: true image_cache_ttl_hours: 168 image_cache_max_size_mb: 512 scrapers: user_agent: "" # Default: Chrome UA. r18dev uses Javinizer UA automatically. # Referer header for CDN compatibility (required by DMM/R18 CDN) referer: https://www.dmm.co.jp/ # HTTP client timeout in seconds (default: 30) timeout_seconds: 30 # Overall request timeout in seconds (default: 60) request_timeout_seconds: 180 priority: - r18dev - libredmm - dmm - javlibrary - javdb - javbus - jav321 - mgstage - tokyohot - aventertainment - caribbeancom - dlgetchu - fc2 - javstash # NEW: Global scrape_actress default (opt-out behavior) scrape_actress: true # NEW: Global Browser configuration browser: enabled: false # Master kill-switch (enable per-scraper below) binary_path: "" # Auto-discovered if empty timeout: 30 # Operation timeout (seconds) headless: true # Run headless (hide browser window) stealth_mode: true # Anti-detection measures window_width: 1920 # Viewport width window_height: 1080 # Viewport height slow_mo: 0 # Slow motion (ms, for debugging) block_images: true # Block images for speed block_css: false # Block CSS (may break some sites) user_agent: "" # Override UA (empty = use scraper's) debug_visible: false # Show browser window for debugging # Global FlareSolverr config for Cloudflare bypass. # Per-scraper override: set flaresolverr at scraper level (e.g., scrapers.r18dev.flaresolverr). flaresolverr: enabled: false url: "http://localhost:8191/v1" timeout: 30 session_ttl: 300 # HTTP/SOCKS5 proxy configuration. # - Define reusable profiles in `profiles` # - Scraper uses `proxy.profile: profilename` to select a profile # - FlareSolverr is configured at scraper level or globally (scrapers.flaresolverr) proxy: enabled: false default_profile: "main" # Global default profile when proxy is enabled profiles: main: url: "" # Examples: "http://proxy.example.com:8080", "socks5://localhost:1080" username: "" # Optional authentication password: "" # Optional authentication backup: url: "" username: "" password: "" # Per-scraper proxy overrides (optional). # Each scraper can override with: proxy.profile, proxy.url, etc. # Per-scraper FlareSolverr: set flaresolverr at scraper level (not under proxy). r18dev: enabled: true language: en # en | ja user_agent: Javinizer (+https://github.com/javinizer/javinizer-go) # Scraper-friendly source, uses Javinizer UA by default respect_retry_after: true # Respect Retry-After header from server # rate_limit: 0 # Delay between requests in milliseconds (0 = no delay) # retry_count: 0 # Number of retries on failure (0 = no retries) dmm: enabled: false use_browser: true # Enable browser for DMM streaming pages # scrape_actress: null # Optional: inherit from global (true) # Or override: scrape_actress: false user_agent: "" use_flaresolverr: false libredmm: enabled: false base_url: "https://www.libredmm.com" mgstage: enabled: false # Opt-in: requires age verification cookie (adc=1) # JavLibrary requires FlareSolverr for Cloudflare bypass. # Configure flaresolverr at scrapers.flaresolverr or at scraper level. javlibrary: enabled: false # Optional guarded per-performer field splits; no default entries. # See docs/02-configuration.md (Explicit cast-name splits). # actress_name_overrides: # aa6sc: {source_name: "Yorimoto Shiori", first_name: "Shiori", last_name: "Yorimoto"} # Frontend scraper options: # language: en, ja, cn, tw language: ja # Default Japanese # rate_limit: 1000 # Delay between requests in milliseconds (0 = no delay) base_url: "http://www.javlibrary.com" cookies: cf_clearance: "" cf_bm: "" user_agent: "" # Proxy configuration: # - enabled: true + profile: name → Use specific profile # - enabled: true (no profile) → Inherit global default # - enabled: false or omitted → Direct (no proxy) # Note: Global scrapers.proxy.enabled must be true for proxy to work. proxy: enabled: false # profile: main # Set enabled: true and uncomment to use proxy use_flaresolverr: false # Enable to use global FlareSolverr for Cloudflare bypass # JavDB: configure flaresolverr at scrapers.flaresolverr or per-scraper javdb: enabled: false base_url: "https://javdb.com" # rate_limit: 1000 # Delay between requests in milliseconds (0 = no delay) # Example: proxy profile (flaresolverr configured globally or per-scraper) # proxy: # enabled: true # profile: main use_flaresolverr: false # Enable to use global FlareSolverr for Cloudflare bypass javbus: enabled: false language: ja base_url: "https://www.javbus.com" # age=verified, dv=1, existmag=mag cookies are applied automatically by scraper. use_flaresolverr: false # Enable to use global FlareSolverr for Cloudflare bypass jav321: enabled: false base_url: "https://jp.jav321.com" tokyohot: enabled: false language: ja base_url: "https://www.tokyo-hot.com" aventertainment: enabled: false language: en base_url: "https://www.aventertainments.com" scrape_bonus_screens: false # Append bonus image files (e.g., "特典ファイル ... (48 Pics)") to screenshot URLs dlgetchu: enabled: false base_url: "http://dl.getchu.com" caribbeancom: enabled: false language: ja base_url: "https://www.caribbeancom.com" fc2: enabled: false base_url: "https://adult.contents.fc2.com" javstash: enabled: false # Opt-in - requires API key from javstash.org api_key: "" # API key for authentication (or set JAVSTASH_API_KEY env var) base_url: "https://javstash.org/graphql" language: en # en | ja metadata: # Per-field priorities default to inherit `scrapers.priority` (empty []). # A non-empty list here locks the field to those scrapers exclusively with # NO fallback to the global list — so it would ignore scrapers the user # later enables (issue #105). Leave fields empty to inherit; set a list only # to customize a specific field's scraper order. priority: actress: [] content_id: [] cover_url: [] description: [] director: [] genre: [] id: [] label: [] maker: [] original_title: [] poster_url: [] rating: [] release_date: [] runtime: [] screenshot_url: [] series: [] title: [] trailer_url: [] # Read-only R18 source evidence in scrape review; restart required. # Separate from offline_name_sync; each scrape operation must also opt in. offline_scrape_evidence: enabled: false artifact_directory: "" max_age_hours: 168 # Actress image database (SQLite-backed) actress_database: enabled: true auto_add: true # Automatically add new actresses to database convert_alias: false # Convert actress names using alias database candidate_retention_days: 30 # Delete creditless scrape candidates after 30 days # Explicitly reviewed Japanese-name updates from a locally provisioned artifact. # No downloads, automatic identity matches, or scrape-time changes. # All settings and the artifact snapshot are pinned until server restart. offline_name_sync: enabled: false # Requires actress_database.enabled artifact_directory: "" # Set a clean absolute server-local path before enabling max_age_hours: 168 # Finite 1..8760; maximum source observation age max_queued_jobs: 16 # 1..32 outstanding jobs across server processes max_queued_tasks: 2000 # 1..8192 outstanding tasks across server processes # Genre replacement/normalization database (SQLite-backed) genre_replacement: enabled: true auto_add: true # Automatically add new genres with identity mapping (genre -> genre) # Word uncensor/text replacement database (SQLite-backed) # Applies substring search-and-replace (longest-match-first) to all text # fields, including title, description, director, maker, label, series, # translations, and each genre token. Default censored->clean pairs (e.g. # S******n -> Shotacon) are seeded into the database on startup. # Opt-in: disabled by default since it rewrites all text fields. word_replacement: enabled: false # Per-movie tag database (SQLite-backed) # Allows adding custom tags to individual movies (appears in NFO files) tag_database: enabled: false # Enable per-movie tag lookup (opt-in feature) # Local r18.dev dump lookup (SQLite-backed) # When the dump database is present (created by `javinizer dump download`), # the r18.dev scraper resolves content_ids locally instead of via # rate-limit-prone HTTP probing. Harmless when the file is absent. r18dev_dump: enabled: true # Activates automatically once the dump is downloaded path: data/r18dev/r18dev_dump.db # Sidecar SQLite path (relative to working dir) # Metadata translation pipeline translation: enabled: false # Opt-in: disabled by default provider: openai # openai | openai-compatible | anthropic | deepl | google source_language: ja # e.g., en, ja, zh, auto target_language: en # e.g., en, ja, zh timeout_seconds: 60 apply_to_primary: true # Replace main metadata fields with translated text overwrite_existing_target: true fields: title: true original_title: true description: true director: true maker: true label: true series: true genres: true actresses: true openai: # OpenAI-compatible endpoint (works with OpenAI, OpenRouter, and compatible providers) base_url: https://api.openai.com/v1 api_key: "" # Tip: set via OPENAI_API_KEY env var model: gpt-4o-mini deepl: mode: free # free | pro (API Free/Pro plans) base_url: "" # Optional override; defaults by mode api_key: "" # Tip: set via DEEPL_API_KEY env var google: mode: free # free (public endpoint) | paid (Cloud Translation API) base_url: "" # Optional override api_key: "" # Required for paid mode (GOOGLE_TRANSLATE_API_KEY) openai_compatible: base_url: http://localhost:11434/v1 api_key: "" # Optional for local/self-hosted endpoints model: "" enable_thinking: false # Automatically mapped to backend-specific thinking controls when supported anthropic: base_url: https://api.anthropic.com api_key: "" # Required when provider=anthropic (set via ANTHROPIC_API_KEY env var) model: claude-sonnet-4-20250514 # Genres to ignore/filter out. Supports both exact strings and regex patterns. # Patterns starting with ^, ending with $, or containing regex metacharacters are treated as regex. # Examples: # - "Sample" # Exact match # - "^Featured" # Starts with "Featured" # - ".*mosaic.*" # Contains "mosaic" # - "^(HD|4K|VR)" # Starts with HD, 4K, or VR # - "(?i)uncensored" # Case-insensitive match for "uncensored" ignore_genres: [] # ignore_genres: # - "^Featured Actress" # - ".*mosaic.*" # - "Sample" # - "Trailer" required_fields: [] nfo: enabled: true display_title: