mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 19:33:11 +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 { useIndexedDB } from "@app/contexts/IndexedDBContext";
|
||||||
import { generateThumbnailForFile } from "@app/utils/thumbnailUtils";
|
import { generateThumbnailForFile } from "@app/utils/thumbnailUtils";
|
||||||
import { FileId } from "@app/types/fileContext";
|
import { FileId } from "@app/types/fileContext";
|
||||||
|
import { useFileManagement } from "@app/contexts/FileContext";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for IndexedDB-aware thumbnail loading
|
* Hook for IndexedDB-aware thumbnail loading
|
||||||
@@ -17,6 +18,7 @@ export function useIndexedDBThumbnail(
|
|||||||
const [thumb, setThumb] = useState<string | null>(null);
|
const [thumb, setThumb] = useState<string | null>(null);
|
||||||
const [generating, setGenerating] = useState(false);
|
const [generating, setGenerating] = useState(false);
|
||||||
const indexedDB = useIndexedDB();
|
const indexedDB = useIndexedDB();
|
||||||
|
const { updateStirlingFileStub } = useFileManagement();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
@@ -27,58 +29,59 @@ export function useIndexedDBThumbnail(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First priority: use stored thumbnail
|
// Tier 1: stored thumbnail on the stub.
|
||||||
if (file.thumbnailUrl) {
|
if (file.thumbnailUrl) {
|
||||||
setThumb(file.thumbnailUrl);
|
setThumb(file.thumbnailUrl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second priority: generate thumbnail for files under 100MB
|
// >=100MB files are skipped entirely — no thumbnail.
|
||||||
if (file.size < 100 * 1024 * 1024 && !generating) {
|
if (file.size >= 100 * 1024 * 1024) {
|
||||||
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
|
|
||||||
setThumb(null);
|
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 () => {
|
return () => {
|
||||||
cancelled = true;
|
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 };
|
return { thumbnail: thumb, isGenerating: generating };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user