My build of nnn with minor changes
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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