| 1 | #!/bin/sh |
| 2 | # waldl: search wallhaven.cc, pick wallpapers in remage, download them. |
| 3 | # Based on https://github.com/pystardust/waldl |
| 4 | # |
| 5 | # waldl [-s SORT] [-n PAGES] [-r WxH] [-d DIR] [QUERY...] |
| 6 | # |
| 7 | # No query = ask with aurora-run (or on the terminal). The thumbnails open in remage's grid in result |
| 8 | # order: mark with m (v = visual mark in the grid, M = invert), quit with q, the marked ones download |
| 9 | # to DIR/QUERY and open in remage (`:` -> "Set as wallpaper" or `setwall -m` to use one). |
| 10 | # WALLHAVEN_API_KEY (optional) is sent along, e.g. for your account's purity/blacklist settings. |
| 11 | |
| 12 | walldir="$HOME/pix/wallhaven" # downloads go to $walldir/<query>/ |
| 13 | max_pages=4 # 24 results per page |
| 14 | sorting=relevance # date_added relevance random views favorites toplist hot |
| 15 | atleast=1920x1080 # smallest resolution |
| 16 | quality=large # thumbnail size: small large original |
| 17 | |
| 18 | usage() { |
| 19 | sed -n '2,10s/^# \{0,1\}//p' "$0" |
| 20 | exit "${1:-0}" |
| 21 | } |
| 22 | |
| 23 | while getopts s:n:r:d:h opt; do |
| 24 | case $opt in |
| 25 | s) sorting=$OPTARG ;; |
| 26 | n) max_pages=$OPTARG ;; |
| 27 | r) atleast=$OPTARG ;; |
| 28 | d) walldir=$OPTARG ;; |
| 29 | h) usage ;; |
| 30 | *) usage 1 >&2 ;; |
| 31 | esac |
| 32 | done |
| 33 | shift $((OPTIND - 1)) |
| 34 | |
| 35 | # progress: stderr + one notification that is updated in place |
| 36 | nid="" |
| 37 | sh_info() { |
| 38 | printf 'waldl: %s\n' "$1" >&2 |
| 39 | nid=$(notify-send -a waldl -p ${nid:+-r "$nid"} "wallhaven" "$1" 2>/dev/null) |
| 40 | [ -n "$2" ] && exit "$2" |
| 41 | } |
| 42 | |
| 43 | for dep in remage curl jq; do |
| 44 | command -v "$dep" >/dev/null 2>&1 || sh_info "$dep not found, install it" 1 |
| 45 | done |
| 46 | |
| 47 | query="$*" |
| 48 | if [ -z "$query" ]; then |
| 49 | query=$(aurora-run -d -l 0 -p "search wallhaven: " </dev/null) |
| 50 | # aurora not running: ask on the terminal instead |
| 51 | [ $? -eq 2 ] && [ -t 0 ] && printf 'search wallhaven: ' >&2 && read -r query |
| 52 | fi |
| 53 | [ -z "$query" ] && exit 1 |
| 54 | |
| 55 | tmp=$(mktemp -d "${TMPDIR:-/tmp}/waldl.XXXXXX") || exit 1 |
| 56 | trap 'rm -rf "$tmp"' EXIT |
| 57 | trap 'exit 1' INT TERM HUP |
| 58 | mkdir "$tmp/thumbs" |
| 59 | |
| 60 | ##################### |
| 61 | ## search results ## |
| 62 | ##################### |
| 63 | |
| 64 | sh_info "searching \"$query\"..." |
| 65 | page=1 |
| 66 | while [ "$page" -le "$max_pages" ]; do |
| 67 | curl -sfG "https://wallhaven.cc/api/v1/search" \ |
| 68 | --data-urlencode "q=$query" \ |
| 69 | -d "page=$page" -d "atleast=$atleast" -d "sorting=$sorting" \ |
| 70 | ${WALLHAVEN_API_KEY:+-H "X-API-Key: $WALLHAVEN_API_KEY"} \ |
| 71 | -o "$tmp/page$page.json" & |
| 72 | page=$((page + 1)) |
| 73 | done |
| 74 | wait |
| 75 | |
| 76 | # id, resolution, thumbnail url, full url; pages in order, without the repeats random sorting gives |
| 77 | page=1 |
| 78 | while [ "$page" -le "$max_pages" ]; do |
| 79 | [ -s "$tmp/page$page.json" ] && |
| 80 | jq -r --arg q "$quality" '.data[]? | [.id, .resolution, .thumbs[$q], .path] | @tsv' "$tmp/page$page.json" |
| 81 | page=$((page + 1)) |
| 82 | done | awk -F '\t' '!seen[$1]++' > "$tmp/results" |
| 83 | |
| 84 | [ -s "$tmp/results" ] || sh_info "nothing found for \"$query\"" 1 |
| 85 | |
| 86 | ######################## |
| 87 | ## pick in remage ## |
| 88 | ######################## |
| 89 | |
| 90 | sh_info "caching $(wc -l < "$tmp/results") thumbnails..." |
| 91 | # named ID_WxH.ext so remage's status bar shows the real resolution, not the thumbnail's |
| 92 | while IFS="$(printf '\t')" read -r id res thumb full; do |
| 93 | printf 'url = "%s"\noutput = "%s/thumbs/%s_%s.%s"\n' "$thumb" "$tmp" "$id" "$res" "${thumb##*.}" |
| 94 | done < "$tmp/results" | curl -sfZ --parallel-max 16 -K - |
| 95 | |
| 96 | # -i keeps the result order, -p keeps these temp files out of the shared thumbnail cache |
| 97 | marked=$(awk -F '\t' -v d="$tmp/thumbs" '{ n = split($3, u, "."); print d "/" $1 "_" $2 "." u[n] }' "$tmp/results" | |
| 98 | while read -r f; do [ -f "$f" ] && printf '%s\n' "$f"; done | |
| 99 | remage -i -t -p -o --class waldl) |
| 100 | [ -z "$marked" ] && exit 0 |
| 101 | |
| 102 | ######################### |
| 103 | ## download ## |
| 104 | ######################### |
| 105 | |
| 106 | dest="$walldir/$query" |
| 107 | mkdir -p "$dest" || sh_info "can't create $dest" 1 |
| 108 | count=$(printf '%s\n' "$marked" | wc -l) |
| 109 | sh_info "downloading $count wallpaper(s)..." |
| 110 | printf '%s\n' "$marked" | while read -r f; do |
| 111 | f=${f##*/} |
| 112 | awk -F '\t' -v id="${f%%_*}" '$1 == id { printf "url = \"%s\"\nremote-name\n", $4 }' "$tmp/results" |
| 113 | done | curl -sfZ --skip-existing --output-dir "$dest" -K - |
| 114 | |
| 115 | sh_info "$count wallpaper(s) in $dest" |
| 116 | remage --sort mtime --reverse "$dest" |