#!/bin/sh
#
# Purpose {{{
# This script will try to control MPV with IPC socket
#   1. Check for MPV proc with IPC socket option.
#   2. Verify if a process runs with one of the expected socket.
#      Unable to correctly extract 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.
# * Set a list of sockets path and use the first existing one.
# * Add new user command ?
# }}}
# Vars {{{
PROGNAME=$(basename "${0}"); readonly PROGNAME
PROGDIR=$(readlink -m $(dirname "${0}")); readonly PROGDIR
ARGS="${*}"; readonly ARGS
[ -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"
readonly MPV_POSSIBLE_SOCKET_PATH="${HOME}/.cache/qutebrowser/mpv.ipc.socket"

## 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}

OPTIONS :
    -c,--command
        Send a command to running MPV. Available commands :
          * toggle play, pause
          * play
          * pause

    -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 {{{
	## Can't extract a valid socket path from the command line !
	## So… no other choice than test a static list of possible socket
	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}")
			;;
		* )                                   ## 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