mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2026-05-01 23:16:31 +02:00
FixThumbnailRegeneration (#6134)
This commit is contained in:
@@ -3,6 +3,7 @@ import { StirlingFileStub } from "@app/types/fileContext";
|
||||
import { useIndexedDB } from "@app/contexts/IndexedDBContext";
|
||||
import { generateThumbnailForFile } from "@app/utils/thumbnailUtils";
|
||||
import { FileId } from "@app/types/fileContext";
|
||||
import { useFileManagement } from "@app/contexts/FileContext";
|
||||
|
||||
/**
|
||||
* Hook for IndexedDB-aware thumbnail loading
|
||||
@@ -17,6 +18,7 @@ export function useIndexedDBThumbnail(
|
||||
const [thumb, setThumb] = useState<string | null>(null);
|
||||
const [generating, setGenerating] = useState(false);
|
||||
const indexedDB = useIndexedDB();
|
||||
const { updateStirlingFileStub } = useFileManagement();
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
@@ -27,58 +29,59 @@ export function useIndexedDBThumbnail(
|
||||
return;
|
||||
}
|
||||
|
||||
// First priority: use stored thumbnail
|
||||
// Tier 1: stored thumbnail on the stub.
|
||||
if (file.thumbnailUrl) {
|
||||
setThumb(file.thumbnailUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
// Second priority: generate thumbnail for files under 100MB
|
||||
if (file.size < 100 * 1024 * 1024 && !generating) {
|
||||
setGenerating(true);
|
||||
try {
|
||||
let fileObject: File;
|
||||
|
||||
// Try to load file from IndexedDB using new context
|
||||
if (file.id && indexedDB) {
|
||||
const loadedFile = await indexedDB.loadFile(file.id as FileId);
|
||||
if (!loadedFile) {
|
||||
throw new Error("File not found in IndexedDB");
|
||||
}
|
||||
fileObject = loadedFile;
|
||||
} else {
|
||||
throw new Error(
|
||||
"File ID not available or IndexedDB context not available",
|
||||
);
|
||||
}
|
||||
|
||||
// Use the universal thumbnail generator
|
||||
const thumbnail = await generateThumbnailForFile(fileObject);
|
||||
if (!cancelled) {
|
||||
setThumb(thumbnail);
|
||||
|
||||
// Save thumbnail to IndexedDB for persistence
|
||||
if (file.id && indexedDB && thumbnail) {
|
||||
try {
|
||||
await indexedDB.updateThumbnail(file.id as FileId, thumbnail);
|
||||
} catch (error) {
|
||||
console.warn("Failed to save thumbnail to IndexedDB:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
"Failed to generate thumbnail for file",
|
||||
file.name,
|
||||
error,
|
||||
);
|
||||
if (!cancelled) setThumb(null);
|
||||
} finally {
|
||||
if (!cancelled) setGenerating(false);
|
||||
}
|
||||
} else {
|
||||
// Large files - no thumbnail
|
||||
// >=100MB files are skipped entirely — no thumbnail.
|
||||
if (file.size >= 100 * 1024 * 1024) {
|
||||
setThumb(null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Tier 2: generate on demand from the File bytes in IndexedDB.
|
||||
// Re-entry guard is handled by the effect's cleanup/cancelled pattern —
|
||||
// `generating` is NOT in the deps, so setGenerating() does not trigger
|
||||
// the effect to re-run and cancel itself mid-flight.
|
||||
setGenerating(true);
|
||||
try {
|
||||
if (!file.id || !indexedDB) {
|
||||
throw new Error(
|
||||
`missing prerequisite fileId=${file.id} indexedDB=${Boolean(indexedDB)}`,
|
||||
);
|
||||
}
|
||||
|
||||
const loadedFile = await indexedDB.loadFile(file.id as FileId);
|
||||
if (!loadedFile) {
|
||||
throw new Error("not in IndexedDB (likely remote-only stub)");
|
||||
}
|
||||
|
||||
const thumbnail = await generateThumbnailForFile(loadedFile);
|
||||
if (cancelled) return;
|
||||
|
||||
setThumb(thumbnail);
|
||||
|
||||
if (file.id && indexedDB && thumbnail) {
|
||||
try {
|
||||
await indexedDB.updateThumbnail(file.id as FileId, thumbnail);
|
||||
// Also sync the in-memory stub so subsequent re-mounts hit tier 1
|
||||
// instead of regenerating. IndexedDB persistence alone only helps
|
||||
// the next page load; the current session reads file.thumbnailUrl
|
||||
// from the FileContext stub.
|
||||
updateStirlingFileStub(file.id as FileId, {
|
||||
thumbnailUrl: thumbnail,
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn("Failed to persist thumbnail:", error);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("Failed to generate thumbnail for file", file.name, error);
|
||||
if (!cancelled) setThumb(null);
|
||||
} finally {
|
||||
if (!cancelled) setGenerating(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +89,11 @@ export function useIndexedDBThumbnail(
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [file, file?.thumbnailUrl, file?.id, indexedDB, generating]);
|
||||
// `generating` is intentionally NOT in the deps — it's an internal flag
|
||||
// set by this effect, and including it caused the effect to cancel
|
||||
// itself mid-flight (orphaning the render and leaving generating=true
|
||||
// stuck forever).
|
||||
}, [file, file?.thumbnailUrl, file?.id, indexedDB, updateStirlingFileStub]);
|
||||
|
||||
return { thumbnail: thumb, isGenerating: generating };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user