scripts/kodi.controller.sh

377 lines
11 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 Kodi with kodi-send command
# 1. Start Kodi if not already running.
# 2. Send user command to Kodi running instance.
#
# In Kodi, pause|play|toggle = TOGGLE ! 😑
# So for a real PAUSE, some extra tests are required :
# * Request the API (with curl) to check if a playlist is active.
# * Request the API to get the media speed.
# * Exit if the media is already paused (speed = 0).
#
# 2022-07-04
# }}}
# Vars {{{
PROGNAME=$(basename "${0}"); readonly PROGNAME
PROGDIR=$(readlink -m $(dirname "${0}")); readonly PROGDIR
ARGS="${*}"; readonly ARGS
readonly NBARGS="${#}"
[ -z "${DEBUG}" ] && DEBUG=1
## Export DEBUG for sub-script
export DEBUG
## Default values for some vars
readonly USER_MULTIMEDIA_COMMAND_DEFAULT="toggle"
readonly KODI_PROC_REGEXP="kodi.bin"
readonly KODI_HOST_DEFAULT="127.0.0.1"
readonly KODI_PORT_DEFAULT="8080"
## 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 Kodi player with some commands.
EXAMPLES:
- Starts playing current playlist
${PROGNAME} --command start
- Start Kodi if not already running
${PROGNAME}
- Stop current current media
${PROGNAME} --command stop
- Send default action (${USER_MULTIMEDIA_COMMAND_DEFAULT}) to default Kodi instance
${PROGNAME}
- Toggle current status on remote host (default : ${KODI_HOST_DEFAULT})
${PROGNAME} --host 192.168.1.33 --command toggle
OPTIONS:
-c,--command
Send a command to running Kodi. Available commands :
* toggle, play
* pause (real one thanks to the API and curl!)
* stop
* next
* previous
* random, party, partymode
-h,--host
Set the Kodi host to manage.
-p,--port
Set the Kodi API's port to use.
-d,--debug
Enable debug messages.
--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() { # {{{
## If KODI_HOST wasn't defined (argument) {{{
if [ -z "${KODI_HOST}" ]; then
## Use default value
readonly KODI_HOST="${KODI_HOST_DEFAULT}"
fi
## }}}
## If KODI_PORT wasn't defined (argument) {{{
if [ -z "${KODI_PORT}" ]; then
## Use default value
readonly KODI_PORT="${KODI_PORT_DEFAULT}"
fi
## }}}
## 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 Kodi action {{{
case "${USER_MULTIMEDIA_COMMAND}" in
toggle|play|pause ) ## Toggle current play
KODI_ACTION="PlayerControl(play)"
;;
stop ) ## Stop current play
KODI_ACTION="PlayerControl(stop)"
;;
next ) ## Next element in the playlist
KODI_ACTION="PlayerControl(next)"
;;
previous ) ## Next element in the playlist
KODI_ACTION="PlayerControl(previous)"
;;
random|party|partymode ) ## Start random music
KODI_ACTION="PlayerControl(partymode)"
;;
* ) ## unknow option
printf '%b\n' "${RED}Invalid Kodi 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}"
}
# }}}
get_current_media_type() { # {{{
debug_message "get_current_media_type \
Run a request to ${KODI_HOST}:${KODI_PORT} API."
KODI_CURRENT_MEDIA_TYPE=$(curl -s -X POST http://"${KODI_HOST}:${KODI_PORT}"/jsonrpc -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","method":"Player.GetActivePlayers","id":0}' | sed -n 's/.*"type":"\(.*\)".*/\1/p')
}
# }}}
is_audio_paused() { # {{{
## Media is playing by default
return_is_audio_paused="1"
debug_message "is_audio_paused \
Run a request to ${KODI_HOST}:${KODI_PORT} API to get status of audio media."
KODI_CURRENT_AUDIO_SPEED=$(curl -s -X POST http://"${KODI_HOST}:${KODI_PORT}"/jsonrpc -H 'Content-Type: application/json' --data '{"jsonrpc": "2.0", "method": "Player.GetProperties", "params": { "playerid": 0, "properties": [ "speed" ] }, "id": "AudioGetItem" }' | sed -n 's/.*"speed":\(.\).*/\1/p')
case "${KODI_CURRENT_AUDIO_SPEED}" in
0 ) ## Media is paused
debug_message "is_audio_paused \
The current media is paused (speed: ${RED}${KODI_CURRENT_MEDIA_TYPE}${COLOR_DEBUG})."
return_is_audio_paused="0"
;;
1 ) ## Media is playing
debug_message "is_audio_paused \
The current media is playing (speed: ${RED}${KODI_CURRENT_MEDIA_TYPE}${COLOR_DEBUG})."
return_is_audio_paused="1"
;;
* ) ## Error getting current media speed
error_message "Error with media speed (${KODI_CURRENT_AUDIO_SPEED})." 1
;;
esac
return "${return_is_audio_paused}"
}
# }}}
is_video_paused() { # {{{
## Media is playing by default
return_is_video_paused="1"
debug_message "is_video_paused \
Run a request to ${KODI_HOST}:${KODI_PORT} API to get status of video media."
KODI_CURRENT_VIDEO_SPEED=$(curl -s -X POST http://"${KODI_HOST}:${KODI_PORT}"/jsonrpc -H 'Content-Type: application/json' --data '{"jsonrpc": "2.0", "method": "Player.GetProperties", "params": { "playerid": 1, "properties": [ "speed" ] }, "id": "VideoGetItem" }' | sed -n 's/.*"speed":\(.\).*/\1/p')
case "${KODI_CURRENT_VIDEO_SPEED}" in
0 ) ## Media is paused
debug_message "is_video_paused \
The current video is paused (speed: ${RED}${KODI_CURRENT_MEDIA_TYPE}${COLOR_DEBUG})."
return_is_video_paused="0"
;;
1 ) ## Media is playing
debug_message "is_video_paused \
The current video is playing (speed: ${RED}${KODI_CURRENT_MEDIA_TYPE}${COLOR_DEBUG})."
return_is_video_paused="1"
;;
* ) ## Error getting current media speed
error_message "Error with media speed (${KODI_CURRENT_VIDEO_SPEED})." 1
;;
esac
return "${return_is_video_paused}"
}
# }}}
main() { # {{{
## Define all vars
define_vars
## For localhost
if [ "${KODI_HOST}" = "${KODI_HOST_DEFAULT}" ]; then
## If kodi is not running {{{
### AND Start it
### AND exit 0
is_proc_absent "${KODI_PROC_REGEXP}" \
&& debug_message "Start a new Kodi instance." \
&& kodi \
&& exit 0
## }}}
fi
## If the media should be paused {{{
if [ "${USER_MULTIMEDIA_COMMAND}" = "pause" ]; then
## Get current playlist type
get_current_media_type
case "${KODI_CURRENT_MEDIA_TYPE}" in
audio ) ## Manage audio media
is_audio_paused \
&& debug_message "${RED}audio${COLOR_DEBUG} media is already paused, no more action is required." \
&& exit 0
;;
video ) ## Manage video media
is_video_paused \
&& debug_message "${RED}video${COLOR_DEBUG} media is already paused, no more action is required." \
&& exit 0
;;
* ) ## Unknown media type or no media at all
debug_message "Unknown media type ->${RED}${KODI_CURRENT_MEDIA_TYPE}${COLOR_DEBUG}<- or no media is playing (if empty), exit."
exit 0
;;
esac
fi
## }}}
## Send Kodi action to running instance {{{
### And exit
debug_message "Send ${RED}${USER_MULTIMEDIA_COMMAND}${COLOR_DEBUG} (${RED}${KODI_ACTION}${COLOR_DEBUG}) action to running Kodi instance (on ${RED}${KODI_HOST}${COLOR_DEBUG} host)." \
&& kodi-send --host="${KODI_HOST}" --action="${KODI_ACTION}" > /dev/null \
&& 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|--host ) ## Kodi host to manage
### Move to the next argument
shift
### Define var
KODI_HOST="${1}"
;;
-p|--port ) ## Kodi API port
### Move to the next argument
shift
### Define var
KODI_PORT="${1}"
;;
--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