Compare commits

12 Commits

6 changed files with 172 additions and 212 deletions

View File

View File

@@ -1,5 +1,3 @@
# xdg-sanity
The `xdg-sanity` script is built to replace your default web browser in your 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 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 `xdg-open` and sends it to the appropriate application. For example, it will
@@ -16,43 +14,20 @@ AUR](https://aur.archlinux.org/packages/xdg-sanity).
Dependencies: Dependencies:
- `curl(1)` - `curl(1)`
- `xdg-utils(1)` or `handlr(1)` - `handlr(1)`
- `tomcat(1)` - [`tomcat(1)`](https://git.tebibyte.media/emma/tomcat) (optional; enables
[extensions](#extensions))
You can get `tomcat` [here](https://git.tebibyte.media/emma/tomcat)
Instructions: Instructions:
Clone this repository and move the `xdg-sanity` binary wherever your operating Clone this repository and move the `xdg-sanity` binary wherever your operating
system stores locally-installed binaries. This is usually `/usr/local/bin` or 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 `"$HOME/.local/bin/"` for your user. Make sure the installation location is in
`$PATH`. your `$PATH`.
Create an `xdg-sanity.desktop` file either manually or with `gendesk(1)`, Create an `xdg-sanity.desktop` file, placing it where your OS stores
placing it where your OS stores locally-installed `.desktop` files, which is locally-installed `.desktop` files, which is usually
usually `/usr/local/share/applications` or `$XDG_DATA_HOME/applications` for `/usr/local/share/applications` or `$XDG_DATA_HOME/applications` for your user.
your user. Set your default web browser to that `.desktop` file with Set your default web browser to that `.desktop` file using `handlr set`.
`xdg-settings(1)` or an equivalent.
### Configuration
This program uses [TOML](https://toml.io/en/v1.0.0) for its configuration. The
configuration file is set up like this:
```
$ cat $XDG_CONFIG_HOME/xdg-sanity.toml
[tools]
browser = "firefox"
xdg = "handlr launch"
```
The options available for `xdg` are `handlr launch` if you use `handlr(1)` and
`xdg-open` if you use `xdg-utils(1)`.
### Usage
`xdg-sanity [RESOURCE]`
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.
#### Extensions #### Extensions
@@ -61,28 +36,42 @@ Extensions are written using TOML and are stored in either
`/usr/local/share/xdg-sanity` when installed locally, or `/usr/local/share/xdg-sanity` when installed locally, or
`$XDG_DATA_HOME/xdg-sanity` for your user. `$XDG_DATA_HOME/xdg-sanity` for your user.
There are two types of extensions: MIME and replace. MIME extensions are parsed Extension support requires the installation of the `tomcat(1)` tool, which
first and replace the MIME type of the content being fetched. Replace extensions parses TOML for the command line.
change the URI passed to the command to another.
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 The type of the extension depends on the file name. MIME extensions should have
a name ending in `-mime.toml` and replace extensions should have a name ending in `.mime.toml`, replace extensions should have
`-replace.toml`. `.replace.toml`, and scheme extensions should end with `.scheme.toml`.
Here's what a MIME extension looks like: Here's what a MIME extension looks like:
``` ```
cat $XDG_DATA_HOME/xdg-sanity/youtube-mime.toml $ cat $XDG_DATA_HOME/xdg-sanity/youtube.mime.toml
[replace] [replace]
urls = [ "youtube.com", "youtu.be" ] urls = [ "youtube.com", "youtu.be" ]
[with] [with]
mime = "video/vnd.youtube.yt" mime = "video/vnd.youtube.yt"
``` ```
and here's what a replace extension looks like: what a replace extension looks like:
``` ```
cat $XDG_DATA_HOME/xdg-sanity/youtube-replace.toml $ cat $XDG_DATA_HOME/xdg-sanity/youtube.replace.toml
[replace] [replace]
urls = [ "youtube.com", "youtu.be" ] urls = [ "youtube.com", "youtu.be" ]
[with] [with]
url = "https://piped.mint.lgbt/" 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://"
```

View File

@@ -1,7 +0,0 @@
# xdg-sanity mime extension
[replace] # replaces these urls
urls = [ "youtube.com", "youtu.be" ]
[with] # replaces the mime type of the above
mime = "video/vnd.youtube.yt"

View File

@@ -1,118 +1,133 @@
#!/bin/sh #!/bin/sh
# Copyright (c) 20222023 Emma Tebibyte <emma@tebibyte.media>
# 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 set -e
argv0="$0" argv0="$0"
# grabs configuration files get_urls() {
CONFIG="$XDG_CONFIG_HOME"/xdg-sanity.toml i="0"
if ! test -e "$CONFIG"; then until ! tomcat replace.urls["$i"] "$file" >/dev/null 2>&1
touch "$CONFIG" do
CONFIG=/etc/xdg-sanity.toml URLS="$(printf "%s\n%s" \
if ! test -e "$CONFIG"; then "$URLS" \
exit 66 # sysexits(3) EX_NOINPUT "$(tomcat replace.urls["$i"] "$file")"
fi )"
fi
i="$(printf "%s+1\n" "$i" | bc)"
done
}
# check if usage is valid # check if usage is valid
if ! test -n "$1"; then if test -z "$1"; then
printf "Usage: %s [resource...]\n" "$argv0" 1>&2 printf "Usage: %s [resource...]\n" "$argv0" 1>&2
exit 64 # sysexits(3) EX_USAGE exit 64 # sysexits(3) EX_USAGE
fi fi
# check if we have curl(1) for dep in \
if ! command -v curl >/dev/null 2>&1; then curl \
printf "%s: Missing dependency: curl(1)\n" "$argv0" 1>&2 handlr
exit 71 # sysexits(3) EX_OSERR do
fi if ! command -v "$dep" >/dev/null 2>&1; then
printf "%s: Missing dependency: %s(1)\n" "$argv0" "$dep" 1>&2
# check if we have tomcat(1) exit 69 # sysexits(3) EX_UNAVAILABLE
if ! command -v tomcat >/dev/null 2>&1; then fi
printf "%s: Missing dependency: stoml(1)\n" "$argv0" 1>&2 done
exit 71 # sysexits(3) EX_OSERR
fi
# set the XDG_COMMAND
test -n "$XDG_COMMAND" || XDG_COMMAND="$(tomcat tools.xdg $CONFIG)"
! command -v handlr >/dev/null 2>&1 && ! command -v xdg-open >/dev/null 2>&1 \
&& XDG_COMMAND=false \
|| true
# check if we have a BROWSER # check if we have a BROWSER
test -n "$BROWSER" || BROWSER="$(tomcat tools.browser $CONFIG)" if test -z "$BROWSER"; then
if ! test -n "$BROWSER"; then printf "%s: \$BROWSER not filled.\n" "$argv0" 1>&2
printf "\ exit 71 # sysexits(3) EX_OSERR
%s: \$BROWSER not filled.
Please place the path to your preferred browser's executable in
$XDG_CONFIG_HOME/xdg-sanity.conf or /etc/xdg-sanity.conf
" "$argv0" 1>&2
exit 71 # sysexits(3) EX_OSERR
fi fi
while test -n "$1"; do while test -n "$1"; do
URL="$1" URL="$1"
# use curl(1) to write out the request header's content_type, # use curl(1) to write out the request header's content_type, strip everything
# strip everything after the first semicolon, # after the first semicolon, chop off any weird whitespace remnants
# chop off any weird whitespace remnants MIME="$(curl -Ls -o /dev/null -w '%{content_type}' "$1" | sed 's/\;.*//' \
MIME="$(curl -Ls -o /dev/null -w '%{content_type}' "$1" | sed 's/\;.*//' |\ | xargs echo)"
xargs echo)"
# get the pattern for the extensions to MATCH # get the URL with no scheme
MATCH=$(printf "%s\n" "$URL" | sed -ne 's/^h.\+\/\///p' |\ NO_SCHEME="$(printf "%s\n" "$URL" | sed -n 's/^h.\+\/\///p')"
sed -e 's/\/.*\+//g')
# run through MIME extensions # get the pattern for the extensions to MATCH
for file in \ MATCH="$(printf "%s\n" "$NO_SCHEME" | sed 's/\/.*\+//g')"
"$XDG_DATA_HOME"/xdg-sanity/*-mime.toml \
/usr/share/xdg-sanity/*-mime.toml \
/usr/local/share/xdg-sanity/*-mime.toml \
/dev/null
do
i=$(tomcat replace.urls "$file" | sed 's/ /\n/g' | xargs wc -l)
while ! [ "$i" = 0 ]; do
if [ "$MATCH" = "$(tomcat replace.urls[$i] $file)" ]; then
MIME=$(tomcat with.mime "$file")
fi
i=$(dc -e "$i 1 - p")
done
done
# and the replace extensions # get the non-domain of the URI for tacking onto the end of replaced URIs
for file in \ URI="$(printf "%s\n" "$NO_SCHEME" | sed -n 's/^[^/]*\///p')"
"$XDG_DATA_HOME"/xdg-sanity/*-replace.toml \
/usr/share/xdg-sanity/*-replace.toml \ # only check for extensions if tomcat(1) is installed
/usr/local/share/xdg-sanity/*-replace.toml \ if command -v tomcat >/dev/null 2>&1; then
/dev/null # run through MIME extensions
do for file in \
i=$(tomcat replace.urls "$file" | sed 's/ /\n/g' | xargs wc -l) "$XDG_DATA_HOME"/xdg-sanity/*.mime.toml \
while ! [ "$i" = 0 ]; do /usr/share/xdg-sanity/*.mime.toml \
if [ "$MATCH" = "$(tomcat replace.urls[$i] $file)" ]; then /usr/local/share/xdg-sanity/*.mime.toml
URL=$(tomcat with.url "$file") do
fi if test -e "$file"; then
i=$(dc -e "$i 1 - p") get_urls
done for url in $URLS; do
done 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 # these commands may fail; this is intentional
if [ "$MIME" = "text/html" ]; then if [ "$MIME" = "text/html" ]; then
"$BROWSER" "$URL" "$BROWSER" "$URL"
else else
case "$(command -v $XDG_COMMAND)" in handlr launch "$MIME" -- "$URL"
*/handlr ) fi
"XDG_COMMAND" "$MIME" -- "$URL" shift
;;
*/xdg-open )
"$(xdg-mime query default $MIME)" "$URL"
;;
false )
exit 69 # sysexits(3) EX_UNAVAILABLE
;;
esac
fi
shift
done done
exit 0 exit 0

29
xdg-sanity.1 Normal file
View File

@@ -0,0 +1,29 @@
.TH XDG-SANITY 1
.SH NAME
.B xdg-sanity
\(en sanely handle HTTP/S URIs.
.SH SYNOPSIS
.B xdg-sanity [URI...]
.SH DESCRIPTION
The xdg-sanity tool stands in as the users web browser, handling links as they
are passed to it.
.SH EXAMPLES
Given a remote PNG file, the following command will open that file using the
users configured handler for that MIME type:
xdg-sanity https://example.com/image.png
.SH AUTHOR
Written by Emma Tebibyte.
.SH REPORTING BUGS
Any bugs may be reported on the bug tracker at
<https://git.tebibyte.media/emma/xdg-sanity>.
.SH COPYRIGHT
Copyright © 2023 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it. There is NO
WARRANTY, to the extent permitted by law.
.SH SEE ALSO
.BR xdg-open(1)\
,
.BR xdg-mime(1)

View File

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