Electron-based kiosk desktop app: large-tile launcher for YouTube, RuTube, movie sites and Google services, designed for low-tech grandparent use. Features: - WebContentsView-per-app tabbed browsing with session persistence - per-app proxy routing (Clash/V2Ray friendly, useProxy flag) - cliqz-electron adblocker with whitelist for OAuth/integrity domains - TMDB-backed movie search across kinogo / hdrezka / filmix - bookmark posters auto-fetched from og:image / JSON-LD - electron-updater wired to Gitea releases API (latest.yml + .blockmap) - cross-domain navigation confirms via custom WebContentsView dialogs - kiosk window with hidden menu, Ctrl+Shift+I devtools shortcut - Trusted Types disabled engine-wide so adblocker scriptlets work on YouTube Google OAuth handling (the hard-won part): Google's anti-abuse JS rejects WebContentsView + custom session settings as "embedded browser". So accounts.google.com opens in a top-level BrowserWindow popup in a dedicated persist:google-login partition that we never call setProxy/setUserAgent on — it inherits Windows system proxy and the default Electron-tagged UA, both of which Google accepts. After login, .google.com/.youtube.com cookies migrate into the parent view's session and the view reloads to pick up the logged-in state. Session restore: only the last-active tab attaches to the window; other tabs load silently in the background and become instantly visible when the user clicks them in the sidebar. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
39 lines
1.2 KiB
JavaScript
39 lines
1.2 KiB
JavaScript
// Waits for Vite dev server, then launches Electron with ELECTRON_RUN_AS_NODE
|
|
// removed from environment (any value of that variable causes Electron to run
|
|
// as plain Node.js instead of a GUI app).
|
|
const { spawn } = require('child_process');
|
|
const http = require('http');
|
|
const electronPath = require('electron');
|
|
|
|
const VITE_URL = 'http://localhost:5173';
|
|
const POLL_INTERVAL = 500;
|
|
const MAX_WAIT_MS = 60000;
|
|
|
|
function waitForVite(url, timeout) {
|
|
return new Promise((resolve, reject) => {
|
|
const deadline = Date.now() + timeout;
|
|
const check = () => {
|
|
http.get(url, (res) => {
|
|
res.resume();
|
|
resolve();
|
|
}).on('error', () => {
|
|
if (Date.now() >= deadline) return reject(new Error('Timed out waiting for ' + url));
|
|
setTimeout(check, POLL_INTERVAL);
|
|
});
|
|
};
|
|
check();
|
|
});
|
|
}
|
|
|
|
console.log('Waiting for Vite at', VITE_URL, '...');
|
|
waitForVite(VITE_URL, MAX_WAIT_MS).then(() => {
|
|
console.log('Vite ready — starting Electron');
|
|
const env = { ...process.env };
|
|
delete env.ELECTRON_RUN_AS_NODE;
|
|
const child = spawn(electronPath, ['.'], { stdio: 'inherit', env });
|
|
child.on('close', code => process.exit(code ?? 0));
|
|
}).catch(err => {
|
|
console.error(err.message);
|
|
process.exit(1);
|
|
});
|