aboutsummaryrefslogtreecommitdiff
path: root/app/converter/audio.py
diff options
context:
space:
mode:
Diffstat (limited to 'app/converter/audio.py')
-rw-r--r--app/converter/audio.py47
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