- Un botón más en la barra del vídeo. Junto a Me gusta y Compartir aparece un botón Subtítulos con el mismo aspecto que los de YouTube. Al pulsarlo, un menú lista las pistas del vídeo.
- Nativos y automáticos. Cada pista dice si la subió el autor o la generó YouTube, y se descarga en
.srt con el título del vídeo, el idioma y el tipo en el nombre. - Traducción automática. Las pistas traducibles se pueden descargar ya traducidas a cualquier idioma del catálogo de YouTube.
- Tus propios subtítulos sobre el vídeo. Cargas un
.srt o un .vtt, desde el menú del botón o desde el popup, y se ven encima del reproductor, también a pantalla completa. Si van desfasados, se ajustan en saltos de medio segundo. - Ajustes de accesibilidad. Tamaño, tipografía (incluida OpenDyslexic), color del texto y del fondo, contorno de alto contraste y posición vertical, que también se cambia arrastrando el subtítulo. Hay cuatro preajustes y una vista previa en directo, y la configuración se guarda entre sesiones.
- Sin tocar lo que estás viendo. Si tenías los subtítulos apagados o en otro idioma, después de la descarga el reproductor vuelve a quedarse como estaba.
- En ocho idiomas, con tema claro u oscuro: español, inglés, francés, alemán, portugués, italiano, japonés y chino.
- Sin servidor. Todo pasa en la pestaña de YouTube y en tu navegador.
Todavía no está en la Chrome Web Store. Puede que la publique más adelante, y el cambio de nombre va en esa dirección: la Store no admite extensiones cuyo nombre empiece por "YouTube", y la fórmula aceptada es la de SubFetch for YouTube™. Lo que más pesa en contra es el mantenimiento, porque la descarga depende de APIs internas del reproductor sin documentar que ya se rompieron una vez sin avisar. Por ahora la uso yo. No tiene repositorio público.
El botón y el popup son Vue 3. El content script vive en el mundo aislado de la extensión, y un segundo script se inyecta en el mundo de la página (MAIN) para poder hablar con #movie_player y envolver fetch y XMLHttpRequest. Los dos se comunican con window.postMessage, mensajes tipados y un requestId por petición.
Para descargar una pista, el script de MAIN la activa con setOption('captions', 'track', …), espera la petición a /api/timedtext que hace el reproductor (con su token), se queda con la respuesta y deja los subtítulos como estaban.
YouTube cambia de vídeo sin recargar la página. Detectarlo bien obliga a combinar sus eventos internos, popstate, un parche de history.pushState en MAIN, un MutationObserver y un sondeo de respaldo, además de cachear la respuesta del reproductor por vídeo.
Los subtítulos propios se pintan en un segundo Shadow DOM montado dentro de #movie_player, que es el elemento que entra en pantalla completa. Un parser propio convierte el .srt o el .vtt en cues en milisegundos, y el overlay actualiza el tiempo en cada fotograma del vídeo con requestVideoFrameCallback. Los ajustes viven en el almacenamiento de la extensión, y lo que cambias en el popup llega al instante al vídeo.
- Respuestas
200 OK vacías. El endpoint de subtítulos dejó de servir contenido a la baseUrl del vídeo. La causa era el PoToken, y la solución, dejar que lo genere el reproductor. - Los datos del primer vídeo.
ytInitialPlayerResponse no cambia al navegar dentro de YouTube. Ahora se intercepta /youtubei/v1/player y la caché se vacía al empezar cada navegación. - Un botón que desaparecía. YouTube recicla la barra de acciones sin cambiar de vídeo. El montaje comprueba en qué contenedor vive el botón, no solo si existe.
- Ficheros
.txt. Chrome cambiaba la extensión de las descargas. Ahora se descargan como application/x-subrip y con un enlace <a download>. - Subtítulos que se saltaban líneas. Los
.srt que salen de los subtítulos automáticos de YouTube tienen cues que se solapan, y la búsqueda binaria solo encontraba uno. Ahora se muestran todos los que están activos a la vez. - Subtítulos a saltos. El evento
timeupdate del vídeo llega pocas veces por segundo y el texto cambiaba con retraso. El tiempo se lee ahora en cada fotograma.