New guide at /blog/remote-control-guide/: enabling the remote in Settings,
opening it on a phone from the QR code, what each control does and which
list it navigates, a checklist for a page that does not load, and why the
remote must stay on the local network. Eight FAQ entries. The remote-control
feature page now links to it instead of the M3U guide.
Both screenshots are mock-backed. The phone view is the first "browser" shot:
a manifest entry names a loopback URL and a mobile viewport, and the capture
frames it in a separate Chromium page behind the same network and content
guards, with the manifest validator accepting loopback origins only. The
setup saves the remote-control setting so the app's own server answers, then
selects a live channel; the Xtream mock's marketing scenario now serves live
stream URLs from local bytes so that selection never leaves the machine.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Publish "How to Load an M3U Playlist and Add an EPG in IPTVnator": the
three import methods plus drag-and-drop and OS file opening, the
playlist views, refresh and startup auto-update, attaching an XMLTV
guide through Settings or a url-tvg header, the tvg-id / tvg-name /
name matching order with manual mapping, catch-up attributes,
troubleshooting and a seven-question FAQ. The three guides now link to
each other, the download pages point at all three, and llms.txt lists
the new one.
Three guide shots join the manifest: the M3U URL dialog, the Groups
view (reusing open-m3u-groups under the guides group) and the EPG
settings section with a staged source row. A settings shot leaves the
form dirty, which arms the app's close guard and blocked app.close()
indefinitely; the capture now discards unsaved settings before every
action and before teardown, and bounds every locator wait.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Publish "How to Connect a Stalker or Ministra Portal to IPTVnator": the
portal URL shapes discovery accepts, MAC normalization, the optional
serial/device-ID/signature fields and the pinning rules behind the
"generate device IDs" toggle, what endpoint discovery does on Add, the
sections a portal source gets, Account info, and a troubleshooting list
built from the app's own refusal messages, plus a seven-question FAQ.
The guide is cross-linked from the download pages and llms.txt.
Guide screenshots come from the capture script. Shots that walk into a
Stalker portal start the stalker-mock-server and seed its marketing-demo
portal for that run only, so release shots never gain a third source
card. The frame guard allowlists exactly that scenario's MAC and keeps
rejecting every other MAC-shaped string.
To keep the live-TV frame free of third-party images, the fictional live
channel list and the channel-logo SVG renderer move into
@iptvnator/shared/marketing-fixtures; both mocks now serve
/assets/marketing/logo/<slug>.svg, the Stalker marketing-demo scenario
builds its ITV categories, channels and schedule from those fixtures
instead of faker names with picsum logos, and the mock resolves asset
URLs on get_all_channels too, which is the response the app renders
the channel list from.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Publish "How to Add an Xtream Codes Account to IPTVnator" as the first
evergreen guide: what the server URL, username and password are, the
Add playlist flow with the connection test and its four verdicts, the
Auto-detect method for pasted provider messages, what the import syncs,
Account info, refresh, troubleshooting and a seven-question FAQ. The
guide is cross-linked from the three download pages and llms.txt.
Blog posts gain an optional `faq` frontmatter list: BlogPost.astro
renders it as an accordion after the body and emits FAQPage JSON-LD
next to the BlogPosting entry. LinkCards and PostButton keep internal
links in the same tab.
Guide screenshots come from the release capture script: manifest shots
may carry a `group`, `--group guides` captures only those into
apps/website/public/blog/guides/screenshots/, and a release run skips
them. New setup actions open the Add playlist dialog with the mock's
fictional Xtream credentials (connection test shown), the Auto-detect
method with a labeled hand-out, and the Xtream Live TV view. Dialog
helpers and fixture identities move into shared modules so the driver
and the navigation actions cannot import each other cyclically.
tools/testing/website-guides.test.mjs checks the FAQPage schema, the
download-hub link and the shipped screenshots of every guide;
screenshot-guards.test.mjs covers group validation and output routing.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Third slice of the release-notes pipeline (#1256 format+generator, #1257 CI
gate): release screenshots become reproducible and provably mock-only.
The v0.20 capture script was single-use (hard-coded slugs, paths, hero) and
fail-open: a lost IPTVNATOR_E2E_DATA_DIR silently fell back to the user's
real ~/.iptvnator database, `...process.env` leaked ambient TMDB keys and
proxies, nothing gated network access, and no frame content was ever
validated. Each hole leaks real playlists, credentials, or copyrighted
artwork into published screenshots without a single signal.
New pipeline:
- tools/release/screenshots.manifest.json — declarative shots (slug, title,
named setup steps, themes). Adding a feature shot = one manifest entry.
- capture-release-screenshots.ts — orchestrator; output goes to
apps/website/public/blog/<release>/screenshots/<slug>-<theme>.png, release
slug derived from package.json (or --release), --only/--theme filters.
- capture-app-driver.ts / capture-navigation.ts — launch, seeding, theme,
and the named-action vocabulary; actions are order-independent (every
portal action starts from the dashboard).
- screenshot-guards.mjs — the fail-closed policy, pure and unit-tested:
G1 the real database is snapshotted (sha256+mtime) before launch and must
be byte-identical after; the isolated DB must actually exist
G2 the app receives an allowlisted environment, never ...process.env
G3 deny-by-default network gate; known app-level calls (GitHub update
check) are answered by local stubs; any other blocked request fails
the run — a silently-blocked TMDB call would leave a frame that looks
broken rather than unsafe
G4 every frame is scanned before capture: external img/background URLs,
credential-shaped text, MAC addresses, non-localhost m3u8 references
G5 TMDB enrichment asserted disabled via the renderer's IndexedDB
Any violation deletes every frame captured in the run and exits non-zero.
The guards paid for themselves on the first live run: G3 caught the mock
server redirecting stream endpoints to a public demo HLS
(test-streams.mux.dev) — meaning earlier hand-run captures could embed
third-party video frames. The M3U shot now deliberately captures the groups
layout without starting playback.
`.changes` validation now cross-checks `screenshot:` slugs against the
manifest, so a note cannot reference an image the capture run never
produces.
Verified end-to-end: 10/10 shots (5 slugs × dark/light) captured against
dist build + xtream-mock-server, frames visually inspected (fictional
titles/artwork only), guard-violation paths exercised live. 67 unit tests
in release-tools, lint green, script files within the repo size limit.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>