Commit Graph
73 Commits
Author SHA1 Message Date
wiiiii123 6858b53655 fix(hud): restore clickability after webcam preview 2026-05-29 02:53:33 +07:00
wiiiii123 9bb288b069 fix(linux): route X11 capture through real sources 2026-05-29 00:48:59 +07:00
wiiiii123 38f5ded48d fix(recording): stabilize capture quality and CUDA export canvas 2026-05-27 18:12:21 +07:00
webadderall de2fbafcf1 Update Recordly app branding assets 2026-05-11 19:20:21 +10:00
Alan Trebugeais b10f0bf4c3 fix: webcam recording, now it works, alongside the microphone etc 2026-05-10 23:37:07 +02:00
wiiiii123 6dab368631 fix(electron): avoid cjs dirname binding collision 2026-05-08 20:07:36 +07:00
wiiiii123 93e1312978 merge main into beta/pr410-native-gpu-export-test
# Conflicts:
#	electron/ipc/project/manager.ts
#	electron/ipc/register/export.ts
#	src/lib/exporter/modernVideoExporter.ts
2026-05-08 10:44:13 +07:00
webadderall d03054f723 Speed up Lightning export and relax local media reads 2026-05-08 11:32:04 +10:00
wiiiii123 678ece2f4a fix(export): harden native beta pipeline 2026-05-07 22:37:27 +07:00
wiiiii123 05327a12ce Add native GPU static layout export path 2026-05-03 22:43:23 +07:00
webadderall cd4ea8fc05 Improve HUD and update prompt UI 2026-04-25 21:34:55 +10:00
大彪 1280670740 chore(smoke-export): let the smoke harness open .recordly project files
Previously the smoke-export harness only accepted a raw MP4 input path.
Validating the export pipeline on a real editor project (with its own
zoom regions, wallpaper, annotations, and webcam state) required
opening the editor by hand and clicking through the GUI.

This adds three new environment variables that are picked up by the
existing smoke-export query string plumbing:

- RECORDLY_SMOKE_EXPORT_PROJECT  — path to a .recordly project file;
  when set, the editor opens it via openProjectFileAtPath and applies
  the saved state before the auto-export fires.
- RECORDLY_SMOKE_EXPORT_QUALITY  — overrides the hard-coded "good"
  quality used by the auto-export trigger; accepts medium / good /
  high / source.
- RECORDLY_SMOKE_EXPORT_FPS      — overrides the frame rate; accepts
  24 / 30 / 60.

No behavior change for existing RECORDLY_SMOKE_EXPORT_INPUT runs;
the new inputs are strictly additive and optional. The startup log
line prefers the project path over the raw-input path when both are
populated.
2026-04-24 16:02:37 +08:00
大彪 bd8a941c12 fix(export): stream MP4 output to disk to unblock >2 GiB exports
Long recordings (35-minute screencaps were the motivating case) fail at
the 99% "Finalizing" step with a RangeError once the muxed MP4 would
exceed V8's ~2 GiB per-ArrayBuffer limit. Both export paths accumulate
the whole file in renderer memory and round-trip it through IPC, so no
output size past that point can complete:

