Files
audio_splitter/audio_splitter/main.py
T

154 lines
6.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Commandline interface and entry point."""
import argparse
import os
import sys
import subprocess
from .constants import DEFAULT_BAD_CHARS
from .defaults import (
DEFAULT_FORMAT,
DEFAULT_OUTPUT_TEMPLATE,
DEFAULT_REPLACEMENT_CHAR,
DEFAULT_BAD_CHARS,
DEFAULT_TRACKLIST_FORMAT,
DEFAULT_ALBUM,
DEFAULT_COMMENT,
DEFAULT_COMMENT_STREAM,
DEFAULT_COMMENT_SEPARATOR,
DEFAULT_NO_COMMENT,
DEFAULT_MERGE_COMMENTS,
DEFAULT_DROP_VIDEO,
DEFAULT_DROP_SUBS,
DEFAULT_NUMBER_TRACKS,
DEFAULT_REPLACE_BAD_CHARS,
DEFAULT_SKIP_EXISTING,
DEFAULT_DELETE_ORIGINAL,
DEFAULT_TRANSCODE_TO,
)
from .core import split_audio
from .tracklist import read_tracklist, parse_format
def main():
parser = argparse.ArgumentParser(description="Split audio file using a tracklist.")
parser.add_argument('input_file', help='Input audio file')
parser.add_argument('tracklist_file', help='Tracklist file')
# Output options
parser.add_argument('--format', default=DEFAULT_FORMAT, help=f"Output container format (default: {DEFAULT_FORMAT})")
parser.add_argument('--transcode-to', default=DEFAULT_TRANSCODE_TO, help="Audio codec to transcode to (default: copy)")
parser.add_argument('--drop-video', action='store_true', default=DEFAULT_DROP_VIDEO, help="Drop video streams")
parser.add_argument('--drop-subs', action='store_true', default=DEFAULT_DROP_SUBS, help="Drop subtitle streams")
# Filename options
parser.add_argument('--number-tracks', action='store_true', default=DEFAULT_NUMBER_TRACKS, help="Prepend track numbers")
parser.add_argument('--output-template', default=DEFAULT_OUTPUT_TEMPLATE, help=f"Output filename template (default: {DEFAULT_OUTPUT_TEMPLATE})")
parser.add_argument('--replace-bad-chars', action='store_true', default=DEFAULT_REPLACE_BAD_CHARS, help="Replace bad characters")
parser.add_argument('--replacement-char', default=DEFAULT_REPLACEMENT_CHAR, help=f"Replacement character (default: {DEFAULT_REPLACEMENT_CHAR})")
parser.add_argument('--bad-chars', default=DEFAULT_BAD_CHARS, help=f"Bad characters to replace (default: {DEFAULT_BAD_CHARS})")
parser.add_argument('--skip-existing', action='store_true', default=DEFAULT_SKIP_EXISTING, help="Skip existing output files")
# Metadata options
parser.add_argument('--album', default=DEFAULT_ALBUM, help="Album name")
parser.add_argument('--comment', default=DEFAULT_COMMENT, help="Comment")
parser.add_argument('--no-comment', action='store_true', default=DEFAULT_NO_COMMENT, help="Ignore comment")
parser.add_argument('--comment-stream', type=int, default=DEFAULT_COMMENT_STREAM, help="Comment stream index")
parser.add_argument('--merge-comments', action='store_true', default=DEFAULT_MERGE_COMMENTS, help="Merge all comments")
parser.add_argument('--comment-separator', default=DEFAULT_COMMENT_SEPARATOR, help=f"Separator for merged comments (default: {DEFAULT_COMMENT_SEPARATOR})")
# Tracklist format
parser.add_argument('--tracklist-format', default=DEFAULT_TRACKLIST_FORMAT, help=f"Tracklist format (default: {DEFAULT_TRACKLIST_FORMAT})")
# Other
parser.add_argument('--delete-original', action='store_true', default=DEFAULT_DELETE_ORIGINAL, help="Delete original file after split")
parser.add_argument('--dry-run', action='store_true', help="Parse and display tracklist without splitting")
args = parser.parse_args()
# --------------------------------------------------------------------------
# Input validation
# --------------------------------------------------------------------------
if not os.path.exists(args.input_file):
print(f"Error: Input file not found: {args.input_file}")
sys.exit(1)
if not os.path.exists(args.tracklist_file):
print(f"Error: Tracklist file not found: {args.tracklist_file}")
sys.exit(1)
# Ensure the replacement character is a single character.
if len(args.replacement_char) != 1:
print("Error: --replacement-char must be a single character.")
sys.exit(1)
# Check that FFmpeg is installed.
try:
subprocess.run(['ffmpeg', '-version'], capture_output=True, check=True)
except (subprocess.CalledProcessError, FileNotFoundError):
print("Error: FFmpeg not found. Please install FFmpeg first.")
print(" - https://ffmpeg.org/download.html")
sys.exit(1)
# Parse the tracklist using the userprovided format.
try:
tokens = parse_format(args.tracklist_format)
except ValueError as error:
print(f"Error in --tracklist-format: {error}")
sys.exit(1)
# Read and parse the tracklist file.
tracks = read_tracklist(args.tracklist_file, tokens)
if not tracks:
print("Error: No valid tracks found in tracklist file.")
sys.exit(1)
print(f"Found {len(tracks)} tracks.")
# Dryrun mode: display parsed data and exit.
if args.dry_run:
print("\nParsed tracklist:")
print("-" * 60)
if tracks:
fields = sorted(tracks[0].keys())
header = " | ".join(f"{f:>10}" for f in fields)
print(header)
print("-" * len(header))
for idx, track in enumerate(tracks, 1):
values = [f"{track.get(f, ''):>10}" for f in fields]
print(f"{idx:3d} | " + " | ".join(values))
print("-" * 60)
print("Dryrun complete. No files were created.")
sys.exit(0)
# Determine the output directory.
if args.output_dir:
output_dir = args.output_dir
print(f"Using custom output directory: {output_dir}")
else:
base_name = os.path.splitext(os.path.basename(args.input_file))[0]
output_dir = base_name + "_splits"
print(f"Using default output directory: {output_dir}")
# Run the splitter.
try:
split_audio(args.input_file, output_dir, tracks, args)
except (RuntimeError, ValueError) as error:
print(f"Error: {error}")
sys.exit(1)
# --------------------------------------------------------------------------
# Delete original file if requested and successful.
# --------------------------------------------------------------------------
if args.delete_original:
try:
os.remove(args.input_file)
print(f"Deleted original file: {args.input_file}")
except OSError as e:
print(f"Warning: Could not delete original file: {e}")
print("Done!")
if __name__ == "__main__":
main()