Communitygithub.com

RolynTrotter/vibe-podcast

Extrae material fuente (charlas de YouTube, conferencias, episodios propios) para obtener citas verificables y convertirlas en clips con marca de tiempo y gráficos de cita (lower thirds) para el podcast. Úsalo cuando te pidan transcribir un video fuente, buscar lo que alguien dijo sobre X, extraer citas o clips para un episodio, o generar citas/gráficos a partir de una charla o conferencia.

¿Qué es vibe-podcast?

Esta skill automatiza el flujo de trabajo completo de curaduría de citas para podcasts: desde la descarga de videos fuente (YouTube, conferencias, episodios propios) hasta la transcripción, minería de citas y generación de clips y gráficos de cita (lower thirds) listos para editar en Final Cut Pro. Soporta transcripción por IA local (mlx-whisper large-v3-turbo) y correcciones manuales mediante un sistema de fixes que se reaplican automáticamente. Está pensada para editores de podcast, productores de contenido o agentes de IA que necesiten extraer rápidamente declaraciones textuales de fuentes audiovisuales y convertirlas en elementos editables. Funciona en macOS con Python estándar, ffmpeg, yol-dlp, y mlx-whisper. El flujo se divide en cuatro pasos: descarga de audio/video, transcripción, minería de citas (con juicio humano o de IA) y generación de cues y clips. Incluye herramientas como "citekit.py" para búsqueda de texto exacto en transcripciones, creación de archivos JSON de citas con metadatos (autor, título, fecha, publicación), y exportación a formatos compatibles con FCP (fcpxml) y scripts de descarga de clips. La habilidad enfatiza la precisión: las citas deben ser cortas (5–25 segundos), autocontenidas y verificables, y el sistema mantiene un registro de todas las correcciones para garantizar consistencia.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/RolynTrotter/vibe-podcast/tree/HEAD/.claude/skills/citations

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Citas: fuentes → transcripciones → citas → cues y clips

Herramienta: agent-citations/citekit.py (Python estándar más mlx_whisper y ffmpeg). Nunca sobrescribe entradas y se niega a reemplazar sus propias salidas sin --force.

Estructura de carpetas

Una carpeta por tema bajo active_edits/<tema>/:

sources/video_sources.txt          lista de URLs del usuario
sources/audio/<id>.m4a .info.json  de yt-dlp (paso 1)
sources/transcripts/<id>.json .md  paso 2
podcast/<ep>.json .md              subtítulos de nuestro propio episodio, importados (paso 2b)
sources/quotes.json                paso 3, escrito por ti
sources/citations/                 salidas del paso 4

1. Descarga (la ejecuta el usuario)

YouTube bloquea yt-dlp anónimo aquí. Dale al usuario este comando en lugar de ejecutarlo tú. Requiere cookies de Firefox y los clientes tv/safari, y mantiene el audio pequeño (Whisper solo necesita 16 kHz mono):

cd active_edits/<tema>/sources && for id in ID1 ID2; do yt-dlp --cookies-from-browser firefox --extractor-args "youtube:player_client=tv,web_safari,mweb" -f "wa/w" -x --audio-format m4a --postprocessor-args "ExtractAudio:-ac 1 -ar 16000" --write-info-json --write-auto-subs --sub-langs en --sub-format json3 --no-overwrites -o "audio/%(id)s.%(ext)s" "https://youtu.be/$id"; done

Para el historial de un canal, listalo primero, luego elige: yt-dlp --flat-playlist --print "%(id)s %(duration_string)s %(title)s" https://www.youtube.com/@CANAL/videos. Clasifica los títulos con Jev (vibe-classification) si la lista es larga.

2. Transcribir

  • citekit.py transcribe sources/audio/<id>.m4a: mlx-whisper large-v3-turbo, marcas de tiempo por palabra. El prompt inicial es el título y la descripción del video, lo que corrige la mayoría de las ortografías de nombres. Funciona aproximadamente 85× en tiempo real en este Mac (un tramo de 15 min tarda ~35 s; el modelo se descarga una vez).
  • citekit.py captions sources/audio/<id>.en.json3: subtítulos automáticos de YouTube. Instantáneo, pero sin puntuación. El cliente tv a menudo no los guarda.
  • 2b. Nuestros propios episodios: citekit.py itt EP.itt --id podcastN --media EP.mp4 --out active_edits/<tema>/podcast --fix 'REGEX=>Correcto'. Los subtítulos de FCP distorsionan los nombres. Para el episodio 1: --fix '\bver ?m+[iu]l+e?\b=>Vermeule' --fix '\bvermil\b=>Vermeule' --fix '\bAsian Vermeule=>Adrian Vermeule'. El episodio 1 también tiene correcciones a nivel de palabra registradas en podcast/podcast1.fixes.json (Schmidt→Schmitt, etc.), que se reaplican al reimportar.

Corrige las malas transcripciones sobre la marcha (no preguntes)

Cuando notes una clara mala interpretación (un nombre, una cita distorsionada, un tartamudeo que Whisper duplicó), corrígela: citekit.py fix TRANSCRIPT 'palabras viejas=>palabras nuevas' [...] [--near SEGUNDOS]. Edita <id>.json/.md in situ (las palabras nuevas comparten la temporización del segmento antiguo, las coincidencias pueden cruzar segmentos, la puntuación final se conserva), mantiene la salida sin modificar del motor como <id>.raw.json, y registra cada corrección en <id>.fixes.json. transcribe e itt reaplican ese registro, por lo que las correcciones sobreviven a una re-ejecución. ¿No estás seguro? Vuelve a escuchar el punto en lugar de adivinar: ffmpeg -ss T -to T2 -i audio.m4a x.wav && mlx_whisper x.wav --output-format txt. Corrige primero, luego cita las palabras corregidas: locate busca en la transcripción.

