ESH-Media v1.0.11 — kiosk media browser for elderly users
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>
This commit is contained in:
40
src/entries/dialog-confirm.tsx
Normal file
40
src/entries/dialog-confirm.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import '../styles/dialogs.css'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
electron?: { handleAction: (action: string) => void }
|
||||
__dialogData?: { text?: string }
|
||||
}
|
||||
}
|
||||
|
||||
const ConfirmDialog = () => {
|
||||
const [visible, setVisible] = useState(false)
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
const text = params.get('text') || window.__dialogData?.text || ''
|
||||
|
||||
useEffect(() => {
|
||||
requestAnimationFrame(() => requestAnimationFrame(() => setVisible(true)))
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) document.body.classList.add('visible')
|
||||
}, [visible])
|
||||
|
||||
return (
|
||||
<div className="card">
|
||||
{text && <div className="msg">{text}</div>}
|
||||
<div className="btns">
|
||||
<button className="btn-yes" onClick={() => window.electron?.handleAction('confirmYes')}>
|
||||
Да
|
||||
</button>
|
||||
<button className="btn-no" onClick={() => window.electron?.handleAction('confirmNo')}>
|
||||
Нет
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(<ConfirmDialog />)
|
||||
Reference in New Issue
Block a user