#!/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 <//\`. 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"