spb/drive Public
SPB Drive — self-hosted personal cloud drive (files, previews, sharing) on the MacLustr cluster.
JavaScript 82.7%
CSS 10.6%
Nunjucks 3.6%
Shell 1.8%
SQL 1.3%
1/**2 * ─────────────────────────────────────────────3 * SPB Drive — Personal Cloud Drive4 * ─────────────────────────────────────────────5 * Author : Simon-Pierre Boucher6 * Contact : contact@spboucher.ai7 * File : src/preview/office-thumb.mjs8 * Purpose : Thumbnail page 1 of a LibreOffice-converted PDF from cache9 * License : MIT © Simon-Pierre Boucher10 * ─────────────────────────────────────────────11 */1213import { execFile } from 'node:child_process';14import { existsSync } from 'node:fs';15import { rename, rm } from 'node:fs/promises';16import path from 'node:path';17import { promisify } from 'node:util';18import sharp from 'sharp';19import { config } from '../config.mjs';20import { enqueue } from './queue.mjs';21import { hasBin } from './thumbs.mjs';2223const execFileP = promisify(execFile);2425/** Thumbnail an office doc via its cached converted PDF (webp, cached). */26export async function getThumbFromFile(sha, size = 256) {27 const sz = Number(size) === 512 ? 512 : 256;28 const out = path.join(config.cacheDir, 'thumbs', `${sha}.${sz}.webp`);29 if (existsSync(out)) return out;30 const pdf = path.join(config.cacheDir, 'office', `${sha}.pdf`);31 if (!existsSync(pdf) || !(await hasBin('pdftoppm'))) return null;3233 return enqueue(`thumb:${sha}:${sz}`, async () => {34 if (existsSync(out)) return out;35 const tmpBase = `${out}.tmp-${process.pid}`;36 try {37 await execFileP('pdftoppm', ['-png', '-f', '1', '-l', '1', '-scale-to', String(sz), pdf, tmpBase], {38 timeout: 60_000,39 });40 const png = `${tmpBase}-1.png`;41 if (!existsSync(png)) return null;42 await sharp(png).webp({ quality: 80 }).toFile(`${tmpBase}.webp`);43 await rm(png, { force: true });44 await rename(`${tmpBase}.webp`, out);45 return out;46 } catch {47 await rm(`${tmpBase}.webp`, { force: true });48 return null;49 }50 });51}52