#!/usr/bin/env bash # fzf_preview_mine file="$1" # cache for slow/big files, exr and hdr and ... CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/fzf_preview_mine" mkdir -p "$CACHE_DIR" # cache hash = hash + mtime cache_key() { local f="$1" stat -c '%n-%Y' "$f" 2>/dev/null | md5sum | cut -d' ' -f1 } # need command need_cmd() { command -v "$1" >/dev/null 2>&1 || { echo "Error: missing dependency: $1" >&2 return 1 } } center() { local text="$1" local width="$FZF_PREVIEW_COLUMNS" local len=${#text} local pad=$(( (width - len) / 2 )) [[ $pad -lt 0 ]] && pad=0 printf "%*s%s\n" "$pad" "" "$text" } # handle directories first if [[ -d "$file" ]]; then center "[DIR] $file" # or better: tree -C -L 2 "$file" exit 0 fi generic() { fold -s -w "$FZF_PREVIEW_COLUMNS" "$1" | head -n 2500 } # echo centered extension or filename (if there is no extension) base="${file##*/}" if [[ "$base" == *.* && "$base" != .* ]]; then ext="${base##*.}" else ext="$base" fi center "$ext" mime=$(file --mime-type -b "$file" 2>/dev/null) encoding=$(file --mime-encoding -b "$file" 2>/dev/null) debug="0" tmp=$(mktemp -d) cleanup() { pkill -P $$ sleep 0.1 rm -rf "$tmp" } trap cleanup EXIT chafaView () { clear local file width_px height_px width_px="$((FZF_PREVIEW_COLUMNS))" height_px="$((FZF_PREVIEW_LINES))" file="$1" need_cmd chafa || exit 1 chafa --dither=diffusion -f sixels -s "${width_px}x${height_px}" "$file" 2>/dev/null echo } if [[ $mime == image/* ]]; then (( debug )) && echo "image" if [[ "$file" == *.psd ]] || [[ "$file" = *.avif ]]; then need_cmd convert || exit 1 convert "$file" -flatten "$tmp/tmp.png" file="$tmp/tmp.png" fi if [[ "$file" == *.svg ]]; then need_cmd inkscape || exit 1 inkscape "$file" --actions="export-filename:$tmp/tmp.png; export-do" 2> /dev/null file="$tmp/tmp.png" fi # if [[ "$file" == *.exr ]] || [[ "$file" = *.hdr ]]; then # #convert "$file" -colorspace sRGB -auto-gamma -auto-level "$tmp/tmp.png" # # sudo apt install openimageio-tools # oiiotool "$file" --colorconvert linear sRGB -o "$tmp/tmp.png" # file="$tmp/tmp.png" # fi # exr and hdr with cache if [[ "$file" == *.exr ]] || [[ "$file" == *.hdr ]]; then key=$(cache_key "$file") cached="$CACHE_DIR/${key}.png" if [[ -f "$cached" ]]; then file="$cached" else need_cmd oiiotool || exit 1 oiiotool "$file" --resize 1200x0 --colorconvert linear sRGB -o "$cached" 2>/dev/null file="$cached" fi fi chafaView "$file" || generic "$file" elif [[ $mime == audio/* ]] || [[ "${file,,}" == *.m4a ]] || [[ "${file,,}" == *.mp3 ]]; then need_cmd mediainfo || exit 1 mediainfo "$file" 2> /dev/null need_cmd mpv || exit 1 mpv --no-video --quiet "$file" 2> /dev/null elif [[ $mime == video/* ]] || [[ "${file,,}" == *.mxf ]]; then (( debug )) && echo "video" dur=$(ffprobe -v panic -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file") [[ -z "$dur" || "$dur" == "N/A" ]] && dur=50 halfdur=$(bc -l <<< "$dur / 2.00") need_cmd ffmpeg || exit 1 ffmpeg -hide_banner -loglevel panic -ss "$halfdur" -i "$file" -frames:v 1 "$tmp/middle.png" -y chafaView "$tmp/middle.png" elif [[ "$file" == *.blend ]] || [[ "$file" == *.blend1 ]]; then # need_cmd blender-thumbnailer || exit 1 # blender-thumbnailer "$file" "$tmp/blend.png" # file="$tmp/blend.png" # chafaView "$file" || generic "$file" # need_cmd blender || exit 1 blender="$HOME/blender_unpacked/blender-5.1.2-linux-x64/blender" if [[ ! -x "$blender" ]]; then blender="blender" fi info="$tmp/blend_info.txt" cat > "$tmp/blend_info.py" </dev/null 2>&1 if [[ -f "$info" ]]; then cat "$info" echo else echo "No blend metadata" echo "or no blender found on path" echo "or blender is too old" echo fi elif [[ "$file" == *.epub ]]; then { epub2txt -a -n "$file" 2>/dev/null || pandoc "$file" -t plain 2>/dev/null } | fold -s -w "$FZF_PREVIEW_COLUMNS" elif [[ "$file" == *.mobi ]]; then need_cmd ebook-convert || exit 1 ebook-convert "$file" "$tmp/tmp.txt" 2>/dev/null clear fold -s -w "$FZF_PREVIEW_COLUMNS" "$tmp/tmp.txt" elif [[ "$file" == *.html ]] || [[ "$file" == *.htm ]]; then need_cmd w3m || exit 1 w3m -o display_link_number=1 -dump -cols "$FZF_PREVIEW_COLUMNS" "$file" || generic "$file" elif [[ "$mime" == application/pdf ]]; then # graphical, show 1st page only need_cmd pdftocairo || exit 1 pdftocairo -png -scale-to 1200 -singlefile "$file" "$tmp/out" chafaView "$tmp/out.png" # textual, extract all text need_cmd pdftotext || exit 1 pdftotext -layout "$file" - 2>/dev/null \ | fold -s -w "$FZF_PREVIEW_COLUMNS" # use shift + up/down to switch between two previews # atool for compressed stuff elif [[ "$file" == *.zip || "$file" == *.tar || "$file" == *.tar.* || "$file" == *.7z || "$file" == *.rar || "$file" == *.gz || "$file" == *.bz2 || "$file" == *.xz ]]; then need_cmd als || exit 1 als -l "$file" 2>/dev/null | head -n 500 elif [[ "$file" == *.deb ]]; then dpkg-deb --contents "$file" elif [[ "$file" == *.docx ]]; then need_cmd pandoc || exit 1 pandoc -s "$file" -t plain # fonts elif [[ "$file" == *.otf ]] || [[ "$file" == *.ttf ]] || [[ "$file" == *.woff ]]; then name="${file##*/}" # fira.ttf name="${name%.*}" # fira name="${name^^}" # FIRA need_cmd convert || exit 1 convert -size 1600x800 xc:black \ -font "$file" \ -fill white \ -gravity northwest \ \ -pointsize 120 \ -annotate +40+80 "${name}" \ \ -pointsize 60 \ -annotate +40+320 "The quick brown čšž ČŠŽ\njumps over the lazy dog\n\nIN RHONCUS NULLA VEL ANTE,\nQUIS BLANDIT TURPIS SAGITTIS.\nSED SODALES, JUSTO AC PLACERAT." \ \ "$tmp/font.png" #open "$tmp/font.png" chafaView "$tmp/font.png" elif [[ $encoding == binary ]]; then echo "[BINARY: $(basename "$file")]" need_cmd xxd || exit 1 xxd "$file" | head -100 || strings "$file" | head -300 else generic "$file" fi