mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-12 15:20:13 +00:00
fix(engine): resolve root-absolute media from project (#2399)
This commit is contained in:
@@ -438,6 +438,38 @@ describe("processCompositionAudio", () => {
|
||||
const prepareArgs = runFfmpegMock.mock.calls[0]?.[0];
|
||||
expect(prepareArgs).toContain(join(baseDir, "assets", filename));
|
||||
});
|
||||
|
||||
it("prepares browser root-absolute audio srcs from the project root", async () => {
|
||||
const baseDir = mkdtempSync(join(tmpdir(), "hf-audio-base-"));
|
||||
const workDir = mkdtempSync(join(tmpdir(), "hf-audio-work-"));
|
||||
tempDirs.push(baseDir, workDir);
|
||||
|
||||
mkdirSync(join(baseDir, ".media"), { recursive: true });
|
||||
writeFileSync(join(baseDir, ".media", "tone.wav"), "stub");
|
||||
|
||||
const result = await processCompositionAudio(
|
||||
[
|
||||
{
|
||||
id: "tone",
|
||||
src: "/.media/tone.wav",
|
||||
start: 0,
|
||||
end: 1,
|
||||
mediaStart: 0,
|
||||
layer: 0,
|
||||
volume: 1,
|
||||
type: "audio",
|
||||
},
|
||||
],
|
||||
baseDir,
|
||||
workDir,
|
||||
join(baseDir, "out.m4a"),
|
||||
1,
|
||||
);
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.error).toBeUndefined();
|
||||
expect(runFfmpegMock.mock.calls[0]?.[0]).toContain(join(baseDir, ".media", "tone.wav"));
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseAudioElements — relative data-start resolution", () => {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import { closeSync, existsSync, mkdirSync, mkdtempSync, openSync, rmSync, writeFileSync } from "fs";
|
||||
import { isAbsolute, join, dirname } from "path";
|
||||
import { join, dirname } from "path";
|
||||
import { parseHTML } from "linkedom";
|
||||
import { extractAudioMetadata } from "../utils/ffprobe.js";
|
||||
import { downloadToTemp, isHttpUrl } from "../utils/urlDownloader.js";
|
||||
@@ -530,7 +530,7 @@ export async function processCompositionAudio(
|
||||
}
|
||||
try {
|
||||
let srcPath = element.src;
|
||||
if (!isAbsolute(srcPath) && !isHttpUrl(srcPath)) {
|
||||
if (!isHttpUrl(srcPath)) {
|
||||
// Same browser-vs-filesystem path semantics as videos — see
|
||||
// resolveProjectRelativeSrc in videoFrameExtractor for the full why.
|
||||
srcPath = resolveProjectRelativeSrc(element.src, baseDir, compiledDir);
|
||||
|
||||
@@ -143,6 +143,13 @@ describe("resolveProjectRelativeSrc — sub-composition path clamping", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("resolves a browser root-absolute URL from the project root", () => {
|
||||
const projectDir = join(tmp, "project");
|
||||
expect(resolveProjectRelativeSrc("/assets/foo.mp4", projectDir)).toBe(
|
||||
join(projectDir, "assets/foo.mp4"),
|
||||
);
|
||||
});
|
||||
|
||||
it("clamps a leading `../` so `../assets/foo.mp4` resolves to assets/foo.mp4", () => {
|
||||
const projectDir = join(tmp, "project");
|
||||
expect(resolveProjectRelativeSrc("../assets/foo.mp4", projectDir)).toBe(
|
||||
|
||||
@@ -670,6 +670,12 @@ export function resolveProjectRelativeSrc(
|
||||
): string {
|
||||
const qIdx = src.indexOf("?");
|
||||
const cleanSrc = qIdx >= 0 ? src.slice(0, qIdx) : src;
|
||||
|
||||
// Preserve explicit filesystem paths when they really exist. Otherwise a
|
||||
// leading slash is a browser origin-root URL (`/assets/foo.mp4`), which the
|
||||
// file server serves from the project root rather than the host filesystem.
|
||||
if (isAbsolute(cleanSrc) && existsSync(cleanSrc)) return cleanSrc;
|
||||
|
||||
const candidates: string[] = [];
|
||||
|
||||
const addCandidate = (candidate: string): void => {
|
||||
@@ -746,11 +752,7 @@ export async function extractAllVideoFrames(
|
||||
if (signal?.aborted) break;
|
||||
try {
|
||||
let videoPath = video.src;
|
||||
// Use isAbsolute() rather than startsWith("/"). On Windows, absolute paths
|
||||
// like "C:\…" are not detected by the latter, so we'd re-join them under
|
||||
// baseDir and produce duplicated, nonexistent paths
|
||||
// (e.g. C:\tmp\hf-vfr-test-X\C:\tmp\hf-vfr-test-X\vfr_screen.mp4).
|
||||
if (!isAbsolute(videoPath) && !isHttpUrl(videoPath)) {
|
||||
if (!isHttpUrl(videoPath)) {
|
||||
videoPath = resolveProjectRelativeSrc(video.src, baseDir, compiledDir);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user