feat: enhance thumbnail generation in media scanning process

- Added error handling for thumbnail generation, providing fallback thumbnails for videos and photos if generation fails.
- Updated database insertion logic to reflect the final thumbnail URL used, improving media management reliability.
This commit is contained in:
tigeren 2025-08-25 16:55:22 +00:00
parent 50deee7f2a
commit 5014434717
53 changed files with 31 additions and 5 deletions

BIN
media.db

Binary file not shown.

View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="320" height="240" viewBox="0 0 320 240" fill="none">
<rect width="320" height="240" fill="#1f2937"/>
<rect x="90" y="80" width="140" height="80" rx="4" stroke="#6b7280" stroke-width="2" fill="none"/>
<circle cx="160" cy="120" r="25" stroke="#6b7280" stroke-width="2" fill="none"/>
<circle cx="160" cy="120" r="12" stroke="#6b7280" stroke-width="1" fill="none"/>
<text x="160" y="180" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#9ca3af">Photo</text>
</svg>

After

Width:  |  Height:  |  Size: 543 B

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="320" height="240" viewBox="0 0 320 240" fill="none">
<rect width="320" height="240" fill="#1f2937"/>
<circle cx="160" cy="120" r="40" stroke="#6b7280" stroke-width="2" fill="none"/>
<polygon points="140,100 180,120 140,140" fill="#6b7280"/>
<text x="160" y="180" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#9ca3af">Video</text>
</svg>

After

Width:  |  Height:  |  Size: 420 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -70,10 +70,21 @@ const scanLibrary = async (library: { id: number; path: string }) => {
fs.mkdirSync(thumbnailsDir, { recursive: true }); fs.mkdirSync(thumbnailsDir, { recursive: true });
} }
if (isVideo) { let finalThumbnailUrl = thumbnailUrl;
await generateVideoThumbnail(file, thumbnailPath); let thumbnailGenerated = false;
} else if (isPhoto) {
await generatePhotoThumbnail(file, thumbnailPath); try {
if (isVideo) {
await generateVideoThumbnail(file, thumbnailPath);
thumbnailGenerated = true;
} else if (isPhoto) {
await generatePhotoThumbnail(file, thumbnailPath);
thumbnailGenerated = true;
}
} catch (thumbnailError) {
console.warn(`Thumbnail generation failed for ${file}:`, thumbnailError);
// Use fallback thumbnail based on media type
finalThumbnailUrl = isVideo ? "/placeholder-video.svg" : "/placeholder-photo.svg";
} }
const media = { const media = {
@ -82,12 +93,14 @@ const scanLibrary = async (library: { id: number; path: string }) => {
type: mediaType, type: mediaType,
title: title, title: title,
size: stats.size, size: stats.size,
thumbnail: thumbnailUrl, thumbnail: finalThumbnailUrl,
}; };
db.prepare( db.prepare(
"INSERT INTO media (library_id, path, type, title, size, thumbnail) VALUES (?, ?, ?, ?, ?, ?)" "INSERT INTO media (library_id, path, type, title, size, thumbnail) VALUES (?, ?, ?, ?, ?, ?)"
).run(media.library_id, media.path, media.type, media.title, media.size, media.thumbnail); ).run(media.library_id, media.path, media.type, media.title, media.size, media.thumbnail);
console.log(`Successfully inserted ${mediaType}: ${title}${thumbnailGenerated ? ' with thumbnail' : ' with fallback thumbnail'}`);
} catch (error: any) { } catch (error: any) {
if (error.code !== "SQLITE_CONSTRAINT_UNIQUE") { if (error.code !== "SQLITE_CONSTRAINT_UNIQUE") {
console.error(`Error inserting media: ${file}`, error); console.error(`Error inserting media: ${file}`, error);