diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d4850f2..158cde08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [4.6.0] - 2026-10-30 +### Added +- `mastodon:iframe` setting (off by default). Mastodon oEmbed html (`blockquote.mastodon-embed` with `data-embed-url`) becomes a sandboxed `', + $code->html + ); + $this->assertSame(400, $code->width); + $this->assertNull($code->height); + } + + /** + * @dataProvider recordedPosts + */ + public function testRecordedPostWithoutSettingKeepsTheBlockquote(string $url, string $embedUrl): void + { + $code = $this->recorded([])->get($url)->code; + + $this->assertNotNull($code); + $this->assertStringStartsWith('
html); + $this->assertStringContainsString('embed.js', $code->html); + } + + public function testEmbedUrlOnAnotherHostIsIgnored(): void + { + $code = $this->fake('
x
') + ->get('https://social.test/@a/1')->code; + + $this->assertNotNull($code); + $this->assertStringStartsWith('html); + } + + public function testNonHttpsEmbedUrlIsIgnored(): void + { + $code = $this->fake('
x
') + ->get('https://social.test/@a/1')->code; + + $this->assertNotNull($code); + $this->assertStringStartsWith('html); + } + + public function testOtherOEmbedHtmlIsUntouched(): void + { + $code = $this->fake('') + ->get('https://social.test/@a/1')->code; + + $this->assertNotNull($code); + $this->assertSame('', $code->html); + } + + /** + * @param array $settings + */ + private function recorded(array $settings): Embed + { + $client = new FileClient(__DIR__.'/cache'); + $client->setMode(-1); + $crawler = new Crawler($client); + $crawler->setUrlPolicy(UrlPolicy::default()->withResolver(static function (string $host): array { + return ['8.8.8.8']; + })); + + $embed = new Embed($crawler); + $embed->setSettings($settings); + + return $embed; + } + + private function fake(string $html): Embed + { + $json = (string) json_encode(['type' => 'rich', 'version' => '1.0', 'html' => $html, 'width' => 400], JSON_UNESCAPED_SLASHES); + $page = 'Post' + .'' + .''; + + $client = new RecordingClient(static function (RequestInterface $request) use ($json, $page): ResponseInterface { + $factory = new Psr17Factory(); + $isOEmbed = $request->getUri()->getPath() === '/api/oembed'; + + return $factory->createResponse(200) + ->withHeader('Content-Type', $isOEmbed ? 'application/json' : 'text/html') + ->withBody($factory->createStream($isOEmbed ? $json : $page)); + }); + + $crawler = new Crawler($client); + $crawler->setUrlPolicy(UrlPolicy::default()->withResolver(static function (string $host): array { + return ['1.1.1.1']; + })); + + $embed = new Embed($crawler); + $embed->setSettings(['mastodon:iframe' => true]); + + return $embed; + } +} diff --git a/tests/PagesTest.php b/tests/PagesTest.php index fb80d5e8..be1ccb5d 100644 --- a/tests/PagesTest.php +++ b/tests/PagesTest.php @@ -230,4 +230,14 @@ public function testBBCNews() { $this->assertEmbed('https://www.bbc.co.uk/news/uk-54222286'); } + + public function testMastodonFosstodon() + { + $this->assertEmbed('https://fosstodon.org/@AkaSci/117514634840174369'); + } + + public function testMastodonHachyderm() + { + $this->assertEmbed('https://hachyderm.io/@briancmoses/117514657412674435'); + } } diff --git a/tests/cache/fosstodon.org.akasci-117514634840174369.php b/tests/cache/fosstodon.org.akasci-117514634840174369.php new file mode 100644 index 00000000..4b9edac5 --- /dev/null +++ b/tests/cache/fosstodon.org.akasci-117514634840174369.php @@ -0,0 +1,231 @@ + [ + 'content-type' => [ + 'text/html; charset=utf-8' + ], + 'server' => [ + 'Mastodon' + ], + 'x-frame-options' => [ + 'DENY' + ], + 'x-content-type-options' => [ + 'nosniff' + ], + 'x-xss-protection' => [ + '0' + ], + 'referrer-policy' => [ + 'strict-origin-when-cross-origin' + ], + 'link' => [ + '; rel="alternate"; type="application/activity+json"' + ], + 'cache-control' => [ + 'max-age=10, public' + ], + 'etag' => [ + 'W/"a0fbe8237ca6961ec645d6bc7be9d764"' + ], + 'content-security-policy' => [ + 'base-uri \'none\'; default-src \'none\'; frame-ancestors \'none\'; font-src \'self\' https://fosstodon.org; img-src \'self\' data: blob: https://fosstodon.org https://cdn.fosstodon.org; media-src \'self\' data: https://fosstodon.org https://cdn.fosstodon.org; manifest-src \'self\' https://fosstodon.org; form-action \'none\'; child-src \'self\' blob: https://fosstodon.org; worker-src \'self\' blob: https://fosstodon.org; connect-src \'self\' data: blob: https://fosstodon.org https://cdn.fosstodon.org wss://fosstodon.org; frame-src \'self\' https:; style-src \'self\' https://fosstodon.org \'nonce-MSc33/z4uVC/aIID+yZ8cg==\'; script-src \'self\' https://fosstodon.org \'wasm-unsafe-eval\' \'sha256-OgOg5CGI7D4Syg38sNIknJKO+3DCTdpfY1ciC+Bklaw=\'' + ], + 'x-request-id' => [ + 'f49e5dcb-0319-4697-a729-62e3c11f6a59' + ], + 'x-runtime' => [ + '0.050827' + ], + 'content-encoding' => [ + 'gzip' + ], + 'via' => [ + '1.1 varnish, 1.1 varnish' + ], + 'accept-ranges' => [ + 'bytes' + ], + 'age' => [ + '0' + ], + 'date' => [ + 'Tue, 27 Oct 2026 20:37:00 GMT' + ], + 'x-served-by' => [ + 'cache-par-lfpg1960097-PAR, cache-pdk-kpdk2140067-PDK' + ], + 'x-cache' => [ + 'MISS, MISS' + ], + 'x-cache-hits' => [ + '0, 0' + ], + 'x-timer' => [ + 'S1793133420.268574,VS0,VE158' + ], + 'vary' => [ + 'Accept-Encoding, Accept, Accept-Language, Cookie' + ], + 'strict-transport-security' => [ + 'max-age=300' + ], + 'alt-svc' => [ + 'h3=":443";ma=86400,h3-29=":443";ma=86400,h3-27=":443";ma=86400' + ], + 'content-length' => [ + '23430' + ], + 'Content-Location' => [ + 'https://fosstodon.org/@AkaSci/117514634840174369' + ], + 'X-Request-Time' => [ + '0.401 ms' + ] + ], + 'statusCode' => 200, + 'reasonPhrase' => 'OK', + 'body' => ' + + + + + + + + + + + + + + + + + + + + + + + +AkaSci 🛰️: "Sam Patten, a former Collins staffer, after seein…" - Fosstodon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + +' +]; diff --git a/tests/cache/fosstodon.org.api-oembed.e8a2b2e5810faf2c1915eba881d2e944.php b/tests/cache/fosstodon.org.api-oembed.e8a2b2e5810faf2c1915eba881d2e944.php new file mode 100644 index 00000000..70707944 --- /dev/null +++ b/tests/cache/fosstodon.org.api-oembed.e8a2b2e5810faf2c1915eba881d2e944.php @@ -0,0 +1,91 @@ + [ + 'content-type' => [ + 'application/json; charset=utf-8' + ], + 'server' => [ + 'Mastodon' + ], + 'x-frame-options' => [ + 'DENY' + ], + 'x-content-type-options' => [ + 'nosniff' + ], + 'x-xss-protection' => [ + '0' + ], + 'referrer-policy' => [ + 'same-origin' + ], + 'x-ratelimit-limit' => [ + '300' + ], + 'x-ratelimit-remaining' => [ + '299' + ], + 'x-ratelimit-reset' => [ + '2026-10-27T20:40:00.760935Z' + ], + 'cache-control' => [ + 'private, no-store' + ], + 'etag' => [ + 'W/"f116ad9d23610952fe0471714c782914"' + ], + 'content-security-policy' => [ + 'default-src \'none\'; frame-ancestors \'none\'; form-action \'none\'' + ], + 'x-request-id' => [ + 'd6a897c3-6f14-49ac-95b7-405a9e1ec60f' + ], + 'x-runtime' => [ + '0.006543' + ], + 'content-encoding' => [ + 'gzip' + ], + 'accept-ranges' => [ + 'bytes' + ], + 'via' => [ + '1.1 varnish, 1.1 varnish' + ], + 'date' => [ + 'Tue, 27 Oct 2026 20:37:00 GMT' + ], + 'x-served-by' => [ + 'cache-par-lfpb1150023-PAR, cache-chi-klot8100098-CHI' + ], + 'x-cache' => [ + 'MISS, MISS' + ], + 'x-cache-hits' => [ + '0, 0' + ], + 'x-timer' => [ + 'S1793133421.707686,VS0,VE120' + ], + 'vary' => [ + 'Accept-Encoding, Authorization, Origin' + ], + 'strict-transport-security' => [ + 'max-age=300' + ], + 'alt-svc' => [ + 'h3=":443";ma=86400,h3-29=":443";ma=86400,h3-27=":443";ma=86400' + ], + 'Content-Location' => [ + 'https://fosstodon.org/api/oembed?format=json&url=https%3A%2F%2Ffosstodon.org%2F%40AkaSci%2F117514634840174369' + ], + 'X-Request-Time' => [ + '0.385 ms' + ] + ], + 'statusCode' => 200, + 'reasonPhrase' => 'OK', + 'body' => '{"type":"rich","version":"1.0","author_name":"AkaSci 🛰️","author_url":"https://fosstodon.org/@AkaSci","provider_name":"fosstodon.org","provider_url":"https://fosstodon.org/","cache_age":86400,"html":"
Post by @AkaSci@fosstodon.org
View on Mastodon
","width":400,"height":null}' +]; diff --git a/tests/cache/hachyderm.io.api-oembed.a5aaedab342a291dc69178c41cd3fde2.php b/tests/cache/hachyderm.io.api-oembed.a5aaedab342a291dc69178c41cd3fde2.php new file mode 100644 index 00000000..feeb5021 --- /dev/null +++ b/tests/cache/hachyderm.io.api-oembed.a5aaedab342a291dc69178c41cd3fde2.php @@ -0,0 +1,77 @@ + [ + 'date' => [ + 'Tue, 27 Oct 2026 20:37:01 GMT' + ], + 'content-type' => [ + 'application/json; charset=utf-8' + ], + 'vary' => [ + 'Accept-Encoding', + 'Authorization, Origin' + ], + 'server' => [ + 'Mastodon' + ], + 'x-frame-options' => [ + 'DENY' + ], + 'x-content-type-options' => [ + 'nosniff' + ], + 'x-xss-protection' => [ + '0' + ], + 'referrer-policy' => [ + 'same-origin' + ], + 'x-ratelimit-limit' => [ + '300' + ], + 'x-ratelimit-remaining' => [ + '299' + ], + 'x-ratelimit-reset' => [ + '2026-10-27T20:40:00.782927Z' + ], + 'cache-control' => [ + 'private, no-store' + ], + 'etag' => [ + 'W/"bca95d7f50136cb65aad68a6e97752d7"' + ], + 'content-security-policy' => [ + 'default-src \'none\'; frame-ancestors \'none\'; form-action \'none\'' + ], + 'x-request-id' => [ + '216ef998-8fe9-4b91-9853-1e500358102c' + ], + 'x-runtime' => [ + '0.011468' + ], + 'x-host' => [ + 'prod-mastodon-web02' + ], + 'content-encoding' => [ + 'gzip' + ], + 'strict-transport-security' => [ + 'max-age=63072000; includeSubDomains; preload' + ], + 'x-cdn-host' => [ + 'prod-cdn-namer-east02' + ], + 'Content-Location' => [ + 'https://hachyderm.io/api/oembed?format=json&url=https%3A%2F%2Fhachyderm.io%2F%40briancmoses%2F117514657412674435' + ], + 'X-Request-Time' => [ + '0.396 ms' + ] + ], + 'statusCode' => 200, + 'reasonPhrase' => 'OK', + 'body' => '{"type":"rich","version":"1.0","author_name":"briancmoses.com","author_url":"https://hachyderm.io/@briancmoses","provider_name":"hachyderm.io","provider_url":"https://hachyderm.io/","cache_age":86400,"html":"
Post by @briancmoses@hachyderm.io
View on Mastodon
","width":400,"height":null}' +]; diff --git a/tests/cache/hachyderm.io.briancmoses-117514657412674435.php b/tests/cache/hachyderm.io.briancmoses-117514657412674435.php new file mode 100644 index 00000000..5f83a8c2 --- /dev/null +++ b/tests/cache/hachyderm.io.briancmoses-117514657412674435.php @@ -0,0 +1,196 @@ + [ + 'date' => [ + 'Tue, 27 Oct 2026 20:37:01 GMT' + ], + 'content-type' => [ + 'text/html; charset=utf-8' + ], + 'vary' => [ + 'Accept-Encoding', + 'Accept, Accept-Language, Cookie, Signature' + ], + 'server' => [ + 'Mastodon' + ], + 'x-frame-options' => [ + 'DENY' + ], + 'x-content-type-options' => [ + 'nosniff' + ], + 'x-xss-protection' => [ + '0' + ], + 'referrer-policy' => [ + 'same-origin' + ], + 'link' => [ + '; rel="alternate"; type="application/activity+json"' + ], + 'cache-control' => [ + 'max-age=10, public' + ], + 'etag' => [ + 'W/"f05e24fb3c2d3ddb5db5e5cf82f017e7"' + ], + 'content-security-policy' => [ + 'base-uri \'none\'; default-src \'none\'; frame-ancestors \'none\'; font-src \'self\' https://hachyderm.io; img-src \'self\' data: blob: https://hachyderm.io https://media.hachyderm.io; media-src \'self\' data: https://hachyderm.io https://media.hachyderm.io; manifest-src \'self\' https://hachyderm.io; form-action \'none\'; child-src \'self\' blob: https://hachyderm.io; worker-src \'self\' blob: https://hachyderm.io; connect-src \'self\' data: blob: https://hachyderm.io https://media.hachyderm.io wss://hachyderm.io; frame-src \'self\' https:; style-src \'self\' https://hachyderm.io \'nonce-JqQLPHzzrjNWrxXVx3TOnQ==\'; script-src \'self\' https://hachyderm.io \'wasm-unsafe-eval\' \'sha256-OgOg5CGI7D4Syg38sNIknJKO+3DCTdpfY1ciC+Bklaw=\'' + ], + 'x-request-id' => [ + '363d7953-15a4-4695-ba33-f0fbf11e1afb' + ], + 'x-runtime' => [ + '0.064023' + ], + 'x-host' => [ + 'prod-mastodon-web01' + ], + 'content-encoding' => [ + 'gzip' + ], + 'strict-transport-security' => [ + 'max-age=63072000; includeSubDomains; preload' + ], + 'x-cdn-host' => [ + 'prod-cdn-namer-east02' + ], + 'Content-Location' => [ + 'https://hachyderm.io/@briancmoses/117514657412674435' + ], + 'X-Request-Time' => [ + '0.546 ms' + ] + ], + 'statusCode' => 200, + 'reasonPhrase' => 'OK', + 'body' => ' + + + + + + + + + + + + + + + + + + + + + + + + +briancmoses.com: "I really didn't want to, but I built a new PC. M…" - Hachyderm.io + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + +' +]; diff --git a/tests/fixtures/fosstodon.org.akasci-117514634840174369.php b/tests/fixtures/fosstodon.org.akasci-117514634840174369.php new file mode 100644 index 00000000..c9dac5a0 --- /dev/null +++ b/tests/fixtures/fosstodon.org.akasci-117514634840174369.php @@ -0,0 +1,147 @@ + 'AkaSci 🛰️', + 'authorUrl' => 'https://fosstodon.org/@AkaSci', + 'cms' => null, + 'code' => [ + 'html' => '
Post by @AkaSci@fosstodon.org
View on Mastodon
', + 'width' => 400, + 'height' => null, + 'ratio' => null + ], + 'description' => 'Attached: 1 image Sam Patten, a former Collins staffer, after seeing the ad, says the race between Susan Collins and Troy Jackson is over. #UsPol 2/n', + 'favicon' => 'https://cdn.fosstodon.org/site_uploads/files/000/000/007/16/91cda647d1c18689.png', + 'feeds' => [], + 'icon' => 'https://cdn.fosstodon.org/site_uploads/files/000/000/005/57/c10e49304bc968d0.png', + 'image' => 'https://cdn.fosstodon.org/media_attachments/files/117/514/621/653/448/543/original/c62eb602e292f0b1.png', + 'keywords' => [], + 'language' => 'en', + 'languages' => [], + 'license' => null, + 'providerName' => 'fosstodon.org', + 'providerUrl' => 'https://fosstodon.org/', + 'publishedTime' => '2026-10-27 19:57:04', + 'redirect' => null, + 'title' => 'AkaSci 🛰️ (@AkaSci@fosstodon.org)', + 'url' => 'https://fosstodon.org/@AkaSci/117514634840174369', + 'linkedData' => [ + '@context' => 'https://schema.org', + '@type' => 'SocialMediaPosting', + 'url' => 'https://fosstodon.org/@AkaSci/117514634840174369', + 'datePublished' => '2026-10-27T19:57:04Z', + 'dateModified' => null, + 'author' => [ + '@type' => 'Person', + 'name' => 'AkaSci 🛰️', + 'alternateName' => 'AkaSci@fosstodon.org', + 'identifier' => 'AkaSci@fosstodon.org', + 'url' => 'https://fosstodon.org/@AkaSci', + 'interactionStatistic' => [ + [ + '@type' => 'InteractionCounter', + 'interactionType' => 'https://schema.org/FollowAction', + 'userInteractionCount' => 8267 + ] + ] + ], + 'text' => '

Sam Patten, a former Collins staffer, after seeing the ad, says the race between Susan Collins and Troy Jackson is over.


2/n

', + 'interactionStatistic' => [ + [ + '@type' => 'InteractionCounter', + 'interactionType' => 'https://schema.org/LikeAction', + 'userInteractionCount' => 5 + ], + [ + '@type' => 'InteractionCounter', + 'interactionType' => 'https://schema.org/ShareAction', + 'userInteractionCount' => 1 + ], + [ + '@type' => 'InteractionCounter', + 'interactionType' => 'https://schema.org/ReplyAction', + 'userInteractionCount' => 1 + ] + ], + 'image' => [ + [ + '@type' => 'ImageObject', + 'contentURL' => 'https://cdn.fosstodon.org/media_attachments/files/117/514/621/653/448/543/original/c62eb602e292f0b1.png', + 'thumbnailURL' => 'https://cdn.fosstodon.org/media_attachments/files/117/514/621/653/448/543/small/c62eb602e292f0b1.png', + 'description' => 'Tweet by Andy O\'Brien @aobrien2010 +Former Susan Collins staffer & Maine Wire editor Sam Patten just eviscerated Collins over her latest ad attacking Troy Jackson. + +“The race is over.” + +With image of post by Sam Patten.' + ] + ] + ], + 'oEmbed' => [ + 'type' => 'rich', + 'version' => '1.0', + 'author_name' => 'AkaSci 🛰️', + 'author_url' => 'https://fosstodon.org/@AkaSci', + 'provider_name' => 'fosstodon.org', + 'provider_url' => 'https://fosstodon.org/', + 'cache_age' => 86400, + 'html' => '
Post by @AkaSci@fosstodon.org
View on Mastodon
', + 'width' => 400, + 'height' => null + ], + 'allLinkedData' => [ + [ + '@context' => 'https://schema.org', + '@type' => 'SocialMediaPosting', + 'url' => 'https://fosstodon.org/@AkaSci/117514634840174369', + 'datePublished' => '2026-10-27T19:57:04Z', + 'dateModified' => null, + 'author' => [ + '@type' => 'Person', + 'name' => 'AkaSci 🛰️', + 'alternateName' => 'AkaSci@fosstodon.org', + 'identifier' => 'AkaSci@fosstodon.org', + 'url' => 'https://fosstodon.org/@AkaSci', + 'interactionStatistic' => [ + [ + '@type' => 'InteractionCounter', + 'interactionType' => 'https://schema.org/FollowAction', + 'userInteractionCount' => 8267 + ] + ] + ], + 'text' => '

Sam Patten, a former Collins staffer, after seeing the ad, says the race between Susan Collins and Troy Jackson is over.


2/n

', + 'interactionStatistic' => [ + [ + '@type' => 'InteractionCounter', + 'interactionType' => 'https://schema.org/LikeAction', + 'userInteractionCount' => 5 + ], + [ + '@type' => 'InteractionCounter', + 'interactionType' => 'https://schema.org/ShareAction', + 'userInteractionCount' => 1 + ], + [ + '@type' => 'InteractionCounter', + 'interactionType' => 'https://schema.org/ReplyAction', + 'userInteractionCount' => 1 + ] + ], + 'image' => [ + [ + '@type' => 'ImageObject', + 'contentURL' => 'https://cdn.fosstodon.org/media_attachments/files/117/514/621/653/448/543/original/c62eb602e292f0b1.png', + 'thumbnailURL' => 'https://cdn.fosstodon.org/media_attachments/files/117/514/621/653/448/543/small/c62eb602e292f0b1.png', + 'description' => 'Tweet by Andy O\'Brien @aobrien2010 +Former Susan Collins staffer & Maine Wire editor Sam Patten just eviscerated Collins over her latest ad attacking Troy Jackson. + +“The race is over.” + +With image of post by Sam Patten.' + ] + ] + ] + ] +]; diff --git a/tests/fixtures/hachyderm.io.briancmoses-117514657412674435.php b/tests/fixtures/hachyderm.io.briancmoses-117514657412674435.php new file mode 100644 index 00000000..a02dfadb --- /dev/null +++ b/tests/fixtures/hachyderm.io.briancmoses-117514657412674435.php @@ -0,0 +1,129 @@ + 'briancmoses.com', + 'authorUrl' => 'https://hachyderm.io/@briancmoses', + 'cms' => null, + 'code' => [ + 'html' => '
Post by @briancmoses@hachyderm.io
View on Mastodon
', + 'width' => 400, + 'height' => null, + 'ratio' => null + ], + 'description' => 'I really didn\'t want to, but I built a new PC. Maybe my experience will help someone else out in a similar situation? https://blog.briancmoses.com/2026/10/ugh-i-had-to-build-a-new-pc.html', + 'favicon' => 'https://media.hachyderm.io/site_uploads/files/000/000/006/16/7b1cc534bd3a902c.png', + 'feeds' => [], + 'icon' => 'https://hachyderm.io/packs/assets/apple-touch-icon-57x57-BsPGHSez.png', + 'image' => null, + 'keywords' => [], + 'language' => 'en', + 'languages' => [], + 'license' => null, + 'providerName' => 'hachyderm.io', + 'providerUrl' => 'https://hachyderm.io/', + 'publishedTime' => '2026-10-27 20:02:49', + 'redirect' => null, + 'title' => 'briancmoses.com (@briancmoses@hachyderm.io)', + 'url' => 'https://hachyderm.io/@briancmoses/117514657412674435', + 'linkedData' => [ + '@context' => 'https://schema.org', + '@type' => 'SocialMediaPosting', + 'url' => 'https://hachyderm.io/@briancmoses/117514657412674435', + 'datePublished' => '2026-10-27T20:02:49Z', + 'dateModified' => null, + 'author' => [ + '@type' => 'Person', + 'name' => 'briancmoses.com', + 'alternateName' => 'briancmoses@hachyderm.io', + 'identifier' => 'briancmoses@hachyderm.io', + 'url' => 'https://hachyderm.io/@briancmoses', + 'interactionStatistic' => [ + [ + '@type' => 'InteractionCounter', + 'interactionType' => 'https://schema.org/FollowAction', + 'userInteractionCount' => 206 + ] + ] + ], + 'text' => '

I really didn't want to, but I built a new PC. Maybe my experience will help someone else out in a similar situation?

blog.briancmoses.com/2026/10/u

', + 'interactionStatistic' => [ + [ + '@type' => 'InteractionCounter', + 'interactionType' => 'https://schema.org/LikeAction', + 'userInteractionCount' => 1 + ], + [ + '@type' => 'InteractionCounter', + 'interactionType' => 'https://schema.org/ShareAction', + 'userInteractionCount' => 0 + ], + [ + '@type' => 'InteractionCounter', + 'interactionType' => 'https://schema.org/ReplyAction', + 'userInteractionCount' => 1 + ] + ], + 'sharedContent' => [ + '@type' => 'WebPage', + 'url' => 'https://blog.briancmoses.com/2026/10/ugh-i-had-to-build-a-new-pc.html' + ] + ], + 'oEmbed' => [ + 'type' => 'rich', + 'version' => '1.0', + 'author_name' => 'briancmoses.com', + 'author_url' => 'https://hachyderm.io/@briancmoses', + 'provider_name' => 'hachyderm.io', + 'provider_url' => 'https://hachyderm.io/', + 'cache_age' => 86400, + 'html' => '
Post by @briancmoses@hachyderm.io
View on Mastodon
', + 'width' => 400, + 'height' => null + ], + 'allLinkedData' => [ + [ + '@context' => 'https://schema.org', + '@type' => 'SocialMediaPosting', + 'url' => 'https://hachyderm.io/@briancmoses/117514657412674435', + 'datePublished' => '2026-10-27T20:02:49Z', + 'dateModified' => null, + 'author' => [ + '@type' => 'Person', + 'name' => 'briancmoses.com', + 'alternateName' => 'briancmoses@hachyderm.io', + 'identifier' => 'briancmoses@hachyderm.io', + 'url' => 'https://hachyderm.io/@briancmoses', + 'interactionStatistic' => [ + [ + '@type' => 'InteractionCounter', + 'interactionType' => 'https://schema.org/FollowAction', + 'userInteractionCount' => 206 + ] + ] + ], + 'text' => '

I really didn't want to, but I built a new PC. Maybe my experience will help someone else out in a similar situation?

blog.briancmoses.com/2026/10/u

', + 'interactionStatistic' => [ + [ + '@type' => 'InteractionCounter', + 'interactionType' => 'https://schema.org/LikeAction', + 'userInteractionCount' => 1 + ], + [ + '@type' => 'InteractionCounter', + 'interactionType' => 'https://schema.org/ShareAction', + 'userInteractionCount' => 0 + ], + [ + '@type' => 'InteractionCounter', + 'interactionType' => 'https://schema.org/ReplyAction', + 'userInteractionCount' => 1 + ] + ], + 'sharedContent' => [ + '@type' => 'WebPage', + 'url' => 'https://blog.briancmoses.com/2026/10/ugh-i-had-to-build-a-new-pc.html' + ] + ] + ] +];