{
  pkgs,
  writeShellApplication,
}:
writeShellApplication
{
  # Originally from: https://github.com/scawp/Steam-Deck.Mount-External-Drive/

  name = "auto-mount";

  runtimeInputs = [pkgs.steam];

  text = ''
    set -euo pipefail

    # Originally from https://serverfault.com/a/767079

    # This script is called from our systemd unit file to mount or unmount
    # a USB drive.

    usage()
    {
        echo "Usage: $0 {add|remove} device_name (e.g. sdb1)"
        exit 1
    }

    if [[ $# -ne 2 ]]; then
        usage
    fi

    ACTION=$1
    DEVBASE=$2
    DEVICE="/dev/''${DEVBASE}"

    # Shared between this and the auto-mount script to ensure we're not double-triggering nor automounting while formatting
    # or vice-versa.
    MOUNT_LOCK="/home/lillian/lock/jupiter-automount-''${DEVBASE//\/_}.lock"

    # Obtain lock
    exec 9<>"$MOUNT_LOCK"
    if ! flock -n 9; then
        echo "$MOUNT_LOCK is active: ignoring action $ACTION"
        # Do not return a success exit code: it could end up putting the service in 'started' state without doing the mount
        # work (further start commands will be ignored after that)
        exit 1
    fi

    # Wait N seconds for steam
    wait_steam()
    {
        local i=0
        local wait=$1
        echo "Waiting up to $wait seconds for steam to load"
        while ! pgrep -x steamwebhelper &>/dev/null && (( i++ < wait )); do
            sleep 1
        done
    }

    send_steam_url()
    {
        local command
        command="$1"
        local arg
        arg="$2"
        local encoded
        encoded=$(urlencode "$arg")
        if pgrep -x "steam" > /dev/null; then
            # TODO use -ifrunning and check return value - if there was a steam process and it returns -1, the message wasn't sent
            # need to retry until either steam process is gone or -ifrunning returns 0, or timeout i guess
            echo "Sent URL to steam: steam://''${command}/''${arg} (steam://''${command}/''${encoded})" >> /home/lillian/steam.txt
            systemd-run -M 1000@ --user --collect --wait sh -c "${pkgs.steam}/bin/steam steam://''${command}/''${encoded@Q}"
        else
            echo "Could not send steam URL steam://''${command}/''${arg} (steam://''${command}/''${encoded}) -- steam not running"
        fi
    }

    # From https://gist.github.com/HazCod/da9ec610c3d50ebff7dd5e7cac76de05
    urlencode()
    {
        [ -z "$1" ] || echo -n "$@" | hexdump -v -e '/1 "%02x"' | sed 's/\(..\)/%\1/g'
    }

    do_mount()
    {
        declare -i ret
        # NOTE: these values are ABI, since they are sent to the Steam client
        # shellcheck disable=SC2034
        readonly FSCK_ERROR=1
        # shellcheck disable=SC2034
        readonly MOUNT_ERROR=2

        # Get info for this drive: $ID_FS_LABEL, and $ID_FS_TYPE
        dev_json=$(lsblk -o PATH,LABEL,FSTYPE --json -- "$DEVICE" | jq '.blockdevices[0]')
        ID_FS_LABEL=$(jq -r '.label | select(type == "string")' <<< "$dev_json")
        ID_FS_TYPE=$(jq -r '.fstype | select(type == "string")' <<< "$dev_json")

        # Global mount options
        OPTS="rw,noatime"

        # File system type specific mount options
        #if [[ ''${ID_FS_TYPE} == "vfat" ]]; then
        #    OPTS+=",users,gid=100,umask=000,shortname=mixed,utf8=1,flush"
        #fi

            case "''${ID_FS_TYPE}" in
                    "ntfs")
                echo "FSType is NTFS"
                #Extra Opts don't seem necessary anymore? add if required
                #OPTS+=""
                        ;;
                    "exfat")
                echo "FSType is exFat"
                        #OPTS+=",users,gid=100,umask=000,shortname=mixed,utf8=1,flush"
                        ;;
                    "btrfs")
                echo "FSType is btrfs"
                        ;;
            "ext4")
                        echo "FSType is ext4"
                #exit 2
                ;;
                    *)
                        echo "Error mounting ''${DEVICE}: unsupported fstype: ''${ID_FS_TYPE} - ''${dev_json}"
                rm "''${MOUNT_LOCK}"
                exit 2
                        ;;
            esac

        # Prior to talking to udisks, we need all udev hooks (we were started by one) to finish, so we know it has knowledge
        # of the drive.  Our own rule starts us as a service with --no-block, so we can wait for rules to settle here
        # safely.
        #if ! udevadm settle; then
        #  echo "Failed to wait for \`udevadm settle\`"
        #  exit 1
        #fi

        # Ask udisks to auto-mount. This needs a version of udisks that supports the 'as-user' option.
        ret=0
        reply=$(busctl call --allow-interactive-authorization=false --expect-reply=true --json=short   \
                    org.freedesktop.UDisks2                                                            \
                    /org/freedesktop/UDisks2/block_devices/"''${DEVBASE}"                                \
                    org.freedesktop.UDisks2.Filesystem                                                 \
                    Mount 'a{sv}' 3                                                                    \
                        as-user s lillian                                                                   \
                        auth.no_user_interaction b true                                                  \
                        options                  s "$OPTS") || ret=$?

        if (( ret != 0 )); then
            # send_steam_url "system/devicemountresult" "''${DEVBASE}/''${MOUNT_ERROR}"
            echo "Error mounting ''${DEVICE} (status = $ret)"
            exit 1
        fi

        # Expected reply is of the format
        #  {"type":"s","data":["/run/media/lillian/home"]}
        mount_point=$(jq -r '.data[0] | select(type == "string")' <<< "$reply" || true)
        if [[ -z $mount_point ]]; then
            echo "Error when mounting ''${DEVICE}: udisks returned success but could not parse reply:"
            echo "---"$'\n'"$reply"$'\n'"---"
            exit 1
        fi

        if [[ ''${ID_FS_TYPE} == "exfat" ]]; then
            echo "exFat does not support symlinks, do not add library to Steam"
            exit 0
        fi

        # Create a symlink from /run/media to keep compatibility with apps
        # that use the older mount point (for SD cards only).
        case "''${DEVBASE}" in
            mmcblk0p*)
                if [[ -z "''${ID_FS_LABEL}" ]]; then
                    old_mount_point="/run/media/''${DEVBASE}"
                else
                    old_mount_point="/run/media/''${mount_point##*/}"
                fi
                if [[ ! -d "''${old_mount_point}" ]]; then
                    rm -f -- "''${old_mount_point}"
                    ln -s -- "''${mount_point}" "''${old_mount_point}"
                fi
                ;;
        esac

        echo "**** Mounted ''${DEVICE} at ''${mount_point} ****"

        if [ -f "''${mount_point}/libraryfolder.vdf" ]; then
            echo " send_steam_url \"addlibraryfolder\" \"''${mount_point}\""
            # send_steam_url "addlibraryfolder" "''${mount_point}"
        else
            #TODO check permissions are 1000  when creating new SteamLibrary
            mkdir -p "''${mount_point}/SteamLibrary"
            chown lillian:users "''${mount_point}/SteamLibrary"
            # send_steam_url "addlibraryfolder" "''${mount_point}/SteamLibrary"
        fi
    }

    do_unmount()
    {
        local mount_point
        mount_point=$(findmnt -fno TARGET "''${DEVICE}" || true)
        if [[ -n $mount_point ]]; then
            # Remove symlink to the mount point that we're unmounting
            find /run/media -maxdepth 1 -xdev -type l -lname "''${mount_point}" -exec rm -- {} \;
        else
            # If we don't know the mount point then remove all broken symlinks
            find /run/media -maxdepth 1 -xdev -xtype l -exec rm -- {} \;
        fi
    }

    do_retrigger()
    {
        local mount_point
        mount_point=$(findmnt -fno TARGET "''${DEVICE}" || true)
        [[ -n $mount_point ]] || return 0

        # In retrigger mode, we want to wait a bit for steam as the common pattern is starting in parallel with a retrigger
        wait_steam 10
        # This is a truly gnarly way to ensure steam is ready for commands.
        # TODO literally anything else
        sleep 6
        # send_steam_url "addlibraryfolder" "''${mount_point}"
    }

    case "''${ACTION}" in
        add)
            do_mount
            ;;
        remove)
            do_unmount
            ;;
        retrigger)
            do_retrigger
            ;;
        *)
            usage
            ;;
    esac
  '';
}