programming (and other) musings
09 Jan 2021

embarking videos

Inspired by Prot's musings on completion, i've, ahem, embarked in a reconsideration of my completions setup (as you might have intuited from my recent experiments with the spotify API and consult). As it happens, i'm starting to feel quite at home with a combination of selectrum, prescient and consult, and the ideas to augment what i have with contextual actions using embark seem really natural to me.

The main premise of embark is pretty simple: one has categories of targets that can be acted upon (URLs, regions, files, buffers…), and, for each category, a collection of commands that take an instance of the target and do something with it (that is, a collection of actions on target instances). As you may imagine, user-defined categories and actions are a thing in embark.

A little application of those ideas immediately popped to my mind when i started reading about embark: streaming videos from video hosting platforms. For many reasons, i try to avoid switching my context to graphical browsers and prefer to play those kind of videos by passing their URLs to mpv, which in turn will use youtube-dl to stream the contents.

Now, it's very easy to recognise when a URL is a video URL, we just need to match it against an appropriate regular expression. For example:

(defvar jao-video-url-rx
  (format "^https?://\\(?:www\\.\\)?%s/.+"
          (regexp-opt '("youtu.be"
                        "youtube.com"
                        "blip.tv"
                        "vimeo.com"
                        "infoq.com")
                      t))
  "A regular expression matching URLs that point to video streams")

Given that regular expression, we can write a "video-url target" finder function, using for instance the Emacs standard library thing-at:

(defun jao-video-finder ()
  "Check whether we're looking at a video URL.
Return (video-url . <URL>) if so."
  (when-let ((url (thing-at-point-url-at-point)))
    (when (string-match-p jao-video-url-rx url)
      (cons 'video-url url))))

Once we have a URL in our hands, playing it with mpv is very easy 1:

(defun jao-play-video-url (&optional url)
  (interactive "sURL: ")
  (let ((cmd (format "mpv %s" (shell-quote-argument url))))
    (start-process-shell-command "mpv" nil cmd)))

Now, we can put both things together with embark and tell it, first, that we have a new kind of target (video-url), and, second, what actions are associated to it (jao-play-video-url, among others).

The new target category definition is accomplished by adding its finder function to embark-target-finders alist:

(add-to-list 'embark-target-finders #'jao-video-finder)

Similarly, registering the possible actions for a target is done by adding a keymap for it to embark-keymap-alist. Embark provides the utility macro embark-define-keymap for easily defining new keymaps, so, putting both things together we have:

(embark-define-keymap jao-video-url-map
  "Actions on URLs pointing to remote video streams."
  ("p" jao-play-video-url)
  ("b" browse-url)
  ("f" browse-url-firefox))

(add-to-list 'embark-keymap-alist '(video-url . jao-video-url-map))

Besides our default, jao-play-video-url, i've thrown in for good measure a couple other actions. Note that they don't need to be specially defined, they're just stock Emacs commands taking one argument; and also that jao-video-url-map is just a run-of-the-mill Emacs keymap. As such, it can also be used and modified via the standard Emacs utilities: embark will just use the final result 2.

With that in place, we're done3: one can invoke M-x embark-act (most probably via a keyboard shortcut) when point is around (or right before) a video stream URL, and then press, say, p, to call mpv on it.

You might be thinking that writing a single Emacs command doing the same thing for us and binding it to a key is very easy too, so why bother? Well, as a matter of fact, "writing a standard Emacs command and binding it to a key" is exactly what we did, so, for starters, making it all part of the embark system is not giving us much additional trouble, if any (a couple of calls to add-to-list, all in all). In exchange, we reap the benefits of making our new action interplay with the generic utilities and integrations provided by embark (for instance, you'll see that a host of other generic actions are available and readily accessible for free for our new video URL target). This is, again, a good illustration of (and a homage to) the modularity and orthogonality of a system composed of pieces such as embark and friends.

Footnotes:

1

Note how we're defining jao-play-video-url as an interactive function, that is, as a command, so that it can be used as an action.

2

That's an illustration of a point highlighted several times by Prot in his talks: a key feature of these utilities is their smooth integration with existing Emacs vanilla APIs, in a modular way that confers them notable power. I cannot overemphasise how right on the money he is!

3

Well, this being Emacs, one is never done. We can build upon these ideas and add new tricks. For instance, i was musing about adding some kind of metadata to these video URLs, which would then be slurped by Marginalia and then be automatically available to all the other little elfs in this completion forest.

Tags: emacs
Creative Commons License
jao.io by jao is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.