@poe-platform/safe-bash 0.1.838 → 0.1.840
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mp4-ast/types.d.ts +4 -2
- package/dist/pdf-ast/cos/security.d.ts +10 -0
- package/dist/pdf-ast/edit/retained-attachment-edits.d.ts +4 -0
- package/dist/pdf-ast/edit/retained-graph.d.ts +1 -1
- package/dist/pdf-ast/image.js +1 -1
- package/dist/pdf-ast/index.d.ts +2 -1
- package/dist/pdf-ast/index.js +7 -1
- package/dist/pdf-ast/vendor/pdfjs-fonts.d.mts +8 -0
- package/dist/pdf-ast/vendor/pdfjs-fonts.mjs +28 -0
- package/dist/safe-bash/command-chunks/{chunk-SG2KOOD4.js → chunk-3SAYZFMD.js} +2 -2
- package/dist/safe-bash/command-chunks/{chunk-FH5VMAPS.js → chunk-45ZH6CNF.js} +20 -4
- package/dist/safe-bash/command-chunks/{chunk-T6OXG7QQ.js → chunk-AAOPVEPF.js} +66 -1
- package/dist/safe-bash/command-chunks/{chunk-46GA576V.js → chunk-CPKVUB7S.js} +2 -2
- package/dist/safe-bash/command-chunks/{chunk-MBXNG6C3.js → chunk-DLLN3C3Q.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-ZSQCROFE.js → chunk-DM5T5D2K.js} +5 -1
- package/dist/safe-bash/command-chunks/{chunk-3EAZRKI4.js → chunk-G7HQYFIU.js} +10 -1
- package/dist/safe-bash/command-chunks/{chunk-GYKQ3IOV.js → chunk-LMYQMJYY.js} +94 -18
- package/dist/safe-bash/command-chunks/{chunk-DX7KU6YU.js → chunk-N52AHO6S.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-4BSD2RGK.js → chunk-QPKL5GWH.js} +102 -42
- package/dist/safe-bash/command-chunks/{chunk-Z2T7E4ID.js → chunk-R7QLP5RH.js} +1212 -1119
- package/dist/safe-bash/command-chunks/{chunk-RSFKQE2U.js → chunk-T5WFJ44Z.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-77ROD2TR.js → chunk-X3WNWRVT.js} +11 -5
- package/dist/safe-bash/command-chunks/{chunk-TCXM7BSZ.js → chunk-YFMNXPLP.js} +4 -4
- package/dist/safe-bash/command-chunks/{chunk-DQVOBGI2.js → chunk-YVFQ5I36.js} +7335 -7162
- package/dist/safe-bash-command-exiftool/index.js +25 -1
- package/dist/safe-bash-command-ffmpeg/index.js +174 -41
- package/dist/safe-bash-command-ffprobe/index.js +2 -2
- package/dist/safe-bash-command-ffprobe/media.js +2 -2
- package/dist/safe-bash-command-imagemagick/index.js +504 -111
- package/dist/safe-bash-command-mdq/index.js +2 -0
- package/dist/safe-bash-command-pandoc/citeproc-filters.js +7 -7
- package/dist/safe-bash-command-pandoc/command.js +8 -8
- package/dist/safe-bash-command-pandoc/index.js +51 -51
- package/dist/safe-bash-command-qpdf/index.js +1037 -654
- package/dist/safe-bash-command-qpdf/page-range.d.ts +2 -0
- package/dist/safe-bash-command-soffice/index.js +28 -8
- package/dist/safe-bash-command-sqlite3/btree.d.ts +2 -1
- package/dist/safe-bash-command-sqlite3/engine.d.ts +15 -1
- package/dist/safe-bash-command-sqlite3/index.js +294 -68
- package/dist/safe-bash-command-tar/create.js +2 -2
- package/dist/safe-bash-command-tar/extract.js +2 -2
- package/dist/safe-bash-command-tar/format.js +1 -1
- package/dist/safe-bash-command-tar/index.js +4 -4
- package/dist/safe-bash-command-tar/modes.js +4 -4
- package/dist/safe-bash-command-unzip/index.js +1 -1
- package/dist/safe-bash-command-unzip/unzip.js +1 -1
- package/dist/safe-bash-markdown-engine/commonmark-blocks.d.ts +17 -1
- package/dist/safe-bash-markdown-engine/commonmark-blocks.js +3 -3
- package/dist/safe-bash-markdown-engine/commonmark-inlines.d.ts +1 -1
- package/dist/safe-bash-markdown-engine/commonmark-inlines.js +3 -3
- package/dist/safe-bash-markdown-engine/commonmark-syntax.d.ts +5 -0
- package/dist/safe-bash-markdown-engine/commonmark-syntax.js +5 -1
- package/dist/safe-bash-markdown-engine/gfm-syntax.js +2 -2
- package/dist/safe-bash-markdown-engine/index.js +4 -4
- package/dist/safe-bash-zip-engine/index.js +1 -1
- package/dist/safe-bash-zip-engine/zip/repair.js +1 -1
- package/dist/safe-bash-zip-engine/zip/sfx.js +1 -1
- package/dist/safe-bash-zip-engine/zip-format.d.ts +2 -0
- package/dist/safe-bash-zip-engine/zip-format.js +1 -1
- package/package.json +2 -2
- package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +2 -0
|
@@ -2208,6 +2208,29 @@ function selected(tags, names, duplicates, resources) {
|
|
|
2208
2208
|
}
|
|
2209
2209
|
return values;
|
|
2210
2210
|
}
|
|
2211
|
+
var jpegPrintConversions = {
|
|
2212
|
+
Orientation: {
|
|
2213
|
+
"1": "Horizontal (normal)",
|
|
2214
|
+
"2": "Mirror horizontal",
|
|
2215
|
+
"3": "Rotate 180",
|
|
2216
|
+
"4": "Mirror vertical",
|
|
2217
|
+
"5": "Mirror horizontal and rotate 270 CW",
|
|
2218
|
+
"6": "Rotate 90 CW",
|
|
2219
|
+
"7": "Mirror horizontal and rotate 90 CW",
|
|
2220
|
+
"8": "Rotate 270 CW"
|
|
2221
|
+
},
|
|
2222
|
+
ResolutionUnit: { "1": "None", "2": "inches", "3": "cm" }
|
|
2223
|
+
};
|
|
2224
|
+
function printConverted(tags, invocation, resources) {
|
|
2225
|
+
if (invocation.numeric || invocation.binary) return tags;
|
|
2226
|
+
resources.admit("work", tags.length * (invocation.valueConvTags.length + 1) * 64);
|
|
2227
|
+
resources.admit("retained", tags.length * 512);
|
|
2228
|
+
return tags.map((tag) => {
|
|
2229
|
+
const conversions = tag.chunkType === "JPEG" && tag.group === "IFD0" ? jpegPrintConversions[tag.name] : void 0;
|
|
2230
|
+
if (!conversions || invocation.valueConvTags.includes(tag.name.toLowerCase())) return tag;
|
|
2231
|
+
return { ...tag, value: conversions[tag.value] ?? "Unknown (" + tag.value + ")" };
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2211
2234
|
function createExiftoolCommand(options = {}) {
|
|
2212
2235
|
const limits = Object.freeze({ ...options.limits });
|
|
2213
2236
|
return Object.freeze({
|
|
@@ -2436,6 +2459,7 @@ Limits:
|
|
|
2436
2459
|
continue;
|
|
2437
2460
|
}
|
|
2438
2461
|
read++;
|
|
2462
|
+
tags = printConverted(tags, invocation, resources);
|
|
2439
2463
|
const chosen = selected(tags, invocation.tags, invocation.json ? invocation.groupFamily === 4 : invocation.duplicates && !invocation.csv, resources);
|
|
2440
2464
|
if (invocation.xml || invocation.tabular || invocation.template !== void 0) {
|
|
2441
2465
|
const values = invocation.template !== void 0 ? selected(tags, [], false, resources) : chosen;
|
|
@@ -2634,7 +2658,7 @@ function evalSyncExiftool(inBytes, opArgs, readFileSync, writeFileSync) {
|
|
|
2634
2658
|
continue;
|
|
2635
2659
|
}
|
|
2636
2660
|
const metadata = jpeg ? inspectJpeg(bytes, resources).tags : png ? inspectPng(bytes, resources).tags : inspectPdf(bytes, resources).tags;
|
|
2637
|
-
const tags = [...systemTags(file, bytes.length, metadata, invocation, resources), ...metadata];
|
|
2661
|
+
const tags = printConverted([...systemTags(file, bytes.length, metadata, invocation, resources), ...metadata], invocation, resources);
|
|
2638
2662
|
const chosen = selected(tags, invocation.tags, invocation.json ? invocation.groupFamily === 4 : invocation.duplicates && !invocation.csv, resources);
|
|
2639
2663
|
if (invocation.xml || invocation.tabular || invocation.template !== void 0) {
|
|
2640
2664
|
const values = invocation.template !== void 0 ? selected(tags, [], false, resources) : chosen;
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
sliceMp4,
|
|
21
21
|
srtAst,
|
|
22
22
|
webvttAst
|
|
23
|
-
} from "../safe-bash/command-chunks/chunk-
|
|
23
|
+
} from "../safe-bash/command-chunks/chunk-45ZH6CNF.js";
|
|
24
24
|
import "../safe-bash/command-chunks/chunk-65DS4IOB.js";
|
|
25
25
|
|
|
26
26
|
// packages/safe-bash-command-ffmpeg/src/index.ts
|
|
@@ -87,8 +87,21 @@ function parseFfmpegTimestamp(spec) {
|
|
|
87
87
|
return parseFloat(trimmed) || 0;
|
|
88
88
|
}
|
|
89
89
|
function parseColorRgba(colorStr) {
|
|
90
|
-
const
|
|
90
|
+
const value = colorStr.trim().toLowerCase();
|
|
91
|
+
const separator = value.indexOf("@");
|
|
92
|
+
const s = separator < 0 ? value : value.slice(0, separator);
|
|
93
|
+
let alpha;
|
|
94
|
+
if (separator >= 0) {
|
|
95
|
+
const suffix = value.slice(separator + 1);
|
|
96
|
+
const opacity = Number(suffix);
|
|
97
|
+
const maximum = suffix.startsWith("0x") ? 255 : 1;
|
|
98
|
+
if (!suffix || !Number.isFinite(opacity) || opacity < 0 || opacity > maximum) {
|
|
99
|
+
throw new Error(`Invalid color alpha: ${colorStr}`);
|
|
100
|
+
}
|
|
101
|
+
alpha = Math.floor(opacity * 255 / maximum);
|
|
102
|
+
}
|
|
91
103
|
const named = {
|
|
104
|
+
aliceblue: [240, 248, 255, 255],
|
|
92
105
|
black: [0, 0, 0, 255],
|
|
93
106
|
white: [255, 255, 255, 255],
|
|
94
107
|
red: [255, 0, 0, 255],
|
|
@@ -103,17 +116,21 @@ function parseColorRgba(colorStr) {
|
|
|
103
116
|
orange: [255, 165, 0, 255],
|
|
104
117
|
purple: [128, 0, 128, 255]
|
|
105
118
|
};
|
|
106
|
-
if (named[s])
|
|
107
|
-
|
|
108
|
-
|
|
119
|
+
if (named[s]) {
|
|
120
|
+
const color = named[s];
|
|
121
|
+
color[3] = alpha ?? color[3];
|
|
122
|
+
return color;
|
|
123
|
+
}
|
|
124
|
+
const hex = s.startsWith("#") ? s.slice(1) : s.startsWith("0x") ? s.slice(2) : s;
|
|
125
|
+
if ((hex.length === 6 || hex.length === 8) && [...hex].every((digit) => "0123456789abcdef".includes(digit))) {
|
|
109
126
|
return [
|
|
110
127
|
parseInt(hex.slice(0, 2), 16) || 0,
|
|
111
128
|
parseInt(hex.slice(2, 4), 16) || 0,
|
|
112
129
|
parseInt(hex.slice(4, 6), 16) || 0,
|
|
113
|
-
255
|
|
130
|
+
alpha ?? (hex.length === 8 ? parseInt(hex.slice(6, 8), 16) : 255)
|
|
114
131
|
];
|
|
115
132
|
}
|
|
116
|
-
|
|
133
|
+
throw new Error(`Invalid color: ${colorStr}`);
|
|
117
134
|
}
|
|
118
135
|
function detachBytesBuffer(bytes) {
|
|
119
136
|
if (!bytes) return;
|
|
@@ -155,11 +172,12 @@ function* lavfiSteps(spec, budget, durationOverride) {
|
|
|
155
172
|
}
|
|
156
173
|
if (filterName === "sine" || filterName === "anullsrc") {
|
|
157
174
|
const sampleRate = parseInt(kv.sample_rate ?? kv.r ?? "44100", 10) || 44100;
|
|
158
|
-
const
|
|
175
|
+
const parsedFrequency = parseFloat(kv.frequency ?? kv.f ?? "440");
|
|
176
|
+
const freq = Number.isNaN(parsedFrequency) ? 440 : parsedFrequency;
|
|
159
177
|
const duration2 = durationOverride ?? (parseFloat(kv.duration ?? kv.d ?? "1") || 1);
|
|
160
178
|
const layout = kv.channel_layout ?? kv.cl;
|
|
161
179
|
const channels = layout === "mono" || layout === void 0 && filterName === "sine" ? 1 : 2;
|
|
162
|
-
const totalSamples = Math.max(
|
|
180
|
+
const totalSamples = Math.max(0, Math.round(duration2 * sampleRate));
|
|
163
181
|
budget.checkDuration(duration2);
|
|
164
182
|
const channelData = [];
|
|
165
183
|
for (let channel = 0; channel < channels; channel++) {
|
|
@@ -167,7 +185,7 @@ function* lavfiSteps(spec, budget, durationOverride) {
|
|
|
167
185
|
if (filterName === "sine") {
|
|
168
186
|
for (let i = 0; i < totalSamples; i++) {
|
|
169
187
|
if (i % 4096 === 0) yield;
|
|
170
|
-
arr[i] = Math.sin(2 * Math.PI * freq * i / sampleRate) * 0.
|
|
188
|
+
arr[i] = Math.sin(2 * Math.PI * freq * i / sampleRate) * 0.125;
|
|
171
189
|
}
|
|
172
190
|
}
|
|
173
191
|
channelData.push(arr);
|
|
@@ -302,12 +320,57 @@ function evalScaleDim(expr, iw, ih) {
|
|
|
302
320
|
if (clean === "-1" || clean === "-2") return -1;
|
|
303
321
|
if (clean === "iw" || clean === "in_w") return iw;
|
|
304
322
|
if (clean === "ih" || clean === "in_h") return ih;
|
|
305
|
-
if (clean.startsWith("iw/")) return Math.max(
|
|
306
|
-
if (clean.startsWith("ih/")) return Math.max(
|
|
307
|
-
if (clean.startsWith("iw*")) return Math.max(
|
|
308
|
-
if (clean.startsWith("ih*")) return Math.max(
|
|
323
|
+
if (clean.startsWith("iw/")) return Math.max(1, Math.round(iw / (parseFloat(clean.slice(3)) || 1)));
|
|
324
|
+
if (clean.startsWith("ih/")) return Math.max(1, Math.round(ih / (parseFloat(clean.slice(3)) || 1)));
|
|
325
|
+
if (clean.startsWith("iw*")) return Math.max(1, Math.round(iw * (parseFloat(clean.slice(3)) || 1)));
|
|
326
|
+
if (clean.startsWith("ih*")) return Math.max(1, Math.round(ih * (parseFloat(clean.slice(3)) || 1)));
|
|
309
327
|
return parseInt(clean, 10) || iw;
|
|
310
328
|
}
|
|
329
|
+
function parseRotateAngle(expression) {
|
|
330
|
+
let offset = 0;
|
|
331
|
+
const source = expression.trim();
|
|
332
|
+
function parse(minPrecedence = 0, depth = 0) {
|
|
333
|
+
if (depth > 64) throw new Error("rotate: angle expression is too deeply nested");
|
|
334
|
+
while (source[offset] === " ") offset++;
|
|
335
|
+
let value;
|
|
336
|
+
const first = source[offset];
|
|
337
|
+
if (first === "+" || first === "-") {
|
|
338
|
+
offset++;
|
|
339
|
+
value = parse(3, depth + 1) * (first === "-" ? -1 : 1);
|
|
340
|
+
} else if (first === "(") {
|
|
341
|
+
offset++;
|
|
342
|
+
value = parse(0, depth + 1);
|
|
343
|
+
if (source[offset++] !== ")") throw new Error("rotate: invalid angle expression");
|
|
344
|
+
} else if (source.slice(offset, offset + 2) === "PI") {
|
|
345
|
+
offset += 2;
|
|
346
|
+
value = Math.PI;
|
|
347
|
+
} else {
|
|
348
|
+
const start = offset;
|
|
349
|
+
while (offset < source.length) {
|
|
350
|
+
const c = source[offset];
|
|
351
|
+
if (c >= "0" && c <= "9" || c === "." || c === "e" || c === "E" || (c === "+" || c === "-") && (source[offset - 1] === "e" || source[offset - 1] === "E")) offset++;
|
|
352
|
+
else break;
|
|
353
|
+
}
|
|
354
|
+
value = start === offset ? NaN : Number(source.slice(start, offset));
|
|
355
|
+
}
|
|
356
|
+
for (; ; ) {
|
|
357
|
+
while (source[offset] === " ") offset++;
|
|
358
|
+
const operator = source[offset];
|
|
359
|
+
const precedence = operator === "+" || operator === "-" ? 1 : operator === "*" || operator === "/" ? 2 : 0;
|
|
360
|
+
if (precedence === 0 || precedence < minPrecedence) break;
|
|
361
|
+
offset++;
|
|
362
|
+
const right = parse(precedence + 1, depth + 1);
|
|
363
|
+
if (operator === "+") value += right;
|
|
364
|
+
else if (operator === "-") value -= right;
|
|
365
|
+
else if (operator === "*") value *= right;
|
|
366
|
+
else value /= right;
|
|
367
|
+
}
|
|
368
|
+
return value;
|
|
369
|
+
}
|
|
370
|
+
const angle = parse();
|
|
371
|
+
if (offset !== source.length || !Number.isFinite(angle)) throw new Error("rotate: invalid or unsupported angle expression");
|
|
372
|
+
return angle;
|
|
373
|
+
}
|
|
311
374
|
var GLYPH_5X7 = {
|
|
312
375
|
" ": [0, 0, 0, 0, 0, 0, 0],
|
|
313
376
|
"0": [14, 17, 19, 21, 25, 17, 14],
|
|
@@ -464,7 +527,23 @@ async function applyVideoFilterChain(frames, filterChainStr, budget, subtitleCue
|
|
|
464
527
|
let work = 0;
|
|
465
528
|
let current = frames;
|
|
466
529
|
if (current.length === 0) return current;
|
|
467
|
-
const filters =
|
|
530
|
+
const filters = [];
|
|
531
|
+
let filter = "";
|
|
532
|
+
let quoted = false;
|
|
533
|
+
for (let i = 0; i < filterChainStr.length; i++) {
|
|
534
|
+
const char = filterChainStr[i];
|
|
535
|
+
if (char === "'") {
|
|
536
|
+
quoted = !quoted;
|
|
537
|
+
} else if (!quoted && char === "\\" && i + 1 < filterChainStr.length) {
|
|
538
|
+
filter += filterChainStr[++i];
|
|
539
|
+
} else if (!quoted && char === ",") {
|
|
540
|
+
if (filter.trim()) filters.push(filter.trim());
|
|
541
|
+
filter = "";
|
|
542
|
+
} else {
|
|
543
|
+
filter += char;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
if (filter.trim()) filters.push(filter.trim());
|
|
468
547
|
for (const filterSpec of filters) {
|
|
469
548
|
if (++work % 1024 === 0) {
|
|
470
549
|
await yieldTurn(signal);
|
|
@@ -494,14 +573,14 @@ async function applyVideoFilterChain(frames, filterChainStr, budget, subtitleCue
|
|
|
494
573
|
let targetW = evalScaleDim(wSpec, iw, ih);
|
|
495
574
|
let targetH = evalScaleDim(hSpec, iw, ih);
|
|
496
575
|
if (targetW < 0 && targetH > 0) {
|
|
497
|
-
targetW = Math.max(
|
|
576
|
+
targetW = Math.max(1, Math.round(iw * targetH / Math.max(1, ih)));
|
|
498
577
|
if (wSpec.trim() === "-2" && targetW % 2 !== 0) targetW++;
|
|
499
578
|
} else if (targetH < 0 && targetW > 0) {
|
|
500
|
-
targetH = Math.max(
|
|
579
|
+
targetH = Math.max(1, Math.round(ih * targetW / Math.max(1, iw)));
|
|
501
580
|
if (hSpec.trim() === "-2" && targetH % 2 !== 0) targetH++;
|
|
502
581
|
}
|
|
503
|
-
targetW = Math.max(
|
|
504
|
-
targetH = Math.max(
|
|
582
|
+
targetW = Math.max(1, targetW);
|
|
583
|
+
targetH = Math.max(1, targetH);
|
|
505
584
|
current = await mapWork(current, async (f) => {
|
|
506
585
|
budget.recordFrame(targetW, targetH);
|
|
507
586
|
const resized = resizeImage(makeRgbaImg(f.width, f.height, f.data), {
|
|
@@ -524,8 +603,11 @@ async function applyVideoFilterChain(frames, filterChainStr, budget, subtitleCue
|
|
|
524
603
|
} else if (name === "crop") {
|
|
525
604
|
const iw = current[0].width;
|
|
526
605
|
const ih = current[0].height;
|
|
527
|
-
const cw =
|
|
528
|
-
const ch =
|
|
606
|
+
const cw = evalScaleDim(named.w ?? positional[0] ?? String(iw), iw, ih);
|
|
607
|
+
const ch = evalScaleDim(named.h ?? positional[1] ?? String(ih), iw, ih);
|
|
608
|
+
if (!Number.isFinite(cw) || !Number.isFinite(ch) || cw <= 0 || ch <= 0 || cw > iw || ch > ih) {
|
|
609
|
+
throw new Error(`Invalid too big or non positive size for width '${cw}' or height '${ch}'`);
|
|
610
|
+
}
|
|
529
611
|
const cx = Math.max(
|
|
530
612
|
0,
|
|
531
613
|
Math.min(iw - cw, parseInt(named.x ?? positional[2] ?? String(Math.floor((iw - cw) / 2)), 10) || 0)
|
|
@@ -551,8 +633,13 @@ async function applyVideoFilterChain(frames, filterChainStr, budget, subtitleCue
|
|
|
551
633
|
} else if (name === "pad") {
|
|
552
634
|
const iw = current[0].width;
|
|
553
635
|
const ih = current[0].height;
|
|
554
|
-
const
|
|
555
|
-
const
|
|
636
|
+
const width = named.w ?? named.width ?? positional[0] ?? String(iw);
|
|
637
|
+
const height = named.h ?? named.height ?? positional[1] ?? String(ih);
|
|
638
|
+
const pw = Number(width) === 0 ? iw : evalScaleDim(width, iw, ih);
|
|
639
|
+
const ph = Number(height) === 0 ? ih : evalScaleDim(height, iw, ih);
|
|
640
|
+
if (pw < iw || ph < ih) {
|
|
641
|
+
throw new Error("Padded dimensions cannot be smaller than input dimensions");
|
|
642
|
+
}
|
|
556
643
|
const px = Math.max(0, Math.min(pw - iw, parseInt(named.x ?? positional[2] ?? "0", 10) || 0));
|
|
557
644
|
const py = Math.max(0, Math.min(ph - ih, parseInt(named.y ?? positional[3] ?? "0", 10) || 0));
|
|
558
645
|
const col = parseColorRgba(named.color ?? positional[4] ?? "black");
|
|
@@ -562,7 +649,7 @@ async function applyVideoFilterChain(frames, filterChainStr, budget, subtitleCue
|
|
|
562
649
|
top: py,
|
|
563
650
|
right: Math.max(0, pw - iw - px),
|
|
564
651
|
bottom: Math.max(0, ph - ih - py),
|
|
565
|
-
background: { r: col[0], g: col[1], b: col[2], a:
|
|
652
|
+
background: { r: col[0], g: col[1], b: col[2], a: col[3] },
|
|
566
653
|
extendWith: "background"
|
|
567
654
|
});
|
|
568
655
|
return {
|
|
@@ -582,11 +669,12 @@ async function applyVideoFilterChain(frames, filterChainStr, budget, subtitleCue
|
|
|
582
669
|
const out = flipImage(makeRgbaImg(f.width, f.height, f.data));
|
|
583
670
|
return { ...f, data: out.data };
|
|
584
671
|
}, signal);
|
|
585
|
-
} else if (name === "transpose"
|
|
672
|
+
} else if (name === "transpose") {
|
|
586
673
|
const dir = named.dir ?? positional[0] ?? "1";
|
|
587
|
-
const angle =
|
|
674
|
+
const angle = dir === "0" || dir === "2" ? 270 : 90;
|
|
588
675
|
current = await mapWork(current, async (f) => {
|
|
589
|
-
const
|
|
676
|
+
const rotated = rotateImage(makeRgbaImg(f.width, f.height, f.data), angle);
|
|
677
|
+
const out = dir === "0" || dir === "3" ? flipImage(rotated) : rotated;
|
|
590
678
|
return {
|
|
591
679
|
...f,
|
|
592
680
|
width: out.width,
|
|
@@ -594,6 +682,41 @@ async function applyVideoFilterChain(frames, filterChainStr, budget, subtitleCue
|
|
|
594
682
|
data: out.data
|
|
595
683
|
};
|
|
596
684
|
}, signal);
|
|
685
|
+
} else if (name === "rotate") {
|
|
686
|
+
const angle = parseRotateAngle(named.angle ?? named.a ?? (positional[0] || "0"));
|
|
687
|
+
const cos = Math.cos(angle);
|
|
688
|
+
const sin = Math.sin(angle);
|
|
689
|
+
current = await mapWork(current, async (f) => {
|
|
690
|
+
budget.recordFrame(f.width, f.height);
|
|
691
|
+
const data = new Uint8Array(f.data.length);
|
|
692
|
+
const cx = (f.width - 1) / 2;
|
|
693
|
+
const cy = (f.height - 1) / 2;
|
|
694
|
+
for (let y = 0; y < f.height; y++) {
|
|
695
|
+
await yieldTurn(signal);
|
|
696
|
+
budget.checkCpu();
|
|
697
|
+
for (let x = 0; x < f.width; x++) {
|
|
698
|
+
const sx = cos * (x - cx) + sin * (y - cy) + cx;
|
|
699
|
+
const sy = -sin * (x - cx) + cos * (y - cy) + cy;
|
|
700
|
+
const dest = (y * f.width + x) * 4;
|
|
701
|
+
data[dest + 3] = 255;
|
|
702
|
+
if (sx < -1 || sx > f.width || sy < -1 || sy > f.height) continue;
|
|
703
|
+
const px = Math.max(0, Math.min(f.width - 1, sx));
|
|
704
|
+
const py = Math.max(0, Math.min(f.height - 1, sy));
|
|
705
|
+
const x0 = Math.floor(px);
|
|
706
|
+
const y0 = Math.floor(py);
|
|
707
|
+
const x1 = Math.min(x0 + 1, f.width - 1);
|
|
708
|
+
const y1 = Math.min(y0 + 1, f.height - 1);
|
|
709
|
+
const dx = px - x0;
|
|
710
|
+
const dy = py - y0;
|
|
711
|
+
for (let c = 0; c < 4; c++) {
|
|
712
|
+
const top = f.data[(y0 * f.width + x0) * 4 + c] * (1 - dx) + f.data[(y0 * f.width + x1) * 4 + c] * dx;
|
|
713
|
+
const bottom = f.data[(y1 * f.width + x0) * 4 + c] * (1 - dx) + f.data[(y1 * f.width + x1) * 4 + c] * dx;
|
|
714
|
+
data[dest + c] = Math.floor(top * (1 - dy) + bottom * dy + 1e-8);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
return { ...f, data };
|
|
719
|
+
}, signal);
|
|
597
720
|
} else if (name === "negate") {
|
|
598
721
|
current = await mapWork(current, async (f) => {
|
|
599
722
|
const out = negateImage(makeRgbaImg(f.width, f.height, f.data));
|
|
@@ -609,15 +732,15 @@ async function applyVideoFilterChain(frames, filterChainStr, budget, subtitleCue
|
|
|
609
732
|
const totalDuration = current.reduce((acc, f) => acc + f.durationSeconds, 0) || 1;
|
|
610
733
|
const targetCount = Math.max(1, Math.round(totalDuration * targetFps));
|
|
611
734
|
const resampled = [];
|
|
735
|
+
let srcIdx = 0;
|
|
612
736
|
for (let i = 0; i < targetCount; i++) {
|
|
613
737
|
if (++work % 1024 === 0) {
|
|
614
738
|
await yieldTurn(signal);
|
|
615
739
|
signal?.throwIfAborted();
|
|
616
740
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
);
|
|
741
|
+
while (srcIdx + 1 < current.length && Math.round(current[srcIdx + 1].ptsSeconds * targetFps) <= i) {
|
|
742
|
+
srcIdx++;
|
|
743
|
+
}
|
|
621
744
|
const src = current[srcIdx];
|
|
622
745
|
resampled.push({
|
|
623
746
|
...src,
|
|
@@ -767,6 +890,9 @@ async function applyVideoFilterChain(frames, filterChainStr, budget, subtitleCue
|
|
|
767
890
|
const bw = parseInt(named.w ?? named.width ?? positional[2] ?? "16", 10) || 16;
|
|
768
891
|
const bh = parseInt(named.h ?? named.height ?? positional[3] ?? "16", 10) || 16;
|
|
769
892
|
const col = parseColorRgba(named.color ?? named.c ?? positional[4] ?? "red");
|
|
893
|
+
const thicknessOption = named.t ?? named.thickness ?? positional[5] ?? "3";
|
|
894
|
+
const thickness = thicknessOption === "fill" ? Infinity : parseInt(thicknessOption, 10);
|
|
895
|
+
const replace = named.replace === "1";
|
|
770
896
|
current = await mapWork(current, async (f) => {
|
|
771
897
|
let work2 = 0;
|
|
772
898
|
const nextData = new Uint8Array(f.data);
|
|
@@ -780,11 +906,15 @@ async function applyVideoFilterChain(frames, filterChainStr, budget, subtitleCue
|
|
|
780
906
|
await yieldTurn(signal);
|
|
781
907
|
signal?.throwIfAborted();
|
|
782
908
|
}
|
|
909
|
+
if (Math.min(x - bx, y - by, bx + bw - 1 - x, by + bh - 1 - y) >= thickness) continue;
|
|
783
910
|
const idx = (y * f.width + x) * 4;
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
911
|
+
if (replace) {
|
|
912
|
+
nextData.set(col, idx);
|
|
913
|
+
continue;
|
|
914
|
+
}
|
|
915
|
+
for (let channel = 0; channel < 3; channel++) {
|
|
916
|
+
nextData[idx + channel] = (nextData[idx + channel] * (255 - col[3]) + col[channel] * col[3]) / 255;
|
|
917
|
+
}
|
|
788
918
|
}
|
|
789
919
|
}
|
|
790
920
|
return { ...f, data: nextData };
|
|
@@ -837,7 +967,6 @@ function evalSyncFfmpeg(inBytesOrArgs, maybeArgs, readFileSync, writeFileSync) {
|
|
|
837
967
|
let rotation;
|
|
838
968
|
let noOverwrite = true;
|
|
839
969
|
const vfFilters = [];
|
|
840
|
-
const afFilters = [];
|
|
841
970
|
const metadata = {};
|
|
842
971
|
let outputTarget;
|
|
843
972
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -914,8 +1043,7 @@ function evalSyncFfmpeg(inBytesOrArgs, maybeArgs, readFileSync, writeFileSync) {
|
|
|
914
1043
|
const f = args[++i];
|
|
915
1044
|
if (f) vfFilters.push(f);
|
|
916
1045
|
} else if (arg === "-af" || arg === "-filter:a") {
|
|
917
|
-
|
|
918
|
-
if (f) afFilters.push(f);
|
|
1046
|
+
return void 0;
|
|
919
1047
|
} else if (arg === "-metadata" || arg.startsWith("-metadata:")) {
|
|
920
1048
|
const kv = args[++i] ?? "";
|
|
921
1049
|
const eq = kv.indexOf("=");
|
|
@@ -1799,7 +1927,7 @@ function createFfmpegCommand(options = {}) {
|
|
|
1799
1927
|
const origCh = t.decodedAudio?.channels ?? t.codecDescriptions[0]?.channels ?? 2;
|
|
1800
1928
|
const targetRate = audioRate ?? origRate;
|
|
1801
1929
|
const targetCh = audioChannels ?? origCh;
|
|
1802
|
-
const durSec =
|
|
1930
|
+
const durSec = (t.duration || origRate) / Math.max(1, t.timescale || origRate);
|
|
1803
1931
|
let volFactor = t.volume ?? 1;
|
|
1804
1932
|
let tempoFactor = 1;
|
|
1805
1933
|
let reverseAudio = false;
|
|
@@ -1816,11 +1944,14 @@ function createFfmpegCommand(options = {}) {
|
|
|
1816
1944
|
const trimmed = item.trim();
|
|
1817
1945
|
if (trimmed.startsWith("volume=")) {
|
|
1818
1946
|
const volSpec = trimmed.slice("volume=".length).trim();
|
|
1819
|
-
|
|
1947
|
+
const gain = parseFloat(volSpec);
|
|
1948
|
+
volFactor *= volSpec.endsWith("dB") ? Math.pow(10, (parseFloat(volSpec.slice(0, -2)) || 0) / 20) : Number.isNaN(gain) ? 1 : gain;
|
|
1820
1949
|
} else if (trimmed.startsWith("atempo=")) {
|
|
1821
1950
|
tempoFactor *= Math.max(0.25, Math.min(4, parseFloat(trimmed.slice(7)) || 1));
|
|
1822
1951
|
} else if (trimmed === "areverse") {
|
|
1823
1952
|
reverseAudio = true;
|
|
1953
|
+
} else {
|
|
1954
|
+
throw new Error(`Unsupported audio filter: ${trimmed}`);
|
|
1824
1955
|
}
|
|
1825
1956
|
}
|
|
1826
1957
|
}
|
|
@@ -1833,6 +1964,7 @@ function createFfmpegCommand(options = {}) {
|
|
|
1833
1964
|
}
|
|
1834
1965
|
const dst = new Float32Array(targetSamples);
|
|
1835
1966
|
const srcCh = t.decodedAudio?.channelData[Math.min(c, (t.decodedAudio.channelData.length || 1) - 1)];
|
|
1967
|
+
const rightCh = origCh === 2 && targetCh === 1 ? t.decodedAudio.channelData[1] : void 0;
|
|
1836
1968
|
if (srcCh && srcCh.length > 0) {
|
|
1837
1969
|
for (let i = 0; i < targetSamples; i++) {
|
|
1838
1970
|
if (++work % 1024 === 0) {
|
|
@@ -1840,7 +1972,8 @@ function createFfmpegCommand(options = {}) {
|
|
|
1840
1972
|
context.signal?.throwIfAborted();
|
|
1841
1973
|
}
|
|
1842
1974
|
const srcIdx = Math.min(srcCh.length - 1, Math.floor(i / targetSamples * srcCh.length));
|
|
1843
|
-
|
|
1975
|
+
const sample = rightCh ? (srcCh[srcIdx] + rightCh[srcIdx]) / 2 : srcCh[srcIdx];
|
|
1976
|
+
dst[i] = Math.max(-1, Math.min(1, sample * volFactor));
|
|
1844
1977
|
}
|
|
1845
1978
|
}
|
|
1846
1979
|
if (reverseAudio) dst.reverse();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createFfprobeCommand
|
|
3
|
-
} from "../safe-bash/command-chunks/chunk-
|
|
3
|
+
} from "../safe-bash/command-chunks/chunk-T5WFJ44Z.js";
|
|
4
4
|
import "../safe-bash/command-chunks/chunk-MGBHGZEX.js";
|
|
5
|
-
import "../safe-bash/command-chunks/chunk-
|
|
5
|
+
import "../safe-bash/command-chunks/chunk-45ZH6CNF.js";
|
|
6
6
|
import "../safe-bash/command-chunks/chunk-65DS4IOB.js";
|
|
7
7
|
|
|
8
8
|
// packages/safe-bash-command-ffprobe/src/index.ts
|
|
@@ -11,9 +11,9 @@ import {
|
|
|
11
11
|
loadManifestResources,
|
|
12
12
|
resolvePath,
|
|
13
13
|
rethrowRuntimeError
|
|
14
|
-
} from "../safe-bash/command-chunks/chunk-
|
|
14
|
+
} from "../safe-bash/command-chunks/chunk-T5WFJ44Z.js";
|
|
15
15
|
import "../safe-bash/command-chunks/chunk-MGBHGZEX.js";
|
|
16
|
-
import "../safe-bash/command-chunks/chunk-
|
|
16
|
+
import "../safe-bash/command-chunks/chunk-45ZH6CNF.js";
|
|
17
17
|
import "../safe-bash/command-chunks/chunk-65DS4IOB.js";
|
|
18
18
|
export {
|
|
19
19
|
createFfprobeCommand,
|