imsh-shot.sh (5097B)
1 #!/usr/bin/env bash 2 3 argv0="imsh-shot" 4 5 usage() { 6 cat <<EOF 7 $argv0 - Capture and optionally upload a screenshot to an imsh server 8 9 Usage: $argv0 target [options...] 10 11 Targets: 12 active 13 Currently active window. 14 15 screen 16 All visible outputs. 17 18 output 19 Currently active output. 20 21 area 22 Manually select a region or window. 23 24 Options: 25 -u, --upload 26 Uploads the screenshot to imsh. 27 28 -a, --api-key=key|@file|%cmd 29 API key for uploading to imsh. 30 Prefix with "@" to read from a file. 31 Prefix with "%" to run a command. 32 33 -e, --endpoint=url 34 The imsh endpoint to upload to. 35 Defaults to https://scrn.is/api/v1/upload 36 37 -o, --output=path-pattern 38 Path to write captured screenshot to. Gets passed through date and 39 supports the same format strings. 40 41 -U, --utc 42 Call date with -u to use UTC for added privacy when sharing. 43 44 -C, --copy 45 Copy the captured screenshot to the clipboard. If uploading, instead 46 copy the returned URL. 47 48 -f, --freeze 49 Freezes the screen before area selection. 50 Only works when target is area. 51 52 -w, --wait=n 53 Wait for n seconds before taking a screenshot. 54 55 -s, --scale=n 56 Passes the -s argument to grim. 57 58 -c, --cursor 59 Include cursors in the screenshot. 60 61 -t, --filetype=type 62 Output filetype. Supports png, ppm, jpeg. 63 Only png works with the -C option. 64 Default: png 65 66 -h, --help 67 Display this message. 68 EOF 69 } 70 71 fatalUser() { 72 cat <<EOF 73 Error: $1 74 75 See $argv0 --help for more information. 76 EOF 77 exit 2 78 } 79 80 fatal() { 81 printf "Error: %s\n" "$1" >&2 82 exit 1 83 } 84 85 check() { 86 err=() 87 while [[ $# -gt 0 ]]; do 88 msg="$1"; shift 89 cond="$1"; shift 90 value="$1"; shift 91 [[ "$cond" -ne 0 ]] && [[ -z "$value" ]] && err+=("$msg" ", ") 92 done 93 if [[ ${#err[@]} -gt 0 ]]; then 94 IFS="" 95 fatalUser "${err[*]::${#err[@]}-1}" >&2 96 fi 97 } 98 99 optsWithArgs=( 100 -a --api-key 101 -e --endpoint 102 -o --output 103 -w --wait 104 -s --scale 105 -t --filetype 106 ) 107 108 # Preprocess options: 109 # Expand -fff to -f -f -f. 110 # Expand -kv to -k v. 111 # Expand --key=value to --key value. 112 # Stop preprocessing once -- is observed. 113 argv=() 114 ignoreOpts= 115 while [[ $# -gt 0 ]]; do 116 case "$ignoreOpts$1" in 117 --) argv+=("$1"); ignoreOpts=1;; 118 --*=*) 119 argv+=("${1%%=*}" "${1#*=}") 120 (IFS="|"; [[ "|${optsWithArgs[*]}" = *"|${1%%=*}"* ]]) \ 121 || fatalUser "invalid option: $1" 122 ;; 123 --*) argv+=("$1");; 124 -*) 125 for ((i=1; i < ${#1}; ++i)); do 126 argv+=("-${1:i:1}"); 127 if (IFS="|"; [[ "|${optsWithArgs[*]}" = *"|-${1:i:1}"* ]]) && [[ -n "${1:i+1}" ]]; then 128 argv+=("${1:i+1}") 129 break 130 fi 131 done;; 132 *) argv+=("$1");; 133 esac 134 shift 135 done 136 set -- "${argv[@]}" 137 138 upload= 139 apiKey= 140 endpoint=https://scrn.is/api/v1/upload 141 out= 142 save= 143 copy= 144 filetype=png 145 dateArgs=() 146 grimblastArgs=() 147 148 positional=() 149 ignoreOpts= 150 while [[ $# -gt 0 ]]; do 151 case "$ignoreOpts$1" in 152 -u|--upload) upload=1;; 153 -a|--api-key) apiKey="$2"; shift;; 154 -e|--endpoint) endpoint="$2"; shift;; 155 -o|--output) out="$2"; save=1; shift;; 156 -U|--utc) dateArgs+=(-u);; 157 -C|--copy) copy=1;; 158 -f|--freeze) grimblastArgs+=(--freeze);; 159 -w|--wait) grimblastArgs+=(--wait "$2"); shift;; 160 -s|--scale) grimblastArgs+=(--scale "$2"); shift;; 161 -c|--cursor) grimblastArgs+=(--cursor);; 162 -t|--filetype) grimblastArgs+=(--filetype "$2"); filetype="$2"; shift;; 163 -h|--help) usage; exit 0;; 164 --) ignoreOpts=1;; 165 -*) fatalUser "invalid option $1";; 166 *) positional+=("$1");; 167 esac 168 shift 169 done 170 set -- "${positional[@]}" 171 172 target="$1"; shift 173 action= 174 case 1 in 175 $((copy && !upload))) action+="copy";;& 176 $((save || upload))) action+="save";; 177 esac 178 grimblastArgs+=("$action" "$target") 179 180 check \ 181 "extraneous positional arguments ($*)" $# ""\ 182 "missing target" 1 "$target" \ 183 "missing one of --copy --output --upload" 1 "$action" \ 184 "missing value for --api-key" "$upload" "$apiKey" \ 185 "missing value for --output" "$save" "$out" \ 186 187 if [[ $((!save && upload)) -ne 0 ]]; then 188 out="$(mktemp --suffix ".$filetype" "$(printf 'X%.0s' {1..8})")" 189 trap "$(trap -P EXIT)"$'\n rm -f "$out"' EXIT 190 elif [[ "$save" -ne 0 ]]; then 191 out="$(date "${dateArgs[@]}" "+${out/#\~/$HOME}")" \ 192 || fatal "date returned non-zero status" 193 fi 194 [[ -n "$out" ]] && grimblastArgs+=("$out") 195 196 if [[ "$upload" -ne 0 ]]; then 197 case "${apiKey:0:1}" in 198 @|%) apiKey=${apiKey:1};;& 199 @) 200 apiKeyRaw="$(<"${apiKey/#\~/$HOME}")" \ 201 || fatal "could not read API key from file: ${apiKey}" 202 ;; 203 %) 204 apiKeyRaw="$(bash -c "${apiKey}")" \ 205 || fatal "API key command returned non-zero status: ${apiKey}" 206 ;; 207 *) apiKeyRaw="$apiKey";; 208 esac 209 apiKey="$(tr -d '[:space:]' <<<"$apiKeyRaw")" 210 fi 211 212 set -eo pipefail 213 mkdir -p "$(dirname "$out")" 214 grimblast "${grimblastArgs[@]}" >/dev/null 215 216 if [[ "$upload" -ne 0 ]]; then 217 response="$(curl -sS --fail-with-body \ 218 "$endpoint" \ 219 -F "image=@$out" \ 220 -H "Authorization: Bearer $apiKey")" 221 url="$(jq -r .url <<<"$response")" 222 printf "%s" "$url" 223 if [[ "$copy" -ne 0 ]]; then 224 tr -d '[:space:]' <<<"$url" | wl-copy 225 fi 226 fi