plumb (5877B)
1 #!/bin/sh 2 3 echo(){ 4 printf '%s\n' "$*" 5 } 6 7 matches(){ 8 echo "$arg" | grep -Ei "$@" >/dev/null 9 } 10 11 fmatches(){ 12 file "$arg" | grep -Ei "$@" >/dev/null 13 } 14 15 fmagic(){ 16 isfile "$arg" || return 1 17 grep "$1" < "$arg" >/dev/null 18 } 19 20 _envsubst(){ 21 str="$*" 22 23 env | 24 while read -r line 25 do 26 str=$(echo "$str" | awk -v "var=${line%%=*}" -v "val=${line#*=}" ' 27 { 28 regex = sprintf("\\$%s", var) 29 gsub(regex, val) 30 print 31 }' 32 ) 33 echo "$str" 34 done | tail -n 1 35 } 36 37 plumb(){ 38 t="$1"; shift 39 [ $norun -eq 1 ] && return 40 export norun=1 41 case "$t" in 42 gui) 43 >/dev/null 2>/dev/null nohup sh -c "$*; rm '$file'" & 44 ;; 45 terminal) 46 >/dev/null 2>/dev/null nohup ${TERMINAL:-st} sh -c "$*; rm '$file'" & 47 ;; 48 prompt) 49 >/dev/null 2>/dev/null nohup ${TERMINAL:-st} sh -c "$(dmenu -i -p "$*"); rm '$file'" & 50 ;; 51 matchlater) 52 export norun=0 53 >/dev/null 2>/dev/null nohup sh -c "$*" & 54 ;; 55 *) 56 herbe "No such plumb-type: $t" 57 ;; 58 esac 59 } 60 61 replace(){ 62 arg=$(echo "$arg" | sed "$*") 63 } 64 65 isfile(){ 66 [ -z "$1" ] && { 67 [ -f "$arg" ] 68 return $? 69 } 70 [ -n "$1" ] && { 71 [ -f "$1" ] 72 return $? 73 } 74 } 75 76 hascmd(){ 77 command -v "$*" >/dev/null 78 } 79 80 wasfetched(){ 81 [ -n "$orig" ] 82 } 83 84 fetch(){ 85 file="/tmp/plumb.$(basename "$arg")" 86 while [ -f $file ] 87 do 88 file="/tmp/plumb.$(base64 </dev/urandom | tr -d / | head -c10).$(basename "$arg")" 89 done 90 $proxy curl $([ "$verbose" != "y" ] && echo -s) "$(echo "$arg" | sed -E 's/]|\[|}|\{/\\&/g')" > "$file" 91 export orig="$arg" 92 export arg="$file" 93 removelater "$file" 94 } 95 96 removelater(){ 97 [ -z "$exittrap" ] && exittrap="$*" 98 exittrap="$exittrap; rm -rf \"$*\"" 99 trap "$exittrap" EXIT 100 } 101 102 mime(){ 103 mime=$($proxy curl -Li$([ "$verbose" != "y" ] && echo s) "$(echo "$arg" | sed -E 's/]|\[|}|\{/\\&/g')" | 104 awk '/^HTTP/ && $2 != "200" {s=1}; /^HTTP/ && $2 == "200" {p=1}; /^[[:space:]]*$/ {if (s) s=0; else exit 1}; p' | 105 tr '[:upper:]' '[:lower:]' | awk '$1 == "content-type:" {print $2}') 106 echo "$mime" | tee /dev/stderr | grep -i "$1" >/dev/null 107 } 108 109 case "$1" in 110 -v) 111 verbose=y 112 shift 113 ;; 114 esac 115 116 [ -n "$PLUMB" ] && exit 117 export PLUMB="$$" 118 119 for arg in "$@" 120 do 121 export norun=0 122 export gui=0 123 export proxy="" 124 export arg=$(_envsubst "$arg") 125 export orig="" 126 127 # remove file:// 128 matches "^file://" && 129 replace 's~^file://~~' 130 131 # network 132 matches "://.*\.onion" && 133 export proxy="torsocks" 134 135 matches "^magnet:" && 136 plumb terminal 'addtorrent "$arg"' 137 138 matches "^(gopher|http)s?://.*\.(ogg|mp3|opus|flac|pls)$" && 139 plumb terminal '$proxy mpv --pause $arg' 140 141 matches "^(gopher|http)s?://.*\.gif$" && 142 plumb gui '$proxy mpv --loop-file $arg' 143 144 matches "(youtu.be|youtube.com).*/feeds/" && 145 plumb gui 'sfeed_addfeed "$arg"' 146 147 matches "^(gopher|http)s?://.*\.(mkv|mp4|avi|webm|ogv|gifv|mp4|ape|m3u|m3u8)$" || 148 matches "^https?://(www\.|m\.)?(youtube.com|youtu.be)" || 149 matches "^https?://.*/videos/watch/" || # peertube 150 matches "^https?://videos?\..*/w/" && # peertube also uses /w/, which is so ambiguous I made this subdomain-dependant 151 plumb gui 'queuevid "$arg" && $proxy mpv --pause "$arg"' 152 153 matches "^https?://" && 154 ! mime "text/html" && 155 fetch 156 157 matches "^https?://" || 158 matches "\.html?$" || 159 fmatches "HTML" && 160 plumb gui 'qutebrowser $arg' 161 162 matches "^gophers?://(.*/[17+0](/|$)|[^/]*$)" && 163 plumb terminal '$proxy zygo $arg' 164 165 matches "^gophers?://" && 166 fetch 167 168 matches "^mailto:" && 169 plumb terminal 'neomutt $(echo "$arg" | sed "s~^mailto:~~")' 170 171 matches "^finger://" && 172 plumb terminal '$proxy finger $(echo "$arg" | sed "s~^finger://~~"); cat' 173 174 matches "^ssh://" && 175 plumb terminal '$proxy ssh $(echo "$arg" | sed "s~^ssh://~~;s~:[0-9]*~~")' 176 177 matches "^git://" && 178 plumb terminal '$proxy git clone $arg' 179 180 # local files now 181 fmatches "gzip" && 182 isfile && 183 plumb matchlater 'gunzip < $arg > $arg.new && mv $arg.new $arg' && 184 removelater "$arg.new" 185 186 fmatches "zip.*archive" && 187 isfile 188 plumb matchlater 'unzip -p $arg > $arg.new && mv $arg.new $arg' && 189 removelater "$arg.new" 190 191 fmatches "PGP.*public.*key|PGP.*ring" && 192 isfile && 193 plumb terminal 'gpg --import $arg; sleep 5' 194 195 fmatches "PGP.*signature" && 196 isfile && 197 plumb terminal 'gpg --verify $arg; sleep 5' 198 199 fmatches "PGP.*message|PGP.*encrypted" && 200 isfile && 201 plumb terminal 'gpg -d $arg; sleep 5' 202 203 matches ".*\.(epub|ps|eps|pdf|dvi|djvu)$" || 204 fmatches "pdf|postscript" && 205 isfile && 206 plumb gui 'zathura $arg' 207 208 matches ".*\.gif$" && 209 isfile && 210 plumb gui 'mpv --loop-file $arg' 211 212 matches ".*\.(mkv|mp4|avi|webm|ogg|ogv|gifv|mp3|mp4|opus|flac|ape|m3u|m3u8)$" || 213 fmatches "video|matroska|audio|sound" && 214 isfile && 215 plumb terminal 'mpv --pause $arg' 216 217 matches ".*\.(jpe?g|gif|tiff?|ppm|bit|bmp|png|xpm)$" || 218 fmatches "image" && 219 isfile && 220 plumb gui 'sxiv $arg' 221 222 matches "\.?/.*\.[0-9]p?$" && 223 fmatches "(roff|preprocessor)" && 224 isfile && 225 plumb terminal 'man $arg' 226 227 matches "\.(gph|gophermap)$|(^|/)gophermap$" && 228 isfile && 229 plumb terminal 'cgo -f $arg' 230 231 matches "\.(atom|rss)$|rss\.xml$|atom\.xml$" || 232 fmatches "atom|rss" || 233 fmagic "<feed.*xmlns.*http://www.w3.org/2005/Atom" || 234 fmagic "<rss" && 235 wasfetched && 236 plumb gui 'sfeed_addfeed $orig' 237 238 matches "\.(atom|rss)$|rss\.xml$" || 239 fmatches "atom|rss" || 240 fmagic "<feed.*xmlns.*http://www.w3.org/2005/Atom" || 241 fmagic "<rss" && 242 ! wasfetched && 243 plumb terminal 'sfeed < $arg | sort -rn | sfeed_curses' 244 245 # dmarc reports 246 fmagic "<feedback" && 247 fmagic "<policy_published" && 248 fmagic "<dkim" && 249 plumb terminal 'dmarc < $arg; cat' 250 251 # numbered file 252 matches ":[0-9][0-9]*$" && 253 isfile ${arg%:*} && 254 plumb terminal 'vim +${arg##*:} ${arg%:*}' 255 256 # catch all for files 257 matches ".*" && 258 isfile && 259 plumb terminal 'vim $arg' 260 261 # include files 262 matches ".*\.h$" && 263 isfile "/usr/include/$arg" && 264 plumb terminal 'vim /usr/include/$arg' 265 266 matches ".*\.h$" && 267 isfile "/usr/local/include/$arg" && 268 plumb terminal 'vim /usr/local/include/$arg' 269 270 # catch-all for non-files 271 matches ".*" && 272 plumb prompt 'Plumb to (use $arg): ' 273 done 274 wait