From 90e7caac43ef0b45d2d6a83cff687dfe37706995 Mon Sep 17 00:00:00 2001 From: Richard R Date: Mon, 18 May 2026 12:37:26 -0600 Subject: [PATCH] refactor(previews): streamline preview generation and update image variant to 400px Remove temporary working directory usage and in-place file writes from preview generation, simplifying logic for both PDF and EPUB previews. Change default preview image variant from 480px to 400px width, updating related constants and cache schema version to maintain consistency across client and server code. --- src/lib/client/cache/previews.ts | 2 +- .../server/documents/previews-blobstore.ts | 6 +-- src/lib/server/documents/previews.ts | 37 +++++-------------- 3 files changed, 14 insertions(+), 31 deletions(-) diff --git a/src/lib/client/cache/previews.ts b/src/lib/client/cache/previews.ts index d8ae889..736c273 100644 --- a/src/lib/client/cache/previews.ts +++ b/src/lib/client/cache/previews.ts @@ -8,7 +8,7 @@ import { documentPreviewFallbackUrl, documentPreviewPresignUrl } from '@/lib/cli const inMemoryPreviewUrlCache = new Map(); const inFlightPreviewPrime = new Map>(); -const PREVIEW_CACHE_SCHEMA_VERSION = 3; +const PREVIEW_CACHE_SCHEMA_VERSION = 4; function revokeIfBlobUrl(url: string | null | undefined): void { if (!url) return; diff --git a/src/lib/server/documents/previews-blobstore.ts b/src/lib/server/documents/previews-blobstore.ts index 01d9ecd..aa2d973 100644 --- a/src/lib/server/documents/previews-blobstore.ts +++ b/src/lib/server/documents/previews-blobstore.ts @@ -10,10 +10,10 @@ import { getS3Client, getS3Config, getS3ProxyClient } from '@/lib/server/storage const SAFE_NAMESPACE_REGEX = /^[a-zA-Z0-9._-]{1,128}$/; const DEFAULT_NAMESPACE_SEGMENT = '_default'; -export const DOCUMENT_PREVIEW_VARIANT = 'card-480-jpeg'; -export const DOCUMENT_PREVIEW_FILE_NAME = 'card-480.jpg'; +export const DOCUMENT_PREVIEW_VARIANT = 'card-400-jpeg'; +export const DOCUMENT_PREVIEW_FILE_NAME = 'card-400.jpg'; export const DOCUMENT_PREVIEW_CONTENT_TYPE = 'image/jpeg'; -export const DOCUMENT_PREVIEW_WIDTH = 480; +export const DOCUMENT_PREVIEW_WIDTH = 400; function sanitizeNamespace(namespace: string | null): string | null { if (!namespace) return null; diff --git a/src/lib/server/documents/previews.ts b/src/lib/server/documents/previews.ts index 8f4414c..9e7000a 100644 --- a/src/lib/server/documents/previews.ts +++ b/src/lib/server/documents/previews.ts @@ -1,7 +1,4 @@ import { randomUUID } from 'crypto'; -import { mkdtemp, rm, writeFile } from 'fs/promises'; -import { tmpdir } from 'os'; -import { join } from 'path'; import { and, eq, inArray, lt, or, sql } from 'drizzle-orm'; import { db } from '@/db'; import { documentPreviews } from '@/db/schema'; @@ -290,31 +287,17 @@ async function markPreviewFailed(docId: string, namespaceKey: string, error: unk } async function generateAndStorePreview(doc: PreviewSourceDocument, namespace: string | null): Promise { - let workDir: string | null = null; - try { - const sourceBytes = await getDocumentBlob(doc.id, namespace); - workDir = await mkdtemp(join(tmpdir(), 'openreader-preview-')); - const sourcePath = join(workDir, 'source'); - await writeFile(sourcePath, sourceBytes); - - let rendered; - if (doc.type === 'pdf') { - rendered = await renderPdfFirstPageToJpeg(sourceBytes, DOCUMENT_PREVIEW_WIDTH); - } else if (doc.type === 'epub') { - rendered = await renderEpubCoverToJpeg(sourceBytes, DOCUMENT_PREVIEW_WIDTH); - } else { - throw new Error(`Unsupported preview type: ${doc.type}`); - } - - // Replace-in-place semantics: clear old preview objects for this document - // prefix before writing the current variant so stale files don't linger. - await deleteDocumentPreviewArtifacts(doc.id, namespace).catch(() => undefined); - await putDocumentPreviewBuffer(doc.id, rendered.bytes, namespace); - } finally { - if (workDir) { - await rm(workDir, { recursive: true, force: true }).catch(() => {}); - } + const sourceBytes = await getDocumentBlob(doc.id, namespace); + let rendered; + if (doc.type === 'pdf') { + rendered = await renderPdfFirstPageToJpeg(sourceBytes, DOCUMENT_PREVIEW_WIDTH); + } else if (doc.type === 'epub') { + rendered = await renderEpubCoverToJpeg(sourceBytes, DOCUMENT_PREVIEW_WIDTH); + } else { + throw new Error(`Unsupported preview type: ${doc.type}`); } + // Hot path: overwrite current variant key directly to avoid prefix list/delete latency. + await putDocumentPreviewBuffer(doc.id, rendered.bytes, namespace); } function pendingResult(status: PreviewStatus, lastError: string | null): EnsureDocumentPreviewResult {