mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-25 15:25:44 +00:00
226 lines
6.3 KiB
TypeScript
226 lines
6.3 KiB
TypeScript
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { app, desktopCapturer, ipcMain, session, systemPreferences } from "electron";
|
|
import { showCursor } from "./cursorHider";
|
|
import { registerExtensionIpcHandlers } from "./extensions/extensionIpc";
|
|
import {
|
|
cleanupNativeVideoExportSessions,
|
|
getSelectedSourceId,
|
|
killWindowsCaptureProcess,
|
|
registerIpcHandlers,
|
|
} from "./ipc/handlers";
|
|
import {
|
|
configureGpuAccelerationSwitches,
|
|
ensureRecordingsDir,
|
|
logSmokeExportGpuDiagnostics,
|
|
} from "./mainBootstrapHelpers";
|
|
import { mainRuntimeState } from "./mainRuntimeState";
|
|
import {
|
|
initializeMainUpdateIntegration,
|
|
registerUpdateIpcHandlers,
|
|
runManualUpdateCheck,
|
|
setupMainAutoUpdates,
|
|
} from "./mainUpdateIntegration";
|
|
import {
|
|
createEditorWindowWrapper,
|
|
createSourceSelectorWindowWrapper,
|
|
createTray,
|
|
createWindow,
|
|
focusOrCreateMainWindow,
|
|
initializeMainWindowControls,
|
|
reassertHudOverlayMouseState,
|
|
restoreWindowSafely,
|
|
setupApplicationMenu,
|
|
syncDockIcon,
|
|
updateTrayMenu,
|
|
} from "./mainWindowControls";
|
|
import { ensureMediaServer } from "./mediaServer";
|
|
import { ensurePackagedRendererServer } from "./rendererServer";
|
|
import {
|
|
createEditorWindow,
|
|
createHudOverlayWindow,
|
|
createSourceSelectorWindow,
|
|
getHudOverlayWindow,
|
|
isHudOverlayMousePassthroughSupported,
|
|
} from "./windows";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const IS_SMOKE_EXPORT = process.env.RECORDLY_SMOKE_EXPORT === "1";
|
|
|
|
app.commandLine.appendSwitch("ignore-gpu-blocklist");
|
|
app.commandLine.appendSwitch("enable-unsafe-webgpu");
|
|
app.commandLine.appendSwitch("enable-gpu-rasterization");
|
|
|
|
configureGpuAccelerationSwitches();
|
|
|
|
process.env.APP_ROOT = path.join(__dirname, "..");
|
|
|
|
export const VITE_DEV_SERVER_URL = process.env["VITE_DEV_SERVER_URL"];
|
|
export const MAIN_DIST = path.join(process.env.APP_ROOT, "dist-electron");
|
|
export const RENDERER_DIST = path.join(process.env.APP_ROOT, "dist");
|
|
|
|
process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL
|
|
? path.join(process.env.APP_ROOT, "public")
|
|
: RENDERER_DIST;
|
|
|
|
const hasSingleInstanceLock = app.requestSingleInstanceLock();
|
|
if (!hasSingleInstanceLock) {
|
|
app.quit();
|
|
}
|
|
|
|
initializeMainWindowControls({
|
|
rendererDist: RENDERER_DIST,
|
|
createHudOverlayWindow,
|
|
createEditorWindow,
|
|
createSourceSelectorWindow,
|
|
getHudOverlayWindow,
|
|
isHudOverlayMousePassthroughSupported,
|
|
onCheckForUpdates: runManualUpdateCheck,
|
|
});
|
|
|
|
initializeMainUpdateIntegration({
|
|
rendererDist: RENDERER_DIST,
|
|
focusOrCreateMainWindow,
|
|
reassertHudOverlayMouseState,
|
|
});
|
|
|
|
app.on("before-quit", () => {
|
|
killWindowsCaptureProcess();
|
|
showCursor();
|
|
cleanupNativeVideoExportSessions();
|
|
});
|
|
|
|
app.on("window-all-closed", () => {
|
|
if (IS_SMOKE_EXPORT || process.platform !== "darwin") {
|
|
app.quit();
|
|
}
|
|
});
|
|
|
|
app.on("activate", () => {
|
|
focusOrCreateMainWindow();
|
|
});
|
|
|
|
app.on("second-instance", () => {
|
|
focusOrCreateMainWindow();
|
|
});
|
|
|
|
app.whenReady().then(async () => {
|
|
if (process.platform === "win32") {
|
|
app.setAppUserModelId("dev.recordly.app");
|
|
}
|
|
|
|
session.defaultSession.setPermissionCheckHandler((_webContents, permission) => {
|
|
const allowed = ["media", "audioCapture", "microphone", "camera", "videoCapture"];
|
|
return allowed.includes(permission);
|
|
});
|
|
|
|
session.defaultSession.setPermissionRequestHandler((_webContents, permission, callback) => {
|
|
const allowed = ["media", "audioCapture", "microphone", "camera", "videoCapture"];
|
|
callback(allowed.includes(permission));
|
|
});
|
|
|
|
session.defaultSession.setDevicePermissionHandler(() => true);
|
|
|
|
if (process.platform === "darwin") {
|
|
const cameraStatus = systemPreferences.getMediaAccessStatus("camera");
|
|
if (cameraStatus !== "granted") {
|
|
await systemPreferences.askForMediaAccess("camera");
|
|
}
|
|
|
|
const micStatus = systemPreferences.getMediaAccessStatus("microphone");
|
|
if (micStatus !== "granted") {
|
|
await systemPreferences.askForMediaAccess("microphone");
|
|
}
|
|
} else if (process.platform === "win32") {
|
|
const cameraStatus = systemPreferences.getMediaAccessStatus("camera");
|
|
const micStatus = systemPreferences.getMediaAccessStatus("microphone");
|
|
if (cameraStatus !== "granted") {
|
|
console.warn(
|
|
`[permissions] Camera access is "${cameraStatus}" — webcam may not work. Check Windows Settings > Privacy > Camera.`,
|
|
);
|
|
}
|
|
if (micStatus !== "granted") {
|
|
console.warn(
|
|
`[permissions] Microphone access is "${micStatus}" — mic recording may not work. Check Windows Settings > Privacy > Microphone.`,
|
|
);
|
|
}
|
|
}
|
|
|
|
ipcMain.on("hud-overlay-close", () => {
|
|
app.quit();
|
|
});
|
|
|
|
registerUpdateIpcHandlers();
|
|
syncDockIcon();
|
|
createTray();
|
|
updateTrayMenu();
|
|
setupApplicationMenu();
|
|
await ensureRecordingsDir();
|
|
|
|
if (!VITE_DEV_SERVER_URL) {
|
|
try {
|
|
await ensurePackagedRendererServer(RENDERER_DIST);
|
|
} catch (error) {
|
|
console.warn("[renderer-server] Failed to start packaged renderer server:", error);
|
|
}
|
|
}
|
|
|
|
try {
|
|
await ensureMediaServer();
|
|
} catch (error) {
|
|
console.warn("[media-server] Failed to start media server:", error);
|
|
}
|
|
|
|
registerIpcHandlers(
|
|
createEditorWindowWrapper,
|
|
createSourceSelectorWindowWrapper,
|
|
() => mainRuntimeState.mainWindow,
|
|
() => mainRuntimeState.sourceSelectorWindow,
|
|
(recording: boolean, sourceName: string) => {
|
|
mainRuntimeState.selectedSourceName = sourceName;
|
|
if (!mainRuntimeState.tray) {
|
|
createTray();
|
|
}
|
|
updateTrayMenu(recording);
|
|
if (recording) {
|
|
reassertHudOverlayMouseState();
|
|
}
|
|
if (!recording) {
|
|
restoreWindowSafely(mainRuntimeState.mainWindow);
|
|
}
|
|
},
|
|
);
|
|
|
|
registerExtensionIpcHandlers();
|
|
|
|
if (IS_SMOKE_EXPORT) {
|
|
await logSmokeExportGpuDiagnostics(IS_SMOKE_EXPORT);
|
|
console.log(
|
|
`[smoke-export] Starting editor smoke export for ${process.env.RECORDLY_SMOKE_EXPORT_INPUT ?? "<missing input>"}`,
|
|
);
|
|
createEditorWindowWrapper();
|
|
return;
|
|
}
|
|
|
|
createWindow();
|
|
setupMainAutoUpdates();
|
|
|
|
session.defaultSession.setDisplayMediaRequestHandler(async (_request, callback) => {
|
|
try {
|
|
const sources = await desktopCapturer.getSources({ types: ["screen", "window"] });
|
|
const sourceId = getSelectedSourceId();
|
|
const source = sourceId
|
|
? (sources.find((candidate) => candidate.id === sourceId) ?? sources[0])
|
|
: sources[0];
|
|
if (source) {
|
|
callback({ video: { id: source.id, name: source.name } });
|
|
} else {
|
|
callback({});
|
|
}
|
|
} catch (error) {
|
|
console.error("setDisplayMediaRequestHandler error:", error);
|
|
callback({});
|
|
}
|
|
});
|
|
});
|