import { S3Client, ListObjectsV2Command, GetObjectCommand } from "@aws-sdk/client-s3"; import exifReader from "exif-reader"; import { diff, sift } from "radash"; import sharp from "sharp"; import db from "@/db/db"; import { photosTable } from "@/db/schema/photo"; import { TRPCError } from "@trpc/server"; export async function update(): Promise { const photos = await db.select().from(photosTable); const currentSources = photos.map((photo) => photo.src); const s3Client = new S3Client({ region: "auto", endpoint: `https://fly.storage.tigris.dev`, }); const listObjCmd = new ListObjectsV2Command({ Bucket: "joemonk-photos" }); const s3Res = await s3Client.send(listObjCmd); if (!s3Res.Contents) { throw new TRPCError({ code: "GATEWAY_TIMEOUT", message: "Could not get contents from Tigris" }); } const s3Photos = sift(s3Res.Contents.map((obj) => { if (!obj.Key?.endsWith('/')) { return `https://fly.storage.tigris.dev/joemonk-photos/${obj.Key}`; } else { return null; } })); const newPhotos = diff(s3Photos, currentSources); if (newPhotos.length === 0) { return []; } const imageData = newPhotos.map(async (fileName: string) => { const getImageCmd = new GetObjectCommand({ Bucket: "joemonk-photos", Key: fileName.replace("https://fly.storage.tigris.dev/joemonk-photos/", "") }); const imgRes = await s3Client.send(getImageCmd); const image = await imgRes.Body?.transformToByteArray(); const { width, height, exif } = await sharp(image).metadata(); const blur = await sharp(image) .resize({ width: 12, height: 12, fit: 'inside' }) .toBuffer(); const exifData = exif ? exifReader(exif) : undefined; const photo: typeof photosTable.$inferInsert = { src: fileName, width: width ?? 10, height: height ?? 10, blur: `data:image/jpeg;base64,${blur.toString('base64')}` as `data:image/${string}`, camera: exifData?.Image?.Model ?? null, exposureBiasValue: exifData?.Photo?.ExposureBiasValue ?? null, fNumber: exifData?.Photo?.FNumber ?? null, isoSpeedRatings: exifData?.Photo?.ISOSpeedRatings ?? null, focalLength: exifData?.Photo?.FocalLength ?? null, dateTimeOriginal: exifData?.Photo?.DateTimeOriginal ?? null, lensModel: exifData?.Photo?.LensModel ?? null, }; return photo; }); const images = await Promise.all(imageData); await db.insert(photosTable).values(images); return newPhotos; };