actually run ffmpeg fr fr
This commit is contained in:
parent
2320091125
commit
502786b689
3 changed files with 59 additions and 22 deletions
|
@ -74,7 +74,7 @@ export class Queue<T, R> {
|
||||||
addReturn(args: T) {
|
addReturn(args: T) {
|
||||||
this.#total += 1;
|
this.#total += 1;
|
||||||
this.updateTotal();
|
this.updateTotal();
|
||||||
if (this.#active.length > this.#maxJobs) {
|
if (this.#active.length >= this.#maxJobs) {
|
||||||
const { promise, resolve, reject } = Promise.withResolvers<R>();
|
const { promise, resolve, reject } = Promise.withResolvers<R>();
|
||||||
this.#queue.push([args, resolve, reject]);
|
this.#queue.push([args, resolve, reject]);
|
||||||
return promise;
|
return promise;
|
||||||
|
|
|
@ -136,7 +136,7 @@ export async function main() {
|
||||||
},
|
},
|
||||||
getItemText: ({ mediaFile, processor }) =>
|
getItemText: ({ mediaFile, processor }) =>
|
||||||
`${mediaFile.path.slice(1)} - ${processor.name}`,
|
`${mediaFile.path.slice(1)} - ${processor.name}`,
|
||||||
maxJobs: 2,
|
maxJobs: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
function decodeProcessors(input: string) {
|
function decodeProcessors(input: string) {
|
||||||
|
@ -430,46 +430,79 @@ const procImageSubsets: Process = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const qualityMap: Record<string, string> = {
|
||||||
const procVideos = transcodeRules.videoFormats.map((preset) => ({
|
u: "ultra-high",
|
||||||
name: "encode image subsets",
|
h: "high",
|
||||||
include: rules.extsImage,
|
m: "medium",
|
||||||
|
l: "low",
|
||||||
|
d: "data-saving",
|
||||||
|
};
|
||||||
|
const procVideos = transcodeRules.videoFormats.map<Process>((preset) => ({
|
||||||
|
name: `encode ${preset.codec} ${UNWRAP(qualityMap[preset.id[1]])}`,
|
||||||
|
include: rules.extsVideo,
|
||||||
enable: ffmpegBin != null,
|
enable: ffmpegBin != null,
|
||||||
async run({ absPath, mediaFile, stat, spin }) {
|
async run({ absPath, mediaFile, spin }) {
|
||||||
await produceAsset(`${mediaFile}/${preset.id}`, async (base) => {
|
await produceAsset(`${mediaFile.hash}/${preset.id}`, async (base) => {
|
||||||
base = path.dirname(base);
|
base = path.dirname(base);
|
||||||
|
await fs.mkdir(base);
|
||||||
|
|
||||||
|
let inputArgs = ["-i", absPath];
|
||||||
|
try {
|
||||||
|
const config = await fs.readJson<any>(
|
||||||
|
path.join(
|
||||||
|
path.dirname(absPath),
|
||||||
|
path.basename(absPath, path.extname(absPath)) + ".json",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (config.encoder && typeof config.encoder.videoSrc === "string") {
|
||||||
|
const { videoSrc, audioSrc, rate } = config.encoder;
|
||||||
|
inputArgs = [
|
||||||
|
...rate ? ["-r", String(rate)] : [],
|
||||||
|
"-i",
|
||||||
|
videoSrc,
|
||||||
|
...audioSrc ? ["-i", audioSrc] : [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
if (err?.code !== "ENOENT") throw err;
|
||||||
|
}
|
||||||
|
|
||||||
const args = transcodeRules.getVideoArgs(
|
const args = transcodeRules.getVideoArgs(
|
||||||
preset,
|
preset,
|
||||||
base,
|
base,
|
||||||
["-i", absPath],
|
inputArgs,
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
const quality = {
|
const fakeProgress = new Progress({ text: spin.text, spinner: null });
|
||||||
u: "ultra-high",
|
fakeProgress.stop();
|
||||||
h: "high",
|
spin.format = (now: number) => fakeProgress.format(now);
|
||||||
m: "medium",
|
// @ts-expect-error
|
||||||
l: "low",
|
fakeProgress.redraw = () => spin.redraw();
|
||||||
d: "data-saving",
|
|
||||||
}[preset.id[1]] ?? preset.id;
|
|
||||||
await ffmpeg.spawn({
|
await ffmpeg.spawn({
|
||||||
ffmpeg: ffmpegBin!,
|
ffmpeg: ffmpegBin!,
|
||||||
title: `${mediaFile.path.slice(1)} (${preset.codec} ${quality})`,
|
title: fakeProgress.text,
|
||||||
|
progress: fakeProgress,
|
||||||
args,
|
args,
|
||||||
});
|
});
|
||||||
return await collectFiles();
|
return await collectFiles();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
for (const file of await collectFiles()) {
|
for (const file of await collectFiles()) {
|
||||||
// TODO: delete assets off disk
|
try {
|
||||||
|
fs.rm(file);
|
||||||
|
} catch {}
|
||||||
}
|
}
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function collectFiles(): Promise<string[]> {
|
async function collectFiles(): Promise<string[]> {
|
||||||
throw new Error("!");
|
return (await fs.readdir(base))
|
||||||
|
.filter((basename) => basename.startsWith(preset.id))
|
||||||
|
.map((basename) => path.join(base, basename));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
} satisfies Process));
|
}));
|
||||||
|
|
||||||
const processors = [
|
const processors = [
|
||||||
procDimensions,
|
procDimensions,
|
||||||
|
@ -596,6 +629,7 @@ export function testProgram(name: string, helpArgument: string) {
|
||||||
|
|
||||||
const monthMilliseconds = 30 * 24 * 60 * 60 * 1000;
|
const monthMilliseconds = 30 * 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
|
import { Progress } from "@paperclover/console/Progress";
|
||||||
import { Spinner } from "@paperclover/console/Spinner";
|
import { Spinner } from "@paperclover/console/Spinner";
|
||||||
import * as async from "#sitegen/async";
|
import * as async from "#sitegen/async";
|
||||||
import * as fs from "#sitegen/fs";
|
import * as fs from "#sitegen/fs";
|
||||||
|
|
|
@ -23,13 +23,15 @@ export interface SpawnOptions {
|
||||||
title: string;
|
title: string;
|
||||||
ffmpeg?: string;
|
ffmpeg?: string;
|
||||||
progress?: Progress;
|
progress?: Progress;
|
||||||
|
cwd: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function spawn(options: SpawnOptions) {
|
export async function spawn(options: SpawnOptions) {
|
||||||
const { ffmpeg = "ffmpeg", args, title } = options;
|
const { ffmpeg = "ffmpeg", args, title, cwd } = options;
|
||||||
const proc = child_process.spawn(ffmpeg, args, {
|
const proc = child_process.spawn(ffmpeg, args, {
|
||||||
stdio: ["ignore", "inherit", "pipe"],
|
stdio: ["ignore", "inherit", "pipe"],
|
||||||
env: { ...process.env, SVT_LOG: "2" },
|
env: { ...process.env, SVT_LOG: "2" },
|
||||||
|
cwd,
|
||||||
});
|
});
|
||||||
const parser = new Parse();
|
const parser = new Parse();
|
||||||
const bar = options.progress ?? new Progress({ text: title });
|
const bar = options.progress ?? new Progress({ text: title });
|
||||||
|
@ -63,8 +65,10 @@ export async function spawn(options: SpawnOptions) {
|
||||||
e.args = [ffmpeg, ...args].join(" ");
|
e.args = [ffmpeg, ...args].join(" ");
|
||||||
e.code = code;
|
e.code = code;
|
||||||
e.signal = signal;
|
e.signal = signal;
|
||||||
|
bar.error(e.message);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
bar.success(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Parse {
|
export class Parse {
|
||||||
|
@ -158,4 +162,3 @@ import * as process from "node:process";
|
||||||
import events from "node:events";
|
import events from "node:events";
|
||||||
import * as path from "node:path";
|
import * as path from "node:path";
|
||||||
import { Progress } from "@paperclover/console/Progress";
|
import { Progress } from "@paperclover/console/Progress";
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue