econvert/econvert.py

132 lines
5.6 KiB
Python

import os
import sys
import argparse
import subprocess
import time
from pathlib import Path
def count_files(source, extensions):
count = 0
if os.path.isfile(source):
if Path(source).suffix[1:].lower() in extensions:
count = 1
else:
for ext in extensions:
count += len(list(Path(source).rglob(f'*.{ext}')))
return count
def progress_bar(iteration, total, prefix='', suffix='', decimals=1, length=50, fill='', print_end="\r"):
percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
filled_length = int(length * iteration // total)
bar = fill * filled_length + '-' * (length - filled_length)
print(f'\r{prefix} |{bar}| {percent}% {suffix}', end=print_end)
if iteration == total:
print()
def get_conversion_command(source_path, target_path, voice_mode=False):
ext = Path(source_path).suffix[1:].lower()
audio_extensions = ['mp3', 'wav', 'm4a', 'opus']
video_extensions = ['mp4', 'avi', 'mov', 'webm', 'mkv']
image_extensions = ['jpg', 'jpeg', 'png', 'gif']
if ext in video_extensions:
target_path = os.path.splitext(target_path)[0] + '.mp4'
elif ext in audio_extensions:
target_path = os.path.splitext(target_path)[0] + '.mp3'
elif ext in image_extensions:
target_path = os.path.splitext(target_path)[0] + '.jpeg'
if ext in audio_extensions:
if voice_mode:
return ['ffmpeg', '-i', source_path, '-vn', '-ar', '22050', '-ac', '1', '-b:a', '32k', '-c:a', 'libmp3lame', target_path]
else:
return ['ffmpeg', '-i', source_path, '-vn', '-ar', '44100', '-ac', '2', '-b:a', '128k', '-c:a', 'libmp3lame', target_path]
elif ext in video_extensions:
if ext == 'mkv':
return ['ffmpeg', '-i', source_path, '-c', 'copy', target_path]
else:
return ['ffmpeg', '-i', source_path, '-vf', "fps=30,scale='min(1280,iw)':min'(720,ih)':force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2", '-c:v', 'libx264', '-crf', '23', '-preset', 'medium', '-c:a', 'aac', '-b:a', '128k', target_path]
elif ext in image_extensions:
return ['ffmpeg', '-i', source_path, '-vf', "scale='min(1280,iw)':min'(720,ih)':force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2", '-q:v', '2', target_path]
else:
return None
def convert_files(source, target, dry_run=False, voice_mode=False, delete_original=False):
all_extensions = ['mp3', 'wav', 'm4a', 'opus', 'mp4', 'avi', 'mov', 'webm', 'mkv',
'jpg', 'jpeg', 'png', 'gif']
total_files = count_files(source, all_extensions)
if dry_run:
print(f"Dry run: {total_files} file(s) would be converted")
return
processed_files = 0
def process_file(source_path, target_path):
nonlocal processed_files
cmd = get_conversion_command(source_path, target_path, voice_mode)
if cmd:
print(f"Converting {source_path} to {target_path}")
if not dry_run:
try:
result = subprocess.run(cmd, check=True, capture_output=True,
text=True)
if delete_original:
os.remove(source_path)
print(f"Deleted original file: {source_path}")
except subprocess.CalledProcessError as e:
print(f"Erreur lors de la conversion : {e}")
print(f"Sortie d'erreur : {e.stderr}")
return
processed_files += 1
progress_bar(processed_files, total_files,
prefix='Progress:', suffix='Complete')
else:
print(f"Skipping unsupported file: {source_path}")
if os.path.isfile(source):
target_dir = os.path.dirname(target) if os.path.isfile(target) else target
os.makedirs(target_dir, exist_ok=True)
process_file(source, target)
else:
for root, _, files in os.walk(source):
for file in files:
source_path = os.path.join(root, file)
relative_path = os.path.relpath(source_path, source)
target_path = os.path.join(target, relative_path)
os.makedirs(os.path.dirname(target_path), exist_ok=True)
process_file(source_path, target_path)
def main():
parser = argparse.ArgumentParser(description='Convert audio, video, and image files.')
parser.add_argument('source',
help='Source file or directory containing files to convert')
parser.add_argument('target',
help='Target file (if source is a file) or directory for converted files')
parser.add_argument('--dry-run',
action='store_true',
help='Perform a dry run without actually converting files')
parser.add_argument('--voice-mode',
action='store_true',
help='Optimize audio encoding for voice')
parser.add_argument('--delete-original',
action='store_true',
help='Delete original files after successful conversion')
args = parser.parse_args()
if not os.path.exists(args.source):
print(f"Error: Source path '{args.source}' does not exist.")
sys.exit(1)
start_time = time.time()
convert_files(args.source, args.target,
args.dry_run,
args.voice_mode,
args.delete_original)
end_time = time.time()
print(f"\nTotal execution time: {end_time - start_time:.2f} seconds")
if __name__ == "__main__":
main()