Refine feed formatting

This commit is contained in:
Sam Becker 2025-06-12 19:04:42 -05:00
parent 4dc9149931
commit 099fcdec8b
2 changed files with 46 additions and 56 deletions

View File

@ -1,4 +1,3 @@
import { INFINITE_SCROLL_FEED_INITIAL } from '@/photo';
import { getPhotosCached } from '@/photo/cache'; import { getPhotosCached } from '@/photo/cache';
import { import {
BASE_URL, BASE_URL,
@ -6,40 +5,39 @@ import {
META_TITLE, META_TITLE,
SITE_FEEDS_ENABLED, SITE_FEEDS_ENABLED,
} from '@/app/config'; } from '@/app/config';
import { feedPhotoToXml, formatPhotoForFeedRss } from '@/app/feed'; import { createRssItems, FEED_PHOTO_REQUEST_LIMIT } from '@/app/feed';
import { ABSOLUTE_PATH_FOR_FEED_JSON } from '@/app/paths'; import { ABSOLUTE_PATH_FOR_RSS_XML } from '@/app/paths';
export const dynamic = 'force-static'; export const dynamic = 'force-static';
export async function GET() { export async function GET() {
if (SITE_FEEDS_ENABLED) { if (SITE_FEEDS_ENABLED) {
const photos = await getPhotosCached({ const photos = await getPhotosCached({
limit: INFINITE_SCROLL_FEED_INITIAL, limit: FEED_PHOTO_REQUEST_LIMIT,
sortBy: 'createdAt', sortBy: 'createdAt',
}); });
const items = photos.map(formatPhotoForFeedRss).map(feedPhotoToXml);
return new Response( const items = createRssItems(photos);
`<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:media="http://search.yahoo.com/mrss/">
<channel> return new Response(`
<title>${META_TITLE}</title> <?xml version="1.0" encoding="UTF-8"?>
<atom:link href="${ABSOLUTE_PATH_FOR_FEED_JSON}" <rss
rel="self" type="application/rss+xml" /> version="2.0"
<link>${BASE_URL}</link> xmlns:content="http://purl.org/rss/1.0/modules/content/"
<description>${META_DESCRIPTION}</description> xmlns:atom="http://www.w3.org/2005/Atom"
${items.join('\n')} xmlns:media="http://search.yahoo.com/mrss/"
</channel> >
<channel>
</rss>`, <title>${META_TITLE}</title>
{ <atom:link href="${ABSOLUTE_PATH_FOR_RSS_XML}"
headers: { rel="self" type="application/rss+xml" />
'Content-Type': 'text/xml', <link>${BASE_URL}</link>
}, <description>${META_DESCRIPTION}</description>
}, ${items.join('\n')}
</channel>
</rss>
`,
{ headers: { 'Content-Type': 'text/xml' } },
); );
} else { } else {
return new Response('RSS feed access disabled', { status: 404 }); return new Response('RSS feed access disabled', { status: 404 });

View File

@ -12,22 +12,6 @@ export const FEED_PHOTO_WIDTH_SMALL = 200;
export const FEED_PHOTO_WIDTH_MEDIUM = 640; export const FEED_PHOTO_WIDTH_MEDIUM = 640;
export const FEED_PHOTO_WIDTH_LARGE = 1200; export const FEED_PHOTO_WIDTH_LARGE = 1200;
export interface PublicFeedJson {
meta: {
title: string
url: string
}
photos: PublicFeedPhotoJson[]
}
export interface PublicFeedRss {
meta: {
title: string
url: string
}
photos: PublicFeedPhotoRss[]
}
interface PublicFeedMedia { interface PublicFeedMedia {
url: string url: string
width: number width: number
@ -42,10 +26,7 @@ interface PublicFeedPhotoJson {
model?: string model?: string
tags?: string[] tags?: string[]
takenAtNaive: string takenAtNaive: string
src: Record< src: Record<'small' | 'medium' | 'large', PublicFeedMedia>
'small' | 'medium' | 'large',
PublicFeedMedia
>
} }
interface PublicFeedPhotoRss { interface PublicFeedPhotoRss {
@ -54,10 +35,15 @@ interface PublicFeedPhotoRss {
description?: string description?: string
link: string link: string
publicationDate: Date publicationDate: Date
media: Record< media: Record<'content' | 'thumb', PublicFeedMedia>
'content' | 'thumb', }
PublicFeedMedia
> export interface PublicFeedJson {
meta: {
title: string
url: string
}
photos: PublicFeedPhotoJson[]
} }
const generateFeedMedia = ( const generateFeedMedia = (
@ -89,7 +75,7 @@ export const formatPhotoForFeedJson = (photo: Photo): PublicFeedPhotoJson => ({
}, },
}); });
export const formatPhotoForFeedRss = (photo: Photo): PublicFeedPhotoRss => ({ const formatPhotoForFeedRss = (photo: Photo): PublicFeedPhotoRss => ({
...getCoreFeedFields(photo), ...getCoreFeedFields(photo),
link: absolutePathForPhoto({ photo }), link: absolutePathForPhoto({ photo }),
publicationDate: photo.createdAt, publicationDate: photo.createdAt,
@ -99,7 +85,7 @@ export const formatPhotoForFeedRss = (photo: Photo): PublicFeedPhotoRss => ({
}, },
}); });
export const feedPhotoToXml = (photo: PublicFeedPhotoRss): string => { const feedPhotoToXml = (photo: PublicFeedPhotoRss): string => {
const formattedDate = formatDate({ const formattedDate = formatDate({
date: photo.publicationDate, date: photo.publicationDate,
length: 'rss', length: 'rss',
@ -112,14 +98,20 @@ export const feedPhotoToXml = (photo: PublicFeedPhotoRss): string => {
<description> <description>
<![CDATA[${photo.description}]]> <![CDATA[${photo.description}]]>
</description> </description>
<media:content url="${photo.media.content.url.replace(/&/g, '&amp;')}" <media:content url="<![CDATA[${photo.media.content.url}]]>"
type="image/jpeg" type="image/jpeg"
medium="image" medium="image"
width="${photo.media.content.width}" width="${photo.media.content.width}"
height="${photo.media.content.height}"> height="${photo.media.content.height}"
<media:thumbnail url="${photo.media.thumb.url.replace(/&/g, '&amp;')}" >
width="${photo.media.thumb.width}" <media:thumbnail
height="${photo.media.thumb.height}" /> url="<![CDATA[${photo.media.thumb.url}]]>"
width="${photo.media.thumb.width}"
height="${photo.media.thumb.height}"
/>
</media:content> </media:content>
</item>`; </item>`;
}; };
export const createRssItems = (photos: Photo[]) =>
photos.map(formatPhotoForFeedRss).map(feedPhotoToXml);