chore: moved rss to api 03731d43
Steve · 2026-01-04 17:10 2 file(s) · +23 −89
src/pages/now/index.astro +23 −1
18 18
      <li>Reading The Dispossessed</li>
19 19
    </ul>
20 20
    <p class="text-gray-400">Last updated: January 3rd, 2026</p>
21 -
  <h2 class="text-xl font-semibold pt-12">Updates</h2>
21 +
  <div class="flex flex-row justify-between items-center w-full pt-12">
22 +
    <h2 class="text-xl font-semibold">Updates</h2>
23 +
    <a
24 +
				class="inline-block p-2 sm:hover:text-link"
25 +
				href="https://api.stevedylan.dev/now/rss"
26 +
				target="_blank"
27 +
				rel="noopener noreferrer"
28 +
			>
29 +
				<svg
30 +
					xmlns="http://www.w3.org/2000/svg"
31 +
					class="h-6 w-6"
32 +
					viewBox="0 0 24 24"
33 +
					stroke-width="1.5"
34 +
					stroke="currentColor"
35 +
					fill="none"
36 +
					stroke-linecap="round"
37 +
					stroke-linejoin="round"
38 +
				>
39 +
				<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M4 11a9 9 0 0 1 9 9M4 4a16 16 0 0 1 16 16"/><circle cx="5" cy="19" r="1"/></g>
40 +
				</svg>
41 +
				<span class="sr-only">RSS</span>
42 +
			</a>
43 +
  </div>
22 44
  <div id="posts-container">
23 45
    <p>Loading...</p>
24 46
  </div>
src/pages/now/rss.xml.ts (deleted) +0 −88
1 -
import rss from "@astrojs/rss";
2 -
import siteMeta from "@/site-config";
3 -
4 -
const DID = "did:plc:ia2zdnhjaokf5lazhxrmj6eu";
5 -
const PDS_URL = "https://polybius.social";
6 -
7 -
export async function GET() {
8 -
	try {
9 -
		// Fetch posts directly from your PDS using the repo.listRecords endpoint
10 -
		const response = await fetch(
11 -
			`${PDS_URL}/xrpc/com.atproto.repo.listRecords?` +
12 -
				new URLSearchParams({
13 -
					repo: DID,
14 -
					collection: "app.bsky.feed.post",
15 -
					limit: "50",
16 -
					filter: "posts_no_replies",
17 -
				}),
18 -
		);
19 -
20 -
		if (!response.ok) {
21 -
			throw new Error(`HTTP error! status: ${response.status}`);
22 -
		}
23 -
24 -
		const data = await response.json();
25 -
26 -
		// Filter out replies (posts that have a reply reference)
27 -
		const posts = data.records
28 -
			? data.records.filter((record) => !record.value.reply)
29 -
			: [];
30 -
31 -
		const items = posts.map((record) => {
32 -
			const post = record.value;
33 -
			const rkey = record.uri.split("/").pop();
34 -
35 -
			// Build content with images if they exist
36 -
			let content = post.text;
37 -
38 -
			if (
39 -
				post.embed &&
40 -
				post.embed.$type === "app.bsky.embed.images" &&
41 -
				post.embed.images
42 -
			) {
43 -
				const imageHTML = post.embed.images
44 -
					.map((image) => {
45 -
						const blobUrl =
46 -
							`${PDS_URL}/xrpc/com.atproto.sync.getBlob?` +
47 -
							new URLSearchParams({
48 -
								did: DID,
49 -
								cid: image.image.ref.$link,
50 -
							});
51 -
52 -
						return `<img src="${blobUrl}" alt="${image.alt || "Image from post"}" />`;
53 -
					})
54 -
					.join("");
55 -
56 -
				content = `<p>${post.text}</p>${imageHTML}`;
57 -
			}
58 -
59 -
			return {
60 -
				title:
61 -
					post.text.substring(0, 100) + (post.text.length > 100 ? "..." : ""),
62 -
				description: post.text,
63 -
				pubDate: new Date(post.createdAt),
64 -
				link: `https://stevedylan.dev/pds?rkey=${rkey}`,
65 -
				content: content,
66 -
			};
67 -
		});
68 -
69 -
		return rss({
70 -
			title: `${siteMeta.title} - Updates`,
71 -
			description:
72 -
				"Small updates from my life that don't quite fit into a blog",
73 -
			site: process.env.SITE_URL || "https://stevedylan.dev",
74 -
			items: items,
75 -
		});
76 -
	} catch (error) {
77 -
		console.error("Error generating RSS feed:", error);
78 -
79 -
		// Return an empty feed on error
80 -
		return rss({
81 -
			title: `${siteMeta.title} - Updates`,
82 -
			description:
83 -
				"Small updates from my life that don't quite fit into a blog",
84 -
			site: process.env.SITE_URL || "https://stevedylan.dev",
85 -
			items: [],
86 -
		});
87 -
	}
88 -
}