I have a pretty extensive music library that I manage with MPD, the Music Player Daemon. For the longest time now I have also been aware of beets, another management system for music libraries. I played around with it a few times but never took the plunge to have it organize my entire collection.

A few days ago, whilst looking up a particularly obscure recording, I ended up finding it on MusicBrainz and decided to give beets, which integrates very tightly with that service, another serious try.

Yesterday I finally completed a first rough import of my entire library (which encompasses about 20,000 songs in 1400 albums). Given the integration with MusicBrainz, I now try to map every album to a release in their database. If I can't find it there, I instead fall back to an old favourite of mine, Discogs. beets will automatically update and correct any tags once I select the right release.

Whilst importing I decided that I should make more use of the "Grouping" tag as a way to organize albums into an arbitrary group. This is useful if a series of media features music that was composed by multiple artists. By matching on the Haibane Renmei grouping, for example, I can find all music that was made for that show, without having to keep artist names in mind.

"Grouping" seemed well-supported in MPD, but whilst updating some albums that I (sadly) only have in MP3 format, I found that MPD would not add the grouping information to its database.

As per the ID3v2.4 standard, the TIT1 frame is used for this kind of information in MP3 files. Sure enough, that tag was set correctly by beets, and both mutagen-inspect and ffprobe found it. MPD, however, even though this PR had been merged almost 3 years ago, refused to pick it up.

After having the #mpd IRC channel sanity-check my configuration, I investigated some more. Perhaps my version of libid3tag was outdated. It wasn't. Perhaps there were some encoding issues, but then why would other tags from the same file work fine? Couldn't be that either. I hooked up GDB and found that this line from the PR was never actually reached at all!

I decided to look a bit closer at how exactly MPD reads tags. The specific scan_id3_tag function that the PR modified is only called in two places, plugins/DsdLib.cxx and (indirectly) in plugins/MadDecoderPlugin.cxx. I had neither of these decoders installed, so... MPD just never got to read anything.

Yet how was I getting any tags, then?

After some spelunking in the decoder plugin folders and with the fact on my mind that the only decoder I had actually compiled in was FFmpeg, something dawned on me. Perhaps it was FFmpeg that was reading the tags.

Indeed it was. Turns out that FFmpeg does all of the heavy lifting here, and MPD really just asks it for any metadata and parses the ones it understands.

MPD uses "grouping" as a cross-format identifier for grouping information. It expects that particular string to be a key in the AVDictionary returned by FFmpeg here. Crucially, FFmpeg does not expose TIT1 as "grouping" in its metadata conversion table, having MPD drop TIT1 on the floor like a hot potato.

It is debatable where this particular bug should be fixed. I decided to send a patch upstream to FFmpeg, given that more than just MPD can benefit from a fix there. For the next poor soul I also prepared a PR that clarifies how exactly MPD reads metadata.


Thunar, XFCE's file manager, was a pretty late addition to my core set of tools that I rely on to accomplish day-to-day tasks. I started using it heavily maybe 2 or 3 years ago. For the longest time before that I had been using ranger, a console file manager.

The ability to move and copy files around between multiple directories using drag-and-drop is basically Thunar's killer feature for me. I'm often faster using the mouse to select a bunch of files and then quickly dragging them someplace else. In comparison, ranger's select-then-yank-and-paste workflow feels very cumbersome.

However, there's always been a feature in ranger that Thunar did not have - the very simple but powerful ability to filter the current directory listing by showing only files matching a given pattern. There's a more or less hidden way to have Thunar select files matching a wildcard with CTRL-S, but that relies on popping up an extra dialogue, and doesn't play well with interactive use.

Very early on I found a feature request for this, but it looked largely abandoned and I forgot about it until today when, to my extreme surprise, I discovered that it was implemented just 3 months ago. There does not seem to have been any large fanfare around it; the changelog buries it in more miscellaneous changes. Not a big deal.

Way more worrisome, however, is that the commit implementing the feature does not introduce any user-facing documentation. Nowhere is explained how the new feature works and what its limitations are. I had to go read the code to find out why my search results were littered with seemingly random files in other directories. Turns out that it consults files in GtkRecent too, merging results in the current directory with matches of files you had recently opened, regardless of their location.

A terrible default in my opinion, so I immediately turned it off by disabling the gtk-recent-files-enabled property in my GTK config. Thankfully you can still do that, albeit in a system-wide fashion, but I don't care about recent files.

Still, it's really sad I had to go out of my way to find that out. A less tech-savvy user could not have done that so easily. It would lower the bar tremendously here to describe what a new feature does and point out how to configure it.

A failure to do so makes software intransparent and hostile, furthers the notion that the user experience is inherently bad, and very quickly leads to resignation in the common user base.


A couple of days ago I turned on hidepid=2 for the /proc mount on my desktop PC. Today I saw the systemd-userdbd service failing on bootup, and realized that it had been failing to start for a few days. Aside from the fact that there really should be a well-supported and easy way to notify administrators of failing units, this obviously needed some investigation.

