Compare commits

..

No commits in common. "f8924a2965f09ac9b9a3b644ce3d7498518b9b89" and "c30669bad241ef3fff16ece084d8d3962ecae2fb" have entirely different histories.

46 changed files with 1463 additions and 7708 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,347 +0,0 @@
#!/bin/bash
# ============================================================
# TubeScript API - COMANDOS RÁPIDOS
# ============================================================
# Usa este archivo como referencia rápida de comandos
# Copia y pega los comandos que necesites
echo "📚 TubeScript API - Comandos Rápidos"
echo ""
# ============================================================
# 🚀 INICIO RÁPIDO
# ============================================================
cat << 'EOF'
🚀 INICIO RÁPIDO (3 pasos):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1⃣ Crear red:
./docker-create-network.sh
2⃣ Iniciar servicios:
./docker-manager.sh
# O:
docker-compose up -d
3⃣ Acceder:
API: http://localhost:8080/docs
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🎛️ GESTIÓN DE SERVICIOS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📍 Gestor Interactivo (Recomendado):
./docker-manager.sh
📍 Iniciar TODO:
docker-compose up -d
📍 Iniciar SOLO API:
./docker-start-api.sh
📍 Detener TODO:
./docker-stop-all.sh
# O:
docker-compose down
📍 Reiniciar TODO:
docker-compose restart
📍 Ver Estado:
docker ps
docker ps -a # Incluir detenidos
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 LOGS Y MONITOREO
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📍 Ver Logs API:
docker logs -f tubescript_api
# O:
./docker-logs-separate.sh api
📍 Ver Logs AMBOS:
docker-compose logs -f
# O:
./docker-logs-separate.sh both
📍 Ver últimas 100 líneas:
docker logs --tail 100 tubescript_api
📍 Ver recursos (CPU/RAM):
docker stats
# O solo TubeScript:
docker stats tubescript_api
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🔄 ACTUALIZACIÓN Y MANTENIMIENTO
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📍 Actualizar yt-dlp:
docker exec tubescript_api pip install --upgrade yt-dlp
📍 Reconstruir Contenedores:
docker-compose down
docker-compose build --no-cache
docker-compose up -d
📍 Actualizar código (con Git):
git pull
docker-compose down
docker-compose build
docker-compose up -d
📍 Limpiar contenedores viejos:
docker container prune -f
📍 Limpiar imágenes viejas:
docker image prune -a -f
📍 Limpiar TODO (⚠️ cuidado):
docker system prune -a --volumes
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🐛 DEBUGGING Y SOLUCIÓN DE PROBLEMAS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📍 Entrar al contenedor (shell):
docker exec -it tubescript_api /bin/bash
📍 Verificar versión yt-dlp:
docker exec tubescript_api yt-dlp --version
📍 Probar endpoint manualmente:
curl http://localhost:8080/stream/G01-33V6I2g
📍 Ver error completo:
docker logs tubescript_api 2>&1 | tail -50
📍 Reiniciar un servicio:
docker restart tubescript_api
📍 Ver qué usa un puerto:
lsof -i :8080 # API
📍 Matar proceso en un puerto (macOS/Linux):
kill -9 $(lsof -ti:8080)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🌐 ACCESO Y URLs
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📍 API FastAPI:
http://localhost:8080
📍 API Docs (Swagger):
http://localhost:8080/docs
📍 API ReDoc:
http://localhost:8080/redoc
📍 Abrir en navegador (macOS):
open http://localhost:8080/docs
📍 Abrir en navegador (Linux):
xdg-open http://localhost:8080/docs
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚙️ CONFIGURACIÓN
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📍 Crear/Editar .env:
cp .env.example .env
nano .env
# O:
vim .env
📍 Ver configuración actual:
cat stream_config.json | python3 -m json.tool
📍 Ver procesos activos:
cat process_state.json | python3 -m json.tool
📍 Reiniciar después de cambiar .env:
docker-compose down
docker-compose up -d
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🧪 TESTING Y PRUEBAS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📍 Probar obtener stream:
curl -X GET "http://localhost:8080/stream/G01-33V6I2g" | jq
📍 Probar obtener transcripción:
curl -X GET "http://localhost:8080/transcript/WODSeZfCnUg?lang=es" | jq
📍 Probar con HTTPie:
http GET localhost:8080/stream/G01-33V6I2g
📍 Extraer solo la URL del stream:
curl -s http://localhost:8080/stream/G01-33V6I2g | jq -r '.stream_url'
📍 Test completo de transmisión:
# 1. Obtener URL
STREAM_URL=$(curl -s http://localhost:8080/stream/G01-33V6I2g | jq -r '.stream_url')
# 2. Transmitir (test de 10 segundos)
timeout 10 ffmpeg -re -i "$STREAM_URL" -c copy -f flv rtmp://test/key
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📊 INFORMACIÓN DEL SISTEMA
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📍 Ver información de contenedores:
docker inspect tubescript_api
📍 Ver red de Docker:
docker network inspect tubescript-network
📍 Ver volúmenes:
docker volume ls
📍 Ver tamaño de imágenes:
docker images | grep tubescript
📍 Ver uso de disco de Docker:
docker system df
📍 Ver procesos dentro del contenedor:
docker top tubescript_api
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🔐 SEGURIDAD Y PERMISOS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📍 Dar permisos a scripts:
chmod +x *.sh
📍 Ver permisos actuales:
ls -la *.sh
📍 Cambiar permisos de archivos de config:
chmod 600 stream_config.json
chmod 600 cookies.txt
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🎯 COMANDOS DE PRODUCCIÓN
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📍 Iniciar en segundo plano:
docker-compose up -d
📍 Ver estado de salud:
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
📍 Reinicio automático (ya configurado):
# En docker-compose.yml:
restart: unless-stopped
📍 Backup de configuración:
tar -czf backup_$(date +%Y%m%d).tar.gz \
stream_config.json \
process_state.json \
streams_state.json \
cookies.txt \
.env
📍 Restaurar backup:
tar -xzf backup_20260130.tar.gz
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
💡 TIPS Y TRUCOS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📍 Alias útiles (agregar a ~/.zshrc o ~/.bashrc):
alias ts-start='docker-compose up -d'
alias ts-stop='docker-compose down'
alias ts-logs='docker-compose logs -f'
alias ts-restart='docker-compose restart'
alias ts-api='open http://localhost:8080/docs'
📍 Ver logs con colores (si tienes grc):
grc docker logs -f tubescript_api
📍 Buscar en logs:
docker logs tubescript_api 2>&1 | grep "ERROR"
📍 Seguir solo errores:
docker logs -f tubescript_api 2>&1 | grep -i error
📍 Contar líneas de log:
docker logs tubescript_api 2>&1 | wc -l
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📚 DOCUMENTACIÓN
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📍 Ver documentación disponible:
ls -1 *.md
📍 Abrir documentación:
QUICKSTART_COMPLETO.md # Inicio rápido
API_EXAMPLES.md # Ejemplos de API
RESUMEN_IMPLEMENTACION.md # Resumen completo
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🆘 AYUDA RÁPIDA
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
❌ PROBLEMA: "No se pudo obtener URL del stream"
✅ SOLUCIÓN:
docker exec streamlit_panel pip install --upgrade yt-dlp
# O reconstruir:
docker-compose down && docker-compose build --no-cache && docker-compose up -d
❌ PROBLEMA: "Puerto ya en uso"
✅ SOLUCIÓN:
lsof -i :8080 # Ver qué lo usa
# Cambiar puerto en docker-compose.yml o matar proceso
❌ PROBLEMA: "Error al descargar subtítulos"
✅ SOLUCIÓN:
# El video puede no tener subtítulos
# Prueba con otro video
❌ PROBLEMA: "Contenedor se detiene"
✅ SOLUCIÓN:
docker logs tubescript_api
docker logs streamlit_panel
# Ver el error específico
❌ PROBLEMA: "Network not found"
✅ SOLUCIÓN:
./docker-create-network.sh
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✨ Para ayuda interactiva, ejecuta:
./docker-manager.sh
📖 Para documentación completa:
cat QUICKSTART_COMPLETO.md
🌐 Para acceder al panel:
open http://localhost:8501
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
TubeScript API Pro © 2026
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
EOF

View File

@ -1,8 +1,3 @@
# Nota importante: El frontend Streamlit ha sido eliminado
> Se ha eliminado el panel Streamlit en esta rama/proyecto. Las instrucciones a continuación permanecen para referencia histórica, pero el flujo operativo actual es usar únicamente la API (FastAPI) y los comandos de Docker relacionados con el servicio `api`.
# 🐳 Comandos Docker - Ejecución por Separado
## 📋 Índice

View File

@ -1,417 +0,0 @@
# 🐳 TubeScript API - Guía de Comandos Docker Separados
Esta guía te muestra cómo ejecutar los servicios de TubeScript API por separado, permitiéndote iniciar solo el API FastAPI o solo el panel Streamlit de forma independiente.
## 📋 Tabla de Contenido
- [Requisitos Previos](#requisitos-previos)
- [Configuración Inicial](#configuración-inicial)
- [Comandos Disponibles](#comandos-disponibles)
- [Uso Individual de Servicios](#uso-individual-de-servicios)
- [Solución de Problemas](#solución-de-problemas)
---
## 📦 Requisitos Previos
Asegúrate de tener instalado:
- **Docker** (versión 20.10 o superior)
- **Docker Compose** (opcional, solo para uso conjunto)
Verifica la instalación:
```bash
docker --version
docker-compose --version
```
---
## ⚙️ Configuración Inicial
### 1. Crear la Red de Docker
Primero, crea la red compartida entre servicios:
```bash
./docker-create-network.sh
```
O manualmente:
```bash
docker network create tubescript-network
```
### 2. Configurar Variables de Entorno
Copia el archivo de ejemplo y edita según tu configuración:
```bash
cp .env.example .env
nano .env
```
**Configuraciones importantes:**
```env
# Para servicios en el mismo servidor (Docker)
API_URL=http://tubescript-api:8000
# Para desarrollo local (sin Docker)
API_URL=http://localhost:8080
# Para producción con dominio
API_URL=https://api.tudominio.com
```
---
## 🚀 Comandos Disponibles
### 1⃣ Iniciar solo FastAPI
```bash
./docker-start-api.sh
```
**Características:**
- Puerto: `8080` (host) → `8000` (contenedor)
- Documentación: http://localhost:8080/docs
- Endpoint de prueba: http://localhost:8080/stream/VIDEO_ID
**Ver logs:**
```bash
docker logs -f tubescript_api
```
**Detener:**
```bash
docker stop tubescript_api
```
---
### 3⃣ Ver Logs
Usa el script de logs para ver la salida de los servicios:
```bash
# Ver logs de FastAPI
./docker-logs-separate.sh api
# Ver logs de Streamlit
./docker-logs-separate.sh streamlit
# Ver logs de ambos (requiere docker-compose)
./docker-logs-separate.sh both
```
O directamente con Docker:
```bash
docker logs -f tubescript_api
docker logs -f streamlit_panel
```
---
### 4⃣ Detener Todos los Servicios
```bash
./docker-stop-all.sh
```
O manualmente:
```bash
docker stop tubescript_api streamlit_panel
docker rm tubescript_api streamlit_panel
```
---
## 🎯 Uso Individual de Servicios
### Escenario 1: Solo API (Backend)
Si solo necesitas el API para integraciones o pruebas:
```bash
# 1. Crear red
./docker-create-network.sh
# 2. Iniciar API
./docker-start-api.sh
# 3. Probar endpoint
curl http://localhost:8080/stream/VIDEO_ID
```
### Escenario 2: Solo Streamlit (Frontend)
Si ya tienes el API corriendo en otro servidor:
```bash
# 1. Configurar URL del API remoto
echo "API_URL=https://api.tudominio.com" > .env
# 2. Iniciar Streamlit
./docker-start-streamlit.sh
# 3. Abrir navegador
open http://localhost:8501
```
### Escenario 3: Ambos Servicios Separados
Para desarrollo o testing:
```bash
# 1. Crear red compartida
./docker-create-network.sh
# 2. Iniciar API
./docker-start-api.sh
# 3. Esperar que API esté listo (verificar logs)
docker logs -f tubescript_api
# Presiona Ctrl+C cuando veas "Application startup complete"
# 4. Iniciar Streamlit
./docker-start-streamlit.sh
# 5. Verificar ambos servicios
curl http://localhost:8080/docs
open http://localhost:8501
```
### Escenario 4: Usar Docker Compose (Recomendado)
Para producción, usa docker-compose:
```bash
# Iniciar ambos servicios
docker-compose up -d
# Ver logs
docker-compose logs -f
# Detener
docker-compose down
```
---
## 🔧 Comandos Docker Manuales
### FastAPI
**Construir imagen:**
```bash
docker build -t tubescript-api .
```
**Ejecutar contenedor:**
```bash
docker run -d \
--name tubescript_api \
--network tubescript-network \
-p 8080:8000 \
-v "$(pwd)/cookies.txt:/app/cookies.txt:ro" \
-v "$(pwd)/stream_config.json:/app/stream_config.json" \
-v "$(pwd)/streams_state.json:/app/streams_state.json" \
-v "$(pwd)/data:/app/data" \
-e PYTHONUNBUFFERED=1 \
tubescript-api \
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
```
### Streamlit
**Ejecutar contenedor:**
```bash
docker run -d \
--name streamlit_panel \
--network tubescript-network \
-p 8501:8501 \
-v "$(pwd)/cookies.txt:/app/cookies.txt:ro" \
-v "$(pwd)/stream_config.json:/app/stream_config.json" \
-v "$(pwd)/streams_state.json:/app/streams_state.json" \
-v "$(pwd)/data:/app/data" \
-e PYTHONUNBUFFERED=1 \
-e API_URL=http://tubescript-api:8000 \
tubescript-api \
streamlit run streamlit_app.py --server.port=8501 --server.address=0.0.0.0 --server.headless=true --browser.gatherUsageStats=false
```
---
## 🔍 Verificar Estado de Servicios
### Listar contenedores activos:
```bash
docker ps
```
### Verificar red:
```bash
docker network inspect tubescript-network
```
### Ver recursos utilizados:
```bash
docker stats tubescript_api streamlit_panel
```
---
## 🛠️ Solución de Problemas
### Problema: "Red no existe"
**Solución:**
```bash
./docker-create-network.sh
```
### Problema: "Puerto ya en uso"
**Identificar proceso:**
```bash
lsof -i :8080 # Para FastAPI
lsof -i :8501 # Para Streamlit
```
**Cambiar puerto en docker-compose.yml:**
```yaml
ports:
- "8081:8000" # Cambiar 8080 por 8081
```
### Problema: "Streamlit no se conecta al API"
**Verificar API_URL:**
```bash
docker exec streamlit_panel env | grep API_URL
```
**Probar conectividad:**
```bash
docker exec streamlit_panel curl http://tubescript-api:8000/docs
```
### Problema: "Error al obtener stream m3u8"
**Actualizar yt-dlp:**
```bash
docker exec tubescript_api pip install --upgrade yt-dlp
docker exec streamlit_panel pip install --upgrade yt-dlp
```
**O reconstruir contenedores:**
```bash
docker-compose down
docker-compose build --no-cache
docker-compose up -d
```
### Problema: "Contenedor se detiene inmediatamente"
**Ver logs completos:**
```bash
docker logs tubescript_api
docker logs streamlit_panel
```
**Ejecutar en modo interactivo para debugging:**
```bash
docker run -it --rm \
--network tubescript-network \
-p 8080:8000 \
tubescript-api \
uvicorn main:app --host 0.0.0.0 --port 8000
```
---
## 📊 Monitoreo y Mantenimiento
### Ver logs en tiempo real:
```bash
# Todos los contenedores
docker logs -f tubescript_api
docker logs -f streamlit_panel
# Con marca de tiempo
docker logs -f --timestamps tubescript_api
```
### Limpiar recursos no utilizados:
```bash
# Eliminar contenedores detenidos
docker container prune
# Eliminar imágenes sin usar
docker image prune -a
# Limpiar todo (cuidado)
docker system prune -a --volumes
```
### Actualizar servicios:
```bash
# Detener servicios
./docker-stop-all.sh
# Reconstruir con últimos cambios
docker-compose build --no-cache
# Reiniciar
docker-compose up -d
```
---
## 📝 Resumen de Comandos Rápidos
```bash
# Iniciar servicios individuales
./docker-create-network.sh # Crear red (solo primera vez)
./docker-start-api.sh # Iniciar FastAPI
./docker-start-streamlit.sh # Iniciar Streamlit
# Ver logs
./docker-logs-separate.sh api # Logs de API
./docker-logs-separate.sh streamlit # Logs de Streamlit
# Detener servicios
./docker-stop-all.sh # Detener todos
# Docker Compose (alternativa)
docker-compose up -d # Iniciar ambos
docker-compose logs -f # Ver logs
docker-compose down # Detener ambos
```
---
## 🌐 URLs de Acceso
| Servicio | URL | Descripción |
|----------|-----|-------------|
| FastAPI | http://localhost:8080 | API principal |
| FastAPI Docs | http://localhost:8080/docs | Documentación interactiva |
| Streamlit | http://localhost:8501 | Panel de control web |
---
## 📚 Documentación Adicional
- [README.md](README.md) - Guía general del proyecto
- [DOCKER_GUIDE.md](DOCKER_GUIDE.md) - Guía completa de Docker
- [API_URL_CONFIG.md](API_URL_CONFIG.md) - Configuración de URL del API
---
**TubeScript API Pro © 2026**
# Nota: Streamlit eliminado
> El panel Streamlit fue eliminado — las secciones que mencionan la ejecución del panel permanecen como referencia histórica. Para uso actual, emplea solamente la API.

View File

@ -1,7 +1,3 @@
# Nota: Streamlit eliminado
> El panel Streamlit fue eliminado en esta rama; las instrucciones que mencionan Streamlit se mantienen solo como referencia histórica. Usa la API (main.py) para operaciones actuales.
# 🐳 Guía de Uso con Docker - TubeScript-API
## 🎯 Descripción
@ -81,6 +77,11 @@ docker-compose logs -f
Una vez iniciados los contenedores:
### Panel Web Streamlit (Frontend)
```
http://localhost:8501
```
### API FastAPI (Backend)
```
http://localhost:8080
@ -101,9 +102,9 @@ http://localhost:8080/docs
├─────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ FastAPI Backend │ ◄──│ Streamlit Panel │ │
│ │ (Puerto 8000) │ │ (Puerto 8501) │ │
│ │ tubescript_api │ │ streamlit_panel │ │
│ │ Streamlit Panel │ │ FastAPI Backend │ │
│ │ (Puerto 8501) │◄────►│ (Puerto 8000) │ │
│ │ streamlit_panel │ │ tubescript_api │ │
│ └──────────────────┘ └──────────────────┘ │
│ │ │ │
│ └─────────┬───────────────┘ │
@ -154,6 +155,9 @@ docker-compose logs -f
# O usar el script
./docker-logs.sh
# Solo el panel Streamlit
docker-compose logs -f streamlit-panel
# Solo la API
docker-compose logs -f tubescript-api
```
@ -174,6 +178,7 @@ docker-compose down
docker-compose restart
# Reiniciar uno específico
docker-compose restart streamlit-panel
docker-compose restart tubescript-api
```
@ -193,10 +198,11 @@ docker-compose up -d --build
```bash
# Acceder al shell del contenedor
docker exec -it streamlit_panel bash
docker exec -it tubescript_api bash
# Ejecutar comando en el contenedor
docker exec tubescript_api ls -la
docker exec streamlit_panel ls -la
```
### Limpiar Todo
@ -233,6 +239,10 @@ Edita `docker-compose.yml`:
```yaml
services:
streamlit-panel:
ports:
- "9090:8501" # Cambiar puerto del host a 9090
tubescript-api:
ports:
- "9091:8000" # Cambiar puerto del host a 9091
@ -245,6 +255,7 @@ services:
Los servicios tienen health checks configurados:
- **FastAPI**: Verifica `/docs` cada 30 segundos
- **Streamlit**: Verifica puerto 8501 cada 30 segundos
Ver estado de salud:

View File

@ -1,53 +0,0 @@
# Ejecutar servicios Docker (API y herramientas) por separado
Este archivo explica cómo levantar el API de forma separada para probar cookies/proxy y cómo pasar la variable `API_PROXY` para usar Tor u otro proxy.
Levantar solo el API (recomendado para desarrollo):
```bash
# Reconstruir la imagen del API y levantar solo el servicio tubescript-api
API_PROXY="" docker compose -f docker-compose.yml build --no-cache tubescript-api
API_PROXY="" docker compose -f docker-compose.yml up -d tubescript-api
# Ver logs
docker logs -f tubescript_api
```
Levantar el API con proxy (Tor ejemplo):
```bash
# Asegúrate de tener Tor corriendo en tu host (socks5 en 127.0.0.1:9050)
# macOS: brew install tor && tor &
# Levantar con API_PROXY apuntando a tor
API_PROXY="socks5h://host.docker.internal:9050" \
docker compose -f docker-compose.yml up -d --build tubescript-api
# Nota: en macOS dentro de contenedores, usa host.docker.internal para apuntar al host
```
Montar cookies y probar endpoints
```bash
# Asegúrate de que ./cookies.txt existe en la raíz del proyecto o súbelo con la API
curl -X POST "http://127.0.0.1:8000/upload_cookies" -F "file=@/ruta/a/cookies.txt"
# Probar metadata
curl -s "http://127.0.0.1:8000/debug/metadata/K08TM4OVLyo" | jq .
# Intento de subtítulos verboso
curl -s "http://127.0.0.1:8000/debug/fetch_subs/K08TM4OVLyo?lang=es" | jq .
# Obtener stream URL
curl -s "http://127.0.0.1:8000/stream/K08TM4OVLyo" | jq .
```
Rebuild del API (cuando hagas cambios en `main.py` o dependencias):
```bash
# Reconstruir imagen (sin cache) y levantar
docker compose -f docker-compose.yml build --no-cache tubescript-api
docker compose -f docker-compose.yml up -d tubescript-api
# Si cambias requirements.txt, reconstruye la imagen para que pip instale nuevas dependencias
```

View File

@ -1,27 +0,0 @@
# Dockerfile para la API (FastAPI) con yt-dlp y ffmpeg
FROM python:3.11-slim
ENV PYTHONUNBUFFERED=1
# Instalar ffmpeg y herramientas necesarias
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ffmpeg \
curl \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Copiar requirements y instalar dependencias
COPY requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir -r /app/requirements.txt \
&& pip install --no-cache-dir yt-dlp
# Copiar el resto del código
COPY . /app
EXPOSE 8000
# Comando por defecto para ejecutar la API
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

View File

@ -1,2 +0,0 @@
# Dockerfile.streamlit removed - Streamlit UI has been removed from this project.
# If you need to restore the Streamlit frontend, revert this file from version control.

View File

@ -1,218 +0,0 @@
# 🎯 Guía Rápida: Obtener Transcripts de YouTube usando Chrome
## ✅ Método Recomendado: Usar cookies desde Chrome directamente
Este método es el **MÁS FÁCIL** porque no necesitas exportar cookies manualmente. yt-dlp lee las cookies directamente desde tu navegador.
### 📋 Requisitos
- Chrome, Firefox o Brave instalado
- Estar logueado en YouTube en el navegador
- yt-dlp actualizado: `pip install -U yt-dlp`
---
## 🚀 Opción 1: Usar el script automático (Recomendado)
### Paso 1: Ejecutar el script
```bash
./get_transcript_chrome.sh VIDEO_ID
```
**Ejemplos:**
```bash
# Usar perfil por defecto de Chrome
./get_transcript_chrome.sh K08TM4OVLyo
# Especificar idioma
./get_transcript_chrome.sh K08TM4OVLyo es
# Usar Firefox en lugar de Chrome
./get_transcript_chrome.sh K08TM4OVLyo es firefox
# Usar un perfil específico de Chrome
./get_transcript_chrome.sh K08TM4OVLyo es chrome Default
./get_transcript_chrome.sh K08TM4OVLyo es chrome "Profile 1"
```
### Paso 2: Resultado
El script generará:
- `VIDEO_ID.LANG.vtt` - Archivo de subtítulos
- `VIDEO_ID_transcript.txt` - Texto plano del transcript
---
## 🔧 Opción 2: Comando manual de yt-dlp
### Comando básico
```bash
yt-dlp --cookies-from-browser chrome \
--skip-download --write-auto-sub \
--sub-lang es --sub-format vtt \
-o "%(id)s.%(ext)s" \
"https://www.youtube.com/watch?v=VIDEO_ID"
```
### Con perfil específico
```bash
yt-dlp --cookies-from-browser "chrome:Profile 1" \
--skip-download --write-auto-sub \
--sub-lang es --sub-format vtt \
-o "%(id)s.%(ext)s" \
"https://www.youtube.com/watch?v=VIDEO_ID"
```
---
## 📂 Encontrar tus perfiles de Chrome
### macOS:
```bash
ls -la ~/Library/Application\ Support/Google/Chrome/
```
### Linux:
```bash
ls -la ~/.config/google-chrome/
```
### Windows:
```cmd
dir "%LOCALAPPDATA%\Google\Chrome\User Data"
```
Los perfiles típicos son:
- `Default` - Perfil por defecto
- `Profile 1`, `Profile 2`, etc. - Perfiles adicionales
---
## 🔍 Ver qué perfil estás usando en Chrome
1. Abre Chrome
2. Haz clic en tu avatar (esquina superior derecha)
3. El nombre del perfil aparece en el menú
4. O ve a `chrome://version/` y busca "Profile Path"
---
## ⚠️ Solución de Problemas
### Problema 1: "ERROR: Unable to extract cookies"
**Solución**: Cierra Chrome completamente antes de ejecutar el comando.
```bash
# macOS: Cerrar Chrome por completo
killall "Google Chrome"
# Luego ejecuta el comando
./get_transcript_chrome.sh VIDEO_ID
```
### Problema 2: "HTTP Error 429"
Significa que YouTube está bloqueando tu IP. **Soluciones**:
1. **Usa Tor/VPN** (más efectivo):
```bash
# Instalar y arrancar Tor
brew install tor && tor &
# Usar con proxy
yt-dlp --cookies-from-browser chrome \
--proxy "socks5h://127.0.0.1:9050" \
--skip-download --write-auto-sub \
--sub-lang es --sub-format vtt \
-o "%(id)s.%(ext)s" \
"https://www.youtube.com/watch?v=VIDEO_ID"
```
2. **Espera unas horas** y vuelve a intentar
3. **Usa otra red** (móvil 4G/5G, otra WiFi)
### Problema 3: No se generan archivos
Verifica que:
- Estés logueado en YouTube en ese navegador
- El video tenga subtítulos (prueba con otro video)
- Tengas la última versión de yt-dlp: `pip install -U yt-dlp`
---
## 📖 Ejemplos Prácticos
### Obtener transcript de un video en vivo
```bash
./get_transcript_chrome.sh VIDEO_ID_EN_VIVO es chrome
```
### Obtener en múltiples idiomas
```bash
# Español
./get_transcript_chrome.sh VIDEO_ID es chrome
# Inglés
./get_transcript_chrome.sh VIDEO_ID en chrome
# Español (variantes latinoamericanas)
yt-dlp --cookies-from-browser chrome \
--skip-download --write-auto-sub \
--sub-lang "es,es-419,es-MX" --sub-format vtt \
-o "%(id)s.%(ext)s" \
"https://www.youtube.com/watch?v=VIDEO_ID"
```
### Convertir VTT a texto plano
```bash
# Usando grep (rápido)
grep -v "WEBVTT" VIDEO_ID.es.vtt | grep -v "^$" | grep -v "^[0-9][0-9]:" > transcript.txt
# Usando el script de Python del proyecto
python3 << 'EOF'
from main import parse_subtitle_format
with open('VIDEO_ID.es.vtt', 'r') as f:
vtt = f.read()
segments = parse_subtitle_format(vtt, 'vtt')
text = '\n'.join([s['text'] for s in segments])
print(text)
EOF
```
---
## 🔗 Integración con la API
Una vez que obtengas el archivo VTT, puedes subirlo al API:
```bash
curl -X POST "http://127.0.0.1:8000/upload_vtt/VIDEO_ID" \
-F "file=@VIDEO_ID.es.vtt" | jq .
```
La API te devolverá:
- `segments`: Array de segmentos parseados con timestamps
- `text`: Texto concatenado completo
- `count`: Número de segmentos
---
## 🎯 Resumen: ¿Qué método usar?
| Situación | Método Recomendado |
|-----------|-------------------|
| **Uso diario, varios videos** | Script `get_transcript_chrome.sh` |
| **Comando rápido, un video** | `yt-dlp --cookies-from-browser chrome ...` |
| **Tienes HTTP 429** | Usar Tor/VPN + cookies desde Chrome |
| **No puedes ejecutar comandos** | Subir VTT manualmente al API |
---
## 📞 Ayuda Adicional
Ver documentación completa: `SOLUCION_HTTP_429_TRANSCRIPT.md`
**Comando de ayuda del script:**
```bash
./get_transcript_chrome.sh
```
---
**Última actualización**: 2025-02-22

View File

@ -1,10 +1,3 @@
# Nota: Streamlit eliminado
> El panel Streamlit fue eliminado. Las instrucciones que mencionan Streamlit se mantienen como referencia, pero el flujo actual usa únicamente la API.
# Guía Rápida Docker + FFmpeg
╔══════════════════════════════════════════════════════════════════════╗
║ ║
║ 🚀 GUÍA RÁPIDA: Docker + Endpoint + FFmpeg ║
@ -73,6 +66,31 @@ docker stop api && docker rm api
---
### Solo Streamlit (Frontend)
```bash
# Construir
docker build -t tubescript-streamlit .
# Ejecutar (conectado a API en host)
docker run -d --name panel -p 8501:8501 \
-e API_URL=http://host.docker.internal:8080 \
-v $(pwd)/stream_config.json:/app/stream_config.json \
tubescript-streamlit \
streamlit run streamlit_app.py \
--server.port=8501 \
--server.address=0.0.0.0 \
--server.headless=true
# Ver logs
docker logs -f panel
# Detener
docker stop panel && docker rm panel
```
---
### Ambos con docker-compose
```bash

View File

@ -1,246 +0,0 @@
# ✅ SOLUCIÓN FINAL - Instrucciones Paso a Paso
## 🎯 El Problema
```
ERROR: [youtube] 6hini9Xz_fc: Requested format is not available
```
## ✅ Cambio Implementado
He simplificado **completamente** el comando yt-dlp en `main.py` (línea ~95):
### ANTES:
```python
command = [
"yt-dlp",
"--skip-download",
"--dump-json",
"--no-warnings",
"--extractor-args", "youtube:player_client=android", # Esto puede causar problemas
url
]
```
### AHORA:
```python
command = [
"yt-dlp",
"--skip-download",
"--dump-json",
"--no-warnings",
url
]
```
**Cambio clave:** Eliminé `--extractor-args` que puede causar conflictos con YouTube.
---
## 🚀 PASOS PARA APLICAR LA SOLUCIÓN
### Paso 1: Detener Todo
```bash
cd /Users/cesarmendivil/Documents/Nextream/TubeScript-API
# Detener servicios
docker-compose down
# O forzar detención
docker stop $(docker ps -aq) 2>/dev/null
docker rm $(docker ps -aq) 2>/dev/null
```
### Paso 2: Limpiar Imágenes Antiguas
```bash
# Eliminar imagen vieja
docker rmi tubescript-api
# O limpiar todo Docker
docker system prune -a
```
### Paso 3: Reconstruir la Imagen
```bash
# Build desde cero (SIN CACHÉ)
docker-compose build --no-cache tubescript-api
# Esto toma 3-5 minutos
# Espera a que termine completamente
```
### Paso 4: Iniciar el Servicio
```bash
# Iniciar en segundo plano
docker-compose up -d tubescript-api
# Esperar 15 segundos
sleep 15
```
### Paso 5: Verificar que Está Corriendo
```bash
# Ver contenedores activos
docker ps
# Debería mostrar: tubescript_api ... Up
```
### Paso 6: Probar el Endpoint
```bash
# Probar el video que fallaba
curl -X GET "http://localhost:8080/transcript/6hini9Xz_fc?lang=es"
# Si funciona, verás JSON con subtítulos
# Si falla, ver logs:
docker logs tubescript_api
```
---
## 🔍 DIAGNÓSTICO SI SIGUE FALLANDO
### Ver Logs Completos
```bash
docker logs tubescript_api 2>&1 | tail -100
```
### Entrar al Contenedor y Probar Manualmente
```bash
# Entrar al contenedor
docker exec -it tubescript_api bash
# Dentro del contenedor, probar yt-dlp directo:
yt-dlp --version
# Probar obtener metadatos del video:
yt-dlp --skip-download --dump-json --no-warnings \
"https://www.youtube.com/watch?v=6hini9Xz_fc" | head -50
# Ver si hay subtítulos:
yt-dlp --list-subs "https://www.youtube.com/watch?v=6hini9Xz_fc"
# Salir:
exit
```
### Probar con Otro Video
```bash
# Probar con un video diferente que sabemos que tiene subtítulos:
curl -X GET "http://localhost:8080/transcript/jNQXAC9IVRw?lang=en"
# Video de prueba popular:
curl -X GET "http://localhost:8080/transcript/dQw4w9WgXcQ?lang=en"
```
---
## 📊 POSIBLES CAUSAS DEL ERROR
### 1. El Video Específico Tiene Problemas
- Prueba con otro video
- Verifica que el video sea accesible: https://www.youtube.com/watch?v=6hini9Xz_fc
### 2. YouTube Está Bloqueando
- Agrega cookies.txt (exporta desde tu navegador)
- Usa una VPN
- Espera unos minutos y vuelve a intentar
### 3. yt-dlp Desactualizado
```bash
# Dentro del contenedor:
docker exec -it tubescript_api bash
pip install --upgrade yt-dlp
exit
# Reiniciar:
docker-compose restart tubescript-api
```
### 4. El Video NO Tiene Subtítulos
- Verifica manualmente en YouTube si el video tiene subtítulos
- El video podría estar geo-bloqueado
- El video podría haber sido eliminado
---
## 💡 SOLUCIÓN ALTERNATIVA
Si el video `6hini9Xz_fc` específicamente siempre falla, puede ser que:
1. **El video no tenga subtítulos** - Verifica manualmente
2. **El video esté restringido** - Prueba con cookies.txt
3. **El video fue eliminado** - Busca otro video
### Probar con Video Conocido que Funciona:
```bash
# CNN en vivo (siempre tiene subtítulos):
curl -X GET "http://localhost:8080/transcript/XWq5kBlakcQ?lang=en"
# BBC News (en inglés):
curl -X GET "http://localhost:8080/transcript/9Auq9mYxFEE?lang=en"
```
Si estos funcionan pero `6hini9Xz_fc` no, el problema es específico de ese video.
---
## 🎯 RESUMEN EJECUTIVO
### ✅ Lo que hice:
1. Simplifiqué el comando yt-dlp eliminando opciones problemáticas
2. Eliminé `--extractor-args` que puede causar conflictos
3. El código ahora es minimalista y robusto
### ✅ Lo que debes hacer:
1. Reconstruir Docker: `docker-compose build --no-cache tubescript-api`
2. Iniciar: `docker-compose up -d tubescript-api`
3. Probar: `curl "http://localhost:8080/transcript/6hini9Xz_fc?lang=es"`
### ✅ Si falla:
1. Ver logs: `docker logs tubescript_api`
2. Probar otro video
3. Verificar que el video tenga subtítulos en YouTube
4. Agregar cookies.txt si es necesario
---
## 📞 COMANDOS COMPLETOS LISTOS PARA COPIAR
```bash
# Ejecuta esto en orden:
# 1. Ir al directorio
cd /Users/cesarmendivil/Documents/Nextream/TubeScript-API
# 2. Detener y limpiar
docker-compose down
docker rmi tubescript-api 2>/dev/null || true
# 3. Reconstruir
docker-compose build --no-cache tubescript-api
# 4. Iniciar
docker-compose up -d tubescript-api
# 5. Esperar
sleep 15
# 6. Probar
curl -X GET "http://localhost:8080/transcript/6hini9Xz_fc?lang=es"
# 7. Ver logs si falla
docker logs tubescript_api 2>&1 | tail -50
```
---
**El código está LISTO. Solo necesitas reconstruir Docker con los pasos de arriba.**
Si después de esto el error persiste, es muy probable que sea un problema específico del video `6hini9Xz_fc` (sin subtítulos, bloqueado, eliminado, etc.) y no del código.
---
**TubeScript API Pro © 2026**
Última Actualización: 30 Enero 2026

View File

@ -1,476 +0,0 @@
# Nota: Streamlit eliminado
> El panel Streamlit fue eliminado en esta rama; este documento se mantiene solo como referencia histórica. Usa la API (main.py) para operar.
# 📺 TubeScript - Panel de Control Web
Panel de control web interactivo para gestionar transmisiones en vivo desde YouTube hacia múltiples plataformas de redes sociales simultáneamente.
## 🎯 Características Principales
### ✨ Funcionalidades
- **🔍 Búsqueda de Videos en Vivo**: Busca transmisiones en vivo de YouTube por palabra clave
- **📺 Preview de Video**: Visualiza el video seleccionado con miniatura y datos del canal
- **🎛️ Control Multi-Plataforma**: Gestiona transmisiones a múltiples redes sociales simultáneamente
- **🔴 Switches de Activación**: Controles tipo toggle para iniciar/detener transmisiones por plataforma
- **📊 Monitoreo en Tiempo Real**: Visualiza el estado de cada transmisión con semáforos de estado
- **🔍 Seguimiento de PIDs**: Monitorea los procesos FFmpeg activos con sus identificadores
- **⚙️ Configuración Fácil**: Panel lateral intuitivo para configurar cada plataforma
---
## 🖥️ Interfaz del Usuario
### 1. Barra Lateral - Configuración de Plataformas
```
⚙️ CONFIGURACIÓN
├── Plataformas de Streaming
│ ├── YouTube
│ │ ├── [Switch] Habilitar esta plataforma
│ │ ├── 🔑 Stream Key (Requerido)
│ │ └── 🌐 RTMP URL (Opcional)
│ ├── Facebook
│ ├── Twitch
│ ├── X (Twitter)
│ ├── Instagram
│ └── TikTok
└── [Botón] 💾 Guardar Configuración
```
**URLs RTMP por Defecto:**
- **YouTube**: `rtmp://a.rtmp.youtube.com/live2`
- **Facebook**: `rtmps://live-api-s.facebook.com:443/rtmp/`
- **Twitch**: `rtmp://live.twitch.tv/app`
- **X (Twitter)**: `rtmps://fa.contribute.live-video.net/app`
- **Instagram**: `rtmps://live-upload.instagram.com:443/rtmp/`
- **TikTok**: `rtmp://push.live.tiktok.com/live/`
### 2. Pestaña: 🔍 Búsqueda
**Funcionalidades:**
- Buscar videos en vivo por palabra clave
- Ingresar URL directa de YouTube
- Ver resultados con título y canal
- Seleccionar video para transmitir
**Ejemplo de búsqueda:**
```
🔍 Buscar Video en Vivo
[Buscar transmisión en vivo de YouTube] [🔍 Buscar]
O ingresa la URL directa del video
[https://www.youtube.com/watch?v=...]
```
### 3. Pestaña: 🎛️ Control
**Vista Principal:**
```
📺 Video Seleccionado
┌─────────────────────────────────────┐
│ [Miniatura] Título del Video │
│ Canal: NombreCanal │
│ 🔴 EN VIVO │
└─────────────────────────────────────┘
🎯 Plataformas Configuradas (3)
[▶️ Iniciar Todas las Transmisiones]
[⏹️ Detener Todas las Transmisiones]
[Transmitiendo: 2/3]
📋 Redes Habilitadas y Listas para Transmitir
┌──────────────┬──────────┬─────┬────────────┬──────────────┐
│ Red Social │ Estado │ PID │ Habilitada │ Configurada │
├──────────────┼──────────┼─────┼────────────┼──────────────┤
│ YouTube │ 🟢 Activo│ 1234│ ✅ Sí │ ✅ Sí │
│ Facebook │ 🟢 Activo│ 1235│ ✅ Sí │ ✅ Sí │
│ Twitch │ ⚪ Listo │ - │ ✅ Sí │ ✅ Sí │
└──────────────┴──────────┴─────┴────────────┴──────────────┘
```
**Tarjetas de Control Individual:**
```
┌─────────────────────────────────────┐
│ 🎥 YouTube 🟢 PID: 1234│
│ │
│ Estado: TRANSMITIENDO │
│ Transmisión activa (PID: 1234) │
│ │
│ [🔴] Transmitir a YouTube │
│ │
│ ⏱️ Tiempo Activo 🔍 Proceso │
│ 00:15:32 ✅ Activo │
│ │
Detalles de Configuración ▼ │
└─────────────────────────────────────┘
```
### 4. Pestaña: 📊 Monitor
**Monitoreo en Tiempo Real:**
- Auto-refresh cada 5 segundos
- Resumen general de todas las transmisiones
- Detalle por plataforma con métricas
- Verificación de estado de procesos (PIDs)
```
📈 Resumen General
┌──────────────┬──────────┬────────────┬─────────────┐
│ Total Trans. │ 🟢 Activas│ 🔴 Errores │ ⚪ Detenidas│
│ 3 │ 2 │ 0 │ 1 │
└──────────────┴──────────┴────────────┴─────────────┘
🔍 Detalle por Plataforma
┌─────────────────────────────────────┐
│ 🟢 YouTube [⏹️ Det.] │
│ PID: 1234 │
│ Transmisión activa (PID: 1234) │
│ │
│ ⏱️ 00:15:32 ✅ Vivo 🕐 14:30:00 │
│ │
Información Técnica ▼ │
└─────────────────────────────────────┘
```
---
## 🎨 Semáforos de Estado
Los semáforos indican el estado de cada transmisión en tiempo real:
| Semáforo | Estado | Descripción |
|----------|--------|-------------|
| 🟢 | **TRANSMITIENDO** | La transmisión está activa y funcionando correctamente |
| ⚪ | **LISTO** | La plataforma está configurada pero no está transmitiendo |
| 🔴 | **ERROR** | Hubo un error en la transmisión o el proceso se detuvo |
| ⚠️ | **DESHABILITADA** | La plataforma está configurada pero deshabilitada |
---
## 🔄 Flujo de Trabajo Completo
### Paso 1: Configurar Plataformas
1. Abre el panel lateral (⚙️ Configuración)
2. Para cada plataforma:
- Activa el switch "Habilitar esta plataforma"
- Ingresa tu **Stream Key** (obligatorio)
- (Opcional) Personaliza la **RTMP URL**
3. Haz clic en "💾 Guardar Configuración"
### Paso 2: Buscar Video en Vivo
Ve a la pestaña **🔍 Búsqueda** y:
**Opción A: Buscar por palabra clave**
```
1. Escribe: "noticias" o "gaming"
2. Clic en "🔍 Buscar"
3. Selecciona un video de los resultados
```
**Opción B: URL directa**
```
1. Pega la URL completa: https://www.youtube.com/watch?v=VIDEO_ID
2. El sistema la detectará automáticamente
```
### Paso 3: Iniciar Transmisiones
Ve a la pestaña **🎛️ Control**:
**Opción A: Iniciar todas**
```
1. Clic en "▶️ Iniciar Todas las Transmisiones"
2. Todas las plataformas habilitadas comenzarán a transmitir
```
**Opción B: Iniciar individualmente**
```
1. Busca la tarjeta de la plataforma deseada
2. Activa el switch "🔴 Transmitir a [Plataforma]"
3. La transmisión comenzará en esa plataforma
```
### Paso 4: Monitorear Transmisiones
Ve a la pestaña **📊 Monitor**:
- El panel se actualiza automáticamente cada 5 segundos
- Verás el PID de cada proceso FFmpeg
- Tiempo activo de cada transmisión
- Estado del proceso (✅ Vivo / ❌ Muerto)
### Paso 5: Detener Transmisiones
**Opción A: Detener todas**
```
En la pestaña Control:
Clic en "⏹️ Detener Todas las Transmisiones"
```
**Opción B: Detener individualmente**
```
1. Desactiva el switch de la plataforma, O
2. En la pestaña Monitor, clic en "⏹️ Detener"
```
---
## 🔧 Configuración Avanzada
### Personalizar RTMP URL
Por defecto, cada plataforma tiene una URL RTMP predefinida. Si necesitas usar un servidor personalizado:
1. En la configuración de la plataforma
2. Marca "Usar URL RTMP personalizada"
3. Ingresa la URL completa: `rtmp://tu-servidor.com/live`
4. Guarda los cambios
### Usar con API Externa
Si tu API está en otro servidor:
1. Edita el archivo `.env`:
```env
API_URL=https://api.tudominio.com
```
2. Reinicia el contenedor:
```bash
docker-compose restart streamlit-panel
```
---
## 🎯 Características Técnicas
### Gestión de Procesos
El panel gestiona procesos FFmpeg en segundo plano:
**Comando FFmpeg usado:**
```bash
ffmpeg -re -i "URL_M3U8" -c copy -f flv RTMP_URL/STREAM_KEY
```
**Parámetros:**
- `-re`: Lee el input a velocidad nativa (importante para streaming)
- `-i`: URL m3u8 obtenida de YouTube
- `-c copy`: Copia sin recodificar (menor latencia y CPU)
- `-f flv`: Formato FLV para RTMP
### Almacenamiento de Datos
El sistema guarda tres archivos JSON:
1. **`stream_config.json`**: Configuración de plataformas
```json
{
"platforms": {
"YouTube": {
"rtmp_url": "rtmp://...",
"stream_key": "xxxxx",
"enabled": true
}
}
}
```
2. **`process_state.json`**: Estado de procesos activos
```json
{
"YouTube": {
"pid": 1234,
"platform": "YouTube",
"start_time": "2026-01-30T14:30:00",
"status": "running",
"rtmp_url": "rtmp://...",
"enabled": true
}
}
```
3. **`streams_state.json`**: Estado de transmisiones
### Verificación de PIDs
El sistema verifica constantemente que los procesos FFmpeg estén vivos:
```python
def check_process_alive(pid):
try:
os.kill(pid, 0) # Señal 0 = verificar existencia
return True
except OSError:
return False
```
---
## 🛠️ Solución de Problemas
### Problema: "No se pudo obtener la URL del stream"
**Posibles causas:**
1. El video no está EN VIVO (🔴)
2. El video tiene restricciones geográficas
3. yt-dlp está desactualizado
**Soluciones:**
```bash
# Actualizar yt-dlp en el contenedor
docker exec streamlit_panel pip install --upgrade yt-dlp
# O reconstruir contenedor
docker-compose down
docker-compose build --no-cache
docker-compose up -d
```
### Problema: "La transmisión se detuvo"
**Verificar:**
1. Que el video de YouTube siga en vivo
2. Que la Stream Key sea correcta
3. Los logs del proceso:
```bash
docker logs streamlit_panel
```
### Problema: "Switch no responde"
**Solución:**
1. Refresca la página (F5)
2. Verifica que el API esté funcionando:
```bash
curl http://localhost:8080/docs
```
### Problema: "Plataforma deshabilitada"
**Verificar en la configuración:**
1. El switch "Habilitar esta plataforma" debe estar activo
2. Debe tener Stream Key configurada
3. Debe tener RTMP URL configurada
---
## 📊 Métricas y KPIs
El panel proporciona las siguientes métricas en tiempo real:
| Métrica | Descripción | Ubicación |
|---------|-------------|-----------|
| **Total Plataformas** | Número de plataformas configuradas | Control |
| **Transmitiendo** | Cuántas están activas | Control/Monitor |
| **Listas** | Configuradas pero inactivas | Control |
| **Errores** | Con problemas | Control/Monitor |
| **Tiempo Activo** | Duración de cada transmisión | Control/Monitor |
| **Estado del Proceso** | Si el PID está vivo | Monitor |
| **PID** | Identificador del proceso FFmpeg | Control/Monitor |
---
## 🔐 Seguridad
### Stream Keys
- Los Stream Keys se almacenan en `stream_config.json`
- En la interfaz solo se muestran los últimos 4 caracteres
- No se registran en logs
### Volúmenes Docker
```yaml
volumes:
- ./stream_config.json:/app/stream_config.json # Configuración
- ./cookies.txt:/app/cookies.txt:ro # Solo lectura
```
### Variables de Entorno
```yaml
environment:
- API_URL=${API_URL} # URL del API
- PYTHONUNBUFFERED=1 # Logs en tiempo real
```
---
## 📝 Requisitos del Sistema
### Mínimos
- **RAM**: 2 GB
- **CPU**: 2 cores
- **Disco**: 5 GB
- **Red**: 10 Mbps upload por transmisión
### Recomendados
- **RAM**: 4 GB
- **CPU**: 4 cores
- **Disco**: 10 GB SSD
- **Red**: 25 Mbps upload por transmisión
---
## 🚀 Próximas Funcionalidades
- [ ] Programación de transmisiones
- [ ] Grabación local simultánea
- [ ] Estadísticas de ancho de banda
- [ ] Alertas por email/Telegram
- [ ] Múltiples fuentes de video
- [ ] Overlays y filtros en tiempo real
- [ ] Soporte para OBS Studio
---
## 📚 Recursos Adicionales
### Obtener Stream Keys
- [YouTube Studio](https://studio.youtube.com) → Emisión en Vivo → Stream
- [Facebook Creator Studio](https://business.facebook.com/creatorstudio) → Emisión en vivo
- [Twitch Dashboard](https://dashboard.twitch.tv/settings/stream) → Configuración del canal
- [X Media Studio](https://studio.twitter.com) → Crear → En vivo
### Documentación
- [FastAPI Backend](README.md)
- [Comandos Docker](DOCKER_COMANDOS_SEPARADOS_COMPLETO.md)
- [Configuración de URLs](API_URL_CONFIG.md)
---
## 🐛 Reportar Problemas
Si encuentras algún problema:
1. Verifica los logs:
```bash
docker logs streamlit_panel
docker logs tubescript_api
```
2. Recopila información:
- Versión de Docker
- Sistema operativo
- Mensaje de error completo
3. Crea un issue con toda la información
---
## 📞 Soporte
- 📧 Email: soporte@tubescript.com
- 💬 Discord: [TubeScript Community](https://discord.gg/tubescript)
- 📖 Docs: [docs.tubescript.com](https://docs.tubescript.com)
---
**TubeScript Panel de Control © 2026**
Desarrollado con ❤️ usando Streamlit y FastAPI

View File

@ -1,8 +1,3 @@
# Nota: Streamlit eliminado
> El panel Streamlit fue eliminado en esta rama; usa la API (FastAPI) para las operaciones. Las instrucciones siguientes han sido adaptadas para el modo API.
# 🚀 Guía de Inicio Rápido - TubeScript Panel Web
## 📋 Prerequisitos

View File

@ -1,472 +0,0 @@
# 🚀 Guía de Inicio Rápido - TubeScript API
## ⚡ Inicio Rápido en 3 Pasos
### 1⃣ Crear Red de Docker
```bash
./docker-create-network.sh
```
### 2⃣ Iniciar Servicios
```bash
# Opción A: Usar el gestor interactivo (Recomendado)
./docker-manager.sh
# Opción B: Iniciar con Docker Compose
docker-compose up -d
# Opción C: Iniciar servicios por separado
./docker-start-api.sh # Solo API
./docker-start-streamlit.sh # Solo Streamlit
```
### 3⃣ Acceder al Panel
- **Panel Web**: http://localhost:8501
- **API**: http://localhost:8080
- **Documentación API**: http://localhost:8080/docs
---
## 🎯 ¿Qué Puedes Hacer?
### ✨ Funcionalidades Principales
1. **🔍 Buscar Videos en Vivo de YouTube**
- Busca por palabra clave
- O ingresa URL directa
2. **📺 Seleccionar Video para Transmitir**
- Ve el preview con miniatura
- Verifica que esté EN VIVO (🔴)
3. **⚙️ Configurar Plataformas de Destino**
- YouTube, Facebook, Twitch, X, Instagram, TikTok
- Solo necesitas el Stream Key
- RTMP URLs configuradas por defecto
4. **🎛️ Controlar Transmisiones**
- Switches individuales por plataforma
- Iniciar/Detener todas a la vez
- Ver estado en tiempo real
5. **📊 Monitorear en Tiempo Real**
- Semáforos de estado (🟢 🔴 ⚪)
- PIDs de procesos FFmpeg
- Tiempo activo de cada transmisión
- Verificación de salud de procesos
---
## 🛠️ Gestión de Servicios
### Gestor Interactivo (Recomendado)
```bash
./docker-manager.sh
```
**Menú disponible:**
```
SERVICIOS:
1) Iniciar TODOS los servicios
2) Iniciar solo FastAPI
3) Iniciar solo Streamlit
CONTROL:
4) Detener todos los servicios
5) Reiniciar todos los servicios
6) Reconstruir contenedores
MONITOREO:
7) Ver logs de FastAPI
8) Ver logs de Streamlit
9) Ver logs de ambos
10) Ver estado de servicios
MANTENIMIENTO:
11) Actualizar yt-dlp
12) Crear red de Docker
13) Limpiar contenedores
UTILIDADES:
14) Abrir panel web
15) Abrir documentación API
16) Editar configuración
```
### Comandos Rápidos
```bash
# Iniciar
./docker-start-api.sh # Solo API
./docker-start-streamlit.sh # Solo Streamlit
docker-compose up -d # Ambos servicios
# Detener
./docker-stop-all.sh # Detener todos
docker-compose down # Con Docker Compose
# Ver Logs
./docker-logs-separate.sh api # Logs de API
./docker-logs-separate.sh streamlit # Logs de Streamlit
docker logs -f tubescript_api # Direct Docker
# Estado
docker ps # Ver contenedores activos
docker stats # Ver uso de recursos
```
---
## ⚙️ Configuración
### 1. Variables de Entorno
Crea tu archivo `.env` (o edita el existente):
```bash
cp .env.example .env
nano .env
```
**Configuraciones principales:**
```env
# URL del API (para Streamlit)
API_URL=http://tubescript-api:8000 # Dentro de Docker
# API_URL=http://localhost:8080 # Para desarrollo local
# API_URL=https://api.tudominio.com # Para producción
# Puertos
API_PORT=8080
STREAMLIT_PORT=8501
```
### 2. Configurar Plataformas
En el panel web (http://localhost:8501):
1. **Abre el menú lateral** (⚙️ Configuración)
2. **Para cada plataforma:**
- ✅ Activa "Habilitar esta plataforma"
- 🔑 Ingresa tu **Stream Key**
- 🌐 (Opcional) Personaliza RTMP URL
3. **Guarda la configuración** (💾 Guardar Configuración)
**URLs RTMP por defecto:**
- YouTube: `rtmp://a.rtmp.youtube.com/live2`
- Facebook: `rtmps://live-api-s.facebook.com:443/rtmp/`
- Twitch: `rtmp://live.twitch.tv/app`
- X (Twitter): `rtmps://fa.contribute.live-video.net/app`
- Instagram: `rtmps://live-upload.instagram.com:443/rtmp/`
- TikTok: `rtmp://push.live.tiktok.com/live/`
### 3. Cookies de YouTube (Opcional)
Si necesitas acceder a videos con restricciones:
```bash
# Exporta cookies de tu navegador
# Usa extensión: "Get cookies.txt"
# Guarda como cookies.txt en el directorio raíz
```
---
## 📺 Cómo Usar el Panel Web
### Flujo Completo
#### Paso 1: Configurar (Primera vez)
```
⚙️ Configuración (Sidebar)
├── Activar plataformas deseadas
├── Ingresar Stream Keys
└── Guardar configuración
```
#### Paso 2: Buscar Video
```
🔍 Búsqueda (Tab)
├── Buscar: "noticias", "gaming", etc.
└── O pegar URL directa
```
#### Paso 3: Controlar Transmisión
```
🎛️ Control (Tab)
├── Ver preview del video
├── Activar switches por plataforma
└── O iniciar todas a la vez
```
#### Paso 4: Monitorear
```
📊 Monitor (Tab)
├── Ver estado en tiempo real
├── Verificar PIDs de procesos
├── Tiempo activo
└── Detener si es necesario
```
---
## 🔍 Ejemplo Práctico
### Transmitir a YouTube y Facebook
```bash
# 1. Iniciar servicios
./docker-manager.sh
# Selecciona opción 1
# 2. Abrir panel web
# Opción 14 del menú, o:
open http://localhost:8501
# 3. En el panel:
# - Sidebar → Configurar YouTube y Facebook
# - Búsqueda → Buscar "CNN live"
# - Control → Activar switches de YouTube y Facebook
# - Monitor → Ver que ambas estén transmitiendo 🟢
# 4. Detener cuando termines
# Control → Desactivar switches
# O desde terminal: ./docker-stop-all.sh
```
---
## 🎨 Semáforos de Estado
| Símbolo | Estado | Significado |
|---------|--------|-------------|
| 🟢 | TRANSMITIENDO | Activo y funcionando |
| ⚪ | LISTO | Configurado, no transmitiendo |
| 🔴 | ERROR | Problema con la transmisión |
| ⚠️ | DESHABILITADA | Configurada pero desactivada |
---
## 🆘 Solución de Problemas
### ❌ "No se pudo obtener la URL del stream"
**Causas:**
- Video no está EN VIVO (🔴)
- Video con restricciones
- yt-dlp desactualizado
**Soluciones:**
```bash
# Actualizar yt-dlp
./docker-manager.sh
# Selecciona opción 11
# O manualmente:
docker exec streamlit_panel pip install --upgrade yt-dlp
# Reconstruir contenedores
./docker-manager.sh
# Selecciona opción 6
```
### ❌ "Error al descargar subtítulos"
**Solución:**
- El video puede no tener subtítulos disponibles
- Intenta con otro video
- Verifica que el video sea accesible públicamente
### ❌ "Transmisión se detuvo"
**Verificar:**
```bash
# Ver logs
docker logs streamlit_panel
# Verificar PIDs en el Monitor (Tab)
# Estado del proceso: ✅ Vivo / ❌ Muerto
# Verificar que video siga en vivo
# Verificar Stream Key correcta
```
### ❌ "Puerto ya en uso"
**Solución:**
```bash
# Ver qué usa el puerto
lsof -i :8080 # FastAPI
lsof -i :8501 # Streamlit
# Cambiar puerto en docker-compose.yml
# O detener el proceso que lo usa
```
---
## 📊 Arquitectura
```
┌─────────────────────────────────────────────┐
│ Panel Web Streamlit (8501) │
│ ┌────────┬────────────┬──────────────┐ │
│ │Búsqueda│ Control │ Monitor │ │
│ └────────┴────────────┴──────────────┘ │
└─────────────────┬───────────────────────────┘
│ HTTP
┌─────────────────▼───────────────────────────┐
│ FastAPI Backend (8000/8080) │
│ /stream/{video_id} - Obtener URL m3u8 │
│ /transcript/{video_id} - Obtener subtíts. │
└─────────────────┬───────────────────────────┘
│ yt-dlp
┌─────────────────▼───────────────────────────┐
│ YouTube Live │
│ (Extrae URL m3u8 HLS) │
└─────────────────┬───────────────────────────┘
│ URL m3u8
┌─────────────────▼───────────────────────────┐
│ Procesos FFmpeg (PIDs) │
│ ┌─────────┬──────────┬────────────────┐ │
│ │YouTube │ Facebook │ Twitch ... │ │
│ │PID:1234 │PID:1235 │ PID:1236 │ │
│ └─────────┴──────────┴────────────────┘ │
└─────────────────┬───────────────────────────┘
│ RTMP/RTMPS
┌─────────────────▼───────────────────────────┐
│ Plataformas de Destino │
│ YouTube │ Facebook │ Twitch │ X │ etc. │
└─────────────────────────────────────────────┘
```
---
## 📝 Archivos de Configuración
```
TubeScript-API/
├── stream_config.json # Configuración de plataformas
├── process_state.json # Estado de procesos FFmpeg
├── streams_state.json # Estado de transmisiones
├── cookies.txt # Cookies de YouTube (opcional)
└── .env # Variables de entorno
```
---
## 🚀 Actualizar el Sistema
```bash
# 1. Detener servicios
./docker-stop-all.sh
# 2. Obtener últimos cambios (si usas Git)
git pull
# 3. Reconstruir contenedores
docker-compose build --no-cache
# 4. Iniciar servicios
docker-compose up -d
# 5. Actualizar yt-dlp
docker exec tubescript_api pip install --upgrade yt-dlp
docker exec streamlit_panel pip install --upgrade yt-dlp
```
O usando el gestor:
```bash
./docker-manager.sh
# Selecciona: 6) Reconstruir contenedores
# Luego: 11) Actualizar yt-dlp
```
---
## 📚 Documentación Completa
- **[Panel Streamlit](PANEL_STREAMLIT_GUIA.md)**: Guía detallada del panel web
- **[Comandos Docker](DOCKER_COMANDOS_SEPARADOS_COMPLETO.md)**: Comandos separados
- **[Docker Guide](DOCKER_GUIDE.md)**: Guía completa de Docker
- **[API Config](API_URL_CONFIG.md)**: Configuración de URLs
---
## 🔗 Enlaces Útiles
- **Panel Web**: http://localhost:8501
- **API FastAPI**: http://localhost:8080
- **API Docs**: http://localhost:8080/docs
- **API Redoc**: http://localhost:8080/redoc
---
## 💡 Consejos y Trucos
### Para Desarrollo
```bash
# Usar API externa en Streamlit
echo "API_URL=http://192.168.1.100:8080" > .env
./docker-start-streamlit.sh
```
### Para Producción
```bash
# Usar dominio real
echo "API_URL=https://api.tudominio.com" > .env
docker-compose up -d
```
### Para Debugging
```bash
# Ejecutar en modo interactivo
docker run -it --rm \
--network tubescript-network \
-p 8080:8000 \
tubescript-api \
uvicorn main:app --host 0.0.0.0 --port 8000
```
---
## 📦 Requisitos del Sistema
**Mínimos:**
- Docker 20.10+
- 2 GB RAM
- 5 GB Disco
- 10 Mbps Upload
**Recomendados:**
- Docker 24+
- 4 GB RAM
- 10 GB SSD
- 25 Mbps Upload (por transmisión)
---
## 🎯 Próximos Pasos
1. ✅ Configura tus plataformas
2. ✅ Prueba con un video en vivo
3. ✅ Monitorea el estado en tiempo real
4. 📖 Lee la [Guía Completa del Panel](PANEL_STREAMLIT_GUIA.md)
5. 🚀 ¡Comienza a transmitir!
---
## 📞 Soporte
¿Problemas? Revisa:
1. Los logs: `docker logs -f streamlit_panel`
2. El estado: `docker ps`
3. La documentación completa en los archivos MD
---
**TubeScript API Pro © 2026**
Transmite en vivo a múltiples plataformas simultáneamente 🚀

View File

@ -1,173 +0,0 @@
# 🚀 INICIO RÁPIDO: Obtener Transcripts de YouTube
## ⚡ Método Más Rápido (30 segundos)
### Usando cookies de Chrome directamente:
```bash
# 1. Asegúrate de estar logueado en YouTube en Chrome
# 2. Ejecuta este comando:
yt-dlp --cookies-from-browser chrome --skip-download --write-auto-sub \
--sub-lang es --sub-format vtt -o "%(id)s.%(ext)s" \
"https://www.youtube.com/watch?v=K08TM4OVLyo"
# 3. Listo! Verás el archivo: K08TM4OVLyo.es.vtt
```
---
## 🎯 3 Formas de Obtener Transcripts
### 1⃣ Script Bash (Recomendado - MÁS FÁCIL)
```bash
./get_transcript_chrome.sh VIDEO_ID
```
**Ventajas**:
- ✅ Genera VTT + TXT automáticamente
- ✅ Muestra preview del contenido
- ✅ Maneja múltiples perfiles de Chrome
### 2⃣ Script Python
```bash
python3 fetch_transcript.py VIDEO_ID es chrome
```
**Ventajas**:
- ✅ Genera JSON + TXT
- ✅ Integrado con el proyecto
- ✅ Maneja formatos automáticamente
### 3⃣ Comando directo yt-dlp
```bash
yt-dlp --cookies-from-browser chrome \
--skip-download --write-auto-sub \
--sub-lang es --sub-format vtt \
-o "%(id)s.%(ext)s" \
"https://www.youtube.com/watch?v=VIDEO_ID"
```
**Ventajas**:
- ✅ Control total
- ✅ Personalizable
- ✅ Para usuarios avanzados
---
## 🔑 Usar Perfil Específico de Chrome
### Ver perfiles disponibles:
```bash
# macOS
ls ~/Library/Application\ Support/Google/Chrome/
# Verás algo como:
# Default
# Profile 1
# Profile 2
```
### Usar un perfil específico:
```bash
# Opción 1: Script bash
./get_transcript_chrome.sh VIDEO_ID es chrome "Profile 1"
# Opción 2: Python
python3 fetch_transcript.py VIDEO_ID es "chrome:Profile 1"
# Opción 3: yt-dlp directo
yt-dlp --cookies-from-browser "chrome:Profile 1" \
--skip-download --write-auto-sub \
--sub-lang es --sub-format vtt \
-o "%(id)s.%(ext)s" \
"https://www.youtube.com/watch?v=VIDEO_ID"
```
---
## ❌ Si te sale "HTTP Error 429"
YouTube está bloqueando tu IP. **Solución rápida con Tor**:
```bash
# 1. Instalar Tor
brew install tor # macOS
# sudo apt install tor # Linux
# 2. Iniciar Tor
tor &
# 3. Usar con proxy
yt-dlp --cookies-from-browser chrome \
--proxy "socks5h://127.0.0.1:9050" \
--skip-download --write-auto-sub \
--sub-lang es --sub-format vtt \
-o "%(id)s.%(ext)s" \
"https://www.youtube.com/watch?v=VIDEO_ID"
```
---
## 📊 Ejemplo Completo
```bash
# 1. Obtener transcript
./get_transcript_chrome.sh K08TM4OVLyo es chrome
# Salida:
# ✅ Archivo generado: K08TM4OVLyo.es.vtt
# 💾 Texto guardado en: K08TM4OVLyo_transcript.txt
# 2. Ver el transcript
cat K08TM4OVLyo_transcript.txt
# 3. Subir al API (opcional)
curl -X POST "http://127.0.0.1:8000/upload_vtt/K08TM4OVLyo" \
-F "file=@K08TM4OVLyo.es.vtt" | jq .
```
---
## 🆘 Problemas Comunes
| Problema | Solución |
|----------|----------|
| "Unable to extract cookies" | Cierra Chrome: `killall "Google Chrome"` |
| "HTTP Error 429" | Usa Tor/VPN (ver arriba) |
| No se genera archivo | Verifica que estés logueado en YouTube |
| "yt-dlp not found" | Instala: `pip install yt-dlp` |
---
## 📚 Más Información
- **Guía completa Chrome**: `GUIA_CHROME_TRANSCRIPTS.md`
- **Soluciones HTTP 429**: `SOLUCION_HTTP_429_TRANSCRIPT.md`
- **API Endpoints**: Consulta `/docs` de la API
---
## 🎬 Demo de 30 segundos
```bash
# Instalar yt-dlp (si no lo tienes)
pip install yt-dlp
# Obtener transcript
yt-dlp --cookies-from-browser chrome --skip-download --write-auto-sub \
--sub-lang es --sub-format vtt -o "%(id)s.%(ext)s" \
"https://www.youtube.com/watch?v=K08TM4OVLyo"
# Convertir a texto plano
grep -v "WEBVTT" K08TM4OVLyo.es.vtt | grep -v "^$" | grep -v "^[0-9][0-9]:" > transcript.txt
# Ver el transcript
cat transcript.txt
```
**¡Listo! 🎉**
---
**Última actualización**: 2025-02-22

View File

@ -366,6 +366,3 @@ Para preguntas o soporte, abre un issue en el repositorio.
**⚠️ Advertencia Legal**: Asegúrate de tener los derechos necesarios para retransmitir el contenido. Este software es solo para uso educativo y personal. El uso indebido puede violar los términos de servicio de las plataformas.
# Nota: Streamlit eliminado
> El panel Streamlit ha sido eliminado en esta rama. El proyecto ahora se centra en la API (FastAPI). Las referencias previas a Streamlit se mantienen solo para histórico.

View File

@ -1,35 +0,0 @@
Guía rápida para construir y ejecutar el contenedor del API (FastAPI) por separado
API (FastAPI) - imagen: tubescript-api:local
Construir:
```bash
cd /Users/cesarmendivil/Documents/Nextream/TubeScript-API
docker build -t tubescript-api:local -f Dockerfile.api .
```
Ejecutar (exponer puerto 8000):
```bash
# Monta cookies.txt y pasa la ruta como variable de entorno (opcional)
docker run --rm -p 8000:8000 \
-v "$(pwd)/cookies.txt:/app/cookies.txt" \
-e API_COOKIES_PATH="/app/cookies.txt" \
--name tubescript-api \
tubescript-api:local
```
Usando docker-compose local (solo API):
```bash
# Levantar el servicio API (usa docker-compose.local.yml)
API_COOKIES_PATH=/app/cookies.txt docker-compose -f docker-compose.local.yml up --build -d
# Parar y remover:
docker-compose -f docker-compose.local.yml down
```
Notas:
- Asegúrate de tener `cookies.txt` en la raíz (o sube con el endpoint /upload_cookies) si necesitas evitar 429/403 por restricciones.
- El `Dockerfile.api` instala `yt-dlp` y `ffmpeg` para que la API pueda extraer m3u8 y manejar subtítulos.

View File

@ -1,5 +1,3 @@
NOTA: El frontend Streamlit fue eliminado en esta rama. El documento conserva información histórica sobre el panel, pero el flujo actual se basa en la API (main.py).
╔══════════════════════════════════════════════════════════════════════════════╗
║ ║
║ ✅ ACTUALIZACIÓN COMPLETADA CON ÉXITO ║

File diff suppressed because it is too large Load Diff

View File

@ -1,342 +0,0 @@
# 🔧 Solución para Error "Requested format is not available"
## ❌ Problema
```json
{
"detail": "Error de yt-dlp al obtener metadatos: ERROR: [youtube] 6hini9Xz_fc: Requested format is not available. Use --list-formats for a list of available formats"
}
```
Este error ocurre cuando:
1. El video no tiene subtítulos en el formato json3 solicitado
2. El video tiene subtítulos pero en otro formato (srv3, vtt, etc.)
3. El video no está disponible o tiene restricciones
---
## ✅ Solución Implementada
He mejorado el código para:
### 1. **Aceptar Múltiples Formatos de Subtítulos**
Ahora el sistema acepta:
- **json3** (JSON format 3 de YouTube)
- **srv3** (Server format 3)
- **vtt** (WebVTT format)
### 2. **Búsqueda Inteligente de Subtítulos**
El sistema busca en orden:
1. `requested_subtitles` (subtítulos solicitados)
2. `automatic_captions` (subtítulos automáticos)
3. `subtitles` (subtítulos manuales)
### 3. **Parser Flexible**
Nueva función `parse_subtitle_format()` que maneja:
- JSON3: Formato estructurado de YouTube
- SRV3: Similar a JSON3
- VTT: Formato de texto WebVTT
---
## 🚀 Actualizar el Sistema
### Método 1: Script Automático
```bash
./docker-update-system.sh
```
### Método 2: Manual
```bash
# 1. Detener servicios
docker-compose down
# 2. Reconstruir con los cambios
docker-compose build --no-cache
# 3. Iniciar
docker-compose up -d
# 4. Verificar logs
docker-compose logs -f tubescript_api
```
---
## 🧪 Probar la Solución
### Test con el video que falló:
```bash
# Probar el video específico
curl -X GET "http://localhost:8080/transcript/6hini9Xz_fc?lang=es"
```
### Test con otros videos:
```bash
# Video de noticias (usualmente tiene subtítulos)
curl -X GET "http://localhost:8080/transcript/jNQXAC9IVRw?lang=en"
# Video popular
curl -X GET "http://localhost:8080/transcript/dQw4w9WgXcQ?lang=en"
```
---
## 🔍 Diagnóstico del Problema
### Verificar Formatos Disponibles
```bash
# Entrar al contenedor
docker exec -it tubescript_api /bin/bash
# Ver formatos disponibles para un video
yt-dlp --list-subs https://www.youtube.com/watch?v=6hini9Xz_fc
# Intentar con diferentes formatos
yt-dlp --skip-download --write-auto-subs --sub-langs "es.*" \
--dump-json https://www.youtube.com/watch?v=6hini9Xz_fc
```
### Ver Logs Detallados
```bash
# Ver últimos errores del API
docker logs tubescript_api 2>&1 | grep -i "error" | tail -20
# Ver todo el log del último intento
docker logs tubescript_api 2>&1 | tail -100
```
---
## 💡 Mejoras Implementadas en el Código
### Antes:
```python
command = [
"yt-dlp",
"--skip-download",
"--write-auto-subs",
"--sub-format", "json3", # ❌ Solo json3
"--sub-langs", f"{lang}.*",
"--dump-json",
url
]
```
### Después:
```python
command = [
"yt-dlp",
"--skip-download",
"--write-auto-subs", # ✅ Sin forzar formato
"--write-subs", # ✅ También manuales
"--sub-langs", f"{lang}.*",
"--dump-json",
url
]
# ✅ Busca en múltiples fuentes
for subtitle_option in automatic_captions[lang_key]:
ext = subtitle_option.get('ext', '')
if ext in ['json3', 'srv3', 'vtt']: # ✅ Acepta múltiples formatos
requested_subs = {lang_key: subtitle_option}
break
```
---
## 📊 Formatos de Subtítulos Soportados
| Formato | Descripción | Soporte |
|---------|-------------|---------|
| **json3** | JSON estructurado de YouTube | ✅ Completo |
| **srv3** | Server format de YouTube | ✅ Completo |
| **vtt** | WebVTT (texto plano) | ✅ Básico |
| **ttml** | Timed Text Markup Language | ⏳ Futuro |
| **srt** | SubRip format | ⏳ Futuro |
---
## ⚠️ Casos Especiales
### Video Sin Subtítulos
Si un video no tiene subtítulos en ningún formato:
```json
{
"detail": "No se encontraron subtítulos para el idioma 'es'. El video puede no tener subtítulos disponibles."
}
```
**Solución:** Probar con otro idioma o verificar que el video tenga subtítulos.
### Video con Restricciones
Si el video tiene restricciones geográficas o de edad:
```json
{
"detail": "Acceso denegado (HTTP 403). El video puede tener restricciones geográficas o de edad. Intenta agregar cookies.txt."
}
```
**Solución:** Agregar cookies.txt de tu cuenta de YouTube.
### Video Privado o Eliminado
```json
{
"detail": "Error de yt-dlp al obtener metadatos: ERROR: [youtube] Video unavailable"
}
```
**Solución:** Verificar que el video esté disponible públicamente.
---
## 🎯 Ejemplo de Uso Completo
### 1. Actualizar Sistema
```bash
./docker-update-system.sh
```
### 2. Probar Endpoint
```bash
# Con cURL
curl -X GET "http://localhost:8080/transcript/6hini9Xz_fc?lang=es" | jq
# Con HTTPie
http GET localhost:8080/transcript/6hini9Xz_fc lang==es
# Con Python
import requests
response = requests.get("http://localhost:8080/transcript/6hini9Xz_fc?lang=es")
print(response.json())
```
### 3. Procesar Respuesta
```python
import requests
video_id = "6hini9Xz_fc"
response = requests.get(f"http://localhost:8080/transcript/{video_id}?lang=es")
if response.status_code == 200:
data = response.json()
print(f"✅ Se obtuvieron {data['count']} segmentos de subtítulos")
# Mostrar primeros 5 segmentos
for segment in data['segments'][:5]:
print(f"{segment['start']:.1f}s: {segment['text']}")
else:
print(f"❌ Error: {response.json()['detail']}")
```
---
## 🔄 Nuevo Flujo de Procesamiento
```
1. Solicitar metadatos sin forzar formato
2. Buscar en requested_subtitles
↓ Si no hay
3. Buscar en automatic_captions
↓ Para cada idioma
4. Buscar formato: json3, srv3, o vtt
↓ Si encuentra
5. Descargar subtítulos
6. Detectar formato automáticamente
7. Parsear según formato:
- JSON3 → clean_youtube_json()
- SRV3 → clean_youtube_json()
- VTT → parse_vtt_format()
8. Retornar formato estándar
```
---
## 📝 Formato de Salida Estándar
Independientemente del formato de entrada, la salida siempre es:
```json
{
"video_id": "6hini9Xz_fc",
"count": 150,
"segments": [
{
"start": 0.0,
"duration": 2.5,
"text": "Texto del subtítulo"
},
{
"start": 2.5,
"duration": 3.0,
"text": "Siguiente segmento"
}
]
}
```
---
## ✅ Checklist de Solución
- [x] ✅ Remover `--sub-format json3` del comando yt-dlp
- [x] ✅ Agregar búsqueda en múltiples fuentes
- [x] ✅ Soportar formatos json3, srv3, vtt
- [x] ✅ Crear función `parse_subtitle_format()`
- [x] ✅ Manejar errores específicos por formato
- [x] ✅ Documentar la solución
- [ ] ⏳ Actualizar tu sistema
- [ ] ⏳ Probar con el video problemático
- [ ] ⏳ Verificar logs
---
## 🎉 Resumen
### Problema:
- ❌ Solo buscaba formato json3
- ❌ No manejaba videos sin ese formato
### Solución:
- ✅ Busca en múltiples formatos (json3, srv3, vtt)
- ✅ Parser flexible para cada formato
- ✅ Búsqueda inteligente en múltiples fuentes
- ✅ Mensajes de error claros
### Próximo Paso:
```bash
# Actualiza tu sistema
./docker-update-system.sh
# Prueba el endpoint
curl -X GET "http://localhost:8080/transcript/6hini9Xz_fc?lang=es"
```
---
**TubeScript API Pro © 2026**
Soporte Multi-Formato de Subtítulos Implementado ✅

View File

@ -1,355 +0,0 @@
# ✅ SOLUCIÓN FINAL SIMPLIFICADA - Error de Formato de Subtítulos
## 📝 Resumen del Problema
```
ERROR: [youtube] 6hini9Xz_fc: Requested format is not available
```
Este error ocurre porque yt-dlp no puede obtener los subtítulos en el formato solicitado.
---
## ✅ Cambios Implementados en main.py
### 1. Comando Simplificado (Sin Restricciones de Formato)
**ANTES:**
```python
command = [
"yt-dlp",
"--skip-download",
"--write-auto-subs",
"--sub-format", "json3", # ❌ Esto causaba el error
"--sub-langs", f"{lang}.*",
...
]
```
**DESPUÉS:**
```python
command = [
"yt-dlp",
"--skip-download",
"--dump-json", # ✅ Solo obtener metadatos
"--no-warnings",
"--extractor-args", "youtube:player_client=android",
url
]
```
### 2. Búsqueda Flexible de Subtítulos
El código ahora:
1. Obtiene SOLO los metadatos del video
2. Busca subtítulos en el JSON de metadatos
3. Acepta CUALQUIER formato disponible
4. Descarga directamente desde la URL encontrada
```python
# Buscar en automatic_captions
for lang_key in automatic_captions.keys():
if lang in lang_key or lang_key.startswith(lang):
# Tomar el PRIMER formato disponible (sin filtrar)
if automatic_captions[lang_key]:
requested_subs = {lang_key: automatic_captions[lang_key][0]}
break
```
---
## 🚀 CÓMO APLICAR LA SOLUCIÓN
### Método 1: Reconstruir Docker (Recomendado)
```bash
# Limpiar todo
docker stop $(docker ps -aq) 2>/dev/null
docker rm $(docker ps -aq) 2>/dev/null
# Reconstruir desde cero
cd /Users/cesarmendivil/Documents/Nextream/TubeScript-API
docker-compose build --no-cache
# Iniciar
docker-compose up -d
# Ver logs
docker-compose logs -f tubescript-api
```
### Método 2: Si Docker da problemas
```bash
# Reiniciar Docker Desktop
# 1. Cierra Docker Desktop completamente
# 2. Ábrelo nuevamente
# 3. Espera que inicie completamente
# 4. Ejecuta:
docker-compose down
docker-compose build --no-cache
docker-compose up -d
```
### Método 3: Build Manual
```bash
# Build solo del API
docker build -t tubescript-api -f Dockerfile .
# Ejecutar manualmente
docker run -d \
--name tubescript_api \
-p 8080:8000 \
-v "$(pwd)/cookies.txt:/app/cookies.txt:ro" \
-v "$(pwd):/app" \
tubescript-api \
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
# Ver logs
docker logs -f tubescript_api
```
---
## 🧪 PROBAR LA SOLUCIÓN
### Test 1: Verificar que Docker está corriendo
```bash
docker ps
```
Debería mostrar al menos `tubescript_api` corriendo.
### Test 2: Probar el endpoint problemático
```bash
# Esperar 10 segundos después de iniciar
sleep 10
# Probar
curl -X GET "http://localhost:8080/transcript/6hini9Xz_fc?lang=es"
```
### Test 3: Ver logs en tiempo real
```bash
# Terminal 1: Ver logs
docker logs -f tubescript_api
# Terminal 2: Hacer petición
curl -X GET "http://localhost:8080/transcript/6hini9Xz_fc?lang=es"
```
---
## 🔍 DIAGNÓSTICO DE PROBLEMAS
### Problema: Docker no responde
```bash
# Reiniciar Docker
killall Docker
open -a Docker
# Esperar 30 segundos
sleep 30
# Verificar
docker ps
```
### Problema: Puerto 8080 ocupado
```bash
# Ver qué usa el puerto
lsof -i :8080
# Matar proceso
kill -9 $(lsof -ti:8080)
# Cambiar puerto en docker-compose.yml
# ports:
# - "8081:8000" # Usar 8081 en lugar de 8080
```
### Problema: Contenedor se detiene inmediatamente
```bash
# Ver logs completos
docker logs tubescript_api
# Ejecutar en modo interactivo
docker run -it --rm \
-p 8080:8000 \
-v "$(pwd):/app" \
tubescript-api \
bash
# Dentro del contenedor:
python3 main.py
```
---
## 📊 QUÉ HACE EL CÓDIGO AHORA
### Flujo Simplificado:
```
1. Usuario pide transcripción de video
2. yt-dlp obtiene SOLO metadatos (sin bajar subtítulos)
3. Parseamos el JSON de metadatos
4. Buscamos en:
- automatic_captions
- subtitles
5. Tomamos el PRIMER formato disponible
(json3, srv3, vtt, o lo que haya)
6. Descargamos desde la URL encontrada
7. Parseamos según el formato
8. ✅ Retornamos formato estándar
```
### Ventajas:
**Más rápido** - Solo obtiene metadatos una vez
**Más flexible** - Acepta cualquier formato
**Menos errores** - No forzamos formatos específicos
**Mejor compatibilidad** - Funciona con más videos
---
## 💡 ALTERNATIVA: Probar Localmente Sin Docker
Si Docker sigue dando problemas, puedes probar localmente:
```bash
# 1. Instalar dependencias
pip install fastapi uvicorn requests yt-dlp
# 2. Ejecutar el API directamente
cd /Users/cesarmendivil/Documents/Nextream/TubeScript-API
uvicorn main:app --reload --port 8080
# 3. En otra terminal, probar:
curl -X GET "http://localhost:8080/transcript/6hini9Xz_fc?lang=es"
```
---
## 🎯 VERIFICACIÓN FINAL
Una vez que hayas reconstruido, verifica:
```bash
# 1. Contenedor corriendo
docker ps | grep tubescript_api
# 2. API respondiendo
curl http://localhost:8080/docs
# 3. Endpoint de transcripción
curl -X GET "http://localhost:8080/transcript/6hini9Xz_fc?lang=es" | jq
# 4. Logs sin errores
docker logs tubescript_api 2>&1 | tail -20
```
---
## ✅ CHECKLIST
- [ ] Detener servicios Docker actuales
- [ ] Verificar que Docker Desktop esté corriendo
- [ ] Reconstruir imagen: `docker-compose build --no-cache`
- [ ] Iniciar servicios: `docker-compose up -d`
- [ ] Esperar 10 segundos para que inicie
- [ ] Verificar contenedor: `docker ps`
- [ ] Probar endpoint: `curl http://localhost:8080/transcript/6hini9Xz_fc?lang=es`
- [ ] Ver logs: `docker logs tubescript_api`
- [ ] Si funciona: ✅ ¡Listo!
- [ ] Si falla: Ver logs y diagnosticar
---
## 🆘 SI TODO FALLA
### Opción 1: Reinstalar Docker
1. Desinstala Docker Desktop
2. Descarga la última versión
3. Instala
4. Reinicia la Mac
5. Abre Docker Desktop
6. Prueba de nuevo
### Opción 2: Usar Python Local
```bash
# Instalar en entorno virtual
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# Ejecutar
uvicorn main:app --reload --port 8080
```
### Opción 3: Contactar Soporte
Si nada funciona, proporciona:
- Logs completos: `docker logs tubescript_api`
- Versión de Docker: `docker --version`
- Sistema: `uname -a`
- Error exacto que ves
---
## 📝 RESUMEN DE CAMBIOS EN EL CÓDIGO
| Archivo | Cambio | Línea Aprox. |
|---------|--------|--------------|
| main.py | Comando yt-dlp simplificado | ~98-108 |
| main.py | Búsqueda flexible de subtítulos | ~125-145 |
| main.py | Acepta cualquier formato | ~125-145 |
| main.py | Parser multi-formato | ~30-80 |
---
## 🎉 RESULTADO ESPERADO
Después de aplicar los cambios:
```bash
curl -X GET "http://localhost:8080/transcript/6hini9Xz_fc?lang=es"
```
**Debería retornar:**
```json
{
"video_id": "6hini9Xz_fc",
"count": 150,
"segments": [
{
"start": 0.0,
"duration": 2.5,
"text": "Texto del subtítulo..."
},
...
]
}
```
---
**TubeScript API Pro © 2026**
¡Reconstruye Docker y prueba!

View File

@ -1,300 +0,0 @@
# 🔧 Solución para Error HTTP 429 - Rate Limiting de YouTube
## ❌ Problema
```
{"detail":"Error al descargar subtítulos desde YouTube (HTTP 429). El video puede tener restricciones."}
```
**HTTP 429** significa "Too Many Requests" - YouTube está limitando las peticiones desde tu IP.
---
## ✅ Soluciones Implementadas
### 1. Sistema de Retry Automático
El sistema ahora intenta automáticamente 3 veces con espera incremental:
- Intento 1: Inmediato
- Intento 2: Espera 2 segundos
- Intento 3: Espera 4 segundos
### 2. Headers de Navegador
Se agregaron headers que simulan un navegador real:
```python
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)...',
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'es-ES,es;q=0.9,en;q=0.8',
'Referer': 'https://www.youtube.com/',
}
```
### 3. Mensajes de Error Mejorados
Ahora el sistema proporciona mensajes específicos para cada error:
- **HTTP 429**: Rate limiting - espera y agrega cookies
- **HTTP 403**: Restricciones geográficas o de edad
- **HTTP 404**: Subtítulos no disponibles
- **Timeout**: Problema de conexión
---
## 🚀 Soluciones Adicionales
### Opción 1: Usar Cookies de YouTube (RECOMENDADO)
Las cookies autenticadas evitan el rate limiting.
#### Paso 1: Exportar Cookies desde tu Navegador
**Chrome/Edge:**
1. Instala la extensión: [Get cookies.txt LOCALLY](https://chrome.google.com/webstore)
2. Ve a youtube.com y asegúrate de estar logueado
3. Haz clic en el icono de la extensión
4. Clic en "Export" → "Export cookies.txt"
**Firefox:**
1. Instala el addon: [cookies.txt](https://addons.mozilla.org/firefox/addon/cookies-txt/)
2. Ve a youtube.com
3. Haz clic en el icono del addon
4. Guarda el archivo
#### Paso 2: Colocar el archivo cookies.txt
```bash
# Copiar el archivo descargado al directorio del proyecto
cp ~/Downloads/cookies.txt /path/to/TubeScript-API/cookies.txt
# Dar permisos correctos
chmod 600 cookies.txt
```
#### Paso 3: Reiniciar los contenedores
```bash
docker-compose restart
```
### Opción 2: Esperar y Reintentar
Si no quieres usar cookies, simplemente espera unos minutos antes de volver a intentar.
```bash
# Espera 5-10 minutos
# Luego intenta nuevamente
```
### Opción 3: Usar una VPN o Cambiar IP
Si YouTube bloqueó tu IP:
1. Conecta a una VPN
2. O reinicia tu router para obtener nueva IP
3. Intenta nuevamente
### Opción 4: Usar Proxy
Configura yt-dlp para usar un proxy:
```bash
# Edita docker-compose.yml y agrega:
environment:
- HTTP_PROXY=http://tu-proxy:puerto
- HTTPS_PROXY=http://tu-proxy:puerto
```
---
## 🧪 Probar la Solución
### Test 1: Sin Cookies
```bash
# Probar endpoint
curl -X GET "http://localhost:8080/transcript/CSlg5S9yL2E?lang=es"
```
Si falla con 429, espera 2 minutos y vuelve a intentar.
### Test 2: Con Cookies
```bash
# Después de agregar cookies.txt
docker-compose restart
# Probar nuevamente
curl -X GET "http://localhost:8080/transcript/CSlg5S9yL2E?lang=es"
```
### Test 3: Verificar Cookies en el Contenedor
```bash
# Verificar que cookies.txt esté presente
docker exec tubescript_api ls -lh cookies.txt
# Ver contenido (primeras líneas)
docker exec tubescript_api head -5 cookies.txt
```
---
## 🔍 Identificar el Problema
### Ver Logs Detallados
```bash
# Logs del API
docker logs tubescript_api 2>&1 | tail -50
# Logs de Streamlit
docker logs streamlit_panel 2>&1 | tail -50
```
### Probar Manualmente con yt-dlp
```bash
# Entrar al contenedor
docker exec -it tubescript_api /bin/bash
# Probar yt-dlp directamente
yt-dlp --dump-json --skip-download \
--write-auto-subs --sub-format json3 --sub-langs "es.*" \
"https://www.youtube.com/watch?v=CSlg5S9yL2E"
# Con cookies
yt-dlp --cookies cookies.txt --dump-json --skip-download \
--write-auto-subs --sub-format json3 --sub-langs "es.*" \
"https://www.youtube.com/watch?v=CSlg5S9yL2E"
```
---
## ⚠️ Prevención de Rate Limiting
### 1. No Hacer Peticiones Excesivas
Evita hacer decenas de peticiones seguidas. YouTube detecta esto como abuso.
### 2. Usar Cookies Siempre
Las cuentas autenticadas tienen límites más altos.
### 3. Caché de Respuestas
Implementar un sistema de caché para no pedir los mismos subtítulos repetidamente.
### 4. Espaciar las Peticiones
Si haces múltiples peticiones, espera al menos 1-2 segundos entre cada una.
---
## 📊 Códigos de Error HTTP
| Código | Significado | Solución |
|--------|-------------|----------|
| **429** | Too Many Requests | Esperar + agregar cookies |
| **403** | Forbidden | Restricciones geográficas/cookies |
| **404** | Not Found | Subtítulos no disponibles |
| **503** | Service Unavailable | YouTube caído temporalmente |
---
## 🛠️ Mejoras Implementadas en el Código
### Antes:
```python
response = requests.get(sub_url, timeout=30)
if response.status_code != 200:
return None, f"Error HTTP {response.status_code}"
```
### Después:
```python
# Headers de navegador
headers = {
'User-Agent': 'Mozilla/5.0...',
'Accept': 'application/json, text/plain, */*',
'Referer': 'https://www.youtube.com/',
}
# Retry con espera incremental
max_retries = 3
for attempt in range(max_retries):
response = requests.get(sub_url, headers=headers, timeout=30)
if response.status_code == 200:
break
elif response.status_code == 429:
if attempt < max_retries - 1:
time.sleep(2 * (attempt + 1)) # 2s, 4s, 6s
continue
return None, "Rate limiting - agrega cookies.txt"
# ... otros casos
```
---
## 💡 Recomendaciones
### Para Uso Personal/Desarrollo
✅ Usar cookies.txt de tu cuenta de YouTube
✅ No hacer más de 10-15 peticiones por minuto
✅ Reiniciar servicios si cambias cookies
### Para Producción
✅ Implementar caché de subtítulos
✅ Usar múltiples IPs rotativas
✅ Considerar YouTube Data API oficial (con cuota)
✅ Implementar rate limiting en tu API
---
## 🔄 Actualizar el Sistema
Si ya tienes el sistema corriendo, actualiza con:
```bash
# Detener servicios
docker-compose down
# Reconstruir con los cambios
docker-compose build --no-cache
# Iniciar nuevamente
docker-compose up -d
# Verificar logs
docker-compose logs -f
```
---
## 📞 Soporte Adicional
Si el problema persiste después de aplicar estas soluciones:
1. **Verifica tu conexión**: `ping youtube.com`
2. **Prueba otro video**: Algunos videos tienen más restricciones
3. **Actualiza yt-dlp**: `docker exec tubescript_api pip install --upgrade yt-dlp`
4. **Revisa los logs completos**: `docker logs tubescript_api 2>&1 | grep -i error`
---
## ✅ Checklist de Solución
- [ ] Agregar cookies.txt al proyecto
- [ ] Reiniciar contenedores Docker
- [ ] Verificar que cookies.txt esté en el contenedor
- [ ] Probar endpoint nuevamente
- [ ] Esperar 5 minutos si sigue fallando
- [ ] Verificar logs para otros errores
- [ ] Probar con otro video
- [ ] Actualizar yt-dlp si es necesario
---
**TubeScript API Pro © 2026**
Solución de Rate Limiting Implementada ✅

View File

@ -1,291 +0,0 @@
# 🎯 Solución HTTP 429 - Extracción de Subtítulos YouTube
## 📋 Estado Actual
### ✅ Implementado
- ✅ Endpoint `/transcript/{video_id}` - Obtiene transcript parseado (segmentos + texto)
- ✅ Endpoint `/transcript_vtt/{video_id}` - Descarga VTT con yt-dlp y devuelve crudo + parseado
- ✅ Endpoint `/stream/{video_id}` - Obtiene URL m3u8 para streaming
- ✅ Endpoint `/upload_vtt/{video_id}` - Permite subir VTT manualmente y parsearlo
- ✅ Endpoint `/debug/metadata/{video_id}` - Muestra metadata de yt-dlp
- ✅ Endpoint `/debug/fetch_subs/{video_id}` - Intenta descargar con verbose y devuelve logs
- ✅ Soporte de cookies (`API_COOKIES_PATH=/app/cookies.txt`)
- ✅ Soporte de proxy (`API_PROXY=socks5h://127.0.0.1:9050`)
- ✅ Script `fetch_transcript.py` - CLI para obtener transcript y guardarlo en JSON/TXT
- ✅ Script `docker-update-ytdlp.sh` - Actualiza yt-dlp en contenedores sin rebuild
### ❌ Problema Actual
**HTTP Error 429: Too Many Requests** al intentar descargar subtítulos desde YouTube.
- **Causa**: YouTube está limitando peticiones al endpoint `timedtext` desde tu IP
- **Afectado**: Tanto `requests` como `yt-dlp` reciben 429
- **Ocurre**: Al intentar descargar subtítulos automáticos (ASR) de videos
## 🔧 Soluciones Disponibles
### Opción 1: Usar Proxy/Tor (Recomendado)
Evita el rate-limit cambiando la IP de salida.
#### Setup rápido con Tor:
```bash
# Instalar Tor
brew install tor # macOS
# sudo apt install tor # Linux
# Iniciar Tor
tor &
# Exportar proxy y arrancar API
export API_PROXY="socks5h://127.0.0.1:9050"
docker compose -f docker-compose.yml up -d --build tubescript-api
# Probar
curl "http://127.0.0.1:8000/transcript_vtt/K08TM4OVLyo?lang=es" | jq .
```
### Opción 2: Usar Cookies Directamente desde Chrome/Firefox (Recomendado)
`yt-dlp` puede leer cookies directamente desde tu navegador sin necesidad de exportarlas.
#### Opción 2A: Usar cookies del navegador directamente
```bash
# Chrome (macOS)
yt-dlp --cookies-from-browser chrome --skip-download --write-auto-sub \
--sub-lang es --sub-format vtt -o "%(id)s.%(ext)s" \
"https://www.youtube.com/watch?v=VIDEO_ID"
# Chrome con perfil específico
yt-dlp --cookies-from-browser chrome:Profile1 --skip-download --write-auto-sub \
--sub-lang es --sub-format vtt -o "%(id)s.%(ext)s" \
"https://www.youtube.com/watch?v=VIDEO_ID"
# Firefox
yt-dlp --cookies-from-browser firefox --skip-download --write-auto-sub \
--sub-lang es --sub-format vtt -o "%(id)s.%(ext)s" \
"https://www.youtube.com/watch?v=VIDEO_ID"
# Brave
yt-dlp --cookies-from-browser brave --skip-download --write-auto-sub \
--sub-lang es --sub-format vtt -o "%(id)s.%(ext)s" \
"https://www.youtube.com/watch?v=VIDEO_ID"
```
**Encontrar perfiles de Chrome:**
```bash
# macOS
ls -la ~/Library/Application\ Support/Google/Chrome/
# Linux
ls -la ~/.config/google-chrome/
# Los perfiles típicos son: Default, Profile 1, Profile 2, etc.
```
#### Opción 2B: Exportar cookies manualmente (si la opción 2A no funciona)
1. Instala extensión "cookies.txt" en Chrome/Firefox
2. Abre YouTube estando logueado en tu cuenta
3. Exporta cookies (extensión → Export → `cookies.txt`)
4. Reemplaza `./cookies.txt` en la raíz del proyecto
5. Reinicia contenedor:
```bash
docker compose down
docker compose up -d --build tubescript-api
```
### Opción 3: Cambiar de IP
- Usar VPN
- Tethering móvil (4G/5G)
- Esperar algunas horas (el rate-limit puede ser temporal)
### Opción 4: Workaround Manual (Más Rápido)
Si necesitas el transcript YA y no puedes resolver el 429:
#### Opción 4A: Subir VTT manualmente al API
```bash
# Descarga el VTT desde otro equipo/navegador donde no esté bloqueado
# o pídele a alguien que te lo pase
# Súbelo al API
curl -X POST "http://127.0.0.1:8000/upload_vtt/VIDEO_ID" \
-H "Content-Type: multipart/form-data" \
-F "file=@/ruta/al/archivo.vtt" | jq .
# El API responde con: { segments, text, count, path }
```
#### Opción 4B: Usar youtube-transcript-api (Python alternativo)
```bash
pip install youtube-transcript-api
python3 << 'EOF'
from youtube_transcript_api import YouTubeTranscriptApi
import json
video_id = "K08TM4OVLyo"
try:
transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=['es'])
with open(f"{video_id}_transcript.json", 'w', encoding='utf-8') as f:
json.dump(transcript, f, ensure_ascii=False, indent=2)
print(f"✅ Guardado: {video_id}_transcript.json")
except Exception as e:
print(f"❌ Error: {e}")
EOF
```
#### Opción 4C: Script usando cookies desde Chrome directamente
```bash
# Crear script que usa cookies del navegador
cat > get_transcript_chrome.sh << 'SCRIPT'
#!/bin/bash
VIDEO_ID="${1:-K08TM4OVLyo}"
LANG="${2:-es}"
BROWSER="${3:-chrome}" # chrome, firefox, brave, etc.
echo "🔍 Obteniendo transcript de: $VIDEO_ID"
echo " Idioma: $LANG"
echo " Navegador: $BROWSER"
yt-dlp --cookies-from-browser "$BROWSER" \
--skip-download --write-auto-sub \
--sub-lang "$LANG" --sub-format vtt \
-o "%(id)s.%(ext)s" \
"https://www.youtube.com/watch?v=$VIDEO_ID" 2>&1 | grep -E "Writing|ERROR|✓"
if [ -f "${VIDEO_ID}.${LANG}.vtt" ]; then
echo "✅ Archivo generado: ${VIDEO_ID}.${LANG}.vtt"
echo "📝 Primeras líneas:"
head -n 20 "${VIDEO_ID}.${LANG}.vtt"
else
echo "❌ No se generó el archivo VTT"
fi
SCRIPT
chmod +x get_transcript_chrome.sh
# Usar el script
./get_transcript_chrome.sh VIDEO_ID es chrome
```
## 📚 Uso de Endpoints
### 1. Obtener Transcript (intenta automáticamente con yt-dlp)
```bash
curl "http://127.0.0.1:8000/transcript/K08TM4OVLyo?lang=es" | jq .
```
Respuesta:
```json
{
"video_id": "K08TM4OVLyo",
"count": 150,
"segments": [...],
"text": "texto concatenado de todos los segmentos"
}
```
### 2. Obtener VTT Crudo + Parseado
```bash
curl "http://127.0.0.1:8000/transcript_vtt/K08TM4OVLyo?lang=es" | jq .
```
Respuesta:
```json
{
"video_id": "K08TM4OVLyo",
"vtt": "WEBVTT\n\n00:00:00.000 --> 00:00:02.000\nHola...",
"count": 150,
"segments": [...],
"text": "..."
}
```
### 3. Debug: Ver Metadata
```bash
curl "http://127.0.0.1:8000/debug/metadata/K08TM4OVLyo" | jq .
```
### 4. Debug: Intentar Descarga Verbose
```bash
curl "http://127.0.0.1:8000/debug/fetch_subs/K08TM4OVLyo?lang=es" | jq .
```
Respuesta incluye:
- `rc`: código de salida de yt-dlp
- `stdout_tail`: últimas 2000 chars de stdout
- `stderr_tail`: últimas 2000 chars de stderr (aquí verás "HTTP Error 429")
- `generated`: lista de archivos generados (si hubo éxito)
### 5. Subir VTT Manualmente
```bash
curl -X POST "http://127.0.0.1:8000/upload_vtt/K08TM4OVLyo" \
-F "file=@K08TM4OVLyo.vtt" | jq .
```
## 🐳 Docker
### Comandos útiles
```bash
# Rebuild y levantar (aplica cambios en main.py)
docker compose -f docker-compose.yml build --no-cache tubescript-api
docker compose -f docker-compose.yml up -d tubescript-api
# Ver logs
docker logs -f tubescript_api
# Actualizar yt-dlp (sin rebuild)
bash docker-update-ytdlp.sh
# Entrar al contenedor
docker exec -it tubescript_api /bin/sh
# Verificar cookies montadas
docker exec -it tubescript_api cat /app/cookies.txt | head -n 10
```
### Variables de Entorno
```yaml
environment:
- API_COOKIES_PATH=/app/cookies.txt
- API_PROXY=socks5h://127.0.0.1:9050 # opcional
```
## 🔍 Diagnóstico
### Verificar HTTP 429
```bash
# Host (local)
yt-dlp --verbose --skip-download --write-auto-sub \
--sub-lang es --sub-format vtt \
--cookies ./cookies.txt -o "%(id)s.%(ext)s" \
"https://www.youtube.com/watch?v=K08TM4OVLyo" 2>&1 | grep -i "error\|429"
# Dentro del contenedor
docker exec -it tubescript_api sh -c \
"yt-dlp --verbose --skip-download --write-auto-sub \
--sub-lang es --sub-format vtt \
--cookies /app/cookies.txt -o '/tmp/%(id)s.%(ext)s' \
'https://www.youtube.com/watch?v=K08TM4OVLyo'" 2>&1 | grep -i "error\|429"
```
### Probar con otro video
```bash
# Prueba con un video de noticias 24/7 (menos probabilidad de 429)
curl "http://127.0.0.1:8000/transcript/NNL3iiDf1HI?lang=es" | jq .
```
## 📖 Referencias
- [yt-dlp GitHub](https://github.com/yt-dlp/yt-dlp)
- [Guía PO Token (si yt-dlp requiere)](https://github.com/yt-dlp/yt-dlp/wiki/PO-Token-Guide)
- [youtube-transcript-api](https://github.com/jdepoix/youtube-transcript-api)
## 🎯 Próximos Pasos
1. **Inmediato**: Probar Opción 1 (Tor) o Opción 4B (youtube-transcript-api)
2. **Corto plazo**: Re-exportar cookies válidas (Opción 2)
3. **Mediano plazo**: Implementar rotación de IPs/proxies automática
4. **Largo plazo**: Considerar usar YouTube Data API v3 (requiere API key pero evita rate-limits)
---
**Última actualización**: 2025-02-22
**Estado**: HTTP 429 confirmado; soluciones alternativas implementadas

View File

@ -1,8 +1,3 @@
# Nota: Streamlit eliminado
> El panel Streamlit fue eliminado en esta rama; por favor use la API (main.py) para todas las operaciones y pruebas.
# 🎯 INSTRUCCIONES DE INICIO
## ⚡ Inicio Rápido (3 pasos)

View File

@ -1,497 +0,0 @@
# Nota: Streamlit eliminado
> El frontend Streamlit fue eliminado. Usa `main.py` o Docker para ejecutar la API.
# START HERE
# 🎉 IMPLEMENTACIÓN COMPLETADA - TubeScript API Pro
## ✅ Estado: COMPLETADO Y LISTO PARA USAR
---
## 📋 Resumen de lo Implementado
### 🔧 Mejoras en el Backend (main.py)
1. **✅ Función `get_transcript_data` mejorada:**
- Manejo robusto de errores con mensajes claros
- Soporte para subtítulos automáticos como fallback
- Timeout de 60 segundos
- Validación exhaustiva de respuestas
- Uso del cliente Android para mayor compatibilidad
2. **✅ Función `get_stream_url` mejorada:**
- Estrategia de fallback con 4 formatos diferentes
- Cliente Android para mejor compatibilidad con YouTube
- Manejo inteligente de timeouts
- Mensajes de error descriptivos y útiles
### 🖥️ Panel Streamlit (streamlit_app.py)
**Ya estaba completo con:**
- ✅ Sistema de switches funcional por plataforma
- ✅ Gestión de PIDs de procesos FFmpeg
- ✅ Semáforos de estado en tiempo real (🟢 🔴 ⚪)
- ✅ Monitoreo activo con auto-refresh (5 segundos)
- ✅ 6 plataformas preconfiguradas con URLs RTMP por defecto
- ✅ Persistencia de configuración en JSON
- ✅ Preview de video con miniatura
- ✅ Control individual y grupal de transmisiones
### 🐳 Scripts Docker Creados
1. **✅ docker-manager.sh** - Gestor interactivo todo-en-uno
2. **✅ docker-start-api.sh** - Iniciar solo FastAPI
3. **✅ docker-start-streamlit.sh** - Iniciar solo Streamlit
4. **✅ docker-stop-all.sh** - Detener todos los servicios
5. **✅ docker-logs-separate.sh** - Ver logs por servicio
6. **✅ docker-create-network.sh** - Crear red de Docker
7. **✅ COMANDOS_RAPIDOS.sh** - Referencia rápida de comandos
### 📚 Documentación Creada
1. **✅ QUICKSTART_COMPLETO.md** - Guía de inicio rápido completa
2. **✅ PANEL_STREAMLIT_GUIA.md** - Guía detallada del panel web
3. **✅ DOCKER_COMANDOS_SEPARADOS_COMPLETO.md** - Comandos Docker detallados
4. **✅ API_EXAMPLES.md** - Ejemplos de uso de la API con cURL, Python, Node.js
5. **✅ RESUMEN_IMPLEMENTACION.md** - Resumen ejecutivo completo
---
## 🚀 Cómo Empezar AHORA
### Opción 1: Gestor Interactivo (Más Fácil)
```bash
./docker-manager.sh
```
Selecciona las opciones del menú:
1. Opción 12: Crear red de Docker
2. Opción 1: Iniciar todos los servicios
3. Opción 14: Abrir panel web
### Opción 2: Comandos Directos
```bash
# 1. Crear red
./docker-create-network.sh
# 2. Iniciar servicios
docker-compose up -d
# 3. Verificar que estén corriendo
docker ps
# 4. Acceder al panel
open http://localhost:8501
```
### Opción 3: Servicios Separados
```bash
# 1. Crear red
./docker-create-network.sh
# 2. Iniciar API
./docker-start-api.sh
# 3. Iniciar Streamlit
./docker-start-streamlit.sh
# 4. Verificar logs
docker logs -f streamlit_panel
```
---
## 📊 Funcionalidades Completas
### Panel Web (http://localhost:8501)
#### Pestaña 1: 🔍 Búsqueda
- Buscar videos en vivo por palabra clave
- Ingresar URL directa de YouTube
- Preview con miniatura y datos del canal
- Verificación de estado EN VIVO (🔴)
#### Pestaña 2: 🎛️ Control
- Vista del video seleccionado
- Switches individuales por plataforma
- Botón "Iniciar Todas" / "Detener Todas"
- Tabla resumen con estado de redes
- Tarjetas por plataforma con:
* Semáforo de estado (🟢 🔴 ⚪)
* PID del proceso
* Tiempo activo
* Switch para activar/desactivar
#### Pestaña 3: 📊 Monitor
- Auto-refresh cada 5 segundos
- Resumen general con métricas
- Estado detallado por plataforma
- Verificación de PIDs en tiempo real
- Botones para detener individualmente
#### Barra Lateral: ⚙️ Configuración
- 6 plataformas: YouTube, Facebook, Twitch, X, Instagram, TikTok
- Switch para habilitar/deshabilitar cada una
- Campo para Stream Key (obligatorio)
- RTMP URL con valor por defecto (opcional personalizar)
- Indicadores visuales de estado
- Guías de ayuda incluidas
### API FastAPI (http://localhost:8080)
#### Endpoints Disponibles:
1. **GET /stream/{video_id}**
- Obtiene URL m3u8 de video en vivo
- Estrategia de fallback inteligente
- Mensajes de error claros
2. **GET /transcript/{video_id}?lang={idioma}**
- Obtiene subtítulos/transcripción
- Soporte para múltiples idiomas
- Fallback a subtítulos automáticos
3. **GET /docs**
- Documentación interactiva Swagger
4. **GET /redoc**
- Documentación ReDoc
---
## 🎯 Plataformas Configuradas
| Plataforma | RTMP URL | Configurada |
|------------|----------|-------------|
| YouTube | rtmp://a.rtmp.youtube.com/live2 | ✅ |
| Facebook | rtmps://live-api-s.facebook.com:443/rtmp/ | ✅ |
| Twitch | rtmp://live.twitch.tv/app | ✅ |
| X (Twitter) | rtmps://fa.contribute.live-video.net/app | ✅ |
| Instagram | rtmps://live-upload.instagram.com:443/rtmp/ | ✅ |
| TikTok | rtmp://push.live.tiktok.com/live/ | ✅ |
---
## 🔄 Flujo de Trabajo Completo
### 1. Configuración Inicial (Primera Vez)
```bash
# Ejecutar gestor
./docker-manager.sh
# Opciones del menú:
# 12 - Crear red de Docker
# 1 - Iniciar todos los servicios
# 14 - Abrir panel web
```
### 2. Configurar Plataformas
En el panel web (http://localhost:8501):
1. Abrir barra lateral (⚙️ Configuración)
2. Para cada plataforma:
- ✅ Activar "Habilitar esta plataforma"
- 🔑 Ingresar Stream Key
- 🌐 (Opcional) Personalizar RTMP URL
3. 💾 Guardar Configuración
### 3. Buscar Video en Vivo
Pestaña 🔍 Búsqueda:
- Buscar: "noticias live" o "CNN live"
- O pegar URL: https://www.youtube.com/watch?v=VIDEO_ID
- Seleccionar video
- Verificar que esté 🔴 EN VIVO
### 4. Iniciar Transmisiones
Pestaña 🎛️ Control:
- Ver preview del video
- Activar switches de las plataformas deseadas
- O clic en "▶️ Iniciar Todas"
- Ver semáforos cambiar a 🟢
### 5. Monitorear
Pestaña 📊 Monitor:
- Ver estado en tiempo real
- Verificar PIDs activos
- Comprobar tiempo de transmisión
- Detener cuando sea necesario
---
## 🎨 Semáforos de Estado
| Semáforo | Estado | Acción |
|----------|--------|--------|
| 🟢 | TRANSMITIENDO | Todo funcionando correctamente |
| ⚪ | LISTO | Configurada pero no transmitiendo |
| 🔴 | ERROR | Revisar logs o reiniciar |
| ⚠️ | DESHABILITADA | Activar en Configuración |
---
## 🛠️ Comandos Útiles
### Ver Logs
```bash
# API
docker logs -f tubescript_api
# Streamlit
docker logs -f streamlit_panel
# Ambos
docker-compose logs -f
```
### Actualizar yt-dlp
```bash
docker exec tubescript_api pip install --upgrade yt-dlp
docker exec streamlit_panel pip install --upgrade yt-dlp
```
### Reiniciar
```bash
docker-compose restart
```
### Detener
```bash
./docker-stop-all.sh
# o
docker-compose down
```
### Reconstruir
```bash
docker-compose down
docker-compose build --no-cache
docker-compose up -d
```
---
## 🆘 Solución de Problemas
### ❌ "No se pudo obtener URL del stream"
**Causas:**
- Video no está EN VIVO (🔴)
- Video con restricciones
- yt-dlp desactualizado
**Solución:**
```bash
# Actualizar yt-dlp
./docker-manager.sh
# Selecciona opción 11
# O reconstruir
docker-compose down
docker-compose build --no-cache
docker-compose up -d
```
### ❌ "Puerto ya en uso"
```bash
# Ver qué usa el puerto
lsof -i :8080 # API
lsof -i :8501 # Streamlit
# Matar proceso
kill -9 $(lsof -ti:8080)
```
### ❌ "Network not found"
```bash
./docker-create-network.sh
```
### ❌ "Transmisión se detuvo"
**Verificar:**
- Video sigue en vivo
- Stream Key correcta
- Ver logs: `docker logs streamlit_panel`
---
## 📦 Archivos Importantes
```
TubeScript-API/
├── main.py # ✅ Backend FastAPI (mejorado)
├── streamlit_app.py # ✅ Frontend Streamlit (completo)
├── docker-compose.yml # Docker Compose
├── Dockerfile # Imagen Docker
├── requirements.txt # Dependencias
├── .env.example # Variables de entorno
├── Scripts:
│ ├── docker-manager.sh # ✅ Gestor interactivo
│ ├── docker-start-api.sh # ✅ Iniciar API
│ ├── docker-start-streamlit.sh # ✅ Iniciar Streamlit
│ ├── docker-stop-all.sh # ✅ Detener todos
│ ├── docker-logs-separate.sh # ✅ Ver logs
│ ├── docker-create-network.sh # ✅ Crear red
│ └── COMANDOS_RAPIDOS.sh # ✅ Referencia rápida
├── Documentación:
│ ├── QUICKSTART_COMPLETO.md # ✅ Inicio rápido
│ ├── PANEL_STREAMLIT_GUIA.md # ✅ Guía del panel
│ ├── DOCKER_COMANDOS_...md # ✅ Comandos Docker
│ ├── API_EXAMPLES.md # ✅ Ejemplos API
│ └── RESUMEN_IMPLEMENTACION.md # ✅ Resumen completo
└── Config:
├── stream_config.json # Configuración de plataformas
├── process_state.json # Estado de procesos
├── streams_state.json # Estado de streams
└── cookies.txt # Cookies de YouTube (opcional)
```
---
## 🌐 URLs de Acceso
| Servicio | URL | Descripción |
|----------|-----|-------------|
| Panel Web | http://localhost:8501 | Interfaz Streamlit |
| API | http://localhost:8080 | FastAPI Backend |
| API Docs | http://localhost:8080/docs | Documentación Swagger |
| API ReDoc | http://localhost:8080/redoc | Documentación alternativa |
---
## 📈 Características Técnicas
### Arquitectura
```
Usuario → Streamlit (8501)
FastAPI (8000/8080) → yt-dlp → YouTube
FFmpeg (PIDs) → RTMP → Plataformas
```
### Gestión de Procesos
- Cada transmisión = Proceso FFmpeg independiente
- PID registrado y monitoreado
- Verificación continua de estado
- Logs separados por plataforma
### Comando FFmpeg
```bash
ffmpeg -re -i "URL_M3U8" -c copy -f flv RTMP_URL/STREAM_KEY
```
---
## ✨ Próximos Pasos
1. ✅ **Ejecutar el gestor:** `./docker-manager.sh`
2. ✅ **Crear red:** Opción 12
3. ✅ **Iniciar servicios:** Opción 1
4. ✅ **Abrir panel:** Opción 14 o http://localhost:8501
5. ✅ **Configurar plataformas:** Stream Keys en la barra lateral
6. ✅ **Buscar video en vivo:** Pestaña Búsqueda
7. ✅ **Iniciar transmisión:** Pestaña Control
8. ✅ **Monitorear:** Pestaña Monitor
---
## 📚 Documentación Completa
Para más detalles, consulta:
- **QUICKSTART_COMPLETO.md** - Guía de inicio rápido
- **PANEL_STREAMLIT_GUIA.md** - Guía completa del panel
- **API_EXAMPLES.md** - Ejemplos de uso de la API
- **DOCKER_COMANDOS_SEPARADOS_COMPLETO.md** - Todos los comandos Docker
- **COMANDOS_RAPIDOS.sh** - Referencia rápida ejecutable
---
## 🎉 ¡Listo para Producción!
El sistema está **100% funcional** y **listo para usar**:
✅ Backend optimizado con manejo robusto de errores
✅ Frontend completo con interfaz intuitiva
✅ Sistema de switches funcional
✅ Gestión de PIDs y monitoreo
✅ Scripts de gestión automatizados
✅ Documentación exhaustiva
✅ 6 plataformas preconfiguradas
✅ Docker Compose para despliegue fácil
---
## 🎯 Características Destacadas
1. **Interfaz Intuitiva** - Diseño limpio con iconos visuales
2. **Control Granular** - Switches individuales por plataforma
3. **Monitoreo en Tiempo Real** - Semáforos y PIDs activos
4. **Fácil Despliegue** - Docker Compose + Scripts automatizados
5. **Multi-Plataforma** - Hasta 6 plataformas simultáneas
6. **Documentación Completa** - Guías paso a paso
7. **Manejo Robusto de Errores** - Mensajes claros y útiles
8. **Persistencia de Config** - No pierde configuración al reiniciar
---
## 💡 Tips Finales
1. **Lee los comandos rápidos:** `./COMANDOS_RAPIDOS.sh`
2. **Usa el gestor interactivo:** `./docker-manager.sh`
3. **Mantén yt-dlp actualizado:** Opción 11 del gestor
4. **Revisa los logs** si algo falla
5. **Guarda tus Stream Keys** en el panel
6. **Usa videos 24/7** como CNN/BBC para pruebas
---
## 🏆 Estado del Proyecto
```
┌─────────────────────────────────────────┐
│ ✅ IMPLEMENTACIÓN COMPLETADA │
│ │
│ Estado: PRODUCCIÓN │
│ Versión: 2.0.0 │
│ Fecha: 30 Enero 2026 │
│ │
│ Backend: ✅ Optimizado │
│ Frontend: ✅ Completo │
│ Docker: ✅ Configurado │
│ Scripts: ✅ Creados │
│ Docs: ✅ Exhaustiva │
│ │
│ 🎉 LISTO PARA USAR 🎉 │
└─────────────────────────────────────────┘
```
---
**TubeScript API Pro © 2026**
Sistema de Retransmisión Multi-Plataforma
✨ Transmite a 6 redes sociales simultáneamente ✨
---
## 🚀 EMPIEZA AHORA:
```bash
./docker-manager.sh
```
¡Éxito con tus transmisiones! 🎥📡🌍

13
demo.sh
View File

@ -29,6 +29,14 @@ echo " ✅ Transmisión simultánea a múltiples plataformas"
echo " ✅ Contador de tiempo de actividad"
echo ""
echo "────────────────────────────────────────────────────────────"
echo "🚀 Para Iniciar el Panel Web:"
echo "────────────────────────────────────────────────────────────"
echo ""
echo " streamlit run streamlit_app.py"
echo ""
echo " El panel se abrirá en: http://localhost:8501"
echo ""
echo "────────────────────────────────────────────────────────────"
echo "📚 Documentación:"
echo "────────────────────────────────────────────────────────────"
echo " • README.md - Documentación completa"
@ -56,8 +64,3 @@ echo "════════════════════════
echo " 🎊 ¡Sistema Listo para Usar!"
echo "════════════════════════════════════════════════════════════"
echo ""
echo "Demo: usar la API (streamlit eliminado)"
echo ""
echo "Accede a la API en: http://localhost:8080/docs"
echo ""
echo "Ejemplo: curl http://localhost:8080/stream/G01-33V6I2g"

View File

@ -1,46 +0,0 @@
version: '3.8'
services:
api:
build:
context: .
dockerfile: Dockerfile.api
container_name: tubescript-api
image: tubescript-api:local
ports:
- "8000:8000"
volumes:
- ./cookies.txt:/app/cookies.txt
- ./stream_config.json:/app/stream_config.json:ro
- ./streams_state.json:/app/streams_state.json:rw
environment:
API_BASE_URL: http://localhost:8000
TZ: UTC
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/docs"]
interval: 30s
timeout: 10s
retries: 3
streamlit:
build:
context: .
dockerfile: Dockerfile.streamlit
container_name: tubescript-streamlit
image: tubescript-streamlit:local
depends_on:
- api
ports:
- "8501:8501"
volumes:
- ./stream_config.json:/app/stream_config.json:ro
- ./cookies.txt:/app/cookies.txt:ro
environment:
API_BASE_URL: http://localhost:8000
TZ: UTC
restart: unless-stopped
networks:
default:
name: tubescript-api_default

View File

@ -1,24 +1,21 @@
version: '3.8'
services:
# Servicio FastAPI - Backend API
tubescript-api:
build:
context: .
dockerfile: Dockerfile.api
dockerfile: Dockerfile
container_name: tubescript_api
command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload
ports:
- "8000:8000"
- "8080:8000"
volumes:
- ./:/app:rw
- ./cookies.txt:/app/cookies.txt:ro
- ./stream_config.json:/app/stream_config.json:ro
- ./cookies.txt:/app/cookies.txt:ro # Solo lectura
- ./stream_config.json:/app/stream_config.json
- ./streams_state.json:/app/streams_state.json
- ./data:/app/data
- ./data:/app/data # Directorio para datos persistentes
environment:
- PYTHONUNBUFFERED=1
- API_COOKIES_PATH=/app/cookies.txt
# Optional: set API_PROXY when you want the container to use a SOCKS/HTTP proxy (e.g. tor)
- API_PROXY=${API_PROXY:-}
restart: unless-stopped
networks:
- tubescript-network
@ -29,6 +26,41 @@ services:
retries: 3
start_period: 40s
# Servicio Streamlit - Frontend Panel Web
streamlit-panel:
build:
context: .
dockerfile: Dockerfile
container_name: streamlit_panel
command: streamlit run streamlit_app.py --server.port=8501 --server.address=0.0.0.0 --server.headless=true --browser.gatherUsageStats=false
ports:
- "8501:8501"
volumes:
- ./cookies.txt:/app/cookies.txt:ro # Solo lectura
- ./stream_config.json:/app/stream_config.json
- ./streams_state.json:/app/streams_state.json
- ./data:/app/data # Directorio para datos persistentes
environment:
- PYTHONUNBUFFERED=1
- API_URL=${API_URL:-http://tubescript-api:8000} # URL de la API, configurable desde .env
restart: unless-stopped
depends_on:
tubescript-api:
condition: service_healthy
networks:
- tubescript-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8501"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
tubescript-network:
name: tubescript-network
driver: bridge
volumes:
data:
driver: local

View File

@ -1,2 +0,0 @@
# Backup del docker-compose original
# Si necesitas restaurarlo, renombra este archivo a docker-compose.yml

View File

@ -1,21 +0,0 @@
#!/bin/bash
# ====================================
# TubeScript API - Crear red de Docker
# ====================================
echo "🌐 Creando red de Docker para TubeScript..."
echo ""
# Verificar si la red ya existe
if docker network inspect tubescript-network >/dev/null 2>&1; then
echo "✅ La red 'tubescript-network' ya existe"
else
# Crear la red
docker network create tubescript-network
echo "✅ Red 'tubescript-network' creada exitosamente"
fi
echo ""
echo "📋 Información de la red:"
docker network inspect tubescript-network --format='{{json .}}' | python3 -m json.tool | head -20

View File

@ -1,34 +0,0 @@
#!/bin/bash
# ====================================
# TubeScript API - Ver logs de servicios
# ====================================
SERVICE=$1
if [ -z "$SERVICE" ]; then
echo "Uso: ./docker-logs.sh [api|both]"
echo ""
echo "Opciones:"
echo " api - Ver logs de FastAPI"
echo " both - Ver logs de ambos servicios"
exit 1
fi
case "$SERVICE" in
api)
echo "📋 Logs de FastAPI (Ctrl+C para salir):"
echo ""
docker logs -f tubescript_api
;;
both)
echo "📋 Logs de ambos servicios (Ctrl+C para salir):"
echo ""
docker-compose logs -f
;;
*)
echo "❌ Opción inválida: $SERVICE"
echo "Usa: api o both"
exit 1
;;
esac

View File

@ -1,271 +0,0 @@
#!/bin/bash
# ====================================
# TubeScript API - Gestor Todo-en-Uno
# ====================================
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# Colores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Función para mostrar el menú
show_menu() {
clear
echo -e "${BLUE}╔════════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ 📺 TubeScript API - Gestor Central ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "${GREEN}SERVICIOS:${NC}"
echo " 1) 🚀 Iniciar TODOS los servicios (Docker Compose)"
echo " 2) 🔧 Iniciar solo FastAPI"
# echo " 3) 🖥️ Iniciar solo Streamlit" # Deshabilitado
echo ""
echo -e "${YELLOW}CONTROL:${NC}"
echo " 4) 🛑 Detener todos los servicios"
echo " 5) 🔄 Reiniciar todos los servicios"
echo " 6) 🏗️ Reconstruir contenedores (rebuild)"
echo ""
echo -e "${BLUE}MONITOREO:${NC}"
echo " 7) 📋 Ver logs de FastAPI"
# echo " 8) 📋 Ver logs de Streamlit" # Deshabilitado
echo " 9) 📋 Ver logs de ambos servicios"
echo " 10) 📊 Ver estado de servicios"
echo ""
echo -e "${GREEN}MANTENIMIENTO:${NC}"
echo " 11) 🔄 Actualizar yt-dlp"
echo " 12) 🌐 Crear red de Docker"
echo " 13) 🧹 Limpiar contenedores y volúmenes"
echo ""
echo -e "${BLUE}UTILIDADES:${NC}"
echo " 14) 🌍 Abrir panel web (Streamlit)"
echo " 15) 📚 Abrir documentación API (FastAPI)"
echo " 16) ⚙️ Editar configuración (.env)"
echo ""
echo " 0) 🚪 Salir"
echo ""
echo -n "Selecciona una opción: "
}
# Función para esperar input del usuario
wait_for_key() {
echo ""
echo -e "${YELLOW}Presiona cualquier tecla para continuar...${NC}"
read -n 1 -s
}
# Función para verificar si Docker está instalado
check_docker() {
if ! command -v docker &> /dev/null; then
echo -e "${RED}❌ Docker no está instalado${NC}"
echo "Por favor instala Docker primero"
exit 1
fi
}
# Función para verificar estado de servicios
check_services() {
echo -e "${BLUE}📊 Estado de los servicios:${NC}"
echo ""
# Verificar FastAPI
if docker ps | grep -q tubescript_api; then
echo -e " FastAPI: ${GREEN}🟢 ACTIVO${NC} (http://localhost:8080)"
else
echo -e " FastAPI: ${RED}🔴 DETENIDO${NC}"
fi
# Verificar Streamlit
if docker ps | grep -q streamlit_panel; then
echo -e " Streamlit: ${GREEN}🟢 ACTIVO${NC} (http://localhost:8501)"
else
echo -e " Streamlit: ${RED}🔴 DETENIDO${NC}"
fi
echo ""
# Mostrar recursos
if docker ps | grep -q "tubescript\|streamlit"; then
echo -e "${BLUE}💻 Uso de recursos:${NC}"
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}" \
$(docker ps -q --filter "name=tubescript\|streamlit") 2>/dev/null || true
fi
}
# Verificar Docker
check_docker
# Loop principal
while true; do
show_menu
read -r option
case $option in
1)
echo ""
echo -e "${GREEN}🚀 Iniciando todos los servicios con Docker Compose...${NC}"
docker-compose down 2>/dev/null
docker-compose up -d
echo ""
echo -e "${GREEN}✅ Servicios iniciados${NC}"
check_services
wait_for_key
;;
2)
echo ""
echo -e "${GREEN}🔧 Iniciando solo FastAPI...${NC}"
./docker-start-api.sh
wait_for_key
;;
# 3) Deshabilitado
# echo ""
# echo -e "${GREEN}🖥️ Iniciando solo Streamlit...${NC}"
# ./docker-start-streamlit.sh
# wait_for_key
# ;;
4)
echo ""
echo -e "${YELLOW}🛑 Deteniendo todos los servicios...${NC}"
./docker-stop-all.sh
docker-compose down 2>/dev/null
echo ""
echo -e "${GREEN}✅ Todos los servicios detenidos${NC}"
wait_for_key
;;
5)
echo ""
echo -e "${YELLOW}🔄 Reiniciando todos los servicios...${NC}"
docker-compose down 2>/dev/null
./docker-stop-all.sh
sleep 2
docker-compose up -d
echo ""
echo -e "${GREEN}✅ Servicios reiniciados${NC}"
check_services
wait_for_key
;;
6)
echo ""
echo -e "${YELLOW}🏗️ Reconstruyendo contenedores...${NC}"
docker-compose down
docker-compose build --no-cache
docker-compose up -d
echo ""
echo -e "${GREEN}✅ Contenedores reconstruidos${NC}"
check_services
wait_for_key
;;
7)
echo ""
echo -e "${BLUE}📋 Logs de FastAPI (Ctrl+C para salir):${NC}"
echo ""
docker logs -f tubescript_api 2>/dev/null || echo -e "${RED}❌ FastAPI no está corriendo${NC}"
wait_for_key
;;
# 8) Deshabilitado
# echo ""
# echo -e "${BLUE}📋 Logs de Streamlit (Ctrl+C para salir):${NC}"
# echo ""
# docker logs -f streamlit_panel 2>/dev/null || echo -e "${RED}❌ Streamlit no está corriendo${NC}"
# wait_for_key
# ;;
9)
echo ""
echo -e "${BLUE}📋 Logs de ambos servicios (Ctrl+C para salir):${NC}"
echo ""
docker-compose logs -f 2>/dev/null || echo -e "${RED}❌ Servicios no están corriendo con Docker Compose${NC}"
wait_for_key
;;
10)
echo ""
check_services
wait_for_key
;;
11)
echo ""
echo -e "${GREEN}🔄 Actualizando yt-dlp en ambos contenedores...${NC}"
echo ""
if docker ps | grep -q tubescript_api; then
echo "Actualizando en FastAPI..."
docker exec tubescript_api pip install --upgrade yt-dlp
fi
if docker ps | grep -q streamlit_panel; then
echo "Actualizando en Streamlit..."
docker exec streamlit_panel pip install --upgrade yt-dlp
fi
echo ""
echo -e "${GREEN}✅ yt-dlp actualizado${NC}"
wait_for_key
;;
12)
echo ""
echo -e "${GREEN}🌐 Creando red de Docker...${NC}"
./docker-create-network.sh
wait_for_key
;;
13)
echo ""
echo -e "${RED}⚠️ ADVERTENCIA: Esto eliminará contenedores e imágenes no utilizados${NC}"
echo -n "¿Continuar? (s/n): "
read -r confirm
if [[ $confirm == "s" || $confirm == "S" ]]; then
docker container prune -f
docker image prune -a -f
echo ""
echo -e "${GREEN}✅ Limpieza completada${NC}"
else
echo "Operación cancelada"
fi
wait_for_key
;;
14)
echo ""
echo -e "${BLUE}🌍 Abriendo panel web...${NC}"
if command -v open &> /dev/null; then
open http://localhost:8501
elif command -v xdg-open &> /dev/null; then
xdg-open http://localhost:8501
else
echo "Abre en tu navegador: http://localhost:8501"
fi
wait_for_key
;;
15)
echo ""
echo -e "${BLUE}📚 Abriendo documentación API...${NC}"
if command -v open &> /dev/null; then
open http://localhost:8080/docs
elif command -v xdg-open &> /dev/null; then
xdg-open http://localhost:8080/docs
else
echo "Abre en tu navegador: http://localhost:8080/docs"
fi
wait_for_key
;;
16)
echo ""
echo -e "${BLUE}⚙️ Editando configuración...${NC}"
if [ ! -f .env ]; then
cp .env.example .env
echo "Archivo .env creado desde .env.example"
fi
${EDITOR:-nano} .env
wait_for_key
;;
0)
echo ""
echo -e "${GREEN}👋 ¡Hasta luego!${NC}"
exit 0
;;
*)
echo ""
echo -e "${RED}❌ Opción inválida${NC}"
wait_for_key
;;
esac
done

