@hyperframes/studio-server 0.9.15 → 0.9.17
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/{chunk-NOIHVBIQ.js → chunk-66YZA32N.js} +1 -1
- package/dist/{chunk-B356RYG5.js → chunk-F4AQECCT.js} +3 -3
- package/dist/{chunk-GTQ6S4O5.js → chunk-IJMPYPJG.js} +2 -2
- package/dist/{chunk-H4NVSSDJ.js → chunk-NEGQQZNI.js} +30 -31
- package/dist/{chunk-LK3ZTZGN.js → chunk-REQUL5L4.js} +12 -5
- package/dist/{chunk-X73QTST2.js → chunk-Y6EZUBYR.js} +13 -3
- package/dist/helpers/loudness.d.ts +4 -4
- package/dist/helpers/loudness.js +2 -2
- package/dist/helpers/mediaCodecMap.js +2 -2
- package/dist/helpers/mediaProxyPreview.d.ts +1 -1
- package/dist/helpers/mediaProxyPreview.js +4 -4
- package/dist/helpers/proxyTranscoder.js +3 -3
- package/dist/helpers/sourceMutation.d.ts +4 -1
- package/dist/helpers/sourceMutation.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +22 -9
- package/dist/{mediaProxyPreview-Ds5TElPq.d.ts → mediaProxyPreview-pNW7nfS0.d.ts} +1 -1
- package/package.json +3 -3
|
@@ -2,11 +2,11 @@ import {
|
|
|
2
2
|
PROXY_STILL_EXTENSION,
|
|
3
3
|
PROXY_VARIANT_CONFIG,
|
|
4
4
|
ffmpegHasHdrFilters
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-66YZA32N.js";
|
|
6
6
|
import {
|
|
7
7
|
probeFirstFrameColour,
|
|
8
8
|
probeMediaMetadata
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-Y6EZUBYR.js";
|
|
10
10
|
import {
|
|
11
11
|
mkdirWithinProject,
|
|
12
12
|
realProjectRoot,
|
|
@@ -768,7 +768,7 @@ async function buildVideoFilter(ffmpegPath, sourcePath, metadata, keepsAlpha, bo
|
|
|
768
768
|
const { hdrTransfer } = metadata.color;
|
|
769
769
|
const toneMap = (hdrTransfer === "pq" || hdrTransfer === "hlg") && !keepsAlpha;
|
|
770
770
|
if (toneMap) await ensureHdrFilters(ffmpegPath);
|
|
771
|
-
const firstFrame = toneMap ? await probeFirstFrameColour(sourcePath) : {};
|
|
771
|
+
const firstFrame = toneMap ? await probeFirstFrameColour(sourcePath, metadata.color.codecName) : {};
|
|
772
772
|
const evenScale = proxyScaleFilter(box);
|
|
773
773
|
const pixelFormat = keepsAlpha ? "yuva420p" : "yuv420p";
|
|
774
774
|
return toneMap ? [
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PROXY_PARAMS_VERSION,
|
|
3
3
|
resolveProxy
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-F4AQECCT.js";
|
|
5
5
|
import {
|
|
6
6
|
createMediaCodecProbeCache,
|
|
7
7
|
proxyVariantFor,
|
|
8
8
|
recordProxyPrewarm,
|
|
9
9
|
scanProjectMedia,
|
|
10
10
|
shouldPrewarmProxy
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-66YZA32N.js";
|
|
12
12
|
|
|
13
13
|
// src/helpers/mediaProxyPreview.ts
|
|
14
14
|
import { resolve } from "path";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
probeAudioTrack
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-Y6EZUBYR.js";
|
|
4
4
|
import {
|
|
5
5
|
resolveWithinProject
|
|
6
6
|
} from "./chunk-QF7MFJJU.js";
|
|
@@ -277,30 +277,24 @@ function audioNormalizationPlan(referenceTrack, targetTrack) {
|
|
|
277
277
|
}
|
|
278
278
|
const referenceLufs = referenceTrack.integratedLufs + gainDb(referenceTrack.volume);
|
|
279
279
|
const targetLufs = targetTrack.integratedLufs + gainDb(targetTrack.volume);
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const volume = 10 ** (wantedGainDb / 20);
|
|
287
|
-
const projectedTruePeakDbfs = targetTrack.truePeakDbfs + wantedGainDb;
|
|
288
|
-
if (projectedTruePeakDbfs > 0) {
|
|
289
|
-
throw new Error(
|
|
290
|
-
`Matching #${targetTrack.id} would clip at +${projectedTruePeakDbfs.toFixed(1)} dBFS; limit or preprocess the source first`
|
|
291
|
-
);
|
|
292
|
-
}
|
|
280
|
+
const previousGainDb = gainDb(targetTrack.volume);
|
|
281
|
+
const { appliedGainDb, limitedBy } = fittedGain(
|
|
282
|
+
referenceLufs - targetTrack.integratedLufs,
|
|
283
|
+
targetTrack.truePeakDbfs,
|
|
284
|
+
previousGainDb
|
|
285
|
+
);
|
|
293
286
|
return {
|
|
294
287
|
referenceId: referenceTrack.id,
|
|
295
288
|
targetId: targetTrack.id,
|
|
296
289
|
referenceLufs,
|
|
297
290
|
targetLufs,
|
|
298
291
|
previousVolume: targetTrack.volume,
|
|
299
|
-
volume,
|
|
300
|
-
gainDb:
|
|
301
|
-
changeDb:
|
|
302
|
-
projectedLufs: targetTrack.integratedLufs +
|
|
303
|
-
projectedTruePeakDbfs
|
|
292
|
+
volume: 10 ** (appliedGainDb / 20),
|
|
293
|
+
gainDb: appliedGainDb,
|
|
294
|
+
changeDb: appliedGainDb - previousGainDb,
|
|
295
|
+
projectedLufs: targetTrack.integratedLufs + appliedGainDb,
|
|
296
|
+
projectedTruePeakDbfs: targetTrack.truePeakDbfs + appliedGainDb,
|
|
297
|
+
limitedBy
|
|
304
298
|
};
|
|
305
299
|
}
|
|
306
300
|
function updateAudioVolume(html, id, volume) {
|
|
@@ -363,19 +357,12 @@ function absoluteLoudnessPlan(track, targetLufs = DEFAULT_TARGET_LUFS) {
|
|
|
363
357
|
if (track.integratedLufs <= SILENCE_LUFS) {
|
|
364
358
|
throw new Error(`#${track.id} is silent in the played window; there is nothing to normalize`);
|
|
365
359
|
}
|
|
366
|
-
const wantedGainDb = targetLufs - track.integratedLufs;
|
|
367
|
-
const peakRoomDb = NORMALIZE_TRUE_PEAK_CEILING_DBFS - track.truePeakDbfs;
|
|
368
|
-
const limits = [
|
|
369
|
-
[null, wantedGainDb],
|
|
370
|
-
["gain-ceiling", MAX_AUDIO_GAIN_DB],
|
|
371
|
-
["true-peak", peakRoomDb]
|
|
372
|
-
];
|
|
373
|
-
const [limitedBy, limitedGainDb] = limits.reduce(
|
|
374
|
-
(lowest, candidate) => candidate[1] < lowest[1] - 1e-9 ? candidate : lowest
|
|
375
|
-
);
|
|
376
360
|
const previousGainDb = track.volume > 0 ? gainDb(track.volume) : 0;
|
|
377
|
-
const
|
|
378
|
-
|
|
361
|
+
const { appliedGainDb, limitedBy } = fittedGain(
|
|
362
|
+
targetLufs - track.integratedLufs,
|
|
363
|
+
track.truePeakDbfs,
|
|
364
|
+
previousGainDb
|
|
365
|
+
);
|
|
379
366
|
return {
|
|
380
367
|
targetId: track.id,
|
|
381
368
|
targetLufs,
|
|
@@ -389,6 +376,18 @@ function absoluteLoudnessPlan(track, targetLufs = DEFAULT_TARGET_LUFS) {
|
|
|
389
376
|
limitedBy
|
|
390
377
|
};
|
|
391
378
|
}
|
|
379
|
+
function fittedGain(wantedGainDb, truePeakDbfs, previousGainDb) {
|
|
380
|
+
const limits = [
|
|
381
|
+
[null, wantedGainDb],
|
|
382
|
+
["gain-ceiling", MAX_AUDIO_GAIN_DB],
|
|
383
|
+
["true-peak", NORMALIZE_TRUE_PEAK_CEILING_DBFS - truePeakDbfs]
|
|
384
|
+
];
|
|
385
|
+
const [limitedBy, limitedGainDb] = limits.reduce(
|
|
386
|
+
(lowest, candidate) => candidate[1] < lowest[1] - 1e-9 ? candidate : lowest
|
|
387
|
+
);
|
|
388
|
+
const appliedGainDb = wantedGainDb > previousGainDb ? Math.max(limitedGainDb, previousGainDb) : limitedGainDb;
|
|
389
|
+
return { appliedGainDb, limitedBy };
|
|
390
|
+
}
|
|
392
391
|
function absoluteOutcome(plan, tolerance) {
|
|
393
392
|
if (Math.abs(plan.changeDb) > tolerance) return "change";
|
|
394
393
|
return Math.abs(plan.projectedLufs - plan.targetLufs) <= tolerance ? "matched" : "held";
|
|
@@ -343,6 +343,12 @@ function probeElementsInSource(source, targets) {
|
|
|
343
343
|
function probeElementInSource(source, target) {
|
|
344
344
|
return probeElementsInSource(source, [target])[0] ?? false;
|
|
345
345
|
}
|
|
346
|
+
var refused = (html, refusal) => ({
|
|
347
|
+
html,
|
|
348
|
+
matched: false,
|
|
349
|
+
newId: null,
|
|
350
|
+
refusal
|
|
351
|
+
});
|
|
346
352
|
function resolveElementTiming(el) {
|
|
347
353
|
const timing = readClipTiming(el);
|
|
348
354
|
return { start: timing.start ?? 0, duration: timing.duration ?? 0 };
|
|
@@ -363,7 +369,7 @@ function isWindowOf(media, row) {
|
|
|
363
369
|
function splitElementInHtml(source, target, splitTime, newId, fallbackTiming) {
|
|
364
370
|
const { document, wrappedFragment } = parseSourceDocument(source);
|
|
365
371
|
const el = findTargetElement(document, target);
|
|
366
|
-
if (!el || !isHTMLElement(el)) return
|
|
372
|
+
if (!el || !isHTMLElement(el)) return refused(source, "target-not-found");
|
|
367
373
|
const timedMediaSelector = "video[data-start], audio[data-start]";
|
|
368
374
|
const innerMedia = el.hasAttribute("data-start") || resolveElementTiming(el).duration > 0 || el.matches("[data-composition-src], [data-composition-id]") ? null : el.querySelector(timedMediaSelector);
|
|
369
375
|
const timedMedia = innerMedia && isWindowOf(resolveElementTiming(innerMedia), fallbackTiming) ? innerMedia : null;
|
|
@@ -373,21 +379,22 @@ function splitElementInHtml(source, target, splitTime, newId, fallbackTiming) {
|
|
|
373
379
|
const reference = readClipTiming(timed).startExpression;
|
|
374
380
|
const startsAfter = reference?.kind === "reference" ? reference : null;
|
|
375
381
|
if (startsAfter) {
|
|
376
|
-
if (!fallbackTiming) return
|
|
382
|
+
if (!fallbackTiming) return refused(source, "reference-without-range");
|
|
377
383
|
start = fallbackTiming.start;
|
|
378
384
|
}
|
|
379
385
|
if (duration <= 0 && fallbackTiming && fallbackTiming.duration > 0) {
|
|
380
386
|
start = fallbackTiming.start;
|
|
381
387
|
duration = fallbackTiming.duration;
|
|
382
388
|
}
|
|
383
|
-
if (duration <= 0
|
|
384
|
-
|
|
389
|
+
if (duration <= 0) return refused(source, "no-duration");
|
|
390
|
+
if (splitTime < start + SPLIT_BOUNDARY_EPSILON_S || splitTime > start + duration - SPLIT_BOUNDARY_EPSILON_S) {
|
|
391
|
+
return refused(source, "outside-clip");
|
|
385
392
|
}
|
|
386
393
|
newId = nextUniqueId(document, newId);
|
|
387
394
|
const firstDuration = splitTime - start;
|
|
388
395
|
const secondDuration = duration - firstDuration;
|
|
389
396
|
const clone = el.cloneNode(true);
|
|
390
|
-
if (!isHTMLElement(clone)) return
|
|
397
|
+
if (!isHTMLElement(clone)) return refused(source, "target-not-found");
|
|
391
398
|
clone.setAttribute("id", newId);
|
|
392
399
|
dedupeClonedCompositionId(document, clone);
|
|
393
400
|
clone.removeAttribute("data-hf-id");
|
|
@@ -3,7 +3,10 @@ import { execFile } from "child_process";
|
|
|
3
3
|
import { extname } from "path";
|
|
4
4
|
import {
|
|
5
5
|
firstFrameColourArgs,
|
|
6
|
-
|
|
6
|
+
keyframeTransferArgs,
|
|
7
|
+
parseFirstFrameColour,
|
|
8
|
+
readsKeyframeTransfers,
|
|
9
|
+
parseKeyframeTransfers
|
|
7
10
|
} from "@hyperframes/core";
|
|
8
11
|
import { findFfBinary } from "@hyperframes/parsers/ff-binaries";
|
|
9
12
|
import { videoStreamHasAlpha } from "@hyperframes/parsers/media-alpha";
|
|
@@ -82,14 +85,21 @@ function classifyMediaColor(stream) {
|
|
|
82
85
|
bitsPerRawSample: stream?.bits_per_raw_sample
|
|
83
86
|
};
|
|
84
87
|
}
|
|
85
|
-
async function probeFirstFrameColour(filePath, runner = execFileRunner) {
|
|
88
|
+
async function probeFirstFrameColour(filePath, codec, runner = execFileRunner) {
|
|
86
89
|
const ffmpegPath = findFfBinary("ffmpeg", { configuredMustExist: true }) ?? (runner === execFileRunner ? void 0 : "ffmpeg");
|
|
87
90
|
if (!ffmpegPath) return {};
|
|
88
91
|
const result = await runner(ffmpegPath, firstFrameColourArgs(filePath), {
|
|
89
92
|
timeout: 15e3,
|
|
90
93
|
maxBuffer: 1024 * 1024
|
|
91
94
|
});
|
|
92
|
-
|
|
95
|
+
const first = result.status === 0 ? parseFirstFrameColour(String(result.stderr)) : {};
|
|
96
|
+
if (result.status !== 0 || !readsKeyframeTransfers(first)) return first;
|
|
97
|
+
const keyframes = await runner(ffmpegPath, keyframeTransferArgs(filePath, codec), {
|
|
98
|
+
timeout: 3e4,
|
|
99
|
+
maxBuffer: 8 * 1024 * 1024
|
|
100
|
+
});
|
|
101
|
+
const keyframeTransfers = keyframes.status === 0 ? parseKeyframeTransfers(String(keyframes.stderr)) : [];
|
|
102
|
+
return { ...first, keyframeTransfers };
|
|
93
103
|
}
|
|
94
104
|
function bitDepthOf(stream) {
|
|
95
105
|
const raw = Number(stream.bits_per_raw_sample);
|
|
@@ -35,6 +35,7 @@ interface AudioNormalizationPlan {
|
|
|
35
35
|
changeDb: number;
|
|
36
36
|
projectedLufs: number;
|
|
37
37
|
projectedTruePeakDbfs: number;
|
|
38
|
+
limitedBy: LoudnessLimit | null;
|
|
38
39
|
}
|
|
39
40
|
/** Read the authored clips with sound — `<audio>` and audible `<video>` — without reserializing. */
|
|
40
41
|
declare function audioTags(html: string): AudioTag[];
|
|
@@ -43,7 +44,7 @@ declare function resolveLocalAudioPath(projectDir: string, src: string): string;
|
|
|
43
44
|
/** Parse FFmpeg's final EBU R128 summary, not its per-window log lines. */
|
|
44
45
|
declare function parseEbur128Summary(stderr: string): LoudnessMeasurement;
|
|
45
46
|
declare function gainDb(volume: number): number;
|
|
46
|
-
/**
|
|
47
|
+
/** The target's gain that matches the reference's played loudness; past a ceiling it stops as fittedGain does. */
|
|
47
48
|
declare function audioNormalizationPlan(referenceTrack: NormalizationTrack, targetTrack: NormalizationTrack): AudioNormalizationPlan;
|
|
48
49
|
/** Patch one authored attribute in place so scripts/styles/comments remain byte-stable. */
|
|
49
50
|
declare function updateAudioVolume(html: string, id: string, volume: number): string;
|
|
@@ -78,9 +79,8 @@ interface AbsoluteLoudnessPlan {
|
|
|
78
79
|
}
|
|
79
80
|
/**
|
|
80
81
|
* The authored gain that brings one clip's played window to an absolute
|
|
81
|
-
* loudness
|
|
82
|
-
*
|
|
83
|
-
* names which limit stopped it.
|
|
82
|
+
* loudness; past the +12 dB authoring ceiling or the true-peak ceiling it
|
|
83
|
+
* applies the most that fits and names which limit stopped it (fittedGain).
|
|
84
84
|
*/
|
|
85
85
|
declare function absoluteLoudnessPlan(track: NormalizationTrack, targetLufs?: number): AbsoluteLoudnessPlan;
|
|
86
86
|
type AbsoluteOutcome = "matched" | "held" | "change";
|
package/dist/helpers/loudness.js
CHANGED
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
requiredFfmpeg,
|
|
13
13
|
resolveLocalAudioPath,
|
|
14
14
|
updateAudioVolume
|
|
15
|
-
} from "../chunk-
|
|
16
|
-
import "../chunk-
|
|
15
|
+
} from "../chunk-NEGQQZNI.js";
|
|
16
|
+
import "../chunk-Y6EZUBYR.js";
|
|
17
17
|
import "../chunk-QF7MFJJU.js";
|
|
18
18
|
import "../chunk-SVQFE44C.js";
|
|
19
19
|
import "../chunk-L3HJVTQE.js";
|
|
@@ -15,8 +15,8 @@ import {
|
|
|
15
15
|
scanProjectMedia,
|
|
16
16
|
scanProjectMediaCodecMap,
|
|
17
17
|
shouldPrewarmProxy
|
|
18
|
-
} from "../chunk-
|
|
19
|
-
import "../chunk-
|
|
18
|
+
} from "../chunk-66YZA32N.js";
|
|
19
|
+
import "../chunk-Y6EZUBYR.js";
|
|
20
20
|
import "../chunk-QF7MFJJU.js";
|
|
21
21
|
import "../chunk-SVQFE44C.js";
|
|
22
22
|
import "../chunk-L3HJVTQE.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import '@hyperframes/core';
|
|
2
|
-
export { a as PreviewApiAdapter, P as PreviewDocumentStore, i as injectMediaCodecMap, f as injectMediaCodecMapIntoHtml, g as isAutoProxyEnabled, p as proxyEtagSalt, r as resolvePreviewMediaCodecProbeCache } from '../mediaProxyPreview-
|
|
2
|
+
export { a as PreviewApiAdapter, P as PreviewDocumentStore, i as injectMediaCodecMap, f as injectMediaCodecMapIntoHtml, g as isAutoProxyEnabled, p as proxyEtagSalt, r as resolvePreviewMediaCodecProbeCache } from '../mediaProxyPreview-pNW7nfS0.js';
|
|
3
3
|
import './mediaCodecMap.js';
|
|
4
4
|
import 'sharp';
|
|
5
5
|
import '@hyperframes/parsers';
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
isAutoProxyEnabled,
|
|
5
5
|
proxyEtagSalt,
|
|
6
6
|
resolvePreviewMediaCodecProbeCache
|
|
7
|
-
} from "../chunk-
|
|
8
|
-
import "../chunk-
|
|
9
|
-
import "../chunk-
|
|
10
|
-
import "../chunk-
|
|
7
|
+
} from "../chunk-IJMPYPJG.js";
|
|
8
|
+
import "../chunk-F4AQECCT.js";
|
|
9
|
+
import "../chunk-66YZA32N.js";
|
|
10
|
+
import "../chunk-Y6EZUBYR.js";
|
|
11
11
|
import "../chunk-QF7MFJJU.js";
|
|
12
12
|
import "../chunk-SVQFE44C.js";
|
|
13
13
|
import "../chunk-L3HJVTQE.js";
|
|
@@ -22,9 +22,9 @@ import {
|
|
|
22
22
|
retryProxyCopy,
|
|
23
23
|
sourceFolderKind,
|
|
24
24
|
waitForProxy
|
|
25
|
-
} from "../chunk-
|
|
26
|
-
import "../chunk-
|
|
27
|
-
import "../chunk-
|
|
25
|
+
} from "../chunk-F4AQECCT.js";
|
|
26
|
+
import "../chunk-66YZA32N.js";
|
|
27
|
+
import "../chunk-Y6EZUBYR.js";
|
|
28
28
|
import "../chunk-QF7MFJJU.js";
|
|
29
29
|
import "../chunk-SVQFE44C.js";
|
|
30
30
|
import "../chunk-L3HJVTQE.js";
|
|
@@ -34,10 +34,13 @@ declare function nextUniqueId(document: Document, base: string, takenIds?: Reado
|
|
|
34
34
|
/** Whether each target exists in `source`; the document is parsed once however many targets ask. */
|
|
35
35
|
declare function probeElementsInSource(source: string, targets: readonly SourceMutationTarget[]): boolean[];
|
|
36
36
|
declare function probeElementInSource(source: string, target: SourceMutationTarget): boolean;
|
|
37
|
+
/** Why a split changed nothing: the cut route says it, so a report names the cause and not just "rejected". */
|
|
38
|
+
type SplitRefusal = "target-not-found" | "reference-without-range" | "no-duration" | "outside-clip";
|
|
37
39
|
interface SplitElementResult {
|
|
38
40
|
html: string;
|
|
39
41
|
matched: boolean;
|
|
40
42
|
newId: string | null;
|
|
43
|
+
refusal?: SplitRefusal;
|
|
41
44
|
}
|
|
42
45
|
declare function splitElementInHtml(source: string, target: SourceMutationTarget, splitTime: number, newId: string, fallbackTiming?: {
|
|
43
46
|
start: number;
|
|
@@ -96,4 +99,4 @@ declare function unwrapElementsFromHtml(source: string, groupTarget: SourceMutat
|
|
|
96
99
|
/** After a cut, give each linked group's right halves their own `data-link` and `data-sync-origin`. */
|
|
97
100
|
declare function relinkSplitHalvesInHtml(source: string, rightHalfIds: readonly string[]): string;
|
|
98
101
|
|
|
99
|
-
export { type ElementRebase, type PatchOperation, type SourceMutationTarget, type SplitElementResult, type UnwrapChildTrack, type UnwrapElementsResult, type WrapElementsResult, dedupeClonedCompositionId, findTargetElement, isHTMLElement, nextUniqueId, parseSourceDocument, patchElementInHtml, probeElementInSource, probeElementsInSource, relinkSplitHalvesInHtml, removeElementFromHtml, removeElementsFromHtml, splitElementInHtml, unwrapElementsFromHtml, wrapElementsInHtml };
|
|
102
|
+
export { type ElementRebase, type PatchOperation, type SourceMutationTarget, type SplitElementResult, type SplitRefusal, type UnwrapChildTrack, type UnwrapElementsResult, type WrapElementsResult, dedupeClonedCompositionId, findTargetElement, isHTMLElement, nextUniqueId, parseSourceDocument, patchElementInHtml, probeElementInSource, probeElementsInSource, relinkSplitHalvesInHtml, removeElementFromHtml, removeElementsFromHtml, splitElementInHtml, unwrapElementsFromHtml, wrapElementsInHtml };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
|
-
import { S as StudioApiAdapter, P as PreviewDocumentStore, M as MediaProcessingJobState } from './mediaProxyPreview-
|
|
3
|
-
export { L as LintResult, a as PreviewApiAdapter, R as RenderJobState, b as ResolvedProject, c as StudioSelectionResponse, d as StudioSelectionSnapshot, e as StudioSelectionTextField } from './mediaProxyPreview-
|
|
2
|
+
import { S as StudioApiAdapter, P as PreviewDocumentStore, M as MediaProcessingJobState } from './mediaProxyPreview-pNW7nfS0.js';
|
|
3
|
+
export { L as LintResult, a as PreviewApiAdapter, R as RenderJobState, b as ResolvedProject, c as StudioSelectionResponse, d as StudioSelectionSnapshot, e as StudioSelectionTextField } from './mediaProxyPreview-pNW7nfS0.js';
|
|
4
4
|
export { C as ClosedWindow, D as DEFAULT_HISTORY_ROOT, S as HISTORY_START, H as HistoryClosedError, a as HistoryEntry, b as HistoryEntrySide, c as HistoryFileChange, d as HistoryListItem, e as HistoryRefusedError, f as HistoryResult, g as HistoryTarget, h as HistoryWho, i as HistoryWindow, M as MAX_WINDOW_IDLE_MS, P as ProjectHistory, j as ProjectHistoryOptions, k as ProjectHistoryView, U as UNDO_MODES, l as UndoMode, o as openProjectHistory, r as readProjectHistory } from './projectHistory-C18HDvac.js';
|
|
5
5
|
export { ArtifactCapture, ArtifactInput, ArtifactRecord, HistoryBusyError, HistoryIdError, InPlaceOutcome, ProjectHistoryRecord, PrunedHistory, ReclaimedHistory, RenderRecord, VideoState, artifactDirectory, beginArtifactCapture, finishSnapshotRun, forgetRecordedArtifacts, historyCache, isUncopiedMedia, listProjectHistories, onRestoredInPlace, pruneGoneProjectHistories, reclaimUncopiedBlobs, recordArtifact, recordArtifacts, recordRenderSuccess, registerRenderOutput, retainSnapshotOutput } from './history/index.js';
|
|
6
6
|
export { CACHE_DIR_NAME as PROXY_CACHE_DIR_NAME } from './helpers/proxyTranscoder.js';
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
splitElementInHtml,
|
|
18
18
|
unwrapElementsFromHtml,
|
|
19
19
|
wrapElementsInHtml
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-REQUL5L4.js";
|
|
21
21
|
import {
|
|
22
22
|
isCompositionSource,
|
|
23
23
|
stampProjectHfIds,
|
|
@@ -85,13 +85,13 @@ import {
|
|
|
85
85
|
requestedProjectPath,
|
|
86
86
|
requiredFfmpeg,
|
|
87
87
|
resolveLocalAudioPath
|
|
88
|
-
} from "./chunk-
|
|
88
|
+
} from "./chunk-NEGQQZNI.js";
|
|
89
89
|
import {
|
|
90
90
|
injectMediaCodecMap,
|
|
91
91
|
isAutoProxyEnabled,
|
|
92
92
|
proxyEtagSalt,
|
|
93
93
|
resolvePreviewMediaCodecProbeCache
|
|
94
|
-
} from "./chunk-
|
|
94
|
+
} from "./chunk-IJMPYPJG.js";
|
|
95
95
|
import {
|
|
96
96
|
CACHE_DIR_NAME,
|
|
97
97
|
PROXY_PENDING_RETRY_AFTER_SECONDS,
|
|
@@ -105,7 +105,7 @@ import {
|
|
|
105
105
|
resolveStill,
|
|
106
106
|
retryProxyCopy,
|
|
107
107
|
waitForProxy
|
|
108
|
-
} from "./chunk-
|
|
108
|
+
} from "./chunk-F4AQECCT.js";
|
|
109
109
|
import {
|
|
110
110
|
PROXY_VARIANT_CONFIG,
|
|
111
111
|
decideMediaProxyEligibility,
|
|
@@ -113,11 +113,11 @@ import {
|
|
|
113
113
|
probeAssetCodec,
|
|
114
114
|
recordProxyRequest,
|
|
115
115
|
resolveProxyVariantRequest
|
|
116
|
-
} from "./chunk-
|
|
116
|
+
} from "./chunk-66YZA32N.js";
|
|
117
117
|
import {
|
|
118
118
|
probeAudioTrack,
|
|
119
119
|
probeMediaMetadata
|
|
120
|
-
} from "./chunk-
|
|
120
|
+
} from "./chunk-Y6EZUBYR.js";
|
|
121
121
|
import {
|
|
122
122
|
folderGone,
|
|
123
123
|
isInHiddenOrVendorDir,
|
|
@@ -2930,6 +2930,12 @@ async function executeGsapMutationRecast(body, block, respond) {
|
|
|
2930
2930
|
return respond({ error: `unknown mutation type: ${body.type}` }, 400);
|
|
2931
2931
|
}
|
|
2932
2932
|
}
|
|
2933
|
+
var CUT_REFUSALS = {
|
|
2934
|
+
"target-not-found": "Cut target was not found",
|
|
2935
|
+
"reference-without-range": "Cut target starts after another clip and the cut sent no range for it",
|
|
2936
|
+
"no-duration": "Cut target has no duration",
|
|
2937
|
+
"outside-clip": "Cut point was outside the clip's start and end"
|
|
2938
|
+
};
|
|
2933
2939
|
async function foldAtomicCutFile(c, file, absPath, before, writer) {
|
|
2934
2940
|
let after = before;
|
|
2935
2941
|
let splitCount = 0;
|
|
@@ -2958,7 +2964,7 @@ async function foldAtomicCutFile(c, file, absPath, before, writer) {
|
|
|
2958
2964
|
});
|
|
2959
2965
|
if (!split.matched || !split.newId) {
|
|
2960
2966
|
return c.json(
|
|
2961
|
-
{ error:
|
|
2967
|
+
{ error: `${CUT_REFUSALS[split.refusal ?? "target-not-found"]} in ${file.path}` },
|
|
2962
2968
|
400
|
|
2963
2969
|
);
|
|
2964
2970
|
}
|
|
@@ -4848,6 +4854,7 @@ function contentDispositionHeader(disposition, filename) {
|
|
|
4848
4854
|
}
|
|
4849
4855
|
function registerRenderRoutes(api, adapter) {
|
|
4850
4856
|
const renderJobs = /* @__PURE__ */ new Map();
|
|
4857
|
+
const CANCEL_SETTLE_MS = 45e3;
|
|
4851
4858
|
const nextFreeRenderJobId = (baseId, ext, rendersDir) => {
|
|
4852
4859
|
let jobId = baseId;
|
|
4853
4860
|
for (let n = 2; renderJobs.has(jobId) || existsSync6(join10(rendersDir, `${jobId}${ext}`)); n++) {
|
|
@@ -4965,13 +4972,19 @@ function registerRenderRoutes(api, adapter) {
|
|
|
4965
4972
|
}
|
|
4966
4973
|
});
|
|
4967
4974
|
});
|
|
4968
|
-
api.post("/render/:jobId/cancel", (c) => {
|
|
4975
|
+
api.post("/render/:jobId/cancel", async (c) => {
|
|
4969
4976
|
const { jobId } = c.req.param();
|
|
4970
4977
|
const job = renderJobs.get(jobId);
|
|
4971
4978
|
if (!job) return c.json({ error: "not found" }, 404);
|
|
4972
4979
|
if (job.status === "rendering") {
|
|
4973
4980
|
job.status = "cancelled";
|
|
4974
|
-
|
|
4981
|
+
let giveUp;
|
|
4982
|
+
const late = new Promise((done) => giveUp = setTimeout(done, CANCEL_SETTLE_MS));
|
|
4983
|
+
try {
|
|
4984
|
+
await Promise.race([job.cancel?.(), late]);
|
|
4985
|
+
} finally {
|
|
4986
|
+
clearTimeout(giveUp);
|
|
4987
|
+
}
|
|
4975
4988
|
}
|
|
4976
4989
|
return c.json({ status: job.status });
|
|
4977
4990
|
});
|
|
@@ -27,7 +27,7 @@ interface RenderJobState {
|
|
|
27
27
|
* stop an in-flight render; adapters that can't abort may omit it (the
|
|
28
28
|
* route still marks the job cancelled so the SSE stream terminates).
|
|
29
29
|
*/
|
|
30
|
-
cancel?: () => void
|
|
30
|
+
cancel?: () => void | Promise<void>;
|
|
31
31
|
}
|
|
32
32
|
interface MediaProcessingJobState {
|
|
33
33
|
id: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio-server",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.17",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/heygen-com/hyperframes",
|
|
@@ -88,8 +88,8 @@
|
|
|
88
88
|
"linkedom": "^0.18.12",
|
|
89
89
|
"postcss": "^8.5.8",
|
|
90
90
|
"postcss-selector-parser": "^7.1.2",
|
|
91
|
-
"@hyperframes/
|
|
92
|
-
"@hyperframes/
|
|
91
|
+
"@hyperframes/parsers": "0.9.17",
|
|
92
|
+
"@hyperframes/core": "0.9.17"
|
|
93
93
|
},
|
|
94
94
|
"devDependencies": {
|
|
95
95
|
"@types/node": "^25.0.10",
|