diff options
Diffstat (limited to 'app/converter/audio.py')
| -rw-r--r-- | app/converter/audio.py | 47 |
1 files changed, 27 insertions, 20 deletions
diff --git a/app/converter/audio.py b/app/converter/audio.py index eb970ff..90ce5ca 100644 --- a/app/converter/audio.py +++ b/app/converter/audio.py @@ -1,4 +1,9 @@ -"""Audio assembly: combining chunks, speed adjustment, cleanup.""" +"""Audio assembly: combining chunks, speed adjustment, cleanup. + +Every function that touches the run's scratch audio takes its folder as an +explicit CHUNKS_DIR argument — the converter owns the folder constants and +threads them through, so there is no module-global path to mutate. +""" import logging import re @@ -13,8 +18,6 @@ from . import config logger = logging.getLogger(__name__) -CHUNKS_FOLDER = Path(__file__).resolve().parent.parent.parent / "app" / "chunks" - # Tolerance for "is this speed 1.0?" comparisons (banner display, atempo # filter elision); shared by every speed check. SPEED_EPSILON = 1e-6 @@ -362,6 +365,7 @@ def _collect_chunk_files(total_chunks: int, def combine_chunks(total_chunks: int, output_path: Path, chunk_results: Dict[int, Optional[Path]], + *, chunks_dir: Path, speed: float = 1.0, output_format: str = config.AUDIO_FORMAT, intermediate: bool = False, meta: Optional[TrackMeta] = None, @@ -369,14 +373,15 @@ def combine_chunks(total_chunks: int, output_path: Path, """Combine audio chunks into the final audiobook using ffmpeg's concat demuxer. ``chunk_results`` maps chunk numbers to the audio file each chunk produced - (None for failed chunks); failed and missing chunks are skipped. When - ``speed`` differs from 1.0, an additional speed-adjusted copy is written - next to the normal-speed file. ``meta``/``cover`` embed tags and cover - art into the output (skipped for intermediate chapter scratch audio). - Chunks are streamed by ffmpeg, so the whole book is never held in - memory. Set ``intermediate`` for scratch chapter audio on the way to a - larger output (e.g. a chaptered m4b) so save messages don't present it - as the final audiobook. + (None for failed chunks); failed and missing chunks are skipped. The + concat scratch list is written to ``chunks_dir``. When ``speed`` differs + from 1.0, an additional speed-adjusted copy is written next to the + normal-speed file. ``meta``/``cover`` embed tags and cover art into the + output (skipped for intermediate chapter scratch audio). Chunks are + streamed by ffmpeg, so the whole book is never held in memory. Set + ``intermediate`` for scratch chapter audio on the way to a larger output + (e.g. a chaptered m4b) so save messages don't present it as the final + audiobook. """ if shutil.which("ffmpeg") is None or shutil.which("ffprobe") is None: logger.error("ffmpeg and ffprobe are required to combine audio chunks (install ffmpeg)") @@ -391,7 +396,7 @@ def combine_chunks(total_chunks: int, output_path: Path, if missing_chunks: logger.warning("Missing chunks: %s", missing_chunks) - concat_list = CHUNKS_FOLDER / "_concat_list.txt" + concat_list = Path(chunks_dir) / "_concat_list.txt" try: with open(concat_list, "w", encoding="utf-8") as list_file: for chunk_file in chunk_files: @@ -463,12 +468,12 @@ def combine_chunks(total_chunks: int, output_path: Path, pass -def cleanup_chunks() -> None: - """Remove temporary chunk and chapter files from the scratch folder.""" +def cleanup_chunks(chunks_dir: Path) -> None: + """Remove temporary chunk and chapter files from the CHUNKS_DIR scratch folder.""" try: chunk_count = 0 for pattern in ("chunk_*", "chapter_*"): - for chunk_file in CHUNKS_FOLDER.glob(pattern): + for chunk_file in Path(chunks_dir).glob(pattern): try: if chunk_file.is_file(): chunk_file.unlink() @@ -532,13 +537,15 @@ def build_ffmetadata(chapters: List[tuple], path: Path) -> None: def combine_chapters_to_m4b(chapter_files: List[Path], titles: List[str], - output_path: Path, speed: float = 1.0, + output_path: Path, *, chunks_dir: Path, + speed: float = 1.0, meta: Optional[TrackMeta] = None, cover: Optional[Path] = None) -> bool: """Concatenate per-chapter audio into a single m4b with embedded chapter markers. Chapter start/end times are derived from each chapter file's duration and - written as ffmpeg chapter metadata. ``meta``/``cover`` embed tags and + written as ffmpeg chapter metadata; the concat list and metadata scratch + files are written to ``chunks_dir``. ``meta``/``cover`` embed tags and cover art. When ``speed`` differs from 1.0, a speed-adjusted copy (with rescaled chapter markers) is written alongside the normal-speed file. """ @@ -550,9 +557,9 @@ def combine_chapters_to_m4b(chapter_files: List[Path], titles: List[str], logger.error("No chapter files provided") return False - concat_list = CHUNKS_FOLDER / "_concat_list.txt" - metadata_file = CHUNKS_FOLDER / "_chapters.txt" - speed_metadata_file = CHUNKS_FOLDER / "_chapters_speed.txt" + concat_list = Path(chunks_dir) / "_concat_list.txt" + metadata_file = Path(chunks_dir) / "_chapters.txt" + speed_metadata_file = Path(chunks_dir) / "_chapters_speed.txt" try: chapters = [] start_ms = 0 |
