- Emacs Lisp 98.6%
- Makefile 1.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| test | ||
| .gitignore | ||
| dirvish-ffpreview.el | ||
| Makefile | ||
| README.md | ||
dirvish-ffpreview
Image, video and music previews for Dirvish
that look the same wherever Emacs runs: GUI frames, terminal frames, an
emacsclient -t reached over SSH, and remote (TRAMP) directories.
Every preview has the same three parts:
- the file name
- a picture: the image itself, a frame from the video, or the album cover
- a metadata block: format, size, duration, bit rate, tags (title, artist, album, ...), video codec, resolution and frame rate, audio codec, sample rate, bit depth and channels
Everything comes from ffprobe and ffmpeg. Only the way the picture is
drawn depends on the frame:
| Frame | Picture drawn with |
|---|---|
| GUI | create-image |
| Terminal with kitty-graphics.el enabled | kitty-graphics.el (kitty protocol or Sixel) |
| Any other terminal | no picture, metadata only |
Remote directories
Dirvish gives remote directories a text-only preview (head/ls) and
skips every media previewer. dirvish-ffpreview-mode puts this previewer
back in front of it (unless dirvish-ffpreview-remote is nil).
Remote files are probed and thumbnailed on their own host, through a
direct-async TRAMP process (a plain ssh host cmd that reuses TRAMP's user,
port and multi-hop settings). Only the PNG thumbnail, usually a few hundred
KB, travels back. The media file is never copied.
The remote command runs in a POSIX login shell (sh -lc, see
dirvish-ffpreview-remote-shell), so ffmpeg installed by Homebrew or in
~/.local/bin is found even though a bare ssh host cmd would not search
those directories.
Requirements
- Emacs 29.1 or later, and Dirvish.
ffmpegandffprobeon Emacs'sexec-pathfor local files.- For remote directories: direct-async TRAMP processes, and
ffmpegandffprobeon the remote host's login-shellPATH. - For pictures in terminal frames: kitty-graphics.el with
kitty-graphics-modeon, in a terminal it supports (kitty, Ghostty, WezTerm, or a Sixel terminal).
Installation
With straight.el and use-package:
(use-package dirvish-ffpreview
:straight (dirvish-ffpreview
:type git
:repo "ssh://git@git.home.provost.one:222/paul/dirvish-ffpreview.git")
:after dirvish
:config (dirvish-ffpreview-mode 1))
dirvish-ffpreview-mode puts the ffpreview previewer first in
dirvish-preview-dispatchers and removes the ones it replaces
(dirvish-ffpreview-superseded-dispatchers: Dirvish's image, video,
audio and gif, and kitty-graphics' kitty-image). kitty-graphics.el
adds kitty-image back whenever kitty-graphics-mode turns on, which in a
daemon happens at the first terminal frame, long after init, so the mode
fixes the list again from kitty-graphics-mode-hook. Changes apply to new
Dirvish sessions.
Direct-async processes for SSH connections:
(connection-local-set-profile-variables
'remote-direct-async-process
'((tramp-direct-async-process . t)))
(dolist (protocol '("ssh" "scp" "sshx"))
(connection-local-set-profiles
`(:application tramp :protocol ,protocol)
'remote-direct-async-process))
How it works
When point lands on a media file, the previewer:
- looks up the cache, keyed by the file's full (possibly TRAMP) name,
size, modification time and
dirvish-ffpreview-thumbnail-width; - if there's no metadata yet, runs
ffprobe -show_format -show_streams -of jsonin the background and shows "Reading metadata…"; - then, if the file has a picture (any video stream, or embedded cover art
for music), runs
ffmpeg ... -frames:v 1 -f image2pipe -c:v png -in the background and shows the metadata with "Generating preview…". Videos are captured atdirvish-ffpreview-video-seek-fraction(10%) of their duration, since the first frames are often black; - shows the cached picture and metadata, instantly from then on.
Only one job runs at a time. Moving to another file stops the running job,
so scrolling quickly through a remote directory doesn't pile up ssh
processes. Jobs give up after dirvish-ffpreview-timeout seconds.
Results live under dirvish-cache-dir, in thumbnails/ffpreview/. Delete
that directory to clear the cache.
Options
| Option | Default | Meaning |
|---|---|---|
dirvish-ffpreview-superseded-dispatchers |
(kitty-image image video audio gif) |
previewers the mode removes |
dirvish-ffpreview-remote |
t |
also preview in TRAMP directories |
dirvish-ffpreview-ffmpeg-program |
"ffmpeg" |
local ffmpeg |
dirvish-ffpreview-ffprobe-program |
"ffprobe" |
local ffprobe |
dirvish-ffpreview-remote-ffmpeg-program |
"ffmpeg" |
ffmpeg on remote hosts |
dirvish-ffpreview-remote-ffprobe-program |
"ffprobe" |
ffprobe on remote hosts |
dirvish-ffpreview-shell |
"/bin/sh" |
local shell used to run them |
dirvish-ffpreview-remote-shell |
("sh" "-lc") |
remote command prefix |
dirvish-ffpreview-thumbnail-width |
800 |
maximum thumbnail width in pixels |
dirvish-ffpreview-video-seek-fraction |
0.1 |
where in a video the thumbnail is taken |
dirvish-ffpreview-image-height |
0.6 |
share of the preview window the picture may use |
dirvish-ffpreview-timeout |
30 |
seconds before a job is abandoned |
dirvish-ffpreview-image-exts, -video-exts, -audio-exts |
Dirvish's lists | which extensions are handled |
Limitations
- SVG images get a picture only in local directories in GUI frames, where Emacs draws them itself. ffmpeg can't rasterize SVG.
- Formats ffmpeg can't decode (some RAW camera files, for instance) show metadata only, if ffprobe can read that.
- Connections without direct-async support keep Dirvish's text preview.
Development
make test # ERT tests, dependencies from the straight.el build directory
make compile # byte-compile with warnings as errors
Set STRAIGHT_BUILD if your straight.el build directory is elsewhere.
License
GPL-3.0-or-later.