View File

@ -1,42 +0,0 @@
#!/bin/bash
# ====================================
# TubeScript API - Iniciar solo FastAPI
# ====================================
echo "🚀 Iniciando servicio FastAPI..."
echo ""
# Detener contenedor si está corriendo
docker stop tubescript_api 2>/dev/null || true
docker rm tubescript_api 2>/dev/null || true
# Construir imagen
echo "📦 Construyendo imagen..."
docker build -t tubescript-api .
# Iniciar contenedor
echo "▶️ Iniciando contenedor FastAPI..."
docker run -d \
--name tubescript_api \
--network tubescript-network \
-p 8080:8000 \
-v "$(pwd)/cookies.txt:/app/cookies.txt:ro" \
-v "$(pwd)/stream_config.json:/app/stream_config.json" \
-v "$(pwd)/streams_state.json:/app/streams_state.json" \
-v "$(pwd)/process_state.json:/app/process_state.json" \
-v "$(pwd)/data:/app/data" \
-e PYTHONUNBUFFERED=1 \
tubescript-api \
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
echo ""
echo "✅ FastAPI iniciado correctamente"
echo "📍 URL: http://localhost:8080"
echo "📚 Docs: http://localhost:8080/docs"
echo ""
echo "📋 Ver logs:"
echo " docker logs -f tubescript_api"
echo ""
echo "🛑 Detener:"
echo " docker stop tubescript_api"

