fix(skills): loop-extended BGM writes .mp3, not MP3-in-a-.wav - #3884
Merged
Conversation
miguel-heygen
approved these changes
Sep 11, 2026
ensureBgmCovers() (duplicated in faceless-explainer, pr-to-video, and product-launch-video's assemble-index.mjs) always re-encodes a short BGM track with libmp3lame, but preserved the source asset's own extension when naming the loop-extended output — so a "bgm.wav" source produced "bgm.loop.wav" containing genuine MP3 audio. ffprobe/ffmpeg/Chromium all decode this correctly via the WAVE_FORMAT_MPEGLAYER3 tag, but a naive/strict WAV parser (e.g. Python's stdlib `wave` module) hard-fails on it. The function's own doc comment already documented the intended output as "*.loop.mp3" — the code just didn't match it. Fix: always emit a .loop.mp3 path regardless of the source extension. music-to-video's assemble-index.mjs does not have this function (it uses the raw BGM asset directly, no loop-extension), so only 3 of the 4 skills needed the change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
miga-heygen
force-pushed
the
fix/bgm-loop-mp3-wav-extension-mismatch
branch
from
September 11, 2026 19:58
979ab2b to
fd2170f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ensureBgmCovers()— duplicated acrossskills/{faceless-explainer,pr-to-video,product-launch-video}/scripts/assemble-index.mjs— always re-encodes a short BGM track withlibmp3lamewhen loop-extending it to cover the video's full duration, but named the output by preserving the source asset's own extension. Abgm.wavsource therefore producedbgm.loop.wavcontaining genuine MP3 audio: a real container/codec mismatch.<audio>via CDP) all decode this file correctly today, because ffmpeg's WAV muxer tags itWAVE_FORMAT_MPEGLAYER3and every consumer in HyperFrames' own pipeline goes through ffprobe/ffmpeg. So the originally-reported symptom (wrong/short duration, silent tail) does not reproduce with the current toolchain — this is a landmine for any future/adjacent naive WAV parser (e.g. Python's stdlibwavemodule, which hard-fails on format tag0x55), not a currently-triggered bug.*.loop.mp3and return that path" — the code just didn't match its own comment..loop.mp3path regardless of the source extension.music-to-video'sassemble-index.mjsdoes not have this function — it mounts the raw BGM asset directly with no loop-extension step — so only 3 of the 4 skills needed the change.Explicitly out of scope
langApplieddiagnostic gap — different piece of work.Test plan
assemble-index.test.mjsfiles ({ skip: !HAS_FFMPEG }, following the existingdither.test.mjsguard pattern): generates a real 1s WAV tone viaffmpeg -f lavfi, runs the actual assemble script against a storyboard whose TOTAL (3s) forces the loop-extend branch, then asserts the emitted<audio id="el-bgm">src ends in.mp3(not.wav) and that the file at that path really does decode ascodec_name=mp3viaffprobe.AssertionError: bgm src should end in .mp3, got "assets/bgm/bed.loop.wav") and passes against the fix.node --teston all 3 modified test files: 12/12 pass.bunx oxlint+bunx oxfmt --writeon all 6 changed files: clean, no reformatting needed beyond the authored diff.bunx fallow audit --base origin/main --fail-on-issues: clean, 0 issues across 6 changed files.🤖 Generated with Claude Code