65 lines
2.0 KiB
JavaScript
65 lines
2.0 KiB
JavaScript
import { json, error } from '@sveltejs/kit';
|
|
import { S3Client, ListObjectsV2Command, GetObjectCommand } from '@aws-sdk/client-s3';
|
|
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
|
import { env } from '$env/dynamic/private';
|
|
|
|
export async function GET({ url }) {
|
|
const nextToken = url.searchParams.get('next') || undefined;
|
|
|
|
try {
|
|
const s3 = new S3Client({
|
|
endpoint: env.B2_ENDPOINT,
|
|
region: env.B2_REGION,
|
|
credentials: {
|
|
accessKeyId: env.B2_ACCESS_KEY_ID,
|
|
secretAccessKey: env.B2_SECRET_ACCESS_KEY
|
|
}
|
|
});
|
|
|
|
const tokenDuration = parseInt(env.B2_TOKEN_DURATION, 10) || 600;
|
|
|
|
// Fetch a batch of files from the thumbs/ folder
|
|
const listCommand = new ListObjectsV2Command({
|
|
Bucket: env.B2_BUCKET_NAME,
|
|
Prefix: 'thumbs/',
|
|
MaxKeys: 40,
|
|
ContinuationToken: nextToken
|
|
});
|
|
|
|
const listResponse = await s3.send(listCommand);
|
|
const contents = listResponse.Contents || [];
|
|
|
|
// 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');
|
|
});
|
|
|
|
// 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: env.B2_BUCKET_NAME, Key: file.Key });
|
|
const fullCommand = new GetObjectCommand({ Bucket: env.B2_BUCKET_NAME, Key: fullSizeKey });
|
|
|
|
// 10 minutes = 600 seconds
|
|
const [thumbUrl, fullUrl] = await Promise.all([
|
|
getSignedUrl(s3, thumbCommand, { expiresIn: tokenDuration }),
|
|
getSignedUrl(s3, fullCommand, { expiresIn: tokenDuration })
|
|
]);
|
|
|
|
return { id, thumbUrl, fullUrl };
|
|
})
|
|
);
|
|
|
|
return json({
|
|
photos,
|
|
nextContinuationToken: listResponse.NextContinuationToken || null
|
|
});
|
|
} catch (err) {
|
|
console.error(err);
|
|
throw error(500, 'Failed to process images from storage.');
|
|
}
|
|
} |