#!/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) # Refactored to work with bemenu by Marty Oehme, 2021 (@martyo@matrix.org on Matrix) # 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 10}" 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}" xdg-open "$path" &