Initial commit
This commit is contained in:
129
README.md
Normal file
129
README.md
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
# OBS Replay Buffer for IT Support
|
||||||
|
|
||||||
|
IT support tool that runs OBS Studio's replay buffer silently on VDI sessions, giving users a system tray button to save the last N minutes of screen activity when an issue occurs. Clips are saved to a central UNC share organized by username.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
1. DEM assigns this to targeted users at logon via App Volumes (OBS) + file transfer + logon task
|
||||||
|
2. OBS launches hidden with the replay buffer running — users never see the OBS interface
|
||||||
|
3. A system tray icon appears — right-click → **Save Replay**
|
||||||
|
4. The clip saves to `\\server\ITCaptures\<username>\YYYY-MM-DD_HH-MM-SS.mkv`
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
| Component | Role |
|
||||||
|
|---|---|
|
||||||
|
| **App Volumes AppStack** | Delivers OBS Studio to targeted VDI sessions |
|
||||||
|
| **DEM File Transfer** | Drops OBS config files into `%APPDATA%\obs-studio\` at logon |
|
||||||
|
| **DEM Logon Task** | Runs `Start-OBSReplayBuffer.ps1` at logon |
|
||||||
|
| **`config.psd1`** | Central config — UNC path, buffer duration, OBS executable path |
|
||||||
|
| **`Start-OBSReplayBuffer.ps1`** | Creates user capture folder, writes OBS profile, launches OBS + tray icon |
|
||||||
|
| **`Show-ReplayTray.ps1`** | WinForms system tray icon — right-click menu with Save Replay / Exit |
|
||||||
|
| **`Invoke-ReplaySave.ps1`** | Sends `SaveReplayBuffer` to OBS via WebSocket v5 (built into OBS 28+) |
|
||||||
|
| **`obs-config/`** | OBS profile, scene collection, and WebSocket config delivered by DEM |
|
||||||
|
|
||||||
|
## Repository Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
obs-replay-buffer/
|
||||||
|
├── config.psd1
|
||||||
|
├── scripts/
|
||||||
|
│ ├── Start-OBSReplayBuffer.ps1
|
||||||
|
│ ├── Show-ReplayTray.ps1
|
||||||
|
│ └── Invoke-ReplaySave.ps1
|
||||||
|
└── obs-config/
|
||||||
|
├── global.ini
|
||||||
|
├── profiles/
|
||||||
|
│ └── ITMonitor/
|
||||||
|
│ └── basic.ini
|
||||||
|
├── scenes/
|
||||||
|
│ └── ITMonitor.json
|
||||||
|
└── plugin_config/
|
||||||
|
└── obs-websocket/
|
||||||
|
└── config.json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **OBS Studio 28+** packaged as an App Volumes AppStack (WebSocket v5 is built in — no plugin needed)
|
||||||
|
- **VMware App Volumes** to deliver OBS to targeted users
|
||||||
|
- **VMware DEM** to deliver config files and run the logon task
|
||||||
|
- A **UNC share** writable by VDI users for clip storage
|
||||||
|
- A **network share** to host this repo's files, accessible from all VDI machines
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Edit `config.psd1` before deploying:
|
||||||
|
|
||||||
|
| Key | Description | Default |
|
||||||
|
|---|---|---|
|
||||||
|
| `UNCPath` | Base UNC path for clip storage — username subfolder created automatically | `\\server\ITCaptures` |
|
||||||
|
| `BufferSeconds` | Replay buffer duration in seconds | `120` |
|
||||||
|
| `WebSocketPort` | OBS WebSocket port — must match `obs-config/plugin_config/obs-websocket/config.json` | `4455` |
|
||||||
|
| `OBSExecutable` | Full path to `obs64.exe` on the VDI machine | `C:\Program Files\obs-studio\bin\64bit\obs64.exe` |
|
||||||
|
| `ProfileName` | OBS profile name — must match the folder under `obs-config/profiles/` | `ITMonitor` |
|
||||||
|
| `SceneCollection` | OBS scene collection name — must match the filename under `obs-config/scenes/` | `ITMonitor` |
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
### Step 1 — Host the repo on a network share
|
||||||
|
|
||||||
|
Place this repo (or a copy of it) on a share accessible from all VDI machines, e.g.:
|
||||||
|
|
||||||
|
```
|
||||||
|
\\stcu-fs01\IT-Tools\OBS-Record\
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2 — DEM: File Transfer tasks
|
||||||
|
|
||||||
|
Create these file transfer tasks in DEM, scoped to the target user group. All run at logon.
|
||||||
|
|
||||||
|
| Source (on network share) | Destination (on VDI session) |
|
||||||
|
|---|---|
|
||||||
|
| `obs-config\profiles\ITMonitor\` | `%APPDATA%\obs-studio\basic\profiles\ITMonitor\` |
|
||||||
|
| `obs-config\scenes\ITMonitor.json` | `%APPDATA%\obs-studio\basic\scenes\ITMonitor.json` |
|
||||||
|
| `obs-config\plugin_config\obs-websocket\config.json` | `%APPDATA%\obs-studio\plugin_config\obs-websocket\config.json` |
|
||||||
|
| `obs-config\global.ini` | `%APPDATA%\obs-studio\global.ini` |
|
||||||
|
|
||||||
|
> **Note:** `basic.ini` is intentionally not delivered by DEM — it is written dynamically at logon by `Start-OBSReplayBuffer.ps1` so that the correct UNC path (including username) and primary monitor resolution are baked in per session.
|
||||||
|
|
||||||
|
### Step 3 — DEM: Logon task
|
||||||
|
|
||||||
|
Create one logon task in DEM (scoped to the same target group). Set it to **not wait for completion**.
|
||||||
|
|
||||||
|
```
|
||||||
|
powershell.exe -ExecutionPolicy Bypass -NonInteractive -WindowStyle Hidden -File "\\stcu-fs01\IT-Tools\OBS-Record\scripts\Start-OBSReplayBuffer.ps1"
|
||||||
|
```
|
||||||
|
|
||||||
|
This script handles launching both OBS and the tray icon — no second task needed.
|
||||||
|
|
||||||
|
### Step 4 — Assign App Volumes AppStack
|
||||||
|
|
||||||
|
Assign the OBS AppStack to the same user group in App Volumes. The logon task will exit cleanly if OBS is not present or already running.
|
||||||
|
|
||||||
|
## User Experience
|
||||||
|
|
||||||
|
- A shield icon appears in the system tray at logon — no other UI is visible
|
||||||
|
- Right-click the icon → **Save Replay** to save the last `BufferSeconds` of screen activity
|
||||||
|
- A balloon notification confirms success or failure
|
||||||
|
- Clips appear at `\\server\ITCaptures\<username>\` named by timestamp
|
||||||
|
|
||||||
|
## Changing the Buffer Duration
|
||||||
|
|
||||||
|
Update `BufferSeconds` in `config.psd1`. The value is written into the OBS profile at each logon, so no repackaging of the App Volumes AppStack is needed.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
### Scene Collection JSON
|
||||||
|
|
||||||
|
The `obs-config/scenes/ITMonitor.json` file was generated to target monitor index `0` (primary display). If it does not capture correctly on first use:
|
||||||
|
|
||||||
|
1. Launch OBS normally on a test machine with the AppStack assigned
|
||||||
|
2. Manually configure a Display Capture source pointed at the primary monitor
|
||||||
|
3. Save, then copy `%APPDATA%\obs-studio\basic\scenes\ITMonitor.json` back into this repo
|
||||||
|
|
||||||
|
The `basic.ini` and WebSocket config are reliable and should not need adjustment.
|
||||||
|
|
||||||
|
### OBS Tray Icon vs. IT Tray Icon
|
||||||
|
|
||||||
|
OBS itself also places a tray icon when minimized to tray. Users will see two icons — the OBS icon and the IT Screen Recorder shield icon. The OBS icon can be right-clicked to quit OBS, which would break the replay buffer. If this is a concern, a future enhancement could hide the OBS tray icon via a startup flag or OBS config setting.
|
||||||
17
config.psd1
Normal file
17
config.psd1
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
@{
|
||||||
|
# Base UNC path for saved clips — a subfolder per username is created automatically
|
||||||
|
UNCPath = '\\server\ITCaptures'
|
||||||
|
|
||||||
|
# Replay buffer duration in seconds (120 = 2 minutes)
|
||||||
|
BufferSeconds = 120
|
||||||
|
|
||||||
|
# OBS WebSocket port — must match obs-config/plugin_config/obs-websocket/config.json
|
||||||
|
WebSocketPort = 4455
|
||||||
|
|
||||||
|
# Full path to OBS executable (standard App Volumes / Program Files install)
|
||||||
|
OBSExecutable = 'C:\Program Files\obs-studio\bin\64bit\obs64.exe'
|
||||||
|
|
||||||
|
# Must match the profile folder name and scene collection filename
|
||||||
|
ProfileName = 'ITMonitor'
|
||||||
|
SceneCollection = 'ITMonitor'
|
||||||
|
}
|
||||||
7
obs-config/global.ini
Normal file
7
obs-config/global.ini
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[General]
|
||||||
|
EnableAutoUpdates=false
|
||||||
|
|
||||||
|
[BasicWindow]
|
||||||
|
SysTrayEnabled=true
|
||||||
|
SysTrayWhenStarted=true
|
||||||
|
ShowOnStartup=false
|
||||||
6
obs-config/plugin_config/obs-websocket/config.json
Normal file
6
obs-config/plugin_config/obs-websocket/config.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"alerts_enabled": false,
|
||||||
|
"auth_required": false,
|
||||||
|
"server_enabled": true,
|
||||||
|
"server_port": 4455
|
||||||
|
}
|
||||||
104
obs-config/scenes/ITMonitor.json
Normal file
104
obs-config/scenes/ITMonitor.json
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
{
|
||||||
|
"name": "ITMonitor",
|
||||||
|
"current_scene": "Screen Capture",
|
||||||
|
"current_program_scene": "Screen Capture",
|
||||||
|
"scene_order": [
|
||||||
|
{ "name": "Screen Capture" }
|
||||||
|
],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"id": "monitor_capture",
|
||||||
|
"name": "Primary Display",
|
||||||
|
"versioned_id": "monitor_capture",
|
||||||
|
"settings": {
|
||||||
|
"capture_cursor": true,
|
||||||
|
"compatibility": false,
|
||||||
|
"force_sdr": false,
|
||||||
|
"monitor": 0
|
||||||
|
},
|
||||||
|
"mixers": 0,
|
||||||
|
"sync": 0,
|
||||||
|
"flags": 0,
|
||||||
|
"volume": 1.0,
|
||||||
|
"balance": 0.5,
|
||||||
|
"enabled": true,
|
||||||
|
"muted": true,
|
||||||
|
"push-to-mute": false,
|
||||||
|
"push-to-mute-delay": 0,
|
||||||
|
"push-to-talk": false,
|
||||||
|
"push-to-talk-delay": 0,
|
||||||
|
"hotkeys": {},
|
||||||
|
"deinterlace_field_order": 0,
|
||||||
|
"deinterlace_mode": 0,
|
||||||
|
"filter_data": [],
|
||||||
|
"filters": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "scene",
|
||||||
|
"name": "Screen Capture",
|
||||||
|
"versioned_id": "scene",
|
||||||
|
"settings": {
|
||||||
|
"id_counter": 1,
|
||||||
|
"custom_size": false,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "Primary Display",
|
||||||
|
"visible": true,
|
||||||
|
"locked": false,
|
||||||
|
"rot": 0.0,
|
||||||
|
"pos": { "x": 0.0, "y": 0.0 },
|
||||||
|
"scale": { "x": 1.0, "y": 1.0 },
|
||||||
|
"align": 5,
|
||||||
|
"bounds_type": 0,
|
||||||
|
"bounds_align": 0,
|
||||||
|
"bounds": { "x": 0.0, "y": 0.0 },
|
||||||
|
"crop_top": 0,
|
||||||
|
"crop_right": 0,
|
||||||
|
"crop_bottom": 0,
|
||||||
|
"crop_left": 0,
|
||||||
|
"group_item_backup": false,
|
||||||
|
"scale_filter": "disable",
|
||||||
|
"blend_method": "default",
|
||||||
|
"blend_type": "normal",
|
||||||
|
"show_transition": { "id": "" },
|
||||||
|
"hide_transition": { "id": "" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mixers": 0,
|
||||||
|
"sync": 0,
|
||||||
|
"flags": 0,
|
||||||
|
"volume": 1.0,
|
||||||
|
"balance": 0.5,
|
||||||
|
"enabled": true,
|
||||||
|
"muted": false,
|
||||||
|
"push-to-mute": false,
|
||||||
|
"push-to-mute-delay": 0,
|
||||||
|
"push-to-talk": false,
|
||||||
|
"push-to-talk-delay": 0,
|
||||||
|
"hotkeys": {
|
||||||
|
"OBSBasic.SelectScene": []
|
||||||
|
},
|
||||||
|
"deinterlace_field_order": 0,
|
||||||
|
"deinterlace_mode": 0,
|
||||||
|
"filter_data": [],
|
||||||
|
"filters": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"groups": [],
|
||||||
|
"transitions": [
|
||||||
|
{
|
||||||
|
"id": "fade_transition",
|
||||||
|
"name": "Fade",
|
||||||
|
"settings": { "duration": 300 },
|
||||||
|
"hotkeys": {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"current_transition": "Fade",
|
||||||
|
"transition_duration": 300,
|
||||||
|
"preview_locked": false,
|
||||||
|
"scaling_enabled": false,
|
||||||
|
"scaling_level": 1,
|
||||||
|
"scaling_off_x": 0.0,
|
||||||
|
"scaling_off_y": 0.0
|
||||||
|
}
|
||||||
61
scripts/Invoke-ReplaySave.ps1
Normal file
61
scripts/Invoke-ReplaySave.ps1
Normal 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() }
|
||||||
|
}
|
||||||
60
scripts/Show-ReplayTray.ps1
Normal file
60
scripts/Show-ReplayTray.ps1
Normal 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()
|
||||||
86
scripts/Start-OBSReplayBuffer.ps1
Normal file
86
scripts/Start-OBSReplayBuffer.ps1
Normal 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
|
||||||
Reference in New Issue
Block a user