137 lines
5.6 KiB
Python
137 lines
5.6 KiB
Python
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) |