#!/usr/bin/env bash
# Both standalone script and qutebrowser userscript that opens a rofi menu with
# all files from the download directory and opens the selected file. It works
# both as a userscript and a standalone script that is called from outside of
# qutebrowser.
#
# Suggested keybinding (for "show downloads"):
# spawn --userscript ~/.config/qutebrowser/open_download
#     sd
#
# Requirements:
#  - rofi (in a recent version), or bemenu
#  - xdg-open and xdg-mime
#  - You should configure qutebrowser to download files to a single directory
#  - It comes in handy if you enable downloads.remove_finished. If you want to
#    see the recent downloads, just press "sd".
#
# Thorsten Wißmann, 2015 (thorsten` on Libera Chat)
# Marty Oehme, 2022 (@martyo@matrix.org on Matrix)
#   refactored to work with bemenu
#   fixed for files with spaces
# Any feedback is welcome!

set -e

# open a file from the download directory using rofi
DOWNLOAD_DIR=${DOWNLOAD_DIR:-${QUTE_DOWNLOAD_DIR:-$HOME/downloads}}
# the name of the rofi-like command
if [ -n "$ROFI_CMD" ]; then
	:
elif command -v rofi >/dev/null 2>&1; then
	ROFI_CMD="rofi"
	ROFI_ARGS=${ROFI_ARGS:-(
    -monitor -2 # place above window
    -location 6 # aligned at the bottom
    -width 100  # use full window width
    -i
    -no-custom
    -format i # make rofi return the index
    -l 10
    -p 'Open download:' -dmenu
)}
elif command -v bemenu >/dev/null 2>&1; then
	ROFI_CMD="bemenu"
	ROFI_ARGS="${ROFI_ARGS:--il 20}"
fi

msg() {
	local cmd="$1"
	shift
	local msg="$*"
	if [ -z "$QUTE_FIFO" ]; then
		echo "$cmd: $msg" >&2
	else
		echo "message-$cmd '${msg//\'/\\\'}'" >>"$QUTE_FIFO"
	fi
}
die() {
	msg error "$*"
	if [ -n "$QUTE_FIFO" ]; then
		# when run as a userscript, the above error message already informs the
		# user about the failure, and no additional "userscript exited with status
		# 1" is needed.
		exit 0
	else
		exit 1
	fi
}

if ! [ -d "$DOWNLOAD_DIR" ]; then
	die "Download directory »$DOWNLOAD_DIR« not found!"
fi
if ! command -v "${ROFI_CMD}" >/dev/null; then
	die "Rofi command »${ROFI_CMD}« not found in PATH!"
fi

crop-first-column() {
	cut -d' ' -f2-
}

ls-files() {
	# add the slash at the end of the download dir enforces to follow the
	# symlink, if the DOWNLOAD_DIR itself is a symlink
	# sort by newest
	find "${DOWNLOAD_DIR}/" -maxdepth 1 -type f -printf "%T+ %f\n" | sort -r
}

mapfile -t entries < <(ls-files)

# we need to manually check that there are items, because rofi doesn't show up
# if there are no items and -no-custom is passed to rofi.
if [ "${#entries[@]}" -eq 0 ]; then
	die "Download directory »${DOWNLOAD_DIR}« empty"
fi

line=$(printf '%s\n' "${entries[@]}" |
	crop-first-column |
	$ROFI_CMD "${ROFI_ARGS[@]}") || true
if [ -z "$line" ]; then
	exit 0
fi

msg info "file is $line"
path="$DOWNLOAD_DIR/$line"
filetype=$(xdg-mime query filetype "$path")
application=$(xdg-mime query default "$filetype")

if [ -z "$application" ]; then
	die "Do not know how to open »$line« of type $filetype"
fi

msg info "Opening »$line« (of type $filetype) with ${application%.desktop}"

if type open >/dev/null 2>&1; then
	open "$path" &
else
	xdg-open "$path" &
fi