Commands/Get-OpenGraph.ps1
|
function Get-OpenGraph { <# .SYNOPSIS Gets Open Graph metadata for a given URL. .DESCRIPTION Gets Open Graph metadata for a given URL. [Open Graph](https://ogp.me/) is a protocol that enables any web page to become a rich object in a social graph. It is used many social networks to display rich content when links are shared. This function retrieves the Open Graph metadata from a given URL and returns it as a custom object. .EXAMPLE Get-OpenGraph -Url https://abc.com/ .EXAMPLE 'https://thebulwark.com/' | Get-OpenGraph .EXAMPLE OpenGraph https://posh.pckt.blog/static-sites-are-simple-6u51kgj #> [Alias('openGraph','ogp','Test-OpenGraph', 'Test-OGP')] [CmdletBinding(PositionalBinding=$false)] param( # A list of any arguments. # This allows the command to take natural input. [Parameter(ValueFromRemainingArguments)] [Alias('Argument','Arguments','Args')] [PSObject[]] $ArgumentList, # The URL that may contain Open Graph metadata [Parameter(ValueFromPipelineByPropertyName)] [string] $Url, # Any HTML that may contain open graph metadata. [Parameter(ValueFromPipelineByPropertyName)] [string] $Html, # A dictionary of additional Open Graph metadata to include in the result [Parameter(ValueFromPipelineByPropertyName)] [Collections.IDictionary] $Data, # If set, forces the function to retrieve the Open Graph metadata even if it is already cached. [Parameter(ValueFromPipelineByPropertyName)] [switch] $Force, # Any number of input objects [Parameter(ValueFromPipeline)] [Alias('Input')] [PSObject[]] $InputObject ) begin { # Make a regex to match meta tags $metaRegex = [Regex]::new('<meta.+?/?>','IgnoreCase','00:00:00.1') if (-not $script:OpenGraphCache) { $script:OpenGraphCache = [Ordered]@{} } filter OpenGraphFromData { $data = $_ -as [Collections.IDictionary] $openGraphMetadata = [Ordered]@{PSTypeName='OpenGraph'} foreach ($key in $Data.Keys) { $openGraphMetadata[$key] = $Data[$key] } [PSCustomObject]$openGraphMetadata } filter OpenGraphFromUrl { $url = $_ -as [uri] if ($script:OpenGraphCache[$url] -and -not $Force) { return $script:OpenGraphCache[$url] } $script:OpenGraphCache[$url] = Invoke-RestMethod -Uri $Url | OpenGraphFromHtml $script:OpenGraphCache[$url] } filter OpenGraphFromHtml { $text = "$_" $openGraphMetadata = [Ordered]@{PSTypeName='OpenGraph'} foreach ($match in $metaRegex.Matches($text)) { $matchXml = ( # close unclosed `<meta>` tags. "$match" -replace '/?>$','/>' ) -as [xml] if ($matchXml.meta.property -and $matchXml.meta.content) { $openGraphMetadata[$matchXml.meta.property] = $matchXml.meta.content } } [PSCustomObject]$openGraphMetadata } } process { # Turn any of our strongly bound parameters into arguments if ($Url) {$Url | OpenGraphFromUrl } # If any data was provided if ($Data) {$Data | OpenGraphFromData } if ($html) { $Html | OpenGraphFromHtml } if ($InputObject) { $ArgumentList = @($ArgumentList) + $InputObject } :nextArgument foreach ($argument in $argumentList) { # Declare an empty object to hold the Open Graph metadata if (-not $argument) { continue } $openGraphMetadata = [Ordered]@{PSTypeName='OpenGraph'} $openGraphMetadata = if ($argument -as [uri] -and $argument -match '^https?://' ) { $argument -as [uri] | OpenGraphFromUrl } elseif ($argument -is [Collections.IDictionary]) { $argument | OpenGraphFromData } elseif ($argument -is [string] -and $argument -match '\<meta') { $argument | OpenGraphFromHtml } else { Write-Warning ( @( "Unsupported argument:" "[uri],[Collections.IDictionary], and [string]s matching <meta> are supported: $argument" ) -join [Environment]::NewLine ) continue nextArgument } # If there was no metadata if (@($openGraphMetadata.psobject.properties).Count -le 1) { # output false (so `Test-` verb scenarios are met) $false # and continue to the next argument. continue nextArgument } $openGraphMetadata } $ArgumentList = @() } } |