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>
42 lines
1.6 KiB
TypeScript
42 lines
1.6 KiB
TypeScript
import React from 'react'
|
|
import ReactDOM from 'react-dom/client'
|
|
import App from './App'
|
|
|
|
declare global {
|
|
interface Window {
|
|
electron?: {
|
|
createView: (name: string, url: string, imageUrl: string, zoom: number, useProxy: boolean) => void
|
|
confirm: (text: string, funcName: string) => void
|
|
removeView: (name?: string) => void
|
|
hideView: () => void
|
|
showView: (name: string) => void
|
|
adjustView: (expanded: boolean) => void
|
|
on: (channel: string, func: (...args: any[]) => void) => () => void
|
|
getCurrentPage: () => Promise<{ name: string; url: string; imageUrl: string } | null>
|
|
handleAction: (action: string) => void
|
|
setProxy: (host: string, port: string) => void
|
|
expandWithHeader: () => void
|
|
collapseWithHeader: () => void
|
|
backwardPage: () => void
|
|
forwardPage: () => void
|
|
refreshPage: () => void
|
|
readConfig: () => Promise<any>
|
|
writeConfig: (data: any) => void
|
|
searchMovies: (query: string, sites: any[]) => Promise<any[]>
|
|
searchTmdb: (query: string, apiKey: string) => Promise<{ results: any[]; error?: string }>
|
|
discoverTmdb: (params: any) => Promise<{ results: any[]; totalPages: number; error?: string }>
|
|
getPageMeta: () => Promise<{ poster: string; title: string; url: string } | null>
|
|
installUpdate: () => Promise<boolean>
|
|
checkUpdateNow: () => Promise<boolean>
|
|
toggleKiosk: () => Promise<boolean>
|
|
isKiosk: () => Promise<boolean>
|
|
}
|
|
}
|
|
}
|
|
|
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
<React.StrictMode>
|
|
<App />
|
|
</React.StrictMode>
|
|
)
|