playfulprogramming / playfulprogramming/hoof

Support BlueSky & mastodon post embeds through JSON-LD

Open
#147 0 comments 0 reactions 1 assignee View on GitHub

@femincan is already working on this.

Since Mar 29, 2026.

Dominant language
TypeScript
Stars
9
Forks
7
Avg merge
1d 2h
Merged PRs (30d)
23

Description

Currently, the url-metadata task supports fetching post implementation only for x.com/twitter.com URLs, through the fxtwitter API. See: getEmbedDataFromPost.ts

This task is for adding support for bluesky as well as arbitrary Mastodon hostnames. This can be done using JSON-LD from the HTML head, for example:

  • Support adding post information from SocialMediaPosting (only profile & content & interaction counts, no images)
  • Fetch the author information from the author.url information
  • Upload profile images to object storage / s3

https://hachyderm.io/@playfulprogramming/114615894255662214

{
  "@context": "https://schema.org",
  "@type": "SocialMediaPosting",
  "url": "https://hachyderm.io/@playfulprogramming/114615894255662214",
  "datePublished": "2025-06-02T21:29:13Z",
  "dateModified": null,
  "author": {
    "@type": "Person",
    "name": "Playful Programming",
    "alternateName": "playfulprogramming@hachyderm.io",
    "identifier": "playfulprogramming@hachyderm.io",
    "url": "https://hachyderm.io/@playfulprogramming",
    "interactionStatistic": [
      {
        "@type": "InteractionCounter",
        "interactionType": "https://schema.org/FollowAction",
        "userInteractionCount": 47
      }
    ]
  },
  "text": "<p>Their blog posts talks about a study at Remesh that shows that starting with high-level diagrams, baking docs into workflows, reviewing designs, documenting tests, among other things all reinforce strong engineering culture. Read all the details below:</p><p><a href=\"https://ntietz.com/blog/our-case-study-on-software-documentation/\" target=\"_blank\" rel=\"nofollow noopener\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"ellipsis\">ntietz.com/blog/our-case-study</span><span class=\"invisible\">-on-software-documentation/</span></a></p>",
  "interactionStatistic": [
    {
      "@type": "InteractionCounter",
      "interactionType": "https://schema.org/LikeAction",
      "userInteractionCount": 0
    },
    {
      "@type": "InteractionCounter",
      "interactionType": "https://schema.org/ShareAction",
      "userInteractionCount": 0
    },
    {
      "@type": "InteractionCounter",
      "interactionType": "https://schema.org/ReplyAction",
      "userInteractionCount": 0
    }
  ],
  "sharedContent": {
    "@type": "WebPage",
    "url": "https://ntietz.com/blog/our-case-study-on-software-documentation/"
  }
}

https://bsky.app/profile/playfulprogramming.com/post/3mgdxznq4pe2f

 <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@type": "DiscussionForumPosting",
      "author": {
        "@type": "Person",
        "name": "Playful Programming",
        "alternateName": "@playfulprogramming.com",
        "url": "https://bsky.app/profile/playfulprogramming.com"
      },
      "text": "In the Web Fundamentals Bootcamp today:

We’re moving from theory to practice — fetching real data and handling it correctly in React.

Because “it works” isn’t the same as “it’s modeled well.”",
      
      "datePublished": "2026-03-05T23:43:01.150Z",
      "interactionStatistic": [
        {
          "@type": "InteractionCounter",
          "interactionType": "https://schema.org/LikeAction",
          "userInteractionCount": 2
        },
        {
          "@type": "InteractionCounter",
          "interactionType": "https://schema.org/CommentAction",
          "userInteractionCount": 1
        },
        {
          "@type": "InteractionCounter",
          "interactionType": "https://schema.org/ShareAction",
          "userInteractionCount": 0
        }
      ]
    }
  </script>

https://bsky.app/profile/playfulprogramming.com

  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "ProfilePage",
    "dateCreated": "2024-08-26T18:49:19.819Z",
    "mainEntity": {
      "@type": "Person",
      "name": "Playful Programming",
      "alternateName": "@playfulprogramming.com",
      "identifier": "did:plc:5n6zdjl4ruqvij67crnyrysq",
      "description": "The perfect place to learn all kinds of programming, from introductory ideas to advanced abstractions.

Join our Discord!

https://discord.gg/FMcvc6T",
      "image": "https://cdn.bsky.app/img/avatar/plain/did:plc:5n6zdjl4ruqvij67crnyrysq/bafkreibv4lhztr2e7stfukainkcukiyvgjuokpdw2ucsooroyjhhtvqhaq",
      "interactionStatistic": [
        {
          "@type": "InteractionCounter",
          "interactionType": "https://schema.org/FollowAction",
          "userInteractionCount": 331
        }
      ],
      "agentInteractionStatistic": [
        {
          "@type": "InteractionCounter",
          "interactionType": "https://schema.org/FollowAction",
          "userInteractionCount": 13
        },
        {
          "@type": "InteractionCounter",
          "interactionType": "https://schema.org/WriteAction",
          "userInteractionCount": 312
        }
      ]
    }
  }
  </script>

Bluesky can be determined via the hostname - however, Mastodon can have any domain, so this will need to be added generically to getEmbedDataFromHtml (possibly as a branch into getEmbedDataFromLinkedData if ld+json metadata is detected)

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.