Compare commits
3 Commits
fde3b6edcb
...
4343521a46
| Author | SHA1 | Date | |
|---|---|---|---|
| 4343521a46 | |||
| 6db95d3feb | |||
| a0f8e79665 |
33
src/main.sh
33
src/main.sh
@@ -103,6 +103,9 @@ MODE_INSERT="show"
|
||||
# Load filters
|
||||
. "sh/filter.sh"
|
||||
|
||||
# Load lyrics support
|
||||
. "sh/lyrics.sh"
|
||||
|
||||
# Command-line options that may only be used internally.
|
||||
# --lines
|
||||
# --playback
|
||||
@@ -115,6 +118,8 @@ MODE_INSERT="show"
|
||||
# --preview
|
||||
# --show-keybindings
|
||||
# --remove-from-cache
|
||||
# --edit-lyrics
|
||||
# --lyrics-custom
|
||||
case "${1:-}" in
|
||||
"--lines")
|
||||
# Print lines that are fed into fzf.
|
||||
@@ -286,6 +291,7 @@ case "${1:-}" in
|
||||
"$VIEW_SEARCH_ARTIST" | "$VIEW_LIST_ARTISTS") view="$VIEW_ARTIST" ;;
|
||||
"$VIEW_ARTIST" | "$VIEW_SEARCH_ALBUM" | "$VIEW_LIST_ALBUMS") view="$VIEW_RELEASEGROUP" ;;
|
||||
"$VIEW_RELEASEGROUP") view="$VIEW_RELEASE" ;;
|
||||
"$VIEW_RELEASE") exit 0 ;;
|
||||
esac
|
||||
;;
|
||||
*) ;;
|
||||
@@ -369,6 +375,20 @@ case "${1:-}" in
|
||||
esac
|
||||
exit 0
|
||||
;;
|
||||
"--edit-lyrics")
|
||||
# Edit lyrics file in an external window
|
||||
info "Call to $*"
|
||||
mbid="${2:-}"
|
||||
file="$(lyrics_file "$mbid")"
|
||||
[ -f "$file" ] || echo "No lyrics" | store_lyrics "$mbid"
|
||||
[ "$EXTERNALEDIT" ] && $EXTERNALEDIT "$file" || err "Failed to externally edit the file $file"
|
||||
exit 0
|
||||
;;
|
||||
"--lyrics-custom")
|
||||
# Use custom command to (re-)fetch the lyrics
|
||||
store_lyrics_custom "$2" "$3"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# Non-interactive user commands intended to the user. These commands do not
|
||||
@@ -432,6 +452,11 @@ case "${1:-}" in
|
||||
cut -d "$(printf '\t')" -f 1
|
||||
exit 0
|
||||
;;
|
||||
"--lyrics")
|
||||
shift
|
||||
lyrics "$@"
|
||||
exit 0
|
||||
;;
|
||||
"--help")
|
||||
# Print help string
|
||||
cat <<EOF
|
||||
@@ -449,6 +474,7 @@ GENERAL OPTIONS:
|
||||
--playlists List stored playlists and exit
|
||||
--load-playlist <playlist> Load specified playlist
|
||||
--print-playlist <playlist> Print specified playlist and exit
|
||||
--lyrics <release> <mbid> Show lyrics specified track and exit
|
||||
|
||||
MANAGE LOCAL MUSIC:
|
||||
--decorate <path> Decorate directory containing a tagged release
|
||||
@@ -571,6 +597,7 @@ fi
|
||||
IN_NORMAL_MODE="[ \$FZF_INPUT_STATE = hidden ]"
|
||||
IN_VIEW_PATTERN="[ \$FZF_LIST_LABEL = %s ]"
|
||||
IN_LIST_ARTISTS_VIEW="$(printf "$IN_VIEW_PATTERN" "$VIEW_LIST_ARTISTS")"
|
||||
IN_RELEASE_VIEW="$(printf "$IN_VIEW_PATTERN" "$VIEW_RELEASE")"
|
||||
FZF_CURRENT_MODE="\$FZF_INPUT_STATE"
|
||||
FZF_CURRENT_VIEW="\$FZF_LIST_LABEL"
|
||||
FZF_CURRENT_MBID="\$FZF_BORDER_LABEL"
|
||||
@@ -735,6 +762,9 @@ while true; do
|
||||
--bind="$KEYS_PLAYLIST_GOTO_RELEASE:print($VIEW_RELEASE)+accept" \
|
||||
--bind="$KEYS_PLAYLIST_STORE:print($VIEW_PLAYLIST_STORE)+print("")+print($LASTVIEW)+print($LASTARG)+accept" \
|
||||
--bind="$KEYS_PLAYLIST_OPEN_STORE:print($VIEW_PLAYLIST_PLAYLISTSTORE)+print("")+print($LASTVIEW)+print($LASTARG)+accept" \
|
||||
--bind="$KEYS_N_LYRICS:show-preview+preview:$0 --lyrics {3} {4}" \
|
||||
--bind="$KEYS_LYRICS_EDIT:execute-silent:$0 --edit-lyrics {4}" \
|
||||
--bind="$KEYS_N_LYRICS_FETCH_CUSTOM:execute-silent($0 --lyrics-custom {3} {4})+show-preview+preview:$0 --lyrics {3} {4}" \
|
||||
--preview-window="hidden" \
|
||||
--wrap-sign="" \
|
||||
--delimiter="\t" \
|
||||
@@ -830,6 +860,9 @@ open \"\$(dirname {5})\"" \
|
||||
--bind="$KEYS_PREVIEW_CLOSE:hide-preview" \
|
||||
--bind="$KEYS_PLAYBACK:transform:$0 --playback $FZF_CURRENT_VIEW \"$FZF_CURRENT_MBID\" {4} {5}" \
|
||||
--bind="$KEYS_N_PLAYBACK:transform:$IN_NORMAL_MODE && $0 --playback $FZF_CURRENT_VIEW \"$FZF_CURRENT_MBID\" {4} {5} || $PUT_FZF_KEY_LOGIC" \
|
||||
--bind="$KEYS_N_LYRICS:transform:$IN_NORMAL_MODE && $IN_RELEASE_VIEW && printf \"show-preview+preview:%s --lyrics %s %s\" \"$0\" {3} {4}" \
|
||||
--bind="$KEYS_LYRICS_EDIT:transform:$IN_RELEASE_VIEW && printf \"execute-silent:%s --edit-lyrics %s\" \"$0\" {4}" \
|
||||
--bind="$KEYS_N_LYRICS_FETCH_CUSTOM:transform:$IN_NORMAL_MODE && $IN_RELEASE_VIEW && {$0 --lyrics-custom {3} {4};printf \"show-preview+preview:%s --lyrics %s %s\" \"$0\" {3} {4}}" \
|
||||
--bind="change:execute-silent($0 --mbsearch $FZF_CURRENT_VIEW &)+reload:$0 --lines $FZF_CURRENT_VIEW" \
|
||||
--preview-window="$FZF_DEFAULT_PREVIEW_WINDOW" \
|
||||
--wrap-sign="" \
|
||||
|
||||
@@ -63,6 +63,11 @@
|
||||
# - KEYS_PREVIEW_TOGGLE_SIZE: Toggle size (small, large) of preview window
|
||||
# - KEYS_REFRESH: Refresh current entry
|
||||
#
|
||||
# Lyrics:
|
||||
# - KEYS_N_LYRICS: Show lyrics of selected track
|
||||
# - KEYS_LYRICS_EDIT: Edit lyrics of selected track
|
||||
# - KEYS_N_LYRICS_FETCH_CUSTOM: Fetch lyrics using custom command
|
||||
#
|
||||
# Playback:
|
||||
# - KEYS_PLAY: Play selected release or selected track
|
||||
# - KEYS_QUEUE: Queue selected release or selected track
|
||||
@@ -165,6 +170,12 @@ if [ ! "${KEYS_LOADED:-}" ]; then
|
||||
KEYS_PREVIEW_OPEN KEYS_PREVIEW_TOGGLE_WRAP KEYS_PREVIEW_TOGGLE_SIZE \
|
||||
KEYS_REFRESH
|
||||
|
||||
# Lyrics:
|
||||
KEYS_N_LYRICS="${KEYS_N_LYRICS:-"L"}"
|
||||
KEYS_LYRICS_EDIT="${KEYS_LYRICS_EDIT:-"alt-L"}"
|
||||
KEYS_N_LYRICS_FETCH_CUSTOM="${KEYS_N_LYRICS_FETCH_CUSTOM:-"Y"}"
|
||||
export KEYS_N_LYRICS KEYS_LYRICS_EDIT KEYS_N_LYRICS_FETCH_CUSTOM
|
||||
|
||||
# Playback:
|
||||
KEYS_PLAY="${KEYS_PLAY:-"enter"}"
|
||||
KEYS_QUEUE="${KEYS_QUEUE:-"ctrl-alt-m"}" # That's actually alt-enter
|
||||
@@ -317,6 +328,10 @@ print_keybindings() {
|
||||
"$KEYS_PLAY_PREV,$KEYS_N_PLAY_PREV" "Play previous track" \
|
||||
"$KEYS_SEEK_FORWARD,$KEYS_N_SEEK_FORWARD" "Seek forward" \
|
||||
"$KEYS_SEEK_BACKWARD,$KEYS_N_SEEK_BACKWARD" "Seek backward"
|
||||
__keybindinggroup_from_args "Lyrics" \
|
||||
"$KEYS_N_LYRICS" "Show lyrics" \
|
||||
"$KEYS_LYRICS_EDIT" "Edit lyrics" \
|
||||
"$KEYS_N_LYRICS_FETCH_CUSTOM" "Fetch lyrics using custom command"
|
||||
__keybindinggroup_from_args "Special operations" \
|
||||
"$KEYS_BROWSE" "Open selected item in browser" \
|
||||
"$KEYS_OPEN" "Open selected item in file manager" \
|
||||
@@ -405,6 +420,10 @@ print_keybindings() {
|
||||
"$KEYS_N_PLAY_PREV" "Play previous track" \
|
||||
"$KEYS_N_SEEK_FORWARD" "Seek forward" \
|
||||
"$KEYS_N_SEEK_BACKWARD" "Seek backward"
|
||||
__keybindinggroup_from_args "Lyrics" \
|
||||
"$KEYS_N_LYRICS" "Show lyrics (normal mode)" \
|
||||
"$KEYS_LYRICS_EDIT" "Edit lyrics" \
|
||||
"$KEYS_N_LYRICS_FETCH_CUSTOM" "Fetch lyrics using custom command (normal)"
|
||||
__keybindinggroup_from_args "Special operations" \
|
||||
"$KEYS_SHOW_PLAYLIST" "Show playlist" \
|
||||
"$KEYS_BROWSE" "Open selected item in browser" \
|
||||
|
||||
@@ -191,7 +191,7 @@ END { for (i in id) print title[i], id[i], fname[i] }
|
||||
# theme-independent fashion. The lists are stored in the files
|
||||
# `LOCALDATA_ARTISTS_LIST` and `LOCALDATA_RELEASEGROUPS_LIST`.
|
||||
__precompute_lists() {
|
||||
cache_get_file_batch "$TYPE_ARTIST" <"$LOCALDATA_ARTISTS" | xargs \
|
||||
cache_get_file_batch "$TYPE_ARTIST" <"$LOCALDATA_ARTISTS" | xargs -d "\n" \
|
||||
$JQ '[
|
||||
.id,
|
||||
.type,
|
||||
@@ -201,7 +201,7 @@ __precompute_lists() {
|
||||
.["life-span"].begin,
|
||||
.["life-span"].end
|
||||
] | join("\t")' >"$LOCALDATA_ARTISTS_LIST" &
|
||||
cache_get_file_batch "$TYPE_RELEASEGROUP" <"$LOCALDATA_RELEASEGROUPS" | xargs \
|
||||
cache_get_file_batch "$TYPE_RELEASEGROUP" <"$LOCALDATA_RELEASEGROUPS" | xargs -d "\n" \
|
||||
$JQ '[
|
||||
.id,
|
||||
."primary-type",
|
||||
@@ -244,7 +244,7 @@ reloaddb() {
|
||||
tmpreleasefiles=$(mktemp)
|
||||
cache_get_file_batch "$TYPE_RELEASE" <"$tmpreleases" >"$tmpreleasefiles"
|
||||
(
|
||||
xargs \
|
||||
xargs -d "\n" \
|
||||
$JQ '."release-group".id' \
|
||||
<"$tmpreleasefiles" >"$LOCALDATA_RELEASEGROUPS"
|
||||
tf1=$(mktemp)
|
||||
@@ -252,7 +252,7 @@ reloaddb() {
|
||||
mv "$tf1" "$LOCALDATA_RELEASEGROUPS"
|
||||
) &
|
||||
(
|
||||
xargs \
|
||||
xargs -d "\n" \
|
||||
$JQ '."release-group"."artist-credit" | map(.artist.id) | join("\n")' \
|
||||
<"$tmpreleasefiles" >"$LOCALDATA_ARTISTS"
|
||||
tf2=$(mktemp)
|
||||
|
||||
114
src/sh/lyrics.sh
Normal file
114
src/sh/lyrics.sh
Normal file
@@ -0,0 +1,114 @@
|
||||
# Methods and constants for lyrics handling
|
||||
#
|
||||
# Lyrics are retrieved as following:
|
||||
# 1. Check if the lyrics are already stored in this store
|
||||
# 2. If the track is playable, check if an accompanying `.lrc` file is present.
|
||||
# 3. If the track is playable, read lyrics from the tags
|
||||
# 4. Call custom fetch command
|
||||
#
|
||||
# The path to the lyrics is `__radix(mbid)/mbid.lrc` where `mbid` is the
|
||||
# MusicBrainz ID of the track.
|
||||
|
||||
if [ ! "${LYRICS_LOADED:-}" ]; then
|
||||
# Folder to store lyrics
|
||||
LYRICS_DIRECTORY="${LYRICS_DIRECTORY:-"$LOCALDATADIR/lyrics"}"
|
||||
[ -d "$LYRICS_DIRECTORY" ] || mkdir -p "$LYRICS_DIRECTORY"
|
||||
export LYRICS_DIRECTORY
|
||||
|
||||
# Custom command to fetch lyrics
|
||||
#
|
||||
# This command reads from stdin the json object of the track and prints the
|
||||
# lyrics.
|
||||
LYRICS_FETCH_CUSTOM="${LYRICS_FETCH_CUSTOM:-"$JQ '.trackid as \$tid | .release.media[].tracks[] | select(.id == \$tid) | .title'"}"
|
||||
#LYRICS_FETCH_CUSTOM="${LYRICS_FETCH_CUSTOM:-"$JQ '.trackid as \$trid | \"Lyrics for \" + .media[].tracks[] | select(.id == \$trid) | .title'"}"
|
||||
export LYRICS_FETCH_CUSTOM
|
||||
|
||||
export LYRICS_LOADED=1
|
||||
fi
|
||||
|
||||
# File path for lyrics file
|
||||
#
|
||||
# @argument $1: MusicBrainz track ID
|
||||
lyrics_file() {
|
||||
mbid="${1:-}"
|
||||
echo "$LYRICS_DIRECTORY/$(__radix "$mbid").lrc"
|
||||
}
|
||||
|
||||
# Store lyrics
|
||||
#
|
||||
# @argument $1: MusicBrainz track ID
|
||||
#
|
||||
# This methods reads from stdin and stores it.
|
||||
store_lyrics() {
|
||||
mbid="${1:-}"
|
||||
file="$(lyrics_file "$mbid")"
|
||||
dir="$(dirname "$file")"
|
||||
[ -d "$dir" ] || mkdir -p "$dir"
|
||||
cat >"$file"
|
||||
}
|
||||
|
||||
# Fetch lyrics using custom command and store them
|
||||
#
|
||||
# @argument $1: MusicBrainz release ID
|
||||
# @argument $2: MusicBrainz track ID
|
||||
store_lyrics_custom() {
|
||||
rlid="${1:-}"
|
||||
mbid="${2:-}"
|
||||
mb_release "$rlid" |
|
||||
$JQ --arg mbid "$mbid" '{release: ., trackid: $mbid}' |
|
||||
sh -c "$LYRICS_FETCH_CUSTOM" |
|
||||
store_lyrics "$mbid"
|
||||
}
|
||||
|
||||
# Print lyrics
|
||||
#
|
||||
# @argument $1: MusicBrainz release ID
|
||||
# @argument $2: MusicBrainz track ID
|
||||
lyrics() {
|
||||
rlid="${1:-}"
|
||||
mbid="${2:-}"
|
||||
# 1. Check if lyrics has already been stored
|
||||
file="$(lyrics_file "$mbid")"
|
||||
if [ -f "$file" ]; then
|
||||
cat "$file"
|
||||
return
|
||||
fi
|
||||
# 2. & 3.: For playable tracks only
|
||||
decoration="$(grep "^$rlid" "$LOCALDATA_RELEASES" | cut -d "$(printf '\t')" -f 2)"
|
||||
if [ "$decoration" ] && [ -f "$decoration" ]; then
|
||||
afname="$($JQ --arg mbid "$mbid" '.tracks | to_entries[] | select(.key == $mbid) | .value' "$decoration")"
|
||||
af="$(dirname "$decoration")/$afname"
|
||||
# Check if `.lrc` file exists
|
||||
lf="$(echo "$af" | rev | cut -d "." -f 2- | rev).lrc"
|
||||
if [ -f "$lf" ]; then
|
||||
store_lyrics "$mbid" <"$lf"
|
||||
cat "$file"
|
||||
return
|
||||
fi
|
||||
# Read lyrics from tag
|
||||
if [ "$FFPROBE" ]; then
|
||||
lyrics="$($FFPROBE -v error -show_entries format_tags -print_format json "$af" |
|
||||
$JQ '.format.tags | ."USLT:description" // ."LYRICS" // ."Lyrics" // ."©lyr" // ."WM/Lyrics" // ""')"
|
||||
if [ "$lyrics" ]; then
|
||||
echo "$lyrics" | store_lyrics "$mbid"
|
||||
cat "$file"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# Make call to external command
|
||||
store_lyrics_custom "$rlid" "$mbid"
|
||||
cat "$file"
|
||||
}
|
||||
|
||||
# Reload lyrics file
|
||||
#
|
||||
# @argument $1: MusicBrainz release ID
|
||||
# @argument $2: MusicBrainz track ID
|
||||
reload_lyrics() {
|
||||
rlid="${1:-}"
|
||||
mbid="${2:-}"
|
||||
file="$(lyrics_file "$mbid")"
|
||||
rm -f "$file"
|
||||
lyrics "$rlid" "$mbid"
|
||||
}
|
||||
@@ -55,5 +55,25 @@ if [ ! "${TOOLS_LOADED:-}" ]; then
|
||||
command -v "xsel" >/dev/null && CLIP="xsel" || CLIP="true"
|
||||
export CLIP
|
||||
|
||||
# Detect external editor
|
||||
editor="${EDITOR:-vi}"
|
||||
if command -v "$editor" >/dev/null; then
|
||||
if command -v "kitty" >/dev/null; then
|
||||
extedit=$(printf "kitty %s" "$editor")
|
||||
elif command -v "x-terminal-emulator" >/dev/null; then
|
||||
extedit=$(printf "x-terminal-emulator -e %s" "$editor")
|
||||
elif command -v "gnome-terminal" >/dev/null; then
|
||||
extedit=$(printf "gnome-terminal -- %s" "$editor")
|
||||
elif command -v "xterm" >/dev/null; then
|
||||
extedit=$(printf "xterm -e %s" "$editor")
|
||||
else
|
||||
extedit=""
|
||||
fi
|
||||
else
|
||||
extedit=""
|
||||
fi
|
||||
EXTERNALEDIT="${EXTERNALEDIT:-"$extedit"}"
|
||||
export EXTERNALEDIT
|
||||
|
||||
export TOOLS_LOADED=1
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user