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.
 
 
 
 
 
 

489 lignes
16 KiB

  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' 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, 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/*: 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, 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. ext="${FNAME##*.}"
  75. if ! [ -z "$ext" ]; then
  76. ext="$(printf "%s" "${ext}" | tr '[:upper:]' '[:lower:]')"
  77. fi
  78. handle_pdf() {
  79. if [ "$GUI" -ne 0 ] && which zathura >/dev/null 2>&1; then
  80. zathura "${FPATH}" >/dev/null 2>&1 &
  81. exit 0
  82. elif which pdftotext >/dev/null 2>&1; then
  83. ## Preview as text conversion
  84. pdftotext -l 10 -nopgbrk -q -- "${FPATH}" - | less -R
  85. exit 0
  86. elif which mutool >/dev/null 2>&1; then
  87. mutool draw -F txt -i -- "${FPATH}" 1-10
  88. exit 0
  89. elif which exiftool >/dev/null 2>&1; then
  90. exiftool "${FPATH}" | less -R
  91. exit 0
  92. fi
  93. }
  94. handle_audio() {
  95. if which mocp >/dev/null 2>&1 && which mocplay >/dev/null 2>&1; then
  96. mocplay "${FPATH}" "opener" >/dev/null 2>&1
  97. exit 0
  98. elif which mpv >/dev/null 2>&1; then
  99. mpv "${FPATH}" >/dev/null 2>&1 &
  100. exit 0
  101. elif which mediainfo >/dev/null 2>&1; then
  102. mediainfo "${FPATH}" | less -R
  103. exit 0
  104. elif which exiftool >/dev/null 2>&1; then
  105. exiftool "${FPATH}"| less -R
  106. exit 0
  107. fi
  108. }
  109. handle_video() {
  110. if [ "$GUI" -ne 0 ] && which smplayer >/dev/null 2>&1; then
  111. smplayer "${FPATH}" >/dev/null 2>&1 &
  112. exit 0
  113. elif [ "$GUI" -ne 0 ] && which mpv >/dev/null 2>&1; then
  114. mpv "${FPATH}" >/dev/null 2>&1 &
  115. exit 0
  116. elif which ffmpegthumbnailer >/dev/null 2>&1; then
  117. # Thumbnail
  118. [ -d "${IMAGE_CACHE_PATH}" ] || mkdir "${IMAGE_CACHE_PATH}"
  119. ffmpegthumbnailer -i "${FPATH}" -o "${IMAGE_CACHE_PATH}/${FNAME}.jpg" -s 0
  120. viu -n "${IMAGE_CACHE_PATH}/${FNAME}.jpg" | less -R
  121. exit 0
  122. elif which mediainfo >/dev/null 2>&1; then
  123. mediainfo "${FPATH}" | less -R
  124. exit 0
  125. elif which exiftool >/dev/null 2>&1; then
  126. exiftool "${FPATH}"| less -R
  127. exit 0
  128. fi
  129. }
  130. # handle this extension and exit
  131. handle_extension() {
  132. case "${ext}" in
  133. ## Archive
  134. a|ace|alz|arc|arj|bz|bz2|cab|cpio|deb|gz|jar|lha|lz|lzh|lzma|lzo|\
  135. rpm|rz|t7z|tar|tbz|tbz2|tgz|tlz|txz|tZ|tzo|war|xpi|xz|Z|zip)
  136. if which atool >/dev/null 2>&1; then
  137. atool --list -- "${FPATH}" | less -R
  138. exit 0
  139. elif which bsdtar >/dev/null 2>&1; then
  140. bsdtar --list --file "${FPATH}" | less -R
  141. exit 0
  142. fi
  143. exit 1;;
  144. rar)
  145. if which unrar >/dev/null 2>&1; then
  146. ## Avoid password prompt by providing empty password
  147. unrar lt -p- -- "${FPATH}" | less -R
  148. fi
  149. exit 1;;
  150. 7z)
  151. if which 7z >/dev/null 2>&1; then
  152. ## Avoid password prompt by providing empty password
  153. 7z l -p -- "${FPATH}" | less -R
  154. exit 0
  155. fi
  156. exit 1;;
  157. ## PDF
  158. pdf)
  159. handle_pdf
  160. exit 1;;
  161. ## Audio
  162. aac|flac|m4a|mid|midi|mpa|mp2|mp3|ogg|wav|wma)
  163. handle_audio
  164. exit 1;;
  165. ## Video
  166. avi|mkv|mp4)
  167. handle_video
  168. exit 1;;
  169. ## Log files
  170. log)
  171. vi "${FPATH}"
  172. exit 0;;
  173. ## BitTorrent
  174. torrent)
  175. if which rtorrent >/dev/null 2>&1; then
  176. rtorrent "${FPATH}"
  177. exit 0
  178. elif which transmission-show >/dev/null 2>&1; then
  179. transmission-show -- "${FPATH}"
  180. exit 0
  181. fi
  182. exit 1;;
  183. ## OpenDocument
  184. odt|ods|odp|sxw)
  185. if which odt2txt >/dev/null 2>&1; then
  186. ## Preview as text conversion
  187. odt2txt "${FPATH}" | less -R
  188. exit 0
  189. fi
  190. exit 1;;
  191. ## Markdown
  192. md)
  193. if which glow >/dev/null 2>&1; then
  194. glow -sdark "${FPATH}" | less -R
  195. exit 0
  196. elif which lowdown >/dev/null 2>&1; then
  197. lowdown -Tterm "${FPATH}" | less -R
  198. exit 0
  199. fi
  200. ;;
  201. ## HTML
  202. htm|html|xhtml)
  203. ## Preview as text conversion
  204. if which w3m >/dev/null 2>&1; then
  205. w3m -dump "${FPATH}" | less -R
  206. exit 0
  207. elif which lynx >/dev/null 2>&1; then
  208. lynx -dump -- "${FPATH}" | less -R
  209. exit 0
  210. elif which elinks >/dev/null 2>&1; then
  211. elinks -dump "${FPATH}" | less -R
  212. exit 0
  213. fi
  214. ;;
  215. ## JSON
  216. json)
  217. if which jq >/dev/null 2>&1; then
  218. jq --color-output . "${FPATH}" | less -R
  219. exit 0
  220. elif which python >/dev/null 2>&1; then
  221. python -m json.tool -- "${FPATH}" | less -R
  222. exit 0
  223. fi
  224. ;;
  225. esac
  226. }
  227. abspath() {
  228. case "$1" in
  229. /*) printf "%s\n" "$1";;
  230. *) printf "%s\n" "$PWD/$1";;
  231. esac
  232. }
  233. listimages() {
  234. find -L "$(dirname "$target")" -maxdepth 1 -type f -iregex \
  235. '.*\(jpe?g\|bmp\|png\|gif\)$' -print0 | sort -z
  236. }
  237. sxiv_load_dir() {
  238. target="$(abspath "$1")"
  239. count="$(listimages | grep -a -m 1 -ZznF "$target" | cut -d: -f1)"
  240. if [ -n "$count" ]; then
  241. listimages | xargs -0 sxiv -n "$count" --
  242. else
  243. sxiv -- "$@" # fallback
  244. fi
  245. }
  246. handle_multimedia() {
  247. ## Size of the preview if there are multiple options or it has to be
  248. ## rendered from vector graphics. If the conversion program allows
  249. ## specifying only one dimension while keeping the aspect ratio, the width
  250. ## will be used.
  251. # local DEFAULT_SIZE="1920x1080"
  252. mimetype="${1}"
  253. case "${mimetype}" in
  254. ## SVG
  255. # image/svg+xml|image/svg)
  256. # convert -- "${FPATH}" "${IMAGE_CACHE_PATH}" && exit 6
  257. # exit 1;;
  258. ## DjVu
  259. # image/vnd.djvu)
  260. # ddjvu -format=tiff -quality=90 -page=1 -size="${DEFAULT_SIZE}" \
  261. # - "${IMAGE_CACHE_PATH}" < "${FPATH}" \
  262. # && exit 6 || exit 1;;
  263. ## Image
  264. image/*)
  265. if [ "$GUI" -ne 0 ] && which sxiv >/dev/null 2>&1; then
  266. sxiv_load_dir "${FPATH}" >/dev/null 2>&1 &
  267. exit 0
  268. elif which viu >/dev/null 2>&1; then
  269. viu -n "${FPATH}" | less -R
  270. exit 0
  271. elif which img2txt >/dev/null 2>&1; then
  272. img2txt --gamma=0.6 -- "${FPATH}" | less -R
  273. exit 0
  274. elif which exiftool >/dev/null 2>&1; then
  275. exiftool "${FPATH}" | less -R
  276. exit 0
  277. fi
  278. # local orientation
  279. # orientation="$( identify -format '%[EXIF:Orientation]\n' -- "${FPATH}" )"
  280. ## If orientation data is present and the image actually
  281. ## needs rotating ("1" means no rotation)...
  282. # if [[ -n "$orientation" && "$orientation" != 1 ]]; then
  283. ## ...auto-rotate the image according to the EXIF data.
  284. # convert -- "${FPATH}" -auto-orient "${IMAGE_CACHE_PATH}" && exit 6
  285. # fi
  286. ## `w3mimgdisplay` will be called for all images (unless overriden
  287. ## as above), but might fail for unsupported types.
  288. exit 7;;
  289. ## PDF
  290. application/pdf)
  291. handle_pdf
  292. exit 1;;
  293. ## Audio
  294. audio/*)
  295. handle_audio
  296. exit 1;;
  297. ## Video
  298. video/*)
  299. handle_video
  300. exit 1;;
  301. # pdftoppm -f 1 -l 1 \
  302. # -scale-to-x "${DEFAULT_SIZE%x*}" \
  303. # -scale-to-y -1 \
  304. # -singlefile \
  305. # -jpeg -tiffcompression jpeg \
  306. # -- "${FPATH}" "${IMAGE_CACHE_PATH%.*}" \
  307. # && exit 6 || exit 1;;
  308. ## ePub, MOBI, FB2 (using Calibre)
  309. # application/epub+zip|application/x-mobipocket-ebook|\
  310. # application/x-fictionbook+xml)
  311. # # ePub (using https://github.com/marianosimone/epub-thumbnailer)
  312. # epub-thumbnailer "${FPATH}" "${IMAGE_CACHE_PATH}" \
  313. # "${DEFAULT_SIZE%x*}" && exit 6
  314. # ebook-meta --get-cover="${IMAGE_CACHE_PATH}" -- "${FPATH}" \
  315. # >/dev/null && exit 6
  316. # exit 1;;
  317. ## Font
  318. # application/font*|application/*opentype)
  319. # preview_png="/tmp/$(basename "${IMAGE_CACHE_PATH%.*}").png"
  320. # if fontimage -o "${preview_png}" \
  321. # --pixelsize "120" \
  322. # --fontname \
  323. # --pixelsize "80" \
  324. # --text " ABCDEFGHIJKLMNOPQRSTUVWXYZ " \
  325. # --text " abcdefghijklmnopqrstuvwxyz " \
  326. # --text " 0123456789.:,;(*!?') ff fl fi ffi ffl " \
  327. # --text " The quick brown fox jumps over the lazy dog. " \
  328. # "${FPATH}";
  329. # then
  330. # convert -- "${preview_png}" "${IMAGE_CACHE_PATH}" \
  331. # && rm "${preview_png}" \
  332. # && exit 6
  333. # else
  334. # exit 1
  335. # fi
  336. # ;;
  337. ## Preview archives using the first image inside.
  338. ## (Very useful for comic book collections for example.)
  339. # application/zip|application/x-rar|application/x-7z-compressed|\
  340. # application/x-xz|application/x-bzip2|application/x-gzip|application/x-tar)
  341. # local fn=""; local fe=""
  342. # local zip=""; local rar=""; local tar=""; local bsd=""
  343. # case "${mimetype}" in
  344. # application/zip) zip=1 ;;
  345. # application/x-rar) rar=1 ;;
  346. # application/x-7z-compressed) ;;
  347. # *) tar=1 ;;
  348. # esac
  349. # { [ "$tar" ] && fn=$(tar --list --file "${FPATH}"); } || \
  350. # { fn=$(bsdtar --list --file "${FPATH}") && bsd=1 && tar=""; } || \
  351. # { [ "$rar" ] && fn=$(unrar lb -p- -- "${FPATH}"); } || \
  352. # { [ "$zip" ] && fn=$(zipinfo -1 -- "${FPATH}"); } || return
  353. #
  354. # fn=$(echo "$fn" | python -c "import sys; import mimetypes as m; \
  355. # [ print(l, end='') for l in sys.stdin if \
  356. # (m.guess_type(l[:-1])[0] or '').startswith('image/') ]" |\
  357. # sort -V | head -n 1)
  358. # [ "$fn" = "" ] && return
  359. # [ "$bsd" ] && fn=$(printf '%b' "$fn")
  360. #
  361. # [ "$tar" ] && tar --extract --to-stdout \
  362. # --file "${FPATH}" -- "$fn" > "${IMAGE_CACHE_PATH}" && exit 6
  363. # fe=$(echo -n "$fn" | sed 's/[][*?\]/\\\0/g')
  364. # [ "$bsd" ] && bsdtar --extract --to-stdout \
  365. # --file "${FPATH}" -- "$fe" > "${IMAGE_CACHE_PATH}" && exit 6
  366. # [ "$bsd" ] || [ "$tar" ] && rm -- "${IMAGE_CACHE_PATH}"
  367. # [ "$rar" ] && unrar p -p- -inul -- "${FPATH}" "$fn" > \
  368. # "${IMAGE_CACHE_PATH}" && exit 6
  369. # [ "$zip" ] && unzip -pP "" -- "${FPATH}" "$fe" > \
  370. # "${IMAGE_CACHE_PATH}" && exit 6
  371. # [ "$rar" ] || [ "$zip" ] && rm -- "${IMAGE_CACHE_PATH}"
  372. # ;;
  373. esac
  374. }
  375. handle_mime() {
  376. mimetype="${1}"
  377. case "${mimetype}" in
  378. ## Manpages
  379. text/troff)
  380. man -l "${FPATH}"
  381. exit 0;;
  382. ## Text
  383. text/* | */xml)
  384. vi "${FPATH}"
  385. exit 0;;
  386. ## Syntax highlight
  387. # if [[ "$( stat --printf='%s' -- "${FPATH}" )" -gt "${HIGHLIGHT_SIZE_MAX}" ]]; then
  388. # exit 2
  389. # fi
  390. # if [[ "$( tput colors )" -ge 256 ]]; then
  391. # local pygmentize_format='terminal256'
  392. # local highlight_format='xterm256'
  393. # else
  394. # local pygmentize_format='terminal'
  395. # local highlight_format='ansi'
  396. # fi
  397. # env HIGHLIGHT_OPTIONS="${HIGHLIGHT_OPTIONS}" highlight \
  398. # --out-format="${highlight_format}" \
  399. # --force -- "${FPATH}" && exit 5
  400. # pygmentize -f "${pygmentize_format}" -O "style=${PYGMENTIZE_STYLE}"\
  401. # -- "${FPATH}" && exit 5
  402. # exit 2;;
  403. ## DjVu
  404. image/vnd.djvu)
  405. if which djvutxt >/dev/null 2>&1; then
  406. ## Preview as text conversion (requires djvulibre)
  407. djvutxt "${FPATH}" | less -R
  408. exit 0
  409. elif which exiftool >/dev/null 2>&1; then
  410. exiftool "${FPATH}" | less -R
  411. exit 0
  412. fi
  413. exit 1;;
  414. esac
  415. }
  416. handle_fallback() {
  417. if [ "$GUI" -ne 0 ]; then
  418. xdg-open "${FPATH}" >/dev/null 2>&1 &
  419. exit 0
  420. fi
  421. echo '----- File details -----' && file --dereference --brief -- "${FPATH}"
  422. exit 1
  423. }
  424. handle_blocked() {
  425. case "${MIMETYPE}" in
  426. application/x-sharedlib)
  427. exit 0;;
  428. application/x-shared-library-la)
  429. exit 0;;
  430. application/x-executable)
  431. exit 0;;
  432. application/x-shellscript)
  433. exit 0;;
  434. esac
  435. }
  436. MIMETYPE="$( file --dereference --brief --mime-type -- "${FPATH}" )"
  437. handle_blocked "${MIMETYPE}"
  438. handle_extension
  439. handle_multimedia "${MIMETYPE}"
  440. handle_mime "${MIMETYPE}"
  441. handle_fallback
  442. exit 1