systemctl status systemd-userdbd.service wasn't very helpful, but journalctl had the specific error:

[..] spawning /lib/systemd/systemd-userdbd: Read-only file system

I didn't immediately jump to the conclusion that this had to do with enabling hidepid=2. After all, why would that result in a read-only file system? Investigating a failure very early on in boot is a pain, so instead of wasting my time on that I took to GitHub issues.

As it turns out, hidepid= is just not supported at all in systemd. This doesn't seem to be pointed out anywhere, and I certainly was not aware of it before. Services can set ProtectProc=, but there doesn't seem to be a clean way of restricting /proc for unprivileged users like a global hidepid=2 did. I've removed the option for now.


Yesterday whilst catching up on the Git mailing list I stumbled upon this patch proposing to improve the hunk header regex for Java. I had never paid much attention to how git-diff(1) finds the right method signature to show in the headers though I was vaguely aware of a bunch of regexes for different languages.

Turns out that by default, as explained in the manual for gitattributes(5), git-diff(1) emulates the behaviour of GNU diff -p and does not consult any of the language-specific regular expressions. This came as a bit of a surprise to me, as Git usually has relatively sane and extensive defaults. Why define all these regexes and then not use them by default?

Perhaps one reason is that it is hard to tell when to use which. Git can only look at the filename, and not all shell scripts share the .sh ending, for example. Surely it would not be too invasive, however, to define sensible defaults for, say, files ending in .py or .rs.

In any case I updated my ~/.config/git/attributes with the following, and am now enjoying better hunk headers across the board:

*.c	diff=cpp
*.cpp	diff=cpp
*.go	diff=go
*.md	diff=markdown
*.pl	diff=perl
*.py	diff=python
*.rs	diff=rust
*.sh	diff=bash
*.tex	diff=tex

The markdown setting is especially neat since it will now display the nearest section right in the diff, like so:

--- a/posts/weltschmerz.md
+++ b/posts/weltschmerz.md
@@ -24,6 +24,10 @@ ## Download

In the previous post I talked about a couple of different ways to apply patches with mutt(1) or neomutt(1). Turns out Maildir might not be the best format to use for git-am(1) because its files are not guaranteed to be in any specific order (per spec they need only carry unique names).

As git-am(1) does not sort its input, patches might be applied in the wrong order. This came up on the mailing list as well, all the way back in 2013. A fix specific to Maildir files created by mutt(1) was added in 18505c3.

Sadly neomutt(1) changed this format 5 years ago, removing the sequence number that git-am(1) relies on in commit 75b3708 and replacing it with a call to mutt_rand64(). I can only assume no one is using neomutt(1) to export patches to Maildir, since having patches applied in the wrong order is a pretty significant problem.

For now I recommend using the mbox format instead when exporting patches. Whilst that doesn't guarantee a specific order either, usually mail clients are nice enough to export mails to mbox in the order they are shown.

The core issue remains until git-am(1) learns to sort mails itself.


When maintaining a project sooner or later there comes the time when you need to apply patches that have been submitted to you. Assuming a patch-based workflow those are going to be one patch per mail, possibly connected in a thread. There's lots of different ways of getting those patches to their final destination, git-am(1), and in this post I want to take a look at ones that work well with mutt(1) or neomutt(1) since that is what I use.

I want to rely on the default bindings as much as possible. All mentioned bindings should work out of the box.

Applying a single patch is very straightforward: Select the mail in the pager and hit | to pipe it to an external command. This command will be some variation of git-am(1), perhaps git am -s to also add a Signed-off-by trailer.

What if you want to apply a patch series, however? An obvious solution would be to pipe each message in the thread to git-am(1). The <pipe-message> command we invoked earlier with | only applies to the currently selected message, so we can't use that on the whole thread. Instead we can tag the whole thread using <Esc>t, then use the <tag-prefix> command ; followed by | to send all tagged messages to git-am(1).

There's two problems with this, though. The first is that depending on the setting of pipe_split, git-am(1) might only apply the first patch in the series. This is the case if pipe_split is set to the default of no; mutt(1) will then concatenate the messages before sending them to the external command. Sadly this concatenated format is slightly different from the mbox format that git-am(1) expects, making it not see anything past the first patch.

With pipe_split set to yes, mutt(1) spawns one process per tagged mail instead, applying all patches correctly. Now that git-am(1) is spawned once per mail, however, you lose its atomicity: Neither ORIG_HEAD will be set correctly, nor will --abort go back to the original branch.

This might not be a big issue, but I am not a fan. Thankfully git-am(1) supports reading patches from mbox files or Maildir structures. So instead of piping mails to git-am(1) via <pipe-message>, let's save them to the current directory: With the thread still tagged, ;C (<tag-prefix> followed by <copy-message>) will save a copy of it under a given path. Now you can apply the series by hitting ! and running git am -s <path>. This works with mbox_type set to either mbox or Maildir (but see № 9 ).

