2024-06-17 Selecting subtitles’ language with mpv and Emacs hacking

As you know quite well if you’re following my blog, I watch Doctor Who regularly. These days, I mostly use mpv for video viewing (unless I watch streamed videos on a certain proprietary platform, which I don’t like, but it seems the only way to watch the newest season). My usual workflow is to buy dvds (which have a great advantage over streaming – I actually, physically own them), rip them to mp4​s and then spend some time watching, translating, screenshotting and doing whatever I want with them.

One issue I have is that for most episodes, I have two versions of the srt file with subtitles – an English one and a Polish one, and I’d like to be able to select either of them easily.

At first, I wanted to write a small convenience Elisp command enabling me to choose which subtitle file to open when starting mpv in Dired. I started to read the mpv manual to find out how you can open the video with a given subtitle file, and I learned that you can tell mpv to read several subtitle files and then cycle through them interactively with j and J. That’s even better, I thought! I can just issue the --sub-file option several times and offload the work onto mpv. Then I learned about the --sub-auto option, and it turned out that I don’t even need to do that! The only thing left to do is to rename my mp4 and srt files. For example, assume that I have the s05e02-the-beast-below.mp4 file. If I rename the subtitles to s05e02-the-beast-below.pl.mp4 and s05e02-the-beast-below.en.mp4, mpv will automatically load them both and let me switch the language by pressing j. That’s pretty cool!

It gets even better! This naming scheme is apparently supported by Subed mode, so it correctly opens file.mp4 in mpv when I visit file.pl.srt. That’s great!

The only thing left is to tell Emacs that I want to use mpv to open mp4 files. One way to do it is to add ("\\.mp4\\'" "mpv") to the dired-guess-shell-alist-user variable. This makes it so pressing & and then RET on a file in Dired will automatically open it in mpv.

That’s two keypresses, though. (Three if you count shift.) Can we do better? I never want to visit an mp4 file in Emacs, so why not configure it so that pressing RET on an mp4 file will open it in mpv? (By the way, you can also press W on a file, which will open it in the browser. That actually works for videos, although obviously the browser UI is far inferior to mpv’s.)

It turns out that the situation is pretty complicated. One thing I found that I thought would help me was the dired-open package. It contains several features which allow you to open files from Dired in various ways, including in external applications. If you include ("mp4" . "mpv") in the dired-open-extensions alist, pressing RET on an mp4 file in Dired will open it using mpv. (Under the hood, it’s using the dired-open-file function, which in turn uses the dired-open-functions hook, which has dired-open-by-extension as one of its functions.)

However, this uses dired-open--start-process, which – for reasons unknown to me – uses file-truename. The problem with that function is that it follows symlinks. In my setup, subtitle files reside in one directory and video files in another, and the latter are symlinked to the directory where the former are stored. This is perfectly reasonable: the subtitles are in the directory included in my backup scripts (since it is me who translates them, and I want my work to be backed up!), but there is no point in making backups of huge video files (I have physical dvds and a flash drive with all the episodes, so I don’t need yet another copy…).

Now that I’ve learned about dired-open, however, I really like it – I just don’t want it to follow symlinks. What can I do?

The best thing to do is to file an issue (and offer to fix it myself), which I did. Until this is resolved, I can (obviously) hack the code of dired-open – this will work until the next update of the dired-open package, and then (hopefully) a fix will have landed, so it’s ugly, but functional. That’s exactly what I did. The trouble with this “solution” is that file-truename was probably used there for a reason, and it’s quite possible that I demolished some Chesterton’s fence this way. I’ll probably live with that unless it breaks something. If it does, I have one more trick up my sleeve. It’s a rather extreme hack, but should be doable. Buckle your seatbelts: I could advise dired-open--start-process, using the :around advice combinator, then advice file-truename before running the original dired-open--start-process, effectively calling expand-file-name instead, and remove that advice after dired-open--start-process returns. In other words, I’d have advice setting and then removing another advice. Do not try this at home, kids;-)!

CategoryEnglish, CategoryBlog, CategoryEmacs