Skip to content

Commit 06e5253

Browse files
Merge pull request #22 from StartAutomating/obs-powershell-updates
obs-powershell 0.1.1
2 parents 15d9742 + 98cf295 commit 06e5253

File tree

298 files changed

+7413
-13753
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

298 files changed

+7413
-13753
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
## obs-powershell 0.1.1
2+
3+
* Connect-OBS now caches connections (Fixes #18)
4+
* Adding new core commands:
5+
* Watch-OBS (Fixes #19)
6+
* Receive-OBS (Fixes #20)
7+
* Send-OBS (Fixes #21)
8+
* All commands now support -PassThru (Fixes #16)
9+
* All commands now increment requests correctly (Fixes #15)
10+
* Improved formatting:
11+
* Get-OBSScene (Fixes #14)
12+
* Get-OBSSceneItem (Fixes #17)
13+
14+
---
15+
116
## obs-powershell 0.1
217

318
Initial Release of obs-powershell

Commands/Connect-OBS.ps1

Lines changed: 40 additions & 199 deletions
Original file line numberDiff line numberDiff line change
@@ -12,225 +12,66 @@ function Connect-OBS
1212
.LINK
1313
Disconnect-OBS
1414
#>
15+
[CmdletBinding(DefaultParameterSetName='ExistingConnections')]
1516
param(
16-
# A credential describing the connection.
17-
# The username should be the IPAddress, and the password should be the obs-websocket password.
18-
[Parameter(ValueFromPipelineByPropertyName)]
19-
[Management.Automation.PSCredential]
20-
$Credential,
21-
22-
# The websocket password.
23-
# You can see the websocket password in Tools -> obs-websocket settings -> show connect info
24-
[Parameter(ValueFromPipelineByPropertyName)]
25-
[securestring]
26-
$WebSocketPassword,
27-
28-
# The websocket URL. If not provided, this will default to loopback on port 4455.
29-
[Parameter(ValueFromPipelineByPropertyName)]
17+
# The OBS websocket URL. If not provided, this will default to loopback on port 4455.
18+
[Parameter(ValueFromPipelineByPropertyName,ParameterSetName='NewConnection')]
3019
[ValidateScript({
3120
if ($_.Scheme -ne 'ws') {
3221
throw "Not a websocket uri"
3322
}
3423
return $true
3524
})]
3625
[uri]
37-
$WebSocketUri = "ws://$([ipaddress]::Loopback):4455"
38-
)
39-
40-
begin {
41-
$obsWatcherJobDefinition = {
42-
param([Management.Automation.PSCredential]$Credential)
43-
44-
function OBSIdentify {
45-
$secret = "$obsPwd$($messageData.d.authentication.salt)"
46-
$enc = [Security.Cryptography.SHA256Managed]::new()
47-
$secretSalted64 = [Convert]::ToBase64String(
48-
$enc.ComputeHash([Text.Encoding]::ascii.GetBytes($secret)
49-
))
50-
51-
$saltedSecretAndChallenge = "$secretSalted64$(
52-
$messageData.d.authentication.challenge
53-
)"
54-
55-
$enc = [Security.Cryptography.SHA256Managed]::new()
56-
$challenge64 = [Convert]::ToBase64String(
57-
$enc.ComputeHash([Text.Encoding]::ascii.GetBytes(
58-
$saltedSecretAndChallenge
59-
))
60-
)
61-
62-
$identifyMessage = [Ordered]@{
63-
op = 1
64-
d = [Ordered]@{
65-
rpcVersion = 1
66-
authentication = $challenge64
67-
}
68-
}
69-
$PayloadJson = $identifyMessage | ConvertTo-Json -Compress
70-
$SendSegment = [ArraySegment[Byte]]::new([Text.Encoding]::UTF8.GetBytes($PayloadJson))
71-
$null = $Websocket.SendAsync($SendSegment,'Text', $true, [Threading.CancellationToken]::new($false))
72-
}
26+
$WebSocketUri = "ws://$([ipaddress]::Loopback):4455",
7327

74-
$webSocketUri = $Credential.UserName
75-
$WebSocketPassword = $Credential.GetNetworkCredential().Password
76-
$Websocket = [Net.WebSockets.ClientWebSocket]::new() # [Net.WebSockets.ClientWebSocket]::new()
77-
$waitFor = [Timespan]'00:00:05'
78-
$ConnectTask = $Websocket.ConnectAsync($webSocketUri, [Threading.CancellationToken]::new($false))
79-
$null = $ConnectTask.ConfigureAwait($false)
80-
81-
82-
$obsPwd = $WebSocketPassword
83-
$WaitInterval = [Timespan]::FromMilliseconds(7)
84-
85-
$BufferSize = 16kb
86-
87-
$maxWaitTime = [DateTime]::Now + $WaitFor
88-
while (!$ConnectTask.IsCompleted -and [DateTime]::Now -lt $maxWaitTime) {
28+
# A randomly generated password used to connect to OBS.
29+
# You can see the websocket password in Tools -> obs-websocket settings -> show connect info
30+
[Parameter(ValueFromPipelineByPropertyName,ParameterSetName='NewConnection')]
31+
[Alias('WebSocketPassword')]
32+
[string]
33+
$WebSocketToken
34+
)
8935

90-
}
91-
92-
$Websocket
93-
94-
try {
95-
96-
while ($true) {
97-
# Create a buffer for the response
98-
$buffer = [byte[]]::new($BufferSize)
99-
$receiveSegment = [ArraySegment[byte]]::new($buffer)
100-
if (!($Websocket.State -eq 'Open')) {
101-
throw 'Websocket is not open anymore. {0}' -f $Websocket.State
102-
}
103-
# Receive the next response from the WebSocket,
104-
$receiveTask = $Websocket.ReceiveAsync($receiveSegment, [Threading.CancellationToken]::new($false))
105-
# then wait for it to complete.
106-
while (-not $receiveTask.IsCompleted) { Start-Sleep -Milliseconds $WaitInterval.TotalMilliseconds }
107-
# "Receiving $($receiveTask.Result.Count)" | Out-Host
108-
$msg = # Get the response and trim with extreme prejudice.
109-
[Text.Encoding]::UTF8.GetString($buffer, 0, $receiveTask.Result.Count).Trim() -replace '\s+$'
110-
111-
if ($msg) {
112-
$messageData = ConvertFrom-Json $msg
113-
$MessageData.pstypenames.insert(0,'OBS.WebSocket.Message')
114-
$newEventSplat = @{}
115-
116-
if ($messageData.op -eq 0 -and $messageData.d.authentication) {
117-
. OBSIdentify
118-
}
119-
120-
$newEventSplat.SourceIdentifier = 'OBS.WebSocket.Message'
121-
$newEventSplat.MessageData = $MessageData
122-
123-
New-Event @newEventSplat
124-
125-
if ($messageData.op -eq 5) {
126-
$newEventSplat = @{}
127-
$newEventSplat.SourceIdentifier = "OBS.Event.$($messageData.d.eventType)"
128-
if ($messageData.d.eventData) {
129-
$newEventSplat.MessageData = [PSObject]::new($messageData.d.eventData)
130-
$newEventSplat.MessageData.pstypenames.insert(0,"OBS.$($MessageData.d.eventType).response")
131-
$newEventSplat.MessageData.pstypenames.insert(0,"$($newEventSplat.SourceIdentifier)")
132-
}
133-
New-Event @newEventSplat
134-
}
135-
136-
if ($messageData.op -eq 7) {
137-
$newEventSplat = @{}
138-
$newEventSplat.SourceIdentifier = $MessageData.d.requestId
139-
if ($messageData.d.responseData) {
140-
$newEventSplat.MessageData = [PSObject]::new($MessageData.d.responseData)
141-
$newEventSplat.MessageData.pstypenames.insert(0,"OBS.$($MessageData.d.requestType).response")
142-
$newEventSplat.MessageData.pstypenames.insert(0,"$($newEventSplat.SourceIdentifier)")
143-
}
144-
New-Event @newEventSplat
145-
}
146-
147-
}
148-
149-
$buffer.Clear()
150-
151-
}
152-
153-
} catch {
154-
Write-Error -Exception $_.Exception -Message "StreamDeck Exception: $($_ | Out-String)" -ErrorId "WebSocket.State.$($Websocket.State)"
155-
}
156-
}
157-
15836

159-
if (-not $script:ObsConnections) {
160-
$script:ObsConnections = [Ordered]@{}
37+
begin {
38+
if ($home) {
39+
$obsPowerShellRoot = Join-Path $home '.obs-powershell'
16140
}
16241
}
16342

164-
process {
165-
if (-not $Credential) {
166-
if ($WebSocketPassword) {
167-
$Credential = [Management.Automation.PSCredential]::new($WebSocketUri, $WebSocketPassword)
43+
process {
44+
if ($PSCmdlet.ParameterSetName -eq 'NewConnection') {
45+
$connectionExists = $script:ObsConnections[$WebSocketUri]
46+
if ($connectionExists -and
47+
$connectionExists.State -eq 'Running' -and
48+
$connectionExists.WebSocket.State -eq 'Open'
49+
) {
50+
$connectionExists
51+
Write-Verbose "Already connected"
52+
return
16853
}
169-
}
17054

171-
if (-not $Credential) {
172-
Write-Error "Must provide -Credential or -WebSocketPassword"
55+
Watch-OBS @PSBoundParameters
17356
return
17457
}
175-
176-
$connectionExists = $script:ObsConnections[$Credential.UserName]
177-
if ($connectionExists -and
178-
$connectionExists.State -eq 'Running' -and
179-
$connectionExists.WebSocket.State -eq 'Open'
180-
) {
181-
$connectionExists
182-
Write-Verbose "Already connected"
183-
return
184-
}
185-
186-
$obsWatcher =
187-
Start-ThreadJob -ScriptBlock $obsWatcherJobDefinition -Name "OBS.Connection.$($Credential.UserName)" -ArgumentList $Credential
188-
189-
$whenOutputAddedHandler =
190-
Register-ObjectEvent -InputObject $obsWatcher.Output -EventName DataAdded -Action {
191-
192-
$dataAdded = $sender[$event.SourceArgs[1].Index]
193-
if ($dataAdded -is [Management.Automation.PSEventArgs]) {
194-
$newEventSplat = [Ordered]@{
195-
SourceIdentifier = $dataAdded.SourceIdentifier
196-
}
197-
$newEventSplat.Sender = $eventSubscriber
198-
if ($dataAdded.MessageData) {
199-
$newEventSplat.MessageData = $dataAdded.MessageData
58+
elseif ($PSCmdlet.ParameterSetName -eq 'ExistingConnections') {
59+
if ($script:ObsConnections.Count) {
60+
$script:ObsConnections.Values
61+
} else {
62+
$storedSockets = Get-ChildItem -path $obsPowerShellRoot -ErrorAction SilentlyContinue -Filter *.obs-websocket.clixml
63+
64+
if (-not $storedSockets) {
65+
[PSCustomObject][Ordered]@{
66+
PSTypeName = 'obs-powershell.not.connected'
67+
Message = 'No connections to OBS. Use Connect-OBS to connect.'
20068
}
201-
if ($dataAdded.SourceEventArgs) {
202-
$newEventSplat.EventArguments = $dataAdded.SourceEventArgs
203-
}
204-
$messageData = $dataAdded.MessageData
205-
New-Event @newEventSplat
206-
}
207-
elseif ($dataAdded -is [Net.WebSockets.ClientWebSocket]) {
208-
$eventSubscriber | Add-Member NoteProperty WebSocket $dataAdded -Force -PassThru
209-
}
210-
else {
211-
69+
} else {
70+
$storedSockets |
71+
Import-Clixml |
72+
Watch-OBS
21273
}
21374
}
214-
215-
$whenOutputAddedHandler | Add-Member NoteProperty Watcher $obsWatcher -Force
216-
217-
$whenOutputAdded = @(
218-
foreach ($subscriber in Get-EventSubscriber) {
219-
if ($subscriber.Action -eq $whenOutputAddedHandler) {
220-
$subscriber;break
221-
}
222-
}
223-
)
224-
225-
$obsWatcher | Add-Member NoteProperty WhenOutputAddedHandler $whenOutputAddedHandler -Force
226-
$obsWatcher | Add-Member NoteProperty WhenOutputAdded $whenOutputAdded -Force
227-
$obsWatcher | Add-Member NoteProperty StartTime ([datetime]::Now) -Force
228-
$obsWatcher | Add-Member ScriptProperty WebSocket {
229-
$this.WhenOutputAdded.WebSocket
230-
} -Force
231-
232-
$obsWatcher.pstypenames.insert(0, 'OBS.Connection')
233-
$script:ObsConnections[$Credential.UserName] = $obsWatcher
234-
$obsWatcher
75+
}
23576
}
23677
}

0 commit comments

Comments
 (0)