import gradio as gr import subprocess import os import uuid # Carpeta temporal para guardar los videos generados TEMP_DIR = "temp_videos" os.makedirs(TEMP_DIR, exist_ok=True) def get_audio_duration(audio_path): """Obtiene duraciรณn del audio en segundos usando ffprobe""" try: result = subprocess.run([ "ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", audio_path ], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) return float(result.stdout.strip()) except: return None def generate_video(audio_path, image_path): if not os.path.isfile(audio_path) or not os.path.isfile(image_path): return "โŒ Missing or invalid input files." duration = get_audio_duration(audio_path) if not duration: return "โŒ Could not get audio duration. Check your audio file." output_filename = os.path.join("temp_videos", f"output_{uuid.uuid4().hex[:8]}.mp4") try: cmd = [ "ffmpeg", "-y", "-loop", "1", "-framerate", "1", "-i", image_path, "-i", audio_path, "-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2", # ๐Ÿ‘ˆ FIX AQUI "-c:v", "libx264", "-preset", "ultrafast", "-tune", "stillimage", "-c:a", "aac", "-b:a", "192k", "-t", str(duration), "-pix_fmt", "yuv420p", "-r", "1", output_filename ] result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) if os.path.exists(output_filename) and os.path.getsize(output_filename) > 0: return output_filename else: print("FFmpeg ERROR:", result.stderr) return "โŒ Something went wrong while generating the video." except Exception as e: return f"โš ๏ธ Error: {str(e)}" # Interfaz Gradio with gr.Blocks(theme="Taithrah/Minimal") as app: gr.Markdown("# ๐ŸŽถ Audio to Video Tool\nUpload an audio file and an image to generate a simple MP4 video (like TunesToTube)") with gr.Row(): audio = gr.Audio(label="๐ŸŽง Upload your audio file", type="filepath") image = gr.Image(label="๐Ÿ–ผ๏ธ Upload your image", type="filepath") submit = gr.Button("๐Ÿš€ Generate Video") output = gr.Video(label="๐ŸŽฌ Your Video") def handle_generate(audio_path, image_path): result = generate_video(audio_path, image_path) # Si es una string con error, la mandamos como mensaje, si es ruta, se muestra el video if result.endswith(".mp4") and os.path.exists(result): return result else: return gr.update(value=None, visible=False), gr.update(value=result, visible=True) submit.click(fn=handle_generate, inputs=[audio, image], outputs=output) app.launch()