feat(windows): bundle ffmpeg runtime dlls and build standalone executable vrec.exe via nsis

This commit is contained in:
katR 2026-09-04 22:50:47 +05:30
parent 4274514918
commit 0ecd522da0
4 changed files with 118 additions and 12 deletions

View file

@ -111,6 +111,8 @@ jobs:
mingw-w64-x86_64-ffmpeg mingw-w64-x86_64-ffmpeg
mingw-w64-x86_64-pkg-config mingw-w64-x86_64-pkg-config
mingw-w64-x86_64-clang mingw-w64-x86_64-clang
mingw-w64-x86_64-ntldd
python3
- name: Build Release Binaries (Windows) - name: Build Release Binaries (Windows)
shell: msys2 {0} shell: msys2 {0}
@ -119,20 +121,34 @@ jobs:
BINDGEN_EXTRA_CLANG_ARGS: "--target=x86_64-w64-windows-gnu" BINDGEN_EXTRA_CLANG_ARGS: "--target=x86_64-w64-windows-gnu"
run: | run: |
cargo build --release cargo build --release
mkdir -p dist/bundle
cp target/release/vrec-daemon.exe dist/bundle/
cp target/release/vrec-ui.exe dist/bundle/
python3 packaging/windows/bundle_deps.py dist/bundle
- name: Package Windows Zip - name: Package Windows Standalone (.exe), Installer, and Zip
shell: pwsh shell: pwsh
run: | run: |
New-Item -ItemType Directory -Force -Path dist/vrec-windows-x64 if (!(Get-Command makensis -ErrorAction SilentlyContinue)) {
Copy-Item target/release/vrec-daemon.exe dist/vrec-windows-x64/ if (Test-Path "C:\Program Files (x86)\NSIS\makensis.exe") {
Copy-Item target/release/vrec-ui.exe dist/vrec-windows-x64/ $env:Path += ";C:\Program Files (x86)\NSIS"
Compress-Archive -Path dist/vrec-windows-x64 -DestinationPath dist/vrec-windows-x64.zip } else {
choco install nsis -y --no-progress
$env:Path += ";C:\Program Files (x86)\NSIS"
}
}
makensis packaging/windows/vrec-standalone.nsi
makensis packaging/windows/vrec-installer.nsi
Compress-Archive -Path dist/bundle/* -DestinationPath dist/vrec-windows-x64.zip
- name: Upload Windows Artifacts - name: Upload Windows Artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: windows-package name: windows-packages
path: dist/vrec-windows-x64.zip path: |
dist/vrec.exe
dist/vrec-setup.exe
dist/vrec-windows-x64.zip
publish-release: publish-release:
name: Publish GitHub Release name: Publish GitHub Release
@ -166,14 +182,16 @@ jobs:
- Multi-channel audio routing (System audio, Microphone, Combined, and Mute) - Multi-channel audio routing (System audio, Microphone, Combined, and Mute)
### Packages ### Packages
- Windows: `vrec-windows-x64.zip` - Windows Standalone: `vrec.exe` (Single standalone executable, zero install required)
- Windows Setup: `vrec-setup.exe` (Full installer with Start Menu & Desktop shortcuts)
- Windows Portable: `vrec-windows-x64.zip` (Zip with all binaries & runtime DLLs)
- Universal Linux: `vrec-x86_64.AppImage` - Universal Linux: `vrec-x86_64.AppImage`
- Debian / Ubuntu / Mint: `vrec_0.1.0_amd64.deb` - Debian / Ubuntu / Mint: `vrec_0.1.0_amd64.deb`
- Fedora / RHEL / openSUSE: `vrec-0.1.0-2.x86_64.rpm` - Fedora / RHEL / openSUSE: `vrec-0.1.0-2.x86_64.rpm`
- Generic Linux: `vrec-linux-x86_64.tar.gz` - Generic Linux: `vrec-linux-x86_64.tar.gz`
files: | files: |
artifacts/linux-packages/* artifacts/linux-packages/*
artifacts/windows-package/* artifacts/windows-packages/*
draft: false draft: false
prerelease: false prerelease: false
generate_release_notes: false generate_release_notes: false

View file

@ -0,0 +1,48 @@
!include "MUI2.nsh"
!include "FileFunc.nsh"
Name "vrec"
OutFile "..\..\dist\vrec-setup.exe"
InstallDir "$LOCALAPPDATA\Programs\vrec"
RequestExecutionLevel user
!define MUI_ABORTWARNING
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!define MUI_FINISHPAGE_RUN "$INSTDIR\vrec-ui.exe"
!define MUI_FINISHPAGE_RUN_PARAMETERS "--menu"
!define MUI_FINISHPAGE_RUN_TEXT "Launch vrec Studio Overlay"
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
Section "vrec" SecMain
SetOutPath "$INSTDIR"
File /r "..\..\dist\bundle\*.*"
; Create Start Menu and Desktop shortcuts
CreateDirectory "$SMPROGRAMS\vrec"
CreateShortcut "$SMPROGRAMS\vrec\vrec Studio.lnk" "$INSTDIR\vrec-ui.exe" "--menu"
CreateShortcut "$SMPROGRAMS\vrec\vrec Background Engine.lnk" "$INSTDIR\vrec-daemon.exe" ""
CreateShortcut "$DESKTOP\vrec.lnk" "$INSTDIR\vrec-ui.exe" "--menu"
; Register uninstaller with Windows Control Panel / Settings
WriteUninstaller "$INSTDIR\uninstall.exe"
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\vrec" "DisplayName" "vrec Screen Recorder"
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\vrec" "UninstallString" '"$INSTDIR\uninstall.exe"'
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\vrec" "DisplayIcon" "$INSTDIR\vrec-ui.exe"
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\vrec" "Publisher" "oiupoyt"
SectionEnd
Section "Uninstall"
Delete "$DESKTOP\vrec.lnk"
RMDir /r "$SMPROGRAMS\vrec"
RMDir /r "$INSTDIR"
DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\vrec"
SectionEnd

View file

@ -0,0 +1,22 @@
!include "FileFunc.nsh"
!include "LogicLib.nsh"
Name "vrec"
OutFile "..\..\dist\vrec.exe"
Caption "vrec Screen Recorder"
SilentInstall silent
RequestExecutionLevel user
Section
; Extract self-contained binaries and all runtime DLLs directly to user app data
SetOutPath "$LOCALAPPDATA\vrec"
File /r "..\..\dist\bundle\*.*"
; Execute vrec-ui with any forwarded command-line arguments, or default to overlay menu
${GetParameters} $R0
${If} $R0 == ""
Exec '"$LOCALAPPDATA\vrec\vrec-ui.exe" --menu'
${Else}
Exec '"$LOCALAPPDATA\vrec\vrec-ui.exe" $R0'
${EndIf}
SectionEnd

View file

@ -35,16 +35,34 @@ fn ensure_wayland_env() {
} }
} }
fn get_daemon_cmd() -> std::process::Command {
if let Ok(mut path) = std::env::current_exe() {
path.pop();
#[cfg(target_os = "windows")]
let candidate = path.join("vrec-daemon.exe");
#[cfg(not(target_os = "windows"))]
let candidate = path.join("vrec-daemon");
if candidate.exists() {
return std::process::Command::new(candidate);
}
}
#[cfg(target_os = "windows")]
return std::process::Command::new("vrec-daemon.exe");
#[cfg(not(target_os = "windows"))]
return std::process::Command::new("vrec-daemon");
}
fn ensure_daemon_running() { fn ensure_daemon_running() {
if query_status().is_err() { if query_status().is_err() {
println!("vrec-daemon not running. Auto-launching vrec-daemon..."); println!("vrec-daemon not running. Auto-launching vrec-daemon...");
let _ = std::process::Command::new("vrec-daemon") let _ = get_daemon_cmd()
.stdin(std::process::Stdio::null()) .stdin(std::process::Stdio::null())
.stdout(std::process::Stdio::null()) .stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null()) .stderr(std::process::Stdio::null())
.spawn(); .spawn();
for _ in 0..15 { for _ in 0..20 {
std::thread::sleep(std::time::Duration::from_millis(100)); std::thread::sleep(std::time::Duration::from_millis(150));
if query_status().is_ok() { if query_status().is_ok() {
println!("vrec-daemon successfully connected."); println!("vrec-daemon successfully connected.");
break; break;