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>
IPTVnator Website
The website is an Astro static site deployed to GitHub Pages at https://4gray.github.io/iptvnator/.
Blog Comments
Blog posts render Giscus comments from apps/website/src/components/GiscusComments.astro.
Giscus stores comments in GitHub Discussions for 4gray/iptvnator and maps each page to a discussion by pathname, including the GitHub Pages base path such as /iptvnator/blog/why-external-players-help/.
The embed is wired to the dedicated Blog comments discussion category:
- Repository id:
MDEwOlJlcG9zaXRvcnkyMTMxOTQ3Mzg= - Category id:
DIC_kwDODLUX8s4C9eBJ - Mapping:
pathname - Theme:
transparent_dark
If the category is recreated, query the new category id:
gh api graphql \
-f owner=4gray \
-f name=iptvnator \
-f query='query($owner:String!, $name:String!) { repository(owner:$owner, name:$name) { discussionCategories(first:25) { nodes { id name slug isAnswerable } } } }'
Then update data-category-id in GiscusComments.astro.
Moderation happens in GitHub Discussions. Maintainers can hide, delete, lock, or move discussions and comments from the repository Discussions UI.
Download Pages
/download/ plus /download/windows/, /download/macos/ and /download/linux/
are per-OS landing pages (apps/website/src/pages/download/). They exist for
search visibility on "IPTVnator download" style queries and to spare users
the 27-asset GitHub release page; each carries OS-specific install steps,
requirements, an FAQ and SoftwareApplication / FAQPage / BreadcrumbList
structured data. Shared pieces live in src/components/download/ and reuse the
blog components (StepRail, Alert, FaqAccordion, CopyCommand).
Latest-release resolution
Direct asset links need the release version, so src/lib/downloads.ts
resolves it at build time:
GET https://api.github.com/repos/4gray/iptvnator/releases/latest(8 s timeout). The asset list from the published release is authoritative: options whose file is missing are dropped, sizes and the publish date come from the API.deploy-website.ymlpassesGITHUB_TOKENto the build so the call is authenticated.- Fallback: the root
package.jsonversion with the asset naming pattern fromelectron-builder.json. This is deterministic but cannot prove the files exist yet (a version bump lands onmasterbefore the release is published), so a warning is printed. SetWEBSITE_SKIP_RELEASE_FETCH=1to force it for offline or reproducible builds.
Both paths produce the same page structure. Adding an artifact means adding a
DownloadOption (matcher + fallback name) in downloads.ts; the pages and the
hub pick it up. The homepage SoftwareApplication schema reads the same
resolved version.
pnpm nx test website builds the site and runs
tools/testing/website-download-pages.test.mjs, which checks titles,
canonicals, direct asset links, JSON-LD, cross-links and sitemap entries
without depending on a specific version.
Guides
Evergreen how-to posts live in the blog collection next to release notes
(xtream-codes-setup-guide.mdx and stalker-portal-setup-guide.mdx in
apps/website/src/content/blog/).
Two conventions set them apart:
faqfrontmatter. An optional list of{ q, a }entries.BlogPost.astrorenders it as an accordion after the body and emits aFAQPageJSON-LD block next to theBlogPostingone, so the answers can surface as rich results.- Screenshots from the capture script. Guide frames are captured by
pnpm release:screenshots --group guidesintoapps/website/public/blog/guides/screenshots/<slug>-<theme>.png; the shots are declared intools/release/screenshots.manifest.jsonwith"group": "guides"and never appear in a release run.
tools/testing/website-guides.test.mjs (part of pnpm nx test website) checks
each guide for the FAQPage schema, a link to the download hub and the presence
of every referenced screenshot in the build output.