9.4. Tutoriales

Si nuestra intención es ilustrar algún aspecto de la CLI de Linux y preferimos crear material audivisual y no escrito una excelente opción es asciinema. La herramienta permite:

  1. Grabar las acciones que hagamos en una intefaz almacenándolas no un formato de vídeo convencional, sino en un formato .cast que no es más que un archivo JSON, qué describe qué hemos escrito o visto y en qué instante de tiempo.

  2. Reproducir en la máquina local el archivo, o bien, alojarlo en una web y reproducirlo en un navegador gracias a la librería Javascript asciinema-player.

  3. La reproducción, por su propia naturaleza, carece de sonido, pero haciendo uso de algunas estrategias, podemos añadirlo.

La ventaja de estos vídeos frente a los tradicionales que se hacen capturando la imagen de la pantalla, es que permiten copiar al portapapeles usando el ratón, lo cual facilita enormemente que un estudiante pueda reproducir las acciones que observa en el vídeo.

El programa tiene paquete en Debian, así que su instalación es sumamente sencilla:

# apt install asciinema

9.4.1. Creación

Para crear un vídeo basta con hacer:

$ asciinema rec tutorial.cast

y comenzar a llevar a cabo la sesión tutorizada que queremos grabar. Al salir de la sesión (con exit, logout o cualquier otro método análogo), se parará la grabación. El resultado será el archivo tutorial.cast.

Es muy interesante la opción -i SECONDS que convierte cualquier periodo de inactividad mayor a SECONDS en un tiempo de inactividad igual a SECONDS. De este modo, si la grabación se lleva a cabo así:

$ asciinema red -i 2 tutorial.cast

Podemos hacer pausas por tiempo indefinido, mientras creamos el tutorial, si temor a que el vídeo se vuelva largo e insufrible: ninguna de esas pausas superará los dos minutos.

Nota

Si nuestra intención es acabar añadiéndole sonido por algún método que veremos más adelante, entonces deberemos a la vez que comezamos la grabación del vídeo, grabar nuestra voz con un micrófono y algún software apropiado. Una alternativa sencilla para la terminal es ffmpeg. Si usamos los drivers de PulseAudio, la grabación será algo así[1]:

$ ffmpeg -f pulse -i 1 -c:a libopus -application:a voip -b:a 8K tutorial.webm

donde el número que es argumento de -i debe ser el micro y puede variar según el sistema. El número concreto en cada caso puede consultarse con:

$ pacmd list-sources

Eso sí, no tenemos modo de hacer que las grabaciones de vídeo y audio empiecen (y acaben a la vez), por lo que debemos preocuparnos de que así sea más o menos, aunque bien es cierto que un pequeño desfase no es muy grave por la naturaleza del vídeo y porque, si el audio empezó antes, es muy sencillo cortar ese exceso inicial con el propio ffmpeg.

Advertencia

El fichero recuerda las dimensiones de la consola en la que trabajábamos, de modo que nos conviene ajustarla primero a un tamaño adecuado.

Creado el vídeo, podemos probar su reproducción con:

$ asciinema play tutorial.cast

que debería reproducir fielmente lo que hicimos previamente. Si en algún momento pulsamos Space, la reproducción se pausará y podremos volverla a reanudar pulsando la misma tecla. Tambiés es posible alterar la velocidad de reproducción:

$ asciinema play -s 1.2 tutorial.cast

lo cual aumentará en un 20% la velocidad a la que se reproduce el vídeo. Sea como sea, esta posibilidad de reproducción se queda un poco corta si lo que pretendemos es crear un tutorial para terceros.

Nota

La reproducción también dispone de la opción -i SECONDS, pero sólo será necesaria si queremos acortar las pausas y no la usamos al grabar.

9.4.2. Publicación

La mejor manera de facilitar el acceso al tutorial es publicarlo y que el posible alumno pueda acceder a él sin necesidad de tener instalado asciinema. Tenemos tres posibilidades:

  1. Publicarlo en la página de asciinema, que es lo más simple.

  2. Crear un archivo de vídeo en un formato estándar (p.e. .mp4).

  3. Alojarlo en una página web propia.

A explicar estas tres alternativas dedicaremos el epígrafe.

9.4.2.1. Página oficial

La principal desventaja de este método es que se reproducirá sin posibilidad de añadirle sonido, lo cual en algunos casos nos podrá resultar inadmisible. Si este no es el caso, esta es la solución más simple.

Es indispensable que nos demos con una dirección de correo electrónico. Dados ya de alta, podemos subir nuestro tutorial a esa cuenta del siguiente modo:

  • Ejecutamos:

    $ asciinema auth
    

    que nos proporcionará una URL basada en un identificador que se genera la primera vez que ejecutamos el programa[2].

  • Visitamos la URL e introducimos en la página la dirección de correo con la que nos registramos. Eso asociará la cuenta con nuestro identificador, además nos enviará un mensaje al correo electroónico con un URL que nos servirá (si lo deseamos) para ingresar en el sitio vía web (útil, por ejemplo, si deseamos añadir alguna descripción al vídeo o borrarlo por no haber quedado satisfechos).

  • Subimos el video tutorial al sitio asociándolo con nuestra cuenta:

    $ asciinema upload tutorial.cast
    

Y listo, se nos proporcionará el enlace donde está accesible la reproducción. En cualquier caso, si accedemos a nuestra cuenta, podremos revisar todos los vídeos que hemos subido y acceder también a este enlace.

