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