View File

@ -1,51 +0,0 @@
#!/bin/bash
# ====================================
# TubeScript API - Iniciar solo Streamlit
# ====================================
echo "🚀 Iniciando servicio Streamlit..."
echo ""
# Detener contenedor si está corriendo
docker stop streamlit_panel 2>/dev/null || true
docker rm streamlit_panel 2>/dev/null || true
# Construir imagen
echo "📦 Construyendo imagen..."
docker build -t tubescript-api .
# Leer API_URL desde .env o usar valor por defecto
if [ -f .env ]; then
export $(cat .env | grep -v '^#' | xargs)
fi
API_URL=${API_URL:-http://tubescript-api:8000}
echo "🔗 Conectando a API: $API_URL"
# Iniciar contenedor
echo "▶️ Iniciando contenedor Streamlit..."
docker run -d \
--name streamlit_panel \
--network tubescript-network \
-p 8501:8501 \
-v "$(pwd)/cookies.txt:/app/cookies.txt:ro" \
-v "$(pwd)/stream_config.json:/app/stream_config.json" \
-v "$(pwd)/streams_state.json:/app/streams_state.json" \
-v "$(pwd)/process_state.json:/app/process_state.json" \
-v "$(pwd)/data:/app/data" \
-e PYTHONUNBUFFERED=1 \
-e API_URL="$API_URL" \
tubescript-api \
streamlit run streamlit_app.py --server.port=8501 --server.address=0.0.0.0 --server.headless=true --browser.gatherUsageStats=false
echo ""
echo "✅ Streamlit iniciado correctamente"
echo "📍 URL: http://localhost:8501"
echo ""
echo "📋 Ver logs:"
echo " docker logs -f streamlit_panel"
echo ""
echo "🛑 Detener:"
echo " docker stop streamlit_panel"

View File

@ -1,27 +0,0 @@
#!/bin/bash
# ====================================
# TubeScript API - Detener todos los servicios
# ====================================
echo "🛑 Deteniendo servicios..."
echo ""
# Detener servicios individuales
services=(tubescript_api streamlit_panel)
for s in "${services[@]}"; do
if docker ps -a --format '{{.Names}}' | grep -q "^$s$"; then
echo "Deteniendo $s..."
docker stop $s 2>/dev/null && echo "$s detenido" || echo "⚠️ $s no estaba corriendo"
fi
done
echo ""
echo "🗑️ Eliminando contenedores..."
for s in "${services[@]}"; do
docker rm $s 2>/dev/null
done
echo ""
echo "✅ Todos los servicios han sido detenidos"

View File

@ -1,49 +0,0 @@
#!/bin/bash
# ====================================
# TubeScript API - Actualizar Sistema
# ====================================
echo "🔄 Actualizando TubeScript API con correcciones..."
echo ""
# Detener servicios
echo "🛑 Deteniendo servicios..."
docker-compose down 2>/dev/null
./docker-stop-all.sh 2>/dev/null
echo ""
echo "🏗️ Reconstruyendo contenedores..."
docker-compose build --no-cache
echo ""
echo "🚀 Iniciando servicios actualizados..."
docker-compose up -d
echo ""
echo "⏳ Esperando que los servicios inicien..."
sleep 5
echo ""
echo "✅ Actualización completada"
echo ""
echo "📊 Estado de servicios:"
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
echo ""
echo "🔍 Verificando versión de yt-dlp..."
docker exec tubescript_api yt-dlp --version 2>/dev/null || echo "⚠️ yt-dlp no disponible aún"
docker exec streamlit_panel yt-dlp --version 2>/dev/null || echo "⚠️ yt-dlp no disponible aún"
echo ""
echo "💡 Mejoras aplicadas:"
echo " ✅ Sistema de retry automático para HTTP 429"
echo " ✅ Headers de navegador para evitar bloqueos"
echo " ✅ Mensajes de error mejorados y específicos"
echo " ✅ Manejo de rate limiting de YouTube"
echo ""
echo "📚 Para más información:"
echo " cat SOLUCION_HTTP_429_RATE_LIMITING.md"
echo ""
echo "🌐 Accede al panel:"
echo " http://localhost:8501"

View File

@ -29,61 +29,52 @@ print_error() {
echo "🔍 Verificando contenedores..."
if ! docker ps | grep -q streamlit_panel; then
print_warning "El contenedor streamlit_panel no está corriendo"
else
print_success "Contenedor streamlit_panel encontrado"
print_error "El contenedor streamlit_panel no está corriendo"
echo "Inicia los contenedores con: docker-compose up -d"
exit 1
fi
if ! docker ps | grep -q tubescript_api; then
print_error "El contenedor tubescript_api no está corriendo"
echo "Inicia los contenedores con: docker-compose up -d"
exit 1
else
print_success "Contenedor tubescript_api encontrado"
fi
print_success "Contenedores encontrados"
echo ""
# Actualizar yt-dlp en streamlit_panel si existe
if docker ps --format '{{.Names}}' | grep -q '^streamlit_panel$'; then
echo "📦 Actualizando yt-dlp en streamlit_panel..."
docker exec streamlit_panel pip install --upgrade yt-dlp
# Actualizar yt-dlp en streamlit_panel
echo "📦 Actualizando yt-dlp en streamlit_panel..."
docker exec streamlit_panel pip install --upgrade yt-dlp
if [ $? -eq 0 ]; then
print_success "yt-dlp actualizado en streamlit_panel"
if [ $? -eq 0 ]; then
print_success "yt-dlp actualizado en streamlit_panel"
# Verificar versión
version=$(docker exec streamlit_panel python3 -c "import yt_dlp; print(yt_dlp.version.__version__)" 2>/dev/null)
if [ ! -z "$version" ]; then
echo " Versión instalada: $version"
fi
else
print_error "Error al actualizar yt-dlp en streamlit_panel"
fi
# Verificar versión
version=$(docker exec streamlit_panel python3 -c "import yt_dlp; print(yt_dlp.version.__version__)" 2>/dev/null)
if [ ! -z "$version" ]; then
echo " Versión instalada: $version"
fi
else
echo "streamlit_panel no encontrado — omitiendo actualización en Streamlit"
print_error "Error al actualizar yt-dlp en streamlit_panel"
fi
echo ""
# Actualizar yt-dlp en tubescript_api
if docker ps --format '{{.Names}}' | grep -q '^tubescript_api$'; then
echo "📦 Actualizando yt-dlp en tubescript_api..."
docker exec tubescript_api pip install --upgrade yt-dlp
echo "📦 Actualizando yt-dlp en tubescript_api..."
docker exec tubescript_api pip install --upgrade yt-dlp
if [ $? -eq 0 ]; then
print_success "yt-dlp actualizado en tubescript_api"
if [ $? -eq 0 ]; then
print_success "yt-dlp actualizado en tubescript_api"
# Verificar versión
version=$(docker exec tubescript_api python3 -c "import yt_dlp; print(yt_dlp.version.__version__)" 2>/dev/null)
if [ ! -z "$version" ]; then
echo " Versión instalada: $version"
fi
else
print_error "Error al actualizar yt-dlp en tubescript_api"
fi
# Verificar versión
version=$(docker exec tubescript_api python3 -c "import yt_dlp; print(yt_dlp.version.__version__)" 2>/dev/null)
if [ ! -z "$version" ]; then
echo " Versión instalada: $version"
fi
else
echo "tubescript_api no encontrado — omitiendo actualización en API"
print_error "Error al actualizar yt-dlp en tubescript_api"
fi
echo ""
@ -91,7 +82,6 @@ echo "════════════════════════
print_success "Actualización completada"
echo "═══════════════════════════════════════════════════════════"
echo ""
echo "💡 Ahora puedes probar con un video en vivo en la API Docs:"
echo " http://localhost:8080/docs"
echo " Para obtener stream URL: curl http://localhost:8080/stream/VIDEO_ID"
echo "💡 Ahora puedes probar con un video en vivo en:"
echo " http://localhost:8501"
echo ""

View File

@ -1,123 +0,0 @@
#!/usr/bin/env python3
"""
Script para obtener transcript de un video de YouTube usando las funciones del proyecto.
Maneja HTTP 429 y guarda el resultado en JSON.
Uso:
python3 fetch_transcript.py VIDEO_ID [LANG] [BROWSER]
Ejemplos:
python3 fetch_transcript.py K08TM4OVLyo es
python3 fetch_transcript.py K08TM4OVLyo es chrome
python3 fetch_transcript.py K08TM4OVLyo es "chrome:Profile 1"
"""
import sys
import json
import os
import subprocess
import tempfile
import glob
from main import parse_subtitle_format
def fetch_with_browser_cookies(video_id, lang="es", browser="chrome"):
"""Intenta obtener transcript usando cookies desde el navegador directamente."""
print(f"🔑 Usando cookies desde navegador: {browser}")
with tempfile.TemporaryDirectory() as tmpdir:
cmd = [
"yt-dlp",
"--cookies-from-browser", browser,
"--skip-download",
"--write-auto-sub",
"--write-sub",
"--sub-lang", lang,
"--sub-format", "vtt",
"-o", os.path.join(tmpdir, "%(id)s.%(ext)s"),
f"https://www.youtube.com/watch?v={video_id}"
]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=180)
# Buscar archivos VTT generados
files = glob.glob(os.path.join(tmpdir, f"{video_id}*.vtt"))
if files:
with open(files[0], 'r', encoding='utf-8') as f:
vtt_content = f.read()
segments = parse_subtitle_format(vtt_content, 'vtt')
return segments, None
else:
stderr = result.stderr or ''
return None, f"No se generaron archivos. Error: {stderr[:500]}"
except subprocess.TimeoutExpired:
return None, "Timeout al ejecutar yt-dlp"
except FileNotFoundError:
return None, "yt-dlp no está instalado. Ejecuta: pip install yt-dlp"
except Exception as e:
return None, f"Error: {str(e)[:200]}"
def main():
if len(sys.argv) < 2:
print("Uso: python3 fetch_transcript.py VIDEO_ID [LANG] [BROWSER]")
print("")
print("Ejemplos:")
print(" python3 fetch_transcript.py K08TM4OVLyo")
print(" python3 fetch_transcript.py K08TM4OVLyo es")
print(" python3 fetch_transcript.py K08TM4OVLyo es chrome")
print(" python3 fetch_transcript.py K08TM4OVLyo es 'chrome:Profile 1'")
print(" python3 fetch_transcript.py K08TM4OVLyo es firefox")
print("")
sys.exit(1)
video_id = sys.argv[1]
lang = sys.argv[2] if len(sys.argv) > 2 else "es"
browser = sys.argv[3] if len(sys.argv) > 3 else None
print(f"🔍 Intentando obtener transcript para: {video_id}")
print(f" Idioma: {lang}")
if browser:
print(f" Método: Cookies desde {browser}")
segments, error = fetch_with_browser_cookies(video_id, lang, browser)
else:
print(f" Método: API del proyecto")
print(f" Cookies: {os.getenv('API_COOKIES_PATH', './cookies.txt')}")
from main import get_transcript_data
segments, error = get_transcript_data(video_id, lang)
print("")
# Intentar obtener transcript
segments, error = get_transcript_data(video_id, lang)
if error:
print(f"❌ ERROR: {error}")
sys.exit(1)
if not segments:
print("❌ No se obtuvieron segmentos")
sys.exit(1)
print(f"✅ Éxito: {len(segments)} segmentos obtenidos")
# Guardar a JSON
output_file = f"{video_id}_transcript.json"
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(segments, f, ensure_ascii=False, indent=2)
print(f"💾 Guardado en: {output_file}")
# Guardar texto concatenado
text_file = f"{video_id}_transcript.txt"
combined_text = "\n".join([seg.get('text', '') for seg in segments])
with open(text_file, 'w', encoding='utf-8') as f:
f.write(combined_text)
print(f"📄 Texto guardado en: {text_file}")
# Mostrar primeros 10 segmentos
print("\n📝 Primeros 10 segmentos:")
for seg in segments[:10]:
print(f" [{seg.get('start', 0):.1f}s] {seg.get('text', '')}")
if __name__ == "__main__":
main()

View File

@ -1,20 +1,132 @@
#!/bin/bash
# Script de arreglo de yt-dlp - solo actúa si el contenedor existe
# Script para forzar reinstalación de yt-dlp en contenedores
if docker ps --format '{{.Names}}' | grep -q '^streamlit_panel$'; then
echo "Actualizando yt-dlp en streamlit_panel..."
docker exec streamlit_panel pip uninstall -y yt-dlp yt_dlp 2>/dev/null || true
docker exec streamlit_panel pip install --no-cache-dir --force-reinstall yt-dlp
else
echo "Contenedor streamlit_panel no encontrado — saltando acciones relacionadas con Streamlit"
echo "═══════════════════════════════════════════════════════════"
echo " 🔧 Reinstalación Forzada de yt-dlp"
echo "═══════════════════════════════════════════════════════════"
echo ""
# Colores
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
print_success() {
echo -e "${GREEN}$1${NC}"
}
print_error() {
echo -e "${RED}$1${NC}"
}
print_info() {
echo -e "${YELLOW} $1${NC}"
}
# Verificar Docker
if ! command -v docker &> /dev/null; then
print_error "Docker no está instalado"
exit 1
fi
# Actualizar en el contenedor de API si existe
if docker ps --format '{{.Names}}' | grep -q '^tubescript_api$'; then
echo "Actualizando yt-dlp en tubescript_api..."
docker exec tubescript_api pip uninstall -y yt-dlp yt_dlp 2>/dev/null || true
docker exec tubescript_api pip install --no-cache-dir --force-reinstall yt-dlp
else
echo "Contenedor tubescript_api no encontrado — asegúrate que la API esté corriendo si deseas actualizar yt-dlp"
# Verificar contenedores
echo "🔍 Verificando contenedores..."
if ! docker ps | grep -q streamlit_panel; then
print_error "El contenedor streamlit_panel no está corriendo"
print_info "Inicia con: docker-compose up -d"
exit 1
fi
if ! docker ps | grep -q tubescript_api; then
print_error "El contenedor tubescript_api no está corriendo"
print_info "Inicia con: docker-compose up -d"
exit 1
fi
print_success "Contenedores encontrados"
echo ""
# Desinstalar yt-dlp actual
echo "🗑️ Desinstalando yt-dlp antiguo en streamlit_panel..."
docker exec streamlit_panel pip uninstall -y yt-dlp 2>/dev/null
docker exec streamlit_panel pip uninstall -y yt_dlp 2>/dev/null
echo "🗑️ Desinstalando yt-dlp antiguo en tubescript_api..."
docker exec tubescript_api pip uninstall -y yt-dlp 2>/dev/null
docker exec tubescript_api pip uninstall -y yt_dlp 2>/dev/null
echo ""
# Limpiar cache de pip
echo "🧹 Limpiando cache de pip..."
docker exec streamlit_panel pip cache purge 2>/dev/null
docker exec tubescript_api pip cache purge 2>/dev/null
echo ""
# Reinstalar yt-dlp desde cero
echo "📦 Reinstalando yt-dlp en streamlit_panel..."
docker exec streamlit_panel pip install --no-cache-dir --force-reinstall yt-dlp
if [ $? -eq 0 ]; then
print_success "yt-dlp reinstalado en streamlit_panel"
# Verificar versión
version=$(docker exec streamlit_panel python3 -c "import yt_dlp; print(yt_dlp.version.__version__)" 2>/dev/null)
if [ ! -z "$version" ]; then
print_info "Versión instalada: $version"
fi
else
print_error "Error al reinstalar yt-dlp en streamlit_panel"
fi
echo ""
echo "📦 Reinstalando yt-dlp en tubescript_api..."
docker exec tubescript_api pip install --no-cache-dir --force-reinstall yt-dlp
if [ $? -eq 0 ]; then
print_success "yt-dlp reinstalado en tubescript_api"
# Verificar versión
version=$(docker exec tubescript_api python3 -c "import yt_dlp; print(yt_dlp.version.__version__)" 2>/dev/null)
if [ ! -z "$version" ]; then
print_info "Versión instalada: $version"
fi
else
print_error "Error al reinstalar yt-dlp en tubescript_api"
fi
echo ""
# Verificar instalación
echo "🔍 Verificando instalación..."
echo ""
echo "Streamlit Panel:"
docker exec streamlit_panel yt-dlp --version 2>&1 | head -1
echo ""
echo "Tubescript API:"
docker exec tubescript_api yt-dlp --version 2>&1 | head -1
echo ""
# Reiniciar contenedores
echo "🔄 Reiniciando contenedores para aplicar cambios..."
docker-compose restart streamlit-panel tubescript-api
echo ""
echo "═══════════════════════════════════════════════════════════"
print_success "Reinstalación completada"
echo "═══════════════════════════════════════════════════════════"
echo ""
print_info "Ahora puedes probar con un video en vivo en:"
echo " http://localhost:8501"
echo ""
print_info "Si el error persiste, ejecuta:"
echo " docker-compose down"
echo " docker-compose build --no-cache"
echo " docker-compose up -d"
echo ""

View File

@ -1,92 +0,0 @@
#!/bin/bash
# Script para obtener transcripts de YouTube usando cookies desde Chrome/Firefox directamente
# Uso: ./get_transcript_chrome.sh VIDEO_ID [LANG] [BROWSER] [PROFILE]
VIDEO_ID="${1}"
LANG="${2:-es}"
BROWSER="${3:-chrome}"
PROFILE="${4:-}"
if [ -z "$VIDEO_ID" ]; then
echo "❌ Error: Debes proporcionar un VIDEO_ID"
echo ""
echo "Uso: $0 VIDEO_ID [LANG] [BROWSER] [PROFILE]"
echo ""
echo "Ejemplos:"
echo " $0 K08TM4OVLyo"
echo " $0 K08TM4OVLyo es chrome"
echo " $0 K08TM4OVLyo es chrome:Profile1"
echo " $0 K08TM4OVLyo es firefox"
echo " $0 K08TM4OVLyo es brave"
echo ""
echo "Perfiles disponibles de Chrome (macOS):"
ls -1 ~/Library/Application\ Support/Google/Chrome/ 2>/dev/null | grep -E "^(Default|Profile)" || echo " (no se encontraron)"
exit 1
fi
# Construir el argumento de browser
if [ -n "$PROFILE" ]; then
BROWSER_ARG="${BROWSER}:${PROFILE}"
else
BROWSER_ARG="${BROWSER}"
fi
echo "🔍 Obteniendo transcript de YouTube"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " 📹 Video ID: $VIDEO_ID"
echo " 🌐 Idioma: $LANG"
echo " 🔑 Navegador: $BROWSER_ARG"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# Ejecutar yt-dlp
yt-dlp --cookies-from-browser "$BROWSER_ARG" \
--skip-download --write-auto-sub --write-sub \
--sub-lang "$LANG" --sub-format vtt \
-o "%(id)s.%(ext)s" \
"https://www.youtube.com/watch?v=$VIDEO_ID"
EXIT_CODE=$?
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# Buscar archivos VTT generados
VTT_FILES=$(ls ${VIDEO_ID}*.vtt 2>/dev/null)
if [ -n "$VTT_FILES" ]; then
echo "✅ Éxito: Archivos VTT generados"
echo ""
for file in $VTT_FILES; do
LINES=$(wc -l < "$file")
SIZE=$(du -h "$file" | cut -f1)
echo " 📄 $file ($LINES líneas, $SIZE)"
done
# Mostrar preview del primer archivo
FIRST_VTT=$(echo "$VTT_FILES" | head -n 1)
echo ""
echo "📝 Preview de $FIRST_VTT:"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
head -n 30 "$FIRST_VTT"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# Crear archivo de texto plano
TXT_FILE="${VIDEO_ID}_transcript.txt"
grep -v "WEBVTT" "$FIRST_VTT" | grep -v "^$" | grep -v "^[0-9][0-9]:" | grep -v "^Kind:" | grep -v "^Language:" > "$TXT_FILE"
echo ""
echo "💾 Texto guardado en: $TXT_FILE"
exit 0
else
echo "❌ Error: No se generaron archivos VTT"
echo ""
echo "💡 Posibles soluciones:"
echo " 1. Verifica que estés logueado en YouTube en $BROWSER"
echo " 2. Prueba con otro navegador: chrome, firefox, brave"
echo " 3. Si usas múltiples perfiles, especifica el perfil:"
echo " $0 $VIDEO_ID $LANG chrome Profile1"
echo " 4. Cierra el navegador antes de ejecutar este script"
echo ""
exit 1
fi

1100
main.py

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,7 @@
fastapi
uvicorn[standard]
uvicorn
# No necesitamos la otra librería, yt-dlp hará todo el trabajo pesado
requests
yt-dlp
python-multipart
pydantic
youtube-transcript-api
# Nota: streamlit y paquetes relacionados fueron removidos porque el frontend fue eliminado
streamlit
streamlit-autorefresh

File diff suppressed because it is too large Load Diff

View File

@ -1,122 +0,0 @@
#!/bin/bash
# ================================================================
# Script de Prueba y Reconstrucción para TubeScript API
# ================================================================
set -e
echo "🔧 TubeScript API - Prueba y Reconstrucción"
echo "=============================================="
echo ""
# Colores
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 1. Detener todo
echo "🛑 Paso 1: Deteniendo servicios actuales..."
docker-compose down 2>/dev/null || docker stop $(docker ps -aq) 2>/dev/null || true
docker rm $(docker ps -aq) 2>/dev/null || true
echo -e "${GREEN}✅ Servicios detenidos${NC}"
echo ""
# 2. Limpiar imágenes viejas
echo "🧹 Paso 2: Limpiando imágenes antiguas..."
docker rmi tubescript-api 2>/dev/null || true
echo -e "${GREEN}✅ Limpieza completada${NC}"
echo ""
# 3. Reconstruir
echo "🏗️ Paso 3: Reconstruyendo imagen..."
echo " (Esto puede tomar 3-5 minutos)"
docker-compose build --no-cache tubescript-api
if [ $? -eq 0 ]; then
echo -e "${GREEN}✅ Build completado exitosamente${NC}"
else
echo -e "${RED}❌ Error en el build${NC}"
exit 1
fi
echo ""
# 4. Iniciar servicio
echo "🚀 Paso 4: Iniciando servicio..."
docker-compose up -d tubescript-api
if [ $? -eq 0 ]; then
echo -e "${GREEN}✅ Servicio iniciado${NC}"
else
echo -e "${RED}❌ Error al iniciar${NC}"
exit 1
fi
echo ""
# 5. Esperar inicialización
echo "⏳ Paso 5: Esperando inicialización (15 segundos)..."
for i in {15..1}; do
echo -n "$i... "
sleep 1
done
echo ""
echo ""
# 6. Verificar que está corriendo
echo "🔍 Paso 6: Verificando estado..."
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep tubescript_api
if [ $? -eq 0 ]; then
echo -e "${GREEN}✅ Contenedor corriendo${NC}"
else
echo -e "${RED}❌ Contenedor NO está corriendo${NC}"
echo "Ver logs:"
docker logs tubescript_api 2>&1 | tail -50
exit 1
fi
echo ""
# 7. Probar endpoint de health
echo "🏥 Paso 7: Probando endpoint de health..."
curl -s http://localhost:8080/docs > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo -e "${GREEN}✅ API respondiendo${NC}"
else
echo -e "${YELLOW}⚠️ API aún no responde (puede necesitar más tiempo)${NC}"
fi
echo ""
# 8. Probar el endpoint problemático
echo "🧪 Paso 8: Probando endpoint de transcripción..."
echo " Video ID: 6hini9Xz_fc"
echo ""
RESPONSE=$(curl -s -w "\n%{http_code}" "http://localhost:8080/transcript/6hini9Xz_fc?lang=es" 2>&1)
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | head -n-1)
if [ "$HTTP_CODE" = "200" ]; then
echo -e "${GREEN}✅ ¡ÉXITO! El endpoint funciona correctamente${NC}"
echo ""
echo "Respuesta:"
echo "$BODY" | python3 -m json.tool 2>/dev/null || echo "$BODY"
elif [ "$HTTP_CODE" = "400" ]; then
echo -e "${RED}❌ Error 400 - El problema persiste${NC}"
echo ""
echo "Respuesta de error:"
echo "$BODY" | python3 -m json.tool 2>/dev/null || echo "$BODY"
echo ""
echo "📋 Ver logs del contenedor:"
echo " docker logs tubescript_api"
else
echo -e "${YELLOW}⚠️ HTTP $HTTP_CODE - Respuesta inesperada${NC}"
echo ""
echo "$BODY"
fi
echo ""
echo "=============================================="
echo "🔍 Comandos útiles:"
echo " Ver logs: docker logs -f tubescript_api"
echo " Entrar: docker exec -it tubescript_api bash"
echo " Detener: docker-compose down"
echo " Reiniciar: docker-compose restart tubescript-api"
echo "=============================================="

