Merge pull request 'feat(media): add play-media fzf picker for audio/video files' (#114) from feat/play-media-fzf-picker into main
CI / test (push) Successful in 1m0s
CI / build-docs (push) Successful in 3m37s

This commit was merged in pull request #114.
This commit is contained in:
2026-08-21 06:52:23 +00:00
4 changed files with 194 additions and 5 deletions
+2
View File
@@ -0,0 +1,2 @@
complete --command play-media --short p --long player --description "Force a specific media player" --require-parameter
complete --command play-media --short h --long help --description "Print this help message"
+5 -5
View File
@@ -36,27 +36,27 @@ function _fish_deps_catalog
set -g _fdc_bins \
uv cargo fish starship fzf zoxide direnv paru yay \
wakatime tailscale \
eza lsd bat btop dust duf prettyping go ov rg lazygit lazydocker docker trash kitty wezterm python3 yt-dlp screen
eza lsd bat btop dust duf prettyping go ov rg lazygit lazydocker docker trash kitty wezterm python3 yt-dlp screen mpv vlc
set -g _fdc_tiers \
rec rec req rec req rec rec rec rec \
int int \
rec rec rec opt opt opt opt opt rec rec opt opt opt rec term term rec opt opt
rec rec rec opt opt opt opt opt rec rec opt opt opt rec term term rec opt opt opt opt
set -g _fdc_cargo \
"" "" "" starship "" zoxide "" "" "" \
"" "" \
eza lsd bat "" du-dust "" "" "" "" ripgrep "" "" "" trashy "" "" "" "" ""
eza lsd bat "" du-dust "" "" "" "" ripgrep "" "" "" trashy "" "" "" "" "" "" ""
set -g _fdc_pm \
uv cargo fish starship fzf zoxide direnv "" yay \
wakatime tailscale \
eza lsd bat btop dust duf prettyping go ov ripgrep lazygit lazydocker docker trash kitty wezterm python yt-dlp screen
eza lsd bat btop dust duf prettyping go ov ripgrep lazygit lazydocker docker trash kitty wezterm python yt-dlp screen mpv vlc
set -g _fdc_special \
curl-uv rustup-installer git-cargo-fish curl-installer fzf-update "" "" paru-build yay-build \
wakatime-binary "" \
"" "" "" "" "" "" "" "" go-ov "" "" curl-lazydocker "" "" "" "" "" "" ""
"" "" "" "" "" "" "" "" go-ov "" "" curl-lazydocker "" "" "" "" "" "" "" "" ""
end
# SYNOPSIS
+60
View File
@@ -0,0 +1,60 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# SYNOPSIS
# _fzf_preview_media <file_path>
#
# DESCRIPTION
# Preview helper for play-media. Looks for a thumbnail already generated
# by a desktop file manager (Dolphin, Nautilus, GNOME Videos, ...) in the
# freedesktop thumbnail cache and renders it via _fzf_preview_image if
# found. Otherwise falls back to ffprobe-formatted metadata (duration,
# codec, resolution, tags) when ffprobe is installed, or plain `file`
# output as a last resort. Neither the thumbnail cache lookup nor ffprobe
# are tracked in fish-deps: both are best-effort, matching how the
# image-preview tool chain (kitten/chafa/viu/timg) is already handled.
#
# ARGUMENTS
# file_path Path to the audio/video file to preview
#
# EXIT STATUS
# 0 Always
#
# EXAMPLE
# _fzf_preview_media ./Videos/clip.mp4
function _fzf_preview_media
set -f file_path $argv
if not test -e "$file_path"
echo "$file_path doesn't exist." >&2
return 0
end
set -l abs_path (realpath -- "$file_path" 2>/dev/null)
# freedesktop.org thumbnail spec: md5 of the file:// URI names the
# cached thumbnail. Dolphin/Nautilus/GNOME Videos already populate this
# cache, so reuse it instead of generating a new thumbnail ourselves.
set -l uri "file://"(string escape --style=url -- "$abs_path")
set -l hash (echo -n "$uri" | md5sum | string split ' ')[1]
set -l cache_home (set --query XDG_CACHE_HOME; and echo $XDG_CACHE_HOME; or echo "$HOME/.cache")
for size in normal large x-large xx-large
set -l thumb "$cache_home/thumbnails/$size/$hash.png"
if test -f "$thumb"
_fzf_preview_image "$thumb"
return 0
end
end
if command -q ffprobe
set -l info (command ffprobe -v error -show_entries \
format=duration,bit_rate:format_tags=title,artist,album:stream=codec_name,codec_type,width,height \
-of default=noprint_wrappers=1 -- "$abs_path" 2>/dev/null)
if test -n "$info"
printf '%s\n' $info
return 0
end
end
command file --brief -- "$abs_path"
end
+127
View File
@@ -0,0 +1,127 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 13-media-and-utilities
#
# SYNOPSIS
# play-media [-p|--player <cmd>]
# play-media --help
#
# DESCRIPTION
# Opens an fzf picker (with thumbnail/metadata preview via
# _fzf_preview_media) listing audio and video files under the current
# directory, and plays the selection(s) in the best available media
# player. Supports multi-select (Tab) to queue several files at once.
#
# Player resolution order:
# 1. -p/--player <cmd> (explicit override, validated as a command)
# 2. $play_media_player (explicit override, validated as a command)
# 3. xdg-mime default handler for the first selected file's mimetype
# 4. First known player binary found in a built-in list (mpv, vlc)
#
# The player is launched backgrounded and detached, mirroring open-url,
# so the shell is never blocked.
#
# ARGUMENTS
# -p, --player <cmd> Force a specific player command
# -h, --help Print usage and exit
#
# EXIT STATUS
# 0 Player launched (or the picker was cancelled)
# 1 No media files found, invalid --player/$play_media_player, or no
# player found
#
# EXAMPLE
# play-media
# play-media --player mpv
function play-media --description 'Pick audio/video files with fzf and play them'
argparse h/help p/player= -- $argv
or return 1
if set -q _flag_help
echo "Usage: play-media [-p|--player <cmd>]"
echo "Pick audio/video files under the current directory with fzf and play them."
echo
echo " -p, --player <cmd> Force a specific player command"
echo " -h, --help Show this help"
return 0
end
set -l audio_exts mp3 flac wav ogg oga opus m4a aac wma alac aiff
set -l video_exts mp4 mkv webm avi mov wmv flv m4v mpg mpeg ts
# Directly use fd binary to avoid output buffering delay caused by a fd
# alias, if any. Debian-based distros install fd as fdfind.
set -f fd_cmd (command -v fdfind || command -v fd || echo "fd")
set -f --append fd_cmd --color=always $fzf_fd_opts
for ext in $audio_exts $video_exts
set -f --append fd_cmd -e $ext
end
set -l selection ($fd_cmd 2>/dev/null | _fzf_wrapper --ansi --multi \
--height=90% \
--layout=reverse \
--border=rounded \
--border-label=' Play Media ' \
--prompt='Play> ' \
--header='Enter: Play Tab: Select Ctrl-/: Toggle Preview Esc: Cancel' \
--bind='ctrl-/:toggle-preview' \
--preview='_fzf_preview_media {}' \
--preview-window='right:50%:wrap:border-left')
if test -z "$selection"
return 0
end
set -l player
if set -q _flag_player
set player $_flag_player
if not type -q $player[1]
set_color red
echo "error: --player '$player[1]' is not a valid command" >&2
set_color normal
return 1
end
else if set -q play_media_player
echo $play_media_player | read -at player
if not type -q $player[1]
set_color red
echo "error: \$play_media_player '$player[1]' is not a valid command" >&2
set_color normal
return 1
end
else
if type -q xdg-mime; and command -q file
set -l mime (command file --brief --mime-type -- "$selection[1]" 2>/dev/null)
set -l desk (xdg-mime query default "$mime" 2>/dev/null)
if test -n "$desk"
set -l candidate (string replace -r '\.desktop$' '' -- $desk)
if type -q $candidate
set player $candidate
end
end
end
if not set -q player[1]
for p in mpv vlc
if type -q -f $p
set player $p
break
end
end
end
end
if not set -q player[1]
set_color red
echo "error: could not find a media player — set \$play_media_player, pass --player, or install mpv/vlc" >&2
set_color normal
return 1
end
# Background the player so it doesn't block the terminal, and discard
# its own console chatter, mirroring open-url.
sh -c '("$@") >/dev/null 2>&1 &' -- $player $selection
return 0
end