3. Extraer citas (a tu criterio)

  1. Lee la transcripción de nuestro episodio, si existe, y enumera las afirmaciones que hacen los presentadores sobre el tema, cada una con su tiempo en el episodio. Esos son los momentos que un clip puede respaldar o refutar.
  2. Para cada afirmación, citekit.py search 'regex' sources/transcripts/ para encontrar candidatos, luego lee el .md alrededor del resultado. Lee también las conferencias completas: las mejores líneas no siempre son las que mencionan los presentadores.
  3. Una buena cita es corta (5–25 s hablados), autocontenida, inequívocamente la posición del propio orador (no resumiendo a un oponente), y citable en un gráfico de cita (lower third). Mantén las palabras exactas de la transcripción. No las limpies, o locate no podrá encontrarlas.
  4. Escribe sources/quotes.json:
{"project": "Ep1 Citas de Vermeule", "fps": 29.97, "episode": "../podcast/podcast1.json",
 "quotes": [{"id": "publius-ejecutivo-debil", "source": "Bw9M01S8MFI", "approx": 1234,
   "text": "palabras exactas de la transcripción",
   "episode_at": 2575, "episode_context": "presentadores sobre Hamilton y el dictador romano",
   "why": "su propia declaración de la tesis", "tags": ["ejecutivo", "Federalista"],
   "citation": {"author": "~Adrian Vermeule", "title": "La Paradoja de Publio", "date": "5 jun 2018",
                "publication": "Charla Chorley, LSE"}}]}

episode (relativo a quotes.json) es la transcripción de nuestro episodio. Con él, el episode_at de cada cita (aproximadamente cuando los presentadores plantean el punto) se convierte en un punto de inserción: el final de la oración del presentador que se está reproduciendo en ese momento. Cita pensamientos completos. Si la siguiente oración completa la imagen o el argumento, inclúyela (un clip de 5–25 s es el objetivo, no un límite estricto).

citation por defecto usa el título del video, la fecha de subida y el canal. Pon el lugar y la fecha reales (de la descripción) una vez por conferencia en un "sources": {"<id>": {"citation": {...}}} de nivel superior. La citation propia de una cita lo anula. Los autores reciben el prefijo ~ del programa, y \n divide un título largo en dos líneas.

Verifica cualquier cosa que esté citando (Hamilton, Kafka, el Digesto) contra el texto original. Whisper escucha palabras incorrectas plausibles: en la conferencia de Publio, dio los "cántaros de sacrificio" de Kafka como "cuadros".

4. Cues y clips

citekit.py cues sources/quotes.json ajusta cada cita a las marcas de tiempo de las palabras (difuso; advierte si la puntuación de coincidencia es < 0.8) y escribe en sources/citations/:

ArchivoPara
citations.mdhoja de revisión en orden de episodio: tiempo de inserción (tal cual y después de inserciones anteriores), las palabras del presentador justo antes del corte, la cita, tiempos de fuente/clip, enlace de YouTube ?t=
clips.jsonedición por agente: entrada/salida de fuente, entrada/salida con relleno (por defecto 5 s por cada lado, --pad-before/--pad-after, pad_before/pad_after por cita), insert_at, insert_at_after_earlier_inserts, insert_after
citation_cues.jsonagent-motion/titles_fcpxml.py: gráficos de cita (lower thirds) de la Versión 2 temporizados para el episodio con los clips insertados, que aparecen cuando empieza a hablar. Las citas no colocadas se colocan una tras otra
download_clips.shlo ejecuta el usuario: video de calidad completa solo para esos rangos con relleno (--download-sections)

Luego citekit.py audio-clips sources/citations/clips.json corta previsualizaciones de audio con relleno desde el audio local, para verificar al oído. Para colocar los gráficos de cita en FCP, sigue la skill de motion-graphics: python3 agent-motion/titles_fcpxml.py sources/citations/citation_cues.json -o citations.fcpxml.

Notas

  • transcribe decodifica a WAV de 16 kHz por sí mismo y rechaza audio que se decodifica mucho más corto que el video. Una descarga de yt-dlp reanudada con un -f diferente empalma dos códecs en un solo .m4a (visto 2026-10-18: AAC-LC luego HE-AAC), y ffmpeg suelta silenciosamente todo después del cambio. Vuelve a descargar con --no-continue. Nunca reanudes entre cambios de formato.

  • Verifica un clip al oído, o económicamente: mlx_whisper citations/audio_clips/<id>.m4a --output-format txt debería mostrar la cita con unos segundos de introducción y final.

  • Las marcas de tiempo de Whisper son precisas en aproximadamente ±0.3 s a nivel de palabra. Por eso existen los rellenos de clip. Los subtítulos iTT de FCP solo temporizan líneas completas, por lo que itt distribuye las palabras uniformemente en cada línea.

  • El conector Wispr Flow solo lee transcripciones del Meeting Recorder. No puede transcribir un archivo.

Skills relacionados