music.git

commit ef5034efc6730ecc8a4307c8112148d8637735b7

Author: Adam <git@apiote.tk>

play music

 file/select | 8 ++
 local/actions/index | 19 ++++++
 local/select | 3 +
 mkfile | 25 ++++++++
 music | 133 +++++++++++++++++++++++++++++++++++++++++++++++
 play | 81 ++++++++++++++++++++++++++++
 queue | 1 
 stream/select | 4 +
 yt/select | 8 ++


diff --git a/file/select b/file/select
new file mode 100755
index 0000000000000000000000000000000000000000..3b981261dfde7494ca86a3dc644593c6edbd433e
--- /dev/null
+++ b/file/select
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+if [ "$1" = '' ]
+then
+	echo "File to play not given" >&2
+else
+	echo "file://$1"
+fi




diff --git a/local/actions/index b/local/actions/index
new file mode 100755
index 0000000000000000000000000000000000000000..29ed819c54ce7acda6524e6291e7ec42bfdb50cf
--- /dev/null
+++ b/local/actions/index
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+DATA_HOME=${XDG_DATA_HOME:-"$HOME/.local/share"}
+index="$DATA_HOME/music/index"
+
+i() {
+	probe=$(ffprobe "$1" 2>&1)
+	album=$(echo "$probe" | grep -i 'album ' | cut -d ':' -f2 | cut -d ' ' -f2-)
+	album_artist=$(echo "$probe" | grep -i 'album_artist ' | cut -d ':' -f2 | cut -d ' ' -f2-)
+	title=$(echo "$probe" | grep -i 'title ' | head -n1 | cut -d ':' -f2 | cut -d ' ' -f2-)
+	echo "$album_artist/$album/$titlefile://$1"
+}
+
+if [ "$1" != '-a' ]
+then
+	echo >"$index"
+fi
+
+find "$(pwd)" -type f | while read -r song; do i "$song"; done >>"$index"




diff --git a/local/select b/local/select
new file mode 100755
index 0000000000000000000000000000000000000000..31be4797dff24d62ecb9a074e2771567e1cd5d69
--- /dev/null
+++ b/local/select
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+fzf --bind 'ctrl-a:toggle-all' -m -d '' --with-nth=1 < ~/.local/share/play/index




diff --git a/mkfile b/mkfile
new file mode 100644
index 0000000000000000000000000000000000000000..9d7768c77ac7430b9b6c2be9fc9bce8a9635b19f
--- /dev/null
+++ b/mkfile
@@ -0,0 +1,25 @@
+all:V: install
+
+PREFIX=`echo ${PREFIX:-/usr/local}`
+install:V: music play local yt file stream #playlist
+	mkdir -m755 -p $PREFIX/bin
+	cp music $PREFIX/bin/music
+	chmod 755 $PREFIX/bin/music
+	cp play $PREFIX/bin/play
+	chmod 755 $PREFIX/bin/play
+	ln -s $PREFIX/bin/play $PREFIX/bin/queue
+	mkdir -m755 -p $PREFIX/share/play
+	cp -R local $PREFIX/share/play/local
+	chmod a+rX,u+rwX $PREFIX/share/play/local
+	cp -R yt $PREFIX/share/play/file
+	chmod a+rX,u+rwX $PREFIX/share/play/file
+	cp -R yt $PREFIX/share/play/yt
+	chmod a+rX,u+rwX $PREFIX/share/play/yt
+	cp -R yt $PREFIX/share/play/stream
+	chmod a+rX,u+rwX $PREFIX/share/play/stream
+
+uninstall:V:
+	rm $PREFIX/bin/music
+	rm $PREFIX/bin/play
+	rm $PREFIX/bin/queue
+	rm -r $PREFIX/share/play




