diff --git a/audio_splitter/core.py b/audio_splitter/core.py index 08a4a12..2f49e3f 100644 --- a/audio_splitter/core.py +++ b/audio_splitter/core.py @@ -194,6 +194,9 @@ def split_audio(input_file: str, output_directory: str, tracks: List[Dict[str, A subtitle_codec=args.subtitle_codec, metadata=metadata, cover_image_path=cover_image_path, + video_quality=getattr(args, 'video_quality', None), + drop_video=args.drop_video, + drop_subs=args.drop_subs, ) print(cmd) diff --git a/audio_splitter/ffmpeg.py b/audio_splitter/ffmpeg.py index 76b6463..b5119b4 100644 --- a/audio_splitter/ffmpeg.py +++ b/audio_splitter/ffmpeg.py @@ -281,30 +281,49 @@ def build_ffmpeg_command( subtitle_codec: Optional[str] = 'copy', metadata: Optional[Dict] = None, cover_image_path: Optional[str] = None, + video_quality: Optional[int] = None, + drop_video: bool = False, + drop_subs: bool = False, ) -> List[str]: """ - Construct the FFmpeg command line. + Construct the FFmpeg command line as a list of arguments. Args: - audio_codec: 'copy' or encoder name (e.g., 'libopus') - video_codec: 'copy' or encoder name (e.g., 'libx264') - subtitle_codec: 'copy' or encoder name (e.g., 'srt') + input_file: Path to the input media file. + start_seconds: Start time for the segment (in seconds). + duration_seconds: Duration of the segment (in seconds). + output_path: Destination path for the output file. + stream_info: Dictionary from get_stream_info(). + format_opt: Output container format (e.g., 'mp3', 'mkv'). + audio_codec: Audio codec to use ('copy' or encoder name like 'libopus'). + video_codec: Video codec to use ('copy' or encoder name). + subtitle_codec: Subtitle codec to use ('copy' or encoder name). + metadata: Optional dict of metadata key/value pairs to write. + cover_image_path: Path to extracted cover image (if any). + video_quality: Quality value for video encoder (e.g., 1-31, lower=better). + drop_video: If True, remove video streams. + drop_subs: If True, remove subtitle streams. + + Returns: + A list of command‑line arguments suitable for subprocess.run(). """ cmd = ['ffmpeg'] - # Add cover image if provided + # Add cover image as first input if provided if cover_image_path: cmd.extend(['-i', cover_image_path]) + + # Add main input file cmd.extend(['-i', input_file]) # Time options cmd.extend(['-ss', format_time(start_seconds), '-t', format_time(duration_seconds)]) - # Clear metadata + # Clear all original metadata. cmd.append('-map_metadata') cmd.append('-1') - # Apply custom metadata + # Apply custom metadata. if metadata: for key, value in metadata.items(): if value is not None and value != '': @@ -328,15 +347,22 @@ def build_ffmpeg_command( else: cmd.extend(['-c:a', 'copy']) - # Subtitle: none (we don't copy from original when using cover image) + # Subtitle: we don't copy subtitles when using cover image (they would be from main input) cmd.append('-sn') + # Video quality if specified + if video_quality is not None: + cmd.extend(['-q:v', str(video_quality)]) + else: - # Standard mapping: copy all streams by default, then filter based on options - if not stream_info.get('has_video') or drop_video: + # Standard mapping (no cover image) + if drop_video and drop_subs: cmd.extend(['-map', '0:a:0']) + elif drop_video: + cmd.extend(['-map', '0:a:0', '-map', '0:s?']) + elif drop_subs: + cmd.extend(['-map', '0:a:0', '-map', '0:v:0']) else: - # Map all streams cmd.extend(['-map', '0']) # Audio codec @@ -345,17 +371,20 @@ def build_ffmpeg_command( else: cmd.extend(['-c:a', 'copy']) - # Video codec (if video present and not dropped) - if stream_info.get('has_video') and not drop_video: + # Video codec + if not drop_video and stream_info.get('has_video'): if video_codec and video_codec != 'copy': cmd.extend(['-c:v', video_codec]) + # Add video quality if specified (only when re-encoding) + if video_quality is not None: + cmd.extend(['-q:v', str(video_quality)]) else: cmd.extend(['-c:v', 'copy']) else: cmd.append('-vn') # Subtitle codec - if stream_info.get('has_subtitle') and not drop_subs: + if not drop_subs and stream_info.get('has_subtitle'): if subtitle_codec and subtitle_codec != 'copy': cmd.extend(['-c:s', subtitle_codec]) else: diff --git a/audio_splitter/main.py b/audio_splitter/main.py index 9d8cd39..070be8f 100644 --- a/audio_splitter/main.py +++ b/audio_splitter/main.py @@ -60,6 +60,13 @@ def main(): help="Drop video streams") parser.add_argument('--drop-subs', action='store_true', default=DEFAULT_DROP_SUBS, help="Drop subtitle streams") + parser.add_argument( + '--video-quality', '-vq', + type=int, + default=None, + help="Video quality (integer, encoder-specific; usually 1-31, lower=better). " + "If omitted, FFmpeg default is used." + ) # Filename options parser.add_argument('--number-tracks', action='store_true', default=DEFAULT_NUMBER_TRACKS,