blog/content/posts/regex-based-url-opener.adoc

5.8 KiB
Raw Blame History


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 ---

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 in my dotfiles repo.

#!/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} <URL> …"
    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 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 we later use, load the PCRE module and set the default browser.

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.

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 Zsh functions directory of my dotfiles repo. Put them anywhere in your ${fpath}. Learn more from the zshmisc man-page or the online documentation. Or you could just put them inside the script, like this for example:

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}
}

Dont 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 (specification).

[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! 🥳