VideoCompressor / app.py
asdas1241's picture
Update app.py
026557e verified
import os
import subprocess
import logging
from typing import Optional
from fastapi import FastAPI, HTTPException
import gradio as gr
# Configuraci贸n de logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# Directorios y rutas
UPLOAD_DIR = os.path.join(os.getcwd(), "uploads")
FFMPEG_PATH = "./ffmpeg"
# Crear directorios
os.makedirs(UPLOAD_DIR, exist_ok=True)
# Definir formatos de video y audio soportados
VIDEO_FORMATS = ['.mp4', '.avi', '.mov', '.mkv', '.webm', '.flv', '.wmv']
AUDIO_FORMATS = ['.mp3', '.wav', '.aac', '.flac', '.ogg', '.m4a', '.wma']
def detect_media_type(file_path: str) -> str:
"""Detectar si el archivo es de audio o video."""
ext = os.path.splitext(file_path)[1].lower()
if ext in VIDEO_FORMATS:
return 'video'
elif ext in AUDIO_FORMATS:
return 'audio'
else:
return 'unsupported'
def sanitize_filename(filename: str) -> str:
"""Limpiar y validar nombre de archivo para prevenir riesgos de seguridad."""
return ''.join(c for c in filename if c.isalnum() or c in ('.', '_', '-')).rstrip()
def ensure_unique_filename(directory: str, filename: str) -> str:
"""Generar un nombre de archivo 煤nico para evitar sobreescrituras."""
base, ext = os.path.splitext(filename)
counter = 1
new_filename = filename
while os.path.exists(os.path.join(directory, new_filename)):
new_filename = f"{base}_{counter}{ext}"
counter += 1
return new_filename
def make_ffmpeg_executable(ffmpeg_path: str):
"""Asegurar permisos correctos para FFmpeg."""
try:
subprocess.run(["chmod", "+x", ffmpeg_path], check=True)
logger.info(f"Permisos de FFmpeg configurados para {ffmpeg_path}")
except subprocess.CalledProcessError as e:
logger.error(f"Error al configurar permisos de FFmpeg: {e}")
raise
def convert_media(input_file: str, output_dir: str) -> str:
"""Convertir archivos multimedia con configuraciones optimizadas."""
try:
media_type = detect_media_type(input_file)
base_name = os.path.basename(input_file)
# Elegir extensi贸n de salida seg煤n el tipo de medio
output_extension = 'mp4' if media_type == 'video' else 'm4a'
output_filename = ensure_unique_filename(
output_dir,
f"{os.path.splitext(base_name)[0]}_converted.{output_extension}"
)
output_file = os.path.join(output_dir, output_filename)
if media_type == 'video':
# Configuraciones de conversi贸n de video
ffmpeg_command = [
FFMPEG_PATH,
'-i', input_file,
'-vf', 'fps=24', # Cambiar la tasa de fotogramas
'-c:v', 'libx264', # Codificador de video
'-c:a', 'libfdk_aac', # Codificador de audio
'-profile:a', 'aac_he_v2', # Perfil de audio
'-crf', '28', # Tasa de compresi贸n
'-b:a', '32k', # Tasa de bits de audio
'-preset', 'slow', # Preajuste de codificaci贸n
'-movflags', '+faststart', # Web optimization
output_file
]
elif media_type == 'audio':
# Configuraciones de conversi贸n de audio
ffmpeg_command = [
FFMPEG_PATH,
'-i', input_file,
'-vn', # Ignorar video
'-c:a', 'libfdk_aac', # Codificador AAC para M4A
'-profile:a', 'aac_he_v2',
'-b:a', '32k', # Calidad de audio alta
'-ar', '44100', # Frecuencia de muestreo
output_file
]
else:
raise ValueError("Formato no soportado")
# Ejecutar conversi贸n
result = subprocess.run(
ffmpeg_command,
check=True,
capture_output=True,
text=True
)
logger.info(f"Medio convertido exitosamente: {output_file}")
return output_file
except subprocess.CalledProcessError as e:
logger.error(f"Error de conversi贸n de FFmpeg: {e.stderr}")
raise HTTPException(status_code=500, detail=f"Fallo en la conversi贸n de medio: {e.stderr}")
except Exception as e:
logger.error(f"Error inesperado durante la conversi贸n: {e}")
raise HTTPException(status_code=500, detail="Error inesperado durante la conversi贸n")
def process_media(file_path: str) -> str:
"""Procesar medio completo."""
return convert_media(file_path, UPLOAD_DIR)
def gradio_interface(media: Optional[str]) -> Optional[str]:
"""Interfaz de Gradio para conversi贸n de medios."""
if not media:
raise gr.Error("No se ha subido ning煤n medio. Por favor, sube un archivo.")
try:
converted_media = process_media(media)
return converted_media
except Exception as e:
raise gr.Error(f"Conversi贸n fallida: {str(e)}")
# Asegurar permisos de FFmpeg
make_ffmpeg_executable(FFMPEG_PATH)
# Crear aplicaci贸n FastAPI
app = FastAPI()
# Configurar interfaz de Gradio
iface = gr.Interface(
fn=gradio_interface,
inputs=gr.File(
label="Subir Archivo",
type="filepath"
),
outputs=gr.File(
label="Descargar Archivo Convertido",
type="filepath"
),
title="馃帴馃幍 Convertidor Universal",
description="Convierte videos a MP4 y audios a M4A con configuraciones optimizadas",
theme="huggingface"
)
# Lanzar interfaz de Gradio
if __name__ == "__main__":
iface.launch(share=True)