first commit
This commit is contained in:
66
src/routes/api/photos/+server.js
Normal file
66
src/routes/api/photos/+server.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import { json, error } from '@sveltejs/kit';
|
||||
import { S3Client, ListObjectsV2Command, GetObjectCommand } from '@aws-sdk/client-s3';
|
||||
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
||||
import {
|
||||
B2_ENDPOINT, B2_REGION, B2_ACCESS_KEY_ID, B2_SECRET_ACCESS_KEY, B2_BUCKET_NAME
|
||||
} from '$env/static/private';
|
||||
|
||||
const s3 = new S3Client({
|
||||
endpoint: B2_ENDPOINT,
|
||||
region: B2_REGION,
|
||||
credentials: {
|
||||
accessKeyId: B2_ACCESS_KEY_ID,
|
||||
secretAccessKey: B2_SECRET_ACCESS_KEY
|
||||
}
|
||||
});
|
||||
|
||||
export async function GET({ url }) {
|
||||
const nextToken = url.searchParams.get('next') || undefined;
|
||||
|
||||
try {
|
||||
// 1. Fetch a batch of files from the thumbs/ folder
|
||||
const listCommand = new ListObjectsV2Command({
|
||||
Bucket: B2_BUCKET_NAME,
|
||||
Prefix: 'thumbs/',
|
||||
MaxKeys: 40, // Increased slight headroom since we filter on the server side now
|
||||
ContinuationToken: nextToken
|
||||
});
|
||||
|
||||
const listResponse = await s3.send(listCommand);
|
||||
const contents = listResponse.Contents || [];
|
||||
|
||||
// 2. Strict Filter: Only allow actual .jpg or .jpeg extensions
|
||||
const imageFiles = contents.filter(file => {
|
||||
const lowerKey = file.Key.toLowerCase();
|
||||
return lowerKey.endsWith('.jpg') || lowerKey.endsWith('.jpeg');
|
||||
});
|
||||
|
||||
// 3. Generate presigned URLs for validated items
|
||||
const photos = await Promise.all(
|
||||
imageFiles.map(async (file) => {
|
||||
const id = file.Key.replace('thumbs/', '');
|
||||
const fullSizeKey = `images/${id}`;
|
||||
|
||||
const thumbCommand = new GetObjectCommand({ Bucket: B2_BUCKET_NAME, Key: file.Key });
|
||||
const fullCommand = new GetObjectCommand({ Bucket: B2_BUCKET_NAME, Key: fullSizeKey });
|
||||
|
||||
// 10 minutes = 600 seconds
|
||||
const [thumbUrl, fullUrl] = await Promise.all([
|
||||
getSignedUrl(s3, thumbCommand, { expiresIn: 600 }),
|
||||
getSignedUrl(s3, fullCommand, { expiresIn: 600 })
|
||||
]);
|
||||
|
||||
return { id, thumbUrl, fullUrl };
|
||||
})
|
||||
);
|
||||
|
||||
return json({
|
||||
photos,
|
||||
// Pass the original continuation token back so pagination structural flow remains intact
|
||||
nextContinuationToken: listResponse.NextContinuationToken || null
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw error(500, 'Failed to process images from storage.');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user