From 04439d74efcfe31b1899679a9e1140058ce14a90 Mon Sep 17 00:00:00 2001 From: mbaharip <62494292+mbahArip@users.noreply.github.com> Date: Sun, 5 May 2024 23:47:55 +0700 Subject: [PATCH] Use `/thumbnail` endpoint and add long cache --- src/app/api/thumb/[encryptedId]/route.ts | 92 +++++++----------------- 1 file changed, 27 insertions(+), 65 deletions(-) diff --git a/src/app/api/thumb/[encryptedId]/route.ts b/src/app/api/thumb/[encryptedId]/route.ts index ed0cd05..39eeccd 100644 --- a/src/app/api/thumb/[encryptedId]/route.ts +++ b/src/app/api/thumb/[encryptedId]/route.ts @@ -1,4 +1,5 @@ import { NextRequest, NextResponse } from "next/server"; +import { z } from "zod"; import { decryptData } from "~/utils/encryptionHelper/hash"; import gdrive from "~/utils/gdriveInstance"; @@ -16,6 +17,14 @@ export async function GET( { params: { encryptedId } }: Props, ) { try { + const searchParams = new URL(request.nextUrl).searchParams; + const size = searchParams.get("size") || "512"; + + const validSize = z.coerce.number().safeParse(size); + if (!validSize.success) { + throw new Error("Invalid size"); + } + const defaultImage = NextResponse.redirect( new URL("/og.png", config.basePath), { @@ -23,86 +32,39 @@ export async function GET( }, ); const decryptedId = await decryptData(encryptedId); - const _fileMeta = gdrive.files.get({ + + const fileMeta = await gdrive.files.get({ fileId: decryptedId, fields: "id, name, mimeType, fileExtension, webContentLink, thumbnailLink", supportsAllDrives: config.apiConfig.isTeamDrive, }); - const _fileContent = gdrive.files.get( - { - fileId: decryptedId, - alt: "media", - supportsAllDrives: config.apiConfig.isTeamDrive, - }, - { - responseType: "stream", - }, - ); - const [fileMeta, fileContent] = await Promise.all([ - _fileMeta, - _fileContent, - ]); - const fileSize = Number(fileMeta.data.size || 0); - - if (!fileMeta.data.webContentLink) return defaultImage; - if (!fileMeta.data.thumbnailLink) return defaultImage; if ( !fileMeta.data.mimeType?.startsWith("image") && !fileMeta.data.mimeType?.startsWith("video") - ) - return defaultImage; - - // If svg, return actual image since there is no thumbnail for svg - if ( - fileMeta.data.mimeType?.includes("svg") && - fileSize <= config.apiConfig.maxFileSize ) { - const fileBuffer = await new Promise((resolve, reject) => { - const chunks: Buffer[] = []; - fileContent.data.on("data", (chunk) => { - chunks.push(chunk); - }); - fileContent.data.on("end", () => { - resolve(Buffer.concat(chunks)); - }); - fileContent.data.on("error", (err) => { - reject(err); - }); - }); - - return new NextResponse(fileBuffer, { - headers: { - "Cache-Control": "public, max-age=31536000, immutable", - "Content-Type": fileMeta.data.mimeType || "application/octet-stream", - "Content-Length": fileBuffer.length.toString(), - "Content-Disposition": `attachment; filename="${encodeURIComponent( - fileMeta.data.name || `Untitled.${fileMeta.data.fileExtension}`, - )}"`, - }, - }); + return defaultImage; } - if (config.apiConfig.proxyThumbnail) { - const downloadThumb = await fetch(fileMeta.data.thumbnailLink, { - cache: "force-cache", - }); - const buffer = await downloadThumb.arrayBuffer(); + const url = `https://drive.google.com/thumbnail?id=${decryptedId}&sz=w${size}`; - return new NextResponse(buffer, { - headers: { - "Cache-Control": "public, max-age=31536000, immutable", - "Content-Type": fileMeta.data.mimeType || "application/octet-stream", - "Content-Length": buffer.byteLength.toString(), - "Content-Disposition": `attachment; filename="${encodeURIComponent( - fileMeta.data.name || `Untitled.${fileMeta.data.fileExtension}`, - )}"`, - }, - }); + if (!config.apiConfig.proxyThumbnail) { + return NextResponse.redirect(url); } - return NextResponse.redirect(fileMeta.data.thumbnailLink); + const downloadThumb = await fetch(url, { + cache: "force-cache", + }); + const buffer = await downloadThumb.arrayBuffer(); + + return new NextResponse(buffer, { + headers: { + "Cache-Control": "public, max-age=31536000, immutable", + "Content-Type": "image/jpeg", + "Content-Length": buffer.byteLength.toString(), + }, + }); } catch (error) { const e = error as Error; console.error(e.message);