BREAKING: postgres + saas

This commit is contained in:
Vasily Zubarev
2025-04-03 13:07:54 +02:00
parent 54a892ddb0
commit f523b1f8ba
136 changed files with 3971 additions and 1563 deletions

19
lib/previews/generate.ts Normal file
View File

@@ -0,0 +1,19 @@
import { resizeImage } from "@/lib/previews/images"
import { pdfToImages } from "@/lib/previews/pdf"
import { User } from "@prisma/client"
export async function generateFilePreviews(
user: User,
filePath: string,
mimetype: string
): Promise<{ contentType: string; previews: string[] }> {
if (mimetype === "application/pdf") {
const { contentType, pages } = await pdfToImages(user, filePath)
return { contentType, previews: pages }
} else if (mimetype.startsWith("image/")) {
const { contentType, resizedPath } = await resizeImage(user, filePath)
return { contentType, previews: [resizedPath] }
} else {
return { contentType: mimetype, previews: [filePath] }
}
}

54
lib/previews/images.ts Normal file
View File

@@ -0,0 +1,54 @@
"use server"
import { fileExists, getUserPreviewsDirectory } from "@/lib/files"
import { User } from "@prisma/client"
import fs from "fs/promises"
import path from "path"
import sharp from "sharp"
const MAX_WIDTH = 1800
const MAX_HEIGHT = 1800
const QUALITY = 90
export async function resizeImage(
user: User,
origFilePath: string,
maxWidth: number = MAX_WIDTH,
maxHeight: number = MAX_HEIGHT
): Promise<{ contentType: string; resizedPath: string }> {
try {
const userPreviewsDirectory = await getUserPreviewsDirectory(user)
await fs.mkdir(userPreviewsDirectory, { recursive: true })
const basename = path.basename(origFilePath, path.extname(origFilePath))
const outputPath = path.join(userPreviewsDirectory, `${basename}.webp`)
if (await fileExists(outputPath)) {
const metadata = await sharp(outputPath).metadata()
return {
contentType: `image/${metadata.format}`,
resizedPath: outputPath,
}
}
await sharp(origFilePath)
.rotate()
.resize(maxWidth, maxHeight, {
fit: "inside",
withoutEnlargement: true,
})
.webp({ quality: QUALITY })
.toFile(outputPath)
return {
contentType: "image/webp",
resizedPath: outputPath,
}
} catch (error) {
console.error("Error resizing image:", error)
return {
contentType: "image/unknown",
resizedPath: origFilePath,
}
}
}

59
lib/previews/pdf.ts Normal file
View File

@@ -0,0 +1,59 @@
"use server"
import { fileExists, getUserPreviewsDirectory } from "@/lib/files"
import { User } from "@prisma/client"
import fs from "fs/promises"
import path from "path"
import { fromPath } from "pdf2pic"
const MAX_PAGES = 10
const DPI = 150
const QUALITY = 90
const MAX_WIDTH = 1500
const MAX_HEIGHT = 1500
export async function pdfToImages(user: User, origFilePath: string): Promise<{ contentType: string; pages: string[] }> {
const userPreviewsDirectory = await getUserPreviewsDirectory(user)
await fs.mkdir(userPreviewsDirectory, { recursive: true })
const basename = path.basename(origFilePath, path.extname(origFilePath))
// Check if converted pages already exist
const existingPages: string[] = []
for (let i = 1; i <= MAX_PAGES; i++) {
const convertedFilePath = path.join(userPreviewsDirectory, `${basename}.${i}.webp`)
if (await fileExists(convertedFilePath)) {
existingPages.push(convertedFilePath)
} else {
break
}
}
if (existingPages.length > 0) {
return { contentType: "image/webp", pages: existingPages }
}
// If not — convert the file as store in previews folder
const pdf2picOptions = {
density: DPI,
saveFilename: basename,
savePath: userPreviewsDirectory,
format: "webp",
quality: QUALITY,
width: MAX_WIDTH,
height: MAX_HEIGHT,
preserveAspectRatio: true,
}
try {
const convert = fromPath(origFilePath, pdf2picOptions)
const results = await convert.bulk(-1, { responseType: "image" }) // TODO: respect MAX_PAGES here too
const paths = results.filter((result) => result && result.path).map((result) => result.path) as string[]
return {
contentType: "image/webp",
pages: paths,
}
} catch (error) {
console.error("Error converting PDF to image:", error)
throw error
}
}