TubeScript-API/SOLUCION_HTTP_429_TRANSCRIPT.md

8.5 KiB

🎯 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:

# 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

# 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:

# 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:
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

# 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)

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

# 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)

curl "http://127.0.0.1:8000/transcript/K08TM4OVLyo?lang=es" | jq .

Respuesta:

{
  "video_id": "K08TM4OVLyo",
  "count": 150,
  "segments": [...],
  "text": "texto concatenado de todos los segmentos"
}

2. Obtener VTT Crudo + Parseado

curl "http://127.0.0.1:8000/transcript_vtt/K08TM4OVLyo?lang=es" | jq .

Respuesta:

{
  "video_id": "K08TM4OVLyo",
  "vtt": "WEBVTT\n\n00:00:00.000 --> 00:00:02.000\nHola...",
  "count": 150,
  "segments": [...],
  "text": "..."
}

3. Debug: Ver Metadata

curl "http://127.0.0.1:8000/debug/metadata/K08TM4OVLyo" | jq .

4. Debug: Intentar Descarga Verbose

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

curl -X POST "http://127.0.0.1:8000/upload_vtt/K08TM4OVLyo" \
  -F "file=@K08TM4OVLyo.vtt" | jq .

🐳 Docker

Comandos útiles

# 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

environment:
  - API_COOKIES_PATH=/app/cookies.txt
  - API_PROXY=socks5h://127.0.0.1:9050  # opcional

🔍 Diagnóstico

Verificar HTTP 429

# 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

# 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

🎯 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