mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
New post at /blog/epg-wrong-program-fix/: a table separating the three symptoms (an empty row, a channel showing another station's schedule, and every programme shifted by a fixed amount), how the tvg-id → tvg-name → name lookup chain produces the first two, the manual "Map EPG channel" flow, and the display-only EPG time offset with the sign to use. Seven FAQ entries. The three screenshots are mock-backed. The Xtream mock gains /demo/guide.xml, an XMLTV guide for its marketing live channels whose ids deliberately match no playlist tvg-id, which is what makes the manual mapping worth showing; the capture imports it through the settings, accepting the private-network confirmation a loopback source raises, then right-clicks a channel of the M3U fixture and searches the dialog. The new actions live in capture-navigation-epg-actions.ts, alongside the setup, portal and download modules, and borrow one entry point from each of its two neighbours instead of duplicating their navigation. Also fixes assertMockServerIdentity: it checked both expected categories against get_vod_categories, but "Urban Drama" is a series category, so the reuse path rejected every already-running mock and a capture could only run when the port happened to be free. Each category is now checked against its own endpoint. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
100 lines
3.4 KiB
TypeScript
100 lines
3.4 KiB
TypeScript
/**
|
|
* Named setup actions for capture-release-screenshots.ts — the vocabulary
|
|
* that screenshots.manifest.json steps refer to — plus theme switching and
|
|
* the playlist-id registry the actions navigate with.
|
|
*
|
|
* The actions themselves live in three modules by subject
|
|
* (`capture-navigation-setup-actions.ts`: dialogs, settings, remote
|
|
* control; `capture-navigation-portal-actions.ts`: portal browsing and
|
|
* alternative sources; `capture-navigation-download-actions.ts`: the
|
|
* download manager; `capture-navigation-epg-actions.ts`: the EPG guide
|
|
* import and channel mapping) over the shared page helpers in
|
|
* `capture-navigation-helpers.ts`. This file only dispatches a step name
|
|
* and re-exports the API the seeding driver and the capture script use.
|
|
*/
|
|
|
|
import type { Page } from '@playwright/test';
|
|
|
|
import {
|
|
type CaptureAction,
|
|
discardUnsavedSettings,
|
|
dismissDialogs,
|
|
settleUi,
|
|
} from './capture-navigation-helpers';
|
|
import { DOWNLOAD_ACTIONS } from './capture-navigation-download-actions';
|
|
import { EPG_ACTIONS } from './capture-navigation-epg-actions';
|
|
import { PORTAL_ACTIONS } from './capture-navigation-portal-actions';
|
|
import { SETUP_ACTIONS } from './capture-navigation-setup-actions';
|
|
|
|
export {
|
|
clickDialogOption,
|
|
discardUnsavedSettings,
|
|
openAddPlaylistDialog,
|
|
registerPlaylistId,
|
|
requirePlaylistId,
|
|
settleUi,
|
|
} from './capture-navigation-helpers';
|
|
export type { PlaylistProvider } from './capture-navigation-helpers';
|
|
|
|
const ACTIONS: Readonly<Record<string, CaptureAction>> = {
|
|
...SETUP_ACTIONS,
|
|
...PORTAL_ACTIONS,
|
|
...DOWNLOAD_ACTIONS,
|
|
...EPG_ACTIONS,
|
|
};
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Theme */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
export async function applyTheme(
|
|
page: Page,
|
|
theme: 'dark' | 'light'
|
|
): Promise<void> {
|
|
await runAction(page, 'open-settings', null);
|
|
const testId = theme === 'dark' ? 'DARK_THEME' : 'LIGHT_THEME';
|
|
const themeButton = page.locator(`[data-test-id="${testId}"]`).first();
|
|
|
|
await themeButton.scrollIntoViewIfNeeded();
|
|
await themeButton.click();
|
|
|
|
const saveButton = page.locator('[data-test-id="save-settings"]').first();
|
|
|
|
if (await saveButton.isEnabled()) {
|
|
await saveButton.click();
|
|
await settleUi(page);
|
|
}
|
|
|
|
await page.waitForFunction(
|
|
(expectedTheme) =>
|
|
document.body.classList.contains('dark-theme') ===
|
|
(expectedTheme === 'dark'),
|
|
theme,
|
|
{ timeout: 10_000 }
|
|
);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Named setup actions */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
export async function runAction(
|
|
page: Page,
|
|
action: string,
|
|
param: string | null
|
|
): Promise<void> {
|
|
const run = ACTIONS[action];
|
|
|
|
if (!run) {
|
|
throw new Error(`Unknown setup action: ${action}`);
|
|
}
|
|
|
|
// Manifest steps are order-independent, and some of them end with a modal
|
|
// dialog open or a dirty settings form. Clear whatever the previous step
|
|
// left behind before this one starts navigating: a dialog backdrop
|
|
// swallows every click, and unsaved settings raise a leave prompt.
|
|
await dismissDialogs(page);
|
|
await discardUnsavedSettings(page);
|
|
await run(page, param);
|
|
}
|