docs: show xQc in the product overview

Replace the generic README fixture with current public xQc profile and VOD data while keeping the screenshot capture isolated from local application data.
This commit is contained in:
Sucukdeluxe
2026-08-10 19:41:36 +02:00
parent b3c2a8b9fd
commit e601c3f3d5
2 changed files with 43 additions and 26 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 543 KiB

+43 -26
View File
@@ -9,6 +9,14 @@ const {
cleanupE2eEnvironment cleanupE2eEnvironment
} = require('./e2e-test-environment'); } = require('./e2e-test-environment');
async function fetchImageDataUrl(url) {
const response = await fetch(url);
if (!response.ok) throw new Error(`Image request failed with ${response.status}`);
const contentType = response.headers.get('content-type') || 'image/jpeg';
const bytes = Buffer.from(await response.arrayBuffer());
return `data:${contentType};base64,${bytes.toString('base64')}`;
}
async function run() { async function run() {
const environment = createE2eEnvironment('readme-screenshot', { const environment = createE2eEnvironment('readme-screenshot', {
language: 'en', language: 'en',
@@ -19,71 +27,80 @@ async function run() {
let app; let app;
try { try {
const publicImages = await Promise.all([
'https://static-cdn.jtvnw.net/jtv_user_pictures/xqc-profile_image-9298dca608632101-150x150.jpeg',
'https://static-cdn.jtvnw.net/cf_vods/d1m7jfoe9zdc1j/73cded95867be2fe9ed5_xqc_320952179547_1786313143//thumb/thumb0-640x360.jpg',
'https://static-cdn.jtvnw.net/cf_vods/d2vi6trrdongqn/a50a886595e03e3ef6ea_xqc_319796892764_1786132273//thumb/thumb0-640x360.jpg',
'https://static-cdn.jtvnw.net/cf_vods/d2vi6trrdongqn/94030284cfbb93ede7b8_xqc_319780491228_1786042905//thumb/thumb0-640x360.jpg',
'https://static-cdn.jtvnw.net/cf_vods/d1m7jfoe9zdc1j/f7d01c3a73dacdb116b3_xqc_320763288922_1785952851//thumb/thumb0-640x360.jpg',
'https://static-cdn.jtvnw.net/cf_vods/d1m7jfoe9zdc1j/d0086ce0b50cded348bb_xqc_320745551322_1785869163//thumb/thumb0-640x360.jpg',
'https://static-cdn.jtvnw.net/cf_vods/d2vi6trrdongqn/94d9a9b26ecc5891d8a0_xqc_319661776222_1785780125//thumb/thumb0-640x360.jpg'
].map(fetchImageDataUrl));
app = await electron.launch(getElectronLaunchOptions(environment)); app = await electron.launch(getElectronLaunchOptions(environment));
const win = await app.firstWindow(); const win = await app.firstWindow();
await verifyE2eIsolation(app, win, environment); await verifyE2eIsolation(app, win, environment);
await installOfflineFixtures(app); await installOfflineFixtures(app);
await app.evaluate(({ ipcMain }) => { await app.evaluate(({ ipcMain }, images) => {
const image = (label, from, to) => { const image = (label, from, to) => {
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="640" height="360"><defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1"><stop stop-color="${from}"/><stop offset="1" stop-color="${to}"/></linearGradient></defs><rect width="640" height="360" fill="url(#g)"/><circle cx="520" cy="80" r="110" fill="rgba(255,255,255,.09)"/><circle cx="100" cy="320" r="170" fill="rgba(0,0,0,.12)"/><text x="34" y="300" fill="white" font-family="Segoe UI,Arial" font-size="34" font-weight="700">${label}</text></svg>`; const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="640" height="360"><defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1"><stop stop-color="${from}"/><stop offset="1" stop-color="${to}"/></linearGradient></defs><rect width="640" height="360" fill="url(#g)"/><circle cx="520" cy="80" r="110" fill="rgba(255,255,255,.09)"/><circle cx="100" cy="320" r="170" fill="rgba(0,0,0,.12)"/><text x="34" y="300" fill="white" font-family="Segoe UI,Arial" font-size="34" font-weight="700">${label}</text></svg>`;
return `data:image/svg+xml;base64,${Buffer.from(svg).toString('base64')}`; return `data:image/svg+xml;base64,${Buffer.from(svg).toString('base64')}`;
}; };
const vods = [ const vods = [
['Ranked highlights and community games', '5h13m20s', 155331, '#6441a5', '#1f7ae0'], ['🍝LIVE🍝DRAMA🍝NEWS🍝VIDEOS🍝GAMES🍝REACTS🍝VIDEOGAMES🍝FUN🍝COOL🍝THINGS🍝IMPORTANT🍝BROADCAST🍝SESSION🍝WICKED🍝', '2026-08-09T22:05:48Z', '9h3m44s', 627553],
['Late night challenge run', '7h39m0s', 241394, '#172554', '#7c3aed'], ['🦴LIVE🦴DRAMA🦴NEWS🦴VIDEOS🦴IMPORTANT🦴COBBLEMON TOURNAMENT🦴WINNER🦴POV🦴WICKED🦴LETS GO YAY🦴IM HERE🦴', '2026-08-07T19:51:18Z', '5h26m23s', 464926],
['Tournament watch party', '5h59m10s', 183557, '#0f766e', '#2563eb'], ['🤒LIVE🤒DRAMA🤒NEWS🤒COBBLEMON🤒IS LIVE🤒DAY4 IMPORTANT🤒LOCK IN🤒QUICKLY🤒BIG THINGS TODAY🤒DONT SLEEP IN🤒', '2026-08-06T19:01:50Z', '11h49m41s', 878537],
['Creative stream and Q&A', '3h40m3s', 94821, '#7c2d12', '#db2777'], ['👈LIVE👈CLICK👈HERE👈DRAMA👈NEWS👈VIDEOS👈GAMES👈COBBLEMON DAY3👈ALSO👈LONG WALK GAME👈FINISHSING?👈HOPEFULY👈LOCK IN👈', '2026-08-05T18:00:55Z', '12h11m17s', 877336],
['Weekend co-op session', '4h50m0s', 127644, '#1e3a8a', '#0891b2'], ['👨‍🎨LIVE👨‍🎨CLICK👨‍🎨DRAMA👨‍🎨NEWS👨‍🎨GAMES👨‍🎨VIDEOS👨‍🎨IM LATE👨‍🎨BUT COBBLEMON IS BACK👨‍🎨LOCK IN👨‍🎨WOOO👨‍🎨PULL UP👨‍🎨', '2026-08-04T18:46:08Z', '12h17m10s', 868187],
['Best moments from the week', '2h54m23s', 119663, '#581c87', '#be123c'] ['🔮LIVE🔮CLICK🔮DRAMA🔮NEWS🔮VIDEOS🔮CLIPS🔮GAMES🔮VIDEOGAMES🔮THINGS🔮IMPORTANT🔮DAY🔮COBBLEMON SERVER🔮LETS GET IT🔮YIPEE🔮TEAM ROCKET POV', '2026-08-03T18:02:10Z', '10h59m24s', 950330]
].map(([title, duration, viewCount, from, to], index) => ({ ].map(([title, createdAt, duration, viewCount], index) => ({
id: `demo-vod-${index + 1}`, id: ['2841886176', '2839940123', '2839002231', '2838068542', '2837216764', '2836308921'][index],
title, title,
created_at: `2026-08-${String(9 - index).padStart(2, '0')}T18:00:00Z`, created_at: createdAt,
duration, duration,
thumbnail_url: image(`DEMO VOD ${index + 1}`, from, to), thumbnail_url: images[index + 1] || image(`xQc VOD ${index + 1}`, '#6441a5', '#1f7ae0'),
url: `https://www.twitch.tv/videos/demo-${index + 1}`, url: `https://www.twitch.tv/videos/${['2841886176', '2839940123', '2839002231', '2838068542', '2837216764', '2836308921'][index]}`,
view_count: viewCount, view_count: viewCount,
stream_id: `demo-stream-${index + 1}` stream_id: ''
})); }));
ipcMain.removeHandler('get-user-id'); ipcMain.removeHandler('get-user-id');
ipcMain.handle('get-user-id', async () => 'demo-user'); ipcMain.handle('get-user-id', async () => '71092938');
ipcMain.removeHandler('get-vods'); ipcMain.removeHandler('get-vods');
ipcMain.handle('get-vods', async () => vods); ipcMain.handle('get-vods', async () => vods);
ipcMain.removeHandler('get-streamer-profile'); ipcMain.removeHandler('get-streamer-profile');
ipcMain.handle('get-streamer-profile', async () => ({ ipcMain.handle('get-streamer-profile', async () => ({
login: 'demo_channel', login: 'xqc',
displayName: 'DemoChannel', displayName: 'xQc',
avatarUrl: image('TVM', '#7c3aed', '#0ea5e9'), avatarUrl: images[0] || image('xQc', '#7c3aed', '#0ea5e9'),
bannerUrl: '', bannerUrl: '',
description: 'Example profile for the public product screenshot', description: 'THE BEST AT ABSOLUTELY EVERYTHING. THE JUICER. LEADER OF THE JUICERS.',
broadcasterType: 'partner', broadcasterType: 'partner',
followerCount: 1250000, followerCount: 12534104,
vodCount: vods.length, vodCount: vods.length,
lastStreamAt: '2026-08-09T18:00:00Z', lastStreamAt: '2026-08-09T22:05:48Z',
isLive: false, isLive: false,
currentTitle: null, currentTitle: null,
currentGame: null, currentGame: null,
currentStreamPreviewUrl: '', currentStreamPreviewUrl: '',
currentStreamViewers: null, currentStreamViewers: null,
twitchUrl: 'https://www.twitch.tv/demo_channel', twitchUrl: 'https://www.twitch.tv/xqc',
fetchedAt: Date.now() fetchedAt: Date.now()
})); }));
ipcMain.removeHandler('get-streamer-display-names'); ipcMain.removeHandler('get-streamer-display-names');
ipcMain.handle('get-streamer-display-names', async () => ({ demo_channel: 'DemoChannel' })); ipcMain.handle('get-streamer-display-names', async () => ({ xqc: 'xQc' }));
}); }, publicImages);
await win.waitForFunction(() => typeof window.showTab === 'function'); await win.waitForFunction(() => typeof window.showTab === 'function');
await win.setViewportSize({ width: 1600, height: 900 }); await win.setViewportSize({ width: 1600, height: 900 });
await win.evaluate(async () => { await win.evaluate(async () => {
window.changeLanguage('en'); window.changeLanguage('en');
showTab('vods'); showTab('vods');
isConnected = true; isConnected = true;
config.streamers = ['demo_channel']; config.streamers = ['xqc'];
config.streamer_display_names = { demo_channel: 'DemoChannel' }; config.streamer_display_names = { xqc: 'xQc' };
config.sidebar_split_view = true; config.sidebar_split_view = true;
streamerVodCache.clear(); streamerVodCache.clear();
streamerProfileCache.clear(); streamerProfileCache.clear();
await window.hydrateStreamerDisplayNames(); await window.hydrateStreamerDisplayNames();
await selectStreamer('demo_channel'); await selectStreamer('xqc');
}); });
await win.waitForTimeout(700); await win.waitForTimeout(700);
fs.mkdirSync(path.dirname(outputPath), { recursive: true }); fs.mkdirSync(path.dirname(outputPath), { recursive: true });