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.

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