将Mastodon与Astro集成
#javascript #astro #mastodon #ssr

如果您错过了它,Twitter正在经历一系列动荡。这导致了许多人离开平台寻求替代方案。一段时间以来,我一直对Mastodon作为Twitter的潜在替代品感兴趣,尤其是因为它是开源的,但是我永远无法跳跃。现在感觉每个人都在尝试替代平台,我在Mastodon上认识的人数已经大大增加了,我已经能够复制我在Twitter上所做的很多事情。

在我走得太远之前,让我们谈谈Mastodon所描述的微博和联邦。对于微博,Mastodon docs说:

类似于博客的发布方式类似于网站发布更新的行为,微博是发布有关个人资料中更新的小型更新的行为。您可以发布文本帖子,并选择附加媒体,例如图片,音频,视频或民意调查。 Mastodon让您关注朋友并发现新朋友。

对我来说,微博是一种分享正在发生的事情或与人们感兴趣的方式,以一种不太正式,更多的对话方式。我可以谈论生活,时事,我的孩子说的话,或者只是分享我发现我感兴趣的事情。在过去的几年中,Twitter一直是我的微博平台,而我在我的网站上写了更长的博客文章。

mastodon如何定义联邦?

联邦是权力下放的一种形式。而不是所有人使用的单个中央服务,而是有多种服务,任何人都可以使用。

Twitter非常集中;只有一个“实例”,您无法从Twitter通信到其他平台。另一方面,联合平台允许多个提供商以标准化的方式进行交流。最简单的比较是电子邮件,这是另一个联合系统。不同的电子邮件提供商根据需要建立规则和过滤内容,并允许您与其他电子邮件提供商进行交互。 Mastodon是相似的,因为每个实例都有自己的主持人和规则,并允许在其他Mastodon实例之间进行互操作。

请注意,在我们继续前进之前:这篇文章不打算切换到Mastodon。我知道这不是每个人。但是我真的很喜欢。

关于Mastodon的真正整洁的事情之一是您可以托管自己的实例,并与Mastodon的其余部分结合起来。这使您可以控制自己的数据,并在自己的网站上托管。这听起来真的很酷!在我拥有的URL下托管自己的社交媒体帐户是整洁的,这似乎是一种验证自己的简单方法。但是,我专门使用静态站点(专门使用Astro),因为我不想每月为服务器付款。仅仅在社交媒体上拥有帐户就开始付款没有意义,所以我将这个想法搁置一旁。

与Fediverse集成

后来,我读了Maarten Balliauw的一篇文章,标题为“ Mastodon on your own domain without a server”,他在其中描述了使用WebFinger Spec将您的帐户告知Mastodon的文章。我强烈建议阅读整篇文章,但简而言之,Mastodon正在寻找/.well-known/webfinger的资源,该资源返回特定结构的JSON。 Mastodon正在传递查询参数以指定帐户,但是如果您托管了自己的网站,则可以忽略参数,而只需返回帐户的JSON结构即可。这听起来很有趣,我想试一试!

我的网站建立在Astro上,并由Netlify托管。为了满足端点的要求,我在/.well-known/webfinger.json上创建了一个端点,该端点只包括以下代码:

export async function get() {
  return {
    body: JSON.stringify({
      subject: 'acct:lindsaykwardell@mastodon.social',
      aliases: [
        'https://mastodon.social/@lindsaykwardell',
        'https://mastodon.social/users/lindsaykwardell',
      ],
      links: [
        {
          rel: 'http://webfinger.net/rel/profile-page',
          type: 'text/html',
          href: 'https://mastodon.social/@lindsaykwardell',
        },
        {
          rel: 'self',
          type: 'application/activity+json',
          href: 'https://mastodon.social/users/lindsaykwardell',
        },
        {
          rel: 'http://ostatus.org/schema/1.0/subscribe',
          template: 'https://mastodon.social/authorize_interaction?uri={uri}',
        },
      ],
    }),
  }
}

然后,在我的netlify config(netlify.toml)中,我添加了一个重定向:

[[redirects]]
  from = "/.well-known/webfinger"
  to = "/.well-known/webfinger.json"

这样,搜索@lindsay@lindsaykwardell.com正确返回了我的帐户。

Screenshot of Mastodon search with my custom domain as the query and my account on mastodon.social as the result

真棒!现在,人们可以通过自己的URL查找我,我不必托管Mastodon实例就可以做到!但是,这种交流只是一种方式。我可以告诉Fediverse我是谁,但是我的网站上没有任何内容。我们该如何解决?

将Fediverse带回家

