Commit graph

5 commits

Author SHA1 Message Date
57585d8ad2 Tell a new viewer what to buy before asking them to fill in a form
Someone with their own accounts had to work out on their own that Amber
needs a paid subscription somewhere before it can find anything, and
which of three services that means. The Zdroje box already turns their
usernames into addon URLs; nothing anywhere told them which usernames to
go and get, or what it would cost.

Six steps as a new #start tab: change the generated password, choose
services, create the accounts and pay, take a free TMDB key, enter it all
in Zdroje, download. Steps 1, 5 and 6 hand off to the tabs that already do
that work. This screen owns no credentials and no crypto on purpose, since
a second encryptor for one blob is how a vault gets corrupted.

The password is step 1, not step 6. Changing it re-keys the vault with a
fresh salt, so every device already signed in holds a stale key until it
authenticates again. Done first, while the vault is empty, there is
nothing to re-encrypt and no paired television to strand.

State is three fields on the user record and nothing more: skipped, chosen
and pwChangedAt. Whether the sources exist is CONFIGS.length and whether
TMDB is set is a field in the decrypted config, so storing those again
would let two answers disagree. pwChangedAt is the one thing that cannot be
derived, because PocketBase records no password-changed timestamp.

Prices and click-paths live in a providers collection, editable in the
admin UI, with priceCheckedAt rendered beside the number so a stale figure
looks stale rather than reading as a promise. Owner supplied the three
signup guides; TorBox Free is called out as unusable because it has no API
access, which is the only way Amber talks to it.

byGo also stops demanding a Czech host. Nothing downstream needed one, and
someone who only wants anime was being told to buy a service they had no
use for.

Verified against PocketBase 0.39.6 from a throwaway data dir with this
repo's real migrations, hooks and page: both migrations applied clean, the
flow opened itself for a user with no sources, a choice persisted as
{"chosen":["prehrajto","torbox"]} and nothing else, guides rendered
numbered with working links, skipping raised the banner and survived a
reload, resuming came back in.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 18:36:55 +02:00
dc4f85fd4f The TV instructions stop naming an app that may not be installed
"Na televizi otevři aplikaci Downloader" was carried over from the old landing page
and never checked. Downloader is a third-party sideloading app people install on Fire
TV sticks; it is not standard on Android TV, and the owner has never seen it on his.
An instruction that points at something absent is worse than no instruction — the
family would simply be stuck.

The browser route is what he actually uses and has confirmed works, so it is the
instruction now: open the TV's browser, go to the site, press a button. The button is
new — telling someone to type a second URL when a link can do it was needless, and
`/tv` stays as the shortcut for anyone who would rather type than click.

Both places said it: the signed-out card and the Stáhnout tab.
2026-08-07 09:33:28 +02:00
5bfc45cd23 The sources form no longer insists on prehraj.to
The addon accepts either host on its own as of stremio_prehrajto 7ef248d, so the
page that mints the URLs stops claiming otherwise. Each host stays all-or-nothing
and at least one must be complete — the same rule /encode enforces, checked here
too so the message arrives in Czech rather than as a 400.
2026-08-07 09:09:56 +02:00
12e7f4103f The unified page becomes the site; retire the two it replaced
index.html was the old landing page with a signup form, and that form can now only
fail — registration is owner-only. A dead button is worse than no button, so the
unified account page takes its place rather than sitting beside it. settings.html
goes too: it is a strict subset of the sources section, and onboarding.html was the
signup wizard.

Verified against the live backend before the swap, signed in as a throwaway account
created the way the owner now creates them (and deleted afterwards — the instance is
back to its five real accounts):

  registration    403 "Only superusers can perform this action", with and without
                  the old invite header
  template route  401 anonymously
  session         survives a full page reload; the password does NOT, so the
                  sources section re-asks for it — the intended split
  prefs           one row, updatedAt distinct from the server cursor, and all 13
                  fields present including the three the page does not render, so
                  the merge did not clobber what the app writes
  sources (BYOC)  the browser reached the addon's /encode cross-origin, minted the
                  prehraj.to token, built TorBox's config locally, encrypted and
                  saved; the stored blob contains no plaintext and carries
                  kdf=pbkdf2-sha256-210000
  downloads       all three platforms resolve to 1.1.6 · clean with a file token

Checked rather than assumed: the Czech URL is stored with /manifest.json (matching
the existing template) and the app strips it on both read and write via
_stripManifest, so minting it that way is correct and not a latent 404.
2026-08-07 02:10:48 +02:00
0b65fd7f49 Family onboarding site: invite-gated signup, template config, /get/tv
Distribution site served by PocketBase itself (pb_public/, same origin):
- Landing (/): create-account CTA, TV sign-in steps, login-gated PC
  downloads via the existing update manifest + file tokens
- Wizard (/onboarding.html): invite code -> account -> named default
  profile -> family template fetched and encrypted IN THE BROWSER under
  the new user's password (PBKDF2-210k + AES-GCM, byte-compatible with
  the app's AddonConfigCrypto - a wizard blob decrypts in Dart, verified)
  -> pushed as their addon_config ciphertext. Adult fields never included.
- /get/tv: public direct download of the latest clean Android APK
  (Downloader-friendly; adult builds stay account-gated)

Backend:
- onboarding_template collection (admin-only, maintained via admin UI)
- AMBER_INVITE_CODE env gates BOTH users creation (X-Amber-Invite header
  or ?invite=) and the template route (per-IP rate limit 10/5min);
  fail-closed when unset. Note: this closes the previously-open in-app
  registration too.
- Dockerfile ships pb_public + --publicDir; compose passes the env var

Contract + Coolify steps (second domain amber.petruzalekr.cz) in
docs/onboarding-contract.md. Verified locally end-to-end against
pocketbase 0.39.6 (real-browser wizard run + Dart decrypt interop).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 18:23:05 +02:00