Changeset 4d1aefb in Klonkt
- Timestamp:
- 06/30/2026 03:16:22 PM (2 months ago)
- Branches:
- main
- Children:
- 28bf7f0
- Parents:
- 98a1990
- File:
-
- 1 edited
-
src/services/ThumbnailService.js (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/ThumbnailService.js
r98a1990 r4d1aefb 65 65 } 66 66 67 // Is the source an animated image (animated WebP or GIF)? If so the thumbnail must keep ALL 68 // frames (a downscaled animated WebP) instead of grabbing a single frame — otherwise an 69 // animated cover shows up frozen on the site. 70 function isAnimatedSrc(filePath) { 71 try { 72 const ext = path.extname(filePath).toLowerCase(); 73 if (ext === '.gif') return true; // a flattened GIF would lose its animation too 74 if (ext !== '.webp') return false; 75 const fd = fs.openSync(filePath, 'r'); 76 try { 77 const buf = Buffer.alloc(40); 78 const n = fs.readSync(fd, buf, 0, 40, 0); 79 // RIFF…WEBP, then a VP8X chunk (bytes 12-15) whose flags byte (20) has the animation bit. 80 return n >= 21 && buf.toString('ascii', 12, 16) === 'VP8X' && (buf[20] & 0x02) !== 0; 81 } finally { fs.closeSync(fd); } 82 } catch { return false; } 83 } 84 67 85 /** 68 86 * Return the on-disk path of the cached thumbnail, generating it if needed. … … 78 96 const cached = path.join(root, '.thumbs', String(width), rel) + '.webp'; 79 97 if (fs.existsSync(cached)) return cached; 98 99 // ffmpeg-static can't decode an animated WebP ("image data not found"), so we can't make a 100 // scaled animated thumbnail. Return null → the route serves the ORIGINAL instead, which keeps 101 // animating. (Animated covers are usually already small, so skipping the downscale is fine.) 102 if (isAnimatedSrc(orig)) return null; 80 103 81 104 await fs.promises.mkdir(path.dirname(cached), { recursive: true });
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)