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