Of course there is no need to rely on the default bindings, especially if you need to do this kind of thing very often. mutt(1) is easily customizable, making it possible to bind the entire chain of actions to just one keystroke. If you're interested in a more detailed examination of a patch-based workflow with mutt(1), check out this post by Greg Kroah-Hartman.


I recently became frightfully aware of how much time I spend in less(1).

It's never been a utility I gave much conscious thought and I realized that it is one of those programs that go largely ignored and underappreciated just for their ubiquity and unobtrusiveness. For most people piping something to less(1) has most likely become second nature. In the same way it is surely unthinkable for some to read log files and manuals in anything other than less(1), or use any other pager for the Git suite.

If you've not given less(1) a closer look, I invite you to read its manual. There's lots of neat features you might have missed, like filtering lines with &, toggling any command-line option on the fly with -, following input as it appears with F, or opening the current file in an editor with v.

A feature I discovered only recently is the "wrap-around search modifier". Introduced in late 2020 (past version 565), this modifier obsoletes the common dance of g and n to redo the current search on the whole file. Now, if you hit Ctrl-W right after issuing a forward or backward search, less(1) toggles search wrap-around.

There is no option to turn this behaviour on automatically. However, it is possible to override the / and ? bindings using lesskey(1). Put the following in ~/.lesskey, run lesskey (not needed on versions past 590), and less(1) should now wrap the search automatically:

/ forw-search ^W
? back-search ^W

HTTP defines the Link header with which Link Relations can be defined directly in the HTTP response. This lets websites define their stylesheets or favicons without having to pass them in an HTML <link> element.

When displaying certain files directly, Firefox wraps them in its own HTML. This happens, for example, when you look at a .txt file marked as text/plain or an image marked as image/png.

Turns out that for plain-text files, Firefox will load and honour any stylesheet passed to it in the Link header and apply it to its own HTML. One could, for example, link a stylesheet that overrides the font settings, or even include pictures. Firefox will duly load all of these when displaying the file, whilst View Page Source will still show only the file itself. It is only when looking at the HTTP response and the Network tab in the Inspector that you see what exactly is happening.

Firefox displaying a plain-text file
alongside a picture.
A plain-text file... in Comic Sans... that also displays a picture?

This does not seem to work when Firefox is displaying images and it doesn't work at all in Chromium-based browsers. The only relevant entry in Mozilla's Bugzilla instance I could find was this issue from 9 years ago.

Arguably this could be considered a bug, and I do strongly feel that Firefox should not load any outside resource when displaying plain-text files. For now, though, have fun confusing people with this.

Thanks to puck for pointing this out to me.


Whilst reviewing and discussing this patch for weltschmerz I found out that there actually exists a global property gtk-cursor-blink that is honoured by all applications that build on GTK.

I don't think I've ever seen this exposed in a settings dialog. Perhaps in the accessibility settings, I rarely venture there. In any case, you can put properties like these straight into ~/.config/gtk-3.0/settings.ini and GTK apps will pick them up.

For QT apps it seems you can set cursorFlashTime to a negative value in the aptly named ~/.config/Trolltech.conf but I could not get this to work with the only QT app that I use, quassel.

Not that I would want to, I do prefer a blinking cursor.


The notion of a "merged" branch is highly dependent on the workflow used for a project. I was wanting to clean up some topic branches in my copy of git.git today, but git branch -d refused to delete them, pointing out that they were not yet merged.

I knew for a fact that they were, which made me look up how git branch -d actually determines that. The manual is not entirely clear, but a comment in the code pointed out that git constructs the merge base of the branch and its upstream (or HEAD if there is none) and checks whether the branch is reachable from that merge base.

In a patch workflow, this will generally not be true. A lot of things may happen to your patches before inclusion, and with git.git they will get at least one other sign-off. They'll be recorded in a merge commit, but it will not have your original branch as one of its parents.

Therefore, neither git branch -d nor git branch --merged will report your branch as merged. Both of these tools are built for the merge workflow instead.

To see if your work was merged in patch-based workflows, use git-cherry(1). Then you can safely force deletion of the branch with git branch -D


In recent versions of Firefox, single words are looked up via DNS when you enter them in the URL bar. If the word resolves, the browser "helpfully" indicates that there's a page at http://<word> to visit.

Weird feature, though when taken at face value I can see its usefulness with a combined search and URL bar. Ideally you'd have completely different semantics for searching and (direct) browsing, but I don't think something like this is forthcoming. If anything I'd expect direct browsing to be ever more discouraged. Nowadays search engines, not browsers, are the gateway to the internet.

In any case, turns out this feature also has interesting side-effects with (browser-based) DoH turned on. If you ever need to turn it off, Firefox 78 added the following about:config switch:


Not that I think this is a great solution. DoH should be done on a system-wide level (with local queries sent to your router or resolved through mDNS) and there should be a way of trusting your router's DNS to not forward local queries to your ISP.