mpvd

[discontinued] Simple daemonization script for mpv with controller
git clone https://noxz.tech/git/mpvd.git
Log | Files | LICENSE

commit: 6e355b26554ea07bba04d4b740f266ab22d77926
parent: ff6ee386fb5bb51060a682982696de69c910b8ed
author: Chris Noxz <chris@noxz.tech>
date:   Fri, 9 Jul 2021 15:37:04 +0200
Update to match code in dotfiles
Mmpvc301++++++++++++++------
1 file changed, 213 insertions(+), 88 deletions(-)
diff --git a/mpvc b/mpvc
@@ -1,113 +1,238 @@
 #!/bin/sh
 
-mpvfifo="/tmp/mpv.fifo"
+mpvdsock="/tmp/mpvd.sock"
+xobfifo="/tmp/xob.fifo"
+cmd_socat="$(command -v socat) - '$mpvdsock'"
+cmd_jq="$(command -v jq)"
+cmd_exif="$(command -v exiftool)"
 
 print_help() {
-    echo "Usage: mpvc ACTION [ARGS]\n"
-    echo "ACTIONS:"
-    echo " append         append file to playlist."
-    echo " help           print this help message."
-    echo " load           load file, and override playlist."
-    echo " next           go to next track."
-    echo " prev           go to previous track."
-    echo " seek           seek (-)n seconds"
-    echo " toggle         toogle play and pause."
-    echo " lower          lower volume 10 units"
-    echo " mute           toggle mute"
-    echo " raise          raise volume 10 units"
-    echo " "
-    echo "EXTRA:"
-    echo " ytdl-format    set ytdl-format"
-    echo " "
-    echo "ALSA:"
-    echo " alower         alsa lower 5%"
-    echo " amute          alsa mute"
-    echo " araise         alsa raise 5%"
+	echo "Usage: mpvc ACTION [ARGS]\n"
+	echo "ACTIONS:"
+	echo " append PATH      append file to playlist."
+	echo " goto INDEX       goto track index of playlist."
+	echo " help             print this help message."
+	echo " list             print playlist."
+	echo " load PATH        load file or directory, and override playlist."
+	echo " lower            lower volume 10 units"
+	echo " mute             toggle mute"
+	echo " next             go to next track."
+	echo " plmenu MODE      launch playlist menu."
+	echo " prev             go to previous track."
+	echo " raise            raise volume 10 units"
+	echo " seek (-)N        seek (-)n seconds"
+	echo " stop             stop playback"
+	echo " toggle           toogle play and pause."
+	echo " "
+	echo "EXTRA:"
+	echo " ytdl-format FMT  set ytdl-format"
+	echo " "
+	echo "ALSA:"
+	echo " alower           alsa lower 5%"
+	echo " amute            alsa mute"
+	echo " araise           alsa raise 5%"
 }
 
 send_command() {
-    local input=""
-    for var in "$@"; do
-        [ "$input" != "" ] && input="$input, "
+	local input=""
+	for var in "$@"; do
+		[ "$input" != "" ] && input="$input, "
 	input="$input\"$var\""
-    done
-    printf '{ "command": [%s] }\n' "$input" > "$mpvfifo"
+	done
+	printf '{ "command": [%s] }\n' "$input" | $cmd_socat
 }
 
 get_path() {
-    local path="$(readlink -f "$@")"
-    if [ -f "$path" ]; then
-        echo "$path"
-    else
-        echo "$@"
-    fi
+	local path="$(readlink -f "$@")"
+	if [ -f "$path" ] || [ -d "$path" ]; then
+		echo "$path"
+	else
+		echo "$@"
+	fi
 }
 
+notify_vol() {
+	case $1 in
+	master)
+		local level="$(amixer sget Master | awk -F"[][]" '/dB/ { print ($2+0) }')"
+	local muted="$(amixer sget Master | awk -F"[][]" '/dB/ { print ($6) }' | sed 's/off/true/')"
+		;;
+	mpv)
+		local level="$(send_command "get_property" "volume" | $cmd_jq -rM '.data')"
+		local muted="$(send_command "get_property" "mute" | $cmd_jq -rM '.data')"
+		;;
+	*) return;;
+	esac
+
+	local marks="$((($level + 5) / 10))"
+	[ "$marks" -gt 10 ] && marks=10
+
+	local output="$1"
+	if [ "$muted" = "true" ]; then
+		local output="$output (muted)"
+	fi
+	local output="$output: [$([ "$marks" -gt 0 ] && printf "%-$((marks))s" "+" | sed 's/\ /+/g')"
+	local output="$output$([ "$marks" -lt 10 ] && printf "%-$((10-marks))s" " ")]"
+	local output="$output$(printf " %3d" "$level")%"
+	ztatus-notify "$output"
+
+	if [ -p "$xobfifo" ]; then
+		printf '%d%s\n' "$level" "$([ "$muted" = "true" ] && echo '!')" \
+		> "$xobfifo"
+	fi
+}
+
+die() {
+	printf "Error: %s\n" "$@"
+	exit 1
+}
+
+# check if prerequisites exist
+[ -z "$cmd_socat" ] && die "could not find 'socat'"
+[ -z "$cmd_jq" ] && die "could not find 'jq'"
+[ -z "$cmd_exif" ] && die "could not find 'exiftool'"
+
 # check if daemonization should apply
 if [ "${0##*/}" = "mpvd" ]; then
-    [ -p "$mpvfifo" ] && rm "$mpvfifo"
-
-    mkfifo "$mpvfifo"
-    chmod 600 "$mpvfifo"
-
-    while true; do
-        mpv --idle \
-            --input-file="$mpvfifo" \
-	    --ytdl-format=best \
-	    --load-scripts=yes
-    done
-    exit 0
+	if pidof -x "$(basename -- "$0")" -o $$ >/dev/null; then
+		die "Another instance of mpvd is already runnig..."
+	fi
+	[ -S "$mpvdsock" ] && rm "$mpvdsock"
+	while true; do
+		mpv --idle=yes \
+			--input-ipc-server="$mpvdsock" \
+		--ytdl-format=best \
+		--load-scripts=yes \
+		2>&1 >/tmp/mpvd.log
+	done
+	exit 0
 fi
 
-# check if fifo exists
-if [ ! -p "$mpvfifo" ]; then
-    echo "$tmpfifo is missing"
-    exit 1
-fi
+# check if socket exists
+[ ! -S "$mpvdsock" ] && die "socket: '$mpvdsock' is missing"
 
 # print help if no argument was passed
 if [ $# -lt 1 ]; then
-    print_help
-    exit 0
+	print_help
+	exit 0
 fi
 
+show_playlist() {
+	cmd="fzf"
+	[ "$1" = "x" ] && cmd="dmenu_vtc -l 20 -p playlist:"
+	script="$(realpath -s $0)"
+	list="$($script list)"
+	[ "$list" = "" ] && exit 1
+	entry="$(
+		echo "$list"                                                        \
+		| sed -e  's/^[ \t]*/  /' -e 's/^[^\w]*current[^\t]*\t/> /'         \
+		| awk '{printf "%-5s %s\n", (NR  ": "), $0}'                        \
+		| $cmd                                                              \
+	)"
+	[ "$entry" != "" ] && $script goto "$((${entry%%:*}-1))" || exit 1
+}
+
+exif_extract() {
+	echo "$1" | grep ^"$2" | cut -d':' -f 2- | sed 's/^[ \t]*//'
+}
+
+exif_wrapper() {
+	exif_data="$($cmd_exif -directory -filename -artist -title -duration "$@")"
+	exif_directory="$(exif_extract "$exif_data" "Directory")"
+	exif_filename="$(exif_extract "$exif_data" "File Name")"
+	exif_artist="$(exif_extract "$exif_data" "Artist")"
+	exif_title="$(exif_extract "$exif_data" "Title")"
+	exif_duration="$(exif_extract "$exif_data" "Duration")"
+	exif_artisttitle="$exif_filename"
+
+	if [ "$exif_artist" != "" ] && [ "$exif_title" != "" ]; then
+		exif_artisttitle="$exif_artist - $exif_title"
+	fi
+
+	exif_directory="$(get_path "$exif_directory")"
+
+	# make sure duration is in the format of 'hh:mm:ss' then to seconds (awk)
+	exif_duration="$(echo "$exif_duration" | cut -d' ' -f 1)"
+	exif_duration="$(                                                       \
+		printf '0:0:%s' "$exif_duration"                                    \
+		| rev | cut -d':' -f -3 | rev                                       \
+		| awk -F':' '{ print ($1 * 3600) + ($2 * 60) + $3 }'                \
+	)"
+
+	echo "$(printf '#EXTINF:%s,%s\n%s/%s\n'                                 \
+		"$exif_duration"                                                    \
+		"$exif_artisttitle"                                                 \
+		"$exif_directory"                                                   \
+		"$exif_filename"                                                    \
+	)"
+}
+
 case "$1" in
