Files
Music-Tools/audio_snippets.py
2026-10-19 15:29:27 +01:00

152 lines
3.4 KiB
Python
Executable File

#!/usr/bin/env python3
import argparse
import re
import subprocess
import tempfile
from pathlib import Path
EXTENSIONS = {
".mp3", ".m4a", ".wav", ".flac",
".aac", ".ogg", ".aiff", ".aif"
}
def run(command):
subprocess.run(command, check=True)
def create_snippets(
source,
output,
snippet_seconds=8,
silence_seconds=4
):
source = Path(source).expanduser().resolve()
output = Path(output).expanduser().resolve()
if not source.is_dir():
raise SystemExit(f"Folder not found: {source}")
if snippet_seconds <= 0 or silence_seconds < 0:
raise SystemExit("Invalid snippet or silence duration")
tracks = sorted(
(
p for p in source.iterdir()
if p.is_file()
and p.suffix.lower() in EXTENSIONS
and p != output
),
key=lambda p: [
int(part) if part.isdigit() else part.lower()
for part in re.split(r"(\d+)", p.name)
]
)
if not tracks:
raise SystemExit("No supported audio files found")
print(f"Found {len(tracks)} tracks")
output.parent.mkdir(parents=True, exist_ok=True)
with tempfile.TemporaryDirectory() as temp:
temp = Path(temp)
segments = []
for index, track in enumerate(tracks, start=1):
print(f"[{index}/{len(tracks)}] {track.name}")
snippet = temp / f"snippet_{index:04d}.wav"
run([
"ffmpeg",
"-hide_banner",
"-loglevel", "error",
"-y",
"-i", str(track),
"-t", str(snippet_seconds),
"-vn",
"-ac", "2",
"-ar", "44100",
"-c:a", "pcm_s16le",
str(snippet)
])
segments.append(snippet)
if index < len(tracks) and silence_seconds > 0:
silence = temp / f"silence_{index:04d}.wav"
run([
"ffmpeg",
"-hide_banner",
"-loglevel", "error",
"-y",
"-f", "lavfi",
"-i",
"anullsrc=r=44100:cl=stereo",
"-t", str(silence_seconds),
"-c:a", "pcm_s16le",
str(silence)
])
segments.append(silence)
playlist = temp / "playlist.txt"
playlist.write_text(
"".join(
f"file '{str(segment)}'\n"
for segment in segments
)
)
print("Combining snippets...")
run([
"ffmpeg",
"-hide_banner",
"-loglevel", "error",
"-y",
"-f", "concat",
"-safe", "0",
"-i", str(playlist),
"-c:a", "libmp3lame",
"-b:a", "192k",
str(output)
])
print()
print("Complete!")
print(f"Output: {output}")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("source")
parser.add_argument("output")
parser.add_argument(
"--snippet",
type=float,
default=5
)
parser.add_argument(
"--silence",
type=float,
default=5
)
args = parser.parse_args()
create_snippets(
args.source,
args.output,
args.snippet,
args.silence
)