functions/follow.ps1
#region Follow a Bluesky profile Function New-BskyFollow { [CmdletBinding(SupportsShouldProcess)] [OutputType('String')] [Alias("Follow-BskyUser")] Param( [Parameter( Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName, HelpMessage = 'Enter the profile or user name.' )] [ValidateNotNullOrEmpty()] [Alias('Profile')] [string]$UserName ) Begin { $PSDefaultParameterValues['_verbose:Command'] = $MyInvocation.MyCommand $PSDefaultParameterValues['_verbose:block'] = 'Begin' _verbose -message $strings.Starting if ($MyInvocation.CommandOrigin -eq 'Runspace') { #Hide this metadata when the command is called from another command _verbose -message ($strings.PSVersion -f $PSVersionTable.PSVersion) _verbose -message ($strings.UsingHost -f $host.Name) _verbose -message ($strings.UsingOS -f $PSVersionTable.OS) _verbose -message ($strings.UsingModule -f $ModuleVersion) } if ($script:BSkySession.accessJwt) { $token = $script:BSkySession.accessJwt $did = $script:BSkySession.did $headers = @{ Authorization = "Bearer $token" 'Content-Type' = 'application/json' } Write-Information $script:BSkySession -Tags raw } else { Write-Warning $strings.NoSession } } #begin Process { $PSDefaultParameterValues['_verbose:block'] = 'Process' if ($Headers) { $apiUrl = "$PDSHOST/xrpc/app.bsky.actor.getProfile?actor=$UserName" _verbose ($strings.UserSearch -f $Username) Try { $splat = @{ Uri = $apiUrl Method = 'Get' Headers = $headers ErrorAction = 'Stop' ResponseHeadersVariable = 'rh' } $User = Invoke-RestMethod @splat Write-Information -MessageData $rh -Tags ResponseHeader Write-Information -MessageData $User -Tags raw } Catch { Write-Error $_ } If ($User) { $FollowDid = $User.did $apiUrl = "$PDSHOST/xrpc/com.atproto.repo.createRecord" $record = [ordered]@{ '$type' = 'app.bsky.graph.follow' subject = $FollowDid createdAt = (Get-Date -Format 'o') } $body = @{ repo = $did collection = 'app.bsky.graph.follow' record = $record } | ConvertTo-Json Write-Information -MessageData $body -Tags raw _verbose ($strings.Following -f $Username) if ($PSCmdlet.ShouldProcess($Username)) { $response = Invoke-RestMethod -Uri $apiUrl -Method Post -Headers $headers -Body $body #output should be the followed account page "https://bsky.app/profile/$($FollowDid)" } } #if user found else { Write-Warning ($strings.FailProfile -f $Username) } } #if headers } #process End { $PSDefaultParameterValues['_verbose:Command'] = $MyInvocation.MyCommand $PSDefaultParameterValues['_verbose:block'] = 'End' _verbose $strings.Ending } #end } #endregion #region Un-follow a Bluesky profile # https://github.com/bluesky-social/atproto/blob/main/lexicons/com/atproto/repo/deleteRecord.json # https://docs.bsky.app/docs/api/com-atproto-repo-delete-record Function Remove-BskyFollow { [CmdletBinding(SupportsShouldProcess,DefaultParameterSetName = 'User')] [OutputType('None','PSObject')] [Alias("Unfollow-BskyUser")] Param( [Parameter( Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName, ParameterSetName = 'User', HelpMessage = 'Enter the profile or user name.' )] [ValidateNotNullOrEmpty()] [Alias('Profile')] [string]$UserName, [Parameter( Position = 0, ValueFromPipelineByPropertyName, ParameterSetName = 'DID', HelpMessage = 'Enter the profile DID' )] [ValidateNotNullOrEmpty()] [ValidatePattern('^did:plc:[a-z0-9]{24}$', ErrorMessage = 'Invalid DID format')] [string]$DID, [switch]$Passthru ) Begin { $PSDefaultParameterValues['_verbose:Command'] = $MyInvocation.MyCommand $PSDefaultParameterValues['_verbose:block'] = 'Begin' _verbose -message $strings.Starting if ($MyInvocation.CommandOrigin -eq 'Runspace') { #Hide this metadata when the command is called from another command _verbose -message ($strings.PSVersion -f $PSVersionTable.PSVersion) _verbose -message ($strings.UsingHost -f $host.Name) _verbose -message ($strings.UsingOS -f $PSVersionTable.OS) _verbose -message ($strings.UsingModule -f $ModuleVersion) } if ($script:BSkySession.accessJwt) { $token = $script:BSkySession.accessJwt $did = $script:BSkySession.did $headers = @{ Authorization = "Bearer $token" 'Content-Type' = 'application/json' } Write-Information $script:BSkySession -Tags raw } else { Write-Warning $strings.NoSession } } #begin Process { if ($headers) { $PSDefaultParameterValues['_verbose:block'] = 'Process' If ($PSCmdlet.ParameterSetName -eq 'User') { $account = $UserName } else { $account = $DID } _verbose ($strings.UserSearch -f $account) $apiUrl = "$PDSHOST/xrpc/app.bsky.actor.getProfile?actor=$account" Try { $splat = @{ Uri = $apiUrl Method = 'Get' Headers = $headers ErrorAction = 'Stop' ResponseHeadersVariable = 'rh' } $User = Invoke-RestMethod @splat Write-Information -MessageData $rh -Tags ResponseHeader Write-Information -MessageData $user -Tags raw } Catch { Write-Warning ($strings.FailProfile -f $account) Write-Error $_ } If ($User.viewer.following) { $rkey = $user.viewer.following.split('/')[-1] $apiUrl = "$PDSHOST/xrpc/com.atproto.repo.deleteRecord" $body = @{ repo = $did collection = 'app.bsky.graph.follow' rkey = $rkey } | ConvertTo-Json $splat = @{ Uri = $apiUrl Method = 'Post' Headers = $headers Body = $body } Write-Information -MessageData $splat -Tags raw if ($PSCmdlet.ShouldProcess($User.handle)) { $delResponse = Invoke-RestMethod @splat Write-Information -MessageData $delResponse -Tags raw if ($Passthru -AND (-Not $WhatIfPreference)) { $delResponse.commit } } } #if viewer property found else { Write-Warning ($strings.NotFollowing -f $user.handle) } } #if headers detected } #process End { $PSDefaultParameterValues['_verbose:Command'] = $MyInvocation.MyCommand $PSDefaultParameterValues['_verbose:block'] = 'End' _verbose $strings.Ending } #end } #endregion |