Cuaderno de GNUtas

Ytel y la búsqueda de vídeos de youtube en Emacs (con Invidious)

El paquete ytel es una biblioteca externa para GNU Emacs que permite buscar los vídeos de youtube mediante una interfaz basada en elfeed, o sea, que quien ya conozca este popular navegador-agregador de feeds, se moverá en ytel como pez en el agua (un ejemplo del aspecto de la interfaz en la fig. 1). A esto hay que sumar dos características importantes más. La primera, que las búsquedas la realiza, de fábrica, mediante la api de Invidious, que es, por otra parte, la forma que recomendamos aquí para buscar y ver vídeos de youtube, pues se trata de software libre, no ejecuta javascript propietario y está descentralizada a través de unas cuantas instancias que van surgiendo por la red. La segunda es que ytel consiste, más que en una aplicación acabada, en una base con herramientas (funciones, variables) para que nos construyamos nuestra propia interfaz de vídeos de youtube en Emacs a gusto, partiendo de la funcionalidad de las búsquedas. Aquí contaré cómo me he apañado la mía, integrando ytel con EMMS, el Emacs multimedia system del que ya hablamos algo aquí y aquí.

Como Invidious tiene unas cuantas instancias activas y disponibles por internet, conviene declarar antes cuál preferimos para realizar las búsquedas de los vídeos. Así que empezamos por configurar esta variable con nuestra instancia preferida:

(setq ytel-invidious-api-url "https://invidious.snopyta.org")

Ahora bien, por saturación de usuarios a veces una instancia puede quedar temporalmente fuera de juego, y suele ser buena práctica diversificar entre instancias para no dar pie a estas saturaciones. Yo he optado por definir una sencilla lista Ido para cambiar de instancia rápidamente. Primero, esta variable con unas cuantas instancias:

(setq instancias-invidious '("yt.iswleuven.be"
                             "invidious.xyz"
                             "invidious.snopyta.org"
                             "inviou.site"
                             "invidious.site"
                             "invidious.tube"
                             "vid.mint.lgbt"
                             "invidio.us"
                             "invidious.glie.town"))

A continuación la función que crea la lista de instancias para que Ido navegue por ellas:

(defun crea-lista-instancias-invidious ()
  (mapcar 'identity instancias-invidious))

Y la lista Ido que devuelve el candidato como variable:

(defun ido-instancias-invidious (argumento)
  (interactive  (list (ido-completing-read "Instancias de Invidious: " (crea-lista-instancias-invidious) nil t)))
  (setq instancia-candidata argumento))

Y entonces ya podemos definir una función para cambiar de instancia cómodamente:

(defun ytel-otra-instancia-invidious-api ()
  "Escoge entre una lista de instancias de Invidious para definir
la url de la api."
  (interactive)
  (let ((instancia (instancia-invidious)))
    (setq ytel-invidious-api-url (concat "https://"  instancia))))

Pero lo esperable (y lo que sucede el 90% de las veces) es que con la instancia por defecto funcione todo bien.

Sigamos configurando. Ya tenemos resuelto el tema de las búsquedas. Ahora queda, por ejemplo, cómo reproducir el vídeo escogido mediante EMMS. Para ello, definimos esta función:

(defun ytel-reproduce ()
   "Reproduce un vídeo de Youtube desde ytel mediante EMMS"
   (interactive)
   (let* ((video (ytel-get-current-video))
          (id    (ytel-video-id video)))
     (emms-play-url (concat ytel-invidious-api-url "/watch?v=" id))
     "--ytdl-format=bestvideo[height<=?720]+bestaudio/best"))

Es decir, cuando lanzamos una búsqueda de ytel se nos muestra, a la manera como lo hace elfeed, una lista de vídeos candidatos. Con el cursor en el vídeo escogido, llamamos a la función anterior.

Pero aún hay más: ¿Y si queremos descargar el vídeo en la posición del cursor mediante youtube-dl, ya sea el vídeo completo o sólo el audio? Pues es muy simple. Suponiendo que ya tenemos creado un directorio permanente donde guardar los vídeos/audios descargados, podemos definir estas dos funciones, basadas en la anterior (nótese que en este caso ponemos la url de youtube para asegurar):

(defun ytel-dl-video-completo ()
  (interactive)
  (let* ((video (ytel-get-current-video))
         (id    (ytel-video-id video))
         (comando (concat
                   "youtube-dl -o '~/Vídeos/y-dl/%(title)s.%(ext)s' "
                   "https://www.youtube.com/watch?v=" id)))
    (message "descargando vídeo completo")
    (start-process-shell-command comando "*proceso-ydl*" comando)))

(defun ytel-dl-solo-audio ()
  (interactive)
  (let* ((video (ytel-get-current-video))
         (id    (ytel-video-id video))
         (comando (concat
                   "youtube-dl -x -o '~/Vídeos/y-dl/%(title)s.%(ext)s' "
                   "https://www.youtube.com/watch?v=" id)))
    (message "descargando vídeo sólo audio")
    (start-process-shell-command comando "*proceso-ydl-audio*" comando)))

Sendas llamadas al comando de shell youtube-dl se hacen de forma asíncrona mediante start-process-shell-command, y la salida de dicho comando va a parar a un búfer temporal, donde podrems ver el estado del proceso de descarga, como si lo estuviésemos haciendo desde la terminal.

Por último, y si no queda otra, podemos definir también esta función para abrir el vídeo (ay) en la página de youtube con el navegador externo:

(defun ytel-abre-en-youtube ()
  "Reproduce un vídeo de Youtube en la página de Youtube en
firefox, la opción evitable :-("
  (interactive)
  (let* ((video (ytel-get-current-video))
         (id    (ytel-video-id video)))
    (browse-url (concat "https://www.youtube.com/watch?v=" id))
    "--ytdl-format=bestvideo[height<=?720]+bestaudio/best"))

Y ya sólo nos queda definir los atajos de rigor, que en ytel pueden ser simples teclas sin prefijo (de fábrica ya incluye ytel algunos, como la tecla «s» para iniciar una búsqueda).

(with-eval-after-load 'ytel
  (define-key ytel-mode-map "m" #'ytel-reproduce)
  (define-key ytel-mode-map "y" #'ytel-abre-en-youtube)
  (define-key ytel-mode-map "q" #'ytel-dl-video-completo)
  (define-key ytel-mode-map "w" #'ytel-dl-solo-audio)
  (define-key ytel-mode-map "x" #'ytel-otra-instancia-invidious-api))

ytel.png

Figura 1: Ejemplo de una lista de vídeos en ytel

Publicado: 29/08/21

Última actualización: 22/11/21


Índice general

Acerca de...

Esta obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial 4.0 Internacional.

© Juan Manuel Macías
Creado con esmero en
GNU Emacs