Refactor json/xml code

This commit is contained in:
Sam Becker 2025-06-12 21:16:26 -05:00
parent 4d904517a5
commit bdfc122beb
4 changed files with 43 additions and 49 deletions

View File

@ -1,11 +1,7 @@
import { getPhotosCached } from '@/photo/cache';
import {
BASE_URL,
SITE_FEEDS_ENABLED,
META_TITLE,
} from '@/app/config';
import { SITE_FEEDS_ENABLED } from '@/app/config';
import { FEED_PHOTO_REQUEST_LIMIT } from '@/feed';
import { formatPhotoForFeedJson } from '@/feed/json';
import { formatFeedJson } from '@/feed/json';
// Cache for 24 hours
export const revalidate = 86_400;
@ -16,13 +12,7 @@ export async function GET() {
limit: FEED_PHOTO_REQUEST_LIMIT,
sortBy: 'createdAt',
});
return Response.json({
meta: {
title: META_TITLE,
url: BASE_URL,
},
photos: photos.map(formatPhotoForFeedJson),
});
return Response.json(formatFeedJson(photos));
} else {
return new Response('Feed disabled', { status: 404 });
}

View File

@ -1,13 +1,7 @@
import { getPhotosCached } from '@/photo/cache';
import {
BASE_URL,
META_DESCRIPTION,
META_TITLE,
SITE_FEEDS_ENABLED,
} from '@/app/config';
import { SITE_FEEDS_ENABLED } from '@/app/config';
import { FEED_PHOTO_REQUEST_LIMIT } from '@/feed';
import { createRssItems } from '@/feed/rss';
import { ABSOLUTE_PATH_FOR_RSS_XML } from '@/app/paths';
import { formatFeedRss } from '@/feed/rss';
// Cache for 24 hours
export const revalidate = 86_400;
@ -19,28 +13,9 @@ export async function GET() {
sortBy: 'createdAt',
});
const items = createRssItems(photos);
return new Response(`<?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>
<title>${META_TITLE}</title>
<atom:link
href="${ABSOLUTE_PATH_FOR_RSS_XML}"
rel="self"
type="application/rss+xml"
/>
<link>${BASE_URL}</link>
<description>${META_DESCRIPTION}</description>
${items.join('\n')}
</channel>
</rss>
`,
{ headers: { 'Content-Type': 'text/xml' } },
return new Response(
formatFeedRss(photos),
{ headers: { 'Content-Type': 'text/xml' } },
);
} else {
return new Response('Feed disabled', { status: 404 });

View File

@ -9,6 +9,8 @@ import {
} from '.';
import { formatDateFromPostgresString } from '@/utility/date';
import { Photo } from '@/photo';
import { BASE_URL } from '@/app/config';
import { META_TITLE } from '@/app/config';
interface FeedPhotoJson {
id: string
@ -21,7 +23,7 @@ interface FeedPhotoJson {
src: Record<'small' | 'medium' | 'large', FeedMedia>
}
export const formatPhotoForFeedJson = (photo: Photo): FeedPhotoJson => ({
const formatPhotoForFeedJson = (photo: Photo): FeedPhotoJson => ({
...getCoreFeedFields(photo),
url: absolutePathForPhoto({ photo }),
...photo.make && { make: photo.make },
@ -34,3 +36,11 @@ export const formatPhotoForFeedJson = (photo: Photo): FeedPhotoJson => ({
large: generateFeedMedia(photo, FEED_PHOTO_WIDTH_LARGE),
},
});
export const formatFeedJson = (photos: Photo[]) => ({
meta: {
title: META_TITLE,
url: BASE_URL,
},
photos: photos.map(formatPhotoForFeedJson),
});

View File

@ -6,9 +6,10 @@ import {
generateFeedMedia,
getCoreFeedFields,
} from '.';
import { absolutePathForPhoto } from '@/app/paths';
import { ABSOLUTE_PATH_FOR_RSS_XML, absolutePathForPhoto } from '@/app/paths';
import { formatDate } from '@/utility/date';
import { formatStringForXml } from '@/utility/string';
import { BASE_URL, META_DESCRIPTION, META_TITLE } from '@/app/config';
interface FeedPhotoRss {
id: string
@ -30,11 +31,12 @@ const formatPhotoForFeedRss = (photo: Photo): FeedPhotoRss => ({
});
const feedPhotoToXml = (photo: FeedPhotoRss): string => {
const formattedDate = formatDate({ date: photo.pubDate, length: 'rss' });
return `<item>
<title>${photo.title}</title>
<link>${photo.link}</link>
<pubDate>${formattedDate}</pubDate>
<pubDate>
${formatDate({ date: photo.pubDate, length: 'rss' })}
</pubDate>
<guid isPermaLink="true">${photo.link}</guid>
${photo.description
? `<description><![CDATA[${photo.description}]]></description>`
@ -55,5 +57,22 @@ const feedPhotoToXml = (photo: FeedPhotoRss): string => {
</item>`;
};
export const createRssItems = (photos: Photo[]) =>
photos.map(formatPhotoForFeedRss).map(feedPhotoToXml);
export const formatFeedRss = (photos: Photo[]) =>
`<?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>
<title>${META_TITLE}</title>
<atom:link
href="${ABSOLUTE_PATH_FOR_RSS_XML}"
rel="self"
type="application/rss+xml"
/>
<link>${BASE_URL}</link>
<description>${META_DESCRIPTION}</description>
${photos.map(formatPhotoForFeedRss).map(feedPhotoToXml).join('\n')}
</channel>
</rss>`;