@bendyline/squisq-cli 2.8.7 → 2.8.8

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.
@@ -17,7 +17,7 @@ import {
17
17
  renderDocToMp4,
18
18
  resolveDashboardDimensions,
19
19
  validateDashboardImageDimensions
20
- } from "./chunk-EVE74NYB.js";
20
+ } from "./chunk-XD2ICI5G.js";
21
21
  import {
22
22
  GIF_EXPORT_DEFAULTS,
23
23
  framesToGifNative,
package/dist/api.js CHANGED
@@ -74,10 +74,15 @@ async function detectFfmpegDetailed(signal) {
74
74
  }
75
75
 
76
76
  // src/util/audioMix.ts
77
+ import { buildMediaRenderIndex, mediaClipRenderKey } from "@bendyline/squisq/mediaEdit";
77
78
  import { computeAudioTimeline } from "@bendyline/squisq-video";
78
79
  async function buildMixedAudioTrack(doc, container, ffmpegPath, coverPreRoll, signal) {
79
80
  signal?.throwIfAborted();
80
- const timeline = computeAudioTimeline(doc, coverPreRoll, { includeVideoAudio: false });
81
+ const processedAudio = await processedAudioLookup(container);
82
+ const timeline = computeAudioTimeline(doc, coverPreRoll, {
83
+ includeVideoAudio: false,
84
+ ...processedAudio ? { processedAudio } : {}
85
+ });
81
86
  if (timeline.length === 0) return null;
82
87
  const bytesBySrc = /* @__PURE__ */ new Map();
83
88
  const readSrc = async (src) => {
@@ -97,6 +102,38 @@ async function buildMixedAudioTrack(doc, container, ffmpegPath, coverPreRoll, si
97
102
  if (usable.length === 0) return null;
98
103
  return mixTimelineClips(ffmpegPath, usable, signal);
99
104
  }
105
+ async function processedAudioLookup(container) {
106
+ const entries = await container.listFiles();
107
+ const index = buildMediaRenderIndex(entries.map((e) => ({ name: e.path, size: e.size })));
108
+ if (index.size === 0) return null;
109
+ return (clip) => {
110
+ const key = mediaClipRenderKey(clip);
111
+ return key ? index.get(key)?.path : void 0;
112
+ };
113
+ }
114
+ function clipFilterChain(clip) {
115
+ const start = Math.max(0, clip.sourceInSec);
116
+ const duration = Math.max(0, clip.durationSec);
117
+ const delayMs = Math.max(0, Math.round(clip.startSec * 1e3));
118
+ const parts = [`atrim=start=${start}:end=${start + duration}`, "asetpts=PTS-STARTPTS"];
119
+ if (clip.gainDb) parts.push(`volume=${clip.gainDb}dB`);
120
+ let fadeIn = Math.max(0, clip.fadeInSec ?? 0);
121
+ let fadeOut = Math.max(0, clip.fadeOutSec ?? 0);
122
+ if (fadeIn + fadeOut > duration && duration > 0) {
123
+ const scale = duration / (fadeIn + fadeOut);
124
+ fadeIn *= scale;
125
+ fadeOut *= scale;
126
+ }
127
+ if (fadeIn > 0) parts.push(`afade=t=in:st=0:d=${round3(fadeIn)}`);
128
+ if (fadeOut > 0) {
129
+ parts.push(`afade=t=out:st=${round3(duration - fadeOut)}:d=${round3(fadeOut)}`);
130
+ }
131
+ parts.push(`adelay=${delayMs}|${delayMs}`);
132
+ return parts.join(",");
133
+ }
134
+ function round3(n) {
135
+ return Math.round(n * 1e3) / 1e3;
136
+ }
100
137
  async function mixTimelineClips(ffmpegPath, usable, signal) {
101
138
  const { writeFile: writeFile2, readFile: readFile4, mkdir: mkdir2, rm: rm2 } = await import("fs/promises");
102
139
  const { join: join3 } = await import("path");
@@ -105,7 +142,6 @@ async function mixTimelineClips(ffmpegPath, usable, signal) {
105
142
  signal?.throwIfAborted();
106
143
  const workDir = join3(tmpdir2(), `squisq-audio-mix-${randomBytes2(8).toString("hex")}`);
107
144
  await mkdir2(workDir, { recursive: true });
108
- const ms = (s) => Math.max(0, Math.round(s * 1e3));
109
145
  try {
110
146
  signal?.throwIfAborted();
111
147
  const inputs = [];
@@ -117,12 +153,7 @@ async function mixTimelineClips(ffmpegPath, usable, signal) {
117
153
  await writeFile2(p, new Uint8Array(buffer));
118
154
  signal?.throwIfAborted();
119
155
  const i = inputs.push(p) - 1;
120
- const delayMs = ms(clip.startSec);
121
- const start = Math.max(0, clip.sourceInSec);
122
- const end = start + Math.max(0, clip.durationSec);
123
- filters.push(
124
- `[${i}:a]atrim=start=${start}:end=${end},asetpts=PTS-STARTPTS,adelay=${delayMs}|${delayMs}[a${i}]`
125
- );
156
+ filters.push(`[${i}:a]${clipFilterChain(clip)}[a${i}]`);
126
157
  labels.push(`[a${i}]`);
127
158
  }
128
159
  const graph = `${filters.join(";")};${labels.join("")}amix=inputs=${labels.length}:normalize=0:dropout_transition=0[aout]`;
@@ -71,10 +71,15 @@ async function detectFfmpegDetailed(signal) {
71
71
  }
72
72
 
73
73
  // src/util/audioMix.ts
74
+ import { buildMediaRenderIndex, mediaClipRenderKey } from "@bendyline/squisq/mediaEdit";
74
75
  import { computeAudioTimeline } from "@bendyline/squisq-video";
75
76
  async function buildMixedAudioTrack(doc, container, ffmpegPath, coverPreRoll, signal) {
76
77
  signal?.throwIfAborted();
77
- const timeline = computeAudioTimeline(doc, coverPreRoll, { includeVideoAudio: false });
78
+ const processedAudio = await processedAudioLookup(container);
79
+ const timeline = computeAudioTimeline(doc, coverPreRoll, {
80
+ includeVideoAudio: false,
81
+ ...processedAudio ? { processedAudio } : {}
82
+ });
78
83
  if (timeline.length === 0) return null;
79
84
  const bytesBySrc = /* @__PURE__ */ new Map();
80
85
  const readSrc = async (src) => {
@@ -94,6 +99,38 @@ async function buildMixedAudioTrack(doc, container, ffmpegPath, coverPreRoll, si
94
99
  if (usable.length === 0) return null;
95
100
  return mixTimelineClips(ffmpegPath, usable, signal);
96
101
  }
102
+ async function processedAudioLookup(container) {
103
+ const entries = await container.listFiles();
104
+ const index = buildMediaRenderIndex(entries.map((e) => ({ name: e.path, size: e.size })));
105
+ if (index.size === 0) return null;
106
+ return (clip) => {
107
+ const key = mediaClipRenderKey(clip);
108
+ return key ? index.get(key)?.path : void 0;
109
+ };
110
+ }
111
+ function clipFilterChain(clip) {
112
+ const start = Math.max(0, clip.sourceInSec);
113
+ const duration = Math.max(0, clip.durationSec);
114
+ const delayMs = Math.max(0, Math.round(clip.startSec * 1e3));
115
+ const parts = [`atrim=start=${start}:end=${start + duration}`, "asetpts=PTS-STARTPTS"];
116
+ if (clip.gainDb) parts.push(`volume=${clip.gainDb}dB`);
117
+ let fadeIn = Math.max(0, clip.fadeInSec ?? 0);
118
+ let fadeOut = Math.max(0, clip.fadeOutSec ?? 0);
119
+ if (fadeIn + fadeOut > duration && duration > 0) {
120
+ const scale = duration / (fadeIn + fadeOut);
121
+ fadeIn *= scale;
122
+ fadeOut *= scale;
123
+ }
124
+ if (fadeIn > 0) parts.push(`afade=t=in:st=0:d=${round3(fadeIn)}`);
125
+ if (fadeOut > 0) {
126
+ parts.push(`afade=t=out:st=${round3(duration - fadeOut)}:d=${round3(fadeOut)}`);
127
+ }
128
+ parts.push(`adelay=${delayMs}|${delayMs}`);
129
+ return parts.join(",");
130
+ }
131
+ function round3(n) {
132
+ return Math.round(n * 1e3) / 1e3;
133
+ }
97
134
  async function mixTimelineClips(ffmpegPath, usable, signal) {
98
135
  const { writeFile: writeFile2, readFile: readFile4, mkdir: mkdir2, rm: rm2 } = await import("fs/promises");
99
136
  const { join: join3 } = await import("path");
@@ -102,7 +139,6 @@ async function mixTimelineClips(ffmpegPath, usable, signal) {
102
139
  signal?.throwIfAborted();
103
140
  const workDir = join3(tmpdir2(), `squisq-audio-mix-${randomBytes2(8).toString("hex")}`);
104
141
  await mkdir2(workDir, { recursive: true });
105
- const ms = (s) => Math.max(0, Math.round(s * 1e3));
106
142
  try {
107
143
  signal?.throwIfAborted();
108
144
  const inputs = [];
@@ -114,12 +150,7 @@ async function mixTimelineClips(ffmpegPath, usable, signal) {
114
150
  await writeFile2(p, new Uint8Array(buffer));
115
151
  signal?.throwIfAborted();
116
152
  const i = inputs.push(p) - 1;
117
- const delayMs = ms(clip.startSec);
118
- const start = Math.max(0, clip.sourceInSec);
119
- const end = start + Math.max(0, clip.durationSec);
120
- filters.push(
121
- `[${i}:a]atrim=start=${start}:end=${end},asetpts=PTS-STARTPTS,adelay=${delayMs}|${delayMs}[a${i}]`
122
- );
153
+ filters.push(`[${i}:a]${clipFilterChain(clip)}[a${i}]`);
123
154
  labels.push(`[a${i}]`);
124
155
  }
125
156
  const graph = `${filters.join(";")};${labels.join("")}amix=inputs=${labels.length}:normalize=0:dropout_transition=0[aout]`;
@@ -331,7 +362,7 @@ function mp4Format() {
331
362
  const animationsEnabled = typeof mp4Opts.animationsEnabled === "boolean" ? mp4Opts.animationsEnabled : MP4_DEFAULTS.animationsEnabled;
332
363
  const outputPath = join(tmpdir(), `squisq-mp4-${randomBytes(8).toString("hex")}.mp4`);
333
364
  try {
334
- const { renderDocToMp4: renderDocToMp42 } = await import("./api-FHTG2OCX.js");
365
+ const { renderDocToMp4: renderDocToMp42 } = await import("./api-QLYK5AQE.js");
335
366
  await renderDocToMp42(input.doc, input.container, {
336
367
  outputPath,
337
368
  fps,
@@ -372,7 +403,7 @@ function gifFormat() {
372
403
  const defaultHeight = portrait ? GIF_DEFAULTS.width : GIF_DEFAULTS.height;
373
404
  const outputPath = join(tmpdir(), `squisq-gif-${randomBytes(8).toString("hex")}.gif`);
374
405
  try {
375
- const { renderDocToGif: renderDocToGif2 } = await import("./api-FHTG2OCX.js");
406
+ const { renderDocToGif: renderDocToGif2 } = await import("./api-QLYK5AQE.js");
376
407
  const result = await renderDocToGif2(input.doc, input.container, {
377
408
  outputPath,
378
409
  fps: typeof gifOpts.fps === "number" ? gifOpts.fps : GIF_DEFAULTS.fps,
@@ -415,7 +446,7 @@ function pngFormat() {
415
446
  async exportDoc(input, options) {
416
447
  options.signal?.throwIfAborted();
417
448
  const pngOpts = options.formatOptions?.png ?? {};
418
- const { renderDocToDashboardPng: renderDocToDashboardPng2 } = await import("./api-FHTG2OCX.js");
449
+ const { renderDocToDashboardPng: renderDocToDashboardPng2 } = await import("./api-QLYK5AQE.js");
419
450
  const result = await renderDocToDashboardPng2(input.doc, input.container, {
420
451
  resolution: pngOpts.resolution,
421
452
  width: pngOpts.width,
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  renderDocToDashboardPng,
10
10
  renderDocToGif,
11
11
  renderDocToMp4
12
- } from "./chunk-EVE74NYB.js";
12
+ } from "./chunk-XD2ICI5G.js";
13
13
  import "./chunk-GGVASRPG.js";
14
14
 
15
15
  // src/index.ts