Skip to content

Instantly share code, notes, and snippets.

@daninsky1
Last active February 23, 2025 19:49
Show Gist options
  • Save daninsky1/e773b240ad0139cf8cacb5ba57e1da12 to your computer and use it in GitHub Desktop.
Save daninsky1/e773b240ad0139cf8cacb5ba57e1da12 to your computer and use it in GitHub Desktop.
Install PWAs on Linux and Unix-like systems.
#!/bin/sh
# Public domain.
VERSION=0.1
show_help() {
cat <<END
Version $VERSION
Usage: $0 [OPTION]
Creates a web app launcher for Chromium based browsers.
Options:
-i <APP_NAME> <URL> [BROWSER] Install PWA app for URL.
-u <APP_NAME> Uninstall PWA app.
-l List PWAs installed with this script in
'\${HOME}/.local/share/applications'.
-h Show this help message and exit.
Arguments:
URL Web address for the PWA, e.g., https://example.com.
APP_NAME Specific name of the application, e.g., "Example App".
BROWSER Optional Chromium based browser executable (default: chromium).
END
}
create_app_id() {
echo "$1" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | awk '{print $1"-pwa"}'
}
DESKTOP_MENU_PATH="${HOME}/.local/share/applications"
FAVICON_SIZES="256 128 96 64 48 32 24 16"
install() {
MIN_ARGS="2"
MAX_ARGS="3"
if [ $# -ne "$MIN_ARGS" ] && [ $# -ne "$MAX_ARGS" ]; then
echo "Error: Expected $MIN_ARGS or $MAX_ARGS arguments, but got $#." >&2
show_help
exit 1
fi
BROWSER=$3
if [ -z "$BROWSER" ]; then
BROWSER=chromium
fi
BROWSER_CMD=$(command -v "$BROWSER")
if [ -z "$BROWSER_CMD" ]; then
echo "Error: '${BROWSER}' is not installed." >&2
exit 1
fi
URL=$2
APP_NAME=$1
DOMAIN=$(echo "$URL" | awk -F/ '{print $3}')
APP_ID=$(create_app_id "$APP_NAME")
mkdir -p "$DESKTOP_MENU_PATH"
DESKTOP_MENU_FILE="${DESKTOP_MENU_PATH}/${APP_ID}.desktop"
cat > "$DESKTOP_MENU_FILE" <<END
#!/usr/bin/env xdg-open
[Desktop Entry]
Version=1.0
Terminal=false
Type=Application
Name=${APP_NAME}
Exec=${BROWSER_CMD} --profile-directory=Default --app=${URL}
Icon=${APP_ID%.*}
StartupWMClass=${DOMAIN}
END
chmod +x "$DESKTOP_MENU_FILE"
if command -v update-desktop-database > /dev/null 2>&1; then
update-desktop-database "$DESKTOP_MENU_PATH"
fi
echo "created: '${DESKTOP_MENU_FILE}'"
for size in $FAVICON_SIZES; do
(
FAVICON_SERVICE_URL="https://www.google.com/s2/favicons?domain=${URL}&sz=${size}"
TMP_ICON=$(mktemp /tmp/tmp.XXXXXXXX.png)
curl -sLo "$TMP_ICON" "$FAVICON_SERVICE_URL"
FILE_FMT=$(file --brief "$TMP_ICON")
if ! echo "$FILE_FMT" | grep -q "PNG image data"; then
echo "${size}x${size} icon must be a PNG image data instead got: ${FILE_FMT}."
rm -f "$TMP_ICON"
continue
fi
xdg-icon-resource install --size "$size" "$TMP_ICON" "$APP_ID"
) &
done
echo "installed icons '${APP_ID}' successfully."
wait
echo "Web app '${APP_NAME}' created successfully!"
}
uninstall() {
NUM_ARGS="1"
if [ $# -ne "$NUM_ARGS" ]; then
echo "Error: Expected ${NUM_ARGS} arguments, but got $#." >&2
show_help
exit 1
fi
APP_NAME=$1
APP_ID=$(create_app_id "$APP_NAME")
DESKTOP_MENU_FILE="${DESKTOP_MENU_PATH}/${APP_ID}.desktop"
if [ ! -e "$DESKTOP_MENU_FILE" ]; then
echo "PWA app '${APP_NAME}' is not installed."
exit 1
fi
rm -f "$DESKTOP_MENU_FILE"
for size in $FAVICON_SIZES; do
xdg-icon-resource uninstall --size "$size" "$APP_ID"
done
echo "removed: '${DESKTOP_MENU_FILE}'"
echo "removed icons '${APP_ID}' successfully."
echo "Web app '${APP_NAME}' uninstalled successfully!"
}
list() {
if [ ! -d "$DESKTOP_MENU_PATH" ]; then return 0; fi
for desktop_file in "${DESKTOP_MENU_PATH}/*-pwa.desktop"; do
echo " - $(grep -m 1 "^Name=" "$desktop_file" | cut -d '=' -f2)"
done
}
while getopts "iulh" opts; do
case "$opts" in
i) shift $((OPTIND - 1)); install "$@"; exit 0 ;;
u) shift $((OPTIND - 1)); uninstall "$@"; exit 0 ;;
l) list; exit 0 ;;
h) show_help ; exit 0 ;;
*) show_help; exit 1 ;;
esac
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment