summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbin/nuke498
1 files changed, 498 insertions, 0 deletions
diff --git a/bin/nuke b/bin/nuke
new file mode 100755
index 0000000..d536aac
--- /dev/null
+++ b/bin/nuke
@@ -0,0 +1,498 @@
1#!/usr/bin/env sh
2
3# #############################################################################
4# Description: Sample script to play files in apps by file type or mime
5#
6# Shell: POSIX compliant
7# Usage: nuke filepath
8#
9# Integration with nnn:
10# 1. Export the required config:
11# export NNN_OPENER=/absolute/path/to/nuke
12# # Otherwise, if nuke is in $PATH
13# # export NNN_OPENER=nuke
14# 2. Run nnn with the program option to indicate a CLI opener
15# nnn -c
16# # The -c program option overrides option -e
17# 3. nuke can use nnn plugins (e.g. mocplay is used for audio), $PATH is updated.
18#
19# Details:
20# Inspired by ranger's scope.sh, modified for usage with nnn.
21#
22# Guards against accidentally opening mime types like executables, shared libs etc.
23#
24# Tries to play 'file' (1st argument) in the following order:
25# i. by extension
26# ii. by mime (image, video, audio, pdf)
27# iii. by mime (other file types)
28#
29# Modification tips:
30# 1. Invokes CLI utilities by default. Set GUI to 1 to enable GUI apps.
31# 2. PAGER is "less -R".
32# 3. Start GUI apps in bg to unblock. Redirect stdout and strerr if required.
33# 4. Some CLI utilities are piped to the $PAGER, to wait and quit uniformly.
34# 5. If the output cannot be paged use "read -r _" to wait for user input.
35# 6. On a DE, try 'xdg-open' in handle_fallback() as last resort.
36#
37# Feel free to change the utilities to your favourites and add more mimes.
38#
39# Defaults:
40# By extension (only the enabled ones):
41# most archives: list with atool, bsdtar
42# rar: list with unrar
43# 7-zip: list with 7z
44# pdf: zathura (GUI), pdftotext, mutool, exiftool
45# audio: mocplay (nnn plugin using MOC), mpv, mediainfo, exiftool
46# avi|mkv|mp4: smplayer, mpv (GUI), ffmpegthumbnailer, mediainfo, exiftool
47# log: vi
48# torrent: rtorrent, transmission-show
49# odt|ods|odp|sxw: odt2txt
50# md: glow (https://github.com/charmbracelet/glow), lowdown (https://kristaps.bsd.lv/lowdown)
51# htm|html|xhtml: w3m, lynx, elinks
52# json: jq, python (json.tool module)
53# Multimedia by mime:
54# image/*: imv/sxiv (GUI), viu (https://github.com/atanunq/viu), img2txt, exiftool
55# video/*: smplayer, mpv (GUI), ffmpegthumbnailer, mediainfo, exiftool
56# audio/*: mocplay (nnn plugin using MOC), mpv, mediainfo, exiftool
57# application/pdf: zathura (GUI), pdftotext, mutool, exiftool
58# Other mimes:
59# text/troff: man -l
60# text/* | */xml: vi
61# image/vnd.djvu): djvutxt, exiftool
62#
63# ToDo:
64# 1. Adapt, test and enable all mimes
65# 2. Clean-up the unnecessary exit codes
66# #############################################################################
67
68# set to 1 to enable GUI apps
69GUI="1"
70
71set -euf -o noclobber -o noglob -o nounset
72IFS="$(printf '%b_' '\n')"; IFS="${IFS%_}" # protect trailing \n
73
74PATH=$PATH:"${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins"
75IMAGE_CACHE_PATH="$(dirname "$1")"/.thumbs
76
77FPATH="$1"
78FNAME=$(basename "$1")
79EDITOR="${EDITOR:-vi}"
80PAGER="${PAGER:-less -R}"
81ext="${FNAME##*.}"
82if ! [ -z "$ext" ]; then
83 ext="$(printf "%s" "${ext}" | tr '[:upper:]' '[:lower:]')"
84fi
85
86handle_pdf() {
87 if [ "$GUI" -ne 0 ] && which zathura >/dev/null 2>&1; then
88 zathura "${FPATH}" >/dev/null 2>&1 &
89 exit 0
90 elif which pdftotext >/dev/null 2>&1; then
91 ## Preview as text conversion
92 pdftotext -l 10 -nopgbrk -q -- "${FPATH}" - | eval "$PAGER"
93 exit 0
94 elif which mutool >/dev/null 2>&1; then
95 mutool draw -F txt -i -- "${FPATH}" 1-10 | eval "$PAGER"
96 exit 0
97 elif which exiftool >/dev/null 2>&1; then
98 exiftool "${FPATH}" | eval "$PAGER"
99 exit 0
100 fi
101}
102
103handle_audio() {
104 if which mocp >/dev/null 2>&1 && which mocplay >/dev/null 2>&1; then
105 mocplay "${FPATH}" "opener" >/dev/null 2>&1
106 exit 0
107 elif which mpv >/dev/null 2>&1; then
108 mpv "${FPATH}" >/dev/null 2>&1 &
109 exit 0
110 elif which mediainfo >/dev/null 2>&1; then
111 mediainfo "${FPATH}" | eval "$PAGER"
112 exit 0
113 elif which exiftool >/dev/null 2>&1; then
114 exiftool "${FPATH}"| eval "$PAGER"
115 exit 0
116 fi
117}
118
119handle_video() {
120 if [ "$GUI" -ne 0 ] && which smplayer >/dev/null 2>&1; then
121 smplayer "${FPATH}" >/dev/null 2>&1 &
122 exit 0
123 elif [ "$GUI" -ne 0 ] && which mpv >/dev/null 2>&1; then
124 mpv "${FPATH}" >/dev/null 2>&1 &
125 exit 0
126 elif which ffmpegthumbnailer >/dev/null 2>&1; then
127 # Thumbnail
128 [ -d "${IMAGE_CACHE_PATH}" ] || mkdir "${IMAGE_CACHE_PATH}"
129 ffmpegthumbnailer -i "${FPATH}" -o "${IMAGE_CACHE_PATH}/${FNAME}.jpg" -s 0
130 viu -n "${IMAGE_CACHE_PATH}/${FNAME}.jpg" | eval "$PAGER"
131 exit 0
132 elif which mediainfo >/dev/null 2>&1; then
133 mediainfo "${FPATH}" | eval "$PAGER"
134 exit 0
135 elif which exiftool >/dev/null 2>&1; then
136 exiftool "${FPATH}"| eval "$PAGER"
137 exit 0
138 fi
139}
140
141# handle this extension and exit
142handle_extension() {
143 case "${ext}" in
144 ## Archive
145 a|ace|alz|arc|arj|bz|bz2|cab|cpio|deb|gz|jar|lha|lz|lzh|lzma|lzo|\
146 rpm|rz|t7z|tar|tbz|tbz2|tgz|tlz|txz|tZ|tzo|war|xpi|xz|Z|zip)
147 if which atool >/dev/null 2>&1; then
148 atool --list -- "${FPATH}" | eval "$PAGER"
149 exit 0
150 elif which bsdtar >/dev/null 2>&1; then
151 bsdtar --list --file "${FPATH}" | eval "$PAGER"
152 exit 0
153 fi
154 exit 1;;
155 rar)
156 if which unrar >/dev/null 2>&1; then
157 ## Avoid password prompt by providing empty password
158 unrar lt -p- -- "${FPATH}" | eval "$PAGER"
159 fi
160 exit 1;;
161 7z)
162 if which 7z >/dev/null 2>&1; then
163 ## Avoid password prompt by providing empty password
164 7z l -p -- "${FPATH}" | eval "$PAGER"
165 exit 0
166 fi
167 exit 1;;
168
169 ## PDF
170 pdf)
171 handle_pdf
172 exit 1;;
173
174 ## Audio
175 aac|flac|m4a|mid|midi|mpa|mp2|mp3|ogg|wav|wma)
176 handle_audio
177 exit 1;;
178
179 ## Video
180 avi|mkv|mp4)
181 handle_video
182 exit 1;;
183
184 ## Log files
185 log)
186 # "$EDITOR" "${FPATH}"
187 "$PAGER" "${FPATH}"
188 exit 0;;
189
190 ## BitTorrent
191 torrent)
192 if which rtorrent >/dev/null 2>&1; then
193 rtorrent "${FPATH}"
194 exit 0
195 elif which transmission-show >/dev/null 2>&1; then
196 transmission-show -- "${FPATH}"
197 exit 0
198 fi
199 exit 1;;
200
201 ## OpenDocument
202 odt|ods|odp|sxw)
203 if which odt2txt >/dev/null 2>&1; then
204 ## Preview as text conversion
205 odt2txt "${FPATH}" | eval "$PAGER"
206 exit 0
207 fi
208 exit 1;;
209
210 ## Markdown
211 md)
212 if which glow >/dev/null 2>&1; then
213 glow -sdark "${FPATH}" | eval "$PAGER"
214 exit 0
215 elif which lowdown >/dev/null 2>&1; then
216 lowdown -Tterm "${FPATH}" | eval "$PAGER"
217 exit 0
218 fi
219 ;;
220
221 ## HTML
222 htm|html|xhtml)
223 ## Preview as text conversion
224 if which w3m >/dev/null 2>&1; then
225 w3m -dump "${FPATH}" | eval "$PAGER"
226 exit 0
227 elif which lynx >/dev/null 2>&1; then
228 lynx -dump -- "${FPATH}" | eval "$PAGER"
229 exit 0
230 elif which elinks >/dev/null 2>&1; then
231 elinks -dump "${FPATH}" | eval "$PAGER"
232 exit 0
233 fi
234 ;;
235
236 ## JSON
237 json)
238 if which jq >/dev/null 2>&1; then
239 jq --color-output . "${FPATH}" | eval "$PAGER"
240 exit 0
241 elif which python >/dev/null 2>&1; then
242 python -m json.tool -- "${FPATH}" | eval "$PAGER"
243 exit 0
244 fi
245 ;;
246 esac
247}
248
249abspath() {
250 case "$1" in
251 /*) printf "%s\n" "$1";;
252 *) printf "%s\n" "$PWD/$1";;
253 esac
254}
255
256listimages() {
257 find -L "$(dirname "$target")" -maxdepth 1 -type f -iregex \
258 '.*\(jpe?g\|bmp\|png\|gif\)$' -print0 | sort -z
259}
260
261load_dir() {
262 target="$(abspath "$2")"
263 count="$(listimages | grep -a -m 1 -ZznF "$target" | cut -d: -f1)"
264
265 if [ -n "$count" ]; then
266 listimages | xargs -0 "$1" -n "$count" --
267 else
268 shift
269 "$1" -- "$@" # fallback
270 fi
271}
272
273handle_multimedia() {
274 ## Size of the preview if there are multiple options or it has to be
275 ## rendered from vector graphics. If the conversion program allows
276 ## specifying only one dimension while keeping the aspect ratio, the width
277 ## will be used.
278 # local DEFAULT_SIZE="1920x1080"
279
280 mimetype="${1}"
281 case "${mimetype}" in
282 ## SVG
283 # image/svg+xml|image/svg)
284 # convert -- "${FPATH}" "${IMAGE_CACHE_PATH}" && exit 6
285 # exit 1;;
286
287 ## DjVu
288 # image/vnd.djvu)
289 # ddjvu -format=tiff -quality=90 -page=1 -size="${DEFAULT_SIZE}" \
290 # - "${IMAGE_CACHE_PATH}" < "${FPATH}" \
291 # && exit 6 || exit 1;;
292
293 ## Image
294 image/*)
295 if [ "$GUI" -ne 0 ] && which imvr >/dev/null 2>&1; then
296 load_dir imvr "${FPATH}" >/dev/null 2>&1 &
297 exit 0
298 elif [ "$GUI" -ne 0 ] && which sxiv >/dev/null 2>&1; then
299 load_dir sxiv "${FPATH}" >/dev/null 2>&1 &
300 exit 0
301 elif which viu >/dev/null 2>&1; then
302 viu -n "${FPATH}" | eval "$PAGER"
303 exit 0
304 elif which img2txt >/dev/null 2>&1; then
305 img2txt --gamma=0.6 -- "${FPATH}" | eval "$PAGER"
306 exit 0
307 elif which exiftool >/dev/null 2>&1; then
308 exiftool "${FPATH}" | eval "$PAGER"
309 exit 0
310 fi
311 # local orientation
312 # orientation="$( identify -format '%[EXIF:Orientation]\n' -- "${FPATH}" )"
313 ## If orientation data is present and the image actually
314 ## needs rotating ("1" means no rotation)...
315 # if [[ -n "$orientation" && "$orientation" != 1 ]]; then
316 ## ...auto-rotate the image according to the EXIF data.
317 # convert -- "${FPATH}" -auto-orient "${IMAGE_CACHE_PATH}" && exit 6
318 # fi
319
320 ## `w3mimgdisplay` will be called for all images (unless overridden
321 ## as above), but might fail for unsupported types.
322 exit 7;;
323
324 ## PDF
325 application/pdf)
326 handle_pdf
327 exit 1;;
328
329 ## Audio
330 audio/*)
331 handle_audio
332 exit 1;;
333
334 ## Video
335 video/*)
336 handle_video
337 exit 1;;
338
339 # pdftoppm -f 1 -l 1 \
340 # -scale-to-x "${DEFAULT_SIZE%x*}" \
341 # -scale-to-y -1 \
342 # -singlefile \
343 # -jpeg -tiffcompression jpeg \
344 # -- "${FPATH}" "${IMAGE_CACHE_PATH%.*}" \
345 # && exit 6 || exit 1;;
346
347
348 ## ePub, MOBI, FB2 (using Calibre)
349 # application/epub+zip|application/x-mobipocket-ebook|\
350 # application/x-fictionbook+xml)
351 # # ePub (using https://github.com/marianosimone/epub-thumbnailer)
352 # epub-thumbnailer "${FPATH}" "${IMAGE_CACHE_PATH}" \
353 # "${DEFAULT_SIZE%x*}" && exit 6
354 # ebook-meta --get-cover="${IMAGE_CACHE_PATH}" -- "${FPATH}" \
355 # >/dev/null && exit 6
356 # exit 1;;
357
358 ## Font
359 # application/font*|application/*opentype)
360 # preview_png="/tmp/$(basename "${IMAGE_CACHE_PATH%.*}").png"
361 # if fontimage -o "${preview_png}" \
362 # --pixelsize "120" \
363 # --fontname \
364 # --pixelsize "80" \
365 # --text " ABCDEFGHIJKLMNOPQRSTUVWXYZ " \
366 # --text " abcdefghijklmnopqrstuvwxyz " \
367 # --text " 0123456789.:,;(*!?') ff fl fi ffi ffl " \
368 # --text " The quick brown fox jumps over the lazy dog. " \
369 # "${FPATH}";
370 # then
371 # convert -- "${preview_png}" "${IMAGE_CACHE_PATH}" \
372 # && rm "${preview_png}" \
373 # && exit 6
374 # else
375 # exit 1
376 # fi
377 # ;;
378
379 ## Preview archives using the first image inside.
380 ## (Very useful for comic book collections for example.)
381 # application/zip|application/x-rar|application/x-7z-compressed|\
382 # application/x-xz|application/x-bzip2|application/x-gzip|application/x-tar)
383 # local fn=""; local fe=""
384 # local zip=""; local rar=""; local tar=""; local bsd=""
385 # case "${mimetype}" in
386 # application/zip) zip=1 ;;
387 # application/x-rar) rar=1 ;;
388 # application/x-7z-compressed) ;;
389 # *) tar=1 ;;
390 # esac
391 # { [ "$tar" ] && fn=$(tar --list --file "${FPATH}"); } || \
392 # { fn=$(bsdtar --list --file "${FPATH}") && bsd=1 && tar=""; } || \
393 # { [ "$rar" ] && fn=$(unrar lb -p- -- "${FPATH}"); } || \
394 # { [ "$zip" ] && fn=$(zipinfo -1 -- "${FPATH}"); } || return
395 #
396 # fn=$(echo "$fn" | python -c "import sys; import mimetypes as m; \
397 # [ print(l, end='') for l in sys.stdin if \
398 # (m.guess_type(l[:-1])[0] or '').startswith('image/') ]" |\
399 # sort -V | head -n 1)
400 # [ "$fn" = "" ] && return
401 # [ "$bsd" ] && fn=$(printf '%b' "$fn")
402 #
403 # [ "$tar" ] && tar --extract --to-stdout \
404 # --file "${FPATH}" -- "$fn" > "${IMAGE_CACHE_PATH}" && exit 6
405 # fe=$(echo -n "$fn" | sed 's/[][*?\]/\\\0/g')
406 # [ "$bsd" ] && bsdtar --extract --to-stdout \
407 # --file "${FPATH}" -- "$fe" > "${IMAGE_CACHE_PATH}" && exit 6
408 # [ "$bsd" ] || [ "$tar" ] && rm -- "${IMAGE_CACHE_PATH}"
409 # [ "$rar" ] && unrar p -p- -inul -- "${FPATH}" "$fn" > \
410 # "${IMAGE_CACHE_PATH}" && exit 6
411 # [ "$zip" ] && unzip -pP "" -- "${FPATH}" "$fe" > \
412 # "${IMAGE_CACHE_PATH}" && exit 6
413 # [ "$rar" ] || [ "$zip" ] && rm -- "${IMAGE_CACHE_PATH}"
414 # ;;
415 esac
416}
417
418handle_mime() {
419 mimetype="${1}"
420 case "${mimetype}" in
421 ## Manpages
422 text/troff)
423 man -l "${FPATH}"
424 exit 0;;
425
426 ## Text
427 text/* | */xml)
428 "$EDITOR" "${FPATH}"
429 exit 0;;
430 ## Syntax highlight
431 # if [[ "$( stat --printf='%s' -- "${FPATH}" )" -gt "${HIGHLIGHT_SIZE_MAX}" ]]; then
432 # exit 2
433 # fi
434 # if [[ "$( tput colors )" -ge 256 ]]; then
435 # local pygmentize_format='terminal256'
436 # local highlight_format='xterm256'
437 # else
438 # local pygmentize_format='terminal'
439 # local highlight_format='ansi'
440 # fi
441 # env HIGHLIGHT_OPTIONS="${HIGHLIGHT_OPTIONS}" highlight \
442 # --out-format="${highlight_format}" \
443 # --force -- "${FPATH}" && exit 5
444 # pygmentize -f "${pygmentize_format}" -O "style=${PYGMENTIZE_STYLE}"\
445 # -- "${FPATH}" && exit 5
446 # exit 2;;
447
448 ## DjVu
449 image/vnd.djvu)
450 if which djvutxt >/dev/null 2>&1; then
451 ## Preview as text conversion (requires djvulibre)
452 djvutxt "${FPATH}" | eval "$PAGER"
453 exit 0
454 elif which exiftool >/dev/null 2>&1; then
455 exiftool "${FPATH}" | eval "$PAGER"
456 exit 0
457 fi
458 exit 1;;
459 esac
460}
461
462handle_fallback() {
463 if [ "$GUI" -ne 0 ]; then
464 xdg-open "${FPATH}" >/dev/null 2>&1 &
465 exit 0
466 fi
467
468 echo '----- File details -----' && file --dereference --brief -- "${FPATH}"
469 exit 1
470}
471
472handle_blocked() {
473 case "${MIMETYPE}" in
474 application/x-sharedlib)
475 exit 0;;
476
477 application/x-shared-library-la)
478 exit 0;;
479
480 application/x-executable)
481 exit 0;;
482
483 application/x-shellscript)
484 exit 0;;
485
486 application/octet-stream)
487 exit 0;;
488 esac
489}
490
491MIMETYPE="$( file --dereference --brief --mime-type -- "${FPATH}" )"
492handle_extension
493handle_multimedia "${MIMETYPE}"
494handle_mime "${MIMETYPE}"
495handle_blocked "${MIMETYPE}"
496handle_fallback
497
498exit 1