Files
UmbraAudio/tests/test_assembly.py
B.D. Murphy c86e323d7a Initial commit: UmbraAudio audiobook generation program
Quality-first multi-pass audiobook generation from English manuscripts.

Includes:
- umbraaudio/ core package (pipeline, config, voices, web review UI)
- scripts/ CLI utilities + model download script
- tts_server/ remote TTS server
- specs/ design docs, tests/, pyproject.toml + uv.lock
- Qwen3-TTS git submodule (pinned 022e286) with local demo.py UI patch
  saved at scripts/qwen3_tts_demo_umbra_patch.patch
- .env with runtime config/secrets

Excluded (see .gitignore): models/ (downloaded via scripts/download_models.sh),
output/, logs/, .venv, .umbra runtime data, and book projects
(DealHunterShip_*), which are committed separately.
2026-08-30 07:58:24 -07:00

94 lines
2.8 KiB
Python

from __future__ import annotations
from pathlib import Path
from umbraaudio.assembly import AudioStitcher
from umbraaudio.assembly.metadata import (
BookMetadata,
ChapterMeta,
build_chapter_metadata,
read_metadata_json,
write_ffmpeg_metadata,
write_metadata_json,
)
def test_stitch_utterances_output_exists(
temp_dir: Path, sample_wavs: list[Path], stitcher: AudioStitcher
):
output = temp_dir / "stitched.wav"
result = stitcher.stitch_utterances(sample_wavs, output)
assert result == output
assert output.exists()
assert output.stat().st_size > 0
def test_stitch_utterances_empty_list(stitcher: AudioStitcher, temp_dir: Path):
output = temp_dir / "empty.wav"
result = stitcher.stitch_utterances([], output)
assert result == output
assert output.exists()
def test_stitch_chapters_output_exists(
temp_dir: Path, sample_wavs: list[Path], stitcher: AudioStitcher
):
output = temp_dir / "chapters.wav"
result = stitcher.stitch_chapters(sample_wavs, output)
assert result == output
assert output.exists()
def test_make_silence(stitcher: AudioStitcher):
silence = stitcher._make_silence(100)
assert len(silence) == int(24000 * 0.1)
assert (silence == 0).all()
def test_build_chapter_metadata():
titles = ["Ch 1", "Ch 2", "Ch 3"]
durations = [10.0, 15.0, 20.0]
meta = build_chapter_metadata(titles, durations, book_title="Test Book", author="Author")
assert meta.title == "Test Book"
assert meta.author == "Author"
assert len(meta.chapters) == 3
assert meta.chapters[0].title == "Ch 1"
assert meta.chapters[0].start_time_sec == 0.0
assert meta.chapters[0].end_time_sec == 10.0
assert meta.chapters[1].start_time_sec == 10.0
assert meta.chapters[1].end_time_sec == 25.0
def test_metadata_json_roundtrip(temp_dir: Path):
meta = BookMetadata(
title="Book",
author="Author",
narrator="Narrator",
chapters=[ChapterMeta(title="Ch 1", start_time_sec=0.0, end_time_sec=10.0, index=0)],
)
path = temp_dir / "meta.json"
write_metadata_json(meta, path)
assert path.exists()
loaded = read_metadata_json(path)
assert loaded.title == "Book"
assert loaded.author == "Author"
assert len(loaded.chapters) == 1
assert loaded.chapters[0].title == "Ch 1"
def test_write_ffmpeg_metadata(temp_dir: Path):
meta = BookMetadata(
title="Test Book",
author="Author",
chapters=[ChapterMeta(title="Ch 1", start_time_sec=0.0, end_time_sec=10.0, index=0)],
)
path = temp_dir / "ffmetadata.txt"
write_ffmpeg_metadata(meta, path)
assert path.exists()
content = path.read_text()
assert "title=Test Book" in content
assert "artist=Author" in content
assert "[CHAPTER]" in content
assert "START=0" in content
assert "END=10000" in content