from flask import Flask, render_template, request, send_file, after_this_request import subprocess import os import uuid import shutil app = Flask(__name__) BASE_DOWNLOADS_DIR = "downloads" os.makedirs(BASE_DOWNLOADS_DIR, exist_ok=True) @app.route("/", methods=["GET", "POST"]) def index(): if request.method == "POST": url = request.form.get("url") mode = request.form.get("mode") # 'audio' o 'video' download_type = request.form.get("type") # 'single' o 'playlist' if not url: # En caso de error, siempre renderiza la plantilla para que el JS pueda leer el error. return render_template("index.html", error="URL obligatoria"), 400 # Modo single o playlist if download_type == "single": folder_id = str(uuid.uuid4()) folder_path = os.path.join(BASE_DOWNLOADS_DIR, folder_id) os.makedirs(folder_path, exist_ok=True) filename_template = "%(title)s.%(ext)s" output_path = os.path.join(folder_path, filename_template) cmd = ["yt-dlp", "-o", output_path] if mode == "audio": cmd += ["-x", "--audio-format", "mp3"] cmd.append(url) try: subprocess.run(cmd, check=True) files = os.listdir(folder_path) if not files: return render_template("index.html", error="No se pudo descargar el archivo."), 500 downloaded_file_path = os.path.join(folder_path, files[0]) @after_this_request def cleanup(response): try: if os.path.exists(downloaded_file_path): os.remove(downloaded_file_path) if os.path.exists(folder_path): os.rmdir(folder_path) except Exception as e: print(f"Error al borrar archivos: {e}") return response # Si es exitoso, solo envía el archivo. No render_template aquí. return send_file(downloaded_file_path, as_attachment=True, download_name=files[0]) except subprocess.CalledProcessError as e: # Captura la salida de error de yt-dlp para un mensaje más específico si es posible error_message = f"Error al descargar el vídeo: {e}" if e.stderr: error_message += f" - {e.stderr.decode().strip()}" return render_template("index.html", error=error_message), 500 except Exception as e: return render_template("index.html", error=f"Error inesperado: {e}"), 500 elif download_type == "playlist": folder_id = str(uuid.uuid4()) folder_path = os.path.join(BASE_DOWNLOADS_DIR, folder_id) os.makedirs(folder_path, exist_ok=True) # Obtener título real de la playlist try: result = subprocess.run( ["yt-dlp", "--flat-playlist", "--print", "%(playlist_title)s", url], stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, text=True ) playlist_title = result.stdout.strip().splitlines()[0] playlist_title_clean = "".join(c for c in playlist_title if c.isalnum() or c in " _-").strip().replace(" ", "_") except subprocess.CalledProcessError as e: error_message = f"Error al obtener el título de la playlist: {e}" if e.stderr: error_message += f" - {e.stderr.decode().strip()}" return render_template("index.html", error=error_message), 500 except Exception as e: return render_template("index.html", error=f"Error inesperado al obtener título de playlist: {e}"), 500 output_path = os.path.join(folder_path, "%(title)s.%(ext)s") cmd = ["yt-dlp", "-o", output_path] if mode == "audio": cmd += ["-x", "--audio-format", "mp3"] cmd.append(url) try: subprocess.run(cmd, check=True) zip_path = shutil.make_archive(folder_path, 'zip', folder_path) zip_filename = f"{playlist_title_clean}.zip" @after_this_request def cleanup(response): try: if os.path.exists(folder_path): shutil.rmtree(folder_path) if os.path.exists(zip_path): os.remove(zip_path) except Exception as e: print(f"Error al borrar archivos de la playlist: {e}") return response # Si es exitoso, solo envía el archivo. No render_template aquí. return send_file(zip_path, as_attachment=True, download_name=zip_filename, mimetype='application/zip') except subprocess.CalledProcessError as e: error_message = f"Error al descargar la lista: {e}" if e.stderr: error_message += f" - {e.stderr.decode().strip()}" return render_template("index.html", error=error_message), 500 except Exception as e: return render_template("index.html", error=f"Error inesperado al descargar playlist: {e}"), 500 else: return render_template("index.html", error="Tipo de descarga no válido."), 400 return render_template("index.html") if __name__ == "__main__": app.run(host="0.0.0.0", port=5000)