scripts/mpv.controller.sh

289 lines
7.9 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
#
# Purpose {{{
# This script will try to control MPV with IPC socket
# 1. Check for MPV proc with IPC socket option.
# 2. Extract the newest socket path from command line.
# 3. Send user command to the last MPV process with a existing socket.
#
# 2022-05-22
# }}}
# TODO {{{
# * Add an option to set the socket path.
# * Add new user command ?
# }}}
# Vars {{{
PROGNAME=$(basename "${0}"); readonly PROGNAME
PROGDIR=$(readlink -m $(dirname "${0}")); readonly PROGDIR
readonly ARGS="${*}"
readonly NBARGS="${#}"
[ -z "${DEBUG}" ] && DEBUG=1
## Export DEBUG for sub-script
export DEBUG
## Default values for some vars
readonly MPV_PROC_REGEXP="mpv.*--input-ipc-server="
readonly USER_MULTIMEDIA_COMMAND_DEFAULT="toggle"
MPV_POSSIBLE_SOCKET_PATH=$(pgrep --newest --full --list-full -- "^${MPV_PROC_REGEXP}" | sed -n -e "s/.*${MPV_PROC_REGEXP}\(.*\) .*/\1/p;q")
readonly MPV_POSSIBLE_SOCKET_PATH
## Colors
readonly PURPLE='\033[1;35m'
readonly RED='\033[0;31m'
readonly RESET='\033[0m'
readonly COLOR_DEBUG="${PURPLE}"
# }}}
usage() { # {{{
cat <<- HELP
usage: $PROGNAME [-c|-d|-h]
Manage MPV with IPC socket.
Can only manage the last mpv process started with --input-ipc-server option.
EXAMPLES:
- Pauses playing
${PROGNAME} --command pause
- Send default command (${USER_MULTIMEDIA_COMMAND_DEFAULT}) to MPV
${PROGNAME}
- Try to play next track (if playing a playlist)
${PROGNAME} --command next
OPTIONS:
-c,--command
Send a command to running MPV. Available commands :
* toggle play, pause
* play
* pause
* next
* prev, previous
-d,--debug
Enable debug messages.
-h,--help
Print this help message.
HELP
}
# }}}
debug_message() { # {{{
local_debug_message="${1}"
## Print message if DEBUG is enable (=0)
[ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6b\e[m\n' "DEBUG ${PROGNAME}: ${local_debug_message}"
unset local_debug_message
return 0
}
# }}}
error_message() { # {{{
local_error_message="${1}"
local_error_code="${2}"
## Print message
printf '%b\n' "ERROR ${PROGNAME}: ${RED}${local_error_message}${RESET}"
exit "${local_error_code:=66}"
}
# }}}
define_vars() { # {{{
## Get the socket path of the last MPV process {{{
MPV_SOCKET_PATH="${MPV_POSSIBLE_SOCKET_PATH}"
debug_message "define_vars \
IPC socket path for the last MPV process : ${RED}${MPV_SOCKET_PATH}${COLOR_DEBUG} ."
## }}}
## If USER_MULTIMEDIA_COMMAND wasn't defined (argument) {{{
if [ -z "${USER_MULTIMEDIA_COMMAND}" ]; then
## Use default value
readonly USER_MULTIMEDIA_COMMAND="${USER_MULTIMEDIA_COMMAND_DEFAULT}"
fi
## }}}
## Translate user command to MPV command {{{
case "${USER_MULTIMEDIA_COMMAND}" in
toggle ) ## Toggle current play
debug_message "define_vars \
Use ${RED}MPV socket${COLOR_DEBUG} to send ${USER_MULTIMEDIA_COMMAND} command."
MPV_COMMAND=$(echo '{ "command": ["cycle", "pause"] }' | socat - "${MPV_SOCKET_PATH}")
;;
play ) ## Starts playing song (default number 1)
debug_message "define_vars \
Use ${RED}MPV socket${COLOR_DEBUG} to send ${USER_MULTIMEDIA_COMMAND} command."
MPV_COMMAND=$(echo '{ "command": ["set_property", "pause", false] }' | socat - "${MPV_SOCKET_PATH}")
;;
pause ) ## Pauses playing
debug_message "define_vars \
Use ${RED}MPV socket${COLOR_DEBUG} to send ${USER_MULTIMEDIA_COMMAND} command."
MPV_COMMAND=$(echo '{ "command": ["set_property", "pause", true] }' | socat - "${MPV_SOCKET_PATH}")
;;
next ) ## Try to play next track (if available)
debug_message "define_vars \
Use ${RED}MPV socket${COLOR_DEBUG} to send ${USER_MULTIMEDIA_COMMAND} command."
MPV_COMMAND=$(echo 'playlist-next' | socat - "${MPV_SOCKET_PATH}")
;;
prev|previous ) ## Try to play previous track (if available)
debug_message "define_vars \
Use ${RED}MPV socket${COLOR_DEBUG} to send ${USER_MULTIMEDIA_COMMAND} command."
MPV_COMMAND=$(echo 'playlist-prev' | socat - "${MPV_SOCKET_PATH}")
;;
* ) ## unknow option
printf '%b\n' "${RED}Invalid MPV command: ${USER_MULTIMEDIA_COMMAND}${RESET}"
printf '%b\n' "---"
usage
exit 1
;;
esac
## }}}
}
# }}}
is_proc_absent() { # {{{
local_proc_pattern="${1}"
## Proc is absent by default
return_proc_absent="0"
local_count_proc_pattern="$(pgrep -f -- "${local_proc_pattern}" | wc -l)"
case "${local_count_proc_pattern}" in
0 ) ## No procs related to this pattern are running
return_proc_absent="0"
;;
* ) ## At least one proc seems running
return_proc_absent="1"
;;
esac
## Simple debug message to valid current variables
debug_message "is_proc_absent \
procs running (with the pattern: ${RED}${local_proc_pattern}${COLOR_DEBUG}) on the current host: ${RED}${local_count_proc_pattern}${COLOR_DEBUG}."
return "${return_proc_absent}"
}
# }}}
is_socket_absent() { # {{{
local_socket_absent="${1}"
## Socket exists by default
return_is_socket_absent="1"
### Check if the socket exists
# shellcheck disable=SC2086
if find ${local_socket_absent} -type s > /dev/null 2>&1; then
return_is_socket_absent="1"
debug_message "is_socket_absent \
The socket ${RED}${local_socket_absent}${COLOR_DEBUG} exists."
else
return_is_socket_absent="0"
debug_message "is_socket_absent \
The socket ${RED}${local_socket_absent}${COLOR_DEBUG} doesn't exist."
fi
return "${return_is_socket_absent}"
}
# }}}
main() { # {{{
## If MPV is not running {{{
### AND exit 1
is_proc_absent "${MPV_PROC_REGEXP}" \
&& debug_message "No MPV running process with IPS socket." \
&& exit 1
## }}}
## Define all vars
define_vars
## If MPV's IPC socket is not present {{{
### AND exit 1
is_socket_absent "${MPV_SOCKET_PATH}" \
&& debug_message "Can't access to MPV IPC socket : ${RED}${MPV_SOCKET_PATH}${COLOR_DEBUG}." \
&& exit 1
## }}}
## Send MPV action to running instance {{{
### And exit
debug_message "Send ${RED}${USER_MULTIMEDIA_COMMAND}${COLOR_DEBUG} action to last MPV running instance with an IPC socket." \
"${MPV_COMMAND}" \
&& exit 0
## }}}
}
# }}}
# Manage arguments # {{{
# This code can't be in a function due to argument management
if [ ! "${NBARGS}" -eq "0" ]; then
manage_arg="0"
## If the first argument is not an option
if ! printf -- '%s' "${1}" | grep -q -E -- "^-+";
then
## Print help message and exit
printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
printf '%b\n' "---"
usage
exit 1
fi
# Parse all options (start with a "-") one by one
while printf -- '%s' "${1}" | grep -q -E -- "^-+"; do
case "${1}" in
-c|--command ) ## User command
### Move to the next argument
shift
### Define var
USER_MULTIMEDIA_COMMAND="${1}"
;;
-d|--debug ) ## debug
DEBUG=0
;;
-h|--help ) ## help
usage
## Exit after help informations
exit 0
;;
* ) ## unknow option
printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
printf '%b\n' "---"
usage
exit 1
;;
esac
debug_message "Arguments management \
${RED}${1}${COLOR_DEBUG} option|command managed."
## Move to the next argument
shift
manage_arg=$((manage_arg+1))
done
debug_message "Arguments management \
${RED}${manage_arg}${COLOR_DEBUG} argument(s) successfully managed."
else
debug_message "Arguments management \
No arguments/options to manage."
fi
# }}}
main
exit 255