| ... | @@ -136,7 +136,7 @@ export async function main() { | ... | @@ -136,7 +136,7 @@ export async function main() { |
| 136 | },
| 136 | },
|
| 137 | getItemText: ({ mediaFile, processor }) =>
| 137 | getItemText: ({ mediaFile, processor }) =>
|
| 138 | `${mediaFile.path.slice(1)} - ${processor.name}`,
| 138 | `${mediaFile.path.slice(1)} - ${processor.name}`,
|
| 139 | maxJobs: 2,
| 139 | maxJobs: 1,
|
| 140 | });
| 140 | });
|
| 141 |
| 141 |
|
| 142 | function decodeProcessors(input: string) {
| 142 | function decodeProcessors(input: string) {
|
| ... | @@ -430,46 +430,79 @@ const procImageSubsets: Process = { | ... | @@ -430,46 +430,79 @@ const procImageSubsets: Process = { |
| 430 | }
| 430 | }
|
| 431 | },
| 431 | },
|
| 432 | };
| 432 | };
|
| 433 |
| 433 | const qualityMap: Record<string, string> = {
|
| 434 | const procVideos = transcodeRules.videoFormats.map((preset) => ({
| 434 | u: "ultra-high",
|
| 435 | name: "encode image subsets",
| 435 | h: "high",
|
| 436 | include: rules.extsImage,
| 436 | m: "medium",
|
| | 437 | l: "low",
|
| | 438 | d: "data-saving",
|
| | 439 | };
|
| | 440 | const procVideos = transcodeRules.videoFormats.map<Process>((preset) => ({
|
| | 441 | name: `encode ${preset.codec} ${UNWRAP(qualityMap[preset.id[1]])}`,
|
| | 442 | include: rules.extsVideo,
|
| 437 | enable: ffmpegBin != null,
| 443 | enable: ffmpegBin != null,
|
| 438 | async run({ absPath, mediaFile, stat, spin }) {
| 444 | async run({ absPath, mediaFile, spin }) {
|
| 439 | await produceAsset(`${mediaFile}/${preset.id}`, async (base) => {
| 445 | await produceAsset(`${mediaFile.hash}/${preset.id}`, async (base) => {
|
| 440 | base = path.dirname(base);
| 446 | base = path.dirname(base);
|
| | 447 | await fs.mkdir(base);
|
| | 448 |
|
| | 449 | let inputArgs = ["-i", absPath];
|
| | 450 | try {
|
| | 451 | const config = await fs.readJson<any>(
|
| | 452 | path.join(
|
| | 453 | path.dirname(absPath),
|
| | 454 | path.basename(absPath, path.extname(absPath)) + ".json",
|
| | 455 | ),
|
| | 456 | );
|
| | 457 | if (config.encoder && typeof config.encoder.videoSrc === "string") {
|
| | 458 | const { videoSrc, audioSrc, rate } = config.encoder;
|
| | 459 | inputArgs = [
|
| | 460 | ...rate ? ["-r", String(rate)] : [],
|
| | 461 | "-i",
|
| | 462 | videoSrc,
|
| | 463 | ...audioSrc ? ["-i", audioSrc] : [],
|
| | 464 | ];
|
| | 465 | }
|
| | 466 | } catch (err: any) {
|
| | 467 | if (err?.code !== "ENOENT") throw err;
|
| | 468 | }
|
| | 469 |
|
| 441 | const args = transcodeRules.getVideoArgs(
| 470 | const args = transcodeRules.getVideoArgs(
|
| 442 | preset,
| 471 | preset,
|
| 443 | base,
| 472 | base,
|
| 444 | ["-i", absPath],
| 473 | inputArgs,
|
| 445 | );
| 474 | );
|
| 446 | try {
| 475 | try {
|
| 447 | const quality = {
| 476 | const fakeProgress = new Progress({ text: spin.text, spinner: null });
|
| 448 | u: "ultra-high",
| 477 | fakeProgress.stop();
|
| 449 | h: "high",
| 478 | spin.format = (now: number) => fakeProgress.format(now);
|
| 450 | m: "medium",
| 479 | // @ts-expect-error
|
| 451 | l: "low",
| 480 | fakeProgress.redraw = () => spin.redraw();
|
| 452 | d: "data-saving",
| 481 |
|
| 453 | }[preset.id[1]] ?? preset.id;
| | |
| 454 | await ffmpeg.spawn({
| 482 | await ffmpeg.spawn({
|
| 455 | ffmpeg: ffmpegBin!,
| 483 | ffmpeg: ffmpegBin!,
|
| 456 | title: `${mediaFile.path.slice(1)} (${preset.codec} ${quality})`,
| 484 | title: fakeProgress.text,
|
| | 485 | progress: fakeProgress,
|
| 457 | args,
| 486 | args,
|
| 458 | });
| 487 | });
|
| 459 | return await collectFiles();
| 488 | return await collectFiles();
|
| 460 | } catch (err) {
| 489 | } catch (err) {
|
| 461 | for (const file of await collectFiles()) {
| 490 | for (const file of await collectFiles()) {
|
| 462 | // TODO: delete assets off disk
| 491 | try {
|
| | 492 | fs.rm(file);
|
| | 493 | } catch {}
|
| 463 | }
| 494 | }
|
| 464 | throw err;
| 495 | throw err;
|
| 465 | }
| 496 | }
|
| 466 |
| 497 |
|
| 467 | async function collectFiles(): Promise<string[]> {
| 498 | async function collectFiles(): Promise<string[]> {
|
| 468 | throw new Error("!");
| 499 | return (await fs.readdir(base))
|
| | 500 | .filter((basename) => basename.startsWith(preset.id))
|
| | 501 | .map((basename) => path.join(base, basename));
|
| 469 | }
| 502 | }
|
| 470 | });
| 503 | });
|
| 471 | },
| 504 | },
|
| 472 | } satisfies Process));
| 505 | }));
|
| 473 |
| 506 |
|
| 474 | const processors = [
| 507 | const processors = [
|
| 475 | procDimensions,
| 508 | procDimensions,
|
| ... | @@ -596,6 +629,7 @@ export function testProgram(name: string, helpArgument: string) { | ... | @@ -596,6 +629,7 @@ export function testProgram(name: string, helpArgument: string) { |
| 596 |
| 629 |
|
| 597 | const monthMilliseconds = 30 * 24 * 60 * 60 * 1000;
| 630 | const monthMilliseconds = 30 * 24 * 60 * 60 * 1000;
|
| 598 |
| 631 |
|
| | 632 | import { Progress } from "@paperclover/console/Progress";
|
| 599 | import { Spinner } from "@paperclover/console/Spinner";
| 633 | import { Spinner } from "@paperclover/console/Spinner";
|
| 600 | import * as async from "#sitegen/async";
| 634 | import * as async from "#sitegen/async";
|
| 601 | import * as fs from "#sitegen/fs";
| 635 | import * as fs from "#sitegen/fs";
|