mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-09 01:16:15 -08:00
95 lines
4.4 KiB
TypeScript
95 lines
4.4 KiB
TypeScript
/** Real UI captures for the 0.23/0.24 feature guides, using local demo media. */
|
|
import { readFileSync } from 'node:fs';
|
|
import path from 'node:path';
|
|
import type { Page } from '@playwright/test';
|
|
import { type CaptureAction, openXtreamSection } from './capture-navigation-helpers';
|
|
import { openM3uGroups } from './capture-navigation-portal-actions';
|
|
import { openSettings } from './capture-navigation-setup-actions';
|
|
|
|
async function openSettingsSection(page: Page, section: string): Promise<void> {
|
|
await openSettings(page);
|
|
await page.locator(`[data-test-id="settings-section-${section}"]`).click();
|
|
await page.locator(`#${section}`).waitFor({ state: 'visible' });
|
|
}
|
|
|
|
async function openUpdateChannel(page: Page): Promise<void> {
|
|
await openSettingsSection(page, 'about');
|
|
await page.locator('[data-test-id="select-update-channel"]').click();
|
|
await page.locator('[data-test-id="update-channel-nightly"]').waitFor();
|
|
}
|
|
|
|
async function openBackup(page: Page): Promise<void> {
|
|
await openSettingsSection(page, 'backup');
|
|
}
|
|
|
|
async function openLibraryWatched(page: Page): Promise<void> {
|
|
await openXtreamSection(page, 'vod', 'Action & Mystery');
|
|
const watched = page.locator('[data-testid="vod-watched-toggle"]');
|
|
await watched.waitFor();
|
|
if ((await watched.getAttribute('aria-label')) === 'Mark as Watched') {
|
|
await watched.click();
|
|
}
|
|
await page.getByRole('button', { name: 'Mark as Unwatched', exact: true }).waitFor();
|
|
}
|
|
|
|
async function openDemoPlayback(page: Page): Promise<void> {
|
|
await openSettingsSection(page, 'playback');
|
|
const player = page.locator('[data-test-id="select-video-player"]');
|
|
if (!(await player.innerText()).includes('HTML5')) {
|
|
await player.click();
|
|
await page.locator('[data-test-id="html5"]').click();
|
|
await page.locator('[data-test-id="save-settings"]').click();
|
|
await page.locator('[data-test-id="save-settings"]').waitFor({ state: 'hidden' });
|
|
}
|
|
// A local generated H.264 slate, never a provider stream. Use MPEG-TS
|
|
// segments so the normal M3U/HLS player path decodes it without overrides.
|
|
const fixture = path.resolve('tools/release/fixtures/guide-demo.mpegts');
|
|
await page.route('**/live/marketing/marketing/*.m3u8', (route) =>
|
|
route.fulfill({
|
|
contentType: 'application/vnd.apple.mpegurl',
|
|
body: '#EXTM3U\n#EXT-X-VERSION:3\n#EXT-X-TARGETDURATION:20\n#EXT-X-MEDIA-SEQUENCE:0\n#EXTINF:20.0,\nhttp://localhost:3211/demo/guide-demo.ts\n#EXT-X-ENDLIST\n',
|
|
})
|
|
);
|
|
await page.route('**/demo/guide-demo.ts', (route) =>
|
|
route.fulfill({ contentType: 'video/mp2t', body: readFileSync(fixture) })
|
|
);
|
|
await openM3uGroups(page);
|
|
await page.locator('[data-test-id="channel-item"]').first().click();
|
|
await page.waitForFunction(() => {
|
|
const video = document.querySelector('video');
|
|
return video && video.readyState >= 2 && video.videoWidth === 1280;
|
|
}, undefined, { timeout: 25_000 });
|
|
// Freeze decoded media, not the interface, for a repeatable illustration.
|
|
await page.locator('video').evaluate((video: HTMLVideoElement) => video.pause());
|
|
await page.locator('video').hover();
|
|
}
|
|
|
|
async function openFullscreenChannels(page: Page): Promise<void> {
|
|
await openDemoPlayback(page);
|
|
await page.getByRole('button', { name: 'Enter fullscreen', exact: true }).click();
|
|
await page.keyboard.press('c');
|
|
await page.locator('[data-test-id="fullscreen-channel-panel"][aria-hidden="false"]').waitFor();
|
|
await page.locator('[data-test-id="m3u-fullscreen-view-all"]').click();
|
|
}
|
|
|
|
async function openSubtitles(page: Page): Promise<void> {
|
|
await openDemoPlayback(page);
|
|
await page.getByRole('button', { name: 'Subtitles', exact: true }).click();
|
|
await page.locator('[data-test-id="player-controls-load-subtitle"]').waitFor();
|
|
}
|
|
|
|
async function openStreamInfo(page: Page): Promise<void> {
|
|
await openDemoPlayback(page);
|
|
await page.locator('[data-test-id="player-controls-stream-info-button"]').click();
|
|
await page.locator('[data-test-id="player-controls-stream-info-panel"]').waitFor();
|
|
}
|
|
|
|
export const FEATURE_ACTIONS: Readonly<Record<string, CaptureAction>> = {
|
|
'open-update-channel': openUpdateChannel,
|
|
'open-backup': openBackup,
|
|
'open-library-watched': openLibraryWatched,
|
|
'open-fullscreen-channels': openFullscreenChannels,
|
|
'open-player-subtitles': openSubtitles,
|
|
'open-stream-info': openStreamInfo,
|
|
};
|