Initial commit
This commit is contained in:
188
fuzzique
Executable file
188
fuzzique
Executable file
@@ -0,0 +1,188 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
if [ "${1:-}" = "--info" ]; then
|
||||
shift
|
||||
file="$1"
|
||||
rel=${file#"$ROOT/"}
|
||||
artist=$(echo "$rel" | cut -d "/" -f 1)
|
||||
release=$(echo "$rel" | cut -d "/" -f 2)
|
||||
d=$(echo "$rel" | awk -F'/' '{ print NF }')
|
||||
[ "$d" -eq 2 ] && printf ">> $AFMT" "$artist"
|
||||
[ "$d" -eq 3 ] && printf ">> $AFMT >> $RFMT" "$artist" "$release"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "${1:-}" = "--preview" ]; then
|
||||
shift
|
||||
file="$1"
|
||||
tags=$(ffprobe -v quiet -show_entries format -of json "$file" | jq)
|
||||
{
|
||||
echo "## Lyrics"
|
||||
echo ""
|
||||
printf "%s" "$tags" | jq -C -r '.format.tags.LYRICS'
|
||||
} | batcat --color always --number --language md
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "${1:-}" = "--show-playlist" ]; then
|
||||
[ ! -S "${MPV_SOCKET:-}" ] && exit 1
|
||||
count=$(echo "{ \"command\": [\"expand-text\",\"\${playlist/count}\"] }" | socat - "$MPV_SOCKET" | jq -r '.data')
|
||||
for i in $(seq 0 $((count - 1))); do
|
||||
file=$(echo "{ \"command\": [\"expand-text\",\"\${playlist/$i/filename}\"] }" | socat - "$MPV_SOCKET" | jq -r '.data')
|
||||
curr=$(echo "{ \"command\": [\"expand-text\",\"\${playlist/$i/current}\"] }" | socat - "$MPV_SOCKET" | jq -r '.data')
|
||||
pnt=" "
|
||||
[ "$curr" = "yes" ] && pnt="👉"
|
||||
artist=$(echo "$file" | rev | cut -d "/" -f 3 | rev)
|
||||
release=$(echo "$file" | rev | cut -d "/" -f 2 | rev)
|
||||
title=$(echo "$file" | rev | cut -d "/" -f 1 | rev | sed 's/\..*$//')
|
||||
artist=$(printf "$AFMT" "$artist")
|
||||
release=$(printf "$RFMT" "$release")
|
||||
title=$(printf "$TFMT" "$title")
|
||||
printf "%s|%s|%s|%s\t%s\n" "$pnt" "$title" "$release" "$artist" "$file"
|
||||
done | grep '.' | column -t -s '|'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if command -v "bat" >/dev/null; then
|
||||
CAT="bat"
|
||||
elif command -v "batcat" >/dev/null; then
|
||||
CAT="batcat"
|
||||
fi
|
||||
CAT=${CAT:+$CAT --color=always --style=plain --language=md}
|
||||
CAT=${CAT:-cat}
|
||||
export CAT
|
||||
|
||||
if [ "${1:-}" = "--help" ]; then
|
||||
$CAT <<EOF
|
||||
Usage: \`$0 [ --help | [ MUSIC_DIRECTORY [ --reset-cache ] ] ]\`
|
||||
|
||||
The \`MUSIC_DIRECTORY\` is the path to a folder with the following tree
|
||||
structure: \`./<artist>/<album>/<track>\`. For instance:
|
||||
\`\`\`sh
|
||||
$ tree /media/Musik
|
||||
/media/Musik/Mos Def
|
||||
└── Black on Both Sides
|
||||
├── 01 Fear Not of Man.m4a
|
||||
├── 02 Hip Hop.m4a
|
||||
├── 03 Love.m4a
|
||||
├── 04 Ms. Fat Booty.m4a
|
||||
├── 05 Speed Law.m4a
|
||||
├── 06 Do It Now.m4a
|
||||
├── 07 Got.m4a
|
||||
├── 08 Umi Says.m4a
|
||||
├── 09 New World Water.m4a
|
||||
├── 10 Rock n Roll.m4a
|
||||
├── 11 Know That.m4a
|
||||
├── 12 Climb.m4a
|
||||
├── 13 Brooklyn.m4a
|
||||
├── 14 Habitat.m4a
|
||||
├── 15 Mr. Nigga.m4a
|
||||
├── 16 Mathematics.m4a
|
||||
├── 17 May‐December.m4a
|
||||
└── cover.jpg
|
||||
\`\`\`
|
||||
|
||||
[OPTIONS]
|
||||
\`--help\`: Show this help and exit
|
||||
\`--reset-cache\`: Reset cache for specified \`MUSIC_DIRECTORY\`
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
[ "${1:-}" ] && ROOT="$1" && shift
|
||||
[ ! -d "${ROOT:-}" ] && echo "Faild to recognize music directory. Run $0 --help." && exit 1
|
||||
ROOT=${ROOT%%/}
|
||||
CACHE="$HOME/.cache/fuzzique"
|
||||
ROOTHASH=$(echo "$ROOT" | sha1sum | cut -d ' ' -f 1)
|
||||
CACHE="$CACHE/$ROOTHASH"
|
||||
DEPTH=$(echo "$ROOT" | awk -F'/' '{ print NF }')
|
||||
FD=/usr/bin/fdfind
|
||||
FZF=fzf
|
||||
MPV=mpv
|
||||
MPV_SOCKET="$(mktemp --suffix=.sock)"
|
||||
ARTIST_COLOR='\033[38;5;202m'
|
||||
RELEASE_COLOR='\033[38;5;208m'
|
||||
TRACK_COLOR='\033[38;5;215m'
|
||||
OFF="\033[m"
|
||||
AFMT="🎤 ${ARTIST_COLOR}%s${OFF}"
|
||||
RFMT="💽 ${RELEASE_COLOR}%s${OFF}"
|
||||
TFMT="🎵 ${TRACK_COLOR}%s${OFF}"
|
||||
export ROOT MPV_SOCKET AFMT RFMT TFMT
|
||||
|
||||
# Load
|
||||
artists_file="$CACHE/artists"
|
||||
release_file="$CACHE/release"
|
||||
tracks_file="$CACHE/tracks"
|
||||
if [ "${1:-}" = "--build-db" ] || [ ! -f "$artists_file" ]; then
|
||||
rm -rf "$CACHE"
|
||||
mkdir -p "$CACHE"
|
||||
[ ! -d "$CACHE" ] && echo "Failed to create cache directory" && exit 1
|
||||
{
|
||||
$FD --max-depth 2 --type d . "$ROOT"
|
||||
$FD --exact-depth 3 --type f -i -e "mp3" -e "mp4" -e "m4a" -e "ogg" -e "flac" -e "wav" . "$ROOT"
|
||||
} |
|
||||
sort |
|
||||
awk \
|
||||
-F'/' \
|
||||
-v afmt="$AFMT" \
|
||||
-v rfmt="$RFMT" \
|
||||
-v tfmt="$TFMT" \
|
||||
-v depth="$DEPTH" \
|
||||
-v artists_file="$artists_file" \
|
||||
-v release_file="$release_file" \
|
||||
-v tracks_file="$tracks_file" \
|
||||
'BEGIN {
|
||||
OFS="\t"
|
||||
iartist = depth + 1
|
||||
irelease = depth + 2
|
||||
itrack = depth + 3
|
||||
}
|
||||
NF >= depth + 1 { ar = sprintf(afmt, $iartist) }
|
||||
NF >= depth + 2 { rl = sprintf(rfmt, $irelease) }
|
||||
NF >= depth + 3 { tr = $itrack; gsub(/\..*$/, "", tr); tr = sprintf(tfmt, tr) }
|
||||
NF == depth + 1 { print ar, $0 >> artists_file }
|
||||
NF == depth + 2 { print rl, $0 >> release_file }
|
||||
NF == depth + 3 { print tr, $0 >> tracks_file }
|
||||
'
|
||||
# NF == depth + 1 { print ar, $0 >> artists_file }
|
||||
# NF == depth + 2 { print rl "|" ar, $0 >> release_file }
|
||||
# NF == depth + 3 { print tr "|" rl "|" ar, $0 >> tracks_file }
|
||||
fi
|
||||
|
||||
$MPV --no-config --no-terminal --input-ipc-server="$MPV_SOCKET" --idle &
|
||||
|
||||
$FZF \
|
||||
--reverse \
|
||||
--ansi \
|
||||
--no-sort \
|
||||
--delimiter="\t" \
|
||||
--with-nth="{1}" \
|
||||
--cycle \
|
||||
--info=inline-right \
|
||||
--info-command="$0 --info {2}" \
|
||||
--bind="ctrl-d:half-page-down,ctrl-u:half-page-up" \
|
||||
--bind="enter:execute:printf '{ \"command\": [\"loadfile\", \"%s\"] }\n' {2} | socat - \"$MPV_SOCKET\"" \
|
||||
--bind="alt-enter:execute:printf '{ \"command\": [\"loadfile\", \"%s\", \"append-play\"] }\n' {2} | socat - \"$MPV_SOCKET\"" \
|
||||
--bind="alt-t:show-input+reload:cat \"$tracks_file\" | column -t -s '|' -E 0" \
|
||||
--bind="alt-r:show-input+reload:cat \"$release_file\" | column -t -s '|'" \
|
||||
--bind="alt-a:show-input+reload:cat \"$artists_file\" | column -t -s '|'" \
|
||||
--bind="ctrl-l:show-input+transform:
|
||||
d=\$(echo {2} | awk -F'/' '{ print NF }')
|
||||
[ \"\$d\" -eq \"$((DEPTH + 1))\" ] && echo \"reload:grep -F {2}/ \\\"$release_file\\\" | column -t -s '|' || true\"
|
||||
[ \"\$d\" -eq \"$((DEPTH + 2))\" ] && echo \"reload:grep -F {2}/ \\\"$tracks_file\\\" | column -t -s '|' || true\"
|
||||
" \
|
||||
--bind="ctrl-h:show-input+transform:
|
||||
d=\$(echo {2} | awk -F'/' '{ print NF }')
|
||||
p=\$(echo {2} | rev | cut -d '/' -f 3- | rev)
|
||||
[ \"\$d\" -eq \"$((DEPTH + 3))\" ] && echo \"reload:grep -F \\\"\$p/\\\" \\\"$release_file\\\" | column -t -s '|' || true\"
|
||||
[ \"\$d\" -eq \"$((DEPTH + 2))\" ] && echo \"reload:grep -F \\\"\$p/\\\" \\\"$artists_file\\\" | column -t -s '|' || true\"
|
||||
" \
|
||||
--bind="ctrl-p:hide-input+reload:$0 --show-playlist" \
|
||||
--preview="$0 --preview {2}" \
|
||||
--bind="alt-/:toggle-preview" \
|
||||
<"$artists_file" || true
|
||||
|
||||
printf '{ "command": ["quit"] }\n' | socat - "$MPV_SOCKET"
|
||||
rm -f "$MPV_SOCKET"
|
Reference in New Issue
Block a user