Begin combining feed and api
This commit is contained in:
parent
0236461d99
commit
ec698b61de
@ -1,11 +1,11 @@
|
|||||||
import { getPhotosCached } from '@/photo/cache';
|
import { getPhotosCached } from '@/photo/cache';
|
||||||
import { INFINITE_SCROLL_FEED_INITIAL } from '@/photo';
|
import { INFINITE_SCROLL_FEED_INITIAL } from '@/photo';
|
||||||
import { formatPhotoForFeed } from '@/app/feed';
|
|
||||||
import {
|
import {
|
||||||
BASE_URL,
|
BASE_URL,
|
||||||
PUBLIC_FEED_ENABLED,
|
PUBLIC_FEED_ENABLED,
|
||||||
META_TITLE,
|
META_TITLE,
|
||||||
} from '@/app/config';
|
} from '@/app/config';
|
||||||
|
import { formatPhotoForFeedJson } from '@/app/feed';
|
||||||
|
|
||||||
export const dynamic = 'force-static';
|
export const dynamic = 'force-static';
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ export async function GET() {
|
|||||||
title: META_TITLE,
|
title: META_TITLE,
|
||||||
url: BASE_URL,
|
url: BASE_URL,
|
||||||
},
|
},
|
||||||
photos: photos.map(formatPhotoForFeed),
|
photos: photos.map(formatPhotoForFeedJson),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return new Response('Feed disabled', { status: 404 });
|
return new Response('Feed disabled', { status: 404 });
|
||||||
|
|||||||
140
src/app/feed.ts
140
src/app/feed.ts
@ -1,17 +1,31 @@
|
|||||||
import { Photo } from '@/photo';
|
import { descriptionForPhoto, Photo, titleForPhoto } from '@/photo';
|
||||||
import { absolutePathForPhoto } from './paths';
|
import { absolutePathForPhoto } from './paths';
|
||||||
import { getNextImageUrlForRequest } from '@/platforms/next-image';
|
import {
|
||||||
import { formatDate } from '@/utility/date';
|
getNextImageUrlForRequest,
|
||||||
|
NextImageSize,
|
||||||
|
} from '@/platforms/next-image';
|
||||||
|
import { formatDate, formatDateFromPostgresString } from '@/utility/date';
|
||||||
|
|
||||||
export const FEED_PHOTO_WIDTH_CONTENT = 1080;
|
export const API_PHOTO_REQUEST_LIMIT = 40;
|
||||||
export const FEED_PHOTO_WIDTH_THUMB = 640;
|
|
||||||
|
|
||||||
export interface PublicFeed {
|
export const FEED_PHOTO_WIDTH_SMALL = 200;
|
||||||
|
export const FEED_PHOTO_WIDTH_MEDIUM = 640;
|
||||||
|
export const FEED_PHOTO_WIDTH_LARGE = 1200;
|
||||||
|
|
||||||
|
export interface PublicFeedJson {
|
||||||
meta: {
|
meta: {
|
||||||
title: string
|
title: string
|
||||||
url: string
|
url: string
|
||||||
}
|
}
|
||||||
photos: PublicFeedPhoto[]
|
photos: PublicFeedPhotoJson[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PublicFeedRss {
|
||||||
|
meta: {
|
||||||
|
title: string
|
||||||
|
url: string
|
||||||
|
}
|
||||||
|
photos: PublicFeedPhotoRss[]
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PublicFeedMedia {
|
interface PublicFeedMedia {
|
||||||
@ -20,7 +34,21 @@ interface PublicFeedMedia {
|
|||||||
height: number
|
height: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PublicFeedPhoto {
|
interface PublicFeedPhotoJson {
|
||||||
|
id: string
|
||||||
|
title?: string
|
||||||
|
url: string
|
||||||
|
make?: string
|
||||||
|
model?: string
|
||||||
|
tags?: string[]
|
||||||
|
takenAtNaive: string
|
||||||
|
src: Record<
|
||||||
|
'small' | 'medium' | 'large',
|
||||||
|
PublicFeedMedia
|
||||||
|
>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PublicFeedPhotoRss {
|
||||||
id: string
|
id: string
|
||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
@ -32,56 +60,66 @@ interface PublicFeedPhoto {
|
|||||||
>
|
>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const formatPhotoForFeed = (photo: Photo): PublicFeedPhoto => ({
|
const generateFeedMedia = (
|
||||||
|
photo: Photo,
|
||||||
|
size: NextImageSize,
|
||||||
|
): PublicFeedMedia => ({
|
||||||
|
url: getNextImageUrlForRequest({ imageUrl: photo.url, size }),
|
||||||
|
width: size,
|
||||||
|
height: Math.round(size / photo.aspectRatio),
|
||||||
|
});
|
||||||
|
|
||||||
|
const getCoreFeedFields = (photo: Photo) => ({
|
||||||
id: photo.id,
|
id: photo.id,
|
||||||
title: photo.title,
|
title: titleForPhoto(photo),
|
||||||
description: photo.caption,
|
description: descriptionForPhoto(photo),
|
||||||
link: absolutePathForPhoto({ photo }),
|
});
|
||||||
publicationDate: photo.createdAt,
|
|
||||||
media: {
|
export const formatPhotoForFeedJson = (photo: Photo): PublicFeedPhotoJson => ({
|
||||||
content: {
|
...getCoreFeedFields(photo),
|
||||||
url: getNextImageUrlForRequest({
|
url: absolutePathForPhoto({ photo }),
|
||||||
imageUrl: photo.url,
|
...photo.make && { make: photo.make },
|
||||||
size: FEED_PHOTO_WIDTH_CONTENT,
|
...photo.model && { model: photo.model },
|
||||||
}),
|
...photo.tags.length > 0 && { tags: photo.tags },
|
||||||
width: FEED_PHOTO_WIDTH_CONTENT,
|
takenAtNaive: formatDateFromPostgresString(photo.takenAtNaive),
|
||||||
height: Math.round(FEED_PHOTO_WIDTH_CONTENT / photo.aspectRatio),
|
src: {
|
||||||
},
|
small: generateFeedMedia(photo, FEED_PHOTO_WIDTH_SMALL),
|
||||||
thumb: {
|
medium: generateFeedMedia(photo, FEED_PHOTO_WIDTH_MEDIUM),
|
||||||
url: getNextImageUrlForRequest({
|
large: generateFeedMedia(photo, FEED_PHOTO_WIDTH_LARGE),
|
||||||
imageUrl: photo.url,
|
|
||||||
size: FEED_PHOTO_WIDTH_THUMB,
|
|
||||||
}),
|
|
||||||
width: FEED_PHOTO_WIDTH_THUMB,
|
|
||||||
height: Math.round(FEED_PHOTO_WIDTH_THUMB / photo.aspectRatio),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const feedPhotoToXml = (photo: PublicFeedPhoto): string => {
|
export const formatPhotoForFeedRss = (photo: Photo): PublicFeedPhotoRss => ({
|
||||||
|
...getCoreFeedFields(photo),
|
||||||
|
link: absolutePathForPhoto({ photo }),
|
||||||
|
publicationDate: photo.createdAt,
|
||||||
|
media: {
|
||||||
|
content: generateFeedMedia(photo, FEED_PHOTO_WIDTH_LARGE),
|
||||||
|
thumb: generateFeedMedia(photo, FEED_PHOTO_WIDTH_MEDIUM),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const feedPhotoToXml = (photo: PublicFeedPhotoRss): string => {
|
||||||
const formattedDate = formatDate({
|
const formattedDate = formatDate({
|
||||||
date: photo.publicationDate,
|
date: photo.publicationDate,
|
||||||
length: 'rss',
|
length: 'rss',
|
||||||
});
|
});
|
||||||
const description = photo.description ?
|
return `<item>
|
||||||
`<description>
|
<title>${photo.title}</title>
|
||||||
|
<link>${photo.link}</link>
|
||||||
|
<pubDate>${formattedDate}</pubDate>
|
||||||
|
<guid isPermaLink="true">${photo.link}</guid>
|
||||||
|
<description>
|
||||||
<![CDATA[${photo.description}]]>
|
<![CDATA[${photo.description}]]>
|
||||||
</description>` : '';
|
</description>
|
||||||
|
<media:content url="${photo.media.content.url.replace(/&/g, '&')}"
|
||||||
return ` <item>
|
type="image/jpeg"
|
||||||
<title>${photo.title}</title>
|
medium="image"
|
||||||
<link>${photo.link}</link>
|
width="${photo.media.content.width}"
|
||||||
<pubDate>${formattedDate}</pubDate>
|
height="${photo.media.content.height}">
|
||||||
<guid isPermaLink="true">${photo.link}</guid>
|
<media:thumbnail url="${photo.media.thumb.url.replace(/&/g, '&')}"
|
||||||
${description}
|
width="${photo.media.thumb.width}"
|
||||||
<media:content url="${photo.media.content.url.replace(/&/g, '&')}"
|
height="${photo.media.thumb.height}" />
|
||||||
type="image/jpeg"
|
</media:content>
|
||||||
medium="image"
|
</item>`;
|
||||||
width="${photo.media.content.width}"
|
|
||||||
height="${photo.media.content.height}">
|
|
||||||
<media:thumbnail url="${photo.media.thumb.url.replace(/&/g, '&')}"
|
|
||||||
width="${photo.media.thumb.width}"
|
|
||||||
height="${photo.media.thumb.height}" />
|
|
||||||
</media:content>
|
|
||||||
</item>`;
|
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user