360 / app.py
salomonsky's picture
Update app.py
000e38d verified
import gradio as gr
import requests
import json
import base64
def descargar_con_api(url, calidad, cookies_txt):
"""
Usa APIs de terceros que funcionan en HF Spaces
"""
try:
# Extraer video ID
import re
video_id_match = re.search(r'(?:v=|\/)([0-9A-Za-z_-]{11})', url)
if not video_id_match:
return None, "❌ URL de YouTube inválida"
video_id = video_id_match.group(1)
# Opción 1: Usar API de invidious (proxy de YouTube open source)
apis_disponibles = [
f"https://inv.riverside.rocks/api/v1/videos/{video_id}",
f"https://invidious.snopyta.org/api/v1/videos/{video_id}",
f"https://yewtu.be/api/v1/videos/{video_id}",
]
info_video = None
for api_url in apis_disponibles:
try:
response = requests.get(api_url, timeout=10)
if response.status_code == 200:
info_video = response.json()
break
except:
continue
if not info_video:
return None, "❌ No se pudo conectar a las APIs disponibles"
# Extraer información
titulo = info_video.get('title', 'Sin título')
duracion = info_video.get('lengthSeconds', 0)
# Filtrar formatos
formatos = info_video.get('formatStreams', [])
# Mapeo de calidades
calidad_map = {
"360p": "360p",
"480p": "480p",
"720p": "720p",
"1080p": "1080p"
}
calidad_buscada = calidad_map.get(calidad, "720p")
# Buscar formato
url_descarga = None
formato_encontrado = None
for fmt in formatos:
if fmt.get('qualityLabel') == calidad_buscada or fmt.get('quality') == calidad_buscada:
url_descarga = fmt.get('url')
formato_encontrado = fmt
break
# Si no encuentra la calidad exacta, buscar la más cercana
if not url_descarga and formatos:
formato_encontrado = formatos[0]
url_descarga = formato_encontrado.get('url')
if not url_descarga:
return None, "❌ No se encontró formato disponible"
# Mensaje con información
mensaje = f"✅ Video encontrado!\n\n"
mensaje += f"📺 Título: {titulo}\n"
mensaje += f"⏱️ Duración: {duracion//60}:{duracion%60:02d}\n"
mensaje += f"📊 Calidad: {formato_encontrado.get('qualityLabel', calidad)}\n\n"
mensaje += f"🔗 URL de descarga:\n{url_descarga}\n\n"
mensaje += f"💡 Copia la URL y pégala en tu navegador para descargar"
return url_descarga, mensaje
except Exception as e:
return None, f"❌ Error: {str(e)}"
def generar_enlace_descarga(url, calidad):
"""Genera enlaces de descarga usando servicios públicos"""
try:
import re
video_id_match = re.search(r'(?:v=|\/)([0-9A-Za-z_-]{11})', url)
if not video_id_match:
return None, "❌ URL inválida"
video_id = video_id_match.group(1)
# Servicios de descarga públicos
servicios = {
"Y2Mate": f"https://www.y2mate.com/youtube/{video_id}",
"SaveFrom": f"https://en.savefrom.net/1-youtube-video-downloader-{video_id}",
"YTMate": f"https://ytmate.ch/es/youtube-downloader/{video_id}",
}
mensaje = f"🔗 **Enlaces de descarga directa**\n\n"
mensaje += f"📺 Video ID: {video_id}\n"
mensaje += f"📊 Calidad solicitada: {calidad}\n\n"
mensaje += "Usa cualquiera de estos servicios:\n\n"
for nombre, link in servicios.items():
mensaje += f"🌐 **{nombre}**: {link}\n\n"
mensaje += "\n💡 **Instrucciones:**\n"
mensaje += "1. Haz clic en cualquier enlace de arriba\n"
mensaje += "2. Selecciona la calidad deseada\n"
mensaje += "3. Descarga el video\n\n"
mensaje += "⚠️ Estos servicios funcionan sin necesidad de cookies"
return None, mensaje
except Exception as e:
return None, f"❌ Error: {str(e)}"
# Interfaz de Gradio
with gr.Blocks(title="YouTube Downloader") as demo:
gr.Markdown("""
# 🎥 Descargador de YouTube
## ⚠️ Limitación de HuggingFace Spaces
HuggingFace Spaces **bloquea conexiones directas a YouTube** por seguridad.
Esta app te proporciona **enlaces directos** para descargar usando servicios públicos.
## 🎯 Opciones disponibles:
""")
with gr.Tabs():
with gr.Tab("🌐 Enlaces Directos (Recomendado)"):
gr.Markdown("""
### Genera enlaces a servicios de descarga populares
No requiere cookies ni instalación.
""")
with gr.Row():
with gr.Column():
url_input1 = gr.Textbox(
label="URL del video",
placeholder="https://www.youtube.com/watch?v=...",
)
calidad_input1 = gr.Radio(
choices=["360p", "480p", "720p", "1080p"],
value="720p",
label="Calidad preferida"
)
btn1 = gr.Button("🔗 Generar Enlaces", variant="primary")
with gr.Column():
output1 = gr.Textbox(label="Enlaces de descarga", lines=15)
btn1.click(
fn=generar_enlace_descarga,
inputs=[url_input1, calidad_input1],
outputs=[gr.File(visible=False), output1]
)
with gr.Tab("🔄 API Invidious"):
gr.Markdown("""
### Usa APIs alternativas de YouTube
Intenta obtener enlaces directos vía Invidious (puede fallar).
""")
with gr.Row():
with gr.Column():
url_input2 = gr.Textbox(
label="URL del video",
placeholder="https://www.youtube.com/watch?v=...",
)
calidad_input2 = gr.Radio(
choices=["360p", "480p", "720p", "1080p"],
value="720p",
label="Calidad"
)
cookies_input2 = gr.File(
label="Cookies (no necesario para videos públicos)",
file_types=[".txt"]
)
btn2 = gr.Button("🔍 Intentar Descarga", variant="secondary")
with gr.Column():
output2 = gr.Textbox(label="Resultado", lines=15)
btn2.click(
fn=descargar_con_api,
inputs=[url_input2, calidad_input2, cookies_input2],
outputs=[gr.File(visible=False), output2]
)
gr.Markdown("""
---
## 💡 Soluciones alternativas para descargas automáticas:
### Opción A: Ejecutar localmente en tu PC
```bash
pip install yt-dlp
yt-dlp --cookies cookies.txt "URL_DEL_VIDEO"
```
### Opción B: Usar Google Colab (Gratis)
```python
!pip install yt-dlp
!yt-dlp --cookies /content/cookies.txt "URL"
```
### Opción C: Desplegar en Railway/Render
Estas plataformas SÍ permiten conexiones a YouTube.
### Opción D: Extensiones de navegador
- Video DownloadHelper (Firefox/Chrome)
- SaveFrom.net Helper
---
## 📝 Nota sobre cookies:
Las cookies solo son necesarias para:
- Videos con restricción de edad (+18)
- Videos privados
- Videos con restricciones regionales
Para videos públicos normales, usa la pestaña **"Enlaces Directos"**.
""")
if __name__ == "__main__":
demo.launch()