diff --git a/dist-electron/main.js b/dist-electron/main.js index 7c61531..c99de03 100644 --- a/dist-electron/main.js +++ b/dist-electron/main.js @@ -1,340 +1,236 @@ -import { BrowserWindow, screen, ipcMain, desktopCapturer, shell, app, nativeImage, Tray, Menu } from "electron"; -import { fileURLToPath } from "node:url"; -import path from "node:path"; -import fs from "node:fs/promises"; -const __dirname$1 = path.dirname(fileURLToPath(import.meta.url)); -const APP_ROOT = path.join(__dirname$1, ".."); -const VITE_DEV_SERVER_URL$1 = process.env["VITE_DEV_SERVER_URL"]; -const RENDERER_DIST$1 = path.join(APP_ROOT, "dist"); -function createHudOverlayWindow() { - const win = new BrowserWindow({ +import { BrowserWindow as _, screen as D, ipcMain as c, desktopCapturer as j, shell as x, app as l, nativeImage as F, Tray as O, Menu as W } from "electron"; +import { fileURLToPath as P } from "node:url"; +import t from "node:path"; +import p from "node:fs/promises"; +const v = t.dirname(P(import.meta.url)), V = t.join(v, ".."), f = process.env.VITE_DEV_SERVER_URL, T = t.join(V, "dist"); +function L() { + const e = new _({ width: 250, height: 80, minWidth: 250, maxWidth: 250, minHeight: 80, maxHeight: 80, - frame: false, - transparent: true, - resizable: false, - alwaysOnTop: true, - skipTaskbar: true, - hasShadow: false, + frame: !1, + transparent: !0, + resizable: !1, + alwaysOnTop: !0, + skipTaskbar: !0, + hasShadow: !1, webPreferences: { - preload: path.join(__dirname$1, "preload.mjs"), - nodeIntegration: false, - contextIsolation: true, - backgroundThrottling: false + preload: t.join(v, "preload.mjs"), + nodeIntegration: !1, + contextIsolation: !0, + backgroundThrottling: !1 } }); - win.webContents.on("did-finish-load", () => { - win == null ? void 0 : win.webContents.send("main-process-message", (/* @__PURE__ */ new Date()).toLocaleString()); - }); - if (VITE_DEV_SERVER_URL$1) { - win.loadURL(VITE_DEV_SERVER_URL$1 + "?windowType=hud-overlay"); - } else { - win.loadFile(path.join(RENDERER_DIST$1, "index.html"), { - query: { windowType: "hud-overlay" } - }); - } - return win; + return e.webContents.on("did-finish-load", () => { + e == null || e.webContents.send("main-process-message", (/* @__PURE__ */ new Date()).toLocaleString()); + }), f ? e.loadURL(f + "?windowType=hud-overlay") : e.loadFile(t.join(T, "index.html"), { + query: { windowType: "hud-overlay" } + }), e; } -function createEditorWindow() { - const win = new BrowserWindow({ +function U() { + const e = new _({ width: 1200, height: 800, minWidth: 800, minHeight: 600, titleBarStyle: "hiddenInset", trafficLightPosition: { x: 12, y: 12 }, - transparent: false, - resizable: true, - alwaysOnTop: false, - skipTaskbar: false, + transparent: !1, + resizable: !0, + alwaysOnTop: !1, + skipTaskbar: !1, title: "OpenScreen", backgroundColor: "#000000", webPreferences: { - preload: path.join(__dirname$1, "preload.mjs"), - nodeIntegration: false, - contextIsolation: true, - webSecurity: false + preload: t.join(v, "preload.mjs"), + nodeIntegration: !1, + contextIsolation: !0, + webSecurity: !1 } }); - win.maximize(); - win.webContents.on("did-finish-load", () => { - win == null ? void 0 : win.webContents.send("main-process-message", (/* @__PURE__ */ new Date()).toLocaleString()); - }); - if (VITE_DEV_SERVER_URL$1) { - win.loadURL(VITE_DEV_SERVER_URL$1 + "?windowType=editor"); - } else { - win.loadFile(path.join(RENDERER_DIST$1, "index.html"), { - query: { windowType: "editor" } - }); - } - return win; + return e.maximize(), e.webContents.on("did-finish-load", () => { + e == null || e.webContents.send("main-process-message", (/* @__PURE__ */ new Date()).toLocaleString()); + }), f ? e.loadURL(f + "?windowType=editor") : e.loadFile(t.join(T, "index.html"), { + query: { windowType: "editor" } + }), e; } -function createSourceSelectorWindow() { - const { width, height } = screen.getPrimaryDisplay().workAreaSize; - const win = new BrowserWindow({ +function k() { + const { width: e, height: s } = D.getPrimaryDisplay().workAreaSize, u = new _({ width: 620, height: 420, minHeight: 350, maxHeight: 500, - x: Math.round((width - 620) / 2), - y: Math.round((height - 420) / 2), - frame: false, - resizable: false, - alwaysOnTop: true, - transparent: true, + x: Math.round((e - 620) / 2), + y: Math.round((s - 420) / 2), + frame: !1, + resizable: !1, + alwaysOnTop: !0, + transparent: !0, backgroundColor: "#00000000", webPreferences: { - preload: path.join(__dirname$1, "preload.mjs"), - nodeIntegration: false, - contextIsolation: true + preload: t.join(v, "preload.mjs"), + nodeIntegration: !1, + contextIsolation: !0 } }); - if (VITE_DEV_SERVER_URL$1) { - win.loadURL(VITE_DEV_SERVER_URL$1 + "?windowType=source-selector"); - } else { - win.loadFile(path.join(RENDERER_DIST$1, "index.html"), { - query: { windowType: "source-selector" } - }); - } - return win; + return f ? u.loadURL(f + "?windowType=source-selector") : u.loadFile(t.join(T, "index.html"), { + query: { windowType: "source-selector" } + }), u; } -let selectedSource = null; -function registerIpcHandlers(createEditorWindow2, createSourceSelectorWindow2, getMainWindow, getSourceSelectorWindow, onRecordingStateChange) { - ipcMain.handle("get-sources", async (_, opts) => { - const sources = await desktopCapturer.getSources(opts); - return sources.map((source) => ({ - id: source.id, - name: source.name, - display_id: source.display_id, - thumbnail: source.thumbnail ? source.thumbnail.toDataURL() : null, - appIcon: source.appIcon ? source.appIcon.toDataURL() : null - })); - }); - ipcMain.handle("select-source", (_, source) => { - selectedSource = source; - const sourceSelectorWin = getSourceSelectorWindow(); - if (sourceSelectorWin) { - sourceSelectorWin.close(); - } - return selectedSource; - }); - ipcMain.handle("get-selected-source", () => { - return selectedSource; - }); - ipcMain.handle("open-source-selector", () => { - const sourceSelectorWin = getSourceSelectorWindow(); - if (sourceSelectorWin) { - sourceSelectorWin.focus(); +let R = null; +function C(e, s, u, m, w) { + c.handle("get-sources", async (o, n) => (await j.getSources(n)).map((r) => ({ + id: r.id, + name: r.name, + display_id: r.display_id, + thumbnail: r.thumbnail ? r.thumbnail.toDataURL() : null, + appIcon: r.appIcon ? r.appIcon.toDataURL() : null + }))), c.handle("select-source", (o, n) => { + R = n; + const a = m(); + return a && a.close(), R; + }), c.handle("get-selected-source", () => R), c.handle("open-source-selector", () => { + const o = m(); + if (o) { + o.focus(); return; } - createSourceSelectorWindow2(); - }); - ipcMain.handle("switch-to-editor", () => { - const mainWin = getMainWindow(); - if (mainWin) { - mainWin.close(); - } - createEditorWindow2(); - }); - ipcMain.handle("store-recorded-video", async (_, videoData, fileName) => { + s(); + }), c.handle("switch-to-editor", () => { + const o = u(); + o && o.close(), e(); + }), c.handle("store-recorded-video", async (o, n, a) => { try { - const videoPath = path.join(RECORDINGS_DIR, fileName); - await fs.writeFile(videoPath, Buffer.from(videoData)); - return { - success: true, - path: videoPath, + const r = t.join(h, a); + return await p.writeFile(r, Buffer.from(n)), { + success: !0, + path: r, message: "Video stored successfully" }; - } catch (error) { - console.error("Failed to store video:", error); - return { - success: false, + } catch (r) { + return console.error("Failed to store video:", r), { + success: !1, message: "Failed to store video", - error: String(error) + error: String(r) }; } - }); - ipcMain.handle("get-recorded-video-path", async () => { + }), c.handle("get-recorded-video-path", async () => { try { - const files = await fs.readdir(RECORDINGS_DIR); - const videoFiles = files.filter((file) => file.endsWith(".webm")); - if (videoFiles.length === 0) { - return { success: false, message: "No recorded video found" }; - } - const latestVideo = videoFiles.sort().reverse()[0]; - const videoPath = path.join(RECORDINGS_DIR, latestVideo); - return { success: true, path: videoPath }; - } catch (error) { - console.error("Failed to get video path:", error); - return { success: false, message: "Failed to get video path", error: String(error) }; + const n = (await p.readdir(h)).filter((y) => y.endsWith(".webm")); + if (n.length === 0) + return { success: !1, message: "No recorded video found" }; + const a = n.sort().reverse()[0]; + return { success: !0, path: t.join(h, a) }; + } catch (o) { + return console.error("Failed to get video path:", o), { success: !1, message: "Failed to get video path", error: String(o) }; } - }); - ipcMain.handle("set-recording-state", (_, recording) => { - const source = selectedSource || { name: "Screen" }; - if (onRecordingStateChange) { - onRecordingStateChange(recording, source.name); - } - }); - ipcMain.handle("open-external-url", async (_, url) => { + }), c.handle("set-recording-state", (o, n) => { + w && w(n, (R || { name: "Screen" }).name); + }), c.handle("open-external-url", async (o, n) => { try { - await shell.openExternal(url); - return { success: true }; - } catch (error) { - console.error("Failed to open URL:", error); - return { success: false, error: String(error) }; + return await x.openExternal(n), { success: !0 }; + } catch (a) { + return console.error("Failed to open URL:", a), { success: !1, error: String(a) }; } - }); - ipcMain.handle("get-asset-base-path", () => { + }), c.handle("get-asset-base-path", () => { try { - if (app.isPackaged) { - return path.join(process.resourcesPath, "assets"); - } - return path.join(app.getAppPath(), "public", "assets"); - } catch (err) { - console.error("Failed to resolve asset base path:", err); - return null; + return l.isPackaged ? t.join(process.resourcesPath, "assets") : t.join(l.getAppPath(), "public", "assets"); + } catch (o) { + return console.error("Failed to resolve asset base path:", o), null; } - }); - ipcMain.handle("save-exported-video", async (_, videoData, fileName) => { + }), c.handle("save-exported-video", async (o, n, a) => { try { - const downloadsPath = app.getPath("downloads"); - const videoPath = path.join(downloadsPath, fileName); - await fs.writeFile(videoPath, Buffer.from(videoData)); - return { - success: true, - path: videoPath, + const r = l.getPath("downloads"), y = t.join(r, a); + return await p.writeFile(y, Buffer.from(n)), { + success: !0, + path: y, message: "Video exported successfully" }; - } catch (error) { - console.error("Failed to save exported video:", error); - return { - success: false, + } catch (r) { + return console.error("Failed to save exported video:", r), { + success: !1, message: "Failed to save exported video", - error: String(error) + error: String(r) }; } }); } -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const RECORDINGS_DIR = path.join(app.getPath("userData"), "recordings"); -async function cleanupOldRecordings() { +const A = t.dirname(P(import.meta.url)), h = t.join(l.getPath("userData"), "recordings"); +async function M() { try { - const files = await fs.readdir(RECORDINGS_DIR); - const now = Date.now(); - const maxAge = 1 * 24 * 60 * 60 * 1e3; - for (const file of files) { - const filePath = path.join(RECORDINGS_DIR, file); - const stats = await fs.stat(filePath); - if (now - stats.mtimeMs > maxAge) { - await fs.unlink(filePath); - console.log(`Deleted old recording: ${file}`); - } + const e = await p.readdir(h), s = Date.now(), u = 1 * 24 * 60 * 60 * 1e3; + for (const m of e) { + const w = t.join(h, m), o = await p.stat(w); + s - o.mtimeMs > u && (await p.unlink(w), console.log(`Deleted old recording: ${m}`)); } - } catch (error) { - console.error("Failed to cleanup old recordings:", error); + } catch (e) { + console.error("Failed to cleanup old recordings:", e); } } -async function ensureRecordingsDir() { +async function z() { try { - await fs.mkdir(RECORDINGS_DIR, { recursive: true }); - console.log("RECORDINGS_DIR:", RECORDINGS_DIR); - console.log("User Data Path:", app.getPath("userData")); - } catch (error) { - console.error("Failed to create recordings directory:", error); + await p.mkdir(h, { recursive: !0 }), console.log("RECORDINGS_DIR:", h), console.log("User Data Path:", l.getPath("userData")); + } catch (e) { + console.error("Failed to create recordings directory:", e); } } -process.env.APP_ROOT = path.join(__dirname, ".."); -const VITE_DEV_SERVER_URL = process.env["VITE_DEV_SERVER_URL"]; -const MAIN_DIST = path.join(process.env.APP_ROOT, "dist-electron"); -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; -let mainWindow = null; -let sourceSelectorWindow = null; -let tray = null; -let selectedSourceName = ""; -function createWindow() { - mainWindow = createHudOverlayWindow(); +process.env.APP_ROOT = t.join(A, ".."); +const H = process.env.VITE_DEV_SERVER_URL, Q = t.join(process.env.APP_ROOT, "dist-electron"), b = t.join(process.env.APP_ROOT, "dist"); +process.env.VITE_PUBLIC = H ? t.join(process.env.APP_ROOT, "public") : b; +let i = null, g = null, d = null, E = ""; +function S() { + i = L(); } -function createTray() { - const iconPath = path.join(process.env.VITE_PUBLIC || RENDERER_DIST, "rec-button.png"); - let icon = nativeImage.createFromPath(iconPath); - icon = icon.resize({ width: 24, height: 24, quality: "best" }); - tray = new Tray(icon); - updateTrayMenu(); +function N() { + const e = t.join(process.env.VITE_PUBLIC || b, "rec-button.png"); + let s = F.createFromPath(e); + s = s.resize({ width: 24, height: 24, quality: "best" }), d = new O(s), I(); } -function updateTrayMenu() { - if (!tray) return; - const menuTemplate = [ +function I() { + if (!d) return; + const e = [ { label: "Stop Recording", click: () => { - if (mainWindow && !mainWindow.isDestroyed()) { - mainWindow.webContents.send("stop-recording-from-tray"); - } + i && !i.isDestroyed() && i.webContents.send("stop-recording-from-tray"); } } - ]; - const contextMenu = Menu.buildFromTemplate(menuTemplate); - tray.setContextMenu(contextMenu); - tray.setToolTip(`Recording: ${selectedSourceName}`); + ], s = W.buildFromTemplate(e); + d.setContextMenu(s), d.setToolTip(`Recording: ${E}`); } -function createEditorWindowWrapper() { - if (mainWindow) { - mainWindow.close(); - mainWindow = null; - } - mainWindow = createEditorWindow(); +function B() { + i && (i.close(), i = null), i = U(); } -function createSourceSelectorWindowWrapper() { - sourceSelectorWindow = createSourceSelectorWindow(); - sourceSelectorWindow.on("closed", () => { - sourceSelectorWindow = null; - }); - return sourceSelectorWindow; +function q() { + return g = k(), g.on("closed", () => { + g = null; + }), g; } -app.on("window-all-closed", () => { +l.on("window-all-closed", () => { }); -app.on("activate", () => { - if (BrowserWindow.getAllWindows().length === 0) { - createWindow(); - } +l.on("activate", () => { + _.getAllWindows().length === 0 && S(); }); -app.on("before-quit", async (event) => { - event.preventDefault(); - await cleanupOldRecordings(); - app.exit(0); +l.on("before-quit", async (e) => { + e.preventDefault(), await M(), l.exit(0); }); -app.whenReady().then(async () => { - await ensureRecordingsDir(); - registerIpcHandlers( - createEditorWindowWrapper, - createSourceSelectorWindowWrapper, - () => mainWindow, - () => sourceSelectorWindow, - (recording, sourceName) => { - selectedSourceName = sourceName; - if (recording) { - if (!tray) createTray(); - updateTrayMenu(); - if (mainWindow) mainWindow.minimize(); - } else { - if (tray) { - tray.destroy(); - tray = null; - } - if (mainWindow) mainWindow.restore(); - } +l.whenReady().then(async () => { + await z(), C( + B, + q, + () => i, + () => g, + (e, s) => { + E = s, e ? (d || N(), I(), i && i.minimize()) : (d && (d.destroy(), d = null), i && i.restore()); } - ); - createWindow(); + ), S(); }); export { - MAIN_DIST, - RECORDINGS_DIR, - RENDERER_DIST, - VITE_DEV_SERVER_URL + Q as MAIN_DIST, + h as RECORDINGS_DIR, + b as RENDERER_DIST, + H as VITE_DEV_SERVER_URL }; diff --git a/dist-electron/preload.mjs b/dist-electron/preload.mjs index 7f7797b..a08f981 100644 --- a/dist-electron/preload.mjs +++ b/dist-electron/preload.mjs @@ -1,42 +1 @@ -"use strict"; -const electron = require("electron"); -electron.contextBridge.exposeInMainWorld("electronAPI", { - getAssetBasePath: async () => { - return await electron.ipcRenderer.invoke("get-asset-base-path"); - }, - getSources: async (opts) => { - return await electron.ipcRenderer.invoke("get-sources", opts); - }, - switchToEditor: () => { - return electron.ipcRenderer.invoke("switch-to-editor"); - }, - openSourceSelector: () => { - return electron.ipcRenderer.invoke("open-source-selector"); - }, - selectSource: (source) => { - return electron.ipcRenderer.invoke("select-source", source); - }, - getSelectedSource: () => { - return electron.ipcRenderer.invoke("get-selected-source"); - }, - storeRecordedVideo: (videoData, fileName) => { - return electron.ipcRenderer.invoke("store-recorded-video", videoData, fileName); - }, - getRecordedVideoPath: () => { - return electron.ipcRenderer.invoke("get-recorded-video-path"); - }, - setRecordingState: (recording) => { - return electron.ipcRenderer.invoke("set-recording-state", recording); - }, - onStopRecordingFromTray: (callback) => { - const listener = () => callback(); - electron.ipcRenderer.on("stop-recording-from-tray", listener); - return () => electron.ipcRenderer.removeListener("stop-recording-from-tray", listener); - }, - openExternalUrl: (url) => { - return electron.ipcRenderer.invoke("open-external-url", url); - }, - saveExportedVideo: (videoData, fileName) => { - return electron.ipcRenderer.invoke("save-exported-video", videoData, fileName); - } -}); +"use strict";const e=require("electron");e.contextBridge.exposeInMainWorld("electronAPI",{getAssetBasePath:async()=>await e.ipcRenderer.invoke("get-asset-base-path"),getSources:async r=>await e.ipcRenderer.invoke("get-sources",r),switchToEditor:()=>e.ipcRenderer.invoke("switch-to-editor"),openSourceSelector:()=>e.ipcRenderer.invoke("open-source-selector"),selectSource:r=>e.ipcRenderer.invoke("select-source",r),getSelectedSource:()=>e.ipcRenderer.invoke("get-selected-source"),storeRecordedVideo:(r,t)=>e.ipcRenderer.invoke("store-recorded-video",r,t),getRecordedVideoPath:()=>e.ipcRenderer.invoke("get-recorded-video-path"),setRecordingState:r=>e.ipcRenderer.invoke("set-recording-state",r),onStopRecordingFromTray:r=>{const t=()=>r();return e.ipcRenderer.on("stop-recording-from-tray",t),()=>e.ipcRenderer.removeListener("stop-recording-from-tray",t)},openExternalUrl:r=>e.ipcRenderer.invoke("open-external-url",r),saveExportedVideo:(r,t)=>e.ipcRenderer.invoke("save-exported-video",r,t)}); diff --git a/src/lib/exporter/videoExporter.ts b/src/lib/exporter/videoExporter.ts index f4e3cdb..4bc6f94 100644 --- a/src/lib/exporter/videoExporter.ts +++ b/src/lib/exporter/videoExporter.ts @@ -205,7 +205,7 @@ export class VideoExporter { const metadata: EncodedVideoChunkMetadata = { decoderConfig: { - codec: this.config.codec || 'avc1.64001f', + codec: this.config.codec || 'avc1.640033', codedWidth: this.config.width, codedHeight: this.config.height, description: this.videoDescription, @@ -230,7 +230,7 @@ export class VideoExporter { }, }); - const codec = this.config.codec || 'avc1.64001f'; + const codec = this.config.codec || 'avc1.640033'; const encoderConfig: VideoEncoderConfig = { codec,