"""CLI interface for audio extraction operations""" from pathlib import Path import tempfile from audio_extractor.extractor import AudioExtractor class AudioExtractorCLI: """Command-line interface for audio extraction""" def __init__(self): self.extractor = AudioExtractor() def extract_audio(self, target: str, output: str) -> None: """ Extract audio from video file(s). Args: target: Path to video file or folder containing video files output: Output folder path for extracted audio files """ target_path = Path(target) output_path = Path(output) if not target_path.exists(): raise FileNotFoundError(f"Target not found: {target}") # Create output directory if it doesn't exist output_path.mkdir(parents=True, exist_ok=True) if target_path.is_file(): # Single file print(f"Extracting audio from: {target_path}") self.extractor.extract_audio_from_file(target_path, output_path) elif target_path.is_dir(): # Directory - process all video files video_files = self.extractor.find_video_files(target_path) if not video_files: print(f"No video files found in: {target_path}") return print(f"Found {len(video_files)} video file(s)") for i, video_file in enumerate(video_files, 1): print(f"[{i}/{len(video_files)}] Extracting audio from: {video_file.name}") try: self.extractor.extract_audio_from_file(video_file, output_path) except Exception as e: print(f" Error processing {video_file.name}: {e}") else: raise ValueError(f"Invalid target: {target}") def add_audio_tracks(self, target: str, input_folder: str, output: str, title: str = None) -> None: """ Add audio tracks to video files. Args: target: Path to folder containing audio files input_folder: Path to folder containing video files output: Output folder for processed video files title: Title/name for the added audio tracks (applied to all added tracks) """ audio_folder = Path(target) video_folder = Path(input_folder) output_folder = Path(output) if not audio_folder.exists(): raise FileNotFoundError(f"Audio folder not found: {target}") if not video_folder.exists(): raise FileNotFoundError(f"Video folder not found: {input_folder}") # Create output directory if it doesn't exist output_folder.mkdir(parents=True, exist_ok=True) # Find all audio files audio_files = self.extractor.find_audio_files(audio_folder) if not audio_files: print(f"No audio files found in: {audio_folder}") return print(f"Found {len(audio_files)} audio file(s)") # Group audio files by matching video videos_with_audio = {} # Process each audio file for audio_file in audio_files: try: # Find matching video file video_file = self.extractor.find_matching_video(audio_file, video_folder) video_stem = video_file.stem if video_stem not in videos_with_audio: videos_with_audio[video_stem] = { 'video': video_file, 'audio_files': [] } videos_with_audio[video_stem]['audio_files'].append(audio_file) except FileNotFoundError as e: print(f"⚠ Skipped: {e}") if not videos_with_audio: print("No matching video files found for audio files") return print(f"Found {len(videos_with_audio)} video(s) to process\n") # Process each video with its audio files for idx, (video_stem, data) in enumerate(videos_with_audio.items(), 1): video_file = data['video'] audio_files_to_add = data['audio_files'] print(f"[{idx}/{len(videos_with_audio)}] Processing: {video_file.name}") try: # Copy original video to output video_ext = video_file.suffix output_video = output_folder / f"{video_stem}{video_ext}" print(f" → Copying original video...") self.extractor.copy_file(video_file, output_video) # Process each audio file for audio_idx, audio_file in enumerate(audio_files_to_add): # For multiple audio files, use temp file for intermediate versions if len(audio_files_to_add) > 1 and audio_idx < len(audio_files_to_add) - 1: # Use temp file for intermediate processing temp_dir = Path(tempfile.gettempdir()) working_video = temp_dir / f"{video_stem}_processing_{audio_idx}{video_ext}" else: # Use final output file working_video = output_folder / f"{video_stem}_new{video_ext}" # Determine input file (original copy for first audio, or previous output) if audio_idx == 0: input_video = output_video else: # Use the previous output as input prev_output = temp_dir / f"{video_stem}_processing_{audio_idx - 1}{video_ext}" if audio_idx > 0 else output_video input_video = prev_output if prev_output.exists() else output_video print(f" ↳ Adding audio: {audio_file.name}") self.extractor.add_audio_to_video( input_video, audio_file, working_video, track_title=title ) except Exception as e: print(f" ✗ Error: {e}")