diff --git a/music b/music
new file mode 100755
index 0000000000000000000000000000000000000000..5bf5d3924b6200a9102d9c7903decfc4202cb0b9
--- /dev/null
+++ b/music
@@ -0,0 +1,133 @@
+#!/bin/sh
+
+## usage: music [-a]
+#         music selector_name action [action_args...]
+
+abspath() {
+	echo "$(cd "$(dirname "$1")" >/dev/null||exit; pwd)/"
+}
+
+DATA_HOME=${XDG_DATA_HOME:-"$HOME/.local/share"}
+XDG_DATA_DIRS=${XDG_DATA_DIRS:-/usr/local/share/:/usr/share/}
+playlist="$DATA_HOME/music/playlist"
+
+SELECTOR_DIRS="$(abspath "$0")${SELECTOR_DIRS}"
+
+is_local() {
+	scheme="${1%%:*}"
+	[ "$scheme" = 'file' ]
+}
+
+exists() {
+	[ -f "${1#*://}" ]
+}
+
+print_usage() {
+	printf "
+Usage:
+\t%s [-a]
+\t%s <selector_name> <action> [action_args...]
+
+Control the music player
+
+Options:
+ -a\t\tappend to queue
+ -h\t\tshow this help and quit
+
+For more details see music(1) and music(8)\n" "$1" "$1"
+}
+
+emplace() {
+	pid=$(cat ~/.local/share/play/pid 2>/dev/null)
+
+	if [ "$pid" = '' ] || ! kill -0 "$pid" 2>/dev/null
+	then
+		mpv --input-ipc-server=/tmp/play-mpv-socket --idle --no-terminal --no-video 2>&1 >/dev/null &  # todo log
+		pid=$!
+		echo $pid > ~/.local/share/play/pid
+	fi
+
+	if [ "$1" = '' ]
+	then
+		mode="replace"
+		echo >"$playlist"
+	elif [ "$1" = '-a' ]
+	then
+		mode="append-play"
+	fi
+
+	# stdin entries must be URI; it is assumed, not checked
+	songs=$(cat /dev/stdin)
+
+	songs_head=$(echo "$songs" | head -n1)
+	songs_tail=$(echo "$songs" | tail -n+2)
+
+	is_idle=$(echo '{"command": ["get_property", "core-idle"]}' | socat - /tmp/play-mpv-socket | jq '.data' -r)
+	is_active_idle=$(echo '{"command": ["get_property", "idle-active"]}' | socat - /tmp/play-mpv-socket | jq '.data' -r)
+
+	uri=$(echo "$songs_head" | cut -d '' -f 2)
+	if is_local "$uri" && ! exists "$uri"
+	then
+		printf "No such file %s\n" "$uri" >&2
+	else
+		reply=$(echo '{"command": ["loadfile", "'"$uri"'", "'"$mode"'"]}' | socat - /tmp/play-mpv-socket)
+		echo "$songs_head" >>"$playlist"
+		# todo print error
+	fi
+
+	if [ "$is_idle" = "true" ] && [ "$is_active_idle" = 'false' ] && [ "$mode" = "replace" ]
+	then
+		reply=$(echo '{"command": ["keypress", "PAUSE"]}' | socat - /tmp/play-mpv-socket)
+		# todo print error
+	fi
+
+	echo "$songs_tail" | while read -r song
+	do
+		if [ "$song" ]
+		then
+			uri=$(echo "$song" | cut -d '' -f 2)
+			if is_local "$uri" && ! exists "$uri"
+			then
+				printf "No such file %s\n" "$uri" >&2
+			else
+				reply=$(echo '{"command": ["loadfile", "'"$uri"'", "append"]}' | socat - /tmp/play-mpv-socket)
+				echo "$song" >>"$playlist"
+				# todo print error
+			fi
+		fi
+	done
+}
+
+do_action() {
+	selector_name="$1"
+	action="$2"
+	shift
+	shift
+	
+	IFS=':'; for dir in $SELECTOR_DIRS
+	do
+		if [ -d "$dir/music/selectors" ] && ls "$dir/music/selectors" | grep "$selector_name" >/dev/null
+		then
+			selector="$dir/music/selectors/$selector_name"
+			break
+		fi
+	done
+
+	if [ "$selector" ]
+	then
+		"$selector/actions/$action" "$@"
+	else
+		echo "selector ‘$selector_name’ not found"
+	fi
+}
+
+
+if [ "$1" = '-h' ]
+then
+	print_usage "$0"
+elif [ "$1" = '-a' ] || [ "$1" = '' ]
+then
+	emplace "$1"
+else
+	do_action "$@"
+fi




