9.5 KiB
Stalker Portal EPG Architecture
This document describes the EPG (Electronic Program Guide) implementation for Stalker/Ministra portal live TV (ITV) streams.
Related architecture docs:
Overview
The Stalker ITV live stream layout displays EPG data in the right panel when a live channel is playing. EPG is fetched per-channel using the Stalker get_short_epg API action, which returns the current program plus the next ~5 upcoming programs. The response is mapped to the shared EpgItem interface and rendered by the reusable EpgViewComponent.
Architecture
┌───────────────────────────────────────────────────────────────────────────┐
│ StalkerLiveStreamLayoutComponent │
│ apps/web/src/app/stalker/stalker-live-stream-layout/ │
│ │
│ ┌──────────────┐ ┌──────────────────────┐ ┌─────────────────────┐ │
│ │ Sidebar │ │ Video Player │ │ EPG Panel │ │
│ │ (channels) │ │ (WebPlayerView) │ │ (EpgViewComponent) │ │
│ │ │ │ │ │ │ │
│ │ click ──────┼────┼──► playChannel() ────┼────┼──► loadEpgFor...() │ │
│ └──────────────┘ └──────────────────────┘ └─────────────────────┘ │
│ │ │ │
└──────────────────────────────┼────────────────────────────┼───────────────┘
│ │
▼ ▼
┌──────────────────────┐ ┌────────────────────────┐
│ StalkerStore │ │ StalkerStore │
│ fetchLinkToPlay() │ │ fetchChannelEpg() │
└──────────┬───────────┘ └────────────┬───────────┘
│ │
▼ ▼
┌──────────────────────────────────────────────────────┐
│ Stalker Portal API │
│ action=create_link action=get_short_epg │
└──────────────────────────────────────────────────────┘
Stalker EPG API
get_short_epg (per-channel)
Request:
GET load.php?type=itv&action=get_short_epg&ch_id={channel_id}&JsHttpRequest=1-xml
Uses standard Stalker auth headers (Bearer token + MAC cookie).
Response:
{
"js": {
"data": [
{
"id": "123",
"ch_id": "45",
"name": "Program Title",
"descr": "Program description",
"time": "2025-01-15 14:00:00",
"time_to": "2025-01-15 14:30:00",
"duration": "1800",
"start_timestamp": "1736949600",
"stop_timestamp": "1736951400",
"t_time": "14:00",
"t_time_to": "14:30"
}
]
}
}
Notes:
- If the channel has no
xmltv_idset on the server, returns an empty array - Response normalization handles both
{ js: { data: [...] } }and{ js: [...] }formats - No backend (Electron IPC) changes needed — the generic
stalker.events.tshandler forwards anyparamsto the portal URL
get_epg_info (bulk — reserved for future use)
GET load.php?type=itv&action=get_epg_info&period={hours}&JsHttpRequest=1-xml
Returns EPG for all channels for a given time period. Currently unused but the enum value StalkerPortalActions.GetEpgInfo is defined for future bulk EPG features.
Data Mapping
Stalker EPG → EpgItem Interface
| Stalker field | EpgItem field |
Notes |
|---|---|---|
id |
id |
Converted to string |
ch_id |
channel_id |
Falls back to passed channelId |
name |
title |
|
descr |
description |
|
time |
start |
Full datetime string |
time_to |
end, stop |
Both set to same value |
start_timestamp |
start_timestamp |
Unix timestamp as string |
stop_timestamp |
stop_timestamp |
Unix timestamp as string |
| (n/a) | epg_id |
Empty string |
| (n/a) | lang |
Empty string |
EpgItem Interface
// libs/shared/interfaces/src/lib/epg-item.interface.ts
interface EpgItem {
id: string;
epg_id: string;
title: string;
lang: string;
start: string;
end: string;
stop: string;
description: string;
channel_id: string;
start_timestamp: string;
stop_timestamp: string;
}
Implementation Details
Key Files
| File | Purpose |
|---|---|
libs/shared/interfaces/src/lib/stalker-portal-actions.enum.ts |
GetShortEpg, GetEpgInfo enum values |
apps/web/src/app/stalker/stalker.store.ts |
fetchChannelEpg() method |
apps/web/src/app/stalker/stalker-live-stream-layout/stalker-live-stream-layout.component.ts |
EPG signals + loadEpgForChannel() |
apps/web/src/app/stalker/stalker-live-stream-layout/stalker-live-stream-layout.component.html |
<app-epg-view> integration |
libs/ui/shared-portals/src/lib/epg-view/epg-view.component.ts |
Shared EPG display component |
StalkerStore.fetchChannelEpg()
Location: apps/web/src/app/stalker/stalker.store.ts (in withMethods)
async fetchChannelEpg(channelId: number | string): Promise<EpgItem[]>
- Sends
get_short_epgrequest withch_idparam - Supports both full Stalker portals (authenticated via
StalkerSessionService) and simple portals (direct IPC) - Returns mapped
EpgItem[]or empty array on failure - No store state mutation — returns data directly to the component
StalkerLiveStreamLayoutComponent EPG Integration
The component manages EPG state locally with signals:
readonly epgItems = signal<EpgItem[]>([]);
readonly isLoadingEpg = signal(false);
Flow:
- User clicks a channel in the sidebar →
playChannel(item) fetchLinkToPlay()gets the stream URL- If using embedded player,
streamUrlis set andloadEpgForChannel(item.id)is called loadEpgForChannel()sets loading state, callsstalkerStore.fetchChannelEpg(), updatesepgItems- Template renders
<app-epg-view [epgItems]="epgItems()">or a loading spinner
EpgViewComponent (shared)
Location: libs/ui/shared-portals/src/lib/epg-view/
Reusable component shared between Stalker and Xtream live stream layouts:
- Input:
epgItems: EpgItem[] - Displays program list with time, title, and info button
- Highlights current program with green progress bar
- Handles empty state (shows "EPG not available" message)
- Info button opens
EpgItemDescriptionComponentdialog with title and description
Current program detection:
isCurrentProgram(item: EpgItem): boolean {
const now = new Date().getTime();
const start = new Date(item.start).getTime();
const stop = new Date(item.stop ?? item.end).getTime();
return now >= start && now <= stop;
}
This works with Stalker's datetime format ("2025-01-15 14:00:00") because new Date() parses it correctly.
Authentication
EPG requests follow the same authentication pattern as all Stalker API calls:
| Portal Type | Auth Method |
|---|---|
Full Stalker (isFullStalkerPortal: true) |
StalkerSessionService.makeAuthenticatedRequest() — handles token refresh and retry on 401 |
| Simple Stalker | Direct IPC via DataService.sendIpcEvent(STALKER_REQUEST, ...) — no auth headers |
Future Enhancements
Bulk EPG in Channel List Sidebar
Use get_epg_info with period=3 to pre-fetch current program titles for all channels when a category is selected:
- Call
get_epg_infoafter category selection - Build a
Map<channelId, currentProgram> - Show current program name below channel title in the sidebar
- Display progress bar per channel item
This is a separate task due to Stalker's lazy-loaded channel pagination model.
EPG Auto-Refresh
Currently EPG is fetched once per channel selection. A future enhancement could add a timer to refresh EPG data periodically (e.g., every 5 minutes) to keep the "current program" indicator accurate during long viewing sessions.