Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion aai_cli/youtube.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,15 @@ def download_audio(url: str, dest_dir: Path) -> Path:

if not path.is_file():
# Post-processing can change the extension; fall back to whatever landed.
# yt-dlp may also drop sidecars (thumbnail, .info.json, a leftover .part)
# in dest_dir, and iterdir() order is arbitrary, so pick the largest file:
# the decoded audio track dwarfs any metadata sidecar.
files = [p for p in dest_dir.iterdir() if p.is_file()]
if not files:
raise CLIError(
f"yt-dlp produced no audio file for {url}.",
error_type="youtube_error",
exit_code=1,
)
path = files[0]
path = max(files, key=lambda p: p.stat().st_size)
return path
28 changes: 28 additions & 0 deletions tests/test_youtube.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,34 @@ def prepare_filename(self, info):
assert youtube.download_audio("https://youtu.be/x", tmp_path) == landed


def test_download_audio_falls_back_to_largest_file(tmp_path, monkeypatch):
# yt-dlp can leave sidecars (thumbnail, .info.json) next to the audio track;
# the fallback must pick the audio (largest), not an arbitrary iterdir() entry.
audio = tmp_path / "actual.webm"
thumb = tmp_path / "actual.webp"

class FakeYDL:
def __init__(self, opts):
pass

def __enter__(self):
return self

def __exit__(self, *exc):
return False

def extract_info(self, url, download):
thumb.write_bytes(b"\x00" * 16) # small sidecar
audio.write_bytes(b"\x00" * 4096) # the real, much larger track
return {"id": "x"}

def prepare_filename(self, info):
return str(tmp_path / "guessed.m4a") # wrong extension; file doesn't exist

_fake_ytdlp(monkeypatch, FakeYDL)
assert youtube.download_audio("https://youtu.be/x", tmp_path) == audio


def test_download_audio_no_file_produced_raises(tmp_path, monkeypatch):
# prepare_filename points at a missing file and nothing landed in dest_dir.
class FakeYDL:
Expand Down
Loading