Initial commit

This commit is contained in:
2026-03-27 11:16:39 -07:00
commit 67d5c9ca5f
8 changed files with 470 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
#Requires -Version 5.1
<#
.SYNOPSIS
Sends a SaveReplayBuffer request to OBS via WebSocket v5 (built into OBS 28+).
Returns $true on success, $false on any failure.
.PARAMETER Port
OBS WebSocket port. Defaults to the value in config.psd1.
#>
param(
[int]$Port = 0
)
$ErrorActionPreference = 'SilentlyContinue'
if ($Port -eq 0) {
$config = Import-PowerShellDataFile -Path (Join-Path $PSScriptRoot '..\config.psd1')
$Port = $config.WebSocketPort
}
$ws = $null
$cts = $null
try {
$ws = New-Object System.Net.WebSockets.ClientWebSocket
$cts = New-Object System.Threading.CancellationTokenSource(5000) # 5-second timeout
$uri = [System.Uri]"ws://localhost:$Port"
$ws.ConnectAsync($uri, $cts.Token).Wait()
$buffer = New-Object byte[] 8192
# Receive Hello (opcode 0)
$null = $ws.ReceiveAsync($buffer, $cts.Token).Result
# Send Identify (opcode 1) — no authentication
$identify = [System.Text.Encoding]::UTF8.GetBytes('{"op":1,"d":{"rpcVersion":1}}')
$ws.SendAsync($identify, [System.Net.WebSockets.WebSocketMessageType]::Text, $true, $cts.Token).Wait()
# Receive Identified (opcode 2)
$null = $ws.ReceiveAsync($buffer, $cts.Token).Result
# Send SaveReplayBuffer request (opcode 6)
$request = [System.Text.Encoding]::UTF8.GetBytes('{"op":6,"d":{"requestType":"SaveReplayBuffer","requestId":"itrecord-1"}}')
$ws.SendAsync($request, [System.Net.WebSockets.WebSocketMessageType]::Text, $true, $cts.Token).Wait()
# Receive RequestResponse (opcode 7)
$null = $ws.ReceiveAsync($buffer, $cts.Token).Result
$ws.CloseAsync([System.Net.WebSockets.WebSocketCloseStatus]::NormalClosure, 'Done', $cts.Token).Wait()
return $true
}
catch {
return $false
}
finally {
if ($ws) { $ws.Dispose() }
if ($cts) { $cts.Dispose() }
}

View File

@@ -0,0 +1,60 @@
#Requires -Version 5.1
<#
.SYNOPSIS
System tray icon that lets users trigger an OBS replay buffer save.
Right-click the tray icon to access Save Replay or Exit.
.NOTES
This script blocks (runs a WinForms message loop) — launch it via Start-Process.
Start-OBSReplayBuffer.ps1 handles launching this automatically at logon.
#>
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$saveScript = Join-Path $PSScriptRoot 'Invoke-ReplaySave.ps1'
# --- Tray icon ---
$tray = New-Object System.Windows.Forms.NotifyIcon
$tray.Icon = [System.Drawing.SystemIcons]::Shield
$tray.Text = 'IT Screen Recorder'
$tray.Visible = $true
# --- Context menu ---
$menu = New-Object System.Windows.Forms.ContextMenuStrip
$saveItem = New-Object System.Windows.Forms.ToolStripMenuItem('Save Replay')
$sep = New-Object System.Windows.Forms.ToolStripSeparator
$exitItem = New-Object System.Windows.Forms.ToolStripMenuItem('Exit')
$saveItem.Add_Click({
$saveItem.Enabled = $false
$saveItem.Text = 'Saving...'
$result = & powershell.exe -ExecutionPolicy Bypass -NonInteractive -File $saveScript
if ($result -eq $true) {
$tray.ShowBalloonTip(4000, 'IT Screen Recorder', 'Replay saved.', [System.Windows.Forms.ToolTipIcon]::Info)
}
else {
$tray.ShowBalloonTip(4000, 'IT Screen Recorder', 'Could not save replay. Please contact the helpdesk.', [System.Windows.Forms.ToolTipIcon]::Error)
}
$saveItem.Text = 'Save Replay'
$saveItem.Enabled = $true
})
$exitItem.Add_Click({
$tray.Visible = $false
[System.Windows.Forms.Application]::Exit()
})
$menu.Items.Add($saveItem) | Out-Null
$menu.Items.Add($sep) | Out-Null
$menu.Items.Add($exitItem) | Out-Null
$tray.ContextMenuStrip = $menu
# --- Message loop (blocks until Exit is chosen) ---
[System.Windows.Forms.Application]::Run()
$tray.Dispose()

View File

@@ -0,0 +1,86 @@
#Requires -Version 5.1
<#
.SYNOPSIS
Launches OBS Studio hidden with the replay buffer running, then starts the tray icon.
Intended to be called by DEM as a logon task (fire and forget — do not wait for completion).
.NOTES
Reads settings from config.psd1 one level above this script.
Writes the OBS profile basic.ini dynamically so the correct UNC path and buffer
duration are baked in at session start.
#>
$ErrorActionPreference = 'Stop'
$configPath = Join-Path $PSScriptRoot '..\config.psd1'
$config = Import-PowerShellDataFile -Path $configPath
# --- Skip if OBS is already running (handles reconnect scenarios) ---
if (Get-Process -Name 'obs64' -ErrorAction SilentlyContinue) {
exit 0
}
# --- Create user capture subfolder on UNC share ---
$userCapturePath = Join-Path $config.UNCPath $env:USERNAME
if (-not (Test-Path -Path $userCapturePath)) {
New-Item -ItemType Directory -Path $userCapturePath -Force | Out-Null
}
# --- Detect primary monitor resolution ---
Add-Type -AssemblyName System.Windows.Forms
$screen = [System.Windows.Forms.Screen]::PrimaryScreen
$width = $screen.Bounds.Width
$height = $screen.Bounds.Height
# --- Write OBS profile (basic.ini) ---
$profileDir = "$env:APPDATA\obs-studio\basic\profiles\$($config.ProfileName)"
New-Item -ItemType Directory -Path $profileDir -Force | Out-Null
@"
[General]
Name=$($config.ProfileName)
[Output]
Mode=Simple
FilenameFormatting=%CCYY-%MM-%DD_%hh-%mm-%ss
[SimpleOutput]
FilePath=$userCapturePath
RecFormat2=mkv
RecQuality=HQ
RecRBTime=$($config.BufferSeconds)
RecRBSize=512
[Video]
BaseCX=$width
BaseCY=$height
OutputCX=$width
OutputCY=$height
FPSType=1
FPSNum=30
FPSDen=1
ScaleType=bicubic
ColorFormat=NV12
ColorSpace=709
ColorRange=Partial
"@ | Set-Content -Path "$profileDir\basic.ini" -Encoding UTF8
# --- Launch OBS hidden ---
$obsArgs = @(
'--minimize-to-tray'
'--startreplaybuffer'
'--disable-updater'
"--profile `"$($config.ProfileName)`""
"--collection `"$($config.SceneCollection)`""
)
Start-Process -FilePath $config.OBSExecutable -ArgumentList $obsArgs -WindowStyle Hidden
# --- Launch tray icon as a separate background process ---
$trayScript = Join-Path $PSScriptRoot 'Show-ReplayTray.ps1'
Start-Process -FilePath 'powershell.exe' -ArgumentList @(
'-ExecutionPolicy', 'Bypass'
'-NonInteractive'
'-WindowStyle', 'Hidden'
'-File', $trayScript
) -WindowStyle Hidden