View File

@ -1,169 +0,0 @@
#!/usr/bin/env python3
"""
Script de prueba rápida para verificar la función de transcripción
sin necesidad de Docker
"""
import sys
import os
import json
import subprocess
import requests
def test_transcript(video_id, lang='es'):
"""Probar la función de transcripción"""
url = f"https://www.youtube.com/watch?v={video_id}"
# Comando simplificado
command = [
"yt-dlp",
"--skip-download",
"--dump-json",
"--no-warnings",
"--extractor-args", "youtube:player_client=android",
url
]
print(f"🔍 Probando video: {video_id}")
print(f"📝 Comando: {' '.join(command)}")
print()
try:
result = subprocess.run(command, capture_output=True, text=True, timeout=60)
if result.returncode != 0:
print(f"❌ Error: {result.stderr[:500]}")
return False
if not result.stdout.strip():
print("❌ No se obtuvieron datos")
return False
metadata = json.loads(result.stdout)
# Buscar subtítulos
print("🔍 Buscando subtítulos...")
print()
# Verificar requested_subtitles
requested_subs = metadata.get('requested_subtitles', {})
if requested_subs:
print(f"✅ Encontrado en requested_subtitles:")
for key, val in requested_subs.items():
print(f" - {key}: {val.get('ext', 'unknown')}")
else:
print("⚪ No hay requested_subtitles")
# Verificar automatic_captions
auto_captions = metadata.get('automatic_captions', {})
if auto_captions:
print(f"\n✅ Automatic captions disponibles:")
for lang_key, formats in auto_captions.items():
if lang in lang_key or lang_key.startswith(lang):
print(f" - {lang_key}:")
for fmt in formats[:3]: # Primeros 3 formatos
print(f"{fmt.get('ext', 'unknown')}: {fmt.get('url', 'N/A')[:80]}...")
else:
print("\n⚪ No hay automatic_captions")
# Verificar subtitles
subtitles = metadata.get('subtitles', {})
if subtitles:
print(f"\n✅ Subtitles manuales disponibles:")
for lang_key, formats in subtitles.items():
if lang in lang_key or lang_key.startswith(lang):
print(f" - {lang_key}:")
for fmt in formats[:3]:
print(f"{fmt.get('ext', 'unknown')}: {fmt.get('url', 'N/A')[:80]}...")
else:
print("\n⚪ No hay subtitles manuales")
# Probar obtener URL
print("\n" + "="*60)
print("🎯 Intentando obtener URL de subtítulos...")
found_subs = requested_subs
if not found_subs and auto_captions:
for lang_key in auto_captions.keys():
if lang in lang_key or lang_key.startswith(lang):
if auto_captions[lang_key]:
found_subs = {lang_key: auto_captions[lang_key][0]}
print(f"✅ Usando automatic_captions[{lang_key}]")
break
if not found_subs and subtitles:
for lang_key in subtitles.keys():
if lang in lang_key or lang_key.startswith(lang):
if subtitles[lang_key]:
found_subs = {lang_key: subtitles[lang_key][0]}
print(f"✅ Usando subtitles[{lang_key}]")
break
if not found_subs:
print("❌ No se encontraron subtítulos para el idioma especificado")
print(f"\n💡 Idiomas disponibles:")
all_langs = set(list(auto_captions.keys()) + list(subtitles.keys()))
for l in sorted(all_langs):
print(f" - {l}")
return False
# Intentar descargar
lang_key = next(iter(found_subs))
sub_url = found_subs[lang_key].get('url')
sub_ext = found_subs[lang_key].get('ext', 'unknown')
if not sub_url:
print("❌ No se pudo obtener URL de subtítulos")
return False
print(f"✅ URL encontrada: {sub_url[:100]}...")
print(f"📝 Formato: {sub_ext}")
# Intentar descargar
print("\n⬇️ Descargando subtítulos...")
response = requests.get(sub_url, timeout=30)
if response.status_code == 200:
print(f"✅ Descarga exitosa ({len(response.content)} bytes)")
# Mostrar muestra del contenido
sample = response.text[:500] if hasattr(response, 'text') else str(response.content[:500])
print(f"\n📄 Muestra del contenido:")
print("" * 60)
print(sample)
print("" * 60)
return True
else:
print(f"❌ Error HTTP {response.status_code}")
return False
except subprocess.TimeoutExpired:
print("❌ Timeout al ejecutar yt-dlp")
return False
except Exception as e:
print(f"❌ Error: {str(e)}")
import traceback
traceback.print_exc()
return False
if __name__ == "__main__":
video_id = sys.argv[1] if len(sys.argv) > 1 else "6hini9Xz_fc"
lang = sys.argv[2] if len(sys.argv) > 2 else "es"
print("="*60)
print("🧪 TubeScript - Test de Transcripción")
print("="*60)
print()
success = test_transcript(video_id, lang)
print()
print("="*60)
if success:
print("✅ TEST EXITOSO")
else:
print("❌ TEST FALLIDO")
print("="*60)
sys.exit(0 if success else 1)

