@@ -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 = 16 kb
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