292 lines
8.5 KiB
Markdown
292 lines
8.5 KiB
Markdown
# 🎯 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
|