Files

Stalker Mock Server

A local mock implementation of the Stalker/Ministra portal API for development and end-to-end testing of IPTVnator. It has two separate test surfaces:

  • the long-running generated catalog server on port 3210;
  • short-lived, stateful replay listeners used by Electron authentication E2E.

Overview

The mock server speaks the same portal.php HTTP protocol as a real Stalker portal. Its scenario, IDs, and catalog structure are seeded from the connecting MAC address. This means:

  • The same MAC address stays consistent between reset/restart events and keeps the same seed-driven structure after regeneration.
  • Ratings, some dates, and current-day EPG are volatile, so regenerated payloads are not byte-for-byte identical.
  • Different MAC addresses have isolated state and seeded catalogs — use predefined scenario MACs for specific test conditions.
  • Data is generated once per MAC on first request and cached until /reset or process restart.

Quick Start

# Start the mock server (port 3210)
nx serve stalker-mock-server

# Or with file watching (auto-restarts on source changes)
nx run stalker-mock-server:serve-with-watch

# Or run both the mock server + Angular dev server in parallel
nx run-many --targets=serve --projects=stalker-mock-server,web

Then in IPTVnator, add a new Stalker portal:

  • Portal URL: http://localhost:3210/portal.php
  • MAC Address: one of the predefined scenarios below (or any MAC for auto-generated data)

Predefined Scenario MAC Addresses

MAC Address Scenario Description
00:1A:79:00:00:01 default 8 categories per type, 40 items each — the balanced go-to for daily dev
00:1A:79:FF:FF:FF large 20 categories, 200 items each — stress-test pagination and virtual scroll
00:1A:79:00:00:02 series-heavy 15 series categories with 6 seasons × 10 episodes — test deep series navigation
00:1A:79:00:00:03 minimal 2 categories, 5 items — edge case testing (empty states, single items)
00:1A:79:00:00:04 is-series 60% of VOD items have is_series=1 — tests the Ministra lazy-season flow
00:1A:79:00:00:05 embedded-series 50% of VOD items have embedded series[] arrays — tests the embedded series flow
00:1A:79:00:00:06 legacy-pagination No get_all_channels support — tests the paginated get_ordered_list crawl fallback for the full ITV channel list
00:1A:79:00:00:07 marketing-demo 35 original poster movies with the newest 20 first — safe for screenshots and marketing
<any other MAC> auto MAC bytes choose the seed for an isolated generated catalog

Configuration

Environment Variable Default Description
PORT 3210 HTTP port the server listens on
NODE_ENV development Node environment

Utility Endpoints

Endpoint Method Description
/health GET Health check — returns { status: "ok" }
/reset POST Clear all in-memory data and favorites (useful between test runs)

API Coverage

All endpoints are served at GET /portal.php?action=<action>&... matching the real Stalker protocol:

Action Description
handshake Returns a mock Bearer token
do_auth Returns a mock user profile
get_categories Category list filtered by type (itv/vod/series)
get_genres Genre list (mirrors categories)
get_ordered_list Paginated content list; if movie_id is present → returns seasons
get_all_channels Complete ITV channel list in one response (type=itv only); excludes censored (adult) genres; disabled in the legacy-pagination scenario
create_link Returns a real public HLS stream URL for playback
favorites Add / remove / get favorites (in-memory, resets on restart)
get_short_epg Current-and-upcoming EPG window for a channel (ch_id, size)
get_epg_info Bulk EPG keyed by channel id for a requested period window

Cover Images

Generated scenarios use Picsum Photos for cover images and logos, so they need an internet connection to display artwork. The marketing-demo scenario instead uses the committed, screenshot-safe poster catalog shared with the Xtream mock. Stalker serves those PNGs itself from /assets/marketing/poster/<slug>.png, so screenshots remain deterministic and offline once the repository is checked out.

Stream URLs

create_link returns real public HLS test streams so video actually plays:

  • https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8
  • https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8
  • https://playertest.longtailvideo.com/adaptive/oceans/oceans.m3u8
  • https://playertest.longtailvideo.com/adaptive/bbbfull/bbbfull.m3u8

The stream chosen for a given item is deterministic based on the item's cmd string.

Using with Playwright E2E Tests

The Playwright config in apps/web-e2e/playwright.config.ts starts the mock server automatically alongside the Angular dev server when running e2e tests. See apps/web-e2e/src/stalker.e2e.ts for example stalker tests.

# Run all e2e tests (starts mock server automatically)
nx e2e web-e2e

# Or run only stalker-specific e2e tests
nx e2e web-e2e --grep "@stalker"

The test suite uses 00:1A:79:00:00:01 (default scenario) for most tests, and calls POST /reset in beforeEach to ensure a clean state between tests.

Stateful Authentication Replay

Authentication, redirects, cookies, response-classifier edge cases, refresh, and custom endpoint layouts use fixtures under fixtures/replay/. These fixtures are not served by the development listener on port 3210.

The Electron replay harness starts a capability-protected loopback control plane, creates one allowlisted fixture run, and receives distinct ephemeral listeners for every named origin. The Electron app receives only synthetic portal inputs. Each run must be finalized for exact request cardinality and terminal state, then disposed in finally.

Validate the complete committed corpus with:

pnpm run stalker:fixtures:validate
pnpm nx test stalker-mock-server
pnpm nx test stalker-fixture-tools

The local HAR converter is only a draft aid:

pnpm run stalker:fixtures:draft -- /absolute/input.har /absolute/output.json

It rejects repository inputs, unsafe files, unknown origins, oversized or deep payloads, and secret-like evidence. Never commit real portal URLs, credentials, account data, catalogs, artwork, or stream links. Review and validate every generated draft before moving it into fixtures/replay/.

EPG Behavior

The mock server generates a 7-day EPG schedule for every ITV channel using 2-hour slots starting at the current UTC day boundary.

  • get_short_epg returns the current program and upcoming items from that schedule, limited by size
  • get_epg_info returns bulk data in the shape { js: { data: Record<channelId, program[]> } }
  • get_epg_info filters the bulk response from the current UTC day start through now + period

Architecture

See docs/architecture/stalker-mock-server.md for full implementation details.

Project Structure

apps/stalker-mock-server/
├── fixtures/replay/                    # Secret-scanned stateful fixtures
├── src/
│   ├── main.ts                         # Generated catalog CLI bootstrap
│   ├── app.ts                          # Import-safe Express app factory
│   └── app/
│       ├── replay/                     # Isolated replay/control-plane runtime
│       ├── scenarios.ts                   # MAC → scenario config mapping
│       ├── data-generator.ts              # Seeded faker data generation
│       ├── data-store.ts                  # Lazy per-MAC in-memory cache
│       ├── routes/
│       │   ├── portal.route.ts            # /portal.php route
│       │   └── dispatch.ts                # Shared Stalker action dispatcher
│       └── handlers/
│           ├── handshake.handler.ts
│           ├── do-auth.handler.ts
│           ├── get-categories.handler.ts
│           ├── get-ordered-list.handler.ts
│           ├── get-seasons.handler.ts
│           ├── create-link.handler.ts
│           ├── favorites.handler.ts
│           ├── get-epg-info.handler.ts
│           ├── get-short-epg.handler.ts
│           └── get-genres.handler.ts
├── project.json
├── tsconfig.json
└── README.md