Optimize safe url generation for og images
This commit is contained in:
parent
af672dfcf4
commit
1994f3bfba
@ -3,7 +3,7 @@
|
||||
import { Photo } from '@/photo';
|
||||
import { NextImageSize } from '@/platforms/next-image';
|
||||
import { IS_PREVIEW } from '@/app/config';
|
||||
import { getOptimizedUrlsForPhotos } from '@/photo/storage';
|
||||
import { getDataUrlsForPhotos } from '@/photo/storage';
|
||||
|
||||
export default async function ImagePhotoGrid({
|
||||
photos,
|
||||
@ -52,7 +52,7 @@ export default async function ImagePhotoGrid({
|
||||
const cellHeight= height / rows -
|
||||
(rows - 1) * gap / rows;
|
||||
|
||||
const photoUrls = await getOptimizedUrlsForPhotos(
|
||||
const photoUrls = await getDataUrlsForPhotos(
|
||||
photos,
|
||||
optimizedSuffix,
|
||||
nextImageWidth,
|
||||
@ -60,7 +60,7 @@ export default async function ImagePhotoGrid({
|
||||
);
|
||||
|
||||
const renderPhoto = (
|
||||
{ id, url }: typeof photoUrls[number],
|
||||
{ id, urlData }: typeof photoUrls[number],
|
||||
width: number,
|
||||
height: number,
|
||||
) =>
|
||||
@ -75,7 +75,7 @@ export default async function ImagePhotoGrid({
|
||||
}}
|
||||
>
|
||||
<img {...{
|
||||
src: url,
|
||||
src: urlData,
|
||||
style: {
|
||||
...imageStyle,
|
||||
width: '100%',
|
||||
|
||||
@ -10,6 +10,7 @@ import {
|
||||
uploadFileFromClient,
|
||||
} from '@/platforms/storage';
|
||||
import { Photo } from '..';
|
||||
import { fetchBase64ImageFromUrl } from '@/utility/image';
|
||||
|
||||
const PREFIX_PHOTO = 'photo';
|
||||
const PREFIX_UPLOAD = 'upload';
|
||||
@ -157,39 +158,35 @@ export const getStorageUrlsForPhoto = async ({ url }: Photo) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const getOptimizedUrlsForPhotos = async (
|
||||
export const getDataUrlsForPhotos = async (
|
||||
photos: Photo[],
|
||||
optimizedSuffix: OptimizedSuffix,
|
||||
nextImageWidth: NextImageSize,
|
||||
addBypassSecret: boolean,
|
||||
) =>
|
||||
Promise.all(photos
|
||||
.map(async({ id, url: _url }) => {
|
||||
.map(async({ id, url }) => {
|
||||
// Check for optimized image first
|
||||
const optimizedUrl =await getSignedUrlForUrl(
|
||||
getOptimizedPhotoUrlForSuffix(_url, optimizedSuffix),
|
||||
getOptimizedPhotoUrlForSuffix(url, optimizedSuffix),
|
||||
'GET',
|
||||
);
|
||||
const optimizedUrlExists = await fetch(optimizedUrl)
|
||||
.then(res => res.ok)
|
||||
.catch(() => false);
|
||||
const optimizedUrlData = await fetchBase64ImageFromUrl(optimizedUrl);
|
||||
|
||||
if (optimizedUrlExists) {
|
||||
return { id, url: optimizedUrl };
|
||||
if (optimizedUrlData) {
|
||||
return { id, urlData: optimizedUrlData };
|
||||
} else {
|
||||
// Fall back on `next/image` if optimized image is not available
|
||||
const nextImageUrl = getOptimizedPhotoUrl({
|
||||
imageUrl: _url,
|
||||
imageUrl: url,
|
||||
size: nextImageWidth,
|
||||
addBypassSecret,
|
||||
});
|
||||
const nextImageUrlExists = await fetch(nextImageUrl)
|
||||
.then(res => res.ok)
|
||||
.catch(() => false);
|
||||
return { id, url: nextImageUrlExists ? nextImageUrl : undefined };
|
||||
const nextImageUrlData = await fetchBase64ImageFromUrl(nextImageUrl);
|
||||
return { id, urlData: nextImageUrlData };
|
||||
}
|
||||
}))
|
||||
.then(urls =>(urls.every(url => Boolean(url))
|
||||
.then(urls =>(urls.every(({ urlData }) => Boolean(urlData))
|
||||
? urls
|
||||
// If any url is defined, return an empty array
|
||||
: []) as { id: string, url: string }[]);
|
||||
// If any url is undefined, return an empty array
|
||||
: []) as { id: string, urlData: string }[]);
|
||||
|
||||
@ -1,15 +1,24 @@
|
||||
import { getFileNamePartsFromStorageUrl } from '@/platforms/storage';
|
||||
|
||||
export const removeBase64Prefix = (base64: string) => {
|
||||
return base64.match(/^data:image\/[a-z]{3,4};base64,(.+)$/)?.[1] ?? base64;
|
||||
};
|
||||
|
||||
export const fetchBase64ImageFromUrl = (
|
||||
export const fetchBase64ImageFromUrl = async (
|
||||
url: string,
|
||||
contentType?: string,
|
||||
fetchOptions?: RequestInit,
|
||||
) =>
|
||||
fetch(url, fetchOptions)
|
||||
) => {
|
||||
const { fileExtension } = getFileNamePartsFromStorageUrl(url);
|
||||
const contentType = fileExtension === 'png' ? 'image/png' : 'image/jpeg';
|
||||
return fetch(url, fetchOptions)
|
||||
.then(async response => {
|
||||
if (response.ok) {
|
||||
const blob = await response.arrayBuffer();
|
||||
// eslint-disable-next-line max-len
|
||||
return `data:${contentType ?? response.headers.get('content-type')};base64,${Buffer.from(blob).toString('base64')}`;
|
||||
});
|
||||
return `data:${contentType};base64,${Buffer.from(blob).toString('base64')}`;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
})
|
||||
.catch(() => undefined);
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user