96 lines
3.4 KiB
Python
96 lines
3.4 KiB
Python
import os
|
|
import ffmpeg
|
|
import subprocess
|
|
import re
|
|
import json
|
|
|
|
|
|
def sanitize_filename(name):
|
|
"""
|
|
Removes invalid characters from the filename.
|
|
"""
|
|
return re.sub(r'[<>:"/\\|?*@]', '_', name)
|
|
|
|
|
|
def extract_audio_tracks(video_path):
|
|
"""
|
|
Extracts all audio tracks from a video file and saves them with their respective titles.
|
|
|
|
Parameters:
|
|
video_path (str): Path to the video file.
|
|
"""
|
|
try:
|
|
# Get the base name and directory of the video file
|
|
base_name = os.path.splitext(os.path.basename(video_path))[0]
|
|
directory = os.path.dirname(video_path)
|
|
|
|
# Use ffmpeg to get information about the video file
|
|
probe_cmd = ["ffprobe", "-v", "error", "-show_streams", "-of", "json", video_path]
|
|
probe_result = subprocess.run(probe_cmd, capture_output=True, text=True, check=True)
|
|
streams = json.loads(probe_result.stdout).get('streams', [])
|
|
|
|
# Process each audio stream
|
|
audio_streams = [s for s in streams if s.get('codec_type') == 'audio']
|
|
if not audio_streams:
|
|
print(f"No audio tracks found in {video_path}.")
|
|
return
|
|
|
|
for i, stream in enumerate(audio_streams):
|
|
# Extract title or fallback to index
|
|
title = stream.get('tags', {}).get('title', f"track_{i + 1}")
|
|
language = stream.get('tags', {}).get('language', 'unknown')
|
|
sanitized_title = sanitize_filename(title)
|
|
sanitized_language = sanitize_filename(language)
|
|
output_name = f"{base_name}__{sanitized_title}__{sanitized_language}.mp3"
|
|
output_path = os.path.join(directory, output_name)
|
|
|
|
# Extract the specific audio stream
|
|
print(f"Extracting audio: {sanitized_title} ({sanitized_language}) to {output_path}")
|
|
result = subprocess.run([
|
|
"ffmpeg", "-i", video_path,
|
|
"-map", f"0:a:{i}", # Select the specific audio stream
|
|
"-c:a", "mp3", # Set the codec to mp3
|
|
output_path,
|
|
"-y" # Overwrite if exists
|
|
], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
|
|
if result.returncode != 0:
|
|
print(f"ffmpeg error for stream {i}: {result.stderr}")
|
|
|
|
print(f"Extraction completed for {video_path}.")
|
|
except Exception as e:
|
|
print(f"Error processing {video_path}: {e}")
|
|
|
|
|
|
def process_path(input_path):
|
|
"""
|
|
Processes a file or directory, extracting all audio tracks from video files.
|
|
|
|
Parameters:
|
|
input_path (str): Path to the video file or directory.
|
|
"""
|
|
if os.path.isfile(input_path):
|
|
# Process a single file
|
|
extract_audio_tracks(input_path)
|
|
elif os.path.isdir(input_path):
|
|
# Process all video files in the directory
|
|
for file_name in os.listdir(input_path):
|
|
file_path = os.path.join(input_path, file_name)
|
|
if os.path.isfile(file_path) and file_name.lower().endswith(('.mp4', '.mkv', '.avi', '.mov')):
|
|
extract_audio_tracks(file_path)
|
|
else:
|
|
print(f"Invalid path: {input_path}")
|
|
|
|
if __name__ == "__main__":
|
|
import argparse
|
|
|
|
# Set up argument parser
|
|
parser = argparse.ArgumentParser(description="Extract all audio tracks from video files.")
|
|
parser.add_argument("input_path", help="Path to the video file or directory.")
|
|
|
|
# Parse arguments
|
|
args = parser.parse_args()
|
|
|
|
# Process the input path
|
|
process_path(args.input_path)
|