Transcripción de YouTube
Descarga transcripciones (subtítulos/leyendas) de videos de YouTube. Funciona tanto con transcripciones creadas manualmente como con las generadas automáticamente. No requiere clave de API ni navegador — utiliza la API InnerTube de YouTube directamente y recurre automáticamente a yt-dlp cuando YouTube bloquea la ruta directa de la API.
Obtiene metadatos del video e imagen de portada en la primera ejecución, almacena en caché los datos sin procesar para un reformateo rápido.
Directorio de scripts
Scripts en el subdirectorio scripts/. {baseDir} = ruta del directorio de este SKILL.md. Resolver el entorno de ejecución ${BUN_X}: si bun está instalado → bun; si npx está disponible → npx -y bun; de lo contrario, sugerir instalar bun. Reemplazar {baseDir} y ${BUN_X} con los valores reales.
| Script | Propósito |
|---|---|
scripts/main.ts | CLI de descarga de transcripciones |
Uso
# Predeterminado: markdown con marcas de tiempo (inglés)
${BUN_X} {baseDir}/scripts/main.ts <url-o-id-de-youtube>
# Especificar idiomas (orden de prioridad)
${BUN_X} {baseDir}/scripts/main.ts <url> --languages zh,en,ja
# Sin marcas de tiempo
${BUN_X} {baseDir}/scripts/main.ts <url> --no-timestamps
# Con segmentación por capítulos
${BUN_X} {baseDir}/scripts/main.ts <url> --chapters
# Con identificación de hablantes (requiere post-procesamiento con IA)
${BUN_X} {baseDir}/scripts/main.ts <url> --speakers
# Archivo de subtítulos SRT
${BUN_X} {baseDir}/scripts/main.ts <url> --format srt
# Traducir transcripción
${BUN_X} {baseDir}/scripts/main.ts <url> --translate zh-Hans
# Listar transcripciones disponibles
${BUN_X} {baseDir}/scripts/main.ts <url> --list
# Forzar re-obtención (ignorar caché)
${BUN_X} {baseDir}/scripts/main.ts <url> --refresh
Opciones
| Opción | Descripción | Predeterminado |
|---|---|---|
<url-o-id> | URL de YouTube o ID del video (se permiten varios) | Requerido |
--languages <códigos> | Códigos de idioma, separados por comas, en orden de prioridad | en |
--format <fmt> | Formato de salida: text, srt | text |
--translate <código> | Traducir al código de idioma especificado | |
--list | Listar transcripciones disponibles en lugar de obtener | |
--timestamps | Incluir marcas de tiempo [HH:MM:SS → HH:MM:SS] por párrafo | activado |
--no-timestamps | Desactivar marcas de tiempo | |
--chapters | Segmentación por capítulos a partir de la descripción del video | |
--speakers | Transcripción cruda con metadatos para identificación de hablantes | |
--exclude-generated | Omitir transcripciones generadas automáticamente | |
--exclude-manually-created | Omitir transcripciones creadas manualmente | |
--refresh | Forzar re-obtención, ignorar datos en caché | |
-o, --output <ruta> | Guardar en una ruta de archivo específica | auto-generado |
--output-dir <directorio> | Directorio base de salida | youtube-transcript |
Variables de entorno opcionales
| Variable | Descripción |
|---|---|
YOUTUBE_TRANSCRIPT_COOKIES_FROM_BROWSER | Se pasa a yt-dlp --cookies-from-browser durante el fallback, p. ej. chrome, safari, firefox, o chrome:Profile 1 |
Formatos de entrada
Acepta cualquiera de estos como entrada de video:
- URL completa:
https://www.youtube.com/watch?v=dQw4w9WgXcQ - URL corta:
https://youtu.be/dQw4w9WgXcQ - URL incrustada:
https://www.youtube.com/embed/dQw4w9WgXcQ - URL de Shorts:
https://www.youtube.com/shorts/dQw4w9WgXcQ - ID del video:
dQw4w9WgXcQ
Formatos de salida
| Formato | Extensión | Descripción |
|---|---|---|
text | .md | Markdown con frontmatter (incl. description), título, resumen, opcional TOC/portada/marcas de tiempo/capítulos/hablantes |
srt | .srt | Formato de subtítulos SubRip para reproductores de video |
Directorio de salida
youtube-transcript/
├── .index.json # Mapeo de ID de video → ruta del directorio (para búsqueda en caché)
└── {nombre-del-canal}/{titulo-completo-en-slug}/
├── meta.json # Metadatos del video (título, canal, descripción, duración, capítulos, etc.)
├── transcript-raw.json # Fragmentos de transcripción crudos de la API de YouTube (en caché)
├── transcript-sentences.json # Transcripción segmentada por oraciones (dividida por puntuación, fusionada entre fragmentos)
├── imgs/
│ └── cover.jpg # Miniatura del video
├── transcript.md # Transcripción en Markdown (generada a partir de oraciones)
└── transcript.srt # Subtítulo SRT (generado a partir de fragmentos crudos, si se usa --format srt)
{nombre-del-canal}: Nombre del canal en kebab-case{titulo-completo-en-slug}: Título completo del video en kebab-case
El modo --list solo imprime en stdout (no guarda archivo).
Caché
En la primera obtención, el script guarda:
meta.json— metadatos del video, capítulos, ruta de la imagen de portada, información del idiomatranscript-raw.json— fragmentos de transcripción crudos de la API de YouTube ({ text, start, duration }[])transcript-sentences.json— transcripción segmentada por oraciones ({ text, start: "HH:mm:ss", end: "HH:mm:ss" }[]), dividida por puntuación de fin de oración (.?!…。?!etc.), marcas de tiempo asignadas proporcionalmente por longitud de caracteres, fusión de texto con reconocimiento CJKimgs/cover.jpg— miniatura del video
Ejecuciones posteriores para el mismo video utilizan datos en caché (sin llamadas de red). Usa --refresh para forzar la re-obtención. Si se solicita un idioma diferente, la caché se actualiza automáticamente.
Cuando YouTube devuelve respuestas anti-bot / bloqueadas en la ruta directa de InnerTube, el script reintenta con identidades de cliente alternativas y luego recurre a yt-dlp si está disponible. Si se necesita el fallback pero yt-dlp no está disponible, el agente debe decidir cómo hacer que yt-dlp esté disponible y continuar, en lugar de trasladar la decisión de instalación al usuario.
La salida SRT (--format srt) se genera a partir de transcript-raw.json. La salida de texto/markdown utiliza transcript-sentences.json para límites de oración naturales.
Flujo de trabajo
Cuando el usuario proporciona una URL de YouTube y quiere la transcripción:
- Ejecutar con
--listprimero si el usuario no ha especificado un idioma, para mostrar las opciones disponibles - Siempre poner la URL entre comillas simples al ejecutar el script — zsh trata
?como un comodín global, por lo que una URL de YouTube sin comillas causa "no se encontraron coincidencias": usar'https://www.youtube.com/watch?v=ID' - Predeterminado: ejecutar con
--chapters --speakerspara la salida más rica (capítulos + identificación de hablantes) - El script guarda automáticamente los datos en caché + el archivo de salida e imprime la ruta del archivo
- Para el modo
--speakers: después de que el script guarda el archivo crudo, seguir el flujo de trabajo de identificación de hablantes a continuación para post-procesar con etiquetas de hablantes
Cuando el usuario solo quiere una imagen de portada o metadatos, ejecutar el script con cualquier opción también almacenará en caché meta.json y imgs/cover.jpg.
Al reformatear el mismo video (por ejemplo, primero texto y luego SRT), los datos en caché se reutilizan — no es necesario re-obtener.
Flujo de trabajo de capítulos e identificación de hablantes
Capítulos (--chapters)
El script analiza las marcas de tiempo de los capítulos de la descripción del video (por ejemplo, 0:00 Introducción), segmenta la transcripción por los límites de los capítulos, agrupa fragmentos en párrafos legibles y guarda como .md con una Tabla de Contenidos. No se requiere procesamiento adicional.
Si no existen marcas de tiempo de capítulos en la descripción, la transcripción se emite como párrafos agrupados sin encabezados de capítulo.
Identificación de hablantes (--speakers)
La identificación de hablantes requiere procesamiento de IA. El script genera un archivo .md crudo que contiene:
- Frontmatter YAML con metadatos del video (título, canal, fecha, portada, descripción, idioma)
- Descripción del video (para extracción de nombres de hablantes)
- Lista de capítulos de la descripción (si está disponible)
- Transcripción cruda en formato SRT (marcas de tiempo de inicio/fin precalculadas, eficiente en tokens)
Después de que el script guarda el archivo crudo, generar un sub-agente (usar un modelo más barato como Sonnet para eficiencia de costos) para procesar la identificación de hablantes:
- Leer el archivo
.mdguardado - Leer la plantilla de prompt en
{baseDir}/prompts/speaker-transcript.md - Procesar la transcripción cruda siguiendo el prompt:
- Identificar hablantes usando metadatos del video (título → invitado, canal → anfitrión, descripción → nombres)
- Detectar turnos de hablantes a partir del flujo de la conversación, patrones de pregunta-respuesta y pistas contextuales
- Segmentar en capítulos (usar capítulos de la descripción si están disponibles, de lo contrario crear a partir de cambios de tema)
- Formatear con etiquetas
**Nombre del hablante:**, agrupación de párrafos (2-4 oraciones) y marcas de tiempo[HH:MM:SS → HH:MM:SS]
- Sobrescribir el archivo
.mdcon la transcripción procesada (mantener el frontmatter YAML)
Cuando se usa --speakers, --chapters está implícito — la salida procesada siempre incluye segmentación por capítulos.
Casos de error
| Error | Significado |
|---|---|
| Transcripciones desactivadas | El video no tiene subtítulos en absoluto |
| No se encontró transcripción | El idioma solicitado no está disponible |
| Video no disponible | Video eliminado, privado o bloqueado por región |
| IP bloqueada | Demasiadas solicitudes, intente de nuevo más tarde |
| Restricción de edad | El video requiere iniciar sesión para verificación de edad |
| bot detectado | El script reintenta con clientes alternativos y luego yt-dlp; si faltan herramientas de fallback, el agente debe resolverlo por sí mismo; de lo contrario, si aún falla, intentar YOUTUBE_TRANSCRIPT_COOKIES_FROM_BROWSER=safari (o tu navegador) |


