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.
This commit is contained in:
parent
8af4e857b7
commit
90e7caac43
3 changed files with 14 additions and 31 deletions
2
src/lib/client/cache/previews.ts
vendored
2
src/lib/client/cache/previews.ts
vendored
|
|
@ -8,7 +8,7 @@ import { documentPreviewFallbackUrl, documentPreviewPresignUrl } from '@/lib/cli
|
||||||
|
|
||||||
const inMemoryPreviewUrlCache = new Map<string, string>();
|
const inMemoryPreviewUrlCache = new Map<string, string>();
|
||||||
const inFlightPreviewPrime = new Map<string, Promise<string | null>>();
|
const inFlightPreviewPrime = new Map<string, Promise<string | null>>();
|
||||||
const PREVIEW_CACHE_SCHEMA_VERSION = 3;
|
const PREVIEW_CACHE_SCHEMA_VERSION = 4;
|
||||||
|
|
||||||
function revokeIfBlobUrl(url: string | null | undefined): void {
|
function revokeIfBlobUrl(url: string | null | undefined): void {
|
||||||
if (!url) return;
|
if (!url) return;
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,10 @@ import { getS3Client, getS3Config, getS3ProxyClient } from '@/lib/server/storage
|
||||||
const SAFE_NAMESPACE_REGEX = /^[a-zA-Z0-9._-]{1,128}$/;
|
const SAFE_NAMESPACE_REGEX = /^[a-zA-Z0-9._-]{1,128}$/;
|
||||||
const DEFAULT_NAMESPACE_SEGMENT = '_default';
|
const DEFAULT_NAMESPACE_SEGMENT = '_default';
|
||||||
|
|
||||||
export const DOCUMENT_PREVIEW_VARIANT = 'card-480-jpeg';
|
export const DOCUMENT_PREVIEW_VARIANT = 'card-400-jpeg';
|
||||||
export const DOCUMENT_PREVIEW_FILE_NAME = 'card-480.jpg';
|
export const DOCUMENT_PREVIEW_FILE_NAME = 'card-400.jpg';
|
||||||
export const DOCUMENT_PREVIEW_CONTENT_TYPE = 'image/jpeg';
|
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 {
|
function sanitizeNamespace(namespace: string | null): string | null {
|
||||||
if (!namespace) return null;
|
if (!namespace) return null;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,4 @@
|
||||||
import { randomUUID } from 'crypto';
|
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 { and, eq, inArray, lt, or, sql } from 'drizzle-orm';
|
||||||
import { db } from '@/db';
|
import { db } from '@/db';
|
||||||
import { documentPreviews } from '@/db/schema';
|
import { documentPreviews } from '@/db/schema';
|
||||||
|
|
@ -290,13 +287,7 @@ async function markPreviewFailed(docId: string, namespaceKey: string, error: unk
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generateAndStorePreview(doc: PreviewSourceDocument, namespace: string | null): Promise<void> {
|
async function generateAndStorePreview(doc: PreviewSourceDocument, namespace: string | null): Promise<void> {
|
||||||
let workDir: string | null = null;
|
|
||||||
try {
|
|
||||||
const sourceBytes = await getDocumentBlob(doc.id, namespace);
|
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;
|
let rendered;
|
||||||
if (doc.type === 'pdf') {
|
if (doc.type === 'pdf') {
|
||||||
rendered = await renderPdfFirstPageToJpeg(sourceBytes, DOCUMENT_PREVIEW_WIDTH);
|
rendered = await renderPdfFirstPageToJpeg(sourceBytes, DOCUMENT_PREVIEW_WIDTH);
|
||||||
|
|
@ -305,16 +296,8 @@ async function generateAndStorePreview(doc: PreviewSourceDocument, namespace: st
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Unsupported preview type: ${doc.type}`);
|
throw new Error(`Unsupported preview type: ${doc.type}`);
|
||||||
}
|
}
|
||||||
|
// Hot path: overwrite current variant key directly to avoid prefix list/delete latency.
|
||||||
// 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);
|
await putDocumentPreviewBuffer(doc.id, rendered.bytes, namespace);
|
||||||
} finally {
|
|
||||||
if (workDir) {
|
|
||||||
await rm(workDir, { recursive: true, force: true }).catch(() => {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function pendingResult(status: PreviewStatus, lastError: string | null): EnsureDocumentPreviewResult {
|
function pendingResult(status: PreviewStatus, lastError: string | null): EnsureDocumentPreviewResult {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue