Blueskyのポストをサイトに表示する

Bluesky の外部公開

Bluesky の公開用 web インターフェースが実装されログインしなくても投稿やプロフィールページを見ることができるようになった。

ubanis(Bluesky) (@ubanis.com)
futanari artist R18 ふたなり絵を描きます 絵 My Bluesky arts https://tinyurl.com/ubanisart Drawpile https://tinyurl.com/drawpile Links https://woosh.link/ubanis.com
ubanis(Bluesky) (@ubanis.com) favicon https://bsky.app/profile/ubanis.com
ubanis(Bluesky) (@ubanis.com)

それに加えてポストの RSS が配信されるようになったので、それを取得してサイトで表示するようにした。

RSS の URL は profile/ユーザーのDID/rss のアドレスになっている。

bsky.app
bsky.app favicon https://bsky.app/profile/did:plc:lmftezsq52hi53taz762s7pc/rss

RSS を読み込む

最初は RSS から json への変換を rss-to-json で行おうとしたものの変換はできるものの表示できないので外部 API を利用することにした。

GitHub - nasa8x/rss-to-json: RSS and Atom feed generator for Node.js
RSS and Atom feed generator for Node.js. Contribute to nasa8x/rss-to-json development by creating an account on GitHub.
GitHub - nasa8x/rss-to-json: RSS and Atom feed generator for Node.js favicon https://github.com/nasa8x/rss-to-json
GitHub - nasa8x/rss-to-json: RSS and Atom feed generator for Node.js

rss-to-json は fetch ではなく axios を使っているのが原因かもしれない(よくわかってないので詳しい方教えて下さい)

move from axios to fetch · Issue #65 · nasa8x/rss-to-json
Currently, fetch is available in Node.js natively. From other side axios doesn't work at serverless env (Cloudflare workers as an example) It would be nice to move from axios to builtin fetch
move from axios to fetch · Issue #65 · nasa8x/rss-to-json favicon https://github.com/nasa8x/rss-to-json/issues/65
move from axios to fetch · Issue #65 · nasa8x/rss-to-json

RSS から json への変換は rss2json.com を利用する。無料版では1時間に1回 RSS が更新される。

RSS to JSON Converter online - rss2json.com
Free online API to convert RSS to JSON
RSS to JSON Converter online - rss2json.com favicon https://rss2json.com

Svelte のコード

以下は svelte のコード。

<script>
import { onMount } from "svelte";
import { fade, slide } from "svelte/transition";
let promise = new Promise(() => {});
onMount(() => {
promise = (async () => {
const res = await fetch("rss2jsonのapi URL");
const data = res.json();
return data;
})();
});
</script>
<div class="break-all rounded-xl bg-(color:--bg-base-color) pb-4">
<h2 class="rounded-t-xl bg-blue-500 p-2 text-lg font-bold leading-8 text-white">Bluesky</h2>
{#await promise}
<p
transition:slide
on:introstart={() => (visible = false)}
on:outroend={() => (visible = true)}
>
読み込み中...
</p>
{:then data}
<div class="loaded" in:fade>
<h3 class="bg-slate-300 p-2 text-base text-black underline">
<a href={data.feed.link}>{data.feed.title}</a>
</h3>
{#each data.items as item}
<p class="border-b border-dotted border-(color:--border-color) px-3 py-3 text-base">
{item.description}
<time class="pt-2 text-sm block">{item.pubDate} + 9h</time>
<a
class="hover:text-(color:--text-linkhover-color) text-(color:--text-link-color) text-sm pt-2"
href={item.link}
target="_blank">[ポスト元]</a
>
</p>
{/each}
</div>
{:catch error}
<p>ERROR {error.message}</p>
{/await}
</div>

完成品

実際に動作しているものは以下のようになる。(Astro の構造上ブログ用スタイルシートがコンポーネントに適用されてレイアウトがおかしいのはご了承ください。正しい表示なのはプロフィールページにあります。)

プロフィール
へび右曲がりはubanisによるふたなりサイトです
プロフィール favicon https://ubanis.com/profile
プロフィール

Bluesky

読み込み中...