diff --git a/play b/play
new file mode 100755
index 0000000000000000000000000000000000000000..27385a969259746b59c4aa4dada7aa4585fe4a72
--- /dev/null
+++ b/play
@@ -0,0 +1,81 @@
+#!/bin/sh
+
+## usage: play [-a] [selector_name [selector_args...]]
+# -a -> play -a; no -a -> play
+# selector == local must not take selector_args
+
+abspath() {
+	echo "$(cd "$(dirname "$1")" >/dev/null||exit; pwd)/"
+}
+
+DATA_HOME=${XDG_DATA_HOME:-"$HOME/.local/share"}
+XDG_DATA_DIRS=${XDG_DATA_DIRS:-/usr/local/share/:/usr/share/}
+
+XDG_DIRS="$DATA_HOME:$XDG_DATA_DIRS"
+SELECTOR_DIRS=''
+IFS=':'; for dir in $XDG_DIRS
+do
+	SELECTOR_DIRS="$SELECTOR_DIRS:$dir/music/selectors"
+done
+SELECTOR_DIRS="$(abspath "$0")${SELECTOR_DIRS}"
+
+mkdir -p "$DATA_HOME/music/selectors"
+
+name="$(basename "$0")"
+
+if [ "$1" = '-h' ]
+then
+	if [ "$name" = 'play' ]
+	then
+		append_arg='[-a] '
+		action="Play"
+		options="
+Options:
+ -a\t\tappend to queue\n"
+	else
+		action="Enqueue"
+	fi
+	printf "
+Usage:
+\t%s %s[selector_name [selector_args]]
+
+%s music
+%b
+For more details see %s(1)\n" "$0" "$append_arg" "$action" "$options" "$name"
+	exit
+fi
+
+if [ "$1" = '-a' ] || [ "$name" = 'queue' ]
+then
+	append="-a"
+	if [ "$1" = '-a' ]
+	then
+		shift
+	fi
+fi
+
+if [ "$1" = "" ]
+then
+	selector_name='local'
+else
+	selector_name="$1"
+	shift
+fi
+
+IFS=':'; for dir in $SELECTOR_DIRS
+do
+	if [ -d "$dir" ] && ls "$dir" | grep "$selector_name" >/dev/null
+	then
+		selector="$dir/$selector_name/select"
+		break
+	fi
+done
+
+if [ "$selector" ]
+then
+	PATH="$(abspath "$0"):$PATH"
+	$selector "$@" | music $append
+else
+	echo "selector ‘$selector_name’ not found"
+fi
+




diff --git a/queue b/queue
new file mode 120000
index 0000000000000000000000000000000000000000..4ade5429d5ee69a8b6037530a755e1025c9837c7
--- /dev/null
+++ b/queue
@@ -0,0 +1 @@
+play
\ No newline at end of file




diff --git a/stream/select b/stream/select
new file mode 100755
index 0000000000000000000000000000000000000000..f1c9cec71132a5f782fc883e16efae32ac0c7796
--- /dev/null
+++ b/stream/select
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+touch ~/.local/share/play/streams
+sed 's/\t//g' <~/.local/share/play/streams | fzf -q "$1" -m -d"" --with-nth 1




diff --git a/yt/select b/yt/select
new file mode 100755
index 0000000000000000000000000000000000000000..4f2fa48607caced988d4b574273bbea32401ee3f
--- /dev/null
+++ b/yt/select
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+if [ "$1" = '' ]
+then
+	echo "Search term not given" >&2
+else
+	youtube-dl -j "ytsearch25:$*" 2>/dev/null | jq '[.title, .webpage_url] | join("")' -r | fzf -m -d"" --with-nth 1
+fi