{% extends "base.html" %} {% block title %}{{ _('Settings') }} — MediaForge
{% endblock %}
{% import "_settings_card_macro.html" as ext %}
{% block styles %}
{% endblock %}
{% set is_admin = not auth_enabled or (current_user and current_user.role == 'admin') %}
{% block content %}
{{ _('Settings') }}
{{ _('Configuration & Management') }}
{% if is_admin %}
{{ _('Your .env has been imported') }}
{{ _('All settings from') }} ~/.mediaforge/.env {{ _('are now stored in the database. The file is no longer needed.') }}
{% endif %}
{% if is_admin %}
{% endif %}
{% if is_admin %}
{% endif %}
{# Brand-new tabs a thirdparty registers with settings_host="settings"
and a settings_tab that isn't one of the ids above (see
registry.py's resolve_dynamic_tabs() / _KNOWN_TABS["settings"]).
Mirrors integrations.html's identical loop. #}
{% for t in get_dynamic_tabs('settings') %}
{% endfor %}
{% for card in get_settings_cards('settings', 'general') %}{{ ext.render_settings_card(card) }}{% endfor %}
{{ _('Data from previous installation') }}
{{ _('A previous AniWorld Downloader installation (~/.aniworld) was detected. Your settings, download history, users and profiles are imported automatically the first time MediaForge starts — so everything is usually already here. Use "Import remaining files" only if something appears to be missing; an existing database is never overwritten. You can hide this notice once you are done, or if you do not want to import.') }}
{{ _('Project & Support') }}
{{ _('MediaForge is an open-source project. For questions, bugs, or feature ideas please visit our GitHub repository.') }}
{{ _('The application was started with --debug. Debug mode is locked on and cannot be changed here.') }}
{% if is_admin %}
{{ _('Restart') }}
{{ _('Restarts MediaForge with the same startup arguments — without installing an update. Running downloads pause and resume afterwards.') }}
{% endif %}
{{ _('Web Console') }}
{{ _('Show the console output directly here in the Web UI') }}
{{ _('Console') }}
{% endif %}
{% for card in get_settings_cards('settings', 'design') %}{{ ext.render_settings_card(card) }}{% endfor %}
{{ _('Design') }}
{{ _('Appearance') }}
{{ _('Accent Color') }}
{{ _('Custom Color') }}
{{ _('Advanced Settings') }}
{{ _('These settings only change the design minimally.') }}
{{ _('A glow highlight for active menu items in the accent color') }}
{{ _('Change header color with accent color') }}
{{ _('Invert header color') }}
{{ _('An animated loading indicator for items not yet loaded in the overview') }}
{{ _('A highlight when hovering over a movie or series in the accent color') }}
{{ _('A highlight for currently downloading items in the accent color') }}
{{ _('Button becomes slightly brighter and 5%% smaller on click') }}
{{ _('Icons animate on hover in menus') }}
{% if is_admin %}
{{ _('Source order') }}
{{ _('Set the order in which sources appear on the start page. Drag the rows or use the arrows. For each source you can also choose whether new or popular items are shown first.') }}
{% endif %}
{% if is_admin %}
{% for card in get_settings_cards('settings', 'sources') %}{{ ext.render_settings_card(card) }}{% endfor %}
{{ _('Sources') }}
{{ _('Enable or disable the available sources. Disabled sources are hidden on the start page and are no longer loaded there.') }}
{{ _('hanime.tv is an adult source (18+) for sexually explicit animated content (hentai). Disabled by default; enabling requires an age confirmation.') }}
{{ _('Search') }}
{{ _('When enabled, disabled sources are also skipped in the search results.') }}
{{ _('Provider order') }}
{{ _('Order in which hosters are tried. If the hoster selected for a download fails (dead link, hoster not offered for that episode), MediaForge automatically continues with the next one in this list. Drag the rows or use the arrows.') }}
{{ _('When disabled, only the selected hoster is used and a download fails if it is unavailable.') }}
{{ _('Domain fallback (mirrors)') }}
{{ _('Alternative domains per site, tried top to bottom whenever a domain is unreachable or blocked (e.g. s.to → serienstream.to → 186.2.175.5). The first entry is the primary domain and cannot be removed. An IP address is called with the primary domain as its Host header. One entry per line.') }}
{% endif %}
{% for card in get_settings_cards('settings', 'downloads') %}{{ ext.render_settings_card(card) }}{% endfor %}
{% if is_admin %}
{{ _('Download Settings') }}
{{ _('Download Path') }}
{{ _('Changes take effect immediately for new downloads.') }}
{{ _('Default Language') }}
{{ _('Used as default when adding a new download.') }}
{{ _('Downloads are sorted by language (e.g. german-dub/, english-sub/).') }}
{{ _('Hides English Sub from the language selection.') }}
{{ _('Each movie gets its own subfolder — recommended for Jellyfin.') }}
{{ _('Custom Paths') }}
{{ _('Add Path') }}
{{ _('Name') }}
{{ _('Path') }}
{{ _('Actions') }}
{{ _('Bandwidth & Schedule') }}
{{ _('Bandwidth Limit') }}
{{ _('Throttles all downloads to this speed. 0 = unlimited. Applies to new downloads.') }}
{{ _('Download Time Window') }}
{{ _('New downloads only start within this window (server local time). Overnight windows like 22:00–06:00 are supported. Running downloads are not interrupted.') }}
{{ _('Download History') }}
{{ _('Automatically delete download-history entries older than the selected period. Runs about hourly.') }}
{% endif %}
{% for card in get_settings_cards('settings', 'autosync') %}{{ ext.render_settings_card(card) }}{% endfor %}
{% if is_admin %}
{{ _('Auto-Sync Defaults') }}
{{ _('How often Auto-Sync checks for new episodes. Language and provider are defaults for new sync jobs.') }} {{ _('Custom path unavailable:') }} {{ _('Defines what Auto-Sync should do when the assigned custom path is not available. This is the default for all new jobs but can be overridden per job.') }}
{{ _('Auto-Sync Error Handling') }}
{{ _('Defines how often and at what interval a failed Auto-Sync is retried before it is considered permanently failed.') }}
{{ _('Adaptive Auto-Sync') }}
{{ _('When an Auto-Sync job finds no new episodes for the selected period, it enters pause mode and is only re-checked at the wider interval below. As soon as a new episode is found again, it returns to the normal cycle.') }}
{% else %}
{{ _('Only administrators can change Auto-Sync settings.') }}
{% endif %}
{% for card in get_settings_cards('settings', 'network') %}{{ ext.render_settings_card(card) }}{% endfor %}
{{ _('Network / DNS') }}
{% if is_admin %}
{% endif %}
{{ _('Defines which DNS server resolves domains. Useful if your ISP blocks AniWorld or SerienStream.') }}
{{ _('DNS Diagnostics') }}
{{ _('DNS Status') }}
{{ _('— Not tested yet') }}
{{ _('Reachability') }}
aniworld.to—
serienstream.to—
filmpalast.to—
megakino.to—
hanime.tv—
{% if is_admin %}
{{ _('Captcha / Browser') }}
{{ _('Reuses one Chromium profile across captcha solves so a once-earned Cloudflare trust (cf_clearance) and browser fingerprint survive. This raises the Turnstile success rate. Applies on the next captcha; a restart guarantees a clean state.') }}
{{ _('Captcha options') }}
{{ _('If Turnstile keeps failing (red cross), delete the profile and solve one captcha manually in the web UI to seed a fresh trust.') }}
{% endif %}
{% if is_admin %}
{{ _('Web Server') }}
{{ _('Base URL (Reverse Proxy)') }}
{{ _('Public URL when MediaForge runs behind a reverse proxy (e.g. Nginx, Traefik). Required for OIDC callbacks and absolute links. Leave empty if no proxy is used.') }}
{{ _('Changes take effect after the next restart.') }}
{% endif %}
{% if is_admin %}
{% for card in get_settings_cards('settings', 'auth') %}{{ ext.render_settings_card(card) }}{% endfor %}
{{ _('User Management') }}
{% if not force_sso %}
{{ _('Add User') }}
{% endif %}
ID
{{ _('Username') }}
{{ _('Role') }}
{{ _('Authentication') }}
{{ _('Created') }}
{{ _('Actions') }}
{{ _('Single Sign-On (SSO / OIDC)') }}
{{ _('Connect MediaForge with an external identity provider (Keycloak, Authentik, Google, etc.).') }}
{{ _('Changes require a server restart.') }}
{{ _('The sub claim is more secure than the username. Found in server logs after the first SSO login.') }}
{{ _('✓ Saved — restart required') }}
{% endif %}
{% if is_admin %}
{% for card in get_settings_cards('settings', 'api') %}{{ ext.render_settings_card(card) }}{% endfor %}
MediaForge API
{{ _('External REST API for Home Assistant & Co. Auth via X-Api-Key header or ?apikey=.') }}
{{ _('AutoSync jobs — status overview (all users)') }}
GET
/api/v1/uptime
{{ _('UpTime monitor — current status per source') }}
GET
/api/v1/update-status
{{ _('Self-update progress / state') }}
GET
/api/v1/mediascan
{{ _('MediaScan run status') }}
GET
/api/v1/upscale
{{ _('Upscale queue, badge count & progress') }}
GET
/api/v1/history
{{ _('Download history — all users') }} ?limit=&offset=&status=&source=
{{ _('Example:') }}…
{{ _('Your installation') }}
{{ _('This ID is generated once per installation and is pseudonymous, not anonymous, from stage 2 onward -- it lets usage over time be linked to this one installation. It is never linked to your MediaForge account or username.') }}
{{ _('Manage my data') }}
{{ _('Request deletion or export of any data already sent under your installation ID -- available whether or not telemetry is currently enabled. The request is sent from this app, with your installation ID attached automatically (never typed by hand).') }}
{{ _('Data collection stages') }}
{{ _('Nothing here is sent unless you actively enable it. Turning a stage on enables every data point in it at once; you can then switch individual points back off -- the stage switch always reflects the combined state of its data points.') }}
{{ _('Telemetry active at all') }}
{% endif %}
{% for card in get_settings_cards('settings', 'updates') %}{{ ext.render_settings_card(card) }}{% endfor %}
Updates
{{ _('Installed') }}{{ app_version or _('unknown') }}
{{ _('Switch between the stable release and the development channel (latest commits from the models branch — may be unstable). Switching installs the selected version right away.') }}
🧪 {{ _('Development channel') }}
{{ _('You are using a stable release. The development channel contains the latest commits directly from the models branch — it may be unstable or contain unfinished features.') }}
{{ _('When enabled, an available update is installed automatically at the selected time on the chosen weekdays. The app restarts itself and running downloads resume afterwards.') }}
{# Brand-new tabs a thirdparty registers with settings_host="settings"
(see the dynamic tab-button loop in the tab bar above and
registry.py's resolve_dynamic_tabs()/_KNOWN_TABS["settings"]). #}
{% for t in get_dynamic_tabs('settings') %}
{% for card in get_settings_cards('settings', t.id) %}{{ ext.render_settings_card(card) }}{% endfor %}
{% endfor %}
18+
{{ _('Enable hanime (18+)') }}
{{ _('hanime.tv is a source for adult, sexually explicit animated content (hentai) and is only permitted for users aged 18 or older.') }}
{{ _('Are you UNDER 18 years old?') }}
18+
{{ _('Enable hanime (18+)') }}
{{ _('hanime.tv is a source for adult, sexually explicit animated content (hentai) and is only permitted for users aged 18 or older.') }}
{{ _('Should we really believe you are at least 18?') }}