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.
 
 
 
 
 
 

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