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