9.4.2.2. Vídeo estándar

Esta estrategia sí nos permite añadir sonido, aunque como el resultado es un vídeo normal reproducible con cualquier reproductor multimedia:

  • El resultado será mucho más pesado.

  • Perderemos la posibilidad de copiar al portapapeles.

  • Es probable que no nos funcione con vídeos demasiado largos.

  • Dado el resultado, ¿no es más sencillo capturar la pantalla y nos ahorramos todo este jaleo?[3]

Pese a las evidentes desventajas, expondremos el procedimiento aquí partiendo de haber creado ya tanto e vídeo (tutorial.cast) como su correspondiente audio grabado simultáneamente (tutorial.webm).

Debemos:

  • Transformar el formato .cast en .gif mediante asciicast2gif. Lo más sencillo es usar el contenedor Docker que ofrecen los propios creadores. Si creamos el directorio /tmp/DATA y guardamos tutorial.cast en él, podemos obtener tutorial.gif del siguiente modo:

    # docker run --rm -v /tmp/DATA:/data asciinema/asciicast2gif -t asciinema -w80 tutorial.cast tutorial.gif
    

    Advertencia

    Si el video es excesivamente largo, se generarán demasiadas imágenes, el programa fallará y no lograremos crear el resultado.

  • Utilizar ffmpeg para mezclar la imagen y el sonido en un video reproducible:

    # nice ffmpeg -i /tmp/DATA/tutorial.gif -i tutorial.webm -c:a copy -movflags faststart \
          -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" -strict -2 tutorial.mp4
    

El resultado será un vídeo mp4 comúnmente reproducible, pero, como tal, sin brindarnos la posibilidad de copiar al portapapel las órdenes que se ilustran.

9.4.2.3. Página propia

Este último procedimiento es el recomendado si se requiere sonido, puesto que aúna todas las ventajas:

  • Mantiene el formato original del vídeo (.cast), que por tanto tendrá un tamaño mínimo.

  • Permite copiar al portapapeles.

  • Proporciona todas las ventajas de la reproducción de un vídeo estándar, incluyendo la sincronización con el sonido.

En contraprestación

  • Requiere que podamos albergar los ficheros en algún espacio web propio y acomodar la reproducción en una página web (que puede ser tan simple como la proporcionada).

  • Como grabamos audio y vídeo por separado (aunque simultáneamente), hacer que estén sincronizados quizás requiera una edición mínima.

Partiendo de haber generado ya el vídeo tutorial.cast y el audio tutorial.webm, necesitamos una página html como ésta[4] en la que inscrustarlo:

<!DOCTYPE html>
<html lang="es">
   <title>Reproducción de tutorial.cast con asciinema (v3)</title>
   <meta charset="utf-8">
   <link rel="stylesheet" type="text/css" href="https://unpkg.com/asciinema-player@latest/dist/bundle/asciinema-player.css" />
   <script>
      window.onload = function() {
         const player = AsciinemaPlayer.create('tutorial.cast', document.getElementById("video"), {
            terminalfontSize: 'medium',
            fit: false,
            // speed: 1,
            // otros parámetros opcionales...
         });
         const audio = document.querySelector("audio");

         player.addEventListener("play", e => audio.play());
         player.addEventListener("pause", e => audio.pause());

         // Sincroniza audio y vídeo al cambiar de posición el vídeo.
         const bar = player.el.querySelector(".ap-progressbar");
         bar.addEventListener("click", e => audio.currentTime = player.getCurrentTime());
      }
   </script>

   <div id="video"><!-- AQUÍ SE INCRUSTA EL VÍDEO --></div>
   <audio preload="auto"><source src="tutorial.webm" type="audio/webm"></audio>
   <script src="https://unpkg.com/asciinema-player@latest/dist/bundle/asciinema-player.js"></script>
</html>

Advertencia

La página debe estar alojada en un servidor. Si intenta usarla como un archivo local, le será imposible cargar el vídeo y el audio. Ahora bien, dado que el vídeo nunca suele ser excesivamente pesado, ya que el formato no es propiamente vídeo, se puede incrustar como dataURI:

const cast64 = 'CAST.EN.BASE64';
const player = AsciinemaPlayer.create('data:text/plain;base64, ' + cast64, document.getElementById("video"), {
   // opciones...
});

donde CAST.EN.BASE64 es la salida de la orden:

$ base64 tutorial.cast

Desgraciadamente, el audio es normalmente excesivamente largo como para incrustarlo análogamente en el propio HTML.

Nota

Una opción que puede añadirse a Asciinema.create es speed para modificar la velocidad de reproducción. No obstante, si también se ha grabado audio, alterar la velocidad resultará un problema.

Nota

Hay dos formas sencillas de controlar las dimensiones del vídeo:

  1. La expuesta en el ejemplo que consiste en evitar que el video se ajuste a su elemento contenedor (fit: false) y establecer el tamaño de la fuente (small, medium, large o una dimensión en píxeles como 12px). Como el propio vídeo contiene la información de filas y columnas que hay, asciinema calculará las dimensiones.

  2. No usar lo anterior y definir las dimensiones del elemento contenedor mediante CSS. Por ejemplo:

    <div id="video" style="width: 600px, margin:auto;"></video>
    

Notas al pie