Skip to content

Commit e70687b

Browse files
fix(player): resolve iframe media src against iframe baseURI (heygen-com#295)
## Summary `_setupParentMedia` scans the iframe for `audio[data-start]` / `video[data-start]` and creates parallel media elements in the host document (so the studio can scrub audio at sub-frame precision without iframe cross-origin restrictions). It was reading the raw `src` attribute string and assigning it directly to the host-document element, which then resolved relative URLs against the **studio root** instead of the **iframe**. Result: a composition like \`\`\`html <audio id="narration" data-start="0" data-duration="53" src="assets/narration.wav"></audio> \`\`\` played fine in rendered MP4 output but 404'd silently in the studio preview (parent audio got `src = http://localhost:PORT/assets/narration.wav` instead of `http://localhost:PORT/api/projects/<name>/preview/assets/narration.wav`). ## Fix Resolve the src against \`iframeEl.ownerDocument.baseURI\` before passing it to \`_createParentMedia\`. Also read the raw \`src\` attribute on \`<source>\` fallbacks so both paths go through the same resolution. Diff is 2 lines of meaningful change (9 total once you include the comment). ## Reproduction 1. Create a project with a narration at \`assets/narration.wav\` 2. Reference it in \`index.html\` with \`<audio data-start="0" data-duration="53" src="assets/narration.wav">\` 3. \`npx hyperframes preview\` → open, click play 4. Before: silent (parent audio's \`error.code === 4\` / \`MEDIA_ERR_SRC_NOT_SUPPORTED\`) 5. After: narration plays, scrubbing syncs ## Test plan - [x] Existing 21 player tests pass (`bun run --filter=@hyperframes/player test`) - [x] oxlint + oxfmt clean on changed file - [x] Manual: verified in-studio playback of a narration sourced via relative URL - [x] Reviewer: confirm render pipeline unaffected (render doesn't go through `_setupParentMedia`) ## Notes No tests added for this path because the existing harness covers only the `audio-src` attribute codepath — `_setupParentMedia` is triggered by an internal probe interval against a live iframe, which the current fixture doesn't build. Happy to add one in a follow-up if reviewers want that coverage before merge.
1 parent 6078077 commit e70687b

1 file changed

Lines changed: 9 additions & 2 deletions

File tree

packages/player/src/hyperframes-player.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -563,8 +563,15 @@ class HyperframesPlayer extends HTMLElement {
563563
);
564564

565565
for (const iframeEl of mediaEls) {
566-
const src = iframeEl.getAttribute("src") || iframeEl.querySelector("source")?.src;
567-
if (!src) continue;
566+
const rawSrc =
567+
iframeEl.getAttribute("src") || iframeEl.querySelector("source")?.getAttribute("src");
568+
if (!rawSrc) continue;
569+
570+
// Resolve against the iframe's baseURI. The parent-frame <audio>/<video>
571+
// we create next lives in the host document, whose base URL differs from
572+
// the iframe's — without this, a relative src like "assets/narration.wav"
573+
// would resolve against the studio root and 404.
574+
const src = new URL(rawSrc, iframeEl.ownerDocument.baseURI).href;
568575

569576
const start = parseFloat(iframeEl.getAttribute("data-start") || "0");
570577
const duration = parseFloat(iframeEl.getAttribute("data-duration") || "Infinity");

0 commit comments

Comments
 (0)