diff --git a/content/posts/regex-based-url-opener.adoc b/content/posts/regex-based-url-opener.adoc
new file mode 100644
index 0000000..e5affcb
--- /dev/null
+++ b/content/posts/regex-based-url-opener.adoc
@@ -0,0 +1,161 @@
+---
+title: "Open URLs based on regular expressions"
+slug: "regex-based-url-opener"
+description: null
+date: 2022-04-18T17:16:08+02:00
+type: posts
+draft: true
+tags:
+- WWW
+- Zsh
+toc: true
+---
+
+:source-highlighter: pygments
+:idprefix:
+:experimental: true
+:toc:
+:toclevels: 2
+
+:url-urlhandler: https://schlomp.space/tastytea/dotfiles/src/branch/main/.local/bin/urlhandler
+:url-functions: https://schlomp.space/tastytea/dotfiles/src/branch/main/.config/zsh/functions
+:url-zshoptions: https://zsh.sourceforge.io/Doc/Release/Options.html
+:url-zshfunctions: https://zsh.sourceforge.io/Doc/Release/Functions.html
+:url-desktop-spec: https://specifications.freedesktop.org/desktop-entry-spec/latest/
+
+:abbr-pcre: pass:[PCRE]
+
+One of the shell scripts that bring me the most joy is my URL opener. I have it
+set as my default browser, so whenever I click a hyperlink somewhere it gets
+called and decides if the URL should be opened with Firefox or with another
+program. mpv for video files and YouTube URLs, a download-and-launch-viewer
+function for pictures and so on.
+
+== The script
+
+I have abbreviated the script here a bit for better readability, the full
+version is available link:{url-urlhandler}[in my dotfiles repo].
+
+[source,shell]
+--------------------------------------------------------------------------------
+#!/usr/bin/env zsh
+# Open URLs based on perl compatible regular expressions. Several commands can
+# be specified with ; as separator. If the URL doesn't match anything or the
+# commands are not found, use ${default_cmd}.
+
+setopt ERR_RETURN NO_UNSET PIPE_FAIL
+
+if [[ ! -v 1 ]]; then
+ print -u 2 "usage: ${0} …"
+ return 1
+fi
+local -a urls=(${@})
+
+autoload -U readwwwlog openwwwimg
+zmodload zsh/pcre
+
+local default_cmd="firefox"
+--------------------------------------------------------------------------------
+
+First, we set some essential options. `ERR_RETURN` stops execution when a
+command has a non-zero exit status, `NO_UNSET` treats non-existing variables as
+an error and `PIPE_FAIL` sets `${?}` to non-zero if any command in a pipeline
+fails. You can read more about them in the *zshoptions* man-page or in the
+link:{url-zshoptions}[online documentation].
+
+Next we check if `${1}` is set (we have at least 1 URL) and assign all arguments
+to the array `${urls}`. Then we autoload some function link:#helper_functions[we
+later use], load the {abbr-pcre} module and set the default browser.
+
+[source,shell]
+--------------------------------------------------------------------------------
+local mpv="mpv --force-window=yes"
+
+local -A assignments=(
+ '\.(mp4|m4v|mkv|avi|webm|flv|xvid|ogv|theora|mov|wmv)$' "${mpv};vlc"
+ '\.(ogg|flac|opus|m4a|wav|mp3|mid|aac|wma)$' "${mpv};vlc"
+ '^https://media\.ccc\.de/v/[^/]*$' "${mpv}"
+ '^https?://(www\.)?youtu(\.be|be\.com)/' "${mpv}"
+ '^(gemini|gopher)://' "kristall"
+ '\.(log|txt)$' "readwwwlog"
+ '^https?://(www\.)?(dpaste|pastebin|irccloud)\.com/' "readwwwlog"
+ '\.(webm|png|jpe?g|gif|svg|bmp|xcf)$' "openwwwimg"
+)
+--------------------------------------------------------------------------------
+
+Now we define the associative array `${assignments}` with the regular expression
+on the left and the command(s) to run on the right. The first command that
+exists will be run.
+
+[source,shell]
+--------------------------------------------------------------------------------
+local selected_cmd=${default_cmd}
+for regex cmds in ${(kv)assignments}; do
+ if [[ ${urls[1]} -pcre-match ${regex} ]]; then
+ for cmd in ${(s/;/)cmds}; do
+ if type ${cmd%% *} >& -; then
+ selected_cmd=${cmd}
+ break
+ fi
+ done
+ break
+ fi
+done
+
+${(@s/ /)selected_cmd} ${urls}
+--------------------------------------------------------------------------------
+
+This loops through all regular expressions and compares it against the
+first URL (we naively assume that all supplied URLs are of the same type 😊). If
+it matches, the first command that exists is run with the URL. If nothing
+matches, the default browser we set earlier is used.
+
+[NOTE]
+Because commands can contain options, we split the command-strings at spaces in
+the existence check and when we run the command. This has the side-effect that
+commands can not contain spaces.
+
+== Helper functions
+
+The functions `readwwwlog` and `openwwwimage` are available in the
+link:{url-functions}[Zsh functions directory] of my dotfiles repo. Put them
+anywhere in your `${fpath}`. Learn more from the *zshmisc* man-page or the
+link:{url-zshfunctions}[online documentation]. Or you could just put them inside
+the script, like this for example:
+
+[source,shell]
+--------------------------------------------------------------------------------
+function openwwwimg() {
+ local file="$(mktemp --suffix='.openwwwimg')"
+ curl --silent --location --output ${file} ${url}
+ if [[ ${?} -eq 0 ]]; then
+ viewnior ${file}
+ else
+ firefox ${url}
+ fi
+ rm -f ${file}
+}
+--------------------------------------------------------------------------------
+
+Don't forget to remove the autoloads if you put them directly in the script.
+
+== Setting the script as default browser
+
+To set the default browser in Linux, you need to have a `.desktop` file
+(link:{url-desktop-spec}[specification]).
+
+[source,toml]
+--------------------------------------------------------------------------------
+[Desktop Entry]
+Type=Application
+Version=1.0
+Name=urlhandler
+Comment=Open URLs with different commands
+TryExec=urlhandler
+Exec=urlhandler %u
+Terminal=false
+--------------------------------------------------------------------------------
+
+Save this in `~/.local/share/applications/urlhandler.desktop` and run
+`xdg-settings set default-web-browser urlhandler.desktop`. Congratulations, you
+are ready to go! 🥳