由于Mastodon的构建是为了与其他系统互操作,因此它具有功能强大的公共API,可用于获取有关用户及其帖子的数据。此外,它提供了多种订阅任何用户帖子(包括RSS feed)的方法。您可以通过将.rss附加到其用户名(随时在https://mastodon.social/@lindsaykwardell.rss上关注我),通过RSS上的任何人订阅。

随时关注我。

我有一个可以在Mastodon上找到的自定义用户名,但是我缺少的是一个页面,可以在网站上实际查看我的内容。在mastodon上,可以在mastodon.social/@lindsaykwardell上找到用户名@lindsaykwardell@mastodon.social。但是,Lindsaykwardell.com/@lindsay不存在,所以我决定解决这个问题!

再次使用Astro,我创建了一个页面(/@lindsay.astro),该页面将获取我的RSS feed的内容然后渲染。我为我的网站创建了一个单独的模板,该模板还可以获取我的mastodon配置文件和横幅图像,描述,追随者计数和其他详细信息,然后使用static html进行渲染。

---
import MicroblogPost from "../layouts/MicroblogPost.astro";
import MicroPost from "../components/MicroPost.astro";
import Parser from 'rss-parser';

const feedUrl = "https://mastodon.social/@lindsaykwardell.rss"
const parser = new Parser({
  customFields: {
    item: [ ['media:content', 'attachments', { keepArray: true} ]]
  }
})

const feed = await parser.parseURL(feedUrl);

const content = {
  title: feed.title,
  snippet: "Public posts from @lindsay@lindsaykwardell.com",
  slug: "/@lindsay"
}
---
<MicroblogPost content={content}>
  {feed.items.map(item => (
    <MicroPost 
      avatar={feed.image.url}
      displayName={feed.title}
      content={item.content}
      createdAt={item.pubDate}
      url={item.link}
      attachments={item.attachments?.map(attachment => attachment['$'])}
    />
  ))}
</MicroblogPost>

在此文件中,我正在导入布局(MicroblogPost)和一个组件(MicroPost)以及rss-parser。然后,我创建了一个解析器,并为媒体内容(例如图像)添加了自定义字段。然后,我获取提要内容,解析并将其传递到站点模板和组件中。这样,我现在可以在自己的网站中看到我的mastodon内容!

The landing page for my Mastodon microblog content on my own website

然后,我将其进一步迈出了一步,并为每个帖子创建了一个单独的页面。在Twitter和Mastodon等网站上,您可以直接链接到帖子(例如https://twitter.com/lindsaykwardell/status/1583481321330200577https://mastodon.social/@lindsaykwardell/109248202243508025)。如果我试图在自己的网站上重新创建微博的界面是有道理的,我想做同样的事情。

这需要使用Astro's dynamic routing并启用SSR mode,但结果是我的任何Mastodon帖子都可以在我的个人网站上viwwwiw!这是代码:

---
import MicroblogPost from "../../layouts/MicroblogPost.astro";
import MicroPost from "../../components/MicroPost.astro";

const { id } = Astro.params;

const data = await fetch(`https://mastodon.social/api/v1/statuses/${id}`).then(res => res.json())

const name = data.account.display_name
const post = data.content.replace(/<[^>]*>?/gm, '');
let snippet = post.substring(0,30);

if (snippet.length === 30) {
  snippet += "..."
}

const card = data.card;

const content = {
  title: name + ": " + snippet,
  snippet: post,
  image: data.media_attachments[0]?.url,
  slug: `/@lindsay/${id}`,
}
---
<MicroblogPost content={content}>
  <MicroPost
    avatar={data.account.avatar}
    url={data.url}
    username={data.account.username}
    userPage={data.account.url}
    createdAt={data.created_at}
    displayName={data.account.display_name}
    content={data.content}
    attachments={data.media_attachments}
    card={card}
    postStats={{
      repliesCount: data.replies_count,
      reblogsCount: data.reblogs_count,
      favouritesCount: data.favourites_count,
    }}
  />
</MicroblogPost>

我没有从RSS提要中获取,而是使用Mastodon的公共API通过ID获取。然后,我将帖子的数据传递到MicroPost组件中,其中包括比RSS feed给我们更多的元数据。因此,我们现在可以将单个Mastodon帖子直接加载到网站上!去this post about my ViteConf talk看!

A post about my ViteConf talk on using Elm in Vite, displayed on my website

以这种方式使用API​​需要注意的一件事,因为我们只是通过ID获取数据,我们可以加载我没有写的帖子。我不太担心它,因为正确的用户的姓名和配置文件图像将显示在帖子内容中,但要牢记。

结论

我敢肯定,可以将我的网站与Fediverse整合在一起,但这已经感觉真的很好。未来的变化可能会导致与Mastodon更好地集成,例如从我的网站上遵循或偏爱事物,而不必去Mastodon,但这并不是一个大问题。

虽然Twitter可能正在经历一些重大斗争,但这是一种与Dev社区保持互动并以Twitter从未允许的方式将其与我自己的网站相结合的好方法。至少这是值得的。

如果您对结果感兴趣,请查看lindsaykwardell.com/@lindsay