/** * Recodifica um vídeo para a vitrine animada, em que o tempo do vídeo muda a cada quadro da rolagem. * Para a busca ser instantânea o vídeo precisa de um quadro-chave a cada 6 quadros e nenhum B-frame; o tamanho * de cada arquivo fica em até 3 MB (sobe o CRF e, se preciso, reduz a imagem até caber). * * ffmpeg-static não é dependência do site: instale-o numa pasta temporária e rode o script a partir dela * (as dependências são resolvidas a partir da pasta onde o comando foi executado): * * mkdir rec && cd rec && npm init -y && npm i ffmpeg-static * node /scripts/encode-scrub-video.mjs --in desktop-original.mp4 --out /public/videos//scrub-desktop.mp4 --size 1120x700 * * Só existe o scrub do computador: o celular da moldura mostra o pôster, sem vídeo. * * Use como entrada o vídeo de melhor qualidade que existir (a entrada de record-project-videos.mjs antes do corte * para MP4/WebM), não os MP4 já comprimidos de public/videos. * * A capa de compartilhamento (og.jpg, 1200x630) sai do poster desktop: * ffmpeg -i public/videos//desktop.webp -vf "scale=1200:750:flags=lanczos,crop=1200:630:0:0" -q:v 4 public/videos//og.jpg */ import { spawnSync } from "node:child_process"; import { statSync } from "node:fs"; import { createRequire } from "node:module"; import { join } from "node:path"; const require = createRequire(join(process.cwd(), "noop.js")); const ffmpegPath = require("ffmpeg-static"); const args = Object.fromEntries( process.argv.slice(2).reduce((acc, cur, i, all) => { if (cur.startsWith("--")) acc.push([cur.slice(2), all[i + 1]]); return acc; }, []), ); const { in: input, out: output } = args; const [width, height] = (args.size ?? "1120x700").split("x").map(Number); const MAX_BYTES = Number(args["max-mb"] ?? 3) * 1024 * 1024; if (!input || !output || !width || !height) { console.error( "uso: --in