File size: 5,648 Bytes
6f39470
 
 
fbac153
6f39470
 
 
 
 
 
 
 
 
 
 
 
 
 
7ade725
 
 
 
fbac153
 
 
 
 
 
 
 
 
 
6f39470
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fbac153
7ade725
6f39470
fbac153
7ade725
fbac153
 
 
6f39470
 
fbac153
6f39470
 
 
fbac153
7ade725
 
 
 
 
 
 
 
 
8c30810
7ade725
 
 
 
fbac153
7ade725
 
 
 
 
fbac153
026557e
 
7ade725
 
 
 
fbac153
6f39470
 
 
 
 
 
 
 
7ade725
6f39470
 
 
 
7ade725
6f39470
 
7ade725
6f39470
fbac153
7ade725
fbac153
6f39470
fbac153
7ade725
 
 
6f39470
 
fbac153
7ade725
6f39470
 
 
 
 
 
 
 
 
7ade725
6f39470
 
fbac153
 
 
 
7ade725
 
fbac153
7ade725
fbac153
 
 
6f39470
 
 
 
4966b41
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
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)