SPB Git

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%
2.1 KB · 52 lines javascript
Raw Blame History
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