refact (core): split large code blocks, remove useless files/code #12
+31
-2
@@ -23,6 +23,7 @@ from .formats import (
|
|||||||
determine_output_format,
|
determine_output_format,
|
||||||
validate_format_compatibility,
|
validate_format_compatibility,
|
||||||
)
|
)
|
||||||
|
from .handlers import get_handler, needs_drop_video
|
||||||
from .timestamp import parse_track_timestamps, resolve_end_times
|
from .timestamp import parse_track_timestamps, resolve_end_times
|
||||||
from .filename import build_filename
|
from .filename import build_filename
|
||||||
from .metadata import build_metadata_dict
|
from .metadata import build_metadata_dict
|
||||||
@@ -162,6 +163,14 @@ def split_audio(input_file: str, output_directory: str, tracks: List[Dict[str, A
|
|||||||
else:
|
else:
|
||||||
cover_image_path = None
|
cover_image_path = None
|
||||||
|
|
||||||
|
# Check if we need special handling (e.g., Opus files need opustags)
|
||||||
|
input_audio_codec = stream_info.get('audio_codec')
|
||||||
|
cover_handler = get_handler(output_container, input_audio_codec)
|
||||||
|
needs_drop = needs_drop_video(output_container, input_audio_codec)
|
||||||
|
if cover_image_path and needs_drop:
|
||||||
|
print(f"Using special handler for {output_container} + {input_audio_codec}")
|
||||||
|
print("Temporarily dropping video for opustags post-processing.")
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
# 8. Process each track
|
# 8. Process each track
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
@@ -208,6 +217,11 @@ def split_audio(input_file: str, output_directory: str, tracks: List[Dict[str, A
|
|||||||
subtitle_enc = CODEC_NAME_TO_FFMPEG.get(subtitle_enc, subtitle_enc)
|
subtitle_enc = CODEC_NAME_TO_FFMPEG.get(subtitle_enc, subtitle_enc)
|
||||||
|
|
||||||
# Then build command with these mapped encoders
|
# Then build command with these mapped encoders
|
||||||
|
# Use temporary drop_video for handlers that need it
|
||||||
|
effective_drop_video = args.drop_video or (cover_image_path and needs_drop)
|
||||||
|
# For handlers that need opustags post-processing, don't pass cover_image_path
|
||||||
|
# to ffmpeg - it will process audio-only, then handler adds cover afterward
|
||||||
|
ffmpeg_cover_path = None if (cover_image_path and needs_drop) else cover_image_path
|
||||||
cmd = build_ffmpeg_command(
|
cmd = build_ffmpeg_command(
|
||||||
input_file=input_file,
|
input_file=input_file,
|
||||||
start_seconds=start_seconds,
|
start_seconds=start_seconds,
|
||||||
@@ -219,9 +233,9 @@ def split_audio(input_file: str, output_directory: str, tracks: List[Dict[str, A
|
|||||||
video_codec=video_enc,
|
video_codec=video_enc,
|
||||||
subtitle_codec=subtitle_enc,
|
subtitle_codec=subtitle_enc,
|
||||||
metadata=metadata,
|
metadata=metadata,
|
||||||
cover_image_path=cover_image_path,
|
cover_image_path=ffmpeg_cover_path,
|
||||||
video_quality=getattr(args, 'video_quality', None),
|
video_quality=getattr(args, 'video_quality', None),
|
||||||
drop_video=args.drop_video,
|
drop_video=effective_drop_video,
|
||||||
drop_subs=args.drop_subs,
|
drop_subs=args.drop_subs,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -235,6 +249,21 @@ def split_audio(input_file: str, output_directory: str, tracks: List[Dict[str, A
|
|||||||
print(result.stderr)
|
print(result.stderr)
|
||||||
else:
|
else:
|
||||||
print(f" -> Saved to: {output_path}")
|
print(f" -> Saved to: {output_path}")
|
||||||
|
# Apply cover image handler if needed
|
||||||
|
if cover_image_path and not args.drop_video and needs_drop:
|
||||||
|
print(f"Applying cover image via {output_container} handler...")
|
||||||
|
if not cover_handler(
|
||||||
|
input_file=input_file,
|
||||||
|
cover_image_path=cover_image_path,
|
||||||
|
output_path=output_path,
|
||||||
|
stream_info=stream_info,
|
||||||
|
audio_codec=audio_enc,
|
||||||
|
video_codec=video_enc,
|
||||||
|
video_quality=getattr(args, 'video_quality', None),
|
||||||
|
drop_video=args.drop_video,
|
||||||
|
drop_subs=args.drop_subs,
|
||||||
|
):
|
||||||
|
print(f"Warning: Failed to attach cover image to {output_path}")
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
# 9. Delete original file if requested
|
# 9. Delete original file if requested
|
||||||
|
|||||||
@@ -310,6 +310,9 @@ def _build_cover_image_mapping(
|
|||||||
else:
|
else:
|
||||||
cmd.extend(['-c:a', 'copy'])
|
cmd.extend(['-c:a', 'copy'])
|
||||||
|
|
||||||
|
# Preserve attached_pic disposition for cover image
|
||||||
|
cmd.extend(['-disposition', 'attached_pic'])
|
||||||
|
|
||||||
cmd.append('-sn')
|
cmd.append('-sn')
|
||||||
|
|
||||||
if video_quality is not None:
|
if video_quality is not None:
|
||||||
|
|||||||
@@ -0,0 +1,167 @@
|
|||||||
|
# audio_splitter/handlers.py
|
||||||
|
"""Handler system for cover image attachment.
|
||||||
|
|
||||||
|
This module provides a registry of handlers for different
|
||||||
|
codec + image combinations. Each handler is responsible for
|
||||||
|
attaching the cover image to the output file in the appropriate way.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from typing import Dict, Optional
|
||||||
|
|
||||||
|
|
||||||
|
def _run_opustags(input_file: str, cover_image_path: str, output_path: Optional[str] = None) -> bool:
|
||||||
|
"""
|
||||||
|
Run opustags to attach a cover image to an Opus file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
input_file: Path to the input Opus file.
|
||||||
|
cover_image_path: Path to the cover image.
|
||||||
|
output_path: Optional output path (if None, overwrites input).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if successful, False otherwise.
|
||||||
|
"""
|
||||||
|
cmd = ['opustags', '--set-cover', cover_image_path, input_file]
|
||||||
|
|
||||||
|
if output_path:
|
||||||
|
cmd.extend(['-o', output_path, '-y'])
|
||||||
|
else:
|
||||||
|
cmd.extend(['-i'])
|
||||||
|
|
||||||
|
result = subprocess.run(cmd, capture_output=True, text=True, check=False)
|
||||||
|
if result.returncode != 0:
|
||||||
|
print(f"opustags failed: {result.stderr}")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _handler_default(
|
||||||
|
input_file: str,
|
||||||
|
cover_image_path: str,
|
||||||
|
output_path: str,
|
||||||
|
stream_info: Dict,
|
||||||
|
audio_codec: str,
|
||||||
|
video_codec: str,
|
||||||
|
video_quality: Optional[int],
|
||||||
|
drop_video: bool,
|
||||||
|
drop_subs: bool,
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Default handler: use ffmpeg with -disposition attached_pic.
|
||||||
|
|
||||||
|
This is the standard approach for formats like MP3, FLAC, etc.
|
||||||
|
"""
|
||||||
|
# This handler doesn't do anything - the cover is already handled
|
||||||
|
# by the ffmpeg command in core.py via build_ffmpeg_command()
|
||||||
|
# We just return True to indicate success.
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _handler_opus_with_cover(
|
||||||
|
input_file: str,
|
||||||
|
cover_image_path: str,
|
||||||
|
output_path: str,
|
||||||
|
stream_info: Dict,
|
||||||
|
audio_codec: str,
|
||||||
|
video_codec: str,
|
||||||
|
video_quality: Optional[int],
|
||||||
|
drop_video: bool,
|
||||||
|
drop_subs: bool,
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Handler for Opus files with cover image.
|
||||||
|
|
||||||
|
Uses opustags to attach the cover image after the file is processed.
|
||||||
|
"""
|
||||||
|
return _run_opustags(output_path, cover_image_path)
|
||||||
|
|
||||||
|
|
||||||
|
def _handler_mp3_with_cover(
|
||||||
|
input_file: str,
|
||||||
|
cover_image_path: str,
|
||||||
|
output_path: str,
|
||||||
|
stream_info: Dict,
|
||||||
|
audio_codec: str,
|
||||||
|
video_codec: str,
|
||||||
|
video_quality: Optional[int],
|
||||||
|
drop_video: bool,
|
||||||
|
drop_subs: bool,
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Handler for MP3 files with cover image.
|
||||||
|
|
||||||
|
Uses ffmpeg with -disposition attached_pic.
|
||||||
|
"""
|
||||||
|
# MP3 handler - the cover is already attached by ffmpeg in core.py
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _handler_flac_with_cover(
|
||||||
|
input_file: str,
|
||||||
|
cover_image_path: str,
|
||||||
|
output_path: str,
|
||||||
|
stream_info: Dict,
|
||||||
|
audio_codec: str,
|
||||||
|
video_codec: str,
|
||||||
|
video_quality: Optional[int],
|
||||||
|
drop_video: bool,
|
||||||
|
drop_subs: bool,
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Handler for FLAC files with cover image.
|
||||||
|
|
||||||
|
Uses ffmpeg with -disposition attached_pic.
|
||||||
|
"""
|
||||||
|
# FLAC handler - the cover is already attached by ffmpeg in core.py
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# Handler registry: maps (output_container, input_codec) to handler function
|
||||||
|
HANDLER_REGISTRY: Dict[tuple, callable] = {
|
||||||
|
('opus', 'opus'): _handler_opus_with_cover,
|
||||||
|
('ogg', 'opus'): _handler_opus_with_cover,
|
||||||
|
('mp3', 'mp3'): _handler_mp3_with_cover,
|
||||||
|
('flac', 'flac'): _handler_flac_with_cover,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_handler(output_container: str, input_audio_codec: Optional[str] = None):
|
||||||
|
"""
|
||||||
|
Get the appropriate handler for the given container and input codec.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
output_container: Output container format (e.g., 'opus', 'mp3', 'flac').
|
||||||
|
input_audio_codec: Input audio codec (e.g., 'opus', 'mp3', 'flac').
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Handler function, or the default handler if no specific handler is found.
|
||||||
|
"""
|
||||||
|
if input_audio_codec:
|
||||||
|
key = (output_container, input_audio_codec)
|
||||||
|
if key in HANDLER_REGISTRY:
|
||||||
|
return HANDLER_REGISTRY[key]
|
||||||
|
|
||||||
|
# Fall back to container-only key
|
||||||
|
if (output_container, None) in HANDLER_REGISTRY:
|
||||||
|
return HANDLER_REGISTRY[(output_container, None)]
|
||||||
|
|
||||||
|
# Default handler
|
||||||
|
return _handler_default
|
||||||
|
|
||||||
|
|
||||||
|
def needs_drop_video(output_container: str, input_audio_codec: Optional[str] = None) -> bool:
|
||||||
|
"""
|
||||||
|
Check if the handler requires dropping video even if user didn't specify --drop-video.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
output_container: Output container format.
|
||||||
|
input_audio_codec: Input audio codec.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if video should be dropped, False otherwise.
|
||||||
|
"""
|
||||||
|
handler = get_handler(output_container, input_audio_codec)
|
||||||
|
# The opus handler requires dropping video
|
||||||
|
return handler == _handler_opus_with_cover
|
||||||
Reference in New Issue
Block a user