- Legacy: src/lib/exporter/muxer.ts uses mediabunny's BufferTarget,
  which holds the entire MP4 in a single ArrayBuffer. finalize() → Blob
  → blob.arrayBuffer() → ipcRenderer.invoke('write-exported-video-to-
  path', arrayBuffer, path) — every step wants a ≥2 GiB contiguous
  allocation.
- Lightning: native-video-export-finish did fs.readFile(finalizedPath)
  and shipped the bytes back to the renderer, which re-serialized them
  again. Same ceiling.

This change moves the finished MP4 across the renderer↔main boundary
via a temp file instead of an ArrayBuffer:

- New electron/ipc/export/exportStream.ts manages streaming temp files
  via fh.write(buf, 0, len, position) so out-of-order writes (moov box
  rewrites, etc.) stay safe. Each session lives in a 0700 mkdtemp()
  directory opened with O_CREAT | O_EXCL so a hostile local user on a
  shared tempdir cannot pre-plant a symlink at the predicted path.
- New renderer-facing IPCs: export-stream-open/write/close,
  finalize-exported-video (renames temp to final path, copy+unlink
  fallback on EXDEV/EPERM/ENOTEMPTY with console.warn on leaked bytes),
  mux-exported-video-audio-from-path (FFmpeg audio fallback that takes
  a path instead of an ArrayBuffer), and discard-exported-temp. Every
  handler validates the caller-supplied path against an owned-export-
  paths registry before touching disk, so a compromised renderer cannot
  route arbitrary filesystem paths into main-process deletes/moves.
- The muxer now picks mediabunny's StreamTarget automatically when the
  Electron bridge is available (BufferTarget stays for tests and any
  non-Electron callers). finalize() returns { mode, tempFilePath,
  bytesWritten } or { mode, blob } so the exporter can branch.
- Exporters forward tempFilePath through ExportResult. Lightning's
  finish returns the ffmpeg temp path directly; the FFmpeg audio
  fallback forks on the muxer result type. modernVideoExporter's
  Lightning success branch now accepts tempFilePath (previously it
  checked blob only, which regressed every native export).
- VideoEditor.tsx dispatches on tempFilePath: finalize via the new IPC,
  keep the temp in place when the save dialog is canceled so "Save
  Again" still works without re-rendering, keep the pending-save entry
  alive on non-canceled save failures, and discard the temp on unmount
  or explicit clear. GIF and smoke-test code paths still use the
  legacy Blob path unchanged.
- app.on('before-quit') also reaps any open streaming sessions via
  cleanupAllExportStreams().

Chunk size is 16 MiB — well under Electron/Mojo IPC message limits
while keeping total writes low (~160 for a 2.5 GB export).

Tested locally: exported a 35:13 source (~2.7 GiB H.264 input) at
Original 1920×1080 + Balanced. Previously failed on finalize with a
RangeError; with this patch the Legacy pipeline produced a valid 3.7
GiB MP4 whose ffmpeg -i duration/streams match the source.

Addresses #194.
2026-04-24 16:02:37 +08:00
webadderall eaa67fce80 Merge pull request #302 from meiiie/fix/linux-wayland-gpu-switches
fix(linux): avoid forcing EGL on Wayland
2026-04-23 12:37:18 +10:00
wiiiii123 4207664c4a fix(recording): recover from fullscreen countdown failures 2026-04-21 20:46:37 +07:00
wiiiii123 de53d398d7 fix(linux): avoid forcing EGL on Wayland 2026-04-21 02:49:08 +07:00
Uri 186b08aa83 fix(linux/wayland): address PR review feedback
- electron/main.ts: treat missing sourceId on linux as portal sentinel
  so the request handler never calls getSources() (which itself opens
  an extra portal dialog) on fresh sessions.
- useScreenRecorder.ts: persist the synthesized portal sentinel via
  selectSource() so main has the source set before getDisplayMedia.
  Extract acquireLinuxPortalStream() helper to dedupe the three
  duplicated getDisplayMedia constraint blocks.
- LaunchWindow.tsx: hide the screen-source selector button (and its
  separator) on Linux so users cannot trigger an extra portal dialog
  via the dropdown.
2026-04-18 16:38:52 +03:00
Uri b6d2aaf5c6 fix(linux/wayland): collapse 3-step capture flow into a single portal dialog
Previously on Linux/Wayland, starting a fullscreen recording required three
separate picker interactions: an in-app source dropdown plus two xdg-desktop-portal
dialogs. The duplicate portal dialogs were caused by:

1. resolveBrowserCaptureSource() calling desktopCapturer.getSources() in the
   renderer, which itself triggers the portal on Wayland.
2. setDisplayMediaRequestHandler() in main also calling getSources(), which
   triggers another portal.
3. Returning a pre-enumerated source id to Chromium, which on Wayland is stale
   and forces Chromium to re-prompt via the portal during MediaStream creation.

Additionally, the editor window failed to appear after recording on some
Wayland sessions because 'ready-to-show' did not fire reliably.

Changes:
- LaunchWindow: skip the in-app source dropdown on Linux and start recording
  directly; the OS portal becomes the source picker.
- useScreenRecorder: introduce a 'screen:linux-portal' sentinel source. When
  set, route capture through navigator.mediaDevices.getDisplayMedia() so the
  portal handles selection in a single dialog. Skip resolveBrowserCaptureSource
  for the sentinel to avoid an extra getSources() call.
- electron/main: in setDisplayMediaRequestHandler, when the sentinel is set,
  skip desktopCapturer.getSources() entirely and return a synthetic source so
  Chromium opens the portal exactly once for the actual capture.
- electron/windows: in createEditorWindow, also call win.show() from
  did-finish-load as a fallback for Linux/Wayland where ready-to-show may
  not fire.
2026-04-18 16:17:08 +03:00
webadderall 596d6faa8d refactor: remove redundant Linux platform guard in GPU config 2026-04-18 22:05:05 +10:00
webadderall dbd5a2a9a2 fix: Linux GPU fallback and HUD window show safety net
- Add Linux GPU config: use EGL (better Wayland compat), disable VAAPI
  video decoder/encoder (many distros ship broken drivers causing
  'vaInitialize failed' and preventing renderer from loading)
- Add ready-to-show fallback for HUD window: if did-finish-load never
  fires (GPU failure), show the window after 500ms via ready-to-show

Ref #261
2026-04-18 21:32:18 +10:00
webadderall 794e2944d6 fix: serve video files via local HTTP server to fix loading on Windows
On Windows, the packaged app serves the renderer from http://127.0.0.1:PORT,
which causes Chromium to block file:// URLs in <video> elements — even with
webSecurity disabled. This affects all users running the packaged build.

Add a local media HTTP server (random port) that streams approved video files
with range request support for seeking. The renderer now resolves video paths
through this server instead of using file:// URLs directly.

- electron/mediaServer.ts: HTTP server with path validation against
  approvedLocalReadPaths and Content-Range support
- IPC handler 'get-local-media-url' converts file paths to HTTP URLs
- resolveVideoUrl() in renderer falls back to file:// if server unavailable
- Improved <video> onError to log actual MediaError details

Fixes #244
2026-04-18 15:55:43 +10:00
webadderall 26f1ce2476 feat: add H.264 stream-copy export, overhaul exporter pipeline, rename native binaries
- IPC: new inputMode 'h264-stream' — browser VideoEncoder output stream-copied
  into MP4 via ffmpeg rather than piping raw RGBA frames, cuts memory usage
- Security: replace flat approvedLocalReadPaths with userApprovedPaths fed from
  dialog pickers and project load; isAllowedLocalReadPath uses it alongside
  dir prefix / existsSync checks
- nativeVideoExport: add buildNativeH264StreamExportArgs for stream-copy path
- frameRenderer / modernFrameRenderer: cursor-follow camera integration,
  annotation blur post-processing, shadow profile, squircle geometry
- audioEncoder / streamingDecoder / gifExporter / muxer: full pipeline
  hardening — drift correction, backpressure, proper teardown
- Rename native helpers openscreen-* → recordly-* on darwin-arm64 and
  darwin-x64; update helpers-manifest.json for win32-x64
- electron/main, windows, updater, rendererServer: startup and window
  lifecycle improvements
- preload: expose inputMode and new IPC surface to renderer
2026-04-16 17:51:41 +10:00
webadderall 18d5a091f8 feat: extension system with marketplace, permissions, and security hardening
- Extension loader with manifest validation, ID sanitization, and path traversal protection
- Permission-gated runtime API (render, cursor, audio, timeline, ui, assets, export)
- Extension host with lifecycle management (activate/deactivate)
- Marketplace client for browsing, downloading, and installing extensions
- Extension Manager UI panel with enable/disable/uninstall
- IPC bridge for extension discovery, management, and marketplace operations
- Proxy guard on window.electronAPI to block extension access to privileged IPC
- Zip-slip protection via post-extraction directory traversal validation
- Safe PowerShell invocation for Windows zip extraction (no string interpolation)
- File URL resolution with path escape prevention
2026-04-12 01:37:28 +10:00
webadderall f56f39ddb3 Hotfix 1.1.17 2026-04-06 18:10:29 +10:00
webadderall e7cd2004fe Improve tray and packaged editor restore paths 2026-04-06 15:22:58 +10:00
webadderall bd7524ca04 Fix Windows tray restore during recording 2026-04-05 23:23:16 +10:00
webadderall de3b396d89 Load packaged renderer over localhost 2026-04-05 18:51:51 +10:00
webadderall 495b714ab8 fix(windows): align Win10 HUD restore with interactive fallback 2026-04-04 17:22:37 +11:00
webadderall e85ceb6497 configure smoke export window boot flow 2026-04-04 13:07:49 +11:00
webadderall c069eb015e fix(electron): Windows HUD visibility - moveTop after show, reassert mouse state on recording start 2026-04-02 21:09:32 +11:00
webadderall 393be9b76a fix(electron): Win10 HUD click-through recovery 2026-04-02 16:29:51 +11:00
webadderall 8709834901 fix: add setDevicePermissionHandler for Windows 11 webcam access
Chromium (Electron 17+) requires setDevicePermissionHandler in addition
to setPermissionCheckHandler/setPermissionRequestHandler. Without it,
device-level access is silently denied on Windows 11 even though the
permission check passes, causing getUserMedia to throw NotAllowedError.
2026-03-30 15:41:01 +11:00
webadderall 3ac1de6996 fix: add Windows camera/microphone permission status logging
- Check systemPreferences.getMediaAccessStatus on Windows startup
- Log warnings when camera/mic access is denied so users know to check
  Windows Settings > Privacy > Camera/Microphone
2026-03-30 15:27:47 +11:00
webadderall 001f86a550 feat(updater): Windows native notifications and toast window fixes
- Use native OS Notification on Windows instead of transparent overlay
  toast window (transparent BrowserWindows are unreliable on Windows)
- Set app user model ID on Windows for proper notification grouping
- Make toast window opaque with solid background on Windows
- Only set transparent body background on macOS for update-toast window
- Refactor UpdateToastWindow to inline styles for Windows compatibility
- Add primaryAction-based button rendering in toast UI
- Add polling fallback for toast payload in UpdateToastWindow
- Add global CSS variables for brand accent color
2026-03-29 19:30:02 +11:00
webadderall cac0126109 fix: TCC permission handling for native helpers on macOS 26
- Add CGPreflightScreenCaptureAccess pre-check in Swift helper
- Add microphone TCC pre-flight when mic capture is requested
- Warm up TCC via desktopCapturer.getSources before spawning helper
- Request mic access from Electron before helper spawn
- Remove unreliable systemPreferences.getMediaAccessStatus pre-checks
- Add camera entitlements to plist files for webcam support
- Guard getScreen() calls behind app.isReady()
- Make tray icons lazy to avoid early screen access
- Suppress duplicate permission error alerts in renderer
2026-03-29 19:15:18 +11:00
webadderall eec536e3b9 fix(desktop): polish editor chrome 2026-03-28 23:24:34 +11:00
webadderall 3e48ea543d fix(updater): remove dev preview auto-toasts 2026-03-28 22:36:04 +11:00
webadderall 33f066464b fix(startup): wait for app readiness before opening hud 2026-03-28 22:02:16 +11:00
webadderall 7bd52918c0 fix(dev): isolate app data paths from production 2026-03-28 22:00:15 +11:00
webadderall b7687605bc fix(updater): resurface dismissed update prompts 2026-03-28 21:22:56 +11:00
webadderall efc89870aa feat(updater): add explicit download toast flow 2026-03-28 21:06:41 +11:00
webadderall 02674009d8 feat: add updater release infrastructure 2026-03-28 20:42:38 +11:00
webadderall 04295afae4 chore(dev): isolate app data in development 2026-03-28 16:11:48 +11:00
webadderall 5ab9368858 chore(updates): add disabled app update infrastructure 2026-03-24 19:32:38 +11:00
webadderall 698f667050 fix(projects): align HUD browser behavior 2026-03-23 21:18:18 +11:00
webadderall 0d90a4b369 Fix webcam sync and app close flow 2026-03-20 11:37:37 +11:00
webadderall 8a5339549d feat(windows): replace WGC with DXGI and fix HUD window bounds 2026-03-18 22:11:10 +11:00
webadderall 285ca3a983 fix: restore cursor fallback and mac mic selection 2026-03-18 21:19:00 +11:00
firtoz 3641818f49 fix(tray): single-click opens window and brings it to front; Linux/Wayland focus workaround
- Add tray.on('click') to call focusOrCreateMainWindow() so left-click
  on the systray icon opens/focuses the app on all platforms (was
  previously only possible via right-click → Open).
- On Linux/Wayland, compositors often ignore focus() for security;
  Electron's tray does not yet handle ProvideXdgActivationToken like
  Qt apps (e.g. Telegram). Workaround: when the HUD exists but is
  not focused, destroy and recreate it so the new window receives
  focus (creation path works). Applied only for the HUD overlay, not
  the editor.
- Reorder: show() before restore(), then moveTop(), focus() for
  more reliable raise-on-restore.

Made-with: Cursor
2026-03-15 22:40:40 +00:00
webadderall 2599ccbf9b fix(startup): enforce single-instance app lock to prevent duplicate menus 2026-03-15 09:52:39 +11:00