rebrand: rename project and components to scythe
This commit is contained in:
parent
354b3e9558
commit
8ed53faefd
20 changed files with 373 additions and 279 deletions
60
Cargo.lock
generated
60
Cargo.lock
generated
|
|
@ -3698,6 +3698,36 @@ dependencies = [
|
||||||
"tiny-skia",
|
"tiny-skia",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scythe"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"ashpd",
|
||||||
|
"cpal",
|
||||||
|
"crossbeam-channel",
|
||||||
|
"dirs",
|
||||||
|
"eframe",
|
||||||
|
"egui",
|
||||||
|
"ffmpeg-next",
|
||||||
|
"ffmpeg-sys-next",
|
||||||
|
"gdk",
|
||||||
|
"glib 0.22.9",
|
||||||
|
"global-hotkey",
|
||||||
|
"gtk",
|
||||||
|
"gtk-layer-shell",
|
||||||
|
"libc",
|
||||||
|
"memmap2",
|
||||||
|
"mp4",
|
||||||
|
"pipewire",
|
||||||
|
"ringbuf",
|
||||||
|
"rubato",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tokio",
|
||||||
|
"windows 0.58.0",
|
||||||
|
"xcb",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.28"
|
version = "1.0.28"
|
||||||
|
|
@ -4480,36 +4510,6 @@ dependencies = [
|
||||||
"syn 2.0.119",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vrec"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"ashpd",
|
|
||||||
"cpal",
|
|
||||||
"crossbeam-channel",
|
|
||||||
"dirs",
|
|
||||||
"eframe",
|
|
||||||
"egui",
|
|
||||||
"ffmpeg-next",
|
|
||||||
"ffmpeg-sys-next",
|
|
||||||
"gdk",
|
|
||||||
"glib 0.22.9",
|
|
||||||
"global-hotkey",
|
|
||||||
"gtk",
|
|
||||||
"gtk-layer-shell",
|
|
||||||
"libc",
|
|
||||||
"memmap2",
|
|
||||||
"mp4",
|
|
||||||
"pipewire",
|
|
||||||
"ringbuf",
|
|
||||||
"rubato",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"tokio",
|
|
||||||
"windows 0.58.0",
|
|
||||||
"xcb",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
|
|
||||||
10
Cargo.toml
10
Cargo.toml
|
|
@ -1,8 +1,16 @@
|
||||||
[package]
|
[package]
|
||||||
name = "vrec"
|
name = "scythe"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "scythe-daemon"
|
||||||
|
path = "src/bin/scythe-daemon.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "scythe-ui"
|
||||||
|
path = "src/bin/scythe-ui.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crossbeam-channel = "0.5.16"
|
crossbeam-channel = "0.5.16"
|
||||||
ffmpeg-next = "9.0.0"
|
ffmpeg-next = "9.0.0"
|
||||||
|
|
|
||||||
38
install.sh
38
install.sh
|
|
@ -2,7 +2,7 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo "============================================="
|
echo "============================================="
|
||||||
echo " Installing vrec Screen Recorder "
|
echo " Installing Scythe Screen Recorder "
|
||||||
echo "============================================="
|
echo "============================================="
|
||||||
|
|
||||||
# Compile release binaries
|
# Compile release binaries
|
||||||
|
|
@ -16,22 +16,30 @@ mkdir -p "$BIN_DIR"
|
||||||
mkdir -p "$APP_DIR"
|
mkdir -p "$APP_DIR"
|
||||||
|
|
||||||
echo "[2/4] Installing binaries to $BIN_DIR..."
|
echo "[2/4] Installing binaries to $BIN_DIR..."
|
||||||
install -m 755 target/release/vrec-daemon "$BIN_DIR/vrec-daemon"
|
install -m 755 target/release/scythe-daemon "$BIN_DIR/scythe-daemon"
|
||||||
install -m 755 target/release/vrec-ui "$BIN_DIR/vrec-ui"
|
install -m 755 target/release/scythe-ui "$BIN_DIR/scythe-ui"
|
||||||
|
ln -sf "$BIN_DIR/scythe-ui" "$BIN_DIR/scythe"
|
||||||
|
|
||||||
|
# Backward-compatible symlinks
|
||||||
|
ln -sf "$BIN_DIR/scythe-daemon" "$BIN_DIR/vrec-daemon"
|
||||||
|
ln -sf "$BIN_DIR/scythe-ui" "$BIN_DIR/vrec-ui"
|
||||||
|
ln -sf "$BIN_DIR/scythe-ui" "$BIN_DIR/vrec"
|
||||||
|
|
||||||
echo "[3/4] Creating application launcher..."
|
echo "[3/4] Creating application launcher..."
|
||||||
cat > "$APP_DIR/vrec.desktop" << EOF
|
cat > "$APP_DIR/scythe.desktop" << EOF
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Type=Application
|
Type=Application
|
||||||
Name=vrec Screen Recorder
|
Name=Scythe Screen Recorder
|
||||||
Comment=Fast GPU Hardware Screen Recorder & Instant Replay
|
Comment=Fast GPU Hardware Screen Recorder & Instant Replay
|
||||||
Exec=vrec-ui --menu
|
Exec=scythe-ui --menu
|
||||||
Icon=media-record
|
Icon=media-record
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Categories=AudioVideo;Recorder;
|
Categories=AudioVideo;Recorder;
|
||||||
Keywords=screen;recorder;replay;capture;
|
Keywords=screen;recorder;replay;capture;scythe;shadowplay;
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
ln -sf "$APP_DIR/scythe.desktop" "$APP_DIR/vrec.desktop"
|
||||||
|
|
||||||
echo "[4/4] Verifying PATH..."
|
echo "[4/4] Verifying PATH..."
|
||||||
if [[ ":$PATH:" != *":$BIN_DIR:"* ]]; then
|
if [[ ":$PATH:" != *":$BIN_DIR:"* ]]; then
|
||||||
echo "Notice: $BIN_DIR is not in your PATH. Consider adding:"
|
echo "Notice: $BIN_DIR is not in your PATH. Consider adding:"
|
||||||
|
|
@ -39,15 +47,15 @@ if [[ ":$PATH:" != *":$BIN_DIR:"* ]]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "============================================="
|
echo "============================================="
|
||||||
echo " vrec successfully installed! "
|
echo " Scythe successfully installed! "
|
||||||
echo "============================================="
|
echo "============================================="
|
||||||
echo "You can now run:"
|
echo "You can now run:"
|
||||||
echo " vrec-daemon # Starts background recording engine"
|
echo " scythe-daemon # Starts background recording engine"
|
||||||
echo " vrec-ui --menu # Opens the HUD overlay menu"
|
echo " scythe-ui --menu # Opens the HUD overlay menu"
|
||||||
echo " vrec-ui --record # Toggles normal recording"
|
echo " scythe-ui --record # Toggles normal recording"
|
||||||
echo " vrec-ui --save # Saves instant replay"
|
echo " scythe-ui --save # Saves instant replay"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Tip: You can bind 'vrec-ui --menu' or 'vrec-ui --save' in Hyprland config (hyprland.conf):"
|
echo "Tip: You can bind 'scythe-ui --menu' or 'scythe-ui --save' in Hyprland config (hyprland.conf):"
|
||||||
echo ' bind = ALT, Z, exec, vrec-ui --menu'
|
echo ' bind = ALT, Z, exec, scythe-ui --menu'
|
||||||
echo ' bind = CONTROL SHIFT, R, exec, vrec-ui --save'
|
echo ' bind = CONTROL SHIFT, R, exec, scythe-ui --save'
|
||||||
echo "============================================="
|
echo "============================================="
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,36 @@
|
||||||
# Maintainer: oiupoyt
|
# Maintainer: oiupoyt
|
||||||
pkgname=vrec-git
|
pkgname=scythe-git
|
||||||
pkgver=0.1.0
|
pkgver=0.1.0
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="High-performance GPU hardware screen recorder and instant replay overlay for Wayland and X11"
|
pkgdesc="High-performance GPU hardware screen recorder and instant replay overlay for Wayland and X11"
|
||||||
arch=('x86_64')
|
arch=('x86_64')
|
||||||
url="https://github.com/oiupoyt/vrec"
|
url="https://github.com/oiupoyt/scythe"
|
||||||
license=('MIT' 'Apache-2.0')
|
license=('MIT' 'Apache-2.0')
|
||||||
depends=('ffmpeg' 'pipewire' 'gtk3' 'gtk-layer-shell' 'libpulse' 'libva' 'libxcb')
|
depends=('ffmpeg' 'pipewire' 'gtk3' 'gtk-layer-shell' 'libpulse' 'libva' 'libxcb')
|
||||||
makedepends=('cargo' 'git' 'pkgconf' 'clang')
|
makedepends=('cargo' 'git' 'pkgconf' 'clang')
|
||||||
provides=('vrec')
|
provides=('scythe' 'vrec' 'vrec-git')
|
||||||
conflicts=('vrec')
|
conflicts=('scythe' 'vrec')
|
||||||
source=("git+https://github.com/oiupoyt/vrec.git")
|
source=("git+https://github.com/oiupoyt/scythe.git")
|
||||||
sha256sums=('SKIP')
|
sha256sums=('SKIP')
|
||||||
|
|
||||||
pkgver() {
|
pkgver() {
|
||||||
cd "$srcdir/vrec"
|
cd "$srcdir/scythe"
|
||||||
git describe --long --tags 2>/dev/null | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g' || echo "0.1.0"
|
git describe --long --tags 2>/dev/null | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g' || echo "0.1.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
cd "$srcdir/vrec"
|
cd "$srcdir/scythe"
|
||||||
cargo build --release --locked
|
cargo build --release --locked
|
||||||
}
|
}
|
||||||
|
|
||||||
package() {
|
package() {
|
||||||
cd "$srcdir/vrec"
|
cd "$srcdir/scythe"
|
||||||
install -Dm755 target/release/vrec-daemon "$pkgdir/usr/bin/vrec-daemon"
|
install -Dm755 target/release/scythe-daemon "$pkgdir/usr/bin/scythe-daemon"
|
||||||
install -Dm755 target/release/vrec-ui "$pkgdir/usr/bin/vrec-ui"
|
install -Dm755 target/release/scythe-ui "$pkgdir/usr/bin/scythe-ui"
|
||||||
install -Dm644 packaging/vrec.desktop "$pkgdir/usr/share/applications/vrec.desktop"
|
install -Dm755 target/release/scythe "$pkgdir/usr/bin/scythe"
|
||||||
|
ln -sf "/usr/bin/scythe-daemon" "$pkgdir/usr/bin/vrec-daemon"
|
||||||
|
ln -sf "/usr/bin/scythe-ui" "$pkgdir/usr/bin/vrec-ui"
|
||||||
|
ln -sf "/usr/bin/scythe" "$pkgdir/usr/bin/vrec"
|
||||||
|
install -Dm644 packaging/scythe.desktop "$pkgdir/usr/share/applications/scythe.desktop"
|
||||||
|
ln -sf "/usr/share/applications/scythe.desktop" "$pkgdir/usr/share/applications/vrec.desktop"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
app-id: com.vrec.Vrec
|
app-id: com.scythe.Scythe
|
||||||
runtime: org.gnome.Platform
|
runtime: org.gnome.Platform
|
||||||
runtime-version: '46'
|
runtime-version: '46'
|
||||||
sdk: org.gnome.Sdk
|
sdk: org.gnome.Sdk
|
||||||
sdk-extensions:
|
sdk-extensions:
|
||||||
- org.freedesktop.Sdk.Extension.rust-stable
|
- org.freedesktop.Sdk.Extension.rust-stable
|
||||||
command: vrec-ui
|
command: scythe-ui
|
||||||
finish-args:
|
finish-args:
|
||||||
- --share=ipc
|
- --share=ipc
|
||||||
- --socket=fallback-x11
|
- --socket=fallback-x11
|
||||||
|
|
@ -19,17 +19,21 @@ finish-args:
|
||||||
build-options:
|
build-options:
|
||||||
append-path: /usr/lib/sdk/rust-stable/bin
|
append-path: /usr/lib/sdk/rust-stable/bin
|
||||||
env:
|
env:
|
||||||
CARGO_HOME: /run/build/vrec/cargo
|
CARGO_HOME: /run/build/scythe/cargo
|
||||||
|
|
||||||
modules:
|
modules:
|
||||||
- name: vrec
|
- name: scythe
|
||||||
buildsystem: simple
|
buildsystem: simple
|
||||||
build-commands:
|
build-commands:
|
||||||
- cargo build --release --verbose
|
- cargo build --release --verbose
|
||||||
- install -Dm755 target/release/vrec-daemon /app/bin/vrec-daemon
|
- install -Dm755 target/release/scythe-daemon /app/bin/scythe-daemon
|
||||||
- install -Dm755 target/release/vrec-ui /app/bin/vrec-ui
|
- install -Dm755 target/release/scythe-ui /app/bin/scythe-ui
|
||||||
- install -Dm644 packaging/vrec.desktop /app/share/applications/com.vrec.Vrec.desktop
|
- install -Dm755 target/release/scythe /app/bin/scythe
|
||||||
|
- ln -sf /app/bin/scythe-daemon /app/bin/vrec-daemon
|
||||||
|
- ln -sf /app/bin/scythe-ui /app/bin/vrec-ui
|
||||||
|
- ln -sf /app/bin/scythe /app/bin/vrec
|
||||||
|
- install -Dm644 packaging/scythe.desktop /app/share/applications/com.scythe.Scythe.desktop
|
||||||
sources:
|
sources:
|
||||||
- type: git
|
- type: git
|
||||||
url: https://github.com/oiupoyt/vrec.git
|
url: https://github.com/oiupoyt/scythe.git
|
||||||
branch: main
|
branch: main
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
Name: vrec
|
Name: scythe
|
||||||
Version: 0.1.0
|
Version: 0.1.0
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: High-performance GPU hardware screen recorder and instant replay overlay
|
Summary: High-performance GPU hardware screen recorder and instant replay overlay
|
||||||
|
|
||||||
License: MIT
|
License: MIT
|
||||||
URL: https://github.com/oiupoyt/vrec
|
URL: https://github.com/oiupoyt/scythe
|
||||||
Source0: %{name}-%{version}.tar.gz
|
Source0: %{name}-%{version}.tar.gz
|
||||||
|
|
||||||
BuildRequires: cargo
|
BuildRequires: cargo
|
||||||
|
|
@ -32,15 +32,25 @@ cargo build --release
|
||||||
|
|
||||||
%install
|
%install
|
||||||
rm -rf $RPM_BUILD_ROOT
|
rm -rf $RPM_BUILD_ROOT
|
||||||
install -D -m 0755 target/release/vrec-daemon %{buildroot}%{_bindir}/vrec-daemon
|
install -D -m 0755 target/release/scythe-daemon %{buildroot}%{_bindir}/scythe-daemon
|
||||||
install -D -m 0755 target/release/vrec-ui %{buildroot}%{_bindir}/vrec-ui
|
install -D -m 0755 target/release/scythe-ui %{buildroot}%{_bindir}/scythe-ui
|
||||||
install -D -m 0644 packaging/vrec.desktop %{buildroot}%{_datadir}/applications/vrec.desktop
|
install -D -m 0755 target/release/scythe %{buildroot}%{_bindir}/scythe
|
||||||
|
ln -sf %{_bindir}/scythe-daemon %{buildroot}%{_bindir}/vrec-daemon
|
||||||
|
ln -sf %{_bindir}/scythe-ui %{buildroot}%{_bindir}/vrec-ui
|
||||||
|
ln -sf %{_bindir}/scythe %{buildroot}%{_bindir}/vrec
|
||||||
|
install -D -m 0644 packaging/scythe.desktop %{buildroot}%{_datadir}/applications/scythe.desktop
|
||||||
|
ln -sf %{_datadir}/applications/scythe.desktop %{buildroot}%{_datadir}/applications/vrec.desktop
|
||||||
|
|
||||||
%files
|
%files
|
||||||
|
%{_bindir}/scythe-daemon
|
||||||
|
%{_bindir}/scythe-ui
|
||||||
|
%{_bindir}/scythe
|
||||||
%{_bindir}/vrec-daemon
|
%{_bindir}/vrec-daemon
|
||||||
%{_bindir}/vrec-ui
|
%{_bindir}/vrec-ui
|
||||||
|
%{_bindir}/vrec
|
||||||
|
%{_datadir}/applications/scythe.desktop
|
||||||
%{_datadir}/applications/vrec.desktop
|
%{_datadir}/applications/vrec.desktop
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Wed Sep 02 2026 oiupoyt - 0.1.0-1
|
* Wed Sep 02 2026 oiupoyt - 0.1.0-1
|
||||||
- Initial release of vrec
|
- Initial release of scythe
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Type=Application
|
Type=Application
|
||||||
Name=vrec Screen Recorder
|
Name=Scythe Screen Recorder
|
||||||
GenericName=Screen Recorder & Instant Replay
|
GenericName=Screen Recorder & Instant Replay
|
||||||
Comment=High-performance GPU hardware screen recorder and instant replay overlay
|
Comment=High-performance GPU hardware screen recorder and instant replay overlay
|
||||||
Exec=vrec-ui --menu
|
Exec=scythe-ui --menu
|
||||||
Icon=media-record
|
Icon=media-record
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Categories=AudioVideo;Recorder;
|
Categories=AudioVideo;Recorder;
|
||||||
Keywords=screen;recorder;replay;capture;game;shadowplay;
|
Keywords=screen;recorder;replay;capture;game;shadowplay;scythe;
|
||||||
StartupNotify=false
|
StartupNotify=false
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
!include "MUI2.nsh"
|
!include "MUI2.nsh"
|
||||||
!include "FileFunc.nsh"
|
!include "FileFunc.nsh"
|
||||||
|
|
||||||
Name "vrec"
|
Name "Scythe"
|
||||||
OutFile "..\..\dist\vrec-setup.exe"
|
OutFile "..\..\dist\scythe-setup.exe"
|
||||||
InstallDir "$LOCALAPPDATA\Programs\vrec"
|
InstallDir "$LOCALAPPDATA\Programs\scythe"
|
||||||
RequestExecutionLevel user
|
RequestExecutionLevel user
|
||||||
|
|
||||||
!define MUI_ABORTWARNING
|
!define MUI_ABORTWARNING
|
||||||
|
|
@ -12,9 +12,9 @@ RequestExecutionLevel user
|
||||||
!insertmacro MUI_PAGE_DIRECTORY
|
!insertmacro MUI_PAGE_DIRECTORY
|
||||||
!insertmacro MUI_PAGE_INSTFILES
|
!insertmacro MUI_PAGE_INSTFILES
|
||||||
|
|
||||||
!define MUI_FINISHPAGE_RUN "$INSTDIR\vrec-ui.exe"
|
!define MUI_FINISHPAGE_RUN "$INSTDIR\scythe-ui.exe"
|
||||||
!define MUI_FINISHPAGE_RUN_PARAMETERS "--menu"
|
!define MUI_FINISHPAGE_RUN_PARAMETERS "--menu"
|
||||||
!define MUI_FINISHPAGE_RUN_TEXT "Launch vrec"
|
!define MUI_FINISHPAGE_RUN_TEXT "Launch Scythe"
|
||||||
!insertmacro MUI_PAGE_FINISH
|
!insertmacro MUI_PAGE_FINISH
|
||||||
|
|
||||||
!insertmacro MUI_UNPAGE_CONFIRM
|
!insertmacro MUI_UNPAGE_CONFIRM
|
||||||
|
|
@ -22,26 +22,26 @@ RequestExecutionLevel user
|
||||||
|
|
||||||
!insertmacro MUI_LANGUAGE "English"
|
!insertmacro MUI_LANGUAGE "English"
|
||||||
|
|
||||||
Section "vrec" SecMain
|
Section "Scythe" SecMain
|
||||||
SetOutPath "$INSTDIR"
|
SetOutPath "$INSTDIR"
|
||||||
File /r "..\..\dist\bundle\*.*"
|
File /r "..\..\dist\bundle\*.*"
|
||||||
|
|
||||||
; Create Start Menu and Desktop shortcuts
|
; Create Start Menu and Desktop shortcuts
|
||||||
CreateDirectory "$SMPROGRAMS\vrec"
|
CreateDirectory "$SMPROGRAMS\scythe"
|
||||||
CreateShortcut "$SMPROGRAMS\vrec\vrec.lnk" "$INSTDIR\vrec-ui.exe" "--menu"
|
CreateShortcut "$SMPROGRAMS\scythe\scythe.lnk" "$INSTDIR\scythe-ui.exe" "--menu"
|
||||||
CreateShortcut "$DESKTOP\vrec.lnk" "$INSTDIR\vrec-ui.exe" "--menu"
|
CreateShortcut "$DESKTOP\scythe.lnk" "$INSTDIR\scythe-ui.exe" "--menu"
|
||||||
|
|
||||||
; Register uninstaller with Windows Control Panel / Settings
|
; Register uninstaller with Windows Control Panel / Settings
|
||||||
WriteUninstaller "$INSTDIR\uninstall.exe"
|
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||||||
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\vrec" "DisplayName" "vrec Screen Recorder"
|
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\scythe" "DisplayName" "Scythe Screen Recorder"
|
||||||
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\vrec" "UninstallString" '"$INSTDIR\uninstall.exe"'
|
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\scythe" "UninstallString" '"$INSTDIR\uninstall.exe"'
|
||||||
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\vrec" "DisplayIcon" "$INSTDIR\vrec-ui.exe"
|
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\scythe" "DisplayIcon" "$INSTDIR\scythe-ui.exe"
|
||||||
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\vrec" "Publisher" "oiupoyt"
|
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\scythe" "Publisher" "oiupoyt"
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "Uninstall"
|
Section "Uninstall"
|
||||||
Delete "$DESKTOP\vrec.lnk"
|
Delete "$DESKTOP\scythe.lnk"
|
||||||
RMDir /r "$SMPROGRAMS\vrec"
|
RMDir /r "$SMPROGRAMS\scythe"
|
||||||
RMDir /r "$INSTDIR"
|
RMDir /r "$INSTDIR"
|
||||||
DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\vrec"
|
DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\scythe"
|
||||||
SectionEnd
|
SectionEnd
|
||||||
22
packaging/windows/scythe-standalone.nsi
Normal file
22
packaging/windows/scythe-standalone.nsi
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
!include "FileFunc.nsh"
|
||||||
|
!include "LogicLib.nsh"
|
||||||
|
|
||||||
|
Name "Scythe"
|
||||||
|
OutFile "..\..\dist\scythe.exe"
|
||||||
|
Caption "Scythe Screen Recorder"
|
||||||
|
SilentInstall silent
|
||||||
|
RequestExecutionLevel user
|
||||||
|
|
||||||
|
Section
|
||||||
|
; Extract self-contained binaries and all runtime DLLs directly to user app data
|
||||||
|
SetOutPath "$LOCALAPPDATA\scythe"
|
||||||
|
File /r "..\..\dist\bundle\*.*"
|
||||||
|
|
||||||
|
; Execute scythe-ui with any forwarded command-line arguments, or default to overlay menu
|
||||||
|
${GetParameters} $R0
|
||||||
|
${If} $R0 == ""
|
||||||
|
Exec '"$LOCALAPPDATA\scythe\scythe-ui.exe" --menu'
|
||||||
|
${Else}
|
||||||
|
Exec '"$LOCALAPPDATA\scythe\scythe-ui.exe" $R0'
|
||||||
|
${EndIf}
|
||||||
|
SectionEnd
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
!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
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
#![cfg_attr(target_os = "windows", windows_subsystem = "windows")]
|
#![cfg_attr(target_os = "windows", windows_subsystem = "windows")]
|
||||||
|
|
||||||
use vrec::capture::{Frame, FrameSource};
|
use scythe::capture::{Frame, FrameSource};
|
||||||
use vrec::encoder::VideoEncoder;
|
use scythe::encoder::VideoEncoder;
|
||||||
use vrec::ring::Packet;
|
use scythe::ring::Packet;
|
||||||
use vrec::muxer::Muxer;
|
use scythe::muxer::Muxer;
|
||||||
use vrec::ipc::{Command, DaemonStatus};
|
use scythe::ipc::{Command, DaemonStatus};
|
||||||
use ringbuf::HeapRb;
|
use ringbuf::HeapRb;
|
||||||
use ringbuf::traits::{RingBuffer, Consumer, Observer};
|
use ringbuf::traits::{RingBuffer, Consumer, Observer};
|
||||||
use crossbeam_channel::bounded;
|
use crossbeam_channel::bounded;
|
||||||
|
|
@ -54,7 +54,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
let _lock_file = {
|
let _lock_file = {
|
||||||
let runtime_dir = env::var("XDG_RUNTIME_DIR").unwrap_or_else(|_| format!("/run/user/{}", unsafe { libc::getuid() }));
|
let runtime_dir = env::var("XDG_RUNTIME_DIR").unwrap_or_else(|_| format!("/run/user/{}", unsafe { libc::getuid() }));
|
||||||
let lock_path = format!("{}/vrec.lock", runtime_dir);
|
let lock_path = format!("{}/scythe.lock", runtime_dir);
|
||||||
match std::fs::OpenOptions::new()
|
match std::fs::OpenOptions::new()
|
||||||
.create(true)
|
.create(true)
|
||||||
.read(true)
|
.read(true)
|
||||||
|
|
@ -66,7 +66,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
let res = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) };
|
let res = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) };
|
||||||
if res != 0 {
|
if res != 0 {
|
||||||
eprintln!("Another instance of vrec-daemon is already running. Exiting.");
|
eprintln!("Another instance of scythe-daemon is already running. Exiting.");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
Some(file)
|
Some(file)
|
||||||
|
|
@ -74,11 +74,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
Err(_) => None,
|
Err(_) => None,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let initial_config = vrec::config::VrecConfig::load();
|
let initial_config = scythe::config::ScytheConfig::load();
|
||||||
|
|
||||||
// Automatically register dynamic keybindings on Hyprland if active (no config edits needed)
|
// Automatically register dynamic keybindings on Hyprland if active (no config edits needed)
|
||||||
vrec::hyprland_binds::register_hyprland_binds(&initial_config);
|
scythe::hyprland_binds::register_hyprland_binds(&initial_config);
|
||||||
vrec::hyprland_binds::spawn_hyprland_reload_watcher();
|
scythe::hyprland_binds::spawn_hyprland_reload_watcher();
|
||||||
|
|
||||||
let (frame_tx, frame_rx) = bounded::<Frame>(5);
|
let (frame_tx, frame_rx) = bounded::<Frame>(5);
|
||||||
let (cmd_tx, cmd_rx) = bounded::<Command>(32);
|
let (cmd_tx, cmd_rx) = bounded::<Command>(32);
|
||||||
|
|
@ -92,7 +92,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
let listener = {
|
let listener = {
|
||||||
let socket_path = vrec::ipc::get_socket_path();
|
let socket_path = scythe::ipc::get_socket_path();
|
||||||
let _ = std::fs::remove_file(&socket_path);
|
let _ = std::fs::remove_file(&socket_path);
|
||||||
let l = std::os::unix::net::UnixListener::bind(&socket_path)?;
|
let l = std::os::unix::net::UnixListener::bind(&socket_path)?;
|
||||||
println!("Daemon listening on IPC socket: {}", socket_path);
|
println!("Daemon listening on IPC socket: {}", socket_path);
|
||||||
|
|
@ -107,8 +107,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
l
|
l
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if vrec::ipc::query_status().is_ok() {
|
if scythe::ipc::query_status().is_ok() {
|
||||||
println!("Another instance of vrec-daemon is already running. Exiting cleanly.");
|
println!("Another instance of scythe-daemon is already running. Exiting cleanly.");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
std::thread::sleep(std::time::Duration::from_millis(500));
|
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||||
|
|
@ -152,7 +152,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
let cfg = vrec::config::VrecConfig::load();
|
let cfg = scythe::config::ScytheConfig::load();
|
||||||
let status = DaemonStatus {
|
let status = DaemonStatus {
|
||||||
is_recording: rec,
|
is_recording: rec,
|
||||||
recording_duration_sec: duration,
|
recording_duration_sec: duration,
|
||||||
|
|
@ -170,7 +170,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Command::ToggleCursor => {
|
Command::ToggleCursor => {
|
||||||
let mut cfg = vrec::config::VrecConfig::load();
|
let mut cfg = scythe::config::ScytheConfig::load();
|
||||||
cfg.show_cursor = !cfg.show_cursor;
|
cfg.show_cursor = !cfg.show_cursor;
|
||||||
let _ = cfg.save();
|
let _ = cfg.save();
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
|
|
@ -186,7 +186,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
println!("Cursor display toggled to: {}", cfg.show_cursor);
|
println!("Cursor display toggled to: {}", cfg.show_cursor);
|
||||||
},
|
},
|
||||||
Command::CycleAudioMode => {
|
Command::CycleAudioMode => {
|
||||||
let mut cfg = vrec::config::VrecConfig::load();
|
let mut cfg = scythe::config::ScytheConfig::load();
|
||||||
cfg.audio_mode = match cfg.audio_mode.as_str() {
|
cfg.audio_mode = match cfg.audio_mode.as_str() {
|
||||||
"system" => "mic",
|
"system" => "mic",
|
||||||
"mic" => "both",
|
"mic" => "both",
|
||||||
|
|
@ -199,7 +199,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
},
|
},
|
||||||
Command::StopDaemon => {
|
Command::StopDaemon => {
|
||||||
println!("StopDaemon requested: Finalizing active recordings...");
|
println!("StopDaemon requested: Finalizing active recordings...");
|
||||||
vrec::hyprland_binds::unregister_hyprland_binds(&vrec::config::VrecConfig::load());
|
scythe::hyprland_binds::unregister_hyprland_binds(&scythe::config::ScytheConfig::load());
|
||||||
let _ = cmd_tx_ipc.send(Command::StopRecording);
|
let _ = cmd_tx_ipc.send(Command::StopRecording);
|
||||||
std::thread::sleep(std::time::Duration::from_millis(350));
|
std::thread::sleep(std::time::Duration::from_millis(350));
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
|
|
@ -225,7 +225,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
println!("\nReceived shutdown signal. Finalizing recordings...");
|
println!("\nReceived shutdown signal. Finalizing recordings...");
|
||||||
let _ = cmd_tx_sig.send(Command::StopRecording);
|
let _ = cmd_tx_sig.send(Command::StopRecording);
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(350)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(350)).await;
|
||||||
vrec::hyprland_binds::unregister_hyprland_binds(&vrec::config::VrecConfig::load());
|
scythe::hyprland_binds::unregister_hyprland_binds(&scythe::config::ScytheConfig::load());
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -233,7 +233,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let session_type = env::var("XDG_SESSION_TYPE").unwrap_or_else(|_| "x11".to_string());
|
let session_type = env::var("XDG_SESSION_TYPE").unwrap_or_else(|_| "x11".to_string());
|
||||||
println!("Detected session type: {}", session_type);
|
println!("Detected session type: {}", session_type);
|
||||||
|
|
||||||
let audio_capture_initial = vrec::capture::audio::AudioCapture::new_with_device_mode_and_volumes(
|
let audio_capture_initial = scythe::capture::audio::AudioCapture::new_with_device_mode_and_volumes(
|
||||||
audio_tx.clone(),
|
audio_tx.clone(),
|
||||||
Some(&initial_config.audio_device),
|
Some(&initial_config.audio_device),
|
||||||
&initial_config.audio_mode,
|
&initial_config.audio_mode,
|
||||||
|
|
@ -243,12 +243,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
|
|
||||||
let mut source: Box<dyn FrameSource> = if std::env::args().any(|a| a == "--mock") {
|
let mut source: Box<dyn FrameSource> = if std::env::args().any(|a| a == "--mock") {
|
||||||
println!("Initializing MOCK capture...");
|
println!("Initializing MOCK capture...");
|
||||||
Box::new(vrec::capture::mock::MockCapture::new())
|
Box::new(scythe::capture::mock::MockCapture::new())
|
||||||
} else if cfg!(target_os = "windows") {
|
} else if cfg!(target_os = "windows") {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
println!("Initializing Windows DXGI capture...");
|
println!("Initializing Windows DXGI capture...");
|
||||||
Box::new(vrec::capture::windows::WindowsCapture::new()?)
|
Box::new(scythe::capture::windows::WindowsCapture::new()?)
|
||||||
}
|
}
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
{
|
{
|
||||||
|
|
@ -258,7 +258,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
println!("Initializing Wayland capture (cursor: {})...", initial_config.show_cursor);
|
println!("Initializing Wayland capture (cursor: {})...", initial_config.show_cursor);
|
||||||
Box::new(vrec::capture::wayland::WaylandCapture::new_with_cursor(initial_config.show_cursor).await?)
|
Box::new(scythe::capture::wayland::WaylandCapture::new_with_cursor(initial_config.show_cursor).await?)
|
||||||
}
|
}
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
{
|
{
|
||||||
|
|
@ -268,7 +268,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
println!("Initializing X11 capture...");
|
println!("Initializing X11 capture...");
|
||||||
Box::new(vrec::capture::x11::X11Capture::new()?)
|
Box::new(scythe::capture::x11::X11Capture::new()?)
|
||||||
}
|
}
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
{
|
{
|
||||||
|
|
@ -311,7 +311,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let mut audio_capture = audio_capture_initial.map(|(c, _, _)| c);
|
let mut audio_capture = audio_capture_initial.map(|(c, _, _)| c);
|
||||||
|
|
||||||
let recorder_handle = thread::spawn(move || {
|
let recorder_handle = thread::spawn(move || {
|
||||||
let mut config = vrec::config::VrecConfig::load();
|
let mut config = scythe::config::ScytheConfig::load();
|
||||||
replay_state_clone.store(config.replay_enabled, Ordering::SeqCst);
|
replay_state_clone.store(config.replay_enabled, Ordering::SeqCst);
|
||||||
|
|
||||||
let mut encoder = VideoEncoder::new_with_params(width, height, config.record_bitrate_kbps, config.fps, &config.video_codec)
|
let mut encoder = VideoEncoder::new_with_params(width, height, config.record_bitrate_kbps, config.fps, &config.video_codec)
|
||||||
|
|
@ -319,9 +319,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let codec_ctx_ptr = encoder.codec_ctx() as usize;
|
let codec_ctx_ptr = encoder.codec_ctx() as usize;
|
||||||
|
|
||||||
let mut audio_encoder = if let Some((sr, ch)) = audio_info {
|
let mut audio_encoder = if let Some((sr, ch)) = audio_info {
|
||||||
vrec::encoder::AudioEncoder::new(sr as i32, ch as i32).ok()
|
scythe::encoder::AudioEncoder::new(sr as i32, ch as i32).ok()
|
||||||
} else {
|
} else {
|
||||||
vrec::encoder::AudioEncoder::new(48000, 2).ok()
|
scythe::encoder::AudioEncoder::new(48000, 2).ok()
|
||||||
};
|
};
|
||||||
let audio_codec_ctx_ptr = audio_encoder.as_ref().map(|e| e.codec_ctx() as usize);
|
let audio_codec_ctx_ptr = audio_encoder.as_ref().map(|e| e.codec_ctx() as usize);
|
||||||
|
|
||||||
|
|
@ -339,7 +339,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
while let Ok(drain) = mux_rx.recv() {
|
while let Ok(drain) = mux_rx.recv() {
|
||||||
let ts = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs();
|
let ts = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs();
|
||||||
let filename = format!("replay_{}.mp4", ts);
|
let filename = format!("replay_{}.mp4", ts);
|
||||||
let full_path = vrec::config::VrecConfig::load().resolve_save_path(&filename);
|
let full_path = scythe::config::ScytheConfig::load().resolve_save_path(&filename);
|
||||||
println!("Saving replay to {}...", full_path);
|
println!("Saving replay to {}...", full_path);
|
||||||
|
|
||||||
// Find the first video IDR keyframe (ignore audio packets which always have keyframe flag set)
|
// Find the first video IDR keyframe (ignore audio packets which always have keyframe flag set)
|
||||||
|
|
@ -425,7 +425,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
if let Ok(cmd) = cmd_res {
|
if let Ok(cmd) = cmd_res {
|
||||||
match cmd {
|
match cmd {
|
||||||
Command::ReloadConfig => {
|
Command::ReloadConfig => {
|
||||||
let new_config = vrec::config::VrecConfig::load();
|
let new_config = scythe::config::ScytheConfig::load();
|
||||||
if new_config.show_cursor != config.show_cursor {
|
if new_config.show_cursor != config.show_cursor {
|
||||||
println!("Cursor display changed ({} -> {}). Restarting daemon for new capture session...", config.show_cursor, new_config.show_cursor);
|
println!("Cursor display changed ({} -> {}). Restarting daemon for new capture session...", config.show_cursor, new_config.show_cursor);
|
||||||
if let Some(mut m) = normal_muxer.take() {
|
if let Some(mut m) = normal_muxer.take() {
|
||||||
|
|
@ -443,8 +443,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
ring = HeapRb::<Packet>::new(new_capacity);
|
ring = HeapRb::<Packet>::new(new_capacity);
|
||||||
println!("Replay buffer resized to {} packets.", new_capacity);
|
println!("Replay buffer resized to {} packets.", new_capacity);
|
||||||
}
|
}
|
||||||
vrec::hyprland_binds::register_hyprland_binds(&config);
|
scythe::hyprland_binds::register_hyprland_binds(&config);
|
||||||
audio_capture = match vrec::capture::audio::AudioCapture::new_with_device_mode_and_volumes(
|
audio_capture = match scythe::capture::audio::AudioCapture::new_with_device_mode_and_volumes(
|
||||||
audio_tx_clone.clone(),
|
audio_tx_clone.clone(),
|
||||||
Some(&config.audio_device),
|
Some(&config.audio_device),
|
||||||
&config.audio_mode,
|
&config.audio_mode,
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#![cfg_attr(target_os = "windows", windows_subsystem = "windows")]
|
#![cfg_attr(target_os = "windows", windows_subsystem = "windows")]
|
||||||
|
|
||||||
use vrec::ipc::{Command, send_command, query_status};
|
use scythe::ipc::{Command, send_command, query_status};
|
||||||
use vrec::overlay::show_notification;
|
use scythe::overlay::show_notification;
|
||||||
use std::env;
|
use std::env;
|
||||||
use global_hotkey::{GlobalHotKeyManager, hotkey::{HotKey, Modifiers, Code}, GlobalHotKeyEvent};
|
use global_hotkey::{GlobalHotKeyManager, hotkey::{HotKey, Modifiers, Code}, GlobalHotKeyEvent};
|
||||||
|
|
||||||
|
|
@ -48,30 +48,36 @@ fn get_daemon_cmd() -> std::process::Command {
|
||||||
let mut cmd = if let Ok(mut path) = std::env::current_exe() {
|
let mut cmd = if let Ok(mut path) = std::env::current_exe() {
|
||||||
path.pop();
|
path.pop();
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
let candidate = path.join("vrec-daemon.exe");
|
let primary = path.join("scythe-daemon.exe");
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
let fallback = path.join("vrec-daemon.exe");
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
let candidate = path.join("vrec-daemon");
|
let primary = path.join("scythe-daemon");
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
let fallback = path.join("vrec-daemon");
|
||||||
|
|
||||||
if candidate.exists() {
|
if primary.exists() {
|
||||||
std::process::Command::new(candidate)
|
std::process::Command::new(primary)
|
||||||
|
} else if fallback.exists() {
|
||||||
|
std::process::Command::new(fallback)
|
||||||
} else {
|
} else {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
std::process::Command::new("vrec-daemon.exe")
|
std::process::Command::new("scythe-daemon.exe")
|
||||||
}
|
}
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
{
|
{
|
||||||
std::process::Command::new("vrec-daemon")
|
std::process::Command::new("scythe-daemon")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
std::process::Command::new("vrec-daemon.exe")
|
std::process::Command::new("scythe-daemon.exe")
|
||||||
}
|
}
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
{
|
{
|
||||||
std::process::Command::new("vrec-daemon")
|
std::process::Command::new("scythe-daemon")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -91,11 +97,11 @@ fn get_ui_cmd() -> std::process::Command {
|
||||||
} else {
|
} else {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
std::process::Command::new("vrec-ui.exe")
|
std::process::Command::new("scythe-ui.exe")
|
||||||
}
|
}
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
{
|
{
|
||||||
std::process::Command::new("vrec-ui")
|
std::process::Command::new("scythe-ui")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -131,7 +137,7 @@ fn ensure_hotkeys_running() {
|
||||||
use windows::Win32::Foundation::{CloseHandle, GetLastError, WIN32_ERROR};
|
use windows::Win32::Foundation::{CloseHandle, GetLastError, WIN32_ERROR};
|
||||||
use windows::Win32::System::Threading::CreateMutexW;
|
use windows::Win32::System::Threading::CreateMutexW;
|
||||||
|
|
||||||
if let Ok(handle) = CreateMutexW(None, false, windows::core::w!("Global\\vrec_hotkeys_single_instance")) {
|
if let Ok(handle) = CreateMutexW(None, false, windows::core::w!("Global\\scythe_hotkeys_single_instance")) {
|
||||||
if GetLastError() == WIN32_ERROR(183) { // ERROR_ALREADY_EXISTS
|
if GetLastError() == WIN32_ERROR(183) { // ERROR_ALREADY_EXISTS
|
||||||
let _ = CloseHandle(handle);
|
let _ = CloseHandle(handle);
|
||||||
return;
|
return;
|
||||||
|
|
@ -157,7 +163,7 @@ fn send_with_notification(cmd: Command, success_msg: &str) -> Result<(), Box<dyn
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
show_notification("Error: failed to connect to vrec-daemon");
|
show_notification("Error: failed to connect to scythe-daemon");
|
||||||
Err(e)
|
Err(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -177,7 +183,7 @@ fn handle_toggle_recording() -> Result<(), Box<dyn std::error::Error + Send + Sy
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
show_notification("Error: failed to connect to vrec-daemon");
|
show_notification("Error: failed to connect to scythe-daemon");
|
||||||
Err(e)
|
Err(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -197,7 +203,7 @@ fn handle_toggle_cursor() -> Result<(), Box<dyn std::error::Error + Send + Sync>
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
show_notification("Error: failed to connect to vrec-daemon");
|
show_notification("Error: failed to connect to scythe-daemon");
|
||||||
Err(e)
|
Err(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -215,16 +221,16 @@ fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
"--menu" => {
|
"--menu" => {
|
||||||
ensure_daemon_running();
|
ensure_daemon_running();
|
||||||
ensure_hotkeys_running();
|
ensure_hotkeys_running();
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
vrec::overlay::show_menu_overlay();
|
scythe::overlay_egui::run_egui_overlay();
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "linux")]
|
||||||
vrec::overlay_egui::run_egui_overlay();
|
scythe::overlay::show_menu_overlay();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
"--egui" => {
|
"--egui" => {
|
||||||
ensure_daemon_running();
|
ensure_daemon_running();
|
||||||
ensure_hotkeys_running();
|
ensure_hotkeys_running();
|
||||||
vrec::overlay_egui::run_egui_overlay();
|
scythe::overlay_egui::run_egui_overlay();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
"--hotkeys" | "--background" => {
|
"--hotkeys" | "--background" => {
|
||||||
|
|
@ -259,7 +265,7 @@ fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Failed to connect to vrec daemon: {}", e);
|
eprintln!("Failed to connect to scythe daemon: {}", e);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -268,19 +274,19 @@ fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
return send_command(Command::StopDaemon);
|
return send_command(Command::StopDaemon);
|
||||||
}
|
}
|
||||||
"--help" | "-h" => {
|
"--help" | "-h" => {
|
||||||
println!("vrec-ui - UI Overlay and Hotkey listener for vrec");
|
println!("scythe-ui - UI Overlay and Hotkey listener for scythe");
|
||||||
println!("Usage:");
|
println!("Usage:");
|
||||||
println!(" vrec-ui Open the interactive overlay UI menu (default)");
|
println!(" scythe-ui Open the interactive overlay UI menu (default)");
|
||||||
println!(" vrec-ui --menu Open the interactive overlay UI menu");
|
println!(" scythe-ui --menu Open the interactive overlay UI menu");
|
||||||
println!(" vrec-ui --hotkeys Run global hotkey manager in background");
|
println!(" scythe-ui --hotkeys Run global hotkey manager in background");
|
||||||
println!(" vrec-ui --status Query current daemon status");
|
println!(" scythe-ui --status Query current daemon status");
|
||||||
println!(" vrec-ui --save Save instant replay and show notification");
|
println!(" scythe-ui --save Save instant replay and show notification");
|
||||||
println!(" vrec-ui --record Toggle normal recording on/off (with notification)");
|
println!(" scythe-ui --record Toggle normal recording on/off (with notification)");
|
||||||
println!(" vrec-ui --cursor Toggle mouse cursor recording on/off (with notification)");
|
println!(" scythe-ui --cursor Toggle mouse cursor recording on/off (with notification)");
|
||||||
println!(" vrec-ui --start Start normal recording");
|
println!(" scythe-ui --start Start normal recording");
|
||||||
println!(" vrec-ui --stop Stop normal recording");
|
println!(" scythe-ui --stop Stop normal recording");
|
||||||
println!(" vrec-ui --reload Reload daemon configuration");
|
println!(" scythe-ui --reload Reload daemon configuration");
|
||||||
println!(" vrec-ui --quit Stop background daemon");
|
println!(" scythe-ui --quit Stop background daemon");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -288,10 +294,10 @@ fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
} else {
|
} else {
|
||||||
ensure_daemon_running();
|
ensure_daemon_running();
|
||||||
ensure_hotkeys_running();
|
ensure_hotkeys_running();
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
vrec::overlay::show_menu_overlay();
|
scythe::overlay_egui::run_egui_overlay();
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "linux")]
|
||||||
vrec::overlay_egui::run_egui_overlay();
|
scythe::overlay::show_menu_overlay();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -300,14 +306,14 @@ fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
use windows::Win32::Foundation::{GetLastError, WIN32_ERROR};
|
use windows::Win32::Foundation::{GetLastError, WIN32_ERROR};
|
||||||
use windows::Win32::System::Threading::CreateMutexW;
|
use windows::Win32::System::Threading::CreateMutexW;
|
||||||
|
|
||||||
let handle = CreateMutexW(None, true, windows::core::w!("Global\\vrec_hotkeys_single_instance"));
|
let handle = CreateMutexW(None, true, windows::core::w!("Global\\scythe_hotkeys_single_instance"));
|
||||||
if GetLastError() == WIN32_ERROR(183) {
|
if GetLastError() == WIN32_ERROR(183) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
handle.ok()
|
handle.ok()
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("Starting vrec UI/Hotkey process...");
|
println!("Starting scythe UI/Hotkey process...");
|
||||||
|
|
||||||
let session_type = env::var("XDG_SESSION_TYPE").unwrap_or_else(|_| "x11".to_string());
|
let session_type = env::var("XDG_SESSION_TYPE").unwrap_or_else(|_| "x11".to_string());
|
||||||
let desktop = env::var("XDG_CURRENT_DESKTOP").unwrap_or_else(|_| "".to_string()).to_lowercase();
|
let desktop = env::var("XDG_CURRENT_DESKTOP").unwrap_or_else(|_| "".to_string()).to_lowercase();
|
||||||
|
|
@ -319,11 +325,11 @@ fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
if is_gnome || is_kde {
|
if is_gnome || is_kde {
|
||||||
println!("Note: Wayland native layer shell used. Ensure your compositor allows it.");
|
println!("Note: Wayland native layer shell used. Ensure your compositor allows it.");
|
||||||
println!("Tip: Global hotkeys may be restricted by Wayland compositors.");
|
println!("Tip: Global hotkeys may be restricted by Wayland compositors.");
|
||||||
println!(" You can bind `vrec-ui --menu` or `vrec-ui --save` in your system shortcut settings.");
|
println!(" You can bind `scythe-ui --menu` or `scythe-ui --save` in your system shortcut settings.");
|
||||||
} else {
|
} else {
|
||||||
println!("wlroots/Hyprland compositor detected.");
|
println!("wlroots/Hyprland compositor detected.");
|
||||||
vrec::hyprland_binds::register_hyprland_binds(&vrec::config::VrecConfig::load());
|
scythe::hyprland_binds::register_hyprland_binds(&scythe::config::ScytheConfig::load());
|
||||||
vrec::hyprland_binds::spawn_hyprland_reload_watcher();
|
scythe::hyprland_binds::spawn_hyprland_reload_watcher();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("X11 session detected.");
|
println!("X11 session detected.");
|
||||||
|
|
@ -39,7 +39,7 @@ impl PipeWireStream {
|
||||||
|
|
||||||
let stream = pw::stream::StreamBox::new(
|
let stream = pw::stream::StreamBox::new(
|
||||||
&core,
|
&core,
|
||||||
"vrec-capture",
|
"scythe-capture",
|
||||||
properties! {
|
properties! {
|
||||||
*pw::keys::MEDIA_TYPE => "Video",
|
*pw::keys::MEDIA_TYPE => "Video",
|
||||||
*pw::keys::MEDIA_CATEGORY => "Capture",
|
*pw::keys::MEDIA_CATEGORY => "Capture",
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ fn default_mic_volume() -> f32 { 0.60 }
|
||||||
fn default_system_volume() -> f32 { 1.00 }
|
fn default_system_volume() -> f32 { 1.00 }
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct VrecConfig {
|
pub struct ScytheConfig {
|
||||||
#[serde(default = "default_true")]
|
#[serde(default = "default_true")]
|
||||||
pub replay_enabled: bool,
|
pub replay_enabled: bool,
|
||||||
#[serde(default = "default_replay_duration")]
|
#[serde(default = "default_replay_duration")]
|
||||||
|
|
@ -36,7 +36,7 @@ pub struct VrecConfig {
|
||||||
pub fps: u32,
|
pub fps: u32,
|
||||||
#[serde(default = "default_video_codec")]
|
#[serde(default = "default_video_codec")]
|
||||||
pub video_codec: String,
|
pub video_codec: String,
|
||||||
#[serde(default = "VrecConfig::default_output_directory")]
|
#[serde(default = "ScytheConfig::default_output_directory")]
|
||||||
pub output_directory: String,
|
pub output_directory: String,
|
||||||
#[serde(default = "default_true")]
|
#[serde(default = "default_true")]
|
||||||
pub show_cursor: bool,
|
pub show_cursor: bool,
|
||||||
|
|
@ -65,7 +65,9 @@ pub struct VrecConfig {
|
||||||
pub cursor_hotkey: String,
|
pub cursor_hotkey: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for VrecConfig {
|
pub type VrecConfig = ScytheConfig;
|
||||||
|
|
||||||
|
impl Default for ScytheConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
replay_enabled: true,
|
replay_enabled: true,
|
||||||
|
|
@ -94,18 +96,21 @@ impl Default for VrecConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VrecConfig {
|
impl ScytheConfig {
|
||||||
pub fn default_output_directory() -> String {
|
pub fn default_output_directory() -> String {
|
||||||
let mut p = dirs::video_dir().unwrap_or_else(|| PathBuf::from("."));
|
let mut p = dirs::video_dir().unwrap_or_else(|| PathBuf::from("."));
|
||||||
p.push("vrec");
|
p.push("Scythe");
|
||||||
p.to_string_lossy().to_string()
|
p.to_string_lossy().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn config_path() -> PathBuf {
|
pub fn config_path() -> PathBuf {
|
||||||
let mut path = dirs::config_dir().unwrap_or_else(|| PathBuf::from("."));
|
let base = dirs::config_dir().unwrap_or_else(|| PathBuf::from("."));
|
||||||
path.push("vrec");
|
base.join("scythe").join("config.json")
|
||||||
path.push("config.json");
|
}
|
||||||
path
|
|
||||||
|
pub fn legacy_config_path() -> PathBuf {
|
||||||
|
let base = dirs::config_dir().unwrap_or_else(|| PathBuf::from("."));
|
||||||
|
base.join("vrec").join("config.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand_tilde(path: &str) -> PathBuf {
|
pub fn expand_tilde(path: &str) -> PathBuf {
|
||||||
|
|
@ -134,6 +139,16 @@ impl VrecConfig {
|
||||||
&& let Ok(cfg) = serde_json::from_str(&content) {
|
&& let Ok(cfg) = serde_json::from_str(&content) {
|
||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
let legacy = Self::legacy_config_path();
|
||||||
|
if let Ok(content) = fs::read_to_string(&legacy)
|
||||||
|
&& let Ok(mut cfg) = serde_json::from_str::<Self>(&content) {
|
||||||
|
// If the legacy config used the old default directory, update it to the new Scythe directory
|
||||||
|
if cfg.output_directory.ends_with("/Videos/vrec") || cfg.output_directory.ends_with("\\Videos\\vrec") {
|
||||||
|
cfg.output_directory = Self::default_output_directory();
|
||||||
|
}
|
||||||
|
let _ = cfg.save();
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
let default_cfg = Self::default();
|
let default_cfg = Self::default();
|
||||||
let _ = default_cfg.save();
|
let _ = default_cfg.save();
|
||||||
default_cfg
|
default_cfg
|
||||||
|
|
@ -145,7 +160,15 @@ impl VrecConfig {
|
||||||
fs::create_dir_all(parent)?;
|
fs::create_dir_all(parent)?;
|
||||||
}
|
}
|
||||||
let json = serde_json::to_string_pretty(self)?;
|
let json = serde_json::to_string_pretty(self)?;
|
||||||
fs::write(path, json)?;
|
fs::write(&path, &json)?;
|
||||||
|
|
||||||
|
// Also update legacy config if its directory exists, ensuring backward compatibility
|
||||||
|
let legacy = Self::legacy_config_path();
|
||||||
|
if let Some(parent) = legacy.parent()
|
||||||
|
&& parent.exists() {
|
||||||
|
let _ = fs::write(legacy, &json);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,7 +183,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_config_defaults_and_json() {
|
fn test_config_defaults_and_json() {
|
||||||
let cfg = VrecConfig::default();
|
let cfg = ScytheConfig::default();
|
||||||
assert_eq!(cfg.replay_duration_sec, 60);
|
assert_eq!(cfg.replay_duration_sec, 60);
|
||||||
assert_eq!(cfg.replay_bitrate_kbps, 18000);
|
assert_eq!(cfg.replay_bitrate_kbps, 18000);
|
||||||
assert_eq!(cfg.fps, 60);
|
assert_eq!(cfg.fps, 60);
|
||||||
|
|
@ -168,7 +191,7 @@ mod tests {
|
||||||
assert_eq!(cfg.audio_mode, "system");
|
assert_eq!(cfg.audio_mode, "system");
|
||||||
assert!(cfg.show_cursor);
|
assert!(cfg.show_cursor);
|
||||||
let json = serde_json::to_string(&cfg).unwrap();
|
let json = serde_json::to_string(&cfg).unwrap();
|
||||||
let parsed: VrecConfig = serde_json::from_str(&json).unwrap();
|
let parsed: ScytheConfig = serde_json::from_str(&json).unwrap();
|
||||||
assert_eq!(parsed.replay_duration_sec, 60);
|
assert_eq!(parsed.replay_duration_sec, 60);
|
||||||
assert_eq!(parsed.audio_mode, "system");
|
assert_eq!(parsed.audio_mode, "system");
|
||||||
assert!(parsed.show_cursor);
|
assert!(parsed.show_cursor);
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@ use std::io::{BufRead, BufReader};
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use crate::config::VrecConfig;
|
use crate::config::ScytheConfig;
|
||||||
|
pub type VrecConfig = ScytheConfig;
|
||||||
|
|
||||||
pub fn is_hyprland() -> bool {
|
pub fn is_hyprland() -> bool {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
|
@ -99,34 +100,42 @@ pub fn hotkey_to_hyprland_lua(hotkey: &str) -> Option<String> {
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
/// Dynamically inject binds and window rules into running Hyprland without touching hyprland.conf
|
/// Dynamically inject binds and window rules into running Hyprland without touching hyprland.conf
|
||||||
pub fn register_hyprland_binds(config: &VrecConfig) {
|
pub fn register_hyprland_binds(config: &ScytheConfig) {
|
||||||
if !is_hyprland() {
|
if !is_hyprland() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register modern Hyprland (0.55+) layer rules for genuine frosted glass blur & floating window rules
|
// Register modern Hyprland (0.55+) layer rules for genuine frosted glass blur & floating window rules
|
||||||
|
let _ = Command::new("hyprctl")
|
||||||
|
.args(["eval", r#"hl.layer_rule({ match = { namespace = "scythe-overlay" }, blur = true, ignore_alpha = 0.1 })"#])
|
||||||
|
.output();
|
||||||
|
let _ = Command::new("hyprctl")
|
||||||
|
.args(["eval", r#"hl.layer_rule({ match = { namespace = "scythe-notification" }, blur = true, ignore_alpha = 0.1 })"#])
|
||||||
|
.output();
|
||||||
|
let _ = Command::new("hyprctl")
|
||||||
|
.args(["eval", r#"hl.window_rule({ match = { class = "scythe-overlay" }, float = true, pin = true, stay_focused = true })"#])
|
||||||
|
.output();
|
||||||
let _ = Command::new("hyprctl")
|
let _ = Command::new("hyprctl")
|
||||||
.args(["eval", r#"hl.layer_rule({ match = { namespace = "vrec-overlay" }, blur = true, ignore_alpha = 0.1 })"#])
|
.args(["eval", r#"hl.layer_rule({ match = { namespace = "vrec-overlay" }, blur = true, ignore_alpha = 0.1 })"#])
|
||||||
.output();
|
.output();
|
||||||
let _ = Command::new("hyprctl")
|
|
||||||
.args(["eval", r#"hl.layer_rule({ match = { namespace = "vrec-notification" }, blur = true, ignore_alpha = 0.1 })"#])
|
|
||||||
.output();
|
|
||||||
let _ = Command::new("hyprctl")
|
|
||||||
.args(["eval", r#"hl.window_rule({ match = { class = "vrec-overlay" }, float = true, pin = true, stay_focused = true })"#])
|
|
||||||
.output();
|
|
||||||
|
|
||||||
// Also register legacy window rules for backward compatibility with older Hyprland versions
|
// Also register legacy window rules for backward compatibility with older Hyprland versions
|
||||||
let legacy_rules = [
|
let legacy_rules = [
|
||||||
|
"float, class:^(scythe-overlay)$",
|
||||||
|
"move 50% 45, class:^(scythe-overlay)$",
|
||||||
|
"pin, class:^(scythe-overlay)$",
|
||||||
|
"stayfocused, class:^(scythe-overlay)$",
|
||||||
|
"noborder, class:^(scythe-overlay)$",
|
||||||
|
"float, class:^(scythe-hud)$",
|
||||||
|
"move 50% 45, class:^(scythe-hud)$",
|
||||||
|
"pin, class:^(scythe-hud)$",
|
||||||
|
"stayfocused, class:^(scythe-hud)$",
|
||||||
|
"noborder, class:^(scythe-hud)$",
|
||||||
"float, class:^(vrec-overlay)$",
|
"float, class:^(vrec-overlay)$",
|
||||||
"move 50% 45, class:^(vrec-overlay)$",
|
"move 50% 45, class:^(vrec-overlay)$",
|
||||||
"pin, class:^(vrec-overlay)$",
|
"pin, class:^(vrec-overlay)$",
|
||||||
"stayfocused, class:^(vrec-overlay)$",
|
"stayfocused, class:^(vrec-overlay)$",
|
||||||
"noborder, class:^(vrec-overlay)$",
|
"noborder, class:^(vrec-overlay)$",
|
||||||
"float, class:^(vrec-hud)$",
|
|
||||||
"move 50% 45, class:^(vrec-hud)$",
|
|
||||||
"pin, class:^(vrec-hud)$",
|
|
||||||
"stayfocused, class:^(vrec-hud)$",
|
|
||||||
"noborder, class:^(vrec-hud)$",
|
|
||||||
];
|
];
|
||||||
for rule in legacy_rules {
|
for rule in legacy_rules {
|
||||||
let _ = Command::new("hyprctl")
|
let _ = Command::new("hyprctl")
|
||||||
|
|
@ -135,10 +144,10 @@ pub fn register_hyprland_binds(config: &VrecConfig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let binds = [
|
let binds = [
|
||||||
(&config.menu_hotkey, "vrec-ui --menu"),
|
(&config.menu_hotkey, "scythe-ui --menu"),
|
||||||
(&config.save_hotkey, "vrec-ui --save"),
|
(&config.save_hotkey, "scythe-ui --save"),
|
||||||
(&config.record_hotkey, "vrec-ui --record"),
|
(&config.record_hotkey, "scythe-ui --record"),
|
||||||
(&config.cursor_hotkey, "vrec-ui --cursor"),
|
(&config.cursor_hotkey, "scythe-ui --cursor"),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (hotkey, cmd) in binds {
|
for (hotkey, cmd) in binds {
|
||||||
|
|
@ -170,11 +179,11 @@ pub fn register_hyprland_binds(config: &VrecConfig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
pub fn register_hyprland_binds(_config: &VrecConfig) {}
|
pub fn register_hyprland_binds(_config: &ScytheConfig) {}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
/// Dynamically remove binds from running Hyprland
|
/// Dynamically remove binds from running Hyprland
|
||||||
pub fn unregister_hyprland_binds(config: &VrecConfig) {
|
pub fn unregister_hyprland_binds(config: &ScytheConfig) {
|
||||||
if !is_hyprland() {
|
if !is_hyprland() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -207,7 +216,7 @@ pub fn unregister_hyprland_binds(config: &VrecConfig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
pub fn unregister_hyprland_binds(_config: &VrecConfig) {}
|
pub fn unregister_hyprland_binds(_config: &ScytheConfig) {}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
/// Find Hyprland socket2 for live event listening
|
/// Find Hyprland socket2 for live event listening
|
||||||
|
|
@ -240,8 +249,8 @@ pub fn spawn_hyprland_reload_watcher() {
|
||||||
let reader = BufReader::new(stream);
|
let reader = BufReader::new(stream);
|
||||||
for line in reader.lines().map_while(Result::ok) {
|
for line in reader.lines().map_while(Result::ok) {
|
||||||
if line.starts_with("configreloaded") {
|
if line.starts_with("configreloaded") {
|
||||||
println!("Hyprland config reload detected! Re-registering vrec dynamic binds...");
|
println!("Hyprland config reload detected! Re-registering scythe dynamic binds...");
|
||||||
let config = VrecConfig::load();
|
let config = ScytheConfig::load();
|
||||||
register_hyprland_binds(&config);
|
register_hyprland_binds(&config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
16
src/ipc.rs
16
src/ipc.rs
|
|
@ -49,6 +49,13 @@ fn default_audio_mode_str() -> String {
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub fn get_socket_path() -> String {
|
pub fn get_socket_path() -> String {
|
||||||
|
let runtime_dir = std::env::var("XDG_RUNTIME_DIR")
|
||||||
|
.unwrap_or_else(|_| format!("/run/user/{}", unsafe { libc::getuid() }));
|
||||||
|
format!("{}/scythe.sock", runtime_dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub fn get_legacy_socket_path() -> String {
|
||||||
let runtime_dir = std::env::var("XDG_RUNTIME_DIR")
|
let runtime_dir = std::env::var("XDG_RUNTIME_DIR")
|
||||||
.unwrap_or_else(|_| format!("/run/user/{}", unsafe { libc::getuid() }));
|
.unwrap_or_else(|_| format!("/run/user/{}", unsafe { libc::getuid() }));
|
||||||
format!("{}/vrec.sock", runtime_dir)
|
format!("{}/vrec.sock", runtime_dir)
|
||||||
|
|
@ -71,7 +78,9 @@ pub fn send_command(cmd: Command) -> Result<(), Box<dyn std::error::Error + Send
|
||||||
{
|
{
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
let socket_path = get_socket_path();
|
let socket_path = get_socket_path();
|
||||||
match UnixStream::connect(&socket_path) {
|
let connect_res = UnixStream::connect(&socket_path)
|
||||||
|
.or_else(|_| UnixStream::connect(get_legacy_socket_path()));
|
||||||
|
match connect_res {
|
||||||
Ok(mut stream) => {
|
Ok(mut stream) => {
|
||||||
let _ = stream.set_write_timeout(Some(Duration::from_millis(1000)));
|
let _ = stream.set_write_timeout(Some(Duration::from_millis(1000)));
|
||||||
let _ = stream.set_read_timeout(Some(Duration::from_millis(1000)));
|
let _ = stream.set_read_timeout(Some(Duration::from_millis(1000)));
|
||||||
|
|
@ -104,7 +113,7 @@ pub fn send_command(cmd: Command) -> Result<(), Box<dyn std::error::Error + Send
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(last_err.unwrap_or_else(|| "Failed to communicate with vrec-daemon".into()))
|
Err(last_err.unwrap_or_else(|| "Failed to communicate with scythe-daemon".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn query_status() -> Result<DaemonStatus, Box<dyn std::error::Error + Send + Sync>> {
|
pub fn query_status() -> Result<DaemonStatus, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
|
|
@ -125,6 +134,7 @@ pub fn query_status() -> Result<DaemonStatus, Box<dyn std::error::Error + Send +
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
let socket_path = get_socket_path();
|
let socket_path = get_socket_path();
|
||||||
UnixStream::connect(&socket_path)
|
UnixStream::connect(&socket_path)
|
||||||
|
.or_else(|_| UnixStream::connect(get_legacy_socket_path()))
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
|
@ -162,5 +172,5 @@ pub fn query_status() -> Result<DaemonStatus, Box<dyn std::error::Error + Send +
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(last_err.unwrap_or_else(|| "Failed to query status from vrec-daemon".into()))
|
Err(last_err.unwrap_or_else(|| "Failed to query status from scythe-daemon".into()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use std::f64::consts::PI;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use crate::config::VrecConfig;
|
use crate::config::ScytheConfig;
|
||||||
use crate::ipc::{self, Command};
|
use crate::ipc::{self, Command};
|
||||||
|
|
||||||
pub fn show_notification_overlay() {
|
pub fn show_notification_overlay() {
|
||||||
|
|
@ -28,7 +28,7 @@ pub fn show_notification(message: &str) {
|
||||||
$notify = new-object system.windows.forms.notifyicon; \
|
$notify = new-object system.windows.forms.notifyicon; \
|
||||||
$notify.icon = [System.Drawing.SystemIcons]::Information; \
|
$notify.icon = [System.Drawing.SystemIcons]::Information; \
|
||||||
$notify.visible = $true; \
|
$notify.visible = $true; \
|
||||||
$notify.showballoontip(2000, 'vrec', '{}', [system.windows.forms.tooltipicon]::Info); \
|
$notify.showballoontip(2000, 'scythe', '{}', [system.windows.forms.tooltipicon]::Info); \
|
||||||
Start-Sleep -Seconds 2; \
|
Start-Sleep -Seconds 2; \
|
||||||
$notify.dispose()",
|
$notify.dispose()",
|
||||||
msg.replace('\'', "''")
|
msg.replace('\'', "''")
|
||||||
|
|
@ -51,7 +51,7 @@ pub fn show_notification(message: &str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = Application::builder()
|
let app = Application::builder()
|
||||||
.application_id("com.vrec.notification")
|
.application_id("com.scythe.notification")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let msg_text = message.to_string();
|
let msg_text = message.to_string();
|
||||||
|
|
@ -70,7 +70,7 @@ pub fn show_notification(message: &str) {
|
||||||
if layer_shell_ok {
|
if layer_shell_ok {
|
||||||
window.init_layer_shell();
|
window.init_layer_shell();
|
||||||
window.set_layer(Layer::Overlay);
|
window.set_layer(Layer::Overlay);
|
||||||
window.set_namespace("vrec-notification");
|
window.set_namespace("scythe-notification");
|
||||||
window.set_layer_shell_margin(gtk_layer_shell::Edge::Top, 40);
|
window.set_layer_shell_margin(gtk_layer_shell::Edge::Top, 40);
|
||||||
window.set_anchor(gtk_layer_shell::Edge::Top, true);
|
window.set_anchor(gtk_layer_shell::Edge::Top, true);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -141,7 +141,7 @@ pub fn show_notification(message: &str) {
|
||||||
hbox.style_context().add_class("notify-box");
|
hbox.style_context().add_class("notify-box");
|
||||||
hbox.set_halign(gtk::Align::Center);
|
hbox.set_halign(gtk::Align::Center);
|
||||||
|
|
||||||
let badge = Label::new(Some("VREC"));
|
let badge = Label::new(Some("SCYTHE"));
|
||||||
badge.style_context().add_class("notify-badge");
|
badge.style_context().add_class("notify-badge");
|
||||||
let label = Label::new(Some(&msg_text));
|
let label = Label::new(Some(&msg_text));
|
||||||
label.style_context().add_class("notify-label");
|
label.style_context().add_class("notify-label");
|
||||||
|
|
@ -253,9 +253,16 @@ fn draw_gear_icon(cr: >k::cairo::Context, width: f64, height: f64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_menu_overlay() {
|
pub fn show_menu_overlay() {
|
||||||
#[cfg(unix)]
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
crate::overlay_egui::run_egui_overlay();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
{
|
||||||
if std::env::var("WAYLAND_DISPLAY").is_err() && std::env::var("DISPLAY").is_err() {
|
if std::env::var("WAYLAND_DISPLAY").is_err() && std::env::var("DISPLAY").is_err() {
|
||||||
eprintln!("Note: No display server detected for GTK. Falling back to cross-platform egui overlay...");
|
eprintln!("Warning: No display found for GTK menu overlay. Falling back to cross-platform egui overlay...");
|
||||||
crate::overlay_egui::run_egui_overlay();
|
crate::overlay_egui::run_egui_overlay();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -266,12 +273,12 @@ pub fn show_menu_overlay() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = Application::builder()
|
let app = Application::builder()
|
||||||
.application_id("com.vrec.hud")
|
.application_id("com.scythe.hud")
|
||||||
.flags(gtk::gio::ApplicationFlags::NON_UNIQUE)
|
.flags(gtk::gio::ApplicationFlags::NON_UNIQUE)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
app.connect_activate(|app| {
|
app.connect_activate(|app| {
|
||||||
let config = VrecConfig::load();
|
let config = ScytheConfig::load();
|
||||||
|
|
||||||
let window = ApplicationWindow::builder()
|
let window = ApplicationWindow::builder()
|
||||||
.application(app)
|
.application(app)
|
||||||
|
|
@ -287,7 +294,7 @@ pub fn show_menu_overlay() {
|
||||||
if layer_shell_ok {
|
if layer_shell_ok {
|
||||||
window.init_layer_shell();
|
window.init_layer_shell();
|
||||||
window.set_layer(Layer::Overlay);
|
window.set_layer(Layer::Overlay);
|
||||||
window.set_namespace("vrec-overlay");
|
window.set_namespace("scythe-overlay");
|
||||||
window.set_keyboard_interactivity(true);
|
window.set_keyboard_interactivity(true);
|
||||||
// Shifted higher towards the top (50px margin) per user feedback
|
// Shifted higher towards the top (50px margin) per user feedback
|
||||||
window.set_layer_shell_margin(gtk_layer_shell::Edge::Top, 50);
|
window.set_layer_shell_margin(gtk_layer_shell::Edge::Top, 50);
|
||||||
|
|
@ -335,8 +342,8 @@ pub fn show_menu_overlay() {
|
||||||
let header_box = Box::new(Orientation::Horizontal, 10);
|
let header_box = Box::new(Orientation::Horizontal, 10);
|
||||||
header_box.style_context().add_class("header-bar");
|
header_box.style_context().add_class("header-bar");
|
||||||
|
|
||||||
let brand_badge = Label::new(Some("VREC"));
|
let brand_badge = Label::new(Some("SCYTHE"));
|
||||||
brand_badge.style_context().add_class("vrec-badge");
|
brand_badge.style_context().add_class("scythe-badge");
|
||||||
|
|
||||||
let title_label = Label::new(Some("SHADOWPLAY OVERLAY"));
|
let title_label = Label::new(Some("SHADOWPLAY OVERLAY"));
|
||||||
title_label.style_context().add_class("overlay-title");
|
title_label.style_context().add_class("overlay-title");
|
||||||
|
|
@ -887,6 +894,7 @@ pub fn show_menu_overlay() {
|
||||||
padding: 8px 18px;
|
padding: 8px 18px;
|
||||||
box-shadow: 0px 12px 32px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.16);
|
box-shadow: 0px 12px 32px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.16);
|
||||||
}
|
}
|
||||||
|
.scythe-badge,
|
||||||
.vrec-badge {
|
.vrec-badge {
|
||||||
background-color: #76b900;
|
background-color: #76b900;
|
||||||
color: #0b1204;
|
color: #0b1204;
|
||||||
|
|
@ -1181,10 +1189,10 @@ pub fn show_menu_overlay() {
|
||||||
let rev_r_hide = replay_revealer.clone();
|
let rev_r_hide = replay_revealer.clone();
|
||||||
let card_r_deactivate = replay_card_btn.clone();
|
let card_r_deactivate = replay_card_btn.clone();
|
||||||
replay_toggle_item.connect_clicked(move |_| {
|
replay_toggle_item.connect_clicked(move |_| {
|
||||||
let mut cfg = VrecConfig::load();
|
let mut cfg = ScytheConfig::load();
|
||||||
cfg.replay_enabled = !cfg.replay_enabled;
|
cfg.replay_enabled = !cfg.replay_enabled;
|
||||||
let _ = cfg.save();
|
let _ = cfg.save();
|
||||||
VrecConfig::notify_daemon_reload();
|
ScytheConfig::notify_daemon_reload();
|
||||||
|
|
||||||
r_state_sync.store(cfg.replay_enabled, Ordering::Relaxed);
|
r_state_sync.store(cfg.replay_enabled, Ordering::Relaxed);
|
||||||
r_icon_sync.queue_draw();
|
r_icon_sync.queue_draw();
|
||||||
|
|
@ -1251,7 +1259,7 @@ pub fn show_menu_overlay() {
|
||||||
// Direct Mouse Cursor Switch Toggle
|
// Direct Mouse Cursor Switch Toggle
|
||||||
let banner_cur = status_banner.clone();
|
let banner_cur = status_banner.clone();
|
||||||
cursor_switch.connect_state_set(move |_, active| {
|
cursor_switch.connect_state_set(move |_, active| {
|
||||||
let mut cfg = VrecConfig::load();
|
let mut cfg = ScytheConfig::load();
|
||||||
if cfg.show_cursor != active {
|
if cfg.show_cursor != active {
|
||||||
cfg.show_cursor = active;
|
cfg.show_cursor = active;
|
||||||
let _ = cfg.save();
|
let _ = cfg.save();
|
||||||
|
|
@ -1275,7 +1283,7 @@ pub fn show_menu_overlay() {
|
||||||
let cur_sw_sync = cursor_switch.clone();
|
let cur_sw_sync = cursor_switch.clone();
|
||||||
|
|
||||||
apply_btn.connect_clicked(move |_| {
|
apply_btn.connect_clicked(move |_| {
|
||||||
let mut cfg = VrecConfig::load();
|
let mut cfg = ScytheConfig::load();
|
||||||
cfg.show_cursor = cur_sw_sync.is_active();
|
cfg.show_cursor = cur_sw_sync.is_active();
|
||||||
cfg.fps = fps_spin.value() as u32;
|
cfg.fps = fps_spin.value() as u32;
|
||||||
let bit_mbps = bit_spin.value() as u32;
|
let bit_mbps = bit_spin.value() as u32;
|
||||||
|
|
@ -1305,7 +1313,7 @@ pub fn show_menu_overlay() {
|
||||||
cfg.autostart = auto_switch.is_active();
|
cfg.autostart = auto_switch.is_active();
|
||||||
|
|
||||||
let _ = cfg.save();
|
let _ = cfg.save();
|
||||||
VrecConfig::notify_daemon_reload();
|
ScytheConfig::notify_daemon_reload();
|
||||||
|
|
||||||
r_sub_lbl_sync.set_text(&format!("{}s Buffer", cfg.replay_duration_sec));
|
r_sub_lbl_sync.set_text(&format!("{}s Buffer", cfg.replay_duration_sec));
|
||||||
rec_sub_lbl_sync.set_text(&format!("{} FPS • {} Mbps", cfg.fps, cfg.record_bitrate_kbps / 1000));
|
rec_sub_lbl_sync.set_text(&format!("{} FPS • {} Mbps", cfg.fps, cfg.record_bitrate_kbps / 1000));
|
||||||
|
|
@ -1386,4 +1394,5 @@ pub fn show_menu_overlay() {
|
||||||
});
|
});
|
||||||
|
|
||||||
app.run_with_args(&[] as &[&str]);
|
app.run_with_args(&[] as &[&str]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use egui::{Color32, CornerRadius, FontId, Margin, Stroke, Vec2};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::mpsc::{channel, Receiver, Sender};
|
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||||
use std::time::{Duration, Instant, SystemTime};
|
use std::time::{Duration, Instant, SystemTime};
|
||||||
use crate::config::VrecConfig;
|
use crate::config::ScytheConfig;
|
||||||
use crate::ipc::{self, Command, DaemonStatus};
|
use crate::ipc::{self, Command, DaemonStatus};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
|
@ -22,7 +22,7 @@ pub struct VideoClipInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scan_recordings(dir_str: &str) -> Vec<VideoClipInfo> {
|
fn scan_recordings(dir_str: &str) -> Vec<VideoClipInfo> {
|
||||||
let dir = VrecConfig::expand_tilde(dir_str);
|
let dir = ScytheConfig::expand_tilde(dir_str);
|
||||||
let mut clips = Vec::new();
|
let mut clips = Vec::new();
|
||||||
if let Ok(entries) = std::fs::read_dir(&dir) {
|
if let Ok(entries) = std::fs::read_dir(&dir) {
|
||||||
for entry in entries.flatten() {
|
for entry in entries.flatten() {
|
||||||
|
|
@ -424,8 +424,8 @@ fn render_section_card(ui: &mut egui::Ui, header: &str, add_contents: impl FnOnc
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VrecOverlayApp {
|
pub struct ScytheOverlayApp {
|
||||||
config: VrecConfig,
|
config: ScytheConfig,
|
||||||
status: DaemonStatus,
|
status: DaemonStatus,
|
||||||
daemon_connected: bool,
|
daemon_connected: bool,
|
||||||
current_view: ShadowPlayView,
|
current_view: ShadowPlayView,
|
||||||
|
|
@ -449,15 +449,17 @@ pub struct VrecOverlayApp {
|
||||||
initial_pos_set: bool,
|
initial_pos_set: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for VrecOverlayApp {
|
pub type VrecOverlayApp = ScytheOverlayApp;
|
||||||
|
|
||||||
|
impl Default for ScytheOverlayApp {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VrecOverlayApp {
|
impl ScytheOverlayApp {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let config = VrecConfig::load();
|
let config = ScytheConfig::load();
|
||||||
let replay_sec = config.replay_duration_sec;
|
let replay_sec = config.replay_duration_sec;
|
||||||
let bitrate_mbps = (config.record_bitrate_kbps / 1000).max(1);
|
let bitrate_mbps = (config.record_bitrate_kbps / 1000).max(1);
|
||||||
let target_fps = config.fps;
|
let target_fps = config.fps;
|
||||||
|
|
@ -571,13 +573,13 @@ impl VrecOverlayApp {
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
ui.set_width(730.0);
|
ui.set_width(730.0);
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
// VREC Badge
|
// SCYTHE Badge
|
||||||
let (badge_rect, _) = ui.allocate_exact_size(Vec2::new(44.0, 20.0), egui::Sense::hover());
|
let (badge_rect, _) = ui.allocate_exact_size(Vec2::new(56.0, 20.0), egui::Sense::hover());
|
||||||
ui.painter().rect_filled(badge_rect, CornerRadius::same(4_u8), Color32::from_rgb(118, 185, 0));
|
ui.painter().rect_filled(badge_rect, CornerRadius::same(4_u8), Color32::from_rgb(118, 185, 0));
|
||||||
ui.painter().text(
|
ui.painter().text(
|
||||||
badge_rect.center(),
|
badge_rect.center(),
|
||||||
egui::Align2::CENTER_CENTER,
|
egui::Align2::CENTER_CENTER,
|
||||||
"VREC",
|
"SCYTHE",
|
||||||
FontId::proportional(11.0),
|
FontId::proportional(11.0),
|
||||||
Color32::from_rgb(11, 18, 4),
|
Color32::from_rgb(11, 18, 4),
|
||||||
);
|
);
|
||||||
|
|
@ -674,10 +676,10 @@ impl VrecOverlayApp {
|
||||||
render_dropdown_menu(ui, card_w, |ui| {
|
render_dropdown_menu(ui, card_w, |ui| {
|
||||||
let toggle_text = if is_replay_active { "Turn off" } else { "Turn on" };
|
let toggle_text = if is_replay_active { "Turn off" } else { "Turn on" };
|
||||||
if render_menu_item(ui, toggle_text) {
|
if render_menu_item(ui, toggle_text) {
|
||||||
let mut cfg = VrecConfig::load();
|
let mut cfg = ScytheConfig::load();
|
||||||
cfg.replay_enabled = !cfg.replay_enabled;
|
cfg.replay_enabled = !cfg.replay_enabled;
|
||||||
let _ = cfg.save();
|
let _ = cfg.save();
|
||||||
VrecConfig::notify_daemon_reload();
|
ScytheConfig::notify_daemon_reload();
|
||||||
self.config.replay_enabled = cfg.replay_enabled;
|
self.config.replay_enabled = cfg.replay_enabled;
|
||||||
self.status.is_replay_active = cfg.replay_enabled;
|
self.status.is_replay_active = cfg.replay_enabled;
|
||||||
self.replay_dropdown_open = false;
|
self.replay_dropdown_open = false;
|
||||||
|
|
@ -958,7 +960,7 @@ impl VrecOverlayApp {
|
||||||
pick_folder(&self.output_dir, self.folder_tx.clone());
|
pick_folder(&self.output_dir, self.folder_tx.clone());
|
||||||
}
|
}
|
||||||
if ui.button(egui::RichText::new("Open").size(11.0)).clicked() {
|
if ui.button(egui::RichText::new("Open").size(11.0)).clicked() {
|
||||||
open_folder(&VrecConfig::expand_tilde(&self.output_dir));
|
open_folder(&ScytheConfig::expand_tilde(&self.output_dir));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ui.label(egui::RichText::new(format!("{} video recordings in destination folder.", self.clips.len())).size(10.5).color(Color32::from_rgb(148, 163, 184)));
|
ui.label(egui::RichText::new(format!("{} video recordings in destination folder.", self.clips.len())).size(10.5).color(Color32::from_rgb(148, 163, 184)));
|
||||||
|
|
@ -1027,7 +1029,7 @@ impl VrecOverlayApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for VrecOverlayApp {
|
impl eframe::App for ScytheOverlayApp {
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
self.poll_async_events();
|
self.poll_async_events();
|
||||||
self.anim_time += 0.033;
|
self.anim_time += 0.033;
|
||||||
|
|
@ -1075,8 +1077,8 @@ impl eframe::App for VrecOverlayApp {
|
||||||
pub fn run_egui_overlay() {
|
pub fn run_egui_overlay() {
|
||||||
let options = eframe::NativeOptions {
|
let options = eframe::NativeOptions {
|
||||||
viewport: egui::ViewportBuilder::default()
|
viewport: egui::ViewportBuilder::default()
|
||||||
.with_title("vrec ShadowPlay")
|
.with_title("Scythe")
|
||||||
.with_app_id("vrec-overlay")
|
.with_app_id("scythe-overlay")
|
||||||
.with_position([400.0, 50.0])
|
.with_position([400.0, 50.0])
|
||||||
.with_inner_size([760.0, 270.0])
|
.with_inner_size([760.0, 270.0])
|
||||||
.with_min_inner_size([740.0, 250.0])
|
.with_min_inner_size([740.0, 250.0])
|
||||||
|
|
@ -1089,8 +1091,8 @@ pub fn run_egui_overlay() {
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = eframe::run_native(
|
let _ = eframe::run_native(
|
||||||
"vrec-overlay",
|
"scythe-overlay",
|
||||||
options,
|
options,
|
||||||
Box::new(|_cc| Ok(Box::new(VrecOverlayApp::new()))),
|
Box::new(|_cc| Ok(Box::new(ScytheOverlayApp::new()))),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gtk::{Window, WindowType, Box, Orientation, Label, Entry, Button, Switch, ComboBoxText};
|
use gtk::{Window, WindowType, Box, Orientation, Label, Entry, Button, Switch, ComboBoxText};
|
||||||
use crate::config::VrecConfig;
|
use crate::config::ScytheConfig;
|
||||||
|
|
||||||
pub fn open_replay_settings(config_in: &VrecConfig) {
|
pub fn open_replay_settings(config_in: &ScytheConfig) {
|
||||||
let window = Window::new(WindowType::Toplevel);
|
let window = Window::new(WindowType::Toplevel);
|
||||||
window.set_title("Replay Settings");
|
window.set_title("Replay Settings");
|
||||||
window.set_default_size(320, 200);
|
window.set_default_size(320, 200);
|
||||||
|
|
@ -32,7 +32,7 @@ pub fn open_replay_settings(config_in: &VrecConfig) {
|
||||||
|
|
||||||
let window_clone = window.clone();
|
let window_clone = window.clone();
|
||||||
save_btn.connect_clicked(move |_| {
|
save_btn.connect_clicked(move |_| {
|
||||||
let mut cfg = VrecConfig::load();
|
let mut cfg = ScytheConfig::load();
|
||||||
if let Ok(val) = duration_entry.text().parse() {
|
if let Ok(val) = duration_entry.text().parse() {
|
||||||
cfg.replay_duration_sec = val;
|
cfg.replay_duration_sec = val;
|
||||||
}
|
}
|
||||||
|
|
@ -40,7 +40,7 @@ pub fn open_replay_settings(config_in: &VrecConfig) {
|
||||||
cfg.replay_bitrate_kbps = val;
|
cfg.replay_bitrate_kbps = val;
|
||||||
}
|
}
|
||||||
let _ = cfg.save();
|
let _ = cfg.save();
|
||||||
VrecConfig::notify_daemon_reload();
|
ScytheConfig::notify_daemon_reload();
|
||||||
window_clone.close();
|
window_clone.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -57,7 +57,7 @@ pub fn open_replay_settings(config_in: &VrecConfig) {
|
||||||
window.show_all();
|
window.show_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_record_settings(config_in: &VrecConfig) {
|
pub fn open_record_settings(config_in: &ScytheConfig) {
|
||||||
let window = Window::new(WindowType::Toplevel);
|
let window = Window::new(WindowType::Toplevel);
|
||||||
window.set_title("Record Settings");
|
window.set_title("Record Settings");
|
||||||
window.set_default_size(320, 150);
|
window.set_default_size(320, 150);
|
||||||
|
|
@ -80,12 +80,12 @@ pub fn open_record_settings(config_in: &VrecConfig) {
|
||||||
|
|
||||||
let window_clone = window.clone();
|
let window_clone = window.clone();
|
||||||
save_btn.connect_clicked(move |_| {
|
save_btn.connect_clicked(move |_| {
|
||||||
let mut cfg = VrecConfig::load();
|
let mut cfg = ScytheConfig::load();
|
||||||
if let Ok(val) = bitrate_entry.text().parse() {
|
if let Ok(val) = bitrate_entry.text().parse() {
|
||||||
cfg.record_bitrate_kbps = val;
|
cfg.record_bitrate_kbps = val;
|
||||||
}
|
}
|
||||||
let _ = cfg.save();
|
let _ = cfg.save();
|
||||||
VrecConfig::notify_daemon_reload();
|
ScytheConfig::notify_daemon_reload();
|
||||||
window_clone.close();
|
window_clone.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -102,7 +102,7 @@ pub fn open_record_settings(config_in: &VrecConfig) {
|
||||||
window.show_all();
|
window.show_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_general_settings(config_in: &VrecConfig) {
|
pub fn open_general_settings(config_in: &ScytheConfig) {
|
||||||
let window = Window::new(WindowType::Toplevel);
|
let window = Window::new(WindowType::Toplevel);
|
||||||
window.set_title("General Settings");
|
window.set_title("General Settings");
|
||||||
window.set_default_size(380, 320);
|
window.set_default_size(380, 320);
|
||||||
|
|
@ -160,7 +160,7 @@ pub fn open_general_settings(config_in: &VrecConfig) {
|
||||||
|
|
||||||
let window_clone = window.clone();
|
let window_clone = window.clone();
|
||||||
save_btn.connect_clicked(move |_| {
|
save_btn.connect_clicked(move |_| {
|
||||||
let mut cfg = VrecConfig::load();
|
let mut cfg = ScytheConfig::load();
|
||||||
cfg.autostart = auto_switch.is_active();
|
cfg.autostart = auto_switch.is_active();
|
||||||
if let Some(txt) = theme_combo.active_text() {
|
if let Some(txt) = theme_combo.active_text() {
|
||||||
cfg.ui_color_theme = txt.to_string();
|
cfg.ui_color_theme = txt.to_string();
|
||||||
|
|
@ -169,7 +169,7 @@ pub fn open_general_settings(config_in: &VrecConfig) {
|
||||||
cfg.menu_hotkey = menu_hk_entry.text().to_string();
|
cfg.menu_hotkey = menu_hk_entry.text().to_string();
|
||||||
cfg.save_hotkey = save_hk_entry.text().to_string();
|
cfg.save_hotkey = save_hk_entry.text().to_string();
|
||||||
let _ = cfg.save();
|
let _ = cfg.save();
|
||||||
VrecConfig::notify_daemon_reload();
|
ScytheConfig::notify_daemon_reload();
|
||||||
window_clone.close();
|
window_clone.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,27 +2,27 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo "============================================="
|
echo "============================================="
|
||||||
echo " vrec Automated End-to-End Test Suite "
|
echo " Scythe Automated End-to-End Test Suite "
|
||||||
echo "============================================="
|
echo "============================================="
|
||||||
|
|
||||||
# Ensure binaries are compiled
|
# Ensure binaries are compiled
|
||||||
echo "[1/6] Building release binaries..."
|
echo "[1/6] Building release binaries..."
|
||||||
cargo build --release --quiet
|
cargo build --release --quiet
|
||||||
|
|
||||||
SOCKET_PATH="${XDG_RUNTIME_DIR:-/tmp}/vrec.sock"
|
SOCKET_PATH="${XDG_RUNTIME_DIR:-/tmp}/scythe.sock"
|
||||||
rm -f "$SOCKET_PATH"
|
rm -f "$SOCKET_PATH"
|
||||||
rm -f record_*.mp4 replay_*.mp4
|
rm -f record_*.mp4 replay_*.mp4
|
||||||
|
|
||||||
SAVE_DIR=$(python3 -c 'import json, os; print(json.load(open(os.path.expanduser("~/.config/vrec/config.json")))["output_directory"])' 2>/dev/null || echo "$HOME/Videos/vrec")
|
SAVE_DIR=$(python3 -c 'import json, os; p=os.path.expanduser("~/.config/scythe/config.json"); print(json.load(open(p))["output_directory"]) if os.path.exists(p) else print(os.path.expanduser("~/Videos/Scythe"))' 2>/dev/null || echo "$HOME/Videos/Scythe")
|
||||||
mkdir -p "$SAVE_DIR"
|
mkdir -p "$SAVE_DIR"
|
||||||
|
|
||||||
echo "[2/6] Starting vrec-daemon with mock capture..."
|
echo "[2/6] Starting scythe-daemon with mock capture..."
|
||||||
target/release/vrec-daemon --mock > daemon_test.log 2>&1 &
|
target/release/scythe-daemon --mock > daemon_test.log 2>&1 &
|
||||||
DAEMON_PID=$!
|
DAEMON_PID=$!
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
if kill -0 $DAEMON_PID 2>/dev/null; then
|
if kill -0 $DAEMON_PID 2>/dev/null; then
|
||||||
target/release/vrec-ui --quit 2>/dev/null || kill -9 $DAEMON_PID 2>/dev/null || true
|
target/release/scythe-ui --quit 2>/dev/null || kill -9 $DAEMON_PID 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
rm -f daemon_test.log
|
rm -f daemon_test.log
|
||||||
}
|
}
|
||||||
|
|
@ -46,23 +46,23 @@ echo "Daemon is live (PID: $DAEMON_PID, Socket: $SOCKET_PATH)"
|
||||||
|
|
||||||
# Test 1: Start Normal Recording
|
# Test 1: Start Normal Recording
|
||||||
echo "[3/6] Testing: Start Normal Recording..."
|
echo "[3/6] Testing: Start Normal Recording..."
|
||||||
target/release/vrec-ui --start
|
target/release/scythe-ui --start
|
||||||
echo "Recording in progress for 3 seconds..."
|
echo "Recording in progress for 3 seconds..."
|
||||||
sleep 3
|
sleep 3
|
||||||
|
|
||||||
# Test 2: Stop Normal Recording
|
# Test 2: Stop Normal Recording
|
||||||
echo "[4/6] Testing: Stop Normal Recording..."
|
echo "[4/6] Testing: Stop Normal Recording..."
|
||||||
target/release/vrec-ui --stop
|
target/release/scythe-ui --stop
|
||||||
sleep 1
|
sleep 1
|
||||||
|
|
||||||
# Test 3: Save Instant Replay
|
# Test 3: Save Instant Replay
|
||||||
echo "[5/6] Testing: Save Instant Replay buffer..."
|
echo "[5/6] Testing: Save Instant Replay buffer..."
|
||||||
target/release/vrec-ui --save
|
target/release/scythe-ui --save
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
# Test 4: Quit Daemon
|
# Test 4: Quit Daemon
|
||||||
echo "[6/6] Testing: Clean Daemon Shutdown..."
|
echo "[6/6] Testing: Clean Daemon Shutdown..."
|
||||||
target/release/vrec-ui --quit
|
target/release/scythe-ui --quit
|
||||||
wait $DAEMON_PID 2>/dev/null || true
|
wait $DAEMON_PID 2>/dev/null || true
|
||||||
echo "Daemon shutdown cleanly."
|
echo "Daemon shutdown cleanly."
|
||||||
|
|
||||||
|
|
@ -72,7 +72,7 @@ echo " Verifying Generated Recordings with ffprobe"
|
||||||
echo "============================================="
|
echo "============================================="
|
||||||
|
|
||||||
FOUND_ANY=0
|
FOUND_ANY=0
|
||||||
for f in $(find "$SAVE_DIR" ./vrec . -maxdepth 2 \( -name "record_*.mp4" -o -name "replay_*.mp4" \) 2>/dev/null); do
|
for f in $(find "$SAVE_DIR" "$HOME/Videos/Scythe" "$HOME/Videos/vrec" . -maxdepth 2 \( -name "record_*.mp4" -o -name "replay_*.mp4" \) 2>/dev/null); do
|
||||||
if [ -f "$f" ]; then
|
if [ -f "$f" ]; then
|
||||||
FOUND_ANY=1
|
FOUND_ANY=1
|
||||||
echo "--> Testing file: $f ($(ls -lh "$f" | awk '{print $5}'))"
|
echo "--> Testing file: $f ($(ls -lh "$f" | awk '{print $5}'))"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue