mirror of
https://github.com/diced/zipline.git
synced 2025-12-05 20:40:12 -08:00
fix: thumbnail generation (better now)
This commit is contained in:
@@ -51,7 +51,7 @@
|
||||
"fast-glob": "^3.3.2",
|
||||
"fastify": "^4.26.2",
|
||||
"fastify-plugin": "^4.5.1",
|
||||
"ffmpeg-static": "^5.2.0",
|
||||
"fluent-ffmpeg": "^2.1.3",
|
||||
"highlight.js": "^11.9.0",
|
||||
"isomorphic-dompurify": "^1.11.0",
|
||||
"katex": "^0.16.9",
|
||||
@@ -75,6 +75,7 @@
|
||||
"devDependencies": {
|
||||
"@types/bytes": "^3.1.4",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/fluent-ffmpeg": "^2.1.24",
|
||||
"@types/katex": "^0.16.7",
|
||||
"@types/ms": "^0.7.34",
|
||||
"@types/multer": "^1.4.11",
|
||||
|
||||
95
pnpm-lock.yaml
generated
95
pnpm-lock.yaml
generated
@@ -101,9 +101,9 @@ importers:
|
||||
fastify-plugin:
|
||||
specifier: ^4.5.1
|
||||
version: 4.5.1
|
||||
ffmpeg-static:
|
||||
specifier: ^5.2.0
|
||||
version: 5.2.0
|
||||
fluent-ffmpeg:
|
||||
specifier: ^2.1.3
|
||||
version: 2.1.3
|
||||
highlight.js:
|
||||
specifier: ^11.9.0
|
||||
version: 11.9.0
|
||||
@@ -168,6 +168,9 @@ importers:
|
||||
'@types/express':
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
'@types/fluent-ffmpeg':
|
||||
specifier: ^2.1.24
|
||||
version: 2.1.24
|
||||
'@types/katex':
|
||||
specifier: ^0.16.7
|
||||
version: 0.16.7
|
||||
@@ -499,10 +502,6 @@ packages:
|
||||
resolution: {integrity: sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@derhuerst/http-basic@8.2.4':
|
||||
resolution: {integrity: sha512-F9rL9k9Xjf5blCz8HsJRO4diy111cayL2vkY2XE4r4t3n0yPXVYy3KD3nJ1qbrSn9743UWSXH4IwuCa/HWlGFw==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
'@esbuild/aix-ppc64@0.19.12':
|
||||
resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -1158,6 +1157,9 @@ packages:
|
||||
'@types/express@4.17.21':
|
||||
resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
|
||||
|
||||
'@types/fluent-ffmpeg@2.1.24':
|
||||
resolution: {integrity: sha512-g5oQO8Jgi2kFS3tTub7wLvfLztr1s8tdXmRd8PiL/hLMLzTIAyMR2sANkTggM/rdEDAg3d63nYRRVepwBiCw5A==}
|
||||
|
||||
'@types/geojson@7946.0.13':
|
||||
resolution: {integrity: sha512-bmrNrgKMOhM3WsafmbGmC+6dsF2Z308vLFsQ3a/bT8X8Sv5clVYpPars/UPq+sAaJP+5OoLAYgwbkS5QEJdLUQ==}
|
||||
|
||||
@@ -1191,9 +1193,6 @@ packages:
|
||||
'@types/multer@1.4.11':
|
||||
resolution: {integrity: sha512-svK240gr6LVWvv3YGyhLlA+6LRRWA4mnGIU7RcNmgjBYFl6665wcXrRfxGp5tEPVHUNm5FMcmq7too9bxCwX/w==}
|
||||
|
||||
'@types/node@10.17.60':
|
||||
resolution: {integrity: sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==}
|
||||
|
||||
'@types/node@17.0.45':
|
||||
resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==}
|
||||
|
||||
@@ -1490,6 +1489,9 @@ packages:
|
||||
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
async@0.2.10:
|
||||
resolution: {integrity: sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==}
|
||||
|
||||
async@3.2.5:
|
||||
resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==}
|
||||
|
||||
@@ -1633,9 +1635,6 @@ packages:
|
||||
caniuse-lite@1.0.30001565:
|
||||
resolution: {integrity: sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==}
|
||||
|
||||
caseless@0.12.0:
|
||||
resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
|
||||
|
||||
ccount@2.0.1:
|
||||
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
||||
|
||||
@@ -1773,10 +1772,6 @@ packages:
|
||||
resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==}
|
||||
engines: {'0': node >= 0.8}
|
||||
|
||||
concat-stream@2.0.0:
|
||||
resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==}
|
||||
engines: {'0': node >= 6.0}
|
||||
|
||||
console-control-strings@1.1.0:
|
||||
resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==}
|
||||
|
||||
@@ -2339,10 +2334,6 @@ packages:
|
||||
fecha@4.2.3:
|
||||
resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==}
|
||||
|
||||
ffmpeg-static@5.2.0:
|
||||
resolution: {integrity: sha512-WrM7kLW+do9HLr+H6tk7LzQ7kPqbAgLjdzNE32+u3Ff11gXt9Kkkd2nusGFrlWMIe+XaA97t+I8JS7sZIrvRgA==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
file-entry-cache@6.0.1:
|
||||
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
|
||||
engines: {node: ^10.12.0 || >=12.0.0}
|
||||
@@ -2382,6 +2373,10 @@ packages:
|
||||
flatted@3.2.9:
|
||||
resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==}
|
||||
|
||||
fluent-ffmpeg@2.1.3:
|
||||
resolution: {integrity: sha512-Be3narBNt2s6bsaqP6Jzq91heDgOEaDCJAXcE3qcma/EJBSy5FB4cvO31XBInuAuKBx8Kptf8dkhjK0IOru39Q==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
fmin@0.0.2:
|
||||
resolution: {integrity: sha512-sSi6DzInhl9d8yqssDfGZejChO8d2bAGIpysPsvYsxFe898z89XhCZg6CPNV3nhUhFefeC/AXZK2bAJxlBjN6A==}
|
||||
|
||||
@@ -2603,9 +2598,6 @@ packages:
|
||||
resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
http-response-object@3.0.2:
|
||||
resolution: {integrity: sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==}
|
||||
|
||||
https-proxy-agent@5.0.1:
|
||||
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
|
||||
engines: {node: '>= 6'}
|
||||
@@ -3637,9 +3629,6 @@ packages:
|
||||
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
parse-cache-control@1.0.1:
|
||||
resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==}
|
||||
|
||||
parse-json@5.2.0:
|
||||
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -4859,6 +4848,10 @@ packages:
|
||||
resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
which@1.3.1:
|
||||
resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
|
||||
hasBin: true
|
||||
|
||||
which@2.0.2:
|
||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||
engines: {node: '>= 8'}
|
||||
@@ -5418,13 +5411,6 @@ snapshots:
|
||||
'@babel/helper-validator-identifier': 7.22.20
|
||||
to-fast-properties: 2.0.0
|
||||
|
||||
'@derhuerst/http-basic@8.2.4':
|
||||
dependencies:
|
||||
caseless: 0.12.0
|
||||
concat-stream: 2.0.0
|
||||
http-response-object: 3.0.2
|
||||
parse-cache-control: 1.0.1
|
||||
|
||||
'@esbuild/aix-ppc64@0.19.12':
|
||||
optional: true
|
||||
|
||||
@@ -6094,6 +6080,10 @@ snapshots:
|
||||
'@types/qs': 6.9.10
|
||||
'@types/serve-static': 1.15.5
|
||||
|
||||
'@types/fluent-ffmpeg@2.1.24':
|
||||
dependencies:
|
||||
'@types/node': 20.10.1
|
||||
|
||||
'@types/geojson@7946.0.13': {}
|
||||
|
||||
'@types/hast@2.3.8':
|
||||
@@ -6122,8 +6112,6 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/express': 4.17.21
|
||||
|
||||
'@types/node@10.17.60': {}
|
||||
|
||||
'@types/node@17.0.45': {}
|
||||
|
||||
'@types/node@20.10.1':
|
||||
@@ -6482,6 +6470,8 @@ snapshots:
|
||||
|
||||
astral-regex@2.0.0: {}
|
||||
|
||||
async@0.2.10: {}
|
||||
|
||||
async@3.2.5: {}
|
||||
|
||||
asynciterator.prototype@1.0.0:
|
||||
@@ -6627,8 +6617,6 @@ snapshots:
|
||||
|
||||
caniuse-lite@1.0.30001565: {}
|
||||
|
||||
caseless@0.12.0: {}
|
||||
|
||||
ccount@2.0.1: {}
|
||||
|
||||
center-align@0.1.3:
|
||||
@@ -6775,13 +6763,6 @@ snapshots:
|
||||
readable-stream: 2.3.8
|
||||
typedarray: 0.0.6
|
||||
|
||||
concat-stream@2.0.0:
|
||||
dependencies:
|
||||
buffer-from: 1.1.2
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.2
|
||||
typedarray: 0.0.6
|
||||
|
||||
console-control-strings@1.1.0: {}
|
||||
|
||||
content-disposition@0.5.4:
|
||||
@@ -7521,15 +7502,6 @@ snapshots:
|
||||
|
||||
fecha@4.2.3: {}
|
||||
|
||||
ffmpeg-static@5.2.0:
|
||||
dependencies:
|
||||
'@derhuerst/http-basic': 8.2.4
|
||||
env-paths: 2.2.1
|
||||
https-proxy-agent: 5.0.1
|
||||
progress: 2.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
file-entry-cache@6.0.1:
|
||||
dependencies:
|
||||
flat-cache: 3.2.0
|
||||
@@ -7584,6 +7556,11 @@ snapshots:
|
||||
|
||||
flatted@3.2.9: {}
|
||||
|
||||
fluent-ffmpeg@2.1.3:
|
||||
dependencies:
|
||||
async: 0.2.10
|
||||
which: 1.3.1
|
||||
|
||||
fmin@0.0.2:
|
||||
dependencies:
|
||||
contour_plot: 0.0.1
|
||||
@@ -7828,10 +7805,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
http-response-object@3.0.2:
|
||||
dependencies:
|
||||
'@types/node': 10.17.60
|
||||
|
||||
https-proxy-agent@5.0.1:
|
||||
dependencies:
|
||||
agent-base: 6.0.2
|
||||
@@ -9021,8 +8994,6 @@ snapshots:
|
||||
dependencies:
|
||||
callsites: 3.1.0
|
||||
|
||||
parse-cache-control@1.0.1: {}
|
||||
|
||||
parse-json@5.2.0:
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.23.5
|
||||
@@ -10360,6 +10331,10 @@ snapshots:
|
||||
gopd: 1.0.1
|
||||
has-tostringtag: 1.0.0
|
||||
|
||||
which@1.3.1:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
||||
which@2.0.2:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
||||
@@ -139,8 +139,6 @@ export async function uploadPartialFiles(
|
||||
() => {
|
||||
const res: Response['/api/upload'] = JSON.parse(req.responseText);
|
||||
|
||||
console.log(res);
|
||||
|
||||
if ((res as ErrorBody).message) {
|
||||
notifications.update({
|
||||
id: 'upload-partial',
|
||||
|
||||
@@ -3,9 +3,8 @@ import { config } from '@/lib/config';
|
||||
import { datasource } from '@/lib/datasource';
|
||||
import { prisma } from '@/lib/db';
|
||||
import { log } from '@/lib/logger';
|
||||
import { spawn } from 'child_process';
|
||||
import ffmpegPath from 'ffmpeg-static';
|
||||
import { createWriteStream } from 'fs';
|
||||
import ffmpeg from 'fluent-ffmpeg';
|
||||
import { createWriteStream, readFileSync, unlinkSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { isMainThread, parentPort, workerData } from 'worker_threads';
|
||||
|
||||
@@ -30,43 +29,31 @@ if (!enabled) {
|
||||
|
||||
logger.debug('started thumbnail worker');
|
||||
|
||||
async function ffmpeg(file: string): Promise<Buffer | undefined> {
|
||||
const args = ['-i', file, '-frames:v', '1', '-f', 'mjpeg', 'pipe:1'];
|
||||
function genThumbnail(file: string, thumbnailTmp: string): Promise<Buffer | undefined> {
|
||||
return new Promise((resolve, reject) => {
|
||||
ffmpeg(file)
|
||||
.videoFilters('thumbnail')
|
||||
.frames(1)
|
||||
.format('mjpeg')
|
||||
.output(thumbnailTmp)
|
||||
.on('start', (cmd) => {
|
||||
logger.debug('generating thumbnail', { cmd });
|
||||
})
|
||||
.on('error', (err) => {
|
||||
logger.error('failed to generate thumbnail', { err: err.message });
|
||||
reject(err);
|
||||
})
|
||||
.on('end', () => {
|
||||
const buffer = readFileSync(thumbnailTmp);
|
||||
|
||||
const proc = spawn(ffmpegPath!, args, {
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
unlinkSync(thumbnailTmp);
|
||||
unlinkSync(file);
|
||||
logger.debug('removed temporary files', { file, thumbnail: thumbnailTmp });
|
||||
|
||||
resolve(buffer);
|
||||
})
|
||||
.run();
|
||||
});
|
||||
|
||||
try {
|
||||
const buffer = await new Promise<Buffer>((resolve, reject) => {
|
||||
const data: Buffer[] = [];
|
||||
|
||||
proc.stdout!.on('data', (d) => {
|
||||
data.push(d);
|
||||
});
|
||||
|
||||
proc.once('error', reject);
|
||||
|
||||
proc.once('close', (code) => {
|
||||
if (code !== 0) {
|
||||
const stringed = Buffer.concat([...data]).toString();
|
||||
|
||||
logger.error('ffmpeg exited with non-zero code');
|
||||
|
||||
reject(stringed);
|
||||
} else {
|
||||
resolve(Buffer.concat([...data]));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return buffer;
|
||||
} catch (e) {
|
||||
logger.error('failed to generate thumbnail', {
|
||||
file,
|
||||
error: e,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function generate(ids: string[]) {
|
||||
@@ -103,7 +90,8 @@ async function generate(ids: string[]) {
|
||||
writeStream.on('finish', resolve);
|
||||
});
|
||||
|
||||
const thumbnail = await ffmpeg(tmpFile);
|
||||
const thumbnailTmpFile = join(config.core.tempDirectory, `zthumbnail_${file.id}.jpg`);
|
||||
const thumbnail = await genThumbnail(tmpFile, thumbnailTmpFile);
|
||||
if (!thumbnail) return;
|
||||
|
||||
await datasource.put(`.thumbnail.${file.id}.jpg`, thumbnail);
|
||||
|
||||
Reference in New Issue
Block a user