From bb5571784a1fd140d5483c50c8338c1f31f0b401 Mon Sep 17 00:00:00 2001 From: space Date: Sat, 23 May 2026 14:47:32 +0200 Subject: [PATCH] Add hidden startup launchers for backend and overlay --- pc/install_startup_shortcut.ps1 | 47 ++++++++++++ pc/start_streamdeck.ps1 | 128 ++++++++++++++++++++++++++++++++ pc/start_streamdeck_hidden.vbs | 11 +++ 3 files changed, 186 insertions(+) create mode 100644 pc/install_startup_shortcut.ps1 create mode 100644 pc/start_streamdeck.ps1 create mode 100644 pc/start_streamdeck_hidden.vbs diff --git a/pc/install_startup_shortcut.ps1 b/pc/install_startup_shortcut.ps1 new file mode 100644 index 0000000..13a1d4e --- /dev/null +++ b/pc/install_startup_shortcut.ps1 @@ -0,0 +1,47 @@ +[CmdletBinding(SupportsShouldProcess = $true)] +param( + [switch]$Remove, + [switch]$AllUsers +) + +$ErrorActionPreference = "Stop" + +$scriptDir = Split-Path -Parent $PSCommandPath +$vbsLauncher = Join-Path $scriptDir "start_streamdeck_hidden.vbs" +$shortcutName = "Custom Streamdeck Launcher.lnk" + +if (-not (Test-Path $vbsLauncher)) { + throw "Launcher file not found: $vbsLauncher" +} + +$startupFolder = if ($AllUsers) { + [Environment]::GetFolderPath("CommonStartup") +} else { + [Environment]::GetFolderPath("Startup") +} + +$shortcutPath = Join-Path $startupFolder $shortcutName + +if ($Remove) { + if (Test-Path $shortcutPath) { + if ($PSCmdlet.ShouldProcess($shortcutPath, "Remove startup shortcut")) { + Remove-Item -LiteralPath $shortcutPath -Force + Write-Host "Removed startup shortcut: $shortcutPath" + } + } else { + Write-Host "No startup shortcut found at: $shortcutPath" + } + return +} + +if ($PSCmdlet.ShouldProcess($shortcutPath, "Create startup shortcut")) { + $shell = New-Object -ComObject WScript.Shell + $shortcut = $shell.CreateShortcut($shortcutPath) + $shortcut.TargetPath = "$env:SystemRoot\System32\wscript.exe" + $shortcut.Arguments = '"' + $vbsLauncher + '"' + $shortcut.WorkingDirectory = $scriptDir + $shortcut.Description = "Launch Custom Streamdeck backend and overlay hidden at sign-in." + $shortcut.Save() + + Write-Host "Created startup shortcut: $shortcutPath" +} diff --git a/pc/start_streamdeck.ps1 b/pc/start_streamdeck.ps1 new file mode 100644 index 0000000..1ef22ef --- /dev/null +++ b/pc/start_streamdeck.ps1 @@ -0,0 +1,128 @@ +param( + [switch]$DryRun +) + +$ErrorActionPreference = "Stop" + +$repoRoot = Split-Path -Parent $PSScriptRoot +$overlayDir = Join-Path $repoRoot "overlay" +$dataDir = Join-Path $repoRoot "data" +$launcherLog = Join-Path $dataDir "startup-launcher.log" + +if (-not (Test-Path $dataDir)) { + New-Item -ItemType Directory -Path $dataDir | Out-Null +} + +function Write-LauncherLog { + param([string]$Message) + $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + Add-Content -Path $launcherLog -Value "[$timestamp] $Message" +} + +function Resolve-PythonPath { + $venvPython = Join-Path $repoRoot ".venv\Scripts\python.exe" + if (Test-Path $venvPython) { + return $venvPython + } + + $pythonCmd = Get-Command python -ErrorAction SilentlyContinue + if ($null -ne $pythonCmd) { + return $pythonCmd.Source + } + + throw "Could not find Python. Install Python or create .venv first." +} + +function Resolve-NpmPath { + $npmCmd = Get-Command npm.cmd -ErrorAction SilentlyContinue + if ($null -ne $npmCmd) { + return $npmCmd.Source + } + + throw "Could not find npm.cmd. Install Node.js/npm first." +} + +function Start-HiddenProcess { + param( + [string]$Name, + [string]$FilePath, + [string[]]$Arguments, + [string]$WorkingDirectory, + [string]$StdOutPath, + [string]$StdErrPath + ) + + if ($DryRun) { + Write-LauncherLog "DRY RUN -> $Name | $FilePath $($Arguments -join ' ')" + return + } + + Start-Process ` + -FilePath $FilePath ` + -ArgumentList $Arguments ` + -WorkingDirectory $WorkingDirectory ` + -WindowStyle Hidden ` + -RedirectStandardOutput $StdOutPath ` + -RedirectStandardError $StdErrPath | Out-Null + + Write-LauncherLog "Started $Name." +} + +function Is-BackendRunning { + $matches = Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | + Where-Object { + $_.Name -like "python*" -and + $_.CommandLine -and + $_.CommandLine -like "*backend.main:app*" + } + return ($matches | Measure-Object).Count -gt 0 +} + +function Is-OverlayRunning { + $matches = Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | + Where-Object { + $_.CommandLine -and + $_.CommandLine -like "*custom-streamdeck*overlay*" + } + return ($matches | Measure-Object).Count -gt 0 +} + +try { + $pythonPath = Resolve-PythonPath + $npmPath = Resolve-NpmPath + + if (-not (Test-Path (Join-Path $repoRoot "frontend\dist\index.html"))) { + Write-LauncherLog "Warning: frontend/dist is missing. Build frontend for production view." + } + + if (Is-BackendRunning) { + Write-LauncherLog "Backend already running. Skipping backend launch." + } else { + $backendOut = Join-Path $dataDir "backend.stdout.log" + $backendErr = Join-Path $dataDir "backend.stderr.log" + Start-HiddenProcess ` + -Name "backend" ` + -FilePath $pythonPath ` + -Arguments @("-m", "uvicorn", "backend.main:app", "--host", "127.0.0.1", "--port", "8000") ` + -WorkingDirectory $repoRoot ` + -StdOutPath $backendOut ` + -StdErrPath $backendErr + } + + if (Is-OverlayRunning) { + Write-LauncherLog "Overlay already running. Skipping overlay launch." + } else { + $overlayOut = Join-Path $dataDir "overlay.stdout.log" + $overlayErr = Join-Path $dataDir "overlay.stderr.log" + Start-HiddenProcess ` + -Name "overlay" ` + -FilePath $npmPath ` + -Arguments @("run", "start") ` + -WorkingDirectory $overlayDir ` + -StdOutPath $overlayOut ` + -StdErrPath $overlayErr + } +} catch { + Write-LauncherLog "Launcher failed: $($_.Exception.Message)" + throw +} diff --git a/pc/start_streamdeck_hidden.vbs b/pc/start_streamdeck_hidden.vbs new file mode 100644 index 0000000..ebb779f --- /dev/null +++ b/pc/start_streamdeck_hidden.vbs @@ -0,0 +1,11 @@ +Option Explicit + +Dim shell, fso, scriptDir, psScript, command +Set shell = CreateObject("WScript.Shell") +Set fso = CreateObject("Scripting.FileSystemObject") + +scriptDir = fso.GetParentFolderName(WScript.ScriptFullName) +psScript = """" & fso.BuildPath(scriptDir, "start_streamdeck.ps1") & """" + +command = "powershell.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File " & psScript +shell.Run command, 0, False