MENU

Add image/video preview on vifm

vifm
目次

Improve vifm filer

I wrote previewing script for image/video for better experience on vifm.

Finder on MacOS is not so useful, but vifm is faster & easy to use.
So I want to set it up as 2nd(1st?) image/video viewer too.
Add image/video previewing function to vifm, with ffmpeg & bash script.
(More simple video previewing script is here.)

Newer version can be downloaded here

https://github.com/riodelphino/preview.vifm

Below codes are old and buggy.

Feature

  • Image preview
  • Video preview (jpg)
  • Cache files with hash filename (for faster viewing)
  • Async generation for all files in current dir
  • Logging if needed

Ensured to work on

  • MacOS
    • kitty
    • tmux on kitty

Code

~/.config/vifm/script/preview.sh

#!/bin/bash

# USAGE:
#    ./preview.sh [filename] [ft_group] [process_type]
#
# ARGS:
#    filename      : target filename
#    ft_group      : image : Use imagemagick
#                    video : Use ffmpeg
#    process_type  : single : Generate preview for the single file
#                    all    : Generate previews for all files in the dir

# --------------------------------------------------------------------------------
# Consts
# --------------------------------------------------------------------------------
# Cache dir
CACHE_DIR="$HOME/.cache/vifm/preview"
# Path for saving previous dir info
PREV_DIR_FILE="$HOME/.cache/vifm/preview/previous_dir"
# Log file path
LOG_FILE="$HOME/.cache/vifm/preview/log"
# Loggin or not
LOG_ENABLED=1 # 0: No logging | 1: Logging (cause timeloss)

# Images
IMAGE_PATTERNS="*.bmp *.jpg *.jpeg *.png *.gif *.xpm *.avif *.webp *.heic"
IMAGE_QUALITY=80
IMAGE_RESIZE="600x600" # the size of vifm window on full screen
# IMAGE_RESIZE="1376x1617" # Measured exact size for me, then remove '--scale-up' option from 'kitten icat'

# Videos
VIDEO_PATTERNS="*.avi *.mp4 *.wmv *.dat *.3gp *.ogv *.mkv *.mpg *.mpeg *.vob fl[icv] *.m2v *.mov *.webm *.ts *.mts *.m4v r[am] *.qt *.divx as[fx]"
VIDEO_FRAME=1000      # frame num for cut, from the movie's start
VIDEO_SCALE="640:360" # width:height
# VIDEO_SCALE="1376:774" # Measured exact size for me, then remove '--scale-up' option from 'kitten icat'

# --------------------------------------------------------------------------------
# Variables
# --------------------------------------------------------------------------------
prev_dir=""
cur_dir=""

# --------------------------------------------------------------------------------
# Functions
# --------------------------------------------------------------------------------

# Loging
function Log() {
   label="$1"
   value="$2"
   length=12
   if [[ $LOG_ENABLED == 1 ]]; then
      printf "%-${length}s: %s\n" "$label" "$value" >>"$LOG_FILE"
   fi
}

# Generate preview & return the hash path
function GeneratePreview() {
   file="$1"     # file path
   ft_group="$2" # image | viode
   # Get preview filename (hash)
   hash=$(echo $(realpath "$file") | sha256sum | cut -d' ' -f1) # get hash
   preview="$CACHE_DIR/$hash.jpg"                               # preview path

   # Generate preview
   if [ ! -f "$preview" ]; then
      if [[ $ft_group == "image" ]]; then
         # Image
         magick "$file" -quality $IMAGE_QUALITY -resize $IMAGE_RESIZE "$preview" >/dev/null 2>&1
      elif [[ $ft_group == "video" ]]; then
         # Video
         ffmpeg -y -i "$1" \
            -vf "select='eq(n,$VIDEO_FRAME)',scale=$VIDEO_SCALE" \
            -frames:v 1 \
            "$preview" >/dev/null 2>&1
      fi
   fi
   Log "preview" "$ft_group=$preview"

   # echo $preview
   printf "%s\n" "$preview"
}

# Record current directory
function RecordCurDir() {
   echo $cur_dir >"$PREV_DIR_FILE"
}

