mirror of
https://github.com/Screenly/Anthias.git
synced 2026-06-10 09:08:09 -04:00
* feat(webview): per-asset auto-refresh interval for webpage assets - Add metadata.refresh_interval_s to Asset, surfaced as a top-level field on AssetSerializerV2 (read) and as a write knob on Create/UpdateAssetSerializerV2; metadata stays read-only on the API so the upload pipeline keeps owning original_ext / transcoded / error_message - Validate 0..86400 (24h cap); update merge preserves existing metadata keys - Wire assets_update form handler to merge refresh_interval_s into metadata - Add edit-modal field inside the existing Advanced section, only rendered for mimetype === 'webpage'; auto-expand Advanced when interval is set - viewer.view_webpage now passes the interval through and always calls the new browser_bus.setReloadInterval slot (so an interval-only edit takes effect even when the URI is unchanged) - Webview: QTimer in View; new setReloadInterval D-Bus slot on MainWindow; loadPage / loadImage clear the timer; reload() targets currentWebView - Bump WebView default version to 2026.05.0 (D-Bus contract change) - Tests: 7 v2 API (POST/PATCH round-trip, negative/over-cap rejection, pipeline-metadata preservation, 0-disables), 3 form-handler (merge, empty-clears, oversize-clamps), 3 viewer pass-through Closes #2813 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(website): rewrite features page; mention webpage auto-refresh Folds the in-progress copy refresh of the marketing features page into the auto-refresh PR so the new "set an auto-refresh interval" capability ships in the same change as the feature itself. The card "Live web pages and dashboards" now explicitly mentions the per-asset reload cadence backed by metadata.refresh_interval_s. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(format): apply ruff format to test_viewer.py CI's run-python-linter rejects the as-written current_browser_url keyword arg wraps; ruff-format collapses them onto single lines. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(review): address four Copilot comments on PR #2841 - viewer: ``current_browser_url is not uri`` was an identity check; switch to ``!=`` so a same-text URL reconstructed each tick still short-circuits the loadPage hop. - viewer: ``elif 'video' or 'streaming' in mime`` evaluated as ``elif 'video' or ('streaming' in mime)`` — the literal short- circuited and the branch ran for any mimetype not caught earlier, making the ``Unknown MimeType`` else arm unreachable. Use ``'video' in mime or 'streaming' in mime``. - v2 serializer: clamp ``get_refresh_interval_s`` to ``>= 0`` so a hand-edited / legacy row with a negative metadata value never surfaces a value the write path would have rejected. - webview: setReloadInterval was arming the QTimer immediately, but loadPage loads into nextWebView and currentWebView remains the *previous* page until the swap. A short interval could fire reload() on the prior page. Stash the cadence in ``pendingReloadIntervalS`` and arm in ``switchToNextWebView`` once the new page is actually visible. The URL-unchanged path (no load in flight, ``pageLoadConnection`` empty) still arms immediately. Tests: add a v2 GET test that a negative refresh_interval_s in metadata is clamped to 0 on read. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(review): four more Copilot comments on PR #2841 - webview: drop the per-reload qDebug() — short intervals (5–10s) flooded journald to no diagnostic gain; failures already surface via loadFinished. - webview: setReloadInterval clamps ``seconds`` to [0, 86400] before multiplying by 1000. Defends the ``int`` math in armReloadTimer from a hostile / buggy D-Bus caller — server-side validation already caps to 86400 but the D-Bus contract is trust-no-one. - viewer: wrap ``browser_bus.setReloadInterval`` in try/except. An older AnthiasWebview (version skew during rollout, or a pinned WEBVIEW_VERSION) doesn't expose the slot; raising would abort the asset loop and black the screen. Log a warning, keep playing. - v2 serializer: ``get_refresh_interval_s`` clamps the upper bound on read in addition to negatives, so a hand-edited / legacy row with 999999 surfaces as 86400 (the documented max) rather than echoing a value the next PATCH would 400 on. Tests: parametrise the GET-clamp test to cover both bounds; add a viewer test that ``setReloadInterval`` raising falls back gracefully. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(review): drop Copilot-attribution noise from inline comments Strip "Per Copilot review" / "Per-Copilot" / PR-number references introduced in the previous two review rounds. They don't help future maintainers understand the code and rot once the PR is merged. Keep the underlying technical rationale (string identity vs value comparison, version-skew fallback, dual-buffer race for the timer arm, GET-side clamp). No behaviour change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(webview): add scheme to README D-Bus example URL The webview only handles ``http://`` / ``https://`` schemes (anything else gets handed to ``QUrl`` which would interpret a schemeless string as a relative URL). Update the documented example so copy/paste works. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(refresh-interval): centralise REFRESH_INTERVAL_S_MAX on the model Hoist the 86400-second cap from api/serializers/v2.py to app/models.py so the v2 serializer, the assets_update form handler, and the edit-modal ``<input max>`` attribute all read it from one place. Without this, the form handler had a hard-coded ``86400`` and the API path had ``REFRESH_INTERVAL_S_MAX``; bumping one and forgetting the other was a real risk. Mirrored separately by ``kMaxReloadIntervalS`` in webview/src/view.cpp because that's a different language; the docstring on the model constant flags the duplication so a future bump knows where to look. No behaviour change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(viewer): latch setReloadInterval capability after first failure Without the latch, every webpage rotation against an older AnthiasWebview re-pays the D-Bus round-trip and refills journald with the same warning. Once the slot is known to be missing, skip both — the version skew can't change for the lifetime of the viewer process (an upgrade requires a viewer restart, which resets the cache). Test updated to assert the second view_webpage call doesn't re-hit setReloadInterval. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(review): three Copilot comments on PR #2841 round 6 - viewer: latch the setReloadInterval capability OFF only when the D-Bus error indicates the method is missing (UnknownMethod / "no such method"). Transient errors (bus disconnect, timeout, race during webview restart) get logged at debug and retried next rotation, so a momentary blip doesn't permanently disable auto-refresh on a webview that actually supports the slot. - v2 response: ``metadata['refresh_interval_s']`` is now clamped to the same [0, REFRESH_INTERVAL_S_MAX] range as the top-level ``refresh_interval_s`` field, so a legacy / hand-edited row can't produce a response where the two halves disagree (and a client reading metadata can't accidentally re-submit the raw bad value). Other pipeline-owned metadata keys pass through unchanged. - ``to_json`` template filter: same sanitisation on ``metadata['refresh_interval_s']`` so the edit modal's ``<input type="number" max="...">`` doesn't land in :invalid state when an existing row carries an out-of-range value — that used to block the operator from saving *any* changes in the modal. Tests: split the version-skew viewer test into the latching (UnknownMethod) and non-latching (transient) branches; assert the v2 GET response for ``metadata.refresh_interval_s`` matches the clamped top-level field. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(review): reset capability flag on browser restart + view_image != - Reset ``_webview_supports_set_reload_interval = True`` at the top of ``load_browser()``: a webview crash + relaunch (or in-place upgrade then process bounce) might bring up a binary that supports the slot, and we don't want to leave auto-refresh disabled for the rest of the viewer's lifetime because the *old* process lacked it. - ``view_image`` was still using ``is not`` for the URL dedup check, same identity-vs-value bug already fixed in ``view_webpage``. Fix for consistency so a JSON-reconstructed URL doesn't bypass the short-circuit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(viewer): clamp refresh_interval_s upper bound in asset_loop A legacy / hand-edited DB row with a huge ``metadata.refresh_interval_s`` would previously pass through asset_loop's ``int(...)`` unchanged and hit the D-Bus marshalling layer. The C++ webview already clamps defensively, but doing it here too saves the round-trip and uses the same shared ``REFRESH_INTERVAL_S_MAX`` constant the v2 serializer and page-form handler enforce. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(refresh-interval): extract clamp_refresh_interval helper CI was unhappy on two fronts: - ruff format check: I'd run ``ruff check`` (lint) but not ``ruff format --check`` after the round-7 edits, so two files landed unformatted. Now reformatted. - SonarCloud: 3.4% duplication on new code (cap is 3%). The clamp pattern (``int(value)`` with try/except + ``max(0, min(_, MAX))``) was duplicated across 4 read sites: v2 serializer, edit-modal ``to_json`` filter, viewer ``asset_loop``, and the page-form handler. Lift it into a single ``clamp_refresh_interval`` helper next to the model constant so all readers funnel through one implementation. No behaviour change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(viewer): import clamp_refresh_interval after django.setup() Importing ``anthias_server.app.models`` at module top — before the explicit ``django.setup()`` call later in the file — can raise ``AppRegistryNotReady`` during a fresh ``python -m anthias_viewer`` startup, because ``Asset(models.Model)``'s class body runs at import time and needs the app registry. Move the helper import into the existing post-setup block, alongside the other Django-aware imports. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(ci): mypy ``Any`` arg + parametrise duplicate tests for sonar - ``clamp_refresh_interval`` was typed ``value: object`` with a ``# type: ignore[arg-type]`` band-aid on the ``int(value)`` line. mypy started rejecting both the ignore (unused) and the call (object isn't accepted by ``int()``). Switch to ``value: Any`` — the function is the catch-all for unknown JSON the column might carry, so ``Any`` is the honest annotation. - SonarCloud was flagging 3.4% duplication on new code (cap 3%) on near-identical PATCH-rejection tests in test_assets.py and the two latches-off / does-not-latch viewer tests. Parametrise both pairs so the body lives once. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
286 lines
21 KiB
HTML
286 lines
21 KiB
HTML
{{ define "main" }}
|
|
<header class="bg-brand-dark py-16 md:py-20 px-6 md:px-12 lg:px-20">
|
|
<div class="max-w-7xl mx-auto">
|
|
<h1 class="text-white text-4xl md:text-5xl font-extrabold tracking-tight">Features</h1>
|
|
<p class="text-white/60 text-lg mt-4 max-w-xl">Everything Anthias does, in plain language — what you can show, when it plays, and how you manage it all.</p>
|
|
</div>
|
|
</header>
|
|
|
|
<section class="bg-white py-16 lg:py-24 px-6 md:px-12 lg:px-20">
|
|
<div class="max-w-7xl mx-auto">
|
|
<h2 class="text-2xl font-bold">What you can show</h2>
|
|
<p class="text-zinc-500 mt-2 max-w-xl">Photos, videos, web pages, YouTube, live streams — if it goes on a screen, Anthias plays it.</p>
|
|
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6 mt-8">
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-yellow/20 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-dark" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="12" rx="2"/><path d="M7 20h10M9 16v4M15 16v4"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Anything that goes on a screen</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Photos, videos, web pages, and live video feeds, all in one playlist. Drag a file in or paste a link — that's the whole workflow.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-purple/10 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-purple" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><rect x="6" y="2" width="12" height="20" rx="2"/><path d="M11 18h2"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Phone photos just work</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">iPhone photos, screenshots, and pictures straight off a camera all upload and play without anyone having to convert them first.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-yellow/20 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-dark" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M4 5h16v14H4z"/><path d="M9 9l6 3-6 3z" fill="currentColor"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Uploads never interrupt the screen</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">If a file isn't quite right for your hardware, Anthias quietly prepares it in the background while whatever's already on screen keeps playing.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-purple/10 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-purple" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M10 8l6 4-6 4z" fill="currentColor"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">YouTube without ads or buffering</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Paste a YouTube link. Anthias downloads the video and plays it locally, so your screen never buffers and never shows ads or recommended videos.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-yellow/20 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-dark" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2c2.5 3 4 6.5 4 10s-1.5 7-4 10c-2.5-3-4-6.5-4-10s1.5-7 4-10z"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Live web pages and dashboards</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Point Anthias at any web page — a status board, a weather widget, a live feed, an internal report — and set an auto-refresh interval so the page reloads on its own and stays current.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-purple/10 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-purple" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Sharp full-HD picture and sound</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">1080p output with smooth, hardware-accelerated video. Sound goes out through HDMI or the headphone jack — your choice.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="bg-bg-light py-16 lg:py-24 px-6 md:px-12 lg:px-20">
|
|
<div class="max-w-7xl mx-auto">
|
|
<h2 class="text-2xl font-bold">When things play</h2>
|
|
<p class="text-zinc-500 mt-2 max-w-xl">Schedule by date, day of the week, or time of day. Anthias takes care of switching things on and off for you.</p>
|
|
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6 mt-8">
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-yellow/20 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-dark" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 10h18M8 3v4M16 3v4"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Schedule by date range</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Set a start and end date so an asset appears for a campaign and disappears on its own when it's over — no reminders, no manual cleanup.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-purple/10 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-purple" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M4 7h16M4 12h16M4 17h10"/><circle cx="6" cy="7" r="1" fill="currentColor"/><circle cx="10" cy="7" r="1" fill="currentColor"/><circle cx="6" cy="12" r="1" fill="currentColor"/><circle cx="14" cy="12" r="1" fill="currentColor"/><circle cx="6" cy="17" r="1" fill="currentColor"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Pick the days of the week</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Run one playlist on weekdays, another on weekends, or something special only on Fridays. Each item picks its own days.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-yellow/20 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-dark" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Pick the time of day</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Show "we're open" content from 9 to 5, then switch to something else overnight. Schedules that cross midnight work too.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-purple/10 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-purple" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M12 7v5l3 2"/><circle cx="12" cy="12" r="9"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Set how long each item plays</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Tell each photo or web page exactly how long to stay on screen. Videos figure out their own length automatically.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-yellow/20 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-dark" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M4 6h16M4 10h16M4 14h10M4 18h7"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Drag to reorder, or shuffle</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Arrange your playlist by dragging items into place, or turn on shuffle to mix things up on every loop.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-purple/10 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-purple" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M5 4l8 8-8 8M14 4v16"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Skip ahead, skip back, pause an item</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Jump forward, jump back, or temporarily turn an item off without deleting it — all from the dashboard.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="bg-white py-16 lg:py-24 px-6 md:px-12 lg:px-20">
|
|
<div class="max-w-7xl mx-auto">
|
|
<h2 class="text-2xl font-bold">Run it from your browser</h2>
|
|
<p class="text-zinc-500 mt-2 max-w-xl">A clean dashboard for managing your screen, with a clear view of how the device is doing.</p>
|
|
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6 mt-8">
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-yellow/20 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-dark" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2c2.5 3 4 6.5 4 10s-1.5 7-4 10c-2.5-3-4-6.5-4-10s1.5-7 4-10z"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">No app to install</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Open the dashboard from your laptop, phone, or tablet. There's no cloud account — Anthias runs on the device itself, on your own network.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-purple/10 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-purple" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><circle cx="11" cy="11" r="6"/><path d="M21 21l-5-5"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Preview before you publish</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Click any photo, video, or web page to see exactly what your screen will show, right inside the dashboard.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-yellow/20 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-dark" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Know when your screen is dark</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Anthias can tell whether the connected TV is actually powered on, so you can spot a dark display at a glance instead of walking over to check.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-purple/10 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-purple" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M13 10V3L4 14h7v7l9-11h-7z"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">System info at a glance</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">See how long the device has been running, how much storage and memory is in use, the software version, and the device's address on your network.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-yellow/20 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-dark" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M12 4v8M12 16h.01"/><circle cx="12" cy="12" r="10"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Tells you when there's an update</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">When a newer version of Anthias is released, the dashboard quietly says so. No mailing lists, no checking the website.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-purple/10 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-purple" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M12 2v10"/><path d="M5 6a8 8 0 1 0 14 0"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Restart and shut down remotely</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Reboot or power off the player from the dashboard, without walking over to the screen. Useful when your displays are scattered around a building.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="bg-bg-light py-16 lg:py-24 px-6 md:px-12 lg:px-20">
|
|
<div class="max-w-7xl mx-auto">
|
|
<h2 class="text-2xl font-bold">First-boot and access</h2>
|
|
<p class="text-zinc-500 mt-2 max-w-xl">Set up a new screen in minutes, then lock it down to whoever should have the keys.</p>
|
|
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6 mt-8">
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-yellow/20 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-dark" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><path d="M14 14h3v3h-3zM18 14h3M14 18h3v3h-3zM18 18h3v3"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Onboarding right on the screen</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">On first boot, your TV shows the device's network address and a QR code. Scan it with your phone and you land straight on the dashboard.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-purple/10 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-purple" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Optional password protection</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Turn on a username and password so only the people you trust can change what's playing. Off by default for quick setup, on whenever you want it.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-yellow/20 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-dark" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="M9 12l2 2 4-4"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Easy HTTPS encryption</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Encrypt the dashboard with one command. Pick a self-signed certificate for a private setup, a free auto-renewing one for your own domain, or bring your own certificate.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="bg-white py-16 lg:py-24 px-6 md:px-12 lg:px-20">
|
|
<div class="max-w-7xl mx-auto">
|
|
<h2 class="text-2xl font-bold">Backups and integrations</h2>
|
|
<p class="text-zinc-500 mt-2 max-w-xl">Move things around, plug Anthias into your tools, or manage many screens at once.</p>
|
|
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6 mt-8">
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-yellow/20 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-dark" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M4 7V4h16v3M9 20h6M12 4v16"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Backup and restore in one file</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Download a single file with your settings and asset list. Upload it later to put everything back, or move it to a brand-new device.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-purple/10 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-purple" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M16 18l2-2-2-2M8 6L6 8l2 2"/><path d="M14.5 4l-5 16"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Plays well with your tools</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Push content and control playback from your own scripts. The programmable interface is fully documented and stays compatible with older integrations.</p>
|
|
</div>
|
|
|
|
<div class="feature-card">
|
|
<div class="w-10 h-10 rounded-lg bg-brand-yellow/20 flex items-center justify-center mb-4">
|
|
<svg class="w-5 h-5 text-brand-dark" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 003 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0021 16z"/><path d="M3.3 7L12 12l8.7-5M12 22V12"/></svg>
|
|
</div>
|
|
<h3 class="text-lg font-bold">Manage many screens with Balena</h3>
|
|
<p class="text-zinc-500 mt-2 text-sm leading-relaxed">Deploy and update Anthias across a fleet of devices through Balena, with over-the-air updates handled for you.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="bg-bg-light py-16 lg:py-24 px-6 md:px-12 lg:px-20">
|
|
<div class="max-w-7xl mx-auto">
|
|
<h2 class="text-2xl font-bold">Supported hardware</h2>
|
|
<p class="text-zinc-500 mt-2 max-w-xl">Anthias runs on Raspberry Pi single-board computers and 64-bit x86 PCs.</p>
|
|
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4 mt-8">
|
|
<div class="bg-white rounded-lg p-4 text-center">
|
|
<p class="font-bold text-sm">Pi 5</p>
|
|
<p class="text-zinc-500 text-xs mt-1">64-bit</p>
|
|
</div>
|
|
<div class="bg-white rounded-lg p-4 text-center">
|
|
<p class="font-bold text-sm">Pi 4</p>
|
|
<p class="text-zinc-500 text-xs mt-1">64-bit</p>
|
|
</div>
|
|
<div class="bg-white rounded-lg p-4 text-center">
|
|
<p class="font-bold text-sm">Pi 3 B+</p>
|
|
<p class="text-zinc-500 text-xs mt-1">64-bit</p>
|
|
</div>
|
|
<div class="bg-white rounded-lg p-4 text-center">
|
|
<p class="font-bold text-sm">Pi 3 B</p>
|
|
<p class="text-zinc-500 text-xs mt-1">64-bit</p>
|
|
</div>
|
|
<div class="bg-white rounded-lg p-4 text-center">
|
|
<p class="font-bold text-sm">Pi 2 B</p>
|
|
<p class="text-zinc-500 text-xs mt-1">32-bit</p>
|
|
</div>
|
|
<div class="bg-white rounded-lg p-4 text-center">
|
|
<p class="font-bold text-sm">x86 PC</p>
|
|
<p class="text-zinc-500 text-xs mt-1">64-bit</p>
|
|
</div>
|
|
</div>
|
|
<p class="text-zinc-400 text-xs mt-4">Pi 2 and Pi 3 are in maintenance mode. We recommend Pi 4 or later for new installations.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="bg-brand-dark py-16 lg:py-24 px-6 md:px-12 lg:px-20">
|
|
<div class="max-w-7xl mx-auto text-center">
|
|
<h2 class="text-white text-3xl lg:text-4xl font-extrabold tracking-tight">Ready to try Anthias?</h2>
|
|
<p class="text-white/50 mt-4 text-lg max-w-lg mx-auto">Free, open source, and yours to run on any supported device.</p>
|
|
<div class="flex flex-wrap justify-center gap-4 mt-8">
|
|
<a class="btn-primary" href="/get-started/">Get Started</a>
|
|
<a class="btn-secondary" href="https://github.com/Screenly/Anthias" target="_blank" rel="noopener">View on GitHub</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
{{ end }}
|