{# ── "try the new home page" ───────────────────────────────────────────
Only rendered on the classic layout, and only until this account has
either dismissed it or switched over once (app.py decides, see
show_new_home_promo). Not rendered at all otherwise: a banner that the
client hides after the fact still ships its text to everyone and still
flashes on a slow paint.
The switch is per ACCOUNT. Trying the new layout does not change what
anybody else sees, which is the whole reason this is an invitation and
not an announcement. #}
{% if show_new_home_promo %}
{{ _('Beta') }}
{{ _('Try the new home page') }}
{{ _('Rows grouped by question instead of by source, with your watch progress and watchlist on top. Only you see the change — switch back at any time in Settings.') }}
{% endif %}
{{ _('What do you want to download?') }}
{{ _('One title is enough — MediaForge asks every active source at once.') }}
{# The Seerr modal reuses .search-bar, so the home-only pill styling hangs off
the extra .home-searchbar class instead of touching .search-bar itself. #}
{# Recent searches / suggestions. Filled by app.js's search history --
empty (and invisible) until the user has searched at least once. #}
{# Direct Link is the quieter alternative to searching, so it reads as a
ghost button and the accent pill anchors the right end of the field. #}
{# The panel-bar keys below (panel_*, hp_*) live in this template rather
than in routes/home_panels.py because babel.cfg extracts Jinja templates
ONLY -- a _() in Python source never reaches a catalogue. The server
sends the key, static/home_panels.js looks it up here.
Placeholders are written as "{}" and not "%s": Flask-Babel installs
newstyle gettext, which rewrites %s to {} in the rendered string while
the catalogue keeps %s -- "{}" keeps template, catalogue and JS in step.
NOTE: do not put a Jinja comment inside the dict below -- a comment is
not allowed inside an expression and takes the whole page down with a
TemplateSyntaxError. (Nor inside this one: the closing delimiter of a
nested comment ends the outer one and the rest leaks onto the page.) #}
{# Every string the home page renders client-side, translated here so it
goes through the same Flask-Babel catalogue as the rest of the app
instead of a hardcoded de/en pair in JavaScript. Rendered for both home
variants -- the search box below is shared. #}
{# The panel bar: buttons under the search field, one panel below them.
Both are empty until /api/home-panels answers -- which panels an account
may even see is decided server-side (Storage and System are admin-only),
so rendering the buttons here would mean rendering buttons that 403. The
bar hides itself when nothing is available. #}
{% if new_home %}
{% endif %}
{# Which sources a search actually hits. Filled by renderSourceChips() in
app.js once /api/settings answered; empty (and invisible) until then.
The new home page does NOT render this: its own chip row (below) says
the same thing *and* filters, and two rows of identical source names
stacked on top of each other is a puzzle, not a control. #}
{% if not new_home %}
{# The way in to "which home page do I want", on the classic layout too.
Not optional politeness: /settings redirects a non-admin to "/", so this
modal is the ONLY place a normal account can pick a layout -- and the
promo banner above is gone for good once it has been answered. Without
this, dismissing the banner would be a one-way door onto v1. #}
{% endif %}
{# Only rendered while something is downloading -- see renderHomeRunStrip(),
fed by the queue poll that runs anyway. #}
{{ _('Searching...') }}
{# Dashboard widgets from enabled extensions (see
register_thirdparty(dashboard_widget_template=...) in
web/thirdparties/registry.py) — each entry's own template is included
as-is, so the widget's markup/behaviour is entirely up to the
extension; this just provides the slot + consistent spacing
(.browse-provider-block, reused for its margin only — no provider dot
styling implied). Nothing renders here if no extension registered one. #}
{% for widget in dashboard_widgets %}
{# "ignore missing" -- a widget template that was removed/renamed after
being registered (e.g. mid-upgrade) silently disappears instead of
taking down the entire home page for every user. #}
{% include widget.template ignore missing %}
{% endfor %}
{# Settings -> General -> "Use the new home page": one row per question,
every enabled source mixed into it, instead of one block per source. The
classic block below stays the default and is what modules extend. #}
{% if new_home %}
{# The chip row and the way in to "which rows do I even want". /settings
is admin-only, so this is where a normal account reaches its own
Start Page settings -- the same controls, same code, same storage. #}
{# Personal rows first: what you were doing beats what a site published.
Each one hides itself when its source has nothing to say (no playback
position yet, no favourites, calendar switched off), so a fresh install
shows exactly the discovery rows below and no empty furniture. #}
{{ _('Continue watching') }}
{{ _('Your watchlist') }}
{{ _('New in your library') }}
{{ _('Airing next') }}
{{ _('New this week') }}
{{ _('Popular right now') }}
{{ _('Movies') }}
{{ _('Nothing to show with these filters.') }}
{% else %}
AniWorld
{{ _('New Anime') }}
{{ _('Popular Anime') }}
SerienStream
{{ _('New Series') }}
{{ _('Popular Series') }}
FilmPalast
{{ _('New Movies') }}
MegaKino
{{ _('New Movies') }}
{{ _('Popular Movies') }}
{{ _('New Series') }}
{{ _('Popular Series') }}
hanime 18+
{{ _('New') }}
{{ _('Trending') }}
{% endif %}
{# Start Page settings for this account. Same macro the Settings tab uses --
an admin sees the instance defaults there as well, everyone sees their own
here. Rendered on BOTH layouts: /settings redirects a non-admin, so this is
the only place a normal account can switch between them at all. #}
{{ _('Your home page') }}
{{ _('These settings are yours alone. Anything you do not change follows the instance default.') }}