# Generate image previews for all files in dir
function GenerateImagePreviewAll() {
   # List files in the directory and loop through each pattern
   for pat in $IMAGE_PATTERNS; do
      Log "pat" "$pat"
      # For each pattern, find matching files
      for file in "$cur_dir"/$pat; do
         # Only proceed if $file is a regular file
         if [[ -f "$file" ]]; then
            Log "file" "$file"
            GeneratePreview "$file" image
         fi
      done
   done
   wait
}

# Generate video previews for all files in dir
function GenerateVideoPreviewAll() {
   # List files in the directory and loop through each pattern
   for pat in $VIDEO_PATTERNS; do
      Log "pat" "$pat"
      # For each pattern, find matching files
      for file in "$cur_dir"/$pat; do
         # Only proceed if $file is a regular file
         if [[ -f "$file" ]]; then
            Log "file" "$file"
            GeneratePreview "$file" video
         fi
      done
   done
   wait
}

# --------------------------------------------------------------------------------
# Main script
# --------------------------------------------------------------------------------

# Get args
FILE_PATH="${1//\\ / }" # replace '\ ' to ' '
FT_GROUP="$2"
PROCESS_TYPE="$3"
PATTERNS="${4//,/ }" # replace ',' to ' ' for loop

# Get directories
cur_dir=$(dirname "$(realpath "$FILE_PATH")")
[ ! -f "$PREV_DIR_FILE" ] && prev_dir="" || prev_dir=$(cat "$PREV_DIR_FILE")

# Logging
Log "ft_group" "$FT_GROUP"
Log "process_type" "$PROCESS_TYPE"
Log "prev_dir" "$prev_dir"
Log "cur_dir" "$cur_dir"
Log "file" "$FILE_PATH"

# Create preview directory
mkdir -p "$CACHE_DIR"

if [[ $PROCESS_TYPE == "all" ]]; then
   # GeneratePreviewAll()' (in background)
   if [[ "$prev_dir" != "$cur_dir" ]]; then # Check if the directory has changed
      Log "function" "GenerateImagePreviewAll()"
      GenerateImagePreviewAll
      Log "function" "GeneratePreviewAll()"
      GenerateVideoPreviewAll
   fi
   Log "function" "RecordCurDir()"
   RecordCurDir "$FILE_PATH"
elif [[ $PROCESS_TYPE == "single" ]]; then
   # Generate preview for the single file
   Log "function" "GeneratePreview()"
   GeneratePreview "$FILE_PATH" $FT_GROUP
fi
Bash

~/.config/vifmrc

" Image
fileviewer {*.bmp,*.jpg,*.jpeg,*.png,*.gif,*.xpm,*.avif,*.webp,*.heic},<image/*>
    \ kitten icat --clear --transfer-mode=file --silent --scale-up --place=%pwx%ph@%pxx%py "$(~/.config/vifm/scripts/preview.sh '%c' image single)" >/dev/tty </dev/tty %N &
    \ sh -c "$HOME/.config/vifm/scripts/preview.sh '%c' image all &"
    \ %pc
    \ kitten icat --clear --silent >/dev/tty </dev/tty %N &

" Video
fileviewer {*.avi,*.mp4,*.wmv,*.dat,*.3gp,*.ogv,*.mkv,*.mpg,*.mpeg,*.vob,*.fl[icv],*.m2v,*.mov,*.webm,*.ts,*.mts,*.m4v,*.r[am],*.qt,*.divx,*.as[fx]},
   \ kitten icat --transfer-mode=file --silent --scale-up --place=%pwx%ph@%pxx%py "$(~/.config/vifm/scripts/preview.sh '%c' video single)" >/dev/tty </dev/tty %N &
   \ sh -c "$HOME/.config/vifm/scripts/preview.sh '%c' video all &"
   \ %pc
   \ kitten icat --clear --silent >/dev/tty </dev/tty %N &
Plaintext

%pc is just a delimiter, between displaying command and cleaning command.

Note that kitten icat and it’s options should be replaced to your own graphic protocol.

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次