View File

@ -1,232 +0,0 @@
"""Utility wrapper for yt-dlp calls with robust cookie handling via cookiejar.
Provides:
- CookieManager: reads cookie string from RedisArchivist and writes a Netscape cookie file
that can be passed to yt-dlp via the --cookiefile option (path).
- YtDlpClient: base class to perform download/extract calls to yt-dlp with consistent
error handling and optional automatic cookie injection.
Usage example:
from yt_wrap import YtDlpClient
client = YtDlpClient(config=config_dict)
info, err = client.extract_info('https://www.youtube.com/watch?v=K08TM4OVLyo')
"""
from __future__ import annotations
import logging
import os
import tempfile
import typing as t
from http import cookiejar
import yt_dlp
# Import project-specific RedisArchivist if available; otherwise provide a local stub
try:
from common.src.ta_redis import RedisArchivist
except Exception:
class RedisArchivist:
"""Fallback stub for environments without the project's RedisArchivist.
Methods mimic the interface used by CookieManager: get_message_str, set_message,
del_message, get_message_dict. These stubs are no-ops and return None/False.
"""
def __init__(self, *args, **kwargs):
pass
def get_message_str(self, key: str):
return None
def set_message(self, key: str, value, expire: int = None, save: bool = False):
return False
def del_message(self, key: str):
return False
def get_message_dict(self, key: str):
return None
logger = logging.getLogger(__name__)
logger.addHandler(logging.NullHandler())
class CookieManager:
"""Manage cookie string storage and provide a cookiefile path for yt-dlp.
This writes the Netscape cookie string to a temporary file (Netscape format)
which is compatible with `yt-dlp`'s `--cookiefile` option and with
`http.cookiejar.MozillaCookieJar`.
"""
DEFAULT_MESSAGE_KEY = "cookie"
def __init__(self, redis_archivist: t.Optional[object] = None):
# Accept a RedisArchivist-like object for testability; otherwise try to create one
if redis_archivist is not None:
self.redis = redis_archivist
else:
if RedisArchivist is None:
self.redis = None
else:
try:
self.redis = RedisArchivist()
except Exception:
self.redis = None
self._temp_files: list[str] = []
def get_cookiefile_path(self, message_key: str | None = None) -> t.Optional[str]:
"""Return a filesystem path to a Netscape cookie file written from the stored cookie string.
If no cookie is available, returns None.
"""
key = message_key or self.DEFAULT_MESSAGE_KEY
cookie_str = None
if self.redis is not None and hasattr(self.redis, "get_message_str"):
try:
cookie_str = self.redis.get_message_str(key)
except Exception as exc:
logger.debug("CookieManager: error reading from redis: %s", exc)
cookie_str = None
if not cookie_str:
# No cookie stored
return None
# Ensure cookie string ends with newline
cookie_str = cookie_str.strip("\x00")
if not cookie_str.endswith("\n"):
cookie_str = cookie_str + "\n"
# Write to a temp file in the system temp dir
tf = tempfile.NamedTemporaryFile(mode="w", delete=False, prefix="yt_cookies_", suffix=".txt")
tf.write(cookie_str)
tf.flush()
tf.close()
self._temp_files.append(tf.name)
# Validate it's a Netscape cookie file by attempting to load with MozillaCookieJar
try:
jar = cookiejar.MozillaCookieJar()
jar.load(tf.name, ignore_discard=True, ignore_expires=True)
except Exception:
# It's okay if load fails; yt-dlp expects the netscape format; keep the file anyway
logger.debug("CookieManager: written cookie file but couldn't load with MozillaCookieJar")
return tf.name
def cleanup(self) -> None:
"""Remove temporary cookie files created by get_cookiefile_path."""
for p in getattr(self, "_temp_files", []):
try:
os.unlink(p)
except Exception:
logger.debug("CookieManager: failed to unlink temp cookie file %s", p)
self._temp_files = []
class YtDlpClient:
"""Base client to interact with yt-dlp.
- `base_opts` are merged with per-call options.
- If `use_redis_cookies` is True, the client will try to fetch a cookiefile
path from Redis via `CookieManager` and inject `cookiefile` into options.
Methods return tuples like (result, error) where result is data or True/False and
error is a string or None.
"""
DEFAULT_OPTS: dict = {
"quiet": True,
"socket_timeout": 10,
"extractor_retries": 2,
"retries": 3,
}
def __init__(self, base_opts: dict | None = None, use_redis_cookies: bool = True, redis_archivist: t.Optional[object] = None):
self.base_opts = dict(self.DEFAULT_OPTS)
if base_opts:
self.base_opts.update(base_opts)
self.use_redis_cookies = use_redis_cookies
self.cookie_mgr = CookieManager(redis_archivist)
def _build_opts(self, extra: dict | None = None) -> dict:
opts = dict(self.base_opts)
if extra:
opts.update(extra)
# If cookie management is enabled, attempt to attach a cookiefile path
if self.use_redis_cookies:
cookiefile = self.cookie_mgr.get_cookiefile_path()
if cookiefile:
opts["cookiefile"] = cookiefile
return opts
def extract_info(self, url: str, extra_opts: dict | None = None) -> tuple[dict | None, str | None]:
"""Extract info for a url using yt-dlp.extract_info.
Returns (info_dict, error_str). If successful, error_str is None.
"""
opts = self._build_opts(extra_opts)
try:
with yt_dlp.YoutubeDL(opts) as ydl:
info = ydl.extract_info(url, download=False)
except cookiejar.LoadError as exc:
logger.error("Cookie load error: %s", exc)
return None, f"cookie_load_error: {exc}"
except yt_dlp.utils.ExtractorError as exc:
logger.warning("ExtractorError for %s: %s", url, exc)
return None, str(exc)
except yt_dlp.utils.DownloadError as exc:
msg = str(exc)
logger.warning("DownloadError for %s: %s", url, msg)
if "Temporary failure in name resolution" in msg:
raise ConnectionError("lost the internet, abort!") from exc
# Detect rate limiting
if "HTTP Error 429" in msg or "too many requests" in msg.lower():
return None, "HTTP 429: rate limited"
return None, msg
except Exception as exc: # pragma: no cover - defensive
logger.exception("Unexpected error in extract_info: %s", exc)
return None, str(exc)
finally:
# Clean up temp cookie files after the call
try:
self.cookie_mgr.cleanup()
except Exception:
pass
return info, None
def download(self, url: str, extra_opts: dict | None = None) -> tuple[bool, str | None]:
"""Invoke ydl.download for the provided url. Returns (success, error_message).
"""
opts = self._build_opts(extra_opts)
try:
with yt_dlp.YoutubeDL(opts) as ydl:
ydl.download([url])
except yt_dlp.utils.DownloadError as exc:
msg = str(exc)
logger.warning("DownloadError while downloading %s: %s", url, msg)
if "Temporary failure in name resolution" in msg:
raise ConnectionError("lost the internet, abort!") from exc
if "HTTP Error 429" in msg or "too many requests" in msg.lower():
return False, "HTTP 429: rate limited"
return False, msg
except Exception as exc:
logger.exception("Unexpected error during download: %s", exc)
return False, str(exc)
finally:
try:
self.cookie_mgr.cleanup()
except Exception:
pass
return True, None
# If running as a script, show a tiny demo (no network calls are performed here)
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
client = YtDlpClient()
print(client._build_opts())