Vercel/app/sitemap.ts
Sam Becker a63f2c3fe3
Select All Photos (1 of 2) (#372)
* Add 'select all photos' to app state

* Create general purpose bulk photo action

* Fix infinite scroll pagination, temporarily hide "select all"

* Refine batch edit behavior

* Add admin endpoints to check storage

* Add missing storage count

* Refine missing file presentation

* Finalize storage status page

* Store image-dependent photo fields when reuploading

* Move storage checks behind flag
2026-02-12 22:28:37 -06:00

151 lines
4.0 KiB
TypeScript

import type { MetadataRoute } from 'next';
import { getDataForCategoriesCached } from '@/category/cache';
import {
ABSOLUTE_PATH_FULL,
ABSOLUTE_PATH_GRID,
absolutePathForAlbum,
absolutePathForCamera,
absolutePathForFilm,
absolutePathForFocalLength,
absolutePathForLens,
absolutePathForPhoto,
absolutePathForRecents,
absolutePathForRecipe,
absolutePathForTag,
absolutePathForYear,
} from '@/app/path';
import { isTagFavs } from '@/tag';
import { BASE_URL, GRID_HOMEPAGE_ENABLED } from '@/app/config';
import { getAllPhotoIdsWithUpdatedAt } from '@/photo/query';
// Cache for 24 hours
export const revalidate = 86_400;
const PRIORITY_HOME = 1;
const PRIORITY_HOME_VIEW = 0.9;
const PRIORITY_CATEGORY_SPECIAL = 0.8;
const PRIORITY_CATEGORY = 0.7;
const PRIORITY_PHOTO = 0.5;
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const [
{
recents,
years,
cameras,
lenses,
albums,
tags,
recipes,
films,
focalLengths,
},
photos,
] = await Promise.all([
getDataForCategoriesCached().catch(() => ({
recents: [],
years: [],
cameras: [],
lenses: [],
albums: [],
tags: [],
recipes: [],
films: [],
focalLengths: [],
})),
getAllPhotoIdsWithUpdatedAt().catch(() => []),
]);
const lastModifiedSite = [
...recents.map(({ lastModified }) => lastModified),
...years.map(({ lastModified }) => lastModified),
...cameras.map(({ lastModified }) => lastModified),
...lenses.map(({ lastModified }) => lastModified),
...albums.map(({ lastModified }) => lastModified),
...tags.map(({ lastModified }) => lastModified),
...recipes.map(({ lastModified }) => lastModified),
...films.map(({ lastModified }) => lastModified),
...focalLengths.map(({ lastModified }) => lastModified),
...photos.map(({ updatedAt }) => updatedAt),
]
.filter(date => date instanceof Date)
.sort((a, b) => b.getTime() - a.getTime())[0];
return [
// Homepage
{
url: BASE_URL!,
priority: PRIORITY_HOME,
lastModified: lastModifiedSite,
},
// Grid or full
{
url: GRID_HOMEPAGE_ENABLED ? ABSOLUTE_PATH_FULL : ABSOLUTE_PATH_GRID,
priority: PRIORITY_HOME_VIEW,
lastModified: lastModifiedSite,
},
// Recents
...recents.map(({ lastModified }) => ({
url: absolutePathForRecents(),
priority: PRIORITY_CATEGORY,
lastModified,
})),
// Years
...years.map(({ year, lastModified }) => ({
url: absolutePathForYear(year),
priority: PRIORITY_CATEGORY,
lastModified,
})),
// Cameras
...cameras.map(({ camera, lastModified }) => ({
url: absolutePathForCamera(camera),
priority: PRIORITY_CATEGORY,
lastModified,
})),
// Lenses
...lenses.map(({ lens, lastModified }) => ({
url: absolutePathForLens(lens),
priority: PRIORITY_CATEGORY,
lastModified,
})),
// Albums
...albums.map(({ album, lastModified }) => ({
url: absolutePathForAlbum(album),
priority: PRIORITY_CATEGORY,
lastModified,
})),
// Tags
...tags.map(({ tag, lastModified }) => ({
url: absolutePathForTag(tag),
priority: isTagFavs(tag)
? PRIORITY_CATEGORY_SPECIAL
: PRIORITY_CATEGORY,
lastModified,
})),
// Recipes
...recipes.map(({ recipe, lastModified }) => ({
url: absolutePathForRecipe(recipe),
priority: PRIORITY_CATEGORY,
lastModified,
})),
// Films
...films.map(({ film, lastModified }) => ({
url: absolutePathForFilm(film),
priority: PRIORITY_CATEGORY,
lastModified,
})),
// Focal Lengths
...focalLengths.map(({ focal, lastModified }) => ({
url: absolutePathForFocalLength(focal),
priority: PRIORITY_CATEGORY,
lastModified,
})),
// Photos
...photos.map(({ id, updatedAt }) => ({
url: absolutePathForPhoto({ photo: id }),
priority: PRIORITY_PHOTO,
lastModified: updatedAt,
})),
];
}