mirror of
https://github.com/Screenly/Anthias.git
synced 2026-06-10 17:18:43 -04:00
* Move website to Hugo * Rewrite in progress * Add Hugo-native API reference page and fix CSS build path Two related changes for the Hugo site: 1. CSS build target: package.json's css:build/css:watch wrote to assets/styles/style.css, but baseof.html uses a plain <link href> that Hugo serves from static/. The merge left a stale 14K static copy alongside the freshly-built 23K asset copy, so pages rendered with most utility classes undefined. Build target is now static/assets/styles/style.css, matching the convention used by every other website asset. 2. Hugo-native API docs at /api/. The OpenAPI spec is loaded from data/openapi.yaml (generated via `manage.py spectacular`) and rendered in layouts/_default/api.html and a recursive schema partial. Endpoints are grouped by tag with anchor jumps, color- coded method badges, params/request/response tables, and inline $ref resolution. Renders all 18 v2 endpoints across 9 tags with the existing Tailwind theme. No third-party JS bundle. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Move documentation under Hugo and redirect old GitHub paths Migrates docs/ markdown into website/content/docs/ rendered with a new docs/ layout (list + single) and Tailwind prose styling. Images and the d2 diagram move to website/static/docs/. Internal links rewritten from /docs/foo.md to /docs/foo/, and GitHub-style alerts pre-converted to bold-labeled blockquotes since the goldmark alert extension is not enabled on this Hugo version. The original docs/*.md files are kept as redirect stubs that point at https://anthias.screenly.io/docs/... so external links into the GitHub docs tree still resolve to a useful page. Root README.md links updated to point at the website URLs. Hugo nav now exposes Docs alongside Features / Get Started / API / FAQ. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Fix factual inaccuracies in migrated docs against the codebase Reviewed all docs against the current source. Concrete fixes: * _index.md: container names use the post-rebrand `anthias-` compose project prefix (e.g. `anthias-anthias-server-1`, `anthias-redis-1`) rather than the legacy `screenly-` form. Replaced `docker-compose logs` with `docker compose logs` and added the optional `anthias- caddy` sidecar to the container table. * developer-documentation.md: fixed leading-letter typo ("unning"), and replaced the old Django test-runner invocation with the pytest commands used by the suite today (`pytest -n auto -m "not integration"` and `pytest -m integration`). * balena-fleet-deployment.md: corrected the supported board list ($BOARD_TYPE) to match `bin/deploy_to_balena.sh --help` (`pi2`, `pi3`, `pi4-64`, `pi5` — no `pi1` or plain `pi4`). Updated registry reference from Docker Hub to GHCR. * migrating-assets-to-screenly.md: `cd ~/screenly` → `cd ~/anthias` (post-rebrand install path). * raspberry-pi5-ssd-install-instructions.md: fixed "Opitions" and "uinsg" typos in the boot-order steps. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Polish docs styling: callouts, syntax highlighting, hierarchy Reworks docs prose styling so the migrated pages don't read like default-Hugo-render-output: * Headings: in-body H1/H2 collapse to a section divider style with a top border so they don't compete with the dark page hero. H4-H6 become small uppercase eyebrows. Markdown sources mix #/##/#### inconsistently — the visual scale now compresses gracefully. * Alerts: a render-blockquote hook detects the bold-label preamble produced by our preprocessor (`> **Note**` etc.) and emits a typed `<blockquote class="docs-alert docs-alert-note">` so each kind gets its own colored border + label (note/tip/important/warning/caution). * Syntax highlighting: enable Hugo Chroma with the github style, noClasses=false. Generated chroma.css ships as a static asset and is loaded alongside style.css. `pre`/`<code>` get a light surface that the chroma token colors sit on top of. * Inline code, lists, links, tables, and images all get a small rebalance — bullet color, link underline weight, image shadow, table border-radius — to match the brand-purple theme. * Footer: the Resources / Docs link pointed at the legacy github.com/.../docs/README.md path; now points at /docs/. Added an API Reference link alongside. * Stripped a stray `<br>` in the Pi5 SSD doc that was creating a random gap between a blockquote and its illustrative screenshot. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Make x86/PC docs consistent and more user-friendly The migrated docs used four different forms — "x86", "x86 device", "PC (x86) devices", and "PC (x86 Devices)" — depending on the page. Standardize on **PC (x86)** as the user-facing label (PC is what people search for; x86 stays as the architecture qualifier). Also rewrites x86-installation.md from a flat bullet dump into a clearer five-step walkthrough — what you need, download, flash, install Debian, prep the system, run the installer — and crosslinks the right anchor in installation-options.md so PC users can hand off to the scripted install without scrolling. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Expand FAQ with forum-driven questions and refactor to data file The FAQ had six entries that didn't reflect what people actually ask on forums.screenly.io. Reviewed the all-time top topics and added the ones that show up over and over: portrait rotation, YouTube playback, Wi-Fi setup, static IP assignment, audio output, resolution / 4K, black-screen troubleshooting, transitions, asset storage / backup, SSH, HTTPS pointer, commercial-use clarity, getting logs, and a link to the API reference. Refactored the layout so it reads from data/faq.yaml grouped by section (About, Installation & updates, Display & playback, Operations) and renders each answer through markdownify. This makes adding new entries a one-paragraph YAML edit instead of duplicating ~15 lines of accordion markup. Answers reuse the .docs-prose styling so code, links, lists, and inline pre snippets all match the docs pages. Also tightened the "Accessing the REST API" section in /docs/ to point at the new /api/ page first, with the live ReDoc URL on the device as a secondary callout. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Correct rotation FAQ — Anthias renders via linuxfb + DRM, no Wayland Verified in code: docker/Dockerfile.viewer.j2 sets QT_QPA_PLATFORM=linuxfb, webview/build_qt{5,6}.sh both pass -skip wayland to the Qt build, and viewer/media_player.py invokes mpv with --vo=drm. There is no Wayland compositor in the runtime stack on any board. Replaced the previous "Pi 5 with Wayland uses a different stack" hand-wave with the actual fallback: if /boot/firmware/config.txt's display_rotate=N doesn't stick on a Pi 5 / KMS pipeline, append video=HDMI-A-1:...,rotate=N to /boot/firmware/cmdline.txt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Tighten three FAQ answers after a code-driven validation pass * SSH: previous answer claimed SSH was on by default for both the Anthias disk image and the scripted install. Anthias's installer doesn't touch sshd at all, so the answer now distinguishes between the prebuilt images (SSH on) and a self-flashed Raspberry Pi OS Lite (SSH must be pre-enabled). * Audio output: static/src/components/settings/audio-output.tsx hides the 3.5mm option on Pi 5 because the hardware lacks the jack. Call that out so Pi 5 users don't go looking for a missing dropdown item. * Black screen: replaced the `xset dpms force on` suggestion. Anthias has no X server on any board (Qt runs on linuxfb, mpv on --vo=drm), so xset can't toggle DPMS. Pointed users at re-seating HDMI or checking the TV's input as a more grounded recovery. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Correct features-page claim — Anthias detects display state, can't toggle it The "Display power control" card promised programmatic on/off toggling of the connected screen for energy savings. That isn't a real feature. lib/diagnostics.py only calls libcec's tv.is_on() to *query* the TV's power state — there's no power-on / standby command path anywhere in the codebase. The result surfaces read-only as display_power on the System Info page (static/src/components/ system-info.tsx). Replaced the card with what's actually shipping: HDMI-CEC display state *detection*, visible on the System Info page. Verified the rest of the page against code while I was in there. Accurate as written: image/video/webpage assets (Qt webview + mpv), scheduling (start_date/end_date/duration on the asset model), drag- drop playlists (@dnd-kit/sortable), shuffle (settings.shufflePlaylist), 1080p output (mpv pinned to 1920x1080@60 on pi4-64/pi5 in viewer/media_player.py), real-time WebSocket sync (Django Channels + Redis pub/sub), REST API (drf-spectacular), four-container compose topology, backup/restore, optional basic auth (lib/auth.py BasicAuth), System Info page fields (loadavg/free_space/uptime/anthias_version), and the supported hardware list (matches ansible/site.yml's device_type assertion). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Punchier homepage tagline: "Free digital signage for everyone." Replaces "Open source digital signage for any screen" with a shorter, benefit-led headline. The new line breaks naturally across two lines on desktop (free digital signage / for everyone.) and stays single- line on mobile to avoid an awkward orphan. Subtitle is unchanged — it still does the explanatory work (Pi or PC, schedule images/videos/webpages, no subscriptions). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * SEO sweep: per-page meta, FAQPage / TechArticle JSON-LD, robots.txt Two functional gaps in the existing setup: * og:description and twitter:description were hardcoded to a single marketing line on every page, while the per-page <meta name= description> already pulled from front matter. So the Slack/Twitter/ Discord card preview always read the same blurb regardless of which page you shared. Now both the OG and Twitter description reflect the page's own .Params.description. * Page titles drifted: most pages embedded "Anthias" in the title string, but the docs pages were just "Documentation" / "Installation Options" / etc. — fine for the H1, weak for SERPs. Title now appends " | Anthias" only when the page title doesn't already contain the brand, so existing branded titles stay clean and docs pages get a brand suffix automatically. Other tightening: * Added FAQPage structured data on /faq/ generated from data/faq.yaml so Google can surface FAQ rich results. * Added TechArticle structured data on individual /docs/ pages. * og:type now flips to "article" on docs pages. * og:image:alt + twitter:image:alt populated. * theme-color set to the brand purple for mobile browser chrome. * JSON-LD home schema URL now uses site.BaseURL instead of a hardcoded production URL — important for staging / dev parity. * <html lang> reads site.LanguageCode instead of a fixed "en". * Added a real robots.txt that points crawlers at /sitemap.xml (Hugo already generates the sitemap, but a robots.txt makes the pointer explicit and unblocks tooling that looks for it). Replaced placeholder image alt text in the docs ("balena-ss-01", "imager-01", "rpi-eeprom-update", etc.) with descriptive captions — better for screen readers and image-search SEO. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Move site assets into Hugo's expected layout and rename /docs URLs Two related cleanups. ASSETS — site assets were split across website/static/assets/ (the shadowed copy hugo.toml's [[module.mounts]] directed traffic to) and website/assets/ (an unused duplicate). Hugo's own build report showed "Processed images: 0" because nothing actually flowed through Pipes. * Removed the [[module.mounts]] override so Hugo uses default layout: assets/ for Pipes-processable resources, static/ for served-as-is files. * Used `git mv` to record the docs/ image and stylesheet renames as history-preserving moves rather than delete+add diffs. * Removed the duplicate website/static/assets/images/ directory — files already lived in website/assets/images/. * Bun's css:build/css:watch now write to assets/styles/style.css so Tailwind output flows through Hugo Pipes. * baseof.html loads style.css and chroma.css via resources.Get + fingerprint, with SRI integrity attributes. Each deploy produces a fresh content-hashed URL (/styles/style.<hash>.css), so the browser cache invalidates correctly without manual cache-busting. * Logos, social icons, hero raster (overview*.png), favicon, and plus/minus accordion icons all flow through resources.Get for consistent asset handling. * Added layouts/_default/_markup/render-image.html so markdown image references in /docs are looked up via resources.Get and emitted with loading="lazy" decoding="async". URL RENAMES — the docs URLs were verbatim copies of the original GitHub filenames, which made for noisy URLs like /docs/raspberry-pi5-ssd-install-instructions/. Slugged each page and left aliases for the old paths so Hugo emits a meta-refresh redirect: /docs/installation-options/ → /docs/install/ /docs/balena-fleet-deployment/ → /docs/balena/ /docs/x86-installation/ → /docs/pc/ /docs/raspberry-pi5-ssd-install-instructions/ → /docs/pi5-ssd/ /docs/migrating-assets-to-screenly/ → /docs/migrate-to-screenly/ /docs/qa-checklist/ → /docs/qa/ /docs/developer-documentation/ → /docs/development/ Cross-doc links inside /docs and the README + repo-root docs/ stub files all point at the new URLs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Fix lint + mypy on raspberry_pi_imager test (carried over from rebase) The test_build_pi_imager_json.py file landed in `88d3881b Move website to Hugo` with two pre-existing CI failures: * ruff format --check: a few helper definitions had a stale line break the formatter wanted to collapse. * mypy: `make_image_metadata(board: str) -> dict` is missing the generic type parameters that the project's mypy config flags as type-arg. Annotated as `dict[str, Any]`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Self-host Plus Jakarta Sans via @fontsource (drop Google Fonts CDN) Removes the third-party Google Fonts <link>. SonarCloud's Web:S5725 hotspot was flagging the link as a resource-integrity (SRI) risk — SRI is impossible against Google Fonts because the served stylesheet rotates per User-Agent and the woff2 URLs change with the font CSS. Self-hosting the same font from npm via @fontsource removes the cross-origin resource entirely. How it's wired: * `bun add -D @fontsource/plus-jakarta-sans` for the font binaries. * `scripts/install-fonts.ts` is a small bun script that, given the installed package, copies woff2 files for latin + latin-ext at weights 400/500/600/700/800 to `static/fonts/` (so Hugo serves them at `/fonts/...`) and emits a combined `assets/fonts/plus-jakarta-sans.css` with the urls rewritten to absolute /fonts/... paths and the woff fallback stripped. * `package.json` adds `fonts:install`, and chains it through `css:build` / `css:watch` so Tailwind always sees the generated CSS up to date. * `main.css` @imports the generated CSS — Tailwind/Lightning CSS inlines the @font-face rules into the final fingerprinted style.<hash>.css. * `.gitignore` excludes `assets/fonts/` and `static/fonts/` since both are deterministically regenerated from node_modules. * `baseof.html` no longer pulls from fonts.googleapis.com. Total payload: 10 woff2 files (~136KB), but each is loaded on-demand by unicode-range — typical English-only visitors fetch ~50KB of fonts, served from same-origin. The second Web:S5725 hotspot (gtag.js from googletagmanager.com) is unchanged in this commit — Google's tag manager script is updated server-side without a stable hash, so SRI cannot apply. That one needs a product call (keep with dismissal, drop GA, or move to a privacy-first SRI-friendly alternative). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Address SonarCloud code-smell findings on the website Cleared the unrelated SonarCloud findings raised on this PR: * `install-fonts.ts`: `fs` and `path` imports use the `node:` prefix (typescript:S7772). The new prefixed form is the bun-recommended one, no behavior change. * `_markup/render-image.html`: rewrote the comment that referenced `<img>` literally — Web:ImgWithoutAltCheck was treating the word inside the Hugo comment block as an actual element with no alt. * `_default/faq.html`: replaced the accordion's `<div role="region">` with a real `<section>` element (Web:S6819). The aria-labelledby binding stays, so the accessible name resolution is identical and the semantics are now native rather than ARIA-emulated. * `assets/styles/chroma.css`: stripped the two stray-semicolon lines left over from the sed pass that emptied the github-style backdrop (css:S1116). The remaining `.chroma { -webkit-text-size-adjust: none }` rule is what's actually load-bearing. * `_default/baseof.html`: - accordion JS now reads `this.dataset.accordion` instead of `this.getAttribute('data-accordion')` (javascript:S7761). - GA bootstrap uses `globalThis.dataLayer` instead of `window.dataLayer` (javascript:S7764). Same semantics in any browser context, no globalThis polyfill needed for our targets. * `layouts/index.html`: dropped the deprecated `scrolling="0"` attribute from the GitHub stars iframe (Web:S1827); replaced with the equivalent `overflow-hidden` Tailwind class. The Web:S5725 SRI hotspot on the gtag.js script (line 162 of baseof.html) is the only remaining finding. Google Tag Manager is versioned server-side without a stable hash, so SRI fundamentally can't apply — that one is being kept and dismissed in the SonarCloud UI. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Address Copilot review + trigger marketing deploy on release publish Copilot review: * api.html: request-body renderer only looked at application/json, so endpoints whose only content type is multipart/form-data (file uploads) or application/x-www-form-urlencoded would render an empty Request body section. Pick application/json first if present, otherwise fall back to the first listed content type, and label the rendered schema with its actual content type. * build_pi_imager_json.py: every requests.get() now sets a 30s timeout and calls raise_for_status() so a slow/rate-limited GitHub API doesn't hang the deploy job and a 4xx/5xx fails fast with a clear message rather than a confusing KeyError on response.json(). * docs/raspberry-pi5-ssd-install-instructions.md: "Other HAT's" → "Other HATs". * docs/qa-checklist.md: dropped the spurious "a" in "Change a the start and end dates". * deploy-website.yaml: jq's has() takes one key, so the validation step `has("name", "description", ...)` was actually a syntax error on every run — rewrote as `all($k; $entry | has($k))` over the required-key list. * layouts/_default/get-started.html: the "Documentation" CTA pointed at the old GitHub markdown file; now links to /docs/ to match the navbar / footer. * website/README.md: rewrote the project-structure tree to match what's actually in the repo (data/, scripts/, layouts/docs/, Goldmark _markup/ hooks etc.) and documented the bun pipeline — `hugo server` alone leaves /fonts/* as 404s because the woff2 files are gitignored and materialized by `bun run fonts:install`. Marketing deploy on release publish: `build-balena-disk-image.yaml` cuts the GitHub release with the *.img.zst artefacts as its final step; until now the marketing site only re-deployed on master push or manual dispatch, so rpi-imager. json on the live site lagged the freshest disk images by however long it took someone to push an unrelated website change. Hooking deploy-website.yaml to `on: release: types: [published]` makes the site rebuild as soon as the release exists, which is exactly when the GitHub API starts surfacing the new assets the JSON generator queries. `prerelease=true` releases are included because that's what build-balena-disk-image.yaml currently flags every release as. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Address second round of Copilot review * installation-options.md: balenaEthcher → balenaEtcher. * balena-fleet-deployment.md: includa → include. * developer-documentation.md: spash screen → splash screen. * qa-checklist.md: enabling **Show splash screen** is supposed to *display* the splash, not hide it — flipped "is not being displayed" → "is being displayed". Also clickin → clicking. * raspberry-pi5-ssd-install-instructions.md: `sudo apt update -y` isn't valid (apt's -y is only for install / upgrade), so the copy-paste step would error. Dropped the `-y` from update; the full-upgrade line keeps it because that's where it actually does something. * deploy-website.yaml: the jq required-keys check was missing `icon` and `website`, which build_pi_imager_json.py's REQUIRED_FIELDS already enforces in the Python tests. Added them so the runtime validation matches the generator's contract. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Address third round of Copilot review * website/.gitignore: `_.log` was a typo from the original Hugo bootstrap — it doesn't match anything. Replaced with the intended `*.log` so log files are actually ignored. * website/package.json: rewrote the `dev` script to capture both child PIDs and trap EXIT/INT/TERM so Ctrl-C (or hugo crashing) takes the Tailwind watcher down with it. Mirrors the pattern in the repo-root package.json's `dev`. * docs/raspberry-pi5-ssd-install-instructions.md: "Early Pi 5's" → "Early Pi 5s" (no apostrophe on plurals). * docs/qa-checklist.md: "make sure that the screen in standby mode" → "make sure that the screen is in standby mode" (missing verb). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Rewrite raspberry_pi_imager tests in pytest style The file was unittest.TestCase classes — pytest discovers and runs those, but the boilerplate doesn't earn its keep. Each test method re-declared `@patch('...requests.get')` and rebuilt the same MagicMock setup, and the per-board cases lived as 5+3+2+2 separate methods that should have been one parametrize each. Reworked as flat module-level functions backed by three fixtures: * `mock_requests_get` — patches the module's `requests.get` and yields the mock so each test sets `return_value` / `side_effect` directly. * `mock_release_assets` — preconfigured to return the canned release asset list, used by the `get_asset_list` cases. * `mock_full_build` — wires up the three call shapes `build_imager_json()` makes (latest, asset list, per-asset json). Per-board cases collapse into `@pytest.mark.parametrize`: get_board_from_url's positive cases, the non-image-returns-None cases, the maintenance-mode boards, and the modern boards. Coverage is the same — 21 collected cases (pytest fans the parametrize out from 12 test methods to 21 ids), all passing in 0.12s. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Fix PR checks and Copilot review items --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
193 B
193 B
Documentation
This page has moved to https://anthias.screenly.io/docs/.
The Anthias documentation now lives at https://anthias.screenly.io/docs/.