Flag photos without recipes as 'outdated'
This commit is contained in:
parent
34667efedf
commit
ee6aed896c
@ -1,17 +1,12 @@
|
||||
import { getPhotos } from '@/photo/db/query';
|
||||
import { OUTDATED_THRESHOLD } from '@/photo';
|
||||
import AdminOutdatedClient from '@/admin/AdminOutdatedClient';
|
||||
import { AI_TEXT_GENERATION_ENABLED } from '@/app/config';
|
||||
import { getOutdatedPhotos } from '@/photo/db/query';
|
||||
|
||||
export const maxDuration = 60;
|
||||
|
||||
export default async function AdminOutdatedPage() {
|
||||
const photos = await getPhotos({
|
||||
hidden: 'include',
|
||||
sortBy: 'createdAtAsc',
|
||||
updatedBefore: OUTDATED_THRESHOLD,
|
||||
limit: 1_000,
|
||||
}).catch(() => []);
|
||||
const photos = await getOutdatedPhotos()
|
||||
.catch(() => []);
|
||||
|
||||
return (
|
||||
<AdminOutdatedClient {...{
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { getStoragePhotoUrlsNoStore } from '@/platforms/storage/cache';
|
||||
import { getPhotos } from '@/photo/db/query';
|
||||
import { getPhotosMetaCached } from '@/photo/cache';
|
||||
import { OUTDATED_THRESHOLD } from '@/photo';
|
||||
import AdminPhotosClient from '@/admin/AdminPhotosClient';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { cookies } from 'next/headers';
|
||||
import { TIMEZONE_COOKIE_NAME } from '@/utility/timezone';
|
||||
import { getOutdatedPhotosCount } from '@/photo/db/query';
|
||||
|
||||
export const maxDuration = 60;
|
||||
|
||||
@ -31,11 +31,7 @@ export default async function AdminPhotosPage() {
|
||||
getPhotosMetaCached({ hidden: 'include'})
|
||||
.then(({ count }) => count)
|
||||
.catch(() => 0),
|
||||
getPhotosMetaCached({
|
||||
hidden: 'include',
|
||||
updatedBefore: OUTDATED_THRESHOLD,
|
||||
})
|
||||
.then(({ count }) => count)
|
||||
getOutdatedPhotosCount()
|
||||
.catch(() => 0),
|
||||
DEBUG_PHOTO_BLOBS
|
||||
? getStoragePhotoUrlsNoStore()
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { OUTDATED_THRESHOLD, Photo } from '@/photo';
|
||||
import { Photo } from '@/photo';
|
||||
import AdminPhotosTable from '@/admin/AdminPhotosTable';
|
||||
import LoaderButton from '@/components/primitives/LoaderButton';
|
||||
import IconGrSync from '@/app/IconGrSync';
|
||||
@ -80,18 +80,13 @@ export default function AdminOutdatedClient({
|
||||
<Note>
|
||||
<div className="space-y-1.5">
|
||||
<div className="font-bold">
|
||||
Outdated photos found
|
||||
{photos.length} outdated
|
||||
{' '}
|
||||
{photos.length === 1 ? 'photo' : 'photos'} found
|
||||
</div>
|
||||
{photos.length}
|
||||
They may have missing EXIF fields, inaccurate blur data,
|
||||
{' '}
|
||||
{photos.length === 1 ? 'photo' : 'photos'}
|
||||
{' ('}last updated before
|
||||
{' '}
|
||||
{new Date(OUTDATED_THRESHOLD).toLocaleDateString()}{')'}
|
||||
{' '}
|
||||
may have: missing EXIF fields, inaccurate blur data,
|
||||
{' '}
|
||||
undesired privacy settings, or missing AI-generated text
|
||||
undesired privacy settings, or text that can be AI-generated
|
||||
</div>
|
||||
</Note>
|
||||
<div className="space-y-4">
|
||||
|
||||
@ -22,6 +22,8 @@ import { RevalidatePhoto } from '@/photo/InfinitePhotoScroll';
|
||||
import { MdOutlineFileDownload } from 'react-icons/md';
|
||||
import MoreMenuItem from '@/components/more/MoreMenuItem';
|
||||
import IconGrSync from '@/app/IconGrSync';
|
||||
import { isPhotoOutdated } from '@/photo/outdated';
|
||||
import { FaCircle } from 'react-icons/fa6';
|
||||
|
||||
export default function AdminPhotoMenuClient({
|
||||
photo,
|
||||
@ -76,7 +78,14 @@ export default function AdminPhotoMenuClient({
|
||||
hrefDownloadName: downloadFileNameForPhoto(photo),
|
||||
});
|
||||
items.push({
|
||||
label: 'Sync',
|
||||
label: <span className="inline-flex items-center gap-2">
|
||||
<span>Sync</span>
|
||||
{isPhotoOutdated(photo) &&
|
||||
<FaCircle
|
||||
size={8}
|
||||
className="text-amber-500 translate-y-[1.5px]"
|
||||
/>}
|
||||
</span>,
|
||||
icon: <IconGrSync className="translate-x-[-1px]" />,
|
||||
action: () => syncPhotoAction(photo.id)
|
||||
.then(() => revalidatePhoto?.(photo.id)),
|
||||
|
||||
@ -12,8 +12,8 @@ import {
|
||||
HAS_STATIC_OPTIMIZATION,
|
||||
MATTE_PHOTOS,
|
||||
} from '@/app/config';
|
||||
import { OUTDATED_THRESHOLD } from '@/photo';
|
||||
import { getGitHubMetaForCurrentApp, getSignificantInsights } from '.';
|
||||
import { getOutdatedPhotosCount } from '@/photo/db/query';
|
||||
|
||||
const BASIC_PHOTO_INSTALLATION_COUNT = 32;
|
||||
|
||||
@ -21,7 +21,7 @@ export default async function AdminAppInsights() {
|
||||
const [
|
||||
{ count: photosCount, dateRange },
|
||||
{ count: photosCountHidden },
|
||||
{ count: photosCountOutdated },
|
||||
photosCountOutdated,
|
||||
{ count: photosCountPortrait },
|
||||
tags,
|
||||
cameras,
|
||||
@ -31,7 +31,7 @@ export default async function AdminAppInsights() {
|
||||
] = await Promise.all([
|
||||
getPhotosMeta({ hidden: 'include' }),
|
||||
getPhotosMeta({ hidden: 'only' }),
|
||||
getPhotosMeta({ hidden: 'include', updatedBefore: OUTDATED_THRESHOLD }),
|
||||
getOutdatedPhotosCount(),
|
||||
getPhotosMeta({ maximumAspectRatio: 0.9 }),
|
||||
getUniqueTags(),
|
||||
getUniqueCameras(),
|
||||
|
||||
@ -342,8 +342,10 @@ export default function AdminAppInsightsClient({
|
||||
)}
|
||||
/>}
|
||||
content={renderHighlightText(
|
||||
// eslint-disable-next-line max-len
|
||||
pluralize(photosCountOutdated || DEBUG_PHOTOS_COUNT_OUTDATED, 'outdated photo'),
|
||||
pluralize(
|
||||
photosCountOutdated || DEBUG_PHOTOS_COUNT_OUTDATED,
|
||||
'outdated photo',
|
||||
),
|
||||
'yellow',
|
||||
)}
|
||||
expandPath={PATH_ADMIN_OUTDATED}
|
||||
|
||||
@ -6,18 +6,17 @@ import {
|
||||
getSignificantInsights,
|
||||
InsightIndicatorStatus,
|
||||
} from '.';
|
||||
import { getPhotosMeta } from '@/photo/db/query';
|
||||
import { OUTDATED_THRESHOLD } from '@/photo';
|
||||
import { getOutdatedPhotosCount } from '@/photo/db/query';
|
||||
|
||||
export const getShouldShowInsightsIndicatorAction =
|
||||
async (): Promise<InsightIndicatorStatus> =>
|
||||
runAuthenticatedAdminServerAction(async () => {
|
||||
const [
|
||||
codeMeta,
|
||||
{ count: photosCountOutdated },
|
||||
photosCountOutdated,
|
||||
] = await Promise.all([
|
||||
getGitHubMetaForCurrentApp(),
|
||||
getPhotosMeta({ hidden: 'include', updatedBefore: OUTDATED_THRESHOLD }),
|
||||
getOutdatedPhotosCount(),
|
||||
]);
|
||||
|
||||
const {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { PRIORITY_ORDER_ENABLED } from '@/app/config';
|
||||
import { parameterize } from '@/utility/string';
|
||||
import { PhotoSetCategory } from '..';
|
||||
import { Camera } from '@/camera';
|
||||
|
||||
export const GENERATE_STATIC_PARAMS_LIMIT = 1000;
|
||||
export const PHOTO_DEFAULT_LIMIT = 100;
|
||||
@ -22,7 +23,9 @@ export type GetPhotosOptions = {
|
||||
takenAfterInclusive?: Date
|
||||
updatedBefore?: Date
|
||||
hidden?: 'exclude' | 'include' | 'only'
|
||||
} & PhotoSetCategory;
|
||||
} & Omit<PhotoSetCategory, 'camera'> & {
|
||||
camera?: Partial<Camera>
|
||||
};
|
||||
|
||||
export const areOptionsSensitive = (options: GetPhotosOptions) =>
|
||||
options.hidden === 'include' || options.hidden === 'only';
|
||||
@ -83,9 +86,11 @@ export const getWheresFromOptions = (
|
||||
wheres.push(`$${valuesIndex++}=ANY(tags)`);
|
||||
wheresValues.push(tag);
|
||||
}
|
||||
if (camera) {
|
||||
if (camera?.make) {
|
||||
wheres.push(`${parameterizeForDb('make')}=$${valuesIndex++}`);
|
||||
wheresValues.push(parameterize(camera.make, true));
|
||||
}
|
||||
if (camera?.model) {
|
||||
wheres.push(`${parameterizeForDb('model')}=$${valuesIndex++}`);
|
||||
wheresValues.push(parameterize(camera.model, true));
|
||||
}
|
||||
|
||||
@ -24,6 +24,8 @@ import { getWheresFromOptions } from '.';
|
||||
import { FocalLengths } from '@/focal';
|
||||
import { Lenses, createLensKey } from '@/lens';
|
||||
import { migrationForError } from './migration';
|
||||
import { UPDATED_BEFORE_01, UPDATED_BEFORE_02 } from '../outdated';
|
||||
import { MAKE_FUJIFILM } from '@/platforms/fujifilm';
|
||||
|
||||
const createPhotosTable = () =>
|
||||
sql`
|
||||
@ -445,3 +447,39 @@ export const getPhoto = async (
|
||||
.then(({ rows }) => rows.map(parsePhotoFromDb))
|
||||
.then(photos => photos.length > 0 ? photos[0] : undefined);
|
||||
}, 'getPhoto');
|
||||
|
||||
// Outdated queries
|
||||
|
||||
const outdatedWhereClause =
|
||||
// eslint-disable-next-line quotes
|
||||
`WHERE updated_at < $1 OR (updated_at < $2 AND make = $3)`;
|
||||
|
||||
const outdatedValues = [
|
||||
UPDATED_BEFORE_01.toISOString(),
|
||||
UPDATED_BEFORE_02.toISOString(),
|
||||
MAKE_FUJIFILM,
|
||||
];
|
||||
|
||||
export const getOutdatedPhotos = () => safelyQueryPhotos(
|
||||
() => query(`
|
||||
SELECT * FROM photos
|
||||
${outdatedWhereClause}
|
||||
ORDER BY created_at ASC
|
||||
LIMIT 1000
|
||||
`,
|
||||
outdatedValues,
|
||||
)
|
||||
.then(({ rows }) => rows.map(parsePhotoFromDb)),
|
||||
'getOutdatedPhotos',
|
||||
);
|
||||
|
||||
export const getOutdatedPhotosCount = () => safelyQueryPhotos(
|
||||
() => query(`
|
||||
SELECT COUNT(*) FROM photos
|
||||
${outdatedWhereClause}
|
||||
`,
|
||||
outdatedValues,
|
||||
)
|
||||
.then(({ rows }) => parseInt(rows[0].count, 10)),
|
||||
'getOutdatedPhotosCount',
|
||||
);
|
||||
|
||||
@ -22,8 +22,6 @@ import { isBefore } from 'date-fns';
|
||||
import type { Metadata } from 'next';
|
||||
import { FujifilmRecipe } from '@/platforms/fujifilm/recipe';
|
||||
|
||||
export const OUTDATED_THRESHOLD = new Date('2024-06-16');
|
||||
|
||||
// INFINITE SCROLL: FEED
|
||||
export const INFINITE_SCROLL_FEED_INITIAL =
|
||||
process.env.NODE_ENV === 'development' ? 2 : 12;
|
||||
|
||||
13
src/photo/outdated.ts
Normal file
13
src/photo/outdated.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { MAKE_FUJIFILM } from '@/platforms/fujifilm';
|
||||
import { Photo } from '.';
|
||||
|
||||
export const UPDATED_BEFORE_01 = new Date('2024-06-16');
|
||||
// UTC 2025-02-24 05:30:00
|
||||
export const UPDATED_BEFORE_02 = new Date(Date.UTC(2025, 1, 24, 5, 30, 0));
|
||||
|
||||
export const isPhotoOutdated = (photo: Photo) => {
|
||||
return photo.updatedAt < UPDATED_BEFORE_01 || (
|
||||
photo.updatedAt < UPDATED_BEFORE_02 &&
|
||||
photo.make === MAKE_FUJIFILM
|
||||
);
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user