From e0ab6d7aeb55c54fc79c7c320497265aa58ffaec Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Wed, 5 Nov 2025 13:09:12 +0000 Subject: [PATCH 01/19] feat: Implement Windows ARM build --- .config/hakari.toml | 1 + .github/workflows/ci.yml | 8 ++- .github/workflows/publish.yml | 27 +++++++- Cargo.lock | 37 ++++++++++ crates/workspace-hack/Cargo.toml | 112 ++++++++++++++++++++++++++++++- scripts/setup.js | 30 +++++---- 6 files changed, 198 insertions(+), 17 deletions(-) diff --git a/.config/hakari.toml b/.config/hakari.toml index 0dea44fe3f..108e078a08 100644 --- a/.config/hakari.toml +++ b/.config/hakari.toml @@ -21,6 +21,7 @@ platforms = [ # "x86_64-apple-darwin", "aarch64-apple-darwin", "x86_64-pc-windows-msvc", + "aarch64-pc-windows-msvc", ] # Write out exact versions rather than a semver range. (Defaults to false.) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed79cdde44..1cc28576b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,6 +106,8 @@ jobs: runner: macos-latest - target: x86_64-pc-windows-msvc runner: windows-latest + - target: aarch64-pc-windows-msvc + runner: windows-latest permissions: contents: read steps: @@ -172,6 +174,8 @@ jobs: runner: macos-latest - target: x86_64-pc-windows-msvc runner: windows-latest + - target: aarch64-pc-windows-msvc + runner: windows-latest runs-on: ${{ matrix.settings.runner }} env: TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} @@ -249,6 +253,8 @@ jobs: runner: macos-latest - target: x86_64-pc-windows-msvc runner: windows-latest + - target: aarch64-pc-windows-msvc + runner: windows-latest runs-on: ${{ matrix.settings.runner }} steps: - name: Checkout @@ -278,7 +284,7 @@ jobs: run: cargo check --all --release - name: Run Clippy - if: ${{ matrix.settings.target == 'aarch64-apple-darwin' || matrix.settings.target == 'x86_64-pc-windows-msvc' }} + if: ${{ matrix.settings.target == 'aarch64-apple-darwin' || matrix.settings.target == 'x86_64-pc-windows-msvc' || matrix.settings.target == 'aarch64-pc-windows-msvc' }} uses: actions-rs-plus/clippy-check@v2 with: args: --workspace --all-features --locked diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a8056edd4d..efa787656a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -8,6 +8,15 @@ on: description: "Discord Interaction ID" required: false type: string + windowsTarget: + description: "Windows build target" + required: false + default: all + type: choice + options: + - all + - x64 + - arm64 env: CN_APPLICATION: cap/cap @@ -129,7 +138,13 @@ jobs: build: needs: draft - if: ${{ needs.draft.outputs.needs_release == 'true' }} + if: ${{ + needs.draft.outputs.needs_release == 'true' && ( + matrix.settings.platform != 'windows' || + inputs.windowsTarget == 'all' || + inputs.windowsTarget == matrix.settings.arch + ) + }} permissions: contents: write actions: read @@ -139,10 +154,20 @@ jobs: settings: - target: x86_64-apple-darwin runner: macos-latest-xlarge + platform: macos + arch: x64 - target: aarch64-apple-darwin runner: macos-latest-xlarge + platform: macos + arch: arm64 - target: x86_64-pc-windows-msvc runner: windows-latest + platform: windows + arch: x64 + - target: aarch64-pc-windows-msvc + runner: windows-latest + platform: windows + arch: arm64 env: TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TEAM: ${{ secrets.TURBO_TEAM }} diff --git a/Cargo.lock b/Cargo.lock index a2db981426..6eba11b9d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11856,25 +11856,37 @@ dependencies = [ "arrayvec", "axum", "bitflags 2.9.4", + "block2 0.6.1", "bytemuck", "chrono", "clang-sys", "clap", "clap_builder", + "concurrent-queue", + "core-foundation 0.9.4", + "core-foundation-sys", + "crossbeam-utils", "deranged", + "dispatch2", "either", "flate2", "form_urlencoded", "futures-channel", "futures-core", "futures-executor", + "futures-io", "futures-sink", "futures-task", "futures-util", "getrandom 0.2.16", + "getrandom 0.3.3", "gif", + "half", "hashbrown 0.15.5", + "hyper 1.7.0", + "hyper-util", "idna", + "indexmap 2.11.4", "itertools 0.12.1", "itertools 0.13.0", "libc", @@ -11884,6 +11896,14 @@ dependencies = [ "nom", "num-rational", "num-traits", + "objc", + "objc2 0.6.2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-foundation 0.3.1", + "objc2-quartz-core 0.3.1", + "once_cell", "percent-encoding", "phf_shared 0.10.0", "phf_shared 0.11.3", @@ -11897,7 +11917,9 @@ dependencies = [ "reqwest 0.12.24", "rgb", "rustc-hash 1.1.0", + "rustix 1.1.2", "schemars 0.8.22", + "scopeguard", "semver", "serde", "serde_core", @@ -11907,15 +11929,30 @@ dependencies = [ "specta", "specta-macros", "stable_deref_trait", + "swift-rs", "syn 2.0.106", "tauri-utils", "thiserror 2.0.16", "time", "tokio", + "tokio-util", + "tower", "tracing", "tracing-core", "tracing-subscriber", "uuid", + "winapi", + "windows 0.58.0", + "windows 0.60.0", + "windows-core 0.60.1", + "windows-core 0.61.2", + "windows-result 0.3.4", + "windows-strings 0.4.2", + "windows-sys 0.48.0", + "windows-sys 0.52.0", + "windows-sys 0.59.0", + "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] diff --git a/crates/workspace-hack/Cargo.toml b/crates/workspace-hack/Cargo.toml index 32e6b341b5..dcd700df36 100644 --- a/crates/workspace-hack/Cargo.toml +++ b/crates/workspace-hack/Cargo.toml @@ -32,7 +32,7 @@ futures-executor = { version = "0.3" } futures-sink = { version = "0.3" } futures-task = { version = "0.3" } futures-util = { version = "0.3", features = ["channel", "io", "sink"] } -getrandom = { version = "0.2", default-features = false, features = ["js", "rdrand", "std"] } +getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-features = false, features = ["js", "rdrand", "std"] } gif = { version = "0.13" } hashbrown = { version = "0.15", default-features = false, features = ["default-hasher", "inline-more"] } idna = { version = "1" } @@ -81,7 +81,7 @@ clang-sys = { version = "1", default-features = false, features = ["clang_11_0", either = { version = "1", features = ["use_std"] } flate2 = { version = "1", features = ["zlib-rs"] } form_urlencoded = { version = "1" } -getrandom = { version = "0.2", default-features = false, features = ["js", "rdrand", "std"] } +getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-features = false, features = ["js", "rdrand", "std"] } hashbrown = { version = "0.15", default-features = false, features = ["default-hasher", "inline-more"] } idna = { version = "1" } itertools-594e8ee84c453af0 = { package = "itertools", version = "0.13" } @@ -115,4 +115,112 @@ tauri-utils = { version = "2", default-features = false, features = ["build", "c thiserror = { version = "2" } uuid = { version = "1", features = ["serde", "v4", "v7"] } +[target.aarch64-apple-darwin.dependencies] +block2 = { version = "0.6" } +core-foundation = { version = "0.9" } +core-foundation-sys = { version = "0.8" } +dispatch2 = { version = "0.3" } +futures-io = { version = "0.3" } +getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] } +half = { version = "2", features = ["num-traits"] } +hyper = { version = "1", features = ["client", "http1", "http2", "server"] } +hyper-util = { version = "0.1", features = ["client-legacy", "client-proxy", "client-proxy-system", "http1", "http2", "server", "service"] } +indexmap = { version = "2" } +libc = { version = "0.2", default-features = false, features = ["extra_traits"] } +num-traits = { version = "0.2", default-features = false, features = ["libm"] } +objc = { version = "0.2", default-features = false, features = ["exception"] } +objc2 = { version = "0.6", features = ["disable-encoding-assertions", "exception"] } +objc2-core-foundation = { version = "0.3", default-features = false, features = ["CFArray", "CFBase", "CFCGTypes", "CFData", "CFDate", "CFDictionary", "CFError", "CFRunLoop", "CFString", "CFURL", "CFUserNotification", "objc2", "std"] } +objc2-core-graphics = { version = "0.3", default-features = false, features = ["CGColor", "CGColorSpace", "CGContext", "CGDataProvider", "CGDirectDisplay", "CGEventTypes", "CGFont", "CGImage", "CGPath", "objc2", "std"] } +objc2-core-image = { version = "0.3", default-features = false, features = ["CIBarcodeDescriptor", "CIColor", "CIContext", "CIFilter", "CIImage"] } +objc2-foundation = { version = "0.3" } +objc2-quartz-core = { version = "0.3", default-features = false, features = ["CADisplayLink", "CALayer", "CAMediaTiming", "CAMediaTimingFunction"] } +once_cell = { version = "1" } +rustix = { version = "1", features = ["event", "fs", "pipe", "process", "system", "time"] } +scopeguard = { version = "1" } +swift-rs = { version = "1", features = ["build"] } +tokio-util = { version = "0.7", features = ["codec", "io"] } +tower = { version = "0.5", default-features = false, features = ["log", "make", "retry", "timeout"] } + +[target.aarch64-apple-darwin.build-dependencies] +deranged = { version = "0.5", features = ["powerfmt", "serde"] } +getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] } +indexmap = { version = "2" } +libc = { version = "0.2", default-features = false, features = ["extra_traits"] } +scopeguard = { version = "1" } +swift-rs = { version = "1", features = ["build"] } +time = { version = "0.3", features = ["formatting", "macros", "parsing", "serde"] } + +[target.x86_64-pc-windows-msvc.dependencies] +concurrent-queue = { version = "2" } +crossbeam-utils = { version = "0.8" } +futures-io = { version = "0.3" } +getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] } +half = { version = "2", features = ["num-traits"] } +hyper = { version = "1", features = ["client", "http1", "http2", "server"] } +hyper-util = { version = "0.1", features = ["client-legacy", "client-proxy", "client-proxy-system", "http1", "http2", "server", "service"] } +indexmap = { version = "2" } +num-traits = { version = "0.2", default-features = false, features = ["libm"] } +once_cell = { version = "1" } +smallvec = { version = "1", default-features = false, features = ["union"] } +tokio-util = { version = "0.7", features = ["codec", "io"] } +tower = { version = "0.5", default-features = false, features = ["log", "make", "retry", "timeout"] } +winapi = { version = "0.3", default-features = false, features = ["consoleapi", "handleapi", "impl-default", "libloaderapi", "memoryapi", "processenv", "processthreadsapi", "psapi", "synchapi", "winbase", "wincon", "winerror", "winuser"] } +windows-332723e2a07a5e2a = { package = "windows", version = "0.58", features = ["Win32_Graphics_Direct3D12", "Win32_Graphics_Direct3D_Dxc", "Win32_Graphics_Direct3D_Fxc", "Win32_Graphics_DirectComposition", "Win32_Graphics_Dxgi_Common", "Win32_Graphics_Gdi", "Win32_Graphics_OpenGL", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Diagnostics_Debug", "Win32_System_Kernel", "Win32_System_LibraryLoader", "Win32_System_Performance", "Win32_System_Pipes", "Win32_System_Threading", "Win32_System_WindowsProgramming", "Win32_UI_WindowsAndMessaging"] } +windows-4db8c43aad08e7ae = { package = "windows", version = "0.60", features = ["Foundation_Collections", "Foundation_Metadata", "Graphics_Capture", "Graphics_DirectX_Direct3D11", "Media_Core", "Media_MediaProperties", "Media_Transcoding", "Security_Authorization_AppCapabilityAccess", "Storage_Search", "Storage_Streams", "System", "Win32_Graphics_Direct3D", "Win32_Graphics_Direct3D11", "Win32_Graphics_Dwm", "Win32_Graphics_Dxgi_Common", "Win32_Graphics_Gdi", "Win32_Media_DirectShow", "Win32_Media_DxMediaObjects", "Win32_Media_KernelStreaming", "Win32_Media_MediaFoundation", "Win32_Storage_FileSystem", "Win32_System_Com_StructuredStorage", "Win32_System_Diagnostics_Debug", "Win32_System_Ole", "Win32_System_Performance", "Win32_System_Threading", "Win32_System_Variant", "Win32_System_WinRT_Direct3D11", "Win32_System_WinRT_Graphics_Capture", "Win32_UI_HiDpi", "Win32_UI_Input_KeyboardAndMouse", "Win32_UI_Shell", "Win32_UI_WindowsAndMessaging"] } +windows-core-4db8c43aad08e7ae = { package = "windows-core", version = "0.60" } +windows-core-d4189bed749088b6 = { package = "windows-core", version = "0.61" } +windows-result = { version = "0.3" } +windows-strings = { version = "0.4", default-features = false, features = ["std"] } +windows-sys-4db8c43aad08e7ae = { package = "windows-sys", version = "0.60", features = ["Win32_Globalization", "Win32_Graphics_Gdi", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Console", "Win32_System_DataExchange", "Win32_System_LibraryLoader", "Win32_System_Memory", "Win32_System_Ole", "Win32_System_SystemServices", "Win32_System_Threading", "Win32_UI_Accessibility", "Win32_UI_Controls", "Win32_UI_HiDpi", "Win32_UI_Input_KeyboardAndMouse", "Win32_UI_Shell", "Win32_UI_WindowsAndMessaging"] } +windows-sys-73dcd821b1037cfd = { package = "windows-sys", version = "0.59", features = ["Wdk_Foundation", "Wdk_Storage_FileSystem", "Wdk_System_IO", "Win32_Graphics_Dwm", "Win32_Graphics_Gdi", "Win32_NetworkManagement_IpHelper", "Win32_Networking_WinSock", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Com", "Win32_System_Diagnostics_Debug", "Win32_System_IO", "Win32_System_LibraryLoader", "Win32_System_Pipes", "Win32_System_Registry", "Win32_System_SystemInformation", "Win32_System_SystemServices", "Win32_System_Threading", "Win32_System_Time", "Win32_System_WindowsProgramming", "Win32_UI_Controls", "Win32_UI_Input_KeyboardAndMouse", "Win32_UI_Shell_Common", "Win32_UI_WindowsAndMessaging"] } +windows-sys-b21d60becc0929df = { package = "windows-sys", version = "0.52", features = ["Win32_Foundation", "Win32_Networking_WinSock", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Console", "Win32_System_IO", "Win32_System_LibraryLoader", "Win32_System_Registry", "Win32_System_SystemInformation", "Win32_System_SystemServices", "Win32_System_Threading", "Win32_System_WindowsProgramming", "Win32_UI_WindowsAndMessaging"] } +windows-sys-c8eced492e86ede7 = { package = "windows-sys", version = "0.48", features = ["Win32_Foundation", "Win32_Globalization", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Com", "Win32_System_Console", "Win32_System_Diagnostics_Debug", "Win32_System_Registry", "Win32_System_SystemInformation", "Win32_System_Time", "Win32_UI_Shell"] } +windows-sys-d4189bed749088b6 = { package = "windows-sys", version = "0.61", features = ["Wdk_Foundation", "Wdk_Storage_FileSystem", "Win32_Globalization", "Win32_Networking_WinSock", "Win32_Security_Authentication_Identity", "Win32_Security_Credentials", "Win32_Security_Cryptography", "Win32_Storage_FileSystem", "Win32_System_Com", "Win32_System_Diagnostics_Debug", "Win32_System_IO", "Win32_System_LibraryLoader", "Win32_System_Memory", "Win32_System_SystemInformation", "Win32_System_Threading", "Win32_System_WindowsProgramming", "Win32_UI_Shell"] } + +[target.x86_64-pc-windows-msvc.build-dependencies] +getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] } +indexmap = { version = "2" } +once_cell = { version = "1" } +smallvec = { version = "1", default-features = false, features = ["union"] } +windows-sys-73dcd821b1037cfd = { package = "windows-sys", version = "0.59", features = ["Wdk_Foundation", "Wdk_Storage_FileSystem", "Wdk_System_IO", "Win32_Graphics_Dwm", "Win32_Graphics_Gdi", "Win32_NetworkManagement_IpHelper", "Win32_Networking_WinSock", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Com", "Win32_System_Diagnostics_Debug", "Win32_System_IO", "Win32_System_LibraryLoader", "Win32_System_Pipes", "Win32_System_Registry", "Win32_System_SystemInformation", "Win32_System_SystemServices", "Win32_System_Threading", "Win32_System_Time", "Win32_System_WindowsProgramming", "Win32_UI_Controls", "Win32_UI_Input_KeyboardAndMouse", "Win32_UI_Shell_Common", "Win32_UI_WindowsAndMessaging"] } +windows-sys-c8eced492e86ede7 = { package = "windows-sys", version = "0.48", features = ["Win32_Foundation", "Win32_Globalization", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Com", "Win32_System_Console", "Win32_System_Diagnostics_Debug", "Win32_System_Registry", "Win32_System_SystemInformation", "Win32_System_Time", "Win32_UI_Shell"] } +windows-sys-d4189bed749088b6 = { package = "windows-sys", version = "0.61", features = ["Wdk_Foundation", "Wdk_Storage_FileSystem", "Win32_Globalization", "Win32_Networking_WinSock", "Win32_Security_Authentication_Identity", "Win32_Security_Credentials", "Win32_Security_Cryptography", "Win32_Storage_FileSystem", "Win32_System_Com", "Win32_System_Diagnostics_Debug", "Win32_System_IO", "Win32_System_LibraryLoader", "Win32_System_Memory", "Win32_System_SystemInformation", "Win32_System_Threading", "Win32_System_WindowsProgramming", "Win32_UI_Shell"] } + +[target.aarch64-pc-windows-msvc.dependencies] +concurrent-queue = { version = "2" } +crossbeam-utils = { version = "0.8" } +futures-io = { version = "0.3" } +getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] } +half = { version = "2", features = ["num-traits"] } +hyper = { version = "1", features = ["client", "http1", "http2", "server"] } +hyper-util = { version = "0.1", features = ["client-legacy", "client-proxy", "client-proxy-system", "http1", "http2", "server", "service"] } +indexmap = { version = "2" } +num-traits = { version = "0.2", default-features = false, features = ["libm"] } +once_cell = { version = "1" } +smallvec = { version = "1", default-features = false, features = ["union"] } +tokio-util = { version = "0.7", features = ["codec", "io"] } +tower = { version = "0.5", default-features = false, features = ["log", "make", "retry", "timeout"] } +winapi = { version = "0.3", default-features = false, features = ["consoleapi", "handleapi", "impl-default", "libloaderapi", "memoryapi", "processenv", "processthreadsapi", "psapi", "synchapi", "winbase", "wincon", "winerror", "winuser"] } +windows-332723e2a07a5e2a = { package = "windows", version = "0.58", features = ["Win32_Graphics_Direct3D12", "Win32_Graphics_Direct3D_Dxc", "Win32_Graphics_Direct3D_Fxc", "Win32_Graphics_DirectComposition", "Win32_Graphics_Dxgi_Common", "Win32_Graphics_Gdi", "Win32_Graphics_OpenGL", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Diagnostics_Debug", "Win32_System_Kernel", "Win32_System_LibraryLoader", "Win32_System_Performance", "Win32_System_Pipes", "Win32_System_Threading", "Win32_System_WindowsProgramming", "Win32_UI_WindowsAndMessaging"] } +windows-4db8c43aad08e7ae = { package = "windows", version = "0.60", features = ["Foundation_Collections", "Foundation_Metadata", "Graphics_Capture", "Graphics_DirectX_Direct3D11", "Media_Core", "Media_MediaProperties", "Media_Transcoding", "Security_Authorization_AppCapabilityAccess", "Storage_Search", "Storage_Streams", "System", "Win32_Graphics_Direct3D", "Win32_Graphics_Direct3D11", "Win32_Graphics_Dwm", "Win32_Graphics_Dxgi_Common", "Win32_Graphics_Gdi", "Win32_Media_DirectShow", "Win32_Media_DxMediaObjects", "Win32_Media_KernelStreaming", "Win32_Media_MediaFoundation", "Win32_Storage_FileSystem", "Win32_System_Com_StructuredStorage", "Win32_System_Diagnostics_Debug", "Win32_System_Ole", "Win32_System_Performance", "Win32_System_Threading", "Win32_System_Variant", "Win32_System_WinRT_Direct3D11", "Win32_System_WinRT_Graphics_Capture", "Win32_UI_HiDpi", "Win32_UI_Input_KeyboardAndMouse", "Win32_UI_Shell", "Win32_UI_WindowsAndMessaging"] } +windows-core-4db8c43aad08e7ae = { package = "windows-core", version = "0.60" } +windows-core-d4189bed749088b6 = { package = "windows-core", version = "0.61" } +windows-result = { version = "0.3" } +windows-strings = { version = "0.4", default-features = false, features = ["std"] } +windows-sys-4db8c43aad08e7ae = { package = "windows-sys", version = "0.60", features = ["Win32_Globalization", "Win32_Graphics_Gdi", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Console", "Win32_System_DataExchange", "Win32_System_LibraryLoader", "Win32_System_Memory", "Win32_System_Ole", "Win32_System_SystemServices", "Win32_System_Threading", "Win32_UI_Accessibility", "Win32_UI_Controls", "Win32_UI_HiDpi", "Win32_UI_Input_KeyboardAndMouse", "Win32_UI_Shell", "Win32_UI_WindowsAndMessaging"] } +windows-sys-73dcd821b1037cfd = { package = "windows-sys", version = "0.59", features = ["Wdk_Foundation", "Wdk_Storage_FileSystem", "Wdk_System_IO", "Win32_Graphics_Dwm", "Win32_Graphics_Gdi", "Win32_NetworkManagement_IpHelper", "Win32_Networking_WinSock", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Com", "Win32_System_Diagnostics_Debug", "Win32_System_IO", "Win32_System_LibraryLoader", "Win32_System_Pipes", "Win32_System_Registry", "Win32_System_SystemInformation", "Win32_System_SystemServices", "Win32_System_Threading", "Win32_System_Time", "Win32_System_WindowsProgramming", "Win32_UI_Controls", "Win32_UI_Input_KeyboardAndMouse", "Win32_UI_Shell_Common", "Win32_UI_WindowsAndMessaging"] } +windows-sys-b21d60becc0929df = { package = "windows-sys", version = "0.52", features = ["Win32_Foundation", "Win32_Networking_WinSock", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Console", "Win32_System_IO", "Win32_System_LibraryLoader", "Win32_System_Registry", "Win32_System_SystemInformation", "Win32_System_SystemServices", "Win32_System_Threading", "Win32_System_WindowsProgramming", "Win32_UI_WindowsAndMessaging"] } +windows-sys-c8eced492e86ede7 = { package = "windows-sys", version = "0.48", features = ["Win32_Foundation", "Win32_Globalization", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Com", "Win32_System_Console", "Win32_System_Diagnostics_Debug", "Win32_System_Registry", "Win32_System_SystemInformation", "Win32_System_Time", "Win32_UI_Shell"] } +windows-sys-d4189bed749088b6 = { package = "windows-sys", version = "0.61", features = ["Wdk_Foundation", "Wdk_Storage_FileSystem", "Win32_Globalization", "Win32_Networking_WinSock", "Win32_Security_Authentication_Identity", "Win32_Security_Credentials", "Win32_Security_Cryptography", "Win32_Storage_FileSystem", "Win32_System_Com", "Win32_System_Diagnostics_Debug", "Win32_System_IO", "Win32_System_LibraryLoader", "Win32_System_Memory", "Win32_System_SystemInformation", "Win32_System_Threading", "Win32_System_WindowsProgramming", "Win32_UI_Shell"] } + +[target.aarch64-pc-windows-msvc.build-dependencies] +getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-features = false, features = ["std"] } +indexmap = { version = "2" } +once_cell = { version = "1" } +smallvec = { version = "1", default-features = false, features = ["union"] } +windows-sys-73dcd821b1037cfd = { package = "windows-sys", version = "0.59", features = ["Wdk_Foundation", "Wdk_Storage_FileSystem", "Wdk_System_IO", "Win32_Graphics_Dwm", "Win32_Graphics_Gdi", "Win32_NetworkManagement_IpHelper", "Win32_Networking_WinSock", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Com", "Win32_System_Diagnostics_Debug", "Win32_System_IO", "Win32_System_LibraryLoader", "Win32_System_Pipes", "Win32_System_Registry", "Win32_System_SystemInformation", "Win32_System_SystemServices", "Win32_System_Threading", "Win32_System_Time", "Win32_System_WindowsProgramming", "Win32_UI_Controls", "Win32_UI_Input_KeyboardAndMouse", "Win32_UI_Shell_Common", "Win32_UI_WindowsAndMessaging"] } +windows-sys-c8eced492e86ede7 = { package = "windows-sys", version = "0.48", features = ["Win32_Foundation", "Win32_Globalization", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Com", "Win32_System_Console", "Win32_System_Diagnostics_Debug", "Win32_System_Registry", "Win32_System_SystemInformation", "Win32_System_Time", "Win32_UI_Shell"] } +windows-sys-d4189bed749088b6 = { package = "windows-sys", version = "0.61", features = ["Wdk_Foundation", "Wdk_Storage_FileSystem", "Win32_Globalization", "Win32_Networking_WinSock", "Win32_Security_Authentication_Identity", "Win32_Security_Credentials", "Win32_Security_Cryptography", "Win32_Storage_FileSystem", "Win32_System_Com", "Win32_System_Diagnostics_Debug", "Win32_System_IO", "Win32_System_LibraryLoader", "Win32_System_Memory", "Win32_System_SystemInformation", "Win32_System_Threading", "Win32_System_WindowsProgramming", "Win32_UI_Shell"] } + ### END HAKARI SECTION diff --git a/scripts/setup.js b/scripts/setup.js index 235ce33af8..48176612d8 100644 --- a/scripts/setup.js +++ b/scripts/setup.js @@ -90,29 +90,33 @@ async function main() { } console.log("Copied ffmpeg dylibs to target/debug"); } else if (process.platform === "win32") { - const FFMPEG_VERSION = "7.1"; - const FFMPEG_ZIP_NAME = `ffmpeg-${FFMPEG_VERSION}-full_build-shared`; - const FFMPEG_ZIP_URL = `https://github.com/GyanD/codexffmpeg/releases/download/${FFMPEG_VERSION}/${FFMPEG_ZIP_NAME}.zip`; + const FFMPEG_RELEASE_TAG = "latest"; + const ffmpegAssets = { + aarch64: "ffmpeg-n7.1-latest-winarm64-gpl-shared-7.1.zip", + x86_64: "ffmpeg-n7.1-latest-win64-gpl-shared-7.1.zip", + }; + const ffmpegZipName = ffmpegAssets[arch] ?? ffmpegAssets.x86_64; + const ffmpegExtractedDir = ffmpegZipName.replace(/\.zip$/, ""); + const ffmpegZipUrl = `https://github.com/BtbN/FFmpeg-Builds/releases/download/${FFMPEG_RELEASE_TAG}/${ffmpegZipName}`; await fs.mkdir(targetDir, { recursive: true }); let downloadedFfmpeg = false; - const ffmpegZip = `ffmpeg-${FFMPEG_VERSION}.zip`; - const ffmpegZipPath = path.join(targetDir, ffmpegZip); + const ffmpegZipPath = path.join(targetDir, ffmpegZipName); if (!(await fileExists(ffmpegZipPath))) { - const ffmpegZipBytes = await fetch(FFMPEG_ZIP_URL) + const ffmpegZipBytes = await fetch(ffmpegZipUrl) .then((r) => r.blob()) .then((b) => b.arrayBuffer()); await fs.writeFile(ffmpegZipPath, Buffer.from(ffmpegZipBytes)); - console.log(`Downloaded ${ffmpegZip}`); + console.log(`Downloaded ${ffmpegZipName}`); downloadedFfmpeg = true; - } else console.log(`Using cached ${ffmpegZip}`); + } else console.log(`Using cached ${ffmpegZipName}`); const ffmpegDir = path.join(targetDir, "ffmpeg"); if (!(await fileExists(ffmpegDir)) || downloadedFfmpeg) { await execFile("tar", ["xf", ffmpegZipPath, "-C", targetDir]); await fs.rm(ffmpegDir, { recursive: true, force: true }).catch(() => {}); - await fs.rename(path.join(targetDir, FFMPEG_ZIP_NAME), ffmpegDir); + await fs.rename(path.join(targetDir, ffmpegExtractedDir), ffmpegDir); console.log("Extracted ffmpeg"); } else console.log("Using cached ffmpeg"); @@ -147,10 +151,10 @@ async function main() { ); console.log("Copied ffmpeg/lib and ffmpeg/include to target/native-deps"); - const { stdout: vcInstallDir } = await exec( - '$(& "${env:ProgramFiles(x86)}/Microsoft Visual Studio/Installer/vswhere.exe" -latest -property installationPath)', - { shell: "powershell.exe" }, - ); + const vsWhereCommand = `$(& "\${env:ProgramFiles(x86)}/Microsoft Visual Studio/Installer/vswhere.exe" -latest -property installationPath)`; + const { stdout: vcInstallDir } = await exec(vsWhereCommand, { + shell: "powershell.exe", + }); const libclangPath = path.join( vcInstallDir.trim(), From e72266618712d2e7eff54b2dcce18190ec62ea2b Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Wed, 5 Nov 2025 13:13:45 +0000 Subject: [PATCH 02/19] Update publish.yml --- .github/workflows/publish.yml | 78 +++++++++++++++++------------------ 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index efa787656a..9311f585a3 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -136,45 +136,45 @@ jobs: main(); - build: - needs: draft - if: ${{ - needs.draft.outputs.needs_release == 'true' && ( - matrix.settings.platform != 'windows' || - inputs.windowsTarget == 'all' || - inputs.windowsTarget == matrix.settings.arch - ) - }} - permissions: - contents: write - actions: read - strategy: - fail-fast: false - matrix: - settings: - - target: x86_64-apple-darwin - runner: macos-latest-xlarge - platform: macos - arch: x64 - - target: aarch64-apple-darwin - runner: macos-latest-xlarge - platform: macos - arch: arm64 - - target: x86_64-pc-windows-msvc - runner: windows-latest - platform: windows - arch: x64 - - target: aarch64-pc-windows-msvc - runner: windows-latest - platform: windows - arch: arm64 - env: - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - runs-on: ${{ matrix.settings.runner }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 +build: + needs: draft + if: ${{ + needs.draft.outputs.needs_release == 'true' && ( + matrix.settings.platform != 'windows' || + inputs.windowsTarget == 'all' || + inputs.windowsTarget == matrix.settings.arch + ) + }} + permissions: + contents: write + actions: read + strategy: + fail-fast: false + matrix: + settings: + - target: x86_64-apple-darwin + runner: macos-latest-xlarge + platform: macos + arch: x64 + - target: aarch64-apple-darwin + runner: macos-latest-xlarge + platform: macos + arch: arm64 + - target: x86_64-pc-windows-msvc + runner: windows-latest + platform: windows + arch: x64 + - target: aarch64-pc-windows-msvc + runner: windows-latest + platform: windows + arch: arm64 + env: + TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + TURBO_TEAM: ${{ secrets.TURBO_TEAM }} + runs-on: ${{ matrix.settings.runner }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 - name: Create API Key File run: echo "${{ secrets.APPLE_API_KEY_FILE }}" > api.p8 From 5b1f707bf9ff51b0593b4191101405d45288cfa0 Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Wed, 5 Nov 2025 13:21:28 +0000 Subject: [PATCH 03/19] Update publish.yml --- .github/workflows/publish.yml | 178 ++++++++++++++++++---------------- 1 file changed, 94 insertions(+), 84 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 9311f585a3..a0f7d31a0b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -47,12 +47,13 @@ jobs: - name: Create tag id: create_tag - if: ${{ steps.create_tag.outputs.tag_existed != 'true' }} uses: actions/github-script@v7 with: script: | - const tag = "cap-v${{ steps.read_version.outputs.value }}"; + const version = "${{ steps.read_version.outputs.value }}"; + const tag = `cap-v${version}`; const tagRef = `tags/${tag}`; + const appCargoToml = "${{ env.APP_CARGO_TOML }}"; const TAG_EXISTED = "tag_existed"; const TAG_NAME = "tag_name"; @@ -69,25 +70,30 @@ jobs: repo: context.repo.repo, }); - tagExisted = true; - core.notice(`Release skipped as tag '${tag}' already exists. Update the version in '${{ env.APP_CARGO_TOML }}' before starting another release.`); + core.notice( + `Release skipped as tag '${tag}' already exists. Update the version in '${appCargoToml}' before starting another release.`, + ); } catch (error) { - if ("status" in error && error.status === 404) tagExisted = false; - else throw error; + if ("status" in error && error.status === 404) { + tagExisted = false; + } else { + throw error; + } } - core.setOutput(TAG_EXISTED, tagExisted); + core.setOutput(TAG_EXISTED, tagExisted); - if (!tagExisted) + if (!tagExisted) { await github.rest.git.createRef({ ref: `refs/${tagRef}`, owner: context.repo.owner, repo: context.repo.repo, sha: context.sha, }); + } } - main(); + await main(); - name: Create draft CN release id: create_cn_release @@ -115,66 +121,65 @@ jobs: const token = await core.getIDToken("cap-discord-bot"); const cnReleaseId = JSON.parse(`${{ steps.create_cn_release.outputs.stdout }}`).id; - const resp = await fetch("https://cap-discord-bot.brendonovich.workers.dev/github-workflow", { - method: "POST", - body: JSON.stringify({ - type: "release-ready", - tag: "${{ steps.create_tag.outputs.tag_name }}", - version: "${{ steps.read_version.outputs.value }}", - releaseUrl: "${{ steps.create_gh_release.outputs.url }}", - interactionId: "${{ inputs.interactionId }}", - cnReleaseId - }), - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - } - }); - - if(resp.status !== 200) throw new Error(await resp.text()); + const resp = await fetch( + "https://cap-discord-bot.brendonovich.workers.dev/github-workflow", + { + method: "POST", + body: JSON.stringify({ + type: "release-ready", + tag: "${{ steps.create_tag.outputs.tag_name }}", + version: "${{ steps.read_version.outputs.value }}", + releaseUrl: "${{ steps.create_gh_release.outputs.url }}", + interactionId: "${{ inputs.interactionId }}", + cnReleaseId, + }), + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }, + ); + + if (resp.status !== 200) { + throw new Error(await resp.text()); + } } - main(); - -build: - needs: draft - if: ${{ - needs.draft.outputs.needs_release == 'true' && ( - matrix.settings.platform != 'windows' || - inputs.windowsTarget == 'all' || - inputs.windowsTarget == matrix.settings.arch - ) - }} - permissions: - contents: write - actions: read - strategy: - fail-fast: false - matrix: - settings: - - target: x86_64-apple-darwin - runner: macos-latest-xlarge - platform: macos - arch: x64 - - target: aarch64-apple-darwin - runner: macos-latest-xlarge - platform: macos - arch: arm64 - - target: x86_64-pc-windows-msvc - runner: windows-latest - platform: windows - arch: x64 - - target: aarch64-pc-windows-msvc - runner: windows-latest - platform: windows - arch: arm64 - env: - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - runs-on: ${{ matrix.settings.runner }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 + await main(); + + build: + needs: draft + if: ${{ needs.draft.outputs.needs_release == 'true' && (matrix.settings.platform != 'windows' || inputs.windowsTarget == 'all' || inputs.windowsTarget == matrix.settings.arch) }} + permissions: + contents: write + actions: read + strategy: + fail-fast: false + matrix: + settings: + - target: x86_64-apple-darwin + runner: macos-latest-xlarge + platform: macos + arch: x64 + - target: aarch64-apple-darwin + runner: macos-latest-xlarge + platform: macos + arch: arm64 + - target: x86_64-pc-windows-msvc + runner: windows-latest + platform: windows + arch: x64 + - target: aarch64-pc-windows-msvc + runner: windows-latest + platform: windows + arch: arm64 + env: + TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + TURBO_TEAM: ${{ secrets.TURBO_TEAM }} + runs-on: ${{ matrix.settings.runner }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 - name: Create API Key File run: echo "${{ secrets.APPLE_API_KEY_FILE }}" > api.p8 @@ -322,22 +327,27 @@ build: const token = await core.getIDToken("cap-discord-bot"); const cnReleaseId = JSON.parse(`${{ needs.draft.outputs.cn_release_stdout }}`).id; - const resp = await fetch("https://cap-discord-bot.brendonovich.workers.dev/github-workflow", { - method: "POST", - body: JSON.stringify({ - type: "release-done", - interactionId: "${{ inputs.interactionId }}", - version: "${{ needs.draft.outputs.version }}", - releaseUrl: "${{ needs.draft.outputs.gh_release_url }}", - cnReleaseId - }), - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - } - }); - - if(resp.status !== 200) throw new Error(await resp.text()); + const resp = await fetch( + "https://cap-discord-bot.brendonovich.workers.dev/github-workflow", + { + method: "POST", + body: JSON.stringify({ + type: "release-done", + interactionId: "${{ inputs.interactionId }}", + version: "${{ needs.draft.outputs.version }}", + releaseUrl: "${{ needs.draft.outputs.gh_release_url }}", + cnReleaseId, + }), + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }, + ); + + if (resp.status !== 200) { + throw new Error(await resp.text()); + } } - main(); + await main(); From 98730ff1b614210bb1821b2e546f66737f5bc3a7 Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Wed, 5 Nov 2025 13:24:11 +0000 Subject: [PATCH 04/19] Update publish.yml --- .github/workflows/publish.yml | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a0f7d31a0b..7d8f2c5710 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -149,7 +149,7 @@ jobs: build: needs: draft - if: ${{ needs.draft.outputs.needs_release == 'true' && (matrix.settings.platform != 'windows' || inputs.windowsTarget == 'all' || inputs.windowsTarget == matrix.settings.arch) }} + if: ${{ needs.draft.outputs.needs_release == 'true' }} permissions: contents: write actions: read @@ -176,36 +176,43 @@ jobs: env: TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TEAM: ${{ secrets.TURBO_TEAM }} + RUN_BUILD: ${{ matrix.settings.platform != 'windows' || inputs.windowsTarget == 'all' || inputs.windowsTarget == matrix.settings.arch }} runs-on: ${{ matrix.settings.runner }} steps: - name: Checkout repository + if: ${{ env.RUN_BUILD == 'true' }} uses: actions/checkout@v4 - name: Create API Key File + if: ${{ env.RUN_BUILD == 'true' }} run: echo "${{ secrets.APPLE_API_KEY_FILE }}" > api.p8 - uses: apple-actions/import-codesign-certs@v2 - if: ${{ matrix.settings.runner == 'macos-latest-xlarge' }} + if: ${{ env.RUN_BUILD == 'true' && matrix.settings.runner == 'macos-latest-xlarge' }} with: p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }} p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - name: Verify certificate - if: ${{ matrix.settings.runner == 'macos-latest-xlarge' }} + if: ${{ env.RUN_BUILD == 'true' && matrix.settings.runner == 'macos-latest-xlarge' }} run: security find-identity -v -p codesigning ${{ runner.temp }}/build.keychain - name: Rust setup + if: ${{ env.RUN_BUILD == 'true' }} uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.settings.target }} - uses: ./.github/actions/setup-rust-cache + if: ${{ env.RUN_BUILD == 'true' }} with: target: ${{ matrix.settings.target }} - uses: ./.github/actions/setup-js + if: ${{ env.RUN_BUILD == 'true' }} - name: Create .env file in root + if: ${{ env.RUN_BUILD == 'true' }} run: | echo "appVersion=${{ needs.draft.outputs.version }}" >> .env echo "VITE_ENVIRONMENT=production" >> .env @@ -218,6 +225,7 @@ jobs: echo 'RUST_TARGET_TRIPLE=${{ matrix.settings.target }}' >> .env - name: Build app + if: ${{ env.RUN_BUILD == 'true' }} working-directory: apps/desktop run: | pnpm -w cap-setup @@ -285,6 +293,7 @@ jobs: # Get-ChildItem -Path $bundleDir -Filter *.exe | ForEach-Object { Write-Host " - $($_.Name)" } - name: Upload assets + if: ${{ env.RUN_BUILD == 'true' }} uses: crabnebula-dev/cloud-release@v0 with: working-directory: apps/desktop @@ -294,9 +303,10 @@ jobs: TAURI_BUNDLE_PATH: ../.. - uses: matbour/setup-sentry-cli@8ef22a4ff03bcd1ebbcaa3a36a81482ca8e3872e + if: ${{ env.RUN_BUILD == 'true' }} - name: Upload debug symbols to Sentry - if: ${{ runner.os == 'macOS' }} + if: ${{ env.RUN_BUILD == 'true' && runner.os == 'macOS' }} shell: bash env: SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} @@ -304,7 +314,7 @@ jobs: sentry-cli debug-files upload -o ${{ env.SENTRY_ORG }} -p ${{ env.SENTRY_PROJECT }} target/Cap.dSYM - name: Upload debug symbols to Sentry - if: ${{ runner.os == 'Windows' }} + if: ${{ env.RUN_BUILD == 'true' && runner.os == 'Windows' }} shell: bash env: SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} From 173bc3e60087f7951680323007583220e4876eaa Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Wed, 5 Nov 2025 14:31:11 +0000 Subject: [PATCH 05/19] Arm fixes --- .github/workflows/publish.yml | 10 +++++++++- Cargo.lock | 2 +- crates/recording/src/output_pipeline/win.rs | 21 ++++++++++++++++++--- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7d8f2c5710..17bc01d015 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -17,6 +17,11 @@ on: - all - x64 - arm64 + buildMac: + description: "Build macOS installers" + required: false + default: true + type: boolean env: CN_APPLICATION: cap/cap @@ -176,7 +181,10 @@ jobs: env: TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - RUN_BUILD: ${{ matrix.settings.platform != 'windows' || inputs.windowsTarget == 'all' || inputs.windowsTarget == matrix.settings.arch }} + RUN_BUILD: ${{ + (matrix.settings.platform == 'macos' && inputs.buildMac) || + (matrix.settings.platform == 'windows' && (inputs.windowsTarget == 'all' || inputs.windowsTarget == matrix.settings.arch)) + }} runs-on: ${{ matrix.settings.runner }} steps: - name: Checkout repository diff --git a/Cargo.lock b/Cargo.lock index 6eba11b9d1..337df96fac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1172,7 +1172,7 @@ dependencies = [ [[package]] name = "cap-desktop" -version = "0.3.81" +version = "0.3.83" dependencies = [ "anyhow", "async-stream", diff --git a/crates/recording/src/output_pipeline/win.rs b/crates/recording/src/output_pipeline/win.rs index 5306b73ce2..bb9f6dd7d6 100644 --- a/crates/recording/src/output_pipeline/win.rs +++ b/crates/recording/src/output_pipeline/win.rs @@ -226,7 +226,13 @@ impl Muxer for WindowsMuxer { .context("run native encoder") } either::Right(mut encoder) => { - while let Ok(Some((frame, time))) = video_rx.recv() { + use scap_ffmpeg::AsFFmpeg; + + while let Ok(message) = video_rx.recv() { + let Some((frame, time)) = message else { + break; + }; + let Ok(mut output) = output.lock() else { continue; }; @@ -237,8 +243,6 @@ impl Muxer for WindowsMuxer { // mp4.resume(); // } - use scap_ffmpeg::AsFFmpeg; - frame .as_ffmpeg() .context("frame as_ffmpeg") @@ -249,6 +253,17 @@ impl Muxer for WindowsMuxer { })?; } + let mut output_guard = output + .lock() + .map_err(|poisoned| { + anyhow!( + "ScreenSoftwareEncoder: failed to lock output mutex during flush: {}", + poisoned + ) + })?; + + encoder.flush(&mut output_guard).context("flush_encoder")?; + Ok(()) } } From f6903cd25dd0f4e58195a7ce7c306d9f1c6e2169 Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Wed, 5 Nov 2025 14:33:13 +0000 Subject: [PATCH 06/19] XL big boi --- .github/workflows/publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 17bc01d015..7679ec4ff8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -171,11 +171,11 @@ jobs: platform: macos arch: arm64 - target: x86_64-pc-windows-msvc - runner: windows-latest + runner: windows-latest-xl platform: windows arch: x64 - target: aarch64-pc-windows-msvc - runner: windows-latest + runner: windows-latest-xl platform: windows arch: arm64 env: From 1686debb48e070eade817a67fdbf8c4f3853b51a Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Wed, 5 Nov 2025 14:35:54 +0000 Subject: [PATCH 07/19] fix --- .github/workflows/publish.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7679ec4ff8..f1fc9aca42 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -181,10 +181,7 @@ jobs: env: TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - RUN_BUILD: ${{ - (matrix.settings.platform == 'macos' && inputs.buildMac) || - (matrix.settings.platform == 'windows' && (inputs.windowsTarget == 'all' || inputs.windowsTarget == matrix.settings.arch)) - }} + RUN_BUILD: ${{ (matrix.settings.platform == 'macos' && inputs.buildMac) || (matrix.settings.platform == 'windows' && (inputs.windowsTarget == 'all' || inputs.windowsTarget == matrix.settings.arch)) }} runs-on: ${{ matrix.settings.runner }} steps: - name: Checkout repository From 5ff9e5be1a586cbbfd4bc60b3cfa69495c44ef9f Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Wed, 5 Nov 2025 14:44:29 +0000 Subject: [PATCH 08/19] Update publish.yml --- .github/workflows/publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f1fc9aca42..84a9b1f0e2 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -171,11 +171,11 @@ jobs: platform: macos arch: arm64 - target: x86_64-pc-windows-msvc - runner: windows-latest-xl + runner: windows-latest-xlarge platform: windows arch: x64 - target: aarch64-pc-windows-msvc - runner: windows-latest-xl + runner: windows-latest-xlarge platform: windows arch: arm64 env: From 18ce26e445851d377df138c4f777887e0f9d3000 Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Wed, 5 Nov 2025 14:48:02 +0000 Subject: [PATCH 09/19] revert --- .github/workflows/publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 84a9b1f0e2..fa82dfaaa5 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -171,11 +171,11 @@ jobs: platform: macos arch: arm64 - target: x86_64-pc-windows-msvc - runner: windows-latest-xlarge + runner: windows-latest platform: windows arch: x64 - target: aarch64-pc-windows-msvc - runner: windows-latest-xlarge + runner: windows-latest platform: windows arch: arm64 env: From 59905683224b669d6a84071203c0ed068ffe57e6 Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Wed, 5 Nov 2025 14:56:41 +0000 Subject: [PATCH 10/19] Update publish.yml --- .github/workflows/publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index fa82dfaaa5..b6938d899e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -171,11 +171,11 @@ jobs: platform: macos arch: arm64 - target: x86_64-pc-windows-msvc - runner: windows-latest + runner: windows-latest-l platform: windows arch: x64 - target: aarch64-pc-windows-msvc - runner: windows-latest + runner: windows-latest-l platform: windows arch: arm64 env: From b6acebc6d8437915443a0c9dfc8238f26fe6ee82 Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Wed, 5 Nov 2025 15:02:47 +0000 Subject: [PATCH 11/19] blacksmith test --- .github/workflows/publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b6938d899e..060e9ee05d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -171,11 +171,11 @@ jobs: platform: macos arch: arm64 - target: x86_64-pc-windows-msvc - runner: windows-latest-l + runner: blacksmith-32vcpu-windows-2025 platform: windows arch: x64 - target: aarch64-pc-windows-msvc - runner: windows-latest-l + runner: blacksmith-32vcpu-windows-2025 platform: windows arch: arm64 env: From 87748497cb3d49d3d8d30dff0053f3be1ce668b5 Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Wed, 5 Nov 2025 15:54:00 +0000 Subject: [PATCH 12/19] feat: Protect "end" time writing --- apps/desktop/src-tauri/src/recording.rs | 22 ++++++++--- crates/rendering/src/project_recordings.rs | 45 ++++++++++++++++++++-- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/apps/desktop/src-tauri/src/recording.rs b/apps/desktop/src-tauri/src/recording.rs index ab5fd90b32..bada34367c 100644 --- a/apps/desktop/src-tauri/src/recording.rs +++ b/apps/desktop/src-tauri/src/recording.rs @@ -1309,11 +1309,23 @@ fn project_config_from_recording( .segments .iter() .enumerate() - .map(|(i, segment)| TimelineSegment { - recording_segment: i as u32, - start: 0.0, - end: segment.duration(), - timescale: 1.0, + .map(|(i, segment)| { + let mut duration = segment.duration(); + + if !duration.is_finite() || duration <= 0.0 { + warn!( + segment_index = i, + duration, "Segment duration was invalid; clamping to zero" + ); + duration = 0.0; + } + + TimelineSegment { + recording_segment: i as u32, + start: 0.0, + end: duration, + timescale: 1.0, + } }) .collect::>(); diff --git a/crates/rendering/src/project_recordings.rs b/crates/rendering/src/project_recordings.rs index a373fcaa7f..3b47c7e608 100644 --- a/crates/rendering/src/project_recordings.rs +++ b/crates/rendering/src/project_recordings.rs @@ -33,13 +33,52 @@ impl Video { .map_err(|e| format!("Failed to get video decoder: {e}"))?; let rate = stream.avg_frame_rate(); - let fps = rate.numerator() as f64 / rate.denominator() as f64; + let fps = if rate.denominator() != 0 { + rate.numerator() as f64 / rate.denominator() as f64 + } else { + 0.0 + }; + + let container_duration = input.duration(); + let mut duration = if container_duration > 0 && container_duration != i64::MIN { + container_duration as f64 / 1_000_000.0 + } else { + 0.0 + }; + + if duration <= 0.0 { + let stream_duration = stream.duration(); + if stream_duration > 0 && stream_duration != i64::MIN { + let time_base = stream.time_base(); + duration = (stream_duration as f64 * time_base.numerator() as f64) + / time_base.denominator() as f64; + } + } + + if duration <= 0.0 { + let frames = stream.frames(); + if frames > 0 && fps > 0.0 { + duration = frames as f64 / fps; + } + } + + if !duration.is_finite() || duration <= 0.0 { + tracing::warn!( + ?path, + container_duration, + stream_duration = stream.duration(), + frames = stream.frames(), + fps, + "Failed to determine video duration; defaulting to zero" + ); + duration = 0.0; + } Ok(Video { width: video_decoder.width(), height: video_decoder.height(), - duration: input.duration() as f64 / 1_000_000.0, - fps: fps.round() as u32, + duration, + fps: if fps > 0.0 { fps.round() as u32 } else { 0 }, start_time, }) } From fe8a8b81ea9e58601591194620ddecc9b2bf2125 Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:13:36 +0000 Subject: [PATCH 13/19] Update publish.yml --- .github/workflows/publish.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 060e9ee05d..fa7785d2c3 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -192,6 +192,17 @@ jobs: if: ${{ env.RUN_BUILD == 'true' }} run: echo "${{ secrets.APPLE_API_KEY_FILE }}" > api.p8 + - name: Install LLVM (clang) + if: ${{ env.RUN_BUILD == 'true' && runner.os == 'Windows' }} + shell: powershell + run: choco install llvm --version=18.1.6 -y --no-progress + + - name: Add LLVM to PATH + if: ${{ env.RUN_BUILD == 'true' && runner.os == 'Windows' }} + shell: powershell + run: | + "C:\Program Files\LLVM\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + - uses: apple-actions/import-codesign-certs@v2 if: ${{ env.RUN_BUILD == 'true' && matrix.settings.runner == 'macos-latest-xlarge' }} with: From 2bdace13b263a2a5869603d45e6e49383825c935 Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:23:25 +0000 Subject: [PATCH 14/19] Revert "Update publish.yml" This reverts commit fe8a8b81ea9e58601591194620ddecc9b2bf2125. --- .github/workflows/publish.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index fa7785d2c3..060e9ee05d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -192,17 +192,6 @@ jobs: if: ${{ env.RUN_BUILD == 'true' }} run: echo "${{ secrets.APPLE_API_KEY_FILE }}" > api.p8 - - name: Install LLVM (clang) - if: ${{ env.RUN_BUILD == 'true' && runner.os == 'Windows' }} - shell: powershell - run: choco install llvm --version=18.1.6 -y --no-progress - - - name: Add LLVM to PATH - if: ${{ env.RUN_BUILD == 'true' && runner.os == 'Windows' }} - shell: powershell - run: | - "C:\Program Files\LLVM\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - - uses: apple-actions/import-codesign-certs@v2 if: ${{ env.RUN_BUILD == 'true' && matrix.settings.runner == 'macos-latest-xlarge' }} with: From 63015f108aed773530c1dea4a9892bfa423de963 Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:24:02 +0000 Subject: [PATCH 15/19] remove blacksmith --- .github/workflows/publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 060e9ee05d..b6938d899e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -171,11 +171,11 @@ jobs: platform: macos arch: arm64 - target: x86_64-pc-windows-msvc - runner: blacksmith-32vcpu-windows-2025 + runner: windows-latest-l platform: windows arch: x64 - target: aarch64-pc-windows-msvc - runner: blacksmith-32vcpu-windows-2025 + runner: windows-latest-l platform: windows arch: arm64 env: From eb474adeac2b9ad01ca449b4020d25a1d55e21ad Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Thu, 6 Nov 2025 14:00:14 +0000 Subject: [PATCH 16/19] Improve FPS calculation fallback logic in Video --- crates/rendering/src/project_recordings.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/rendering/src/project_recordings.rs b/crates/rendering/src/project_recordings.rs index 3b47c7e608..fa246b374e 100644 --- a/crates/rendering/src/project_recordings.rs +++ b/crates/rendering/src/project_recordings.rs @@ -33,12 +33,19 @@ impl Video { .map_err(|e| format!("Failed to get video decoder: {e}"))?; let rate = stream.avg_frame_rate(); - let fps = if rate.denominator() != 0 { + let mut fps = if rate.denominator() != 0 && rate.numerator() != 0 { rate.numerator() as f64 / rate.denominator() as f64 } else { 0.0 }; + if fps <= 0.0 { + let r_rate = stream.rate(); + if r_rate.denominator() != 0 && r_rate.numerator() != 0 { + fps = r_rate.numerator() as f64 / r_rate.denominator() as f64; + } + } + let container_duration = input.duration(); let mut duration = if container_duration > 0 && container_duration != i64::MIN { container_duration as f64 / 1_000_000.0 From 6198c23b18cda57de408e5707f5b333455afbd3a Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Thu, 6 Nov 2025 15:02:18 +0000 Subject: [PATCH 17/19] fps fix --- crates/enc-ffmpeg/src/video/h264.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crates/enc-ffmpeg/src/video/h264.rs b/crates/enc-ffmpeg/src/video/h264.rs index a338229cb7..b63697a33b 100644 --- a/crates/enc-ffmpeg/src/video/h264.rs +++ b/crates/enc-ffmpeg/src/video/h264.rs @@ -200,6 +200,18 @@ impl H264EncoderBuilder { output_stream.set_rate(input_config.frame_rate); output_stream.set_parameters(&encoder); + unsafe { + let s = output_stream.as_mut_ptr(); + (*s).avg_frame_rate = ffmpeg::ffi::AVRational { + num: input_config.frame_rate.0, + den: input_config.frame_rate.1, + }; + (*s).r_frame_rate = ffmpeg::ffi::AVRational { + num: input_config.frame_rate.0, + den: input_config.frame_rate.1, + }; + } + Ok(H264Encoder { base: EncoderBase::new(stream_index), encoder, From d8aec67491150f9c68624fcd23607408d586fb35 Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Thu, 6 Nov 2025 16:22:01 +0000 Subject: [PATCH 18/19] Improve header writing and duration calculation logic --- crates/recording/src/output_pipeline/win.rs | 18 +++++++++++++++- crates/rendering/src/project_recordings.rs | 23 +++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/crates/recording/src/output_pipeline/win.rs b/crates/recording/src/output_pipeline/win.rs index bb9f6dd7d6..ed8d109a8e 100644 --- a/crates/recording/src/output_pipeline/win.rs +++ b/crates/recording/src/output_pipeline/win.rs @@ -179,10 +179,26 @@ impl Muxer for WindowsMuxer { let encoder = match encoder { Ok(encoder) => { + let mut output_guard = match output.lock() { + Ok(guard) => guard, + Err(poisoned) => { + error!("Failed to lock output mutex for write_header: {}", poisoned); + let _ = ready_tx.send(Err(anyhow!("Failed to lock output for header"))); + return Err(anyhow!("Failed to lock output for header")); + } + }; + + if let Err(e) = output_guard.write_header() { + error!("Failed to write header: {:#}", e); + let _ = ready_tx.send(Err(anyhow!("write_header: {e}"))); + return Err(anyhow!("write_header: {e}")); + } + if ready_tx.send(Ok(())).is_err() { error!("Failed to send ready signal - receiver dropped"); return Ok(()); } + encoder } Err(e) => { @@ -274,7 +290,7 @@ impl Muxer for WindowsMuxer { .await .map_err(|_| anyhow!("Encoder thread ended unexpectedly"))??; - output.lock().unwrap().write_header()?; + // write_header is performed inside the encoder thread after all streams are added Ok(Self { video_tx, diff --git a/crates/rendering/src/project_recordings.rs b/crates/rendering/src/project_recordings.rs index fa246b374e..e88ab617f9 100644 --- a/crates/rendering/src/project_recordings.rs +++ b/crates/rendering/src/project_recordings.rs @@ -62,6 +62,29 @@ impl Video { } } + if duration <= 0.0 { + let mut last_ts: i64 = -1; + for (s, packet) in input.packets() { + if s.index() == stream.index() { + if let Some(pts) = packet.pts() { + if pts > last_ts { + last_ts = pts; + } + } else if let Some(dts) = packet.dts() { + if dts > last_ts { + last_ts = dts; + } + } + } + } + + if last_ts >= 0 { + let tb = stream.time_base(); + duration = (last_ts as f64 * tb.numerator() as f64) + / tb.denominator() as f64; + } + } + if duration <= 0.0 { let frames = stream.frames(); if frames > 0 && fps > 0.0 { From d7cd6244995f410e5240033ab7816986ad2d3a49 Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Thu, 6 Nov 2025 16:26:37 +0000 Subject: [PATCH 19/19] Update project_recordings.rs --- crates/rendering/src/project_recordings.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/rendering/src/project_recordings.rs b/crates/rendering/src/project_recordings.rs index e88ab617f9..8ac7b73e5d 100644 --- a/crates/rendering/src/project_recordings.rs +++ b/crates/rendering/src/project_recordings.rs @@ -80,8 +80,7 @@ impl Video { if last_ts >= 0 { let tb = stream.time_base(); - duration = (last_ts as f64 * tb.numerator() as f64) - / tb.denominator() as f64; + duration = (last_ts as f64 * tb.numerator() as f64) / tb.denominator() as f64; } }