+	# actions
+	load)
+		shift;
+		playlist="$(get_path "$@")"
+		if [ -d "$playlist" ]; then
+			playlist_tmp="$(mktemp /tmp/pls.mpvc.XXXXXXXXXX)"
+			echo '#EXTM3U' > "$playlist_tmp"
+			find "$playlist" -maxdepth 2 -type f | sort -n | while read -r f; do
+				case "$f" in
+				*.flac | *.mp3 | *.ogg)
+					exif_wrapper "$f" >> "$playlist_tmp" ;;
+				*) continue ;;
+				esac
+			done
+			playlist="$playlist_tmp"
+		fi
+		send_command "loadfile" "$playlist"
+		[ "$playlist_tmp" != "" ] && (sleep 10 && rm "$playlist_tmp") &
+		;;
+	append)
+		shift; send_command "loadfile" "$(get_path "$@")" "append" ;;
+	stop)
+		send_command "stop" ;;
+	toggle)
+		send_command "cycle" "pause" ;;
+	prev)
+		send_command "playlist-prev" ;;
+	next)
+		send_command "playlist-next" ;;
+	goto)
+		shift; send_command "set_property" "playlist-pos" "$@" ;;
+	list)
+		send_command "get_property" "playlist" \
+		| $cmd_jq -rM '.data[]|(
+			if .current then
+				"\\e[1;37mcurrent\\e[0m\\t"
+			else
+				"\\t" end
+		)+(.title//.filename)' \
+		| sed -e "s/\\\\t/\\t/g" -e "s/\\\\e/`printf "\033"`/g";;
+	plmenu) shift; show_playlist "$@" ;;
+	seek)
+		shift; send_command "seek" "$@" ;;
+	mute)
+		send_command "cycle" "mute"; notify_vol mpv;;
+	raise)
+		send_command "add" "volume" "10"; notify_vol mpv;;
+	lower)
+		send_command "add" "volume" "-10"; notify_vol mpv;;
+
+	# extra
+	ytdl-format)
+		shift; send_command "set" "ytdl-format" "$@" ;;
+
+	# alsa
+	amute)
+		amixer set Master toggle; notify_vol master;;
+	araise)
+		amixer -q sset Master 5%+; notify_vol master;;
+	alower)
+		amixer -q sset Master 5%-; notify_vol master;;
 
-    # actions
-    load)
-        shift; send_command "loadfile" "$(get_path "$@")" ;;
-    append)
-        shift; send_command "loadfile" "$(get_path "$@")" "append" ;;
-    toggle)
-        send_command "cycle" "pause" ;;
-    prev)
-        send_command "playlist-prev" ;;
-    next)
-        send_command "playlist-next" ;;
-    seek)
-        shift; send_command "seek" "$@" ;;
-    mute)
-        send_command "cycle" "mute" ;;
-    raise)
-        send_command "add" "volume" "10" ;;
-    lower)
-        send_command "add" "volume" "-10" ;;
-
-    # extra
-    ytdl-format)
-        shift; send_command "set" "ytdl-format" "$@" ;;
-
-    # alsa
-    amute)
-        amixer set Master toggle ;;
-    araise)
-        amixer -q sset Master 5%+; ztatusc update volume ;;
-    alower)
-        amixer -q sset Master 5%-; ztatusc update volume ;;
-
-    # default behaviour
-    help)
-        print_help ;;
-    *)
-        echo "Unknown option: $*"; print_help ;;
+	# default behaviour
+	help)
+		print_help ;;
+	*)
+		echo "Unknown option: $*"; print_help ;;
 esac