From f00d381f94d548b9e6a6400faedb5d12683db04e Mon Sep 17 00:00:00 2001 From: Nikhil Solanki Date: Thu, 25 Dec 2025 14:48:24 +0530 Subject: [PATCH] fixed swloppy gitignore --- .github/ISSUE_TEMPLATE/bug_report.md | 38 ++ .github/ISSUE_TEMPLATE/feature_request.md | 20 + .github/pull_request_template.md | 43 +++ .github/workflows/build.yml | 99 +++++ .gitignore | 370 +------------------ dist-electron/main.js | 423 ++++++++++++++++++++++ dist-electron/preload.mjs | 63 ++++ 7 files changed, 703 insertions(+), 353 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/build.yml create mode 100644 dist-electron/main.js create mode 100644 dist-electron/preload.mjs diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..dd84ea7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bbcbbe7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..79f39d4 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,43 @@ +# Pull Request Template + +## Description + + +## Motivation + + +## Type of Change +- [ ] New Feature +- [ ] Bug Fix +- [ ] Refactor / Code Cleanup +- [ ] Documentation Update +- [ ] Other (please specify) + +## Related Issue(s) + + +## Screenshots / Video + + +**Screenshot** (if applicable): + +```markdown +![Screenshot Description](path/to/screenshot.png) +``` + +**Video** (if applicable): + +```html + +``` + +## Testing + + +## Checklist +- [ ] I have performed a self-review of my code. +- [ ] I have added any necessary screenshots or videos. +- [ ] I have linked related issue(s) and updated the changelog if applicable. + +--- +*Thank you for contributing!* diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..790884e --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,99 @@ + +name: Build Electron App + +on: + workflow_dispatch: + +jobs: + build-windows: + runs-on: windows-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '22' + + - name: Install dependencies + run: npm ci + + - name: Install app dependencies + run: npx electron-builder install-app-deps + + - name: Build Windows app + run: npm run build:win + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload Windows build + uses: actions/upload-artifact@v4 + with: + name: windows-installer + path: release/**/*.exe + retention-days: 30 + + build-macos: + runs-on: macos-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '22' + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install dependencies + run: npm ci + + - name: Install app dependencies + run: npx electron-builder install-app-deps + + - name: Build macOS app + run: npm run build:mac + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload macOS build + uses: actions/upload-artifact@v4 + with: + name: macos-installer + path: release/**/*.dmg + retention-days: 30 + + build-linux: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '22' + + - name: Install dependencies + run: npm ci + + - name: Install app dependencies + run: npx electron-builder install-app-deps + + - name: Build Linux app + run: npm run build:linux + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload Linux build + uses: actions/upload-artifact@v4 + with: + name: linux-installer + path: release/**/*.AppImage + retention-days: 30 + diff --git a/.gitignore b/.gitignore index 5db2cfd..3913db1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,363 +1,27 @@ -# ============================================================================ -# OpenScreen - Comprehensive .gitignore -# Electron + Vite + React + TypeScript + Tailwind + Vitest -# ============================================================================ - -# ============================================================================ -# DEPENDENCIES -# ============================================================================ -node_modules/ -bower_components/ -jspm_packages/ - -# ============================================================================ -# LOGS -# ============================================================================ -logs/ +# Logs +logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log* -debug.log -error.log -combined.log -# ============================================================================ -# BUILD OUTPUTS -# ============================================================================ -# Vite build output -dist/ -dist-ssr/ - -# Electron compiled files -dist-electron/ - -# Generic build directories -build/ -out/ -.output/ - -# ============================================================================ -# ELECTRON BUILDER -# ============================================================================ -# Release/installer output -release/ - -# Platform-specific installers -*.exe -*.msi -*.dmg -*.pkg -*.AppImage -*.deb -*.rpm -*.snap -*.flatpak - -# Electron builder metadata -*.blockmap -builder-effective-config.yaml -builder-debug.yml - -# Auto-update manifests -latest.yml -latest-mac.yml -latest-linux.yml - -# ============================================================================ -# CACHE DIRECTORIES -# ============================================================================ -# Vite cache -.vite/ -node_modules/.vite/ -vite.config.ts.timestamp-* -vite.config.*.timestamp-* - -# General cache -.cache/ -.parcel-cache/ -.turbo/ - -# Build tool caches -.webpack/ -.esbuild/ -.swc/ - -# Electron cache -.electron/ -.cache/electron/ -.cache/electron-builder/ - -# ============================================================================ -# TYPESCRIPT -# ============================================================================ -*.tsbuildinfo -tsconfig.tsbuildinfo - -# ============================================================================ -# TESTING (Vitest + Fast-Check) -# ============================================================================ -# Coverage reports -coverage/ -.coverage/ -.nyc_output/ -*.lcov - -# Vitest cache -.vitest/ -node_modules/.vitest/ - -# Test results -test-results/ -junit.xml -test-report.xml -*.junit.xml -vitest-results.json - -# Fast-check -.fast-check-* -fast-check-report.json - -# ============================================================================ -# LINTING -# ============================================================================ -.eslintcache -.stylelintcache - -# ============================================================================ -# SOURCE MAPS -# ============================================================================ -*.map -*.js.map -*.css.map - -# ============================================================================ -# ENVIRONMENT & SECRETS (CRITICAL!) -# ============================================================================ -# Environment files -.env -.env.local -.env.*.local -.env.development -.env.development.local -.env.test -.env.test.local -.env.production -.env.production.local -.env.staging - -# API Keys & Credentials -*.pem -*.key -*.p12 -*.pfx -*.crt -*.cer -*.der -credentials.json -secrets.json -*-credentials.json -*-secrets.json -service-account*.json -firebase-adminsdk*.json -google-credentials.json - -# SSL Certificates -certs/ -certificates/ -ssl/ - -# ============================================================================ -# LOCAL CONFIGURATION -# ============================================================================ +node_modules +dist +dist-ssr *.local -*.local.json -*.local.yaml -*.local.yml -config.local.* -local.settings.json -# ============================================================================ -# KIRO AI ASSISTANT -# ============================================================================ -.kiro/ - -# ============================================================================ -# GITHUB -# ============================================================================ -.github/ - -# ============================================================================ -# TEMPORARY & BACKUP FILES -# ============================================================================ -*.tmp -*.temp -*.bak -*.backup -*.orig -*.old -*~ -.tmp/ -temp/ - -# ============================================================================ -# EDITOR & IDE -# ============================================================================ -# VS Code -.vscode/ -.history/ -*.vsix - -# JetBrains IDEs (IntelliJ, WebStorm, etc.) -.idea/ -*.iml -*.iws -*.ipr -cmake-build-*/ - -# Vim/Neovim -*.swp -*.swo -*.swn -[._]*.s[a-v][a-z] -[._]*.sw[a-p] -Session.vim -Sessionx.vim -.netrwhist -.nvimlog -tags -GTAGS -GRTAGS -GPATH - -# Sublime Text -*.sublime-project -*.sublime-workspace - -# Emacs -\#*\# -/.emacs.desktop -/.emacs.desktop.lock -*.elc -auto-save-list -tramp -.\#* - -# ============================================================================ -# OPERATING SYSTEM FILES -# ============================================================================ -# macOS +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea .DS_Store -.DS_Store? -.AppleDouble -.LSOverride -._* -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk -Icon? - -# Windows -Thumbs.db -Thumbs.db:encryptable -ehthumbs.db -ehthumbs_vista.db -*.stackdump -[Dd]esktop.ini -$RECYCLE.BIN/ -*.cab -*.msix -*.msm -*.msp -*.lnk - -# Linux -.fuse_hidden* -.directory -.Trash-* -.nfs* - -# ============================================================================ -# NATIVE MODULES -# ============================================================================ -*.node -build/Release/ - -# ============================================================================ -# CRASH REPORTS -# ============================================================================ -*.dmp -crash-reports/ - -# ============================================================================ -# DATABASE FILES -# ============================================================================ -*.sqlite -*.sqlite3 -*.db -*.sql -dump.sql -*.dump - -# ============================================================================ -# PACKAGE MANAGER SPECIFIC -# ============================================================================ -# npm -.npm - -# Yarn v1 -.yarn-integrity - -# Yarn v2+ (Berry) -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions -.pnp -.pnp.js -.pnp.cjs -.pnp.loader.mjs - -# pnpm -.pnpm-store/ -.pnpm-debug.log - -# ============================================================================ -# MISCELLANEOUS -# ============================================================================ -# Node REPL history -.node_repl_history - -# Nx cache -.nx/cache - -# Storybook -storybook-static/ - -# Serverless -.serverless/ - -# FuseBox -.fusebox/ - -# DynamoDB Local -.dynamodb/ - -# TernJS -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +release/** +*.kiro/ +# npx electron-builder --mac --win \ No newline at end of file diff --git a/dist-electron/main.js b/dist-electron/main.js new file mode 100644 index 0000000..515edf4 --- /dev/null +++ b/dist-electron/main.js @@ -0,0 +1,423 @@ +import { ipcMain, screen, BrowserWindow, desktopCapturer, shell, app, dialog, 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"); +let hudOverlayWindow = null; +ipcMain.on("hud-overlay-hide", () => { + if (hudOverlayWindow && !hudOverlayWindow.isDestroyed()) { + hudOverlayWindow.minimize(); + } +}); +function createHudOverlayWindow() { + const primaryDisplay = screen.getPrimaryDisplay(); + const { workArea } = primaryDisplay; + const windowWidth = 500; + const windowHeight = 100; + const x = Math.floor(workArea.x + (workArea.width - windowWidth) / 2); + const y = Math.floor(workArea.y + workArea.height - windowHeight - 5); + const win = new BrowserWindow({ + width: windowWidth, + height: windowHeight, + minWidth: 500, + maxWidth: 500, + minHeight: 100, + maxHeight: 100, + x, + y, + frame: false, + transparent: true, + resizable: false, + alwaysOnTop: true, + skipTaskbar: true, + hasShadow: false, + webPreferences: { + preload: path.join(__dirname$1, "preload.mjs"), + nodeIntegration: false, + contextIsolation: true, + backgroundThrottling: false + } + }); + win.webContents.on("did-finish-load", () => { + win == null ? void 0 : win.webContents.send("main-process-message", (/* @__PURE__ */ new Date()).toLocaleString()); + }); + hudOverlayWindow = win; + win.on("closed", () => { + if (hudOverlayWindow === win) { + hudOverlayWindow = null; + } + }); + 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; +} +function createEditorWindow() { + const isMac = process.platform === "darwin"; + const win = new BrowserWindow({ + width: 1200, + height: 800, + minWidth: 800, + minHeight: 600, + ...isMac && { + titleBarStyle: "hiddenInset", + trafficLightPosition: { x: 12, y: 12 } + }, + transparent: false, + resizable: true, + alwaysOnTop: false, + skipTaskbar: false, + title: "OpenScreen", + backgroundColor: "#000000", + webPreferences: { + preload: path.join(__dirname$1, "preload.mjs"), + nodeIntegration: false, + contextIsolation: true, + webSecurity: false, + backgroundThrottling: false + } + }); + 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; +} +function createSourceSelectorWindow() { + const { width, height } = screen.getPrimaryDisplay().workAreaSize; + const win = new BrowserWindow({ + 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, + backgroundColor: "#00000000", + webPreferences: { + preload: path.join(__dirname$1, "preload.mjs"), + nodeIntegration: false, + contextIsolation: true + } + }); + 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; +} +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(); + return; + } + createSourceSelectorWindow2(); + }); + ipcMain.handle("switch-to-editor", () => { + const mainWin = getMainWindow(); + if (mainWin) { + mainWin.close(); + } + createEditorWindow2(); + }); + ipcMain.handle("store-recorded-video", async (_, videoData, fileName) => { + try { + const videoPath = path.join(RECORDINGS_DIR, fileName); + await fs.writeFile(videoPath, Buffer.from(videoData)); + currentVideoPath = videoPath; + return { + success: true, + path: videoPath, + message: "Video stored successfully" + }; + } catch (error) { + console.error("Failed to store video:", error); + return { + success: false, + message: "Failed to store video", + error: String(error) + }; + } + }); + ipcMain.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) }; + } + }); + ipcMain.handle("set-recording-state", (_, recording) => { + const source = selectedSource || { name: "Screen" }; + if (onRecordingStateChange) { + onRecordingStateChange(recording, source.name); + } + }); + ipcMain.handle("open-external-url", async (_, url) => { + try { + await shell.openExternal(url); + return { success: true }; + } catch (error) { + console.error("Failed to open URL:", error); + return { success: false, error: String(error) }; + } + }); + ipcMain.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; + } + }); + ipcMain.handle("save-exported-video", async (_, videoData, fileName) => { + try { + const mainWindow2 = getMainWindow(); + const isGif = fileName.toLowerCase().endsWith(".gif"); + const filters = isGif ? [{ name: "GIF Image", extensions: ["gif"] }] : [{ name: "MP4 Video", extensions: ["mp4"] }]; + const result = await dialog.showSaveDialog(mainWindow2 || void 0, { + title: isGif ? "Save Exported GIF" : "Save Exported Video", + defaultPath: path.join(app.getPath("downloads"), fileName), + filters, + properties: ["createDirectory", "showOverwriteConfirmation"] + }); + if (result.canceled || !result.filePath) { + return { + success: false, + cancelled: true, + message: "Export cancelled" + }; + } + await fs.writeFile(result.filePath, Buffer.from(videoData)); + return { + success: true, + path: result.filePath, + message: "Video exported successfully" + }; + } catch (error) { + console.error("Failed to save exported video:", error); + return { + success: false, + message: "Failed to save exported video", + error: String(error) + }; + } + }); + ipcMain.handle("open-video-file-picker", async () => { + try { + const result = await dialog.showOpenDialog({ + title: "Select Video File", + defaultPath: RECORDINGS_DIR, + filters: [ + { name: "Video Files", extensions: ["webm", "mp4", "mov", "avi", "mkv"] }, + { name: "All Files", extensions: ["*"] } + ], + properties: ["openFile"] + }); + if (result.canceled || result.filePaths.length === 0) { + return { success: false, cancelled: true }; + } + return { + success: true, + path: result.filePaths[0] + }; + } catch (error) { + console.error("Failed to open file picker:", error); + return { + success: false, + message: "Failed to open file picker", + error: String(error) + }; + } + }); + let currentVideoPath = null; + ipcMain.handle("set-current-video-path", (_, path2) => { + currentVideoPath = path2; + return { success: true }; + }); + ipcMain.handle("get-current-video-path", () => { + return currentVideoPath ? { success: true, path: currentVideoPath } : { success: false }; + }); + ipcMain.handle("clear-current-video-path", () => { + currentVideoPath = null; + return { success: true }; + }); + ipcMain.handle("get-platform", () => { + return process.platform; + }); +} +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const RECORDINGS_DIR = path.join(app.getPath("userData"), "recordings"); +async function ensureRecordingsDir() { + 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); + } +} +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 = ""; +const defaultTrayIcon = getTrayIcon("openscreen.png"); +const recordingTrayIcon = getTrayIcon("rec-button.png"); +function createWindow() { + mainWindow = createHudOverlayWindow(); +} +function createTray() { + tray = new Tray(defaultTrayIcon); +} +function getTrayIcon(filename) { + return nativeImage.createFromPath(path.join(process.env.VITE_PUBLIC || RENDERER_DIST, filename)).resize({ + width: 24, + height: 24, + quality: "best" + }); +} +function updateTrayMenu(recording = false) { + if (!tray) return; + const trayIcon = recording ? recordingTrayIcon : defaultTrayIcon; + const trayToolTip = recording ? `Recording: ${selectedSourceName}` : "OpenScreen"; + const menuTemplate = recording ? [ + { + label: "Stop Recording", + click: () => { + if (mainWindow && !mainWindow.isDestroyed()) { + mainWindow.webContents.send("stop-recording-from-tray"); + } + } + } + ] : [ + { + label: "Open", + click: () => { + if (mainWindow && !mainWindow.isDestroyed()) { + mainWindow.isMinimized() && mainWindow.restore(); + } else { + createWindow(); + } + } + }, + { + label: "Quit", + click: () => { + app.quit(); + } + } + ]; + tray.setImage(trayIcon); + tray.setToolTip(trayToolTip); + tray.setContextMenu(Menu.buildFromTemplate(menuTemplate)); +} +function createEditorWindowWrapper() { + if (mainWindow) { + mainWindow.close(); + mainWindow = null; + } + mainWindow = createEditorWindow(); +} +function createSourceSelectorWindowWrapper() { + sourceSelectorWindow = createSourceSelectorWindow(); + sourceSelectorWindow.on("closed", () => { + sourceSelectorWindow = null; + }); + return sourceSelectorWindow; +} +app.on("window-all-closed", () => { +}); +app.on("activate", () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow(); + } +}); +app.whenReady().then(async () => { + const { ipcMain: ipcMain2 } = await import("electron"); + ipcMain2.on("hud-overlay-close", () => { + app.quit(); + }); + createTray(); + updateTrayMenu(); + await ensureRecordingsDir(); + registerIpcHandlers( + createEditorWindowWrapper, + createSourceSelectorWindowWrapper, + () => mainWindow, + () => sourceSelectorWindow, + (recording, sourceName) => { + selectedSourceName = sourceName; + if (!tray) createTray(); + updateTrayMenu(recording); + if (!recording) { + if (mainWindow) mainWindow.restore(); + } + } + ); + createWindow(); +}); +export { + MAIN_DIST, + RECORDINGS_DIR, + RENDERER_DIST, + VITE_DEV_SERVER_URL +}; diff --git a/dist-electron/preload.mjs b/dist-electron/preload.mjs new file mode 100644 index 0000000..cb59604 --- /dev/null +++ b/dist-electron/preload.mjs @@ -0,0 +1,63 @@ +"use strict"; +const electron = require("electron"); +electron.contextBridge.exposeInMainWorld("electronAPI", { + hudOverlayHide: () => { + electron.ipcRenderer.send("hud-overlay-hide"); + }, + hudOverlayClose: () => { + electron.ipcRenderer.send("hud-overlay-close"); + }, + 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); + }, + openVideoFilePicker: () => { + return electron.ipcRenderer.invoke("open-video-file-picker"); + }, + setCurrentVideoPath: (path) => { + return electron.ipcRenderer.invoke("set-current-video-path", path); + }, + getCurrentVideoPath: () => { + return electron.ipcRenderer.invoke("get-current-video-path"); + }, + clearCurrentVideoPath: () => { + return electron.ipcRenderer.invoke("clear-current-video-path"); + }, + getPlatform: () => { + return electron.ipcRenderer.invoke("get-platform"); + } +});