mpvd

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

mpvc
1#!/bin/sh
2
3mpvdsock="/tmp/mpvd.sock"
4xobfifo="/tmp/xob.fifo"
5cmd_socat="$(command -v socat) - '$mpvdsock'"
6cmd_jq="$(command -v jq)"
7cmd_exif="$(command -v exiftool)"
8
9print_help() {
10	echo "Usage: mpvc ACTION [ARGS]\n"
11	echo "ACTIONS:"
12	echo " append PATH      append file to playlist."
13	echo " goto INDEX       goto track index of playlist."
14	echo " help             print this help message."
15	echo " list             print playlist."
16	echo " load PATH        load file or directory, and override playlist."
17	echo " lower            lower volume 10 units"
18	echo " mute             toggle mute"
19	echo " next             go to next track."
20	echo " plmenu MODE      launch playlist menu."
21	echo " prev             go to previous track."
22	echo " raise            raise volume 10 units"
23	echo " seek (-)N        seek (-)n seconds"
24	echo " stop             stop playback"
25	echo " toggle           toogle play and pause."
26	echo " "
27	echo "EXTRA:"
28	echo " ytdl-format FMT  set ytdl-format"
29	echo " "
30	echo "ALSA:"
31	echo " alower           alsa lower 5%"
32	echo " amute            alsa mute"
33	echo " araise           alsa raise 5%"
34}
35
36send_command() {
37	local input=""
38	for var in "$@"; do
39		[ "$input" != "" ] && input="$input, "
40	input="$input\"$var\""
41	done
42	printf '{ "command": [%s] }\n' "$input" | $cmd_socat
43}
44
45get_path() {
46	local path="$(readlink -f "$@")"
47	if [ -f "$path" ] || [ -d "$path" ]; then
48		echo "$path"
49	else
50		echo "$@"
51	fi
52}
53
54notify_vol() {
55	case $1 in
56	master)
57		local level="$(amixer sget Master | awk -F"[][]" '/dB/ { print ($2+0) }')"
58	local muted="$(amixer sget Master | awk -F"[][]" '/dB/ { print ($6) }' | sed 's/off/true/')"
59		;;
60	mpv)
61		local level="$(send_command "get_property" "volume" | $cmd_jq -rM '.data')"
62		local muted="$(send_command "get_property" "mute" | $cmd_jq -rM '.data')"
63		;;
64	*) return;;
65	esac
66
67	local marks="$((($level + 5) / 10))"
68	[ "$marks" -gt 10 ] && marks=10
69
70	local output="$1"
71	if [ "$muted" = "true" ]; then
72		local output="$output (muted)"
73	fi
74	local output="$output: [$([ "$marks" -gt 0 ] && printf "%-$((marks))s" "+" | sed 's/\ /+/g')"
75	local output="$output$([ "$marks" -lt 10 ] && printf "%-$((10-marks))s" " ")]"
76	local output="$output$(printf " %3d" "$level")%"
77	ztatus-notify "$output"
78
79	if [ -p "$xobfifo" ]; then
80		printf '%d%s\n' "$level" "$([ "$muted" = "true" ] && echo '!')" \
81		> "$xobfifo"
82	fi
83}
84
85die() {
86	printf "Error: %s\n" "$@"
87	exit 1
88}
89
90# check if prerequisites exist
91[ -z "$cmd_socat" ] && die "could not find 'socat'"
92[ -z "$cmd_jq" ] && die "could not find 'jq'"
93[ -z "$cmd_exif" ] && die "could not find 'exiftool'"
94
95# check if daemonization should apply
96if [ "${0##*/}" = "mpvd" ]; then
97	if pidof -x "$(basename -- "$0")" -o $$ >/dev/null; then
98		die "Another instance of mpvd is already runnig..."
99	fi
100	[ -S "$mpvdsock" ] && rm "$mpvdsock"
101	while true; do
102		mpv --idle=yes \
103			--input-ipc-server="$mpvdsock" \
104		--ytdl-format=best \
105		--load-scripts=yes \
106		2>&1 >/tmp/mpvd.log
107	done
108	exit 0
109fi
110
111# check if socket exists
112[ ! -S "$mpvdsock" ] && die "socket: '$mpvdsock' is missing"
113
114# print help if no argument was passed
115if [ $# -lt 1 ]; then
116	print_help
117	exit 0
118fi
119
120show_playlist() {
121	cmd="fzf"
122	[ "$1" = "x" ] && cmd="dmenu_vtc -l 20 -p playlist:"
123	script="$(realpath -s $0)"
124	list="$($script list)"
125	[ "$list" = "" ] && exit 1
126	entry="$(
127		echo "$list"                                                        \
128		| sed -e  's/^[ \t]*/  /' -e 's/^[^\w]*current[^\t]*\t/> /'         \
129		| awk '{printf "%-5s %s\n", (NR  ": "), $0}'                        \
130		| $cmd                                                              \
131	)"
132	[ "$entry" != "" ] && $script goto "$((${entry%%:*}-1))" || exit 1
133}
134
135exif_extract() {
136	echo "$1" | grep ^"$2" | cut -d':' -f 2- | sed 's/^[ \t]*//'
137}
138
139exif_wrapper() {
140	exif_data="$($cmd_exif -directory -filename -artist -title -duration "$@")"
141	exif_directory="$(exif_extract "$exif_data" "Directory")"
142	exif_filename="$(exif_extract "$exif_data" "File Name")"
143	exif_artist="$(exif_extract "$exif_data" "Artist")"
144	exif_title="$(exif_extract "$exif_data" "Title")"
145	exif_duration="$(exif_extract "$exif_data" "Duration")"
146	exif_artisttitle="$exif_filename"
147
148	if [ "$exif_artist" != "" ] && [ "$exif_title" != "" ]; then
149		exif_artisttitle="$exif_artist - $exif_title"
150	fi
151
152	exif_directory="$(get_path "$exif_directory")"
153
154	# make sure duration is in the format of 'hh:mm:ss' then to seconds (awk)
155	exif_duration="$(echo "$exif_duration" | cut -d' ' -f 1)"
156	exif_duration="$(                                                       \
157		printf '0:0:%s' "$exif_duration"                                    \
158		| rev | cut -d':' -f -3 | rev                                       \
159		| awk -F':' '{ print ($1 * 3600) + ($2 * 60) + $3 }'                \
160	)"
161
162	echo "$(printf '#EXTINF:%s,%s\n%s/%s\n'                                 \
163		"$exif_duration"                                                    \
164		"$exif_artisttitle"                                                 \
165		"$exif_directory"                                                   \
166		"$exif_filename"                                                    \
167	)"
168}
169
170case "$1" in
171	# actions
172	load)
173		shift;
174		playlist="$(get_path "$@")"
175		if [ -d "$playlist" ]; then
176			playlist_tmp="$(mktemp /tmp/pls.mpvc.XXXXXXXXXX)"
177			echo '#EXTM3U' > "$playlist_tmp"
178			find "$playlist" -maxdepth 2 -type f | sort -n | while read -r f; do
179				case "$f" in
180				*.flac | *.mp3 | *.ogg)
181					exif_wrapper "$f" >> "$playlist_tmp" ;;
182				*) continue ;;
183				esac
184			done
185			playlist="$playlist_tmp"
186		fi
187		send_command "loadfile" "$playlist"
188		[ "$playlist_tmp" != "" ] && (sleep 10 && rm "$playlist_tmp") &
189		;;
190	append)
191		shift; send_command "loadfile" "$(get_path "$@")" "append" ;;
192	stop)
193		send_command "stop" ;;
194	toggle)
195		send_command "cycle" "pause" ;;
196	prev)
197		send_command "playlist-prev" ;;
198	next)
199		send_command "playlist-next" ;;
200	goto)
201		shift; send_command "set_property" "playlist-pos" "$@" ;;
202	list)
203		send_command "get_property" "playlist" \
204		| $cmd_jq -rM '.data[]|(
205			if .current then
206				"\\e[1;37mcurrent\\e[0m\\t"
207			else
208				"\\t" end
209		)+(.title//.filename)' \
210		| sed -e "s/\\\\t/\\t/g" -e "s/\\\\e/`printf "\033"`/g";;
211	plmenu) shift; show_playlist "$@" ;;
212	seek)
213		shift; send_command "seek" "$@" ;;
214	mute)
215		send_command "cycle" "mute"; notify_vol mpv;;
216	raise)
217		send_command "add" "volume" "10"; notify_vol mpv;;
218	lower)
219		send_command "add" "volume" "-10"; notify_vol mpv;;
220
221	# extra
222	ytdl-format)
223		shift; send_command "set" "ytdl-format" "$@" ;;
224
225	# alsa
226	amute)
227		amixer set Master toggle; notify_vol master;;
228	araise)
229		amixer -q sset Master 5%+; notify_vol master;;
230	alower)
231		amixer -q sset Master 5%-; notify_vol master;;
232
233	# default behaviour
234	help)
235		print_help ;;
236	*)
237		echo "Unknown option: $*"; print_help ;;
238esac