Draft: Open URLs based on regular expressions

This commit is contained in:
tastytea 2022-04-18 19:58:52 +02:00
parent f8305131c8
commit 3e785d30bb
Signed by: tastytea
SSH Key Fingerprint: SHA256:FBkvrOlhq5use1XEttyUGT4bUTDVA1ar9SgIc9P03cM
1 changed files with 161 additions and 0 deletions

View File

@ -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:[<abbr title='Perl Compatible Regular Expressions'>PCRE</abbr>]
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} <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
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! 🥳