mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-12 03:56:15 -08:00
* docs: design Linux frame-copy packaging * docs: plan Linux frame-copy packaging * feat(packaging): define Linux frame-copy profiles * fix(packaging): reject inherited profile names * feat(embedded-mpv): validate staged Linux runtime * fix(embedded-mpv): require Linux source packages * fix(embedded-mpv): harden Linux runtime staging * feat(embedded-mpv): build LGPL Linux runtime * fix(embedded-mpv): pin Linux runtime inputs * feat(embedded-mpv): build relocatable Linux helper * fix(embedded-mpv): require bundled Linux runtime * fix(embedded-mpv): make Linux runtime portable * feat(packaging): ship Linux frame-copy artifacts * fix(embedded-mpv): verify Linux helper linkage * fix(packaging): enforce Linux frame-copy isolation * fix(embedded-mpv): pin Linux display data * docs(embedded-mpv): document Linux frame-copy packaging * feat(embedded-mpv): probe Linux frame-copy runtime * test(embedded-mpv): smoke packaged Linux frame-copy * docs(embedded-mpv): clarify Linux system runtime baseline * fix(embedded-mpv): harden Linux runtime capability gate * ci: verify Linux frame-copy packages * test(embedded-mpv): harden packaged Linux smoke * test(embedded-mpv): preserve packaged GL mode * test(packaging): harden Linux package probes * fix(embedded-mpv): enable private Snap shared memory * fix(embedded-mpv): sanitize Linux helper environment * fix(packaging): enforce private Snap memory semantics * fix(packaging): reject ambiguous Snap memory metadata * fix(embedded-mpv): prioritize trusted Snap GL * fix(packaging): reject advanced Snap YAML semantics * fix(packaging): reject arbitrary Snap YAML aliases * feat(packaging): ship Linux runtime license notices * docs(embedded-mpv): document Linux runtime distribution * fix(packaging): parse Snap trailing comments safely * fix(release): gate Snap publish on public source release * fix(packaging): strip VCS metadata from source bundle * docs(packaging): clarify Linux source release gate * test(embedded-mpv): smoke missing bundled libmpv * style(embedded-mpv): format final validation inputs * fix(e2e): satisfy fixture index signature typing * fix(ci): declare fontconfig gperf generator * fix(embedded-mpv): hash runtime cache identities * fix(packaging): harden Linux frame-copy delivery * fix(packaging): tighten runtime delivery gates * fix(ci): decouple Linux runtime matrix * fix(packaging): harden Linux frame-copy delivery * fix(packaging): validate Linux frame-copy runtimes * fix(packaging): scope Snap Electron library checks * feat(packaging): ship Linux frame-copy runtimes * fix(packaging): improve Linux runtime smoke diagnostics * fix(packaging): expose bounded helper probe details * test(packaging): trace Snap EGL probe failures * fix(packaging): prefer core22 ABI in Snap helper * fix(packaging): bound helper probe capture * fix(packaging): harden Linux frame-copy releases * fix(packaging): canonicalize libplacebo submodule identity * fix(packaging): make source archive inspection portable * fix(packaging): harden Snap release verification
215 lines
8.1 KiB
TypeScript
215 lines
8.1 KiB
TypeScript
import { app, BrowserWindow } from 'electron';
|
|
import { getElectronUserDataPath } from '@iptvnator/shared/database';
|
|
import { autoUpdater } from 'electron-updater';
|
|
import fixPath from 'fix-path';
|
|
import App from './app/app';
|
|
import { initDatabase } from './app/database/connection';
|
|
import DatabaseEvents from './app/events/database.events';
|
|
import {
|
|
resetStaleDownloads,
|
|
setMainWindow as setDownloadsMainWindow,
|
|
} from './app/events/database/downloads.events';
|
|
import ElectronEvents from './app/events/electron.events';
|
|
import EmbeddedMpvEvents, {
|
|
shutdownEmbeddedMpv,
|
|
} from './app/events/embedded-mpv.events';
|
|
import EpgEvents from './app/events/epg.events';
|
|
import AppUpdateEvents from './app/events/app-update.events';
|
|
import { shutdownMpvSession } from './app/events/mpv-session.service';
|
|
import PlayerEvents from './app/events/player.events';
|
|
import { shutdownVlcSession } from './app/events/vlc-session.service';
|
|
import PlaylistEvents from './app/events/playlist.events';
|
|
import RemoteControlEvents from './app/events/remote-control.events';
|
|
import SettingsEvents from './app/events/settings.events';
|
|
import SharedEvents from './app/events/shared.events';
|
|
import SquirrelEvents from './app/events/squirrel.events';
|
|
import StalkerEvents from './app/events/stalker.events';
|
|
import { isStartupTraceEnabled, trace } from './app/services/debug-trace';
|
|
import { registerStaticHeaderShims } from './app/services/request-header-overrides.service';
|
|
import { AppUpdateService } from './app/services/app-update.service';
|
|
import { databaseWorkerClient } from './app/services/database-worker-client';
|
|
import WindowEvents from './app/events/window.events';
|
|
import XtreamEvents from './app/events/xtream.events';
|
|
import { environment } from './environments/environment';
|
|
import {
|
|
isFrameCopyRuntimeUsable,
|
|
shouldPromotePersistedFrameCopyOptIn,
|
|
} from './app/services/embedded-mpv-frame-copy-platform.util';
|
|
import { isEmbeddedMpvFeatureEnabled } from './app/services/embedded-mpv-runtime-policy.util';
|
|
import { runEmbeddedMpvRuntimeDiagnosticOrContinue } from './app/services/embedded-mpv-runtime-diagnostic';
|
|
import { EMBEDDED_MPV_FRAME_COPY, store } from './app/services/store.service';
|
|
|
|
app.setName('iptvnator');
|
|
|
|
// Packaged Linux launchers force X11 via the .desktop entry
|
|
// (electron-builder `executableArgs`), but direct binary/AppImage launches
|
|
// from a terminal bypass that entry. Embedded MPV supports X11/XWayland
|
|
// only, and its support probe requires the ozone switch to be present, so
|
|
// mirror the launcher behavior here. Explicit user intent wins: both an
|
|
// --ozone-platform switch and the ELECTRON_OZONE_PLATFORM_HINT env var
|
|
// suppress the fallback.
|
|
if (
|
|
process.platform === 'linux' &&
|
|
!app.commandLine.hasSwitch('ozone-platform') &&
|
|
!process.env.ELECTRON_OZONE_PLATFORM_HINT
|
|
) {
|
|
app.commandLine.appendSwitch('ozone-platform', 'x11');
|
|
}
|
|
|
|
const electronUserDataPath = getElectronUserDataPath();
|
|
|
|
if (electronUserDataPath) {
|
|
app.setPath('userData', electronUserDataPath);
|
|
}
|
|
|
|
// The frame-copy embedded MPV engine must be decided before the main window
|
|
// exists: it relaxes the window sandbox for the preload frame pump, and
|
|
// webPreferences are fixed at window creation. The Settings toggle persists
|
|
// to the main-process config store; an explicitly set env var (including
|
|
// '0') always wins so dev/CI behavior stays scriptable.
|
|
if (
|
|
isEmbeddedMpvFeatureEnabled() &&
|
|
shouldPromotePersistedFrameCopyOptIn(
|
|
store.get(EMBEDDED_MPV_FRAME_COPY, false),
|
|
process.env.IPTVNATOR_ENABLE_EMBEDDED_MPV_FRAME_COPY,
|
|
isFrameCopyRuntimeUsable
|
|
)
|
|
) {
|
|
process.env.IPTVNATOR_ENABLE_EMBEDDED_MPV_FRAME_COPY = '1';
|
|
}
|
|
|
|
let fixPathScheduled = false;
|
|
|
|
/**
|
|
* Update process.env.PATH from the user's interactive login shell so that
|
|
* spawned external players (MPV/VLC) can be resolved by binary name.
|
|
*
|
|
* Runs after window creation + IPC handler registration so the 50-300 ms
|
|
* shell-spawn cost (bash/zsh -ilc env) doesn't block startup. Idempotent:
|
|
* subsequent calls are no-ops.
|
|
*/
|
|
function scheduleDeferredFixPath(): void {
|
|
if (fixPathScheduled || process.platform === 'win32') {
|
|
return;
|
|
}
|
|
|
|
fixPathScheduled = true;
|
|
setImmediate(() => {
|
|
try {
|
|
fixPath();
|
|
if (isStartupTraceEnabled()) {
|
|
trace('startup', 'fix-path:done');
|
|
}
|
|
} catch (error) {
|
|
console.warn('fix-path failed:', error);
|
|
}
|
|
});
|
|
}
|
|
|
|
export default class Main {
|
|
static initialize() {
|
|
if (SquirrelEvents.handleEvents()) {
|
|
// squirrel event handled (except first run event) and app will exit in 1000ms, so don't do anything else
|
|
app.quit();
|
|
}
|
|
}
|
|
|
|
static bootstrapApp() {
|
|
if (isStartupTraceEnabled()) {
|
|
trace('startup', 'bootstrap-app');
|
|
}
|
|
App.main(app, BrowserWindow);
|
|
}
|
|
|
|
static async bootstrapAppEvents() {
|
|
if (isStartupTraceEnabled()) {
|
|
trace('startup', 'bootstrap-events:start');
|
|
}
|
|
|
|
const appUpdateService = new AppUpdateService({
|
|
app,
|
|
appVersion: environment.version,
|
|
getMainWindow: () => App.mainWindow,
|
|
updater: () => autoUpdater,
|
|
});
|
|
AppUpdateEvents.bootstrapAppUpdateEvents(appUpdateService);
|
|
|
|
registerStaticHeaderShims();
|
|
ElectronEvents.bootstrapElectronEvents();
|
|
WindowEvents.bootstrapWindowEvents();
|
|
EmbeddedMpvEvents.bootstrapEmbeddedMpvEvents();
|
|
PlaylistEvents.bootstrapPlaylistEvents();
|
|
SharedEvents.bootstrapSharedEvents();
|
|
PlayerEvents.bootstrapPlayerEvents();
|
|
SettingsEvents.bootstrapSettingsEvents();
|
|
StalkerEvents.bootstrapStalkerEvents();
|
|
XtreamEvents.bootstrapXtreamEvents();
|
|
DatabaseEvents.bootstrapDatabaseEvents();
|
|
EpgEvents.bootstrapEpgEvents();
|
|
RemoteControlEvents.bootstrapRemoteControlEvents();
|
|
|
|
// Set main window for downloads and reset stale downloads
|
|
if (App.mainWindow) {
|
|
setDownloadsMainWindow(App.mainWindow);
|
|
}
|
|
|
|
// Load the renderer only after IPC handlers are registered. On slower
|
|
// Linux CI hosts the renderer can otherwise invoke Electron bridge IPC
|
|
// before the main process has installed handlers.
|
|
await App.loadMainWindow();
|
|
void appUpdateService.checkForUpdatesOnStartup();
|
|
|
|
// Initialize the database after the first renderer load is underway so
|
|
// Linux Electron E2E can observe a BrowserWindow even when SQLite
|
|
// startup or download recovery is slow. IPC handlers call getDatabase()
|
|
// lazily and share the same initialization promise.
|
|
await initDatabase();
|
|
|
|
if (isStartupTraceEnabled()) {
|
|
trace('startup', 'init-database:done');
|
|
}
|
|
|
|
await resetStaleDownloads();
|
|
|
|
if (isStartupTraceEnabled()) {
|
|
trace('startup', 'reset-stale-downloads:done');
|
|
}
|
|
|
|
if (isStartupTraceEnabled()) {
|
|
trace('startup', 'bootstrap-events:done');
|
|
}
|
|
|
|
// Hydrate process.env.PATH from the user's login shell now — after
|
|
// the window has loaded and IPC handlers are live. Fire-and-forget
|
|
// (setImmediate) so it doesn't gate any user-visible work. Worst
|
|
// case: the user clicks an external player within the ~100 ms it
|
|
// takes to complete; the spawn would still find MPV/VLC at any of
|
|
// the well-known paths checked by getDefault*Path before falling
|
|
// back to bare-name PATH lookup.
|
|
scheduleDeferredFixPath();
|
|
}
|
|
}
|
|
|
|
runEmbeddedMpvRuntimeDiagnosticOrContinue(process.argv, () => {
|
|
// handle setup events as quickly as possible
|
|
Main.initialize();
|
|
|
|
// bootstrap app
|
|
Main.bootstrapApp();
|
|
|
|
// Bootstrap app events after Electron app is ready
|
|
app.whenReady().then(async () => {
|
|
if (isStartupTraceEnabled()) {
|
|
trace('startup', 'app.whenReady');
|
|
}
|
|
await Main.bootstrapAppEvents();
|
|
});
|
|
|
|
app.on('before-quit', () => {
|
|
shutdownEmbeddedMpv();
|
|
shutdownMpvSession();
|
|
shutdownVlcSession();
|
|
void databaseWorkerClient.shutdown();
|
|
});
|
|
});
|