Spaces:
Runtime error
Runtime error
| 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() |