import gradio as gr import os import shutil import subprocess import zipfile import tempfile from pathlib import Path def compress_video(input_path, output_path, compression_level): """ Сжимает видео используя ffmpeg и CRF. compression_level (1-3): 1 = Легкое сжатие (Высокое качество, CRF 23) 2 = Среднее сжатие (Баланс, CRF 28) 3 = Сильное сжатие (Низкое качество, CRF 35) """ # Настройки в зависимости от уровня слайдера if compression_level == 1: crf = "23" # Стандартное качество preset = "medium" elif compression_level == 2: crf = "28" # Хорошее сжатие preset = "faster" else: # level 3 crf = "35" # Сильное сжатие (могут быть артефакты) preset = "veryfast" cmd = [ "ffmpeg", "-y", # Перезаписать без вопросов "-i", str(input_path), "-c:v", "libx264", "-crf", crf, "-preset", preset, "-c:a", "aac", # Сжимаем аудио тоже "-b:a", "128k", str(output_path) ] try: # Запускаем ffmpeg, подавляем лишний вывод subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) return True except subprocess.CalledProcessError: print(f"Error converting {input_path}") return False def process_archive(zip_file, compression_level): if zip_file is None: return None # Создаем временные папки для работы temp_dir = tempfile.mkdtemp() input_dir = os.path.join(temp_dir, "input") output_dir = os.path.join(temp_dir, "output") os.makedirs(input_dir, exist_ok=True) os.makedirs(output_dir, exist_ok=True) try: # 1. Распаковка архива print("Распаковка архива...") with zipfile.ZipFile(zip_file.name, 'r') as zip_ref: zip_ref.extractall(input_dir) # 2. Обход файлов и конвертация video_extensions = {'.mp4', '.mov', '.avi', '.mkv', '.flv', '.wmv', '.webm'} file_count = 0 for root, _, files in os.walk(input_dir): for file_name in files: if file_name.startswith("._") or file_name == ".DS_Store": continue input_path = Path(root) / file_name # Сохраняем структуру папок relative_path = os.path.relpath(root, input_dir) output_subdir = os.path.join(output_dir, relative_path) os.makedirs(output_subdir, exist_ok=True) output_path = Path(output_subdir) / file_name # Проверяем расширение if input_path.suffix.lower() in video_extensions: print(f"Сжимаю: {file_name} (Уровень {compression_level})") # Меняем расширение на mp4 для единообразия, или оставляем как есть # Для надежности лучше выводить в mp4, так как кодек libx264 output_path = output_path.with_suffix(".mp4") success = compress_video(input_path, output_path, compression_level) if not success: # Если сбой, просто копируем оригинал shutil.copy2(input_path, output_path) else: # Если не видео, просто копируем файл shutil.copy2(input_path, output_path) file_count += 1 # 3. Запаковка результата print("Создание итогового архива...") output_zip_path = os.path.join(temp_dir, "compressed_videos") shutil.make_archive(output_zip_path, 'zip', output_dir) return output_zip_path + ".zip" finally: # Очистка (удаляем временные распакованные папки, но возвращаем путь к зипу) # shutil.rmtree(temp_dir) # Gradio само почистит temp файлы, но лучше оставить пока отдаем файл pass # Интерфейс Gradio with gr.Interface( fn=process_archive, inputs=[ gr.File(label="Загрузите ZIP архив с видео"), gr.Slider(minimum=1, maximum=3, step=1, value=2, label="Степень сжатия (1=Качество, 3=Маленький размер)") ], outputs=gr.File(label="Скачать сжатый архив"), title="Video Compressor", description="Загрузите архив с видео. Скрипт найдет все видео, сожмет их и вернет архив с сохранением структуры папок." ) as demo: pass if __name__ == "__main__": demo.launch()