Skip to content

Give Live TV passes a front door: /iptv, and the pitch where a reader has no line - #210

Merged
ralyodio merged 1 commit into
masterfrom
iptv-front-door
Sep 6, 2026
Merged

Give Live TV passes a front door: /iptv, and the pitch where a reader has no line#210
ralyodio merged 1 commit into
masterfrom
iptv-front-door

Conversation

@ralyodio

@ralyodio ralyodio commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Why

The argontv line has been for sale since January and the only way to find it was the IPTV tab inside account settings. The Live TV page linked to /account, which opens on the Account tab, so even that link landed a click short. /pricing never mentioned it. tipoffwatch sells its live pass from a page of its own and pitches it on the event page to a reader with no line; this does the same here.

What

  • /iptv, the page that sells a pass and reports on the one held. Readable signed out like /pricing. Every price comes from getAllPackagePrices, the same table the checkout charges, so the page can never advertise one number and the account take another. The four real terms only; the test packages stay off sales surfaces.
  • Buying stays on the account's IPTV tab, where the crypto picker and the CoinPay handoff already live. /iptv chooses the term and sends the reader to /account?tab=iptv&package=<key>, through /login?redirect= when signed out, and the choice survives the round trip. /account now honours ?tab= and ?package=, which it never did.
  • IptvOfferCard, one component for the pitch: the hero on /iptv, a compact card on Live TV for a signed-in reader with no playlist at all (and nowhere for somebody who already has channels), and a section on /pricing between the plans and the payment methods.

Not touched, and worth knowing before this ships

The reseller call itself. The stored IPTV_ARGON_API_KEY is refused by distributors.argontv.nl (Unauthorized on /api/v1/templates with every auth shape I tried), and prod has no IPTV_ARGON_TEMPLATE_ID, so today a purchase would settle and then fail to provision a line. Both need fixing in the argontv reseller dashboard and Doppler before this page is worth promoting. The page is honest either way: it sells nothing itself.

Tests

src/app/iptv/page.test.tsx: the four terms and prices, every button's destination, the signed-out login round trip with the term kept, an unknown ?package= ignored, a held pass reported, and no API call when signed out. Pre-commit ran the full suite green; tsc --noEmit clean; no lint errors in the new files.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SKAohrRkqLKVQL2cGCAkR5

… has no line

The argontv line has been for sale since January, and the only way to
find it was the IPTV tab inside account settings. The Live TV page linked
to /account, which opens on the Account tab, so even the one link there
landed a click short. Nothing on /pricing mentioned it.

/iptv is the page that sells a pass and reports on the one held, readable
signed out the way /pricing is. Every price on it comes from the same
table the checkout charges, so the page can never advertise one number
and the account take another. Buying still happens on the account's IPTV
tab, where the crypto picker and the CoinPay handoff already live; /iptv
chooses the term and sends the reader there with it preselected, through
login if need be, and the choice survives the round trip.

The same card is pitched on Live TV to a signed-in reader with no playlist
at all, and nowhere to somebody who already has channels, which is the
rule tipoffwatch applies on its event page. /pricing carries it between
the plans and the payment methods. /account now honours ?tab= and
?package=, which it never did.

Not touched: the reseller call itself. The stored argontv key is refused
by distributors.argontv.nl and prod has no IPTV_ARGON_TEMPLATE_ID, so a
purchase would pay and then fail to provision until both are fixed in the
reseller dashboard and Doppler.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKAohrRkqLKVQL2cGCAkR5
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

ThreatCrush Security Scan

99 finding(s)

HIGH/CRITICAL: 11 | MEDIUM: 29 | LOW: 59

Severity Rule Location
HIGH secret-private-key src/app/settings/seedbox-section.tsx:412
HIGH secret-generic-api-key docs/incidents/2026-05-okshanaby-supply-chain.md:18
HIGH tls-verification-disabled src/app/api/iptv-proxy/route.ts:38
HIGH tls-verification-disabled src/app/api/iptv/channels/route.ts:35
HIGH tls-verification-disabled src/app/api/iptv/playlists/[id]/route.ts:73
HIGH tls-verification-disabled src/app/api/iptv/playlists/route.ts:64
HIGH js-cors-origin-reflected src/app/api/public/shares/[slug]/checkout/route.ts:40
HIGH js-cors-origin-reflected src/app/api/public/vod/[slug]/checkout/route.ts:34
HIGH tls-verification-disabled src/lib/iptv/shares/upstream.ts:37
HIGH tls-verification-disabled workers/iptv-cache/epg-fetcher.ts:25
HIGH tls-verification-disabled workers/iptv-cache/playlist-fetcher.ts:62
MEDIUM secret-jwt .github/workflows/ci.yml:120
MEDIUM secret-jwt .github/workflows/ci.yml:121
MEDIUM secret-jwt .github/workflows/ci.yml:123
MEDIUM secret-jwt .github/workflows/ci.yml:162
MEDIUM secret-jwt .github/workflows/ci.yml:164
MEDIUM secret-jwt docs/tunein (2).py:9
MEDIUM secret-jwt docs/tunein.py:9
MEDIUM sh-remote-script-execution scripts/setup-server.sh:182
MEDIUM sh-remote-script-execution scripts/setup-server.sh:419
MEDIUM sh-remote-script-execution scripts/setup-server.sh:428
MEDIUM sh-unquoted-expansion-destructive scripts/setup-server.sh:1073
MEDIUM sh-unquoted-expansion-destructive scripts/setup-server.sh:1083
MEDIUM js-unescaped-html-sink src/app/api/player/route.ts:110
MEDIUM js-unescaped-html-sink src/app/api/player/route.ts:249
MEDIUM js-unescaped-html-sink src/app/blog/[slug]/page.tsx:40
MEDIUM js-unescaped-html-sink src/app/blog/[slug]/page.tsx:66
MEDIUM js-unescaped-html-sink src/app/email/email-content.tsx:566
MEDIUM js-open-redirect src/app/login/page.tsx:50
MEDIUM js-open-redirect src/app/pricing/page.tsx:162
MEDIUM js-open-redirect src/app/rent/[slug]/rent-client.tsx:170
MEDIUM js-unescaped-html-sink src/app/rss/rss-content.tsx:615
MEDIUM js-open-redirect src/app/vod/[slug]/vod-client.tsx:134
MEDIUM js-open-redirect src/app/watch/[slug]/watch-client.tsx:129
MEDIUM js-unescaped-html-sink src/app/youtube/youtube-content.tsx:546
MEDIUM js-open-redirect src/components/account/iptv-subscription-section.tsx:135
MEDIUM js-open-redirect src/components/account/iptv-subscription-section.tsx:167
MEDIUM js-unescaped-html-sink src/components/news/news-section.tsx:361
MEDIUM js-unescaped-html-sink src/components/news/news-section.tsx:734
MEDIUM redos-nested-quantifier src/lib/metadata-enrichment/metadata-enrichment.ts:317
LOW tls-verification-disabled docs/tunein (2).py:34
LOW tls-verification-disabled docs/tunein (2).py:37
LOW py-xpath-injection docs/tunein (2).py:37
LOW tls-verification-disabled docs/tunein (2).py:47
LOW py-xpath-injection docs/tunein (2).py:47
LOW tls-verification-disabled docs/tunein.py:34
LOW tls-verification-disabled docs/tunein.py:37
LOW py-xpath-injection docs/tunein.py:37
LOW tls-verification-disabled docs/tunein.py:47
LOW py-xpath-injection docs/tunein.py:47

…and 49 more. Full results in the Security tab.

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio merged commit a77a546 into master Sep 6, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant