diff --git a/LICENSE b/COPYING similarity index 100% rename from LICENSE rename to COPYING diff --git a/README.md b/README.md index 80f87be..e31533e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -# xdg-sanity - The `xdg-sanity` script is built to replace your default web browser in your desktop/XDG settings. It intercepts http/s URIs sent to the default browser by `xdg-open` and sends it to the appropriate application. For example, it will @@ -7,28 +5,73 @@ send `image/jpeg` MIME type files to your image viewer. ## Installation -### Arch +### Arch Linux I maintain a package [on the AUR](https://aur.archlinux.org/packages/xdg-sanity). ### From Source -First, make sure you have `curl(1)` and `handlr(1)` installed. Then, clone this -repository and move the `xdg-sanity/` folder into `/etc` and `xdg-sanity.sh` to -`xdg-sanity` wherever your operating system stores locally-installed binaries. -This is usually `/usr/local/bin`. Make sure the installation location is in your -`$PATH`. +Dependencies: +- `curl(1)` +- `handlr(1)` +- [`tomcat(1)`](https://git.tebibyte.media/emma/tomcat) (optional; enables +[extensions](#extensions)) -Create a `xdg-sanity.desktop` file either manually or with `gendesk(1)`, -placing it, also, where your OS stores locally-installed `.desktop` files, -usually `/usr/local/applications`. Set your default web browser to that -`.desktop` file. +Instructions: +Clone this repository and move the `xdg-sanity` binary wherever your operating +system stores locally-installed binaries. This is usually `/usr/local/bin/` or +`"$HOME/.local/bin/"` for your user. Make sure the installation location is in +your `$PATH`. -Add your default web browser to `/etc/xdg-sanity/xdg-sanity.conf` so the -script can forward links to it. +Create an `xdg-sanity.desktop` file, placing it where your OS stores +locally-installed `.desktop` files, which is usually +`/usr/local/share/applications` or `$XDG_DATA_HOME/applications` for your user. +Set your default web browser to that `.desktop` file using `handlr set`. -### Usage +#### Extensions -Open links from applications outside your web browser as normal. Alternatively, -you can call `xdg-sanity` directly with the only argument accepted being a URI. \ No newline at end of file +Extensions are written using TOML and are stored in either +`/usr/share/xdg-sanity` when installed from a package manager, +`/usr/local/share/xdg-sanity` when installed locally, or +`$XDG_DATA_HOME/xdg-sanity` for your user. + +Extension support requires the installation of the `tomcat(1)` tool, which +parses TOML for the command line. + +There are three kinds of extensions: MIME, replace, and scheme. MIME extensions +are parsed first and replace the MIME type of the content being fetched. Replace +extensions change the URI passed to the command to another. Scheme extensions +replace the protocol by which the URI hostname is being accessed. + +The type of the extension depends on the file name. MIME extensions should have +a name ending in `.mime.toml`, replace extensions should have +`.replace.toml`, and scheme extensions should end with `.scheme.toml`. + +Here's what a MIME extension looks like: +``` +$ cat $XDG_DATA_HOME/xdg-sanity/youtube.mime.toml +[replace] +urls = [ "youtube.com", "youtu.be" ] + +[with] +mime = "video/vnd.youtube.yt" +``` +what a replace extension looks like: +``` +$ cat $XDG_DATA_HOME/xdg-sanity/youtube.replace.toml +[replace] +urls = [ "youtube.com", "youtu.be" ] + +[with] +url = "https://piped.mint.lgbt/" +``` +and what a scheme extension looks like: +``` +$ cat $XDG_DATA_HOME/xdg-sanity/spotify.scheme.toml +[replace] +urls = [ "spotify.com" ] + +[with] +scheme = "spotify://" +``` diff --git a/xdg-sanity b/xdg-sanity new file mode 100755 index 0000000..8d4724f --- /dev/null +++ b/xdg-sanity @@ -0,0 +1,133 @@ +#!/bin/sh + +# Copyright (c) 2022–2023 Emma Tebibyte +# SPDX-License-Identifier: AGPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License along +# with this program. If not, see https://www.gnu.org/licenses/. + +set -e + +argv0="$0" + +get_urls() { + i="0" + until ! tomcat replace.urls["$i"] "$file" >/dev/null 2>&1 + do + URLS="$(printf "%s\n%s" \ + "$URLS" \ + "$(tomcat replace.urls["$i"] "$file")" + )" + + i="$(printf "%s+1\n" "$i" | bc)" + done +} + +# check if usage is valid +if test -z "$1"; then + printf "Usage: %s [resource...]\n" "$argv0" 1>&2 + exit 64 # sysexits(3) EX_USAGE +fi + +for dep in \ + curl \ + handlr +do + if ! command -v "$dep" >/dev/null 2>&1; then + printf "%s: Missing dependency: %s(1)\n" "$argv0" "$dep" 1>&2 + exit 69 # sysexits(3) EX_UNAVAILABLE + fi +done + +# check if we have a BROWSER +if test -z "$BROWSER"; then + printf "%s: \$BROWSER not filled.\n" "$argv0" 1>&2 + exit 71 # sysexits(3) EX_OSERR +fi + +while test -n "$1"; do + URL="$1" + + # use curl(1) to write out the request header's content_type, strip everything + # after the first semicolon, chop off any weird whitespace remnants + MIME="$(curl -Ls -o /dev/null -w '%{content_type}' "$1" | sed 's/\;.*//' \ + | xargs echo)" + + # get the URL with no scheme + NO_SCHEME="$(printf "%s\n" "$URL" | sed -n 's/^h.\+\/\///p')" + + # get the pattern for the extensions to MATCH + MATCH="$(printf "%s\n" "$NO_SCHEME" | sed 's/\/.*\+//g')" + + # get the non-domain of the URI for tacking onto the end of replaced URIs + URI="$(printf "%s\n" "$NO_SCHEME" | sed -n 's/^[^/]*\///p')" + + # only check for extensions if tomcat(1) is installed + if command -v tomcat >/dev/null 2>&1; then + # run through MIME extensions + for file in \ + "$XDG_DATA_HOME"/xdg-sanity/*.mime.toml \ + /usr/share/xdg-sanity/*.mime.toml \ + /usr/local/share/xdg-sanity/*.mime.toml + do + if test -e "$file"; then + get_urls + for url in $URLS; do + if [ "$MATCH" = "$url" ]; then + MIME="$(tomcat with.mime "$file")" + fi + done + fi + done + + # then replace extensions + for file in \ + "$XDG_DATA_HOME"/xdg-sanity/*.replace.toml \ + /usr/share/xdg-sanity/*.replace.toml \ + /usr/local/share/xdg-sanity/*.replace.toml + do + if test -e "$file"; then + get_urls + for url in $URLS; do + if [ "$MATCH" = "$url" ]; then + URL="$(tomcat with.url "$file")$URI" + fi + done + fi + done + + # and the scheme extensions + for file in \ + "$XDG_DATA_HOME"/xdg-sanity/*.scheme.toml \ + /usr/share/xdg-sanity/*.scheme.toml \ + /usr/local/share/xdg-sanity/*.scheme.toml + do + get_urls + for url in $URLS; do + if [ "$URL" = "$url" ]; then + URL="$(tomcat with.scheme "$file")$MATCH" + fi + done + done + fi + + # these commands may fail; this is intentional + if [ "$MIME" = "text/html" ]; then + "$BROWSER" "$URL" + else + handlr launch "$MIME" -- "$URL" + fi + shift +done + +exit 0 diff --git a/xdg-sanity.sh b/xdg-sanity.sh deleted file mode 100755 index 3ee015c..0000000 --- a/xdg-sanity.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/sh - -INPUT=$(echo $1) -echo "Loading configuration..." -CONFIG=$(cat /etc/xdg-sanity/xdg-sanity.conf) -BROWSER=$(echo $CONFIG | sed -ne 's/^browser *= *//p') - -if [ "$BROWSER" = "" ] -then -echo "Please place the path to your default browser's executable in /etc/xdg-sanity/xdg-sanity.conf" -exit -else -echo "Found default browser $BROWSER" -fi - -echo "Loading extensions..." -for EXT in /etc/xdg-sanity/extensions/*.sh -do - -if [ "$EXT" = "/etc/xdg-sanity/extensions/*.sh" ] -then -echo "No extensions to load" -else - -for EXT in /etc/xdg-sanity/extensions/*.sh -do -TYPE=$(cat $EXT | sed -ne 's/^# EXT-TYPE=//p' | tr -d '\n') -echo "Found $TYPE extension $EXT" - -if [ "$TYPE" = "replace" ] -then -echo "Modifying $INPUT..." -INPUT=$($EXT "$INPUT") -echo "Got $INPUT" - -else -if [ "$TYPE" = "mime" ] -then -echo "Modifying MIME type..." -MIME=$($EXT "$INPUT") -echo "Got $MIME" - -fi -fi - -done -fi - -done - -if [ "$MIME" = "" ] || [ "$MIME" = "$1" ] || [ "$MIME" = "$INPUT" ] -then -echo "Determining MIME type of $INPUT:" -# Determines HTTP code, might use for something else? -# CODE=$(curl -fLIs "$INPUT" | sed -ne 's/ [[:space:]]*$//p' | sed -ne 's|^HTTP/.\+ ||p') -MIME=$(curl -fLIs "$INPUT" | sed -ne 's/^[cC]ontent-[tT]ype: //p' | sed -e 's/;.\+//p' | tail -n1 | tr -d '\r') -echo $MIME -fi - -if [ "$MIME" = "text/html" ] -then -$BROWSER $INPUT - -else -handlr launch "$MIME" -- "$INPUT" -fi \ No newline at end of file diff --git a/xdg-sanity/extensions/teddit-mime.sample b/xdg-sanity/extensions/teddit-mime.sample deleted file mode 100755 index 74908ee..0000000 --- a/xdg-sanity/extensions/teddit-mime.sample +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -# EXT-TYPE=mime - -TEST=$(echo $1 | sed -ne 's/^h.\+\/\///p' | sed -e 's/\/.*\+//g') - -if [ "$TEST" = "teddit.net" ] -then -echo "text/html" -else -echo $1 -fi \ No newline at end of file diff --git a/xdg-sanity/extensions/youtube-replace b/xdg-sanity/extensions/youtube-replace deleted file mode 100755 index e0276d2..0000000 --- a/xdg-sanity/extensions/youtube-replace +++ /dev/null @@ -1,3 +0,0 @@ -# EXT-TYPE=replace - -replace youtube.com or youtu.be with piped.mint.lgbt \ No newline at end of file diff --git a/xdg-sanity/extensions/youtube-replace.sample b/xdg-sanity/extensions/youtube-replace.sample deleted file mode 100755 index a1fd473..0000000 --- a/xdg-sanity/extensions/youtube-replace.sample +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -# EXT-TYPE=replace - -TEST=$(echo $1 | sed -ne 's/^h.\+\/\///p' | sed -e 's/\/.*\+//g') - -if [ "$TEST" = "youtube.com" ] -then -echo $1 | sed -ne 's/youtube.com/piped.mint.lgbt/p' -else -echo $1 -fi diff --git a/xdg-sanity/xdg-sanity.conf b/xdg-sanity/xdg-sanity.conf deleted file mode 100644 index 1acbb9a..0000000 --- a/xdg-sanity/xdg-sanity.conf +++ /dev/null @@ -1 +0,0 @@ -browser =