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
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
@@ -16,43 +14,20 @@ AUR](https://aur.archlinux.org/packages/xdg-sanity).
Dependencies:
- `curl(1)`
- `xdg-utils(1)` or `handlr(1)`
- `tomcat(1)`
You can get `tomcat` [here](https://git.tebibyte.media/emma/tomcat)
- `handlr(1)`
- [`tomcat(1)`](https://git.tebibyte.media/emma/tomcat) (optional; enables
[extensions](#extensions))
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`.
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`.
Create an `xdg-sanity.desktop` file either manually or with `gendesk(1)`,
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 with
`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.
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`.
#### Extensions
@@ -61,28 +36,42 @@ Extensions are written using TOML and are stored in either
`/usr/local/share/xdg-sanity` when installed locally, or
`$XDG_DATA_HOME/xdg-sanity` for your user.
There are two types of extensions: MIME and replace. 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.
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` and replace extensions should have
`-replace.toml`.
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
$ cat $XDG_DATA_HOME/xdg-sanity/youtube.mime.toml
[replace]
urls = [ "youtube.com", "youtu.be" ]
[with]
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]
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://"
```

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,116 +1,131 @@
#!/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
argv0="$0"
# grabs configuration files
CONFIG="$XDG_CONFIG_HOME"/xdg-sanity.toml
if ! test -e "$CONFIG"; then
touch "$CONFIG"
CONFIG=/etc/xdg-sanity.toml
if ! test -e "$CONFIG"; then
exit 66 # sysexits(3) EX_NOINPUT
fi
fi
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 -n "$1"; then
if test -z "$1"; then
printf "Usage: %s [resource...]\n" "$argv0" 1>&2
exit 64 # sysexits(3) EX_USAGE
fi
# check if we have curl(1)
if ! command -v curl >/dev/null 2>&1; then
printf "%s: Missing dependency: curl(1)\n" "$argv0" 1>&2
exit 71 # sysexits(3) EX_OSERR
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
# check if we have tomcat(1)
if ! command -v tomcat >/dev/null 2>&1; then
printf "%s: Missing dependency: stoml(1)\n" "$argv0" 1>&2
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
done
# check if we have a BROWSER
test -n "$BROWSER" || BROWSER="$(tomcat tools.browser $CONFIG)"
if ! test -n "$BROWSER"; then
printf "\
%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
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)"
# 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" "$URL" | sed -ne 's/^h.\+\/\///p' |\
sed -e 's/\/.*\+//g')
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 \
/dev/null
"$XDG_DATA_HOME"/xdg-sanity/*.mime.toml \
/usr/share/xdg-sanity/*.mime.toml \
/usr/local/share/xdg-sanity/*.mime.toml
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")
if test -e "$file"; then
get_urls
for url in $URLS; do
if [ "$MATCH" = "$url" ]; then
MIME="$(tomcat with.mime "$file")"
fi
i=$(dc -e "$i 1 - p")
done
fi
done
# and the replace extensions
# 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 \
/dev/null
"$XDG_DATA_HOME"/xdg-sanity/*.replace.toml \
/usr/share/xdg-sanity/*.replace.toml \
/usr/local/share/xdg-sanity/*.replace.toml
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
URL=$(tomcat with.url "$file")
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
i=$(dc -e "$i 1 - p")
done
done
fi
# these commands may fail; this is intentional
if [ "$MIME" = "text/html" ]; then
"$BROWSER" "$URL"
else
case "$(command -v $XDG_COMMAND)" in
*/handlr )
"XDG_COMMAND" "$MIME" -- "$URL"
;;
*/xdg-open )
"$(xdg-mime query default $MIME)" "$URL"
;;
false )
exit 69 # sysexits(3) EX_UNAVAILABLE
;;
esac
handlr launch "$MIME" -- "$URL"
fi
shift
done

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