Dubbing a video URL on Windows (v0.3.8) failed with 'You have requested merging of multiple formats but ffmpeg is not installed.' The download format selector pulls separate video+audio streams, so yt-dlp muxes them via ffmpeg (merge_output_format=mp4) — but yt-dlp only checks PATH, while OmniVoice's ffmpeg is typically a bundled Tauri sidecar / imageio-ffmpeg binary that isn't on PATH. yt_download_sync now sets ydl_opts['ffmpeg_location'] = find_ffmpeg() (the same resolver the rest of the dub pipeline uses) when ffmpeg is resolvable; if it isn't, the key is omitted so yt-dlp falls back to PATH as before (no regression). Tests assert the location is passed when resolved and omitted when not. Co-authored-by: mergetest <test@local> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
mergetest
Claude Opus 4.8
parent
ea4d5e7839
commit
935b38a962
@@ -124,6 +124,11 @@ across dub, generate, and design (a corrupt-binary failure no longer poses as
|
||||
"get a free token" link. (#657, #669)
|
||||
### Fixed
|
||||
|
||||
- **Dubbing a video URL no longer fails with "ffmpeg is not installed."** yt-dlp
|
||||
downloads video and audio as separate streams and muxes them with ffmpeg, but
|
||||
it only looked on PATH — so on Windows (where OmniVoice's ffmpeg is a bundled
|
||||
sidecar / `imageio-ffmpeg` binary off PATH) the merge aborted before the dub
|
||||
could start. yt-dlp is now pointed at the same ffmpeg OmniVoice resolves. (#712)
|
||||
- **A synth that succeeded no longer 500s because of a history-logging hiccup.**
|
||||
If the local database somehow missed schema init, recording the clip to
|
||||
generation history failed with *"no such table: generation_history"* and
|
||||
|
||||
@@ -551,6 +551,15 @@ def yt_download_sync(
|
||||
"extractor_retries": 5,
|
||||
"skip_unavailable_fragments": True,
|
||||
}
|
||||
# #712: the format selector above pulls separate video+audio streams, so
|
||||
# yt-dlp muxes them via ffmpeg (merge_output_format=mp4). yt-dlp only looks
|
||||
# for ffmpeg on PATH and aborts with "you have requested merging of multiple
|
||||
# formats but ffmpeg is not installed" — but OmniVoice's ffmpeg is often a
|
||||
# bundled Tauri sidecar / imageio-ffmpeg binary that isn't on PATH (common on
|
||||
# Windows). Point yt-dlp at the exact ffmpeg we resolve so the merge works.
|
||||
_ffmpeg_bin = find_ffmpeg()
|
||||
if _ffmpeg_bin:
|
||||
ydl_opts["ffmpeg_location"] = _ffmpeg_bin
|
||||
if progress_hook is not None:
|
||||
ydl_opts["progress_hooks"] = [progress_hook]
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
"""yt-dlp must merge video+audio with OmniVoice's ffmpeg, not just PATH (#712).
|
||||
|
||||
The download format selector pulls separate streams, so yt-dlp muxes them via
|
||||
ffmpeg. yt-dlp only checks PATH and aborts ("you have requested merging of
|
||||
multiple formats but ffmpeg is not installed") when ffmpeg is a bundled sidecar
|
||||
/ imageio binary off PATH (common on Windows). yt_download_sync must pass the
|
||||
resolved ffmpeg as `ffmpeg_location`.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "backend"))
|
||||
|
||||
from services import dub_pipeline # noqa: E402
|
||||
|
||||
|
||||
class _FakeYDL:
|
||||
captured: dict = {}
|
||||
|
||||
def __init__(self, opts):
|
||||
type(self).captured = dict(opts)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, *a):
|
||||
return False
|
||||
|
||||
def extract_info(self, url, download=True):
|
||||
raise RuntimeError("stop after capturing opts")
|
||||
|
||||
def prepare_filename(self, info):
|
||||
return "unused"
|
||||
|
||||
|
||||
def test_download_passes_resolved_ffmpeg_location(tmp_path, monkeypatch):
|
||||
import yt_dlp
|
||||
|
||||
monkeypatch.setattr(dub_pipeline, "find_ffmpeg", lambda: "/opt/omnivoice/ffmpeg")
|
||||
monkeypatch.setattr(yt_dlp, "YoutubeDL", _FakeYDL)
|
||||
with pytest.raises(Exception):
|
||||
dub_pipeline.yt_download_sync("https://youtu.be/abc", str(tmp_path))
|
||||
|
||||
assert _FakeYDL.captured.get("ffmpeg_location") == "/opt/omnivoice/ffmpeg", (
|
||||
"yt-dlp must merge formats with OmniVoice's resolved ffmpeg, not just PATH (#712)"
|
||||
)
|
||||
|
||||
|
||||
def test_download_omits_ffmpeg_location_when_unresolved(tmp_path, monkeypatch):
|
||||
# If we can't resolve ffmpeg, don't pin a bogus location — let yt-dlp try
|
||||
# PATH as before (no regression for users who have ffmpeg on PATH).
|
||||
import yt_dlp
|
||||
|
||||
monkeypatch.setattr(dub_pipeline, "find_ffmpeg", lambda: None)
|
||||
monkeypatch.setattr(yt_dlp, "YoutubeDL", _FakeYDL)
|
||||
with pytest.raises(Exception):
|
||||
dub_pipeline.yt_download_sync("https://youtu.be/abc", str(tmp_path))
|
||||
|
||||
assert "ffmpeg_location" not in _FakeYDL.captured
|
||||
Reference in New Issue
Block a user