@hyperframes/studio-server 0.9.5 → 0.9.7
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-CEQWOCYI.js → chunk-BAJ6HKBU.js} +45 -5
- package/dist/{chunk-PN2VGFAA.js → chunk-J4SRRKQU.js} +2 -2
- package/dist/{chunk-FUTDRYQK.js → chunk-NOIHVBIQ.js} +2 -0
- package/dist/helpers/mediaCodecMap.d.ts +2 -1
- package/dist/helpers/mediaCodecMap.js +3 -1
- package/dist/helpers/mediaProxyPreview.js +3 -3
- package/dist/helpers/proxyTranscoder.d.ts +3 -1
- package/dist/helpers/proxyTranscoder.js +4 -2
- package/dist/index.js +33 -5
- package/package.json +3 -3
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
+
PROXY_STILL_EXTENSION,
|
|
2
3
|
PROXY_VARIANT_CONFIG,
|
|
3
4
|
ffmpegHasHdrFilters
|
|
4
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-NOIHVBIQ.js";
|
|
5
6
|
import {
|
|
6
7
|
probeFirstFrameColour,
|
|
7
8
|
probeMediaMetadata
|
|
@@ -36,9 +37,10 @@ import { extname, join } from "path";
|
|
|
36
37
|
var DEFAULT_MAX_BYTES = 10 * 1024 * 1024 * 1024;
|
|
37
38
|
var DEFAULT_STALE_TEMP_MS = 60 * 60 * 1e3;
|
|
38
39
|
var DEFAULT_MIN_SWEEP_INTERVAL_MS = 5 * 60 * 1e3;
|
|
39
|
-
var PROXY_EXTENSIONS = new Set(
|
|
40
|
-
Object.values(PROXY_VARIANT_CONFIG).map(({ extension }) => extension)
|
|
41
|
-
|
|
40
|
+
var PROXY_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
41
|
+
...Object.values(PROXY_VARIANT_CONFIG).map(({ extension }) => extension),
|
|
42
|
+
PROXY_STILL_EXTENSION
|
|
43
|
+
]);
|
|
42
44
|
var TRANSCODER_PROXY_NAME = /^[0-9a-f]{64}\.\w+$/;
|
|
43
45
|
var TRANSCODER_TEMP_NAME = /^\.tmp-[0-9a-f-]{36}-(?:\.part-[0-9a-f]{64}-\d+|[0-9a-f]{64})\.\w+$/;
|
|
44
46
|
var TRANSCODER_PIECE_NAME = /^\.part-([0-9a-f]{64})-\d+(\.\w+)$/;
|
|
@@ -1082,6 +1084,43 @@ async function resolveProxies(projectDir, sources, onSettled = () => {
|
|
|
1082
1084
|
await Promise.all(Array.from({ length: workers }, worker));
|
|
1083
1085
|
return results;
|
|
1084
1086
|
}
|
|
1087
|
+
var stillsInFlight = /* @__PURE__ */ new Map();
|
|
1088
|
+
function resolveStill(projectDir, absoluteSourcePath, atSeconds, box) {
|
|
1089
|
+
const source = canonicalizeProxySource(projectDir, absoluteSourcePath);
|
|
1090
|
+
const at = Math.max(0, Math.round(atSeconds * 10) / 10);
|
|
1091
|
+
const key = fastCopyKey(source.sourcePath, PROXY_PARAMS_VERSION, `still@${at}`, box);
|
|
1092
|
+
const cachePath = join4(source.projectDir, CACHE_DIR_NAME, `${key}${PROXY_STILL_EXTENSION}`);
|
|
1093
|
+
if (existsSync4(cachePath)) return Promise.resolve(cachePath);
|
|
1094
|
+
const shared = stillsInFlight.get(cachePath);
|
|
1095
|
+
if (shared) return shared;
|
|
1096
|
+
const made = makeStill(source, at, box, cachePath).finally(
|
|
1097
|
+
() => stillsInFlight.delete(cachePath)
|
|
1098
|
+
);
|
|
1099
|
+
stillsInFlight.set(cachePath, made);
|
|
1100
|
+
return made;
|
|
1101
|
+
}
|
|
1102
|
+
async function makeStill(source, at, box, cachePath) {
|
|
1103
|
+
const ffmpegPath = findFfBinary("ffmpeg", { configuredMustExist: true });
|
|
1104
|
+
if (!ffmpegPath) throw new FfmpegUnavailableError();
|
|
1105
|
+
const filter = await buildVideoFilter(
|
|
1106
|
+
ffmpegPath,
|
|
1107
|
+
source.sourcePath,
|
|
1108
|
+
await probeMediaMetadata(source.sourcePath),
|
|
1109
|
+
false,
|
|
1110
|
+
box
|
|
1111
|
+
);
|
|
1112
|
+
mkdirWithinProject(source.projectDir, dirname3(cachePath));
|
|
1113
|
+
const tempPath = join4(dirname3(cachePath), `.tmp-${randomUUID()}-${basename3(cachePath)}`);
|
|
1114
|
+
try {
|
|
1115
|
+
const args = ["-y", "-ss", String(at), "-i", source.sourcePath, "-map", "0:V:0"];
|
|
1116
|
+
args.push("-frames:v", "1", "-vf", filter, "-pix_fmt", "yuvj420p", "-q:v", "3", tempPath);
|
|
1117
|
+
await spawnFfmpeg(ffmpegPath, args, TRANSCODE_STALL_MS, new AbortController().signal);
|
|
1118
|
+
renameSync(tempPath, cachePath);
|
|
1119
|
+
} finally {
|
|
1120
|
+
rmSync2(tempPath, { force: true });
|
|
1121
|
+
}
|
|
1122
|
+
return cachePath;
|
|
1123
|
+
}
|
|
1085
1124
|
function joinJob(promise, job, signal) {
|
|
1086
1125
|
job.callers++;
|
|
1087
1126
|
if (!signal) return promise;
|
|
@@ -1117,5 +1156,6 @@ export {
|
|
|
1117
1156
|
retryProxyCopy,
|
|
1118
1157
|
proxyActivityMark,
|
|
1119
1158
|
resolveProxy,
|
|
1120
|
-
resolveProxies
|
|
1159
|
+
resolveProxies,
|
|
1160
|
+
resolveStill
|
|
1121
1161
|
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PROXY_PARAMS_VERSION,
|
|
3
3
|
resolveProxy
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BAJ6HKBU.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-NOIHVBIQ.js";
|
|
12
12
|
|
|
13
13
|
// src/helpers/mediaProxyPreview.ts
|
|
14
14
|
import { resolve } from "path";
|
|
@@ -98,6 +98,7 @@ var PROXY_VARIANT_CONFIG = {
|
|
|
98
98
|
h264: { extension: ".mp4", contentType: "video/mp4" },
|
|
99
99
|
vp8: { extension: ".webm", contentType: "video/webm" }
|
|
100
100
|
};
|
|
101
|
+
var PROXY_STILL_EXTENSION = ".jpg";
|
|
101
102
|
function isProxyVariant(value) {
|
|
102
103
|
return Object.hasOwn(PROXY_VARIANT_CONFIG, value);
|
|
103
104
|
}
|
|
@@ -252,6 +253,7 @@ export {
|
|
|
252
253
|
recordProxyPrewarm,
|
|
253
254
|
recordProxyRequest,
|
|
254
255
|
PROXY_VARIANT_CONFIG,
|
|
256
|
+
PROXY_STILL_EXTENSION,
|
|
255
257
|
isProxyVariant,
|
|
256
258
|
isProxyVariantRequest,
|
|
257
259
|
proxyVariantFor,
|
|
@@ -89,6 +89,7 @@ declare const PROXY_VARIANT_CONFIG: Record<ProxyVariant, {
|
|
|
89
89
|
extension: ".mp4" | ".webm";
|
|
90
90
|
contentType: "video/mp4" | "video/webm";
|
|
91
91
|
}>;
|
|
92
|
+
declare const PROXY_STILL_EXTENSION = ".jpg";
|
|
92
93
|
declare function isProxyVariant(value: string): value is ProxyVariant;
|
|
93
94
|
declare function isProxyVariantRequest(value: string): value is ProxyVariantRequest;
|
|
94
95
|
declare function proxyVariantFor(facts: AssetCodecFacts): ProxyVariant;
|
|
@@ -144,4 +145,4 @@ declare function scanProjectMedia(projectDir: string, htmlSources: HtmlSourceLik
|
|
|
144
145
|
/** The injection map alone: root-relative URL pathname -> codec facts of the hostile videos. */
|
|
145
146
|
declare function scanProjectMediaCodecMap(projectDir: string, htmlSources: HtmlSourceLike[], options?: ScanProjectMediaCodecMapOptions): Promise<MediaCodecMap>;
|
|
146
147
|
|
|
147
|
-
export { type AssetCodecFacts, BROWSER_HOSTILE_CODECS, type BrowserHostileCodec, type HtmlSourceLike, type MediaCodecMap, type MediaCodecProbeCache, type MediaProxyEligibility, type MediaProxyIneligibilityReason, PROXY_VARIANT_CONFIG, type ProjectMediaScan, type ProxyVariant, type ProxyVariantRequest, type ScanProjectMediaCodecMapOptions, createMediaCodecProbeCache, decideMediaProxyEligibility, isProxyVariant, isProxyVariantRequest, mediaProxyDemand, probeAssetCodec, proxyVariantFor, recordProxyPrewarm, recordProxyRequest, resolveProxyVariantRequest, scanProjectMedia, scanProjectMediaCodecMap, shouldPrewarmProxy };
|
|
148
|
+
export { type AssetCodecFacts, BROWSER_HOSTILE_CODECS, type BrowserHostileCodec, type HtmlSourceLike, type MediaCodecMap, type MediaCodecProbeCache, type MediaProxyEligibility, type MediaProxyIneligibilityReason, PROXY_STILL_EXTENSION, PROXY_VARIANT_CONFIG, type ProjectMediaScan, type ProxyVariant, type ProxyVariantRequest, type ScanProjectMediaCodecMapOptions, createMediaCodecProbeCache, decideMediaProxyEligibility, isProxyVariant, isProxyVariantRequest, mediaProxyDemand, probeAssetCodec, proxyVariantFor, recordProxyPrewarm, recordProxyRequest, resolveProxyVariantRequest, scanProjectMedia, scanProjectMediaCodecMap, shouldPrewarmProxy };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BROWSER_HOSTILE_CODECS,
|
|
3
|
+
PROXY_STILL_EXTENSION,
|
|
3
4
|
PROXY_VARIANT_CONFIG,
|
|
4
5
|
createMediaCodecProbeCache,
|
|
5
6
|
decideMediaProxyEligibility,
|
|
@@ -14,13 +15,14 @@ import {
|
|
|
14
15
|
scanProjectMedia,
|
|
15
16
|
scanProjectMediaCodecMap,
|
|
16
17
|
shouldPrewarmProxy
|
|
17
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-NOIHVBIQ.js";
|
|
18
19
|
import "../chunk-X73QTST2.js";
|
|
19
20
|
import "../chunk-QF7MFJJU.js";
|
|
20
21
|
import "../chunk-SVQFE44C.js";
|
|
21
22
|
import "../chunk-L3HJVTQE.js";
|
|
22
23
|
export {
|
|
23
24
|
BROWSER_HOSTILE_CODECS,
|
|
25
|
+
PROXY_STILL_EXTENSION,
|
|
24
26
|
PROXY_VARIANT_CONFIG,
|
|
25
27
|
createMediaCodecProbeCache,
|
|
26
28
|
decideMediaProxyEligibility,
|
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
isAutoProxyEnabled,
|
|
5
5
|
proxyEtagSalt,
|
|
6
6
|
resolvePreviewMediaCodecProbeCache
|
|
7
|
-
} from "../chunk-
|
|
8
|
-
import "../chunk-
|
|
9
|
-
import "../chunk-
|
|
7
|
+
} from "../chunk-J4SRRKQU.js";
|
|
8
|
+
import "../chunk-BAJ6HKBU.js";
|
|
9
|
+
import "../chunk-NOIHVBIQ.js";
|
|
10
10
|
import "../chunk-X73QTST2.js";
|
|
11
11
|
import "../chunk-QF7MFJJU.js";
|
|
12
12
|
import "../chunk-SVQFE44C.js";
|
|
@@ -87,6 +87,8 @@ declare function resolveProxies(projectDir: string, sources: ReadonlyArray<{
|
|
|
87
87
|
variant: ProxyVariant;
|
|
88
88
|
box?: PreviewProxyBox;
|
|
89
89
|
}>, onSettled?: (index: number) => void, onProgress?: (index: number, progress: ProxyProgress) => void, signal?: AbortSignal): Promise<PromiseSettledResult<string>[]>;
|
|
90
|
+
/** One JPEG of the source at a time (to a tenth of a second), sized like the copy's box. */
|
|
91
|
+
declare function resolveStill(projectDir: string, absoluteSourcePath: string, atSeconds: number, box?: PreviewProxyBox): Promise<string>;
|
|
90
92
|
interface ResolveProxyOptions {
|
|
91
93
|
priority?: boolean;
|
|
92
94
|
background?: boolean;
|
|
@@ -95,4 +97,4 @@ interface ResolveProxyOptions {
|
|
|
95
97
|
onProgress?: (progress: ProxyProgress) => void;
|
|
96
98
|
}
|
|
97
99
|
|
|
98
|
-
export { CACHE_DIR_NAME, DEFAULT_PROXY_WAIT_TIMEOUT_MS, FfmpegMissingFilterError, FfmpegUnavailableError, PROXY_CHUNK_SECONDS, PROXY_PARAMS_VERSION, PROXY_PENDING_RETRY_AFTER_SECONDS, ProxyCapacityError, type ProxyProgress, ProxySourceOutsideProjectError, ProxyTranscodeError, ProxyWaitTimeoutError, type ResolveProxyOptions, type SourceFolderKind, TRANSCODE_STALL_MS, clearFailedTranscodesForTest, getProxyCachePath, proxyActivityMark, proxyCopyProgress, resolveProxies, resolveProxy, retryProxyCopy, sourceFolderKind, waitForProxy };
|
|
100
|
+
export { CACHE_DIR_NAME, DEFAULT_PROXY_WAIT_TIMEOUT_MS, FfmpegMissingFilterError, FfmpegUnavailableError, PROXY_CHUNK_SECONDS, PROXY_PARAMS_VERSION, PROXY_PENDING_RETRY_AFTER_SECONDS, ProxyCapacityError, type ProxyProgress, ProxySourceOutsideProjectError, ProxyTranscodeError, ProxyWaitTimeoutError, type ResolveProxyOptions, type SourceFolderKind, TRANSCODE_STALL_MS, clearFailedTranscodesForTest, getProxyCachePath, proxyActivityMark, proxyCopyProgress, resolveProxies, resolveProxy, resolveStill, retryProxyCopy, sourceFolderKind, waitForProxy };
|
|
@@ -17,11 +17,12 @@ import {
|
|
|
17
17
|
proxyCopyProgress,
|
|
18
18
|
resolveProxies,
|
|
19
19
|
resolveProxy,
|
|
20
|
+
resolveStill,
|
|
20
21
|
retryProxyCopy,
|
|
21
22
|
sourceFolderKind,
|
|
22
23
|
waitForProxy
|
|
23
|
-
} from "../chunk-
|
|
24
|
-
import "../chunk-
|
|
24
|
+
} from "../chunk-BAJ6HKBU.js";
|
|
25
|
+
import "../chunk-NOIHVBIQ.js";
|
|
25
26
|
import "../chunk-X73QTST2.js";
|
|
26
27
|
import "../chunk-QF7MFJJU.js";
|
|
27
28
|
import "../chunk-SVQFE44C.js";
|
|
@@ -45,6 +46,7 @@ export {
|
|
|
45
46
|
proxyCopyProgress,
|
|
46
47
|
resolveProxies,
|
|
47
48
|
resolveProxy,
|
|
49
|
+
resolveStill,
|
|
48
50
|
retryProxyCopy,
|
|
49
51
|
sourceFolderKind,
|
|
50
52
|
waitForProxy
|
package/dist/index.js
CHANGED
|
@@ -91,7 +91,7 @@ import {
|
|
|
91
91
|
isAutoProxyEnabled,
|
|
92
92
|
proxyEtagSalt,
|
|
93
93
|
resolvePreviewMediaCodecProbeCache
|
|
94
|
-
} from "./chunk-
|
|
94
|
+
} from "./chunk-J4SRRKQU.js";
|
|
95
95
|
import {
|
|
96
96
|
CACHE_DIR_NAME,
|
|
97
97
|
PROXY_PENDING_RETRY_AFTER_SECONDS,
|
|
@@ -102,9 +102,10 @@ import {
|
|
|
102
102
|
proxyActivityMark,
|
|
103
103
|
proxyCopyProgress,
|
|
104
104
|
resolveProxy,
|
|
105
|
+
resolveStill,
|
|
105
106
|
retryProxyCopy,
|
|
106
107
|
waitForProxy
|
|
107
|
-
} from "./chunk-
|
|
108
|
+
} from "./chunk-BAJ6HKBU.js";
|
|
108
109
|
import {
|
|
109
110
|
PROXY_VARIANT_CONFIG,
|
|
110
111
|
decideMediaProxyEligibility,
|
|
@@ -112,7 +113,7 @@ import {
|
|
|
112
113
|
probeAssetCodec,
|
|
113
114
|
recordProxyRequest,
|
|
114
115
|
resolveProxyVariantRequest
|
|
115
|
-
} from "./chunk-
|
|
116
|
+
} from "./chunk-NOIHVBIQ.js";
|
|
116
117
|
import {
|
|
117
118
|
probeAudioTrack,
|
|
118
119
|
probeMediaMetadata
|
|
@@ -3940,6 +3941,7 @@ import {
|
|
|
3940
3941
|
PREVIEW_PROXY_PRIORITY_HEADER,
|
|
3941
3942
|
PREVIEW_PROXY_PROGRESS_HEADER,
|
|
3942
3943
|
PREVIEW_PROXY_RETRY_PARAM,
|
|
3944
|
+
PREVIEW_PROXY_STILL_PARAM,
|
|
3943
3945
|
parsePreviewProxyBox
|
|
3944
3946
|
} from "@hyperframes/core";
|
|
3945
3947
|
import {
|
|
@@ -4624,6 +4626,22 @@ ${etag}`;
|
|
|
4624
4626
|
return c.text("media proxy variant does not match asset", 422);
|
|
4625
4627
|
}
|
|
4626
4628
|
}
|
|
4629
|
+
const stillParam = c.req.query(PREVIEW_PROXY_STILL_PARAM);
|
|
4630
|
+
if (stillParam !== void 0) {
|
|
4631
|
+
const at = Number(stillParam);
|
|
4632
|
+
if (stillParam === "" || !Number.isFinite(at) || at < 0 || !proxyVariant) {
|
|
4633
|
+
return c.text("not found", 404);
|
|
4634
|
+
}
|
|
4635
|
+
try {
|
|
4636
|
+
const still = await resolveStill(project.dir, file, at, proxyBox);
|
|
4637
|
+
return new Response(readFileSync6(still), {
|
|
4638
|
+
headers: { "Content-Type": "image/jpeg", "Cache-Control": "private, max-age=3600" }
|
|
4639
|
+
});
|
|
4640
|
+
} catch (err) {
|
|
4641
|
+
if (isProjectRootMissing(err)) throw err;
|
|
4642
|
+
return c.text("media still failed", 502);
|
|
4643
|
+
}
|
|
4644
|
+
}
|
|
4627
4645
|
const tag = settledFileTag(stat2);
|
|
4628
4646
|
const etag = tag && `"${tag}${proxyEtagSalt(proxyVariant, proxyBox)}"`;
|
|
4629
4647
|
const cacheHeaders = isText ? { "Cache-Control": "no-store" } : { "Cache-Control": "private, no-cache", ...etag && { ETag: etag } };
|
|
@@ -4806,6 +4824,13 @@ function contentDispositionHeader(disposition, filename) {
|
|
|
4806
4824
|
}
|
|
4807
4825
|
function registerRenderRoutes(api, adapter) {
|
|
4808
4826
|
const renderJobs = /* @__PURE__ */ new Map();
|
|
4827
|
+
const nextFreeRenderJobId = (baseId, ext, rendersDir) => {
|
|
4828
|
+
let jobId = baseId;
|
|
4829
|
+
for (let n = 2; renderJobs.has(jobId) || existsSync6(join10(rendersDir, `${jobId}${ext}`)); n++) {
|
|
4830
|
+
jobId = `${baseId}-${n}`;
|
|
4831
|
+
}
|
|
4832
|
+
return jobId;
|
|
4833
|
+
};
|
|
4809
4834
|
const TTL_MS = 3e5;
|
|
4810
4835
|
const CLEANUP_INTERVAL_MS = 6e4;
|
|
4811
4836
|
let cleanupTimer = null;
|
|
@@ -4869,11 +4894,14 @@ function registerRenderRoutes(api, adapter) {
|
|
|
4869
4894
|
return c.json({ error: "pageMotionBlur must be off when supplied" }, 400);
|
|
4870
4895
|
}
|
|
4871
4896
|
const pageMotionBlur = requestedPageMotionBlur === void 0 && body.previewMotionBlur === false ? "off" : requestedPageMotionBlur;
|
|
4872
|
-
const now = /* @__PURE__ */ new Date();
|
|
4873
|
-
const jobId = `${project.id}_${formatRenderOutputTimestamp(now)}`;
|
|
4874
4897
|
const rendersDir = adapter.rendersDir(project);
|
|
4875
4898
|
mkdirWithinProject(project.dir, rendersDir);
|
|
4876
4899
|
const ext = FORMAT_EXT[format] ?? ".mp4";
|
|
4900
|
+
const jobId = nextFreeRenderJobId(
|
|
4901
|
+
`${project.id}_${formatRenderOutputTimestamp(/* @__PURE__ */ new Date())}`,
|
|
4902
|
+
ext,
|
|
4903
|
+
rendersDir
|
|
4904
|
+
);
|
|
4877
4905
|
const outputPath = join10(rendersDir, `${jobId}${ext}`);
|
|
4878
4906
|
const jobState = adapter.startRender({
|
|
4879
4907
|
project,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio-server",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.7",
|
|
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.7",
|
|
92
|
+
"@hyperframes/core": "0.9.7"
|
|
93
93
|
},
|
|
94
94
|
"devDependencies": {
|
|
95
95
|
"@types/node": "^25.0.10",
|