mirror of
https://github.com/thorsten-gehrig/alexa-remote-control.git
synced 2024-11-14 12:59:02 +01:00
f05854f123
CustomerId is now retrieved from the logged in user. The customerId in the device list is always from the user registering the device initially
922 lines
33 KiB
Bash
922 lines
33 KiB
Bash
#!/bin/sh
|
|
#
|
|
# Amazon Alexa Remote Control
|
|
# alex(at)loetzimmer.de
|
|
#
|
|
# 2017-10-10: v0.1 initial release
|
|
# 2017-10-11: v0.2 TuneIn Station Search
|
|
# 2017-10-11: v0.2a commands on special device "ALL" are executed on all ECHO+WHA
|
|
# 2017-10-16: v0.3 added playback of library tracks
|
|
# 2017-10-24: v0.4 added playback information
|
|
# 2017-11-21: v0.5 added Prime station and playlist
|
|
# 2017-11-22: v0.6 added Prime historical queue and replaced getopts
|
|
# 2017-11-25: v0.6a cURL is now configurable
|
|
# 2017-11-25: v0.7 added multiroom create/delete, playback of library playlist
|
|
# 2017-11-30: v0.7a added US config, fixed device names containing spaces
|
|
# 2017-12-07: v0.7b added Bluetooth connect/disconnect
|
|
# 2017-12-18: v0.7c fixed US version
|
|
# 2017-12-19: v0.7d fixed AWK csrf extraction on some systems
|
|
# 2017-12-20: v0.7e moved get_devlist after check_status
|
|
# 2018-01-08: v0.7f added echo-show to ALL group, TuneIn station can now be up to 6 digits
|
|
# 2018-01-08: v0.8 added bluetooth list function
|
|
# 2018-01-10: v0.8a abort when login was unsuccessful
|
|
# 2018-01-25: v0.8b added echo-spot to ALL group
|
|
# 2018-01-28: v0.8c added configurable browser string
|
|
# 2018-02-17: v0.8d no need to write the cookie file on every "check_status"
|
|
# 2018-02-27: v0.8e added "lastalexa" option for HA-Bridge to send its command to a specific device
|
|
# (Markus Wennesheimer: https://wennez.wordpress.com/light-on-with-alexa-for-each-room/)
|
|
# 2018-02-27: v0.9 unsuccessful logins will now give a short info how to debug the login
|
|
# 2018-03-09: v0.9a workaround for login problem, force curl to use http1.1
|
|
# 2018-05-17: v0.9b update browser string and accept language
|
|
# 2018-05-23: v0.9c update accept language (again)
|
|
# 2018-06-12: v0.10 introducing TTS and more
|
|
# (thanks to Michael Geramb and his openHAB2 Amazon Echo Control binding)
|
|
# https://github.com/openhab/openhab2-addons/tree/master/addons/binding/org.openhab.binding.amazonechocontrol
|
|
# (thanks to Ralf Otto for implementing this feature in this script)
|
|
# 2018-06-13: v0.10a added album play of imported library
|
|
# 2018-06-18: v0.10b added Alexa routine execution
|
|
# 2019-01-22: v0.11 added repeat command, added environment variable parsing
|
|
#
|
|
###
|
|
#
|
|
# (no BASHisms were used, should run with any shell)
|
|
# - requires cURL for web communication
|
|
# - (GNU) sed and awk for extraction
|
|
# - jq as command line JSON parser (optional for the fancy bits)
|
|
#
|
|
##########################################
|
|
|
|
SET_EMAIL='amazon_account@email.address'
|
|
SET_PASSWORD='Very_Secret_Amazon_Account_Password'
|
|
|
|
SET_LANGUAGE="de-DE"
|
|
#SET_LANGUAGE="en-US"
|
|
|
|
SET_AMAZON='amazon.de'
|
|
#SET_AMAZON='amazon.com'
|
|
|
|
SET_ALEXA='alexa.amazon.de'
|
|
#SET_ALEXA='pitangui.amazon.com'
|
|
|
|
# cURL binary
|
|
SET_CURL='/usr/bin/curl'
|
|
|
|
# cURL options
|
|
# -k : if your cURL cannot verify CA certificates, you'll have to trust any
|
|
# --compressed : if your cURL was compiled with libz you may use compression
|
|
# --http1.1 : cURL defaults to HTTP/2 on HTTPS connections if available
|
|
SET_OPTS='--compressed --http1.1'
|
|
#SET_OPTS='-k --compressed --http1.1'
|
|
|
|
# browser identity
|
|
SET_BROWSER='Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:1.0) bash-script/1.0'
|
|
#SET_BROWSER='Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0'
|
|
|
|
# tmp path
|
|
SET_TMP="/tmp"
|
|
|
|
###########################################
|
|
# nothing to configure below here
|
|
#
|
|
|
|
# retrieving environment variables if any are set
|
|
EMAIL=${EMAIL:-$SET_EMAIL}
|
|
PASSWORD=${PASSWORD:-$SET_PASSWORD}
|
|
AMAZON=${AMAZON:-$SET_AMAZON}
|
|
ALEXA=${ALEXA:-$SET_ALEXA}
|
|
LANGUAGE=${LANGUAGE:-$SET_LANGUAGE}
|
|
BROWSER=${BROWSER:-$SET_BROWSER}
|
|
CURL=${CURL:-$SET_CURL}
|
|
OPTS=${OPTS:-$SET_OPTS}
|
|
TMP=${TMP:-$SET_TMP}
|
|
|
|
COOKIE="${TMP}/.alexa.cookie"
|
|
DEVLIST="${TMP}/.alexa.devicelist.json"
|
|
|
|
GUIVERSION=0
|
|
|
|
LIST=""
|
|
LOGOFF=""
|
|
COMMAND=""
|
|
TTS=""
|
|
UTTERANCE=""
|
|
SEQUENCECMD=""
|
|
STATIONID=""
|
|
QUEUE=""
|
|
SONG=""
|
|
ALBUM=""
|
|
ARTIST=""
|
|
TYPE=""
|
|
ASIN=""
|
|
SEEDID=""
|
|
HIST=""
|
|
LEMUR=""
|
|
CHILD=""
|
|
PLIST=""
|
|
BLUETOOTH=""
|
|
LASTALEXA=""
|
|
|
|
usage()
|
|
{
|
|
echo "$0 [-d <device>|ALL] -e <pause|play|next|prev|fwd|rwd|shuffle|repeat|vol:<0-100>> |"
|
|
echo " -b [list|<\"AA:BB:CC:DD:EE:FF\">] | -q | -r <\"station name\"|stationid> |"
|
|
echo " -s <trackID|'Artist' 'Album'> | -t <ASIN> | -u <seedID> | -v <queueID> | -w <playlistId> |"
|
|
echo " -i | -p | -P | -S | -a | -m <multiroom_device> [device_1 .. device_X] | -lastalexa | -l | -h"
|
|
echo
|
|
echo " -e : run command, additional SEQUENCECMDs:"
|
|
echo " weather,traffic,flashbriefing,goodmorning,singasong,tellstory,speak:'<text>',automation:'<routine name>'"
|
|
echo " -b : connect/disconnect/list bluetooth device"
|
|
echo " -q : query queue"
|
|
echo " -r : play tunein radio"
|
|
echo " -s : play library track/library album"
|
|
echo " -t : play Prime playlist"
|
|
echo " -u : play Prime station"
|
|
echo " -v : play Prime historical queue"
|
|
echo " -w : play library playlist"
|
|
echo " -i : list imported library tracks"
|
|
echo " -p : list purchased library tracks"
|
|
echo " -P : list Prime playlists"
|
|
echo " -S : list Prime stations"
|
|
echo " -a : list available devices"
|
|
echo " -m : delete multiroom and/or create new multiroom containing devices"
|
|
echo " -lastalexa : print device that received the last voice command"
|
|
echo " -l : logoff"
|
|
echo " -h : help"
|
|
}
|
|
|
|
while [ "$#" -gt 0 ] ; do
|
|
case "$1" in
|
|
-d)
|
|
if [ "${2#-}" != "${2}" -o -z "$2" ] ; then
|
|
echo "ERROR: missing argument for ${1}"
|
|
usage
|
|
exit 1
|
|
fi
|
|
DEVICE=$2
|
|
shift
|
|
;;
|
|
-e)
|
|
if [ "${2#-}" != "${2}" -o -z "$2" ] ; then
|
|
echo "ERROR: missing argument for ${1}"
|
|
usage
|
|
exit 1
|
|
fi
|
|
COMMAND=$2
|
|
shift
|
|
;;
|
|
-b)
|
|
if [ "${2#-}" = "${2}" -a -n "$2" ] ; then
|
|
BLUETOOTH=$2
|
|
shift
|
|
else
|
|
BLUETOOTH="null"
|
|
fi
|
|
;;
|
|
-m)
|
|
if [ "${2#-}" != "${2}" -o -z "$2" ] ; then
|
|
echo "ERROR: missing argument for ${1}"
|
|
usage
|
|
exit 1
|
|
fi
|
|
LEMUR=$2
|
|
shift
|
|
while [ "${2#-}" = "${2}" -a -n "$2" ] ; do
|
|
CHILD="${CHILD} ${2}"
|
|
shift
|
|
done
|
|
;;
|
|
-r)
|
|
if [ "${2#-}" != "${2}" -o -z "$2" ] ; then
|
|
echo "ERROR: missing argument for ${1}"
|
|
usage
|
|
exit 1
|
|
fi
|
|
STATIONID=$2
|
|
shift
|
|
# stationIDs are "s1234" or "s12345"
|
|
if [ -n "${STATIONID##s[0-9][0-9][0-9][0-9]}" -a -n "${STATIONID##s[0-9][0-9][0-9][0-9][0-9]}" -a -n "${STATIONID##s[0-9][0-9][0-9][0-9][0-9][0-9]}" ] ; then
|
|
# search for station name
|
|
STATIONID=$(${CURL} ${OPTS} -s --data-urlencode "query=${STATIONID}" -G "https://api.tunein.com/profiles?fullTextSearch=true" | jq -r '.Items[] | select(.ContainerType == "Stations") | .Children[] | select( .Index==1 ) | .GuideId')
|
|
if [ -z "$STATIONID" ] ; then
|
|
echo "ERROR: no Station \"$2\" found on TuneIn"
|
|
exit 1
|
|
fi
|
|
fi
|
|
;;
|
|
-s)
|
|
if [ "${2#-}" != "${2}" -o -z "$2" ] ; then
|
|
echo "ERROR: missing argument for ${1}"
|
|
usage
|
|
exit 1
|
|
fi
|
|
SONG=$2
|
|
shift
|
|
if [ "${2#-}" = "${2}" -a -n "$2" ] ; then
|
|
ALBUM=$2
|
|
ARTIST=$SONG
|
|
shift
|
|
fi
|
|
;;
|
|
-t)
|
|
if [ "${2#-}" != "${2}" -o -z "$2" ] ; then
|
|
echo "ERROR: missing argument for ${1}"
|
|
usage
|
|
exit 1
|
|
fi
|
|
ASIN=$2
|
|
shift
|
|
;;
|
|
-u)
|
|
if [ "${2#-}" != "${2}" -o -z "$2" ] ; then
|
|
echo "ERROR: missing argument for ${1}"
|
|
usage
|
|
exit 1
|
|
fi
|
|
SEEDID=$2
|
|
shift
|
|
;;
|
|
-v)
|
|
if [ "${2#-}" != "${2}" -o -z "$2" ] ; then
|
|
echo "ERROR: missing argument for ${1}"
|
|
usage
|
|
exit 1
|
|
fi
|
|
HIST=$2
|
|
shift
|
|
;;
|
|
-w)
|
|
if [ "${2#-}" != "${2}" -o -z "$2" ] ; then
|
|
echo "ERROR: missing argument for ${1}"
|
|
usage
|
|
exit 1
|
|
fi
|
|
PLIST=$2
|
|
shift
|
|
;;
|
|
-l)
|
|
LOGOFF="true"
|
|
;;
|
|
-a)
|
|
LIST="true"
|
|
;;
|
|
-i)
|
|
TYPE="IMPORTED"
|
|
;;
|
|
-p)
|
|
TYPE="PURCHASES"
|
|
;;
|
|
-P)
|
|
PRIME="prime-playlist-browse-nodes"
|
|
;;
|
|
-S)
|
|
PRIME="prime-sections"
|
|
;;
|
|
-q)
|
|
QUEUE="true"
|
|
;;
|
|
-lastalexa)
|
|
LASTALEXA="true"
|
|
;;
|
|
-h|-\?|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "ERROR: unknown option ${1}"
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
case "$COMMAND" in
|
|
pause)
|
|
COMMAND='{"type":"PauseCommand"}'
|
|
;;
|
|
play)
|
|
COMMAND='{"type":"PlayCommand"}'
|
|
;;
|
|
next)
|
|
COMMAND='{"type":"NextCommand"}'
|
|
;;
|
|
prev)
|
|
COMMAND='{"type":"PreviousCommand"}'
|
|
;;
|
|
fwd)
|
|
COMMAND='{"type":"ForwardCommand"}'
|
|
;;
|
|
rwd)
|
|
COMMAND='{"type":"RewindCommand"}'
|
|
;;
|
|
shuffle)
|
|
COMMAND='{"type":"ShuffleCommand","shuffle":"true"}'
|
|
;;
|
|
repeat)
|
|
COMMAND='{"type":"RepeatCommand","repeat":true}'
|
|
;;
|
|
vol:*)
|
|
VOL=${COMMAND##*:}
|
|
# volume as integer!
|
|
if [ $VOL -le 100 -a $VOL -ge 0 ] ; then
|
|
COMMAND='{"type":"VolumeLevelCommand","volumeLevel":'${VOL}'}'
|
|
else
|
|
echo "ERROR: volume should be an integer between 0 and 100"
|
|
usage
|
|
exit 1
|
|
fi
|
|
;;
|
|
speak:*)
|
|
SEQUENCECMD='Alexa.Speak'
|
|
TTS=$(echo ${COMMAND##*:} | sed -r 's/[^-a-zA-Z0-9_,?! ]//g' | sed 's/ /_/g')
|
|
TTS=",\\\"textToSpeak\\\":\\\"${TTS}\\\""
|
|
;;
|
|
automation:*)
|
|
SEQUENCECMD='automation'
|
|
UTTERANCE=$(echo ${COMMAND##*:} | sed -r 's/[^-a-zA-Z0-9_,?! ]//g')
|
|
;;
|
|
weather)
|
|
SEQUENCECMD='Alexa.Weather.Play'
|
|
;;
|
|
traffic)
|
|
SEQUENCECMD='Alexa.Traffic.Play'
|
|
;;
|
|
flashbriefing)
|
|
SEQUENCECMD='Alexa.FlashBriefing.Play'
|
|
;;
|
|
goodmorning)
|
|
SEQUENCECMD='Alexa.GoodMorning.Play'
|
|
;;
|
|
singasong)
|
|
SEQUENCECMD='Alexa.SingASong.Play'
|
|
;;
|
|
tellstory)
|
|
SEQUENCECMD='Alexa.TellStory.Play'
|
|
;;
|
|
"")
|
|
;;
|
|
*)
|
|
echo "ERROR: unknown command \"${COMMAND}\"!"
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
#
|
|
# Amazon Login
|
|
#
|
|
log_in()
|
|
{
|
|
################################################################
|
|
#
|
|
# following headers are required:
|
|
# Accept-Language (possibly for determining login region)
|
|
# User-Agent (cURL wouldn't store cookies without)
|
|
#
|
|
################################################################
|
|
|
|
rm -f ${DEVLIST}
|
|
rm -f ${COOKIE}
|
|
rm -f ${TMP}/.alexa.*.list
|
|
|
|
#
|
|
# get first cookie and write redirection target into referer
|
|
#
|
|
${CURL} ${OPTS} -s -D "${TMP}/.alexa.header" -c ${COOKIE} -b ${COOKIE} -A "${BROWSER}" -H "Accept-Language: ${LANGUAGE}" -H "DNT: 1" -H "Connection: keep-alive" -H "Upgrade-Insecure-Requests: 1" -L\
|
|
https://alexa.${AMAZON} | grep "hidden" | sed 's/hidden/\n/g' | grep "value=\"" | sed -r 's/^.*name="([^"]+)".*value="([^"]+)".*/\1=\2\&/g' > "${TMP}/.alexa.postdata"
|
|
|
|
#
|
|
# login empty to generate session
|
|
#
|
|
${CURL} ${OPTS} -s -c ${COOKIE} -b ${COOKIE} -A "${BROWSER}" -H "Accept-Language: ${LANGUAGE}" -H "DNT: 1" -H "Connection: keep-alive" -H "Upgrade-Insecure-Requests: 1" -L\
|
|
-H "$(grep 'Location: ' ${TMP}/.alexa.header | sed 's/Location: /Referer: /')" -d "@${TMP}/.alexa.postdata" https://www.${AMAZON}/ap/signin | grep "hidden" | sed 's/hidden/\n/g' | grep "value=\"" | sed -r 's/^.*name="([^"]+)".*value="([^"]+)".*/\1=\2\&/g' > "${TMP}/.alexa.postdata2"
|
|
|
|
#
|
|
# login with filled out form
|
|
# !!! referer now contains session in URL
|
|
#
|
|
${CURL} ${OPTS} -s -D "${TMP}/.alexa.header2" -c ${COOKIE} -b ${COOKIE} -A "${BROWSER}" -H "Accept-Language: ${LANGUAGE}" -H "DNT: 1" -H "Connection: keep-alive" -H "Upgrade-Insecure-Requests: 1" -L\
|
|
-H "Referer: https://www.${AMAZON}/ap/signin/$(awk "\$0 ~/.${AMAZON}.*session-id[ \\s\\t]+/ {print \$7}" ${COOKIE})" --data-urlencode "email=${EMAIL}" --data-urlencode "password=${PASSWORD}" -d "@${TMP}/.alexa.postdata2" https://www.${AMAZON}/ap/signin > "${TMP}/.alexa.login"
|
|
|
|
# check whether the login has been successful or exit otherwise
|
|
if [ -z "$(grep 'Location: https://alexa.*html' ${TMP}/.alexa.header2)" ] ; then
|
|
echo "ERROR: Amazon Login was unsuccessful. Possibly you get a captcha login screen."
|
|
echo " Try logging in to https://alexa.${AMAZON} with your browser. In your browser"
|
|
echo " make sure to have all Amazon related cookies deleted and Javascript disabled!"
|
|
echo
|
|
echo " (For more information have a look at ${TMP}/.alexa.login)"
|
|
|
|
rm -f ${COOKIE}
|
|
rm -f "${TMP}/.alexa.header"
|
|
rm -f "${TMP}/.alexa.header2"
|
|
rm -f "${TMP}/.alexa.postdata"
|
|
rm -f "${TMP}/.alexa.postdata2"
|
|
exit 1
|
|
fi
|
|
|
|
#
|
|
# get CSRF
|
|
#
|
|
${CURL} ${OPTS} -s -c ${COOKIE} -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
https://${ALEXA}/api/language > /dev/null
|
|
|
|
rm -f "${TMP}/.alexa.login"
|
|
rm -f "${TMP}/.alexa.header"
|
|
rm -f "${TMP}/.alexa.header2"
|
|
rm -f "${TMP}/.alexa.postdata"
|
|
rm -f "${TMP}/.alexa.postdata2"
|
|
}
|
|
|
|
#
|
|
# get JSON device list
|
|
#
|
|
get_devlist()
|
|
{
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})"\
|
|
"https://${ALEXA}/api/devices-v2/device?cached=false" > ${DEVLIST}
|
|
}
|
|
|
|
check_status()
|
|
{
|
|
#
|
|
# bootstrap with GUI-Version writes GUI version to cookie
|
|
# returns among other the current authentication state
|
|
#
|
|
AUTHSTATUS=$(${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L https://${ALEXA}/api/bootstrap?version=${GUIVERSION})
|
|
MEDIAOWNERCUSTOMERID=$(echo $AUTHSTATUS | sed -r 's/^.*"customerId":"([^,]+)",.*$/\1/g')
|
|
AUTHSTATUS=$(echo $AUTHSTATUS | sed -r 's/^.*"authenticated":([^,]+),.*$/\1/g')
|
|
|
|
if [ "$AUTHSTATUS" = "true" ] ; then
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
#
|
|
# set device specific variables from JSON device list
|
|
#
|
|
set_var()
|
|
{
|
|
DEVICE=$(echo ${DEVICE} | sed -r 's/%20/ /g')
|
|
|
|
if [ -z "${DEVICE}" ] ; then
|
|
# if no device was supplied, use the first Echo(dot) in device list
|
|
echo "setting default device to:"
|
|
DEVICE=$(jq -r '[ .devices[] | select(.deviceFamily == "ECHO" or .deviceFamily == "KNIGHT" or .deviceFamily == "ROOK" ) | .accountName] | .[0]' ${DEVLIST})
|
|
echo ${DEVICE}
|
|
fi
|
|
|
|
DEVICETYPE=$(jq --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .deviceType' ${DEVLIST})
|
|
DEVICESERIALNUMBER=$(jq --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .serialNumber' ${DEVLIST})
|
|
|
|
# customerId is now retrieved from the logged in user
|
|
# the customerId in the device list is always from the user registering the device initially
|
|
# MEDIAOWNERCUSTOMERID=$(jq --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .deviceOwnerCustomerId' ${DEVLIST})
|
|
|
|
if [ -z "${DEVICESERIALNUMBER}" ] ; then
|
|
echo "ERROR: unkown device dev:${DEVICE}"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
#
|
|
# list available devices from JSON device list
|
|
#
|
|
list_devices()
|
|
{
|
|
jq -r '.devices[].accountName' ${DEVLIST}
|
|
}
|
|
|
|
#
|
|
# execute command
|
|
# (SequenceCommands by Michael Geramb and Ralf Otto)
|
|
#
|
|
run_cmd()
|
|
{
|
|
if [ -n "${SEQUENCECMD}" ]
|
|
then
|
|
if [ "${SEQUENCECMD}" = 'automation' ] ; then
|
|
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
|
|
"https://${ALEXA}/api/behaviors/automations" > "${TMP}/.alexa.automation"
|
|
|
|
AUTOMATION=$(jq --arg utterance "${UTTERANCE}" -r '.[] | select( .triggers[].payload.utterance == $utterance) | .automationId' "${TMP}/.alexa.automation")
|
|
if [ -z "${AUTOMATION}" ] ; then
|
|
echo "ERROR: no such utterance '${UTTERANCE}' in Alexa routines"
|
|
rm -f "${TMP}/.alexa.automation"
|
|
exit 1
|
|
fi
|
|
SEQUENCE=$(jq --arg utterance "${UTTERANCE}" -rc '.[] | select( .triggers[].payload.utterance == $utterance) | .sequence' "${TMP}/.alexa.automation" | sed 's/"/\\"/g' | sed "s/ALEXA_CURRENT_DEVICE_TYPE/${DEVICETYPE}/g" | sed "s/ALEXA_CURRENT_DSN/${DEVICESERIALNUMBER}/g" | sed "s/ALEXA_CUSTOMER_ID/${MEDIAOWNERCUSTOMERID}/g" | sed 's/ /_/g')
|
|
rm -f "${TMP}/.alexa.automation"
|
|
|
|
echo "Running routine: ${UTTERANCE}"
|
|
COMMAND="{\"behaviorId\":\"${AUTOMATION}\",\"sequenceJson\":\"${SEQUENCE}\",\"status\":\"ENABLED\"}"
|
|
else
|
|
echo "Sequence command: ${SEQUENCECMD}"
|
|
COMMAND="{\"behaviorId\":\"PREVIEW\",\"sequenceJson\":\"{\\\"@type\\\":\\\"com.amazon.alexa.behaviors.model.Sequence\\\",\\\"startNode\\\":{\\\"@type\\\":\\\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\\\",\\\"type\\\":\\\"${SEQUENCECMD}\\\",\\\"operationPayload\\\":{\\\"deviceType\\\":\\\"${DEVICETYPE}\\\",\\\"deviceSerialNumber\\\":\\\"${DEVICESERIALNUMBER}\\\",\\\"locale\\\":\\\"${LANGUAGE}\\\",\\\"customerId\\\":\\\"${MEDIAOWNERCUSTOMERID}\\\"${TTS}}}}\",\"status\":\"ENABLED\"}"
|
|
fi
|
|
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X POST -d ${COMMAND}\
|
|
"https://${ALEXA}/api/behaviors/preview"
|
|
else
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X POST -d ${COMMAND}\
|
|
"https://${ALEXA}/api/np/command?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}"
|
|
fi
|
|
}
|
|
|
|
#
|
|
# play TuneIn radio station
|
|
#
|
|
play_radio()
|
|
{
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X POST\
|
|
"https://${ALEXA}/api/tunein/queue-and-play?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}&guideId=${STATIONID}&contentType=station&callSign=&mediaOwnerCustomerId=${MEDIAOWNERCUSTOMERID}"
|
|
}
|
|
|
|
#
|
|
# play library track
|
|
#
|
|
play_song()
|
|
{
|
|
if [ -z "${ALBUM}" ] ; then
|
|
JSON="{\"trackId\":\"${SONG}\",\"playQueuePrime\":true}"
|
|
else
|
|
JSON="{\"albumArtistName\":\"${ARTIST}\",\"albumName\":\"${ALBUM}\"}"
|
|
fi
|
|
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X POST -d "${JSON}"\
|
|
"https://${ALEXA}/api/cloudplayer/queue-and-play?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}&mediaOwnerCustomerId=${MEDIAOWNERCUSTOMERID}&shuffle=false"
|
|
}
|
|
|
|
#
|
|
# play library playlist
|
|
#
|
|
play_playlist()
|
|
{
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X POST -d "{\"playlistId\":\"${PLIST}\",\"playQueuePrime\":true}"\
|
|
"https://${ALEXA}/api/cloudplayer/queue-and-play?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}&mediaOwnerCustomerId=${MEDIAOWNERCUSTOMERID}&shuffle=false"
|
|
}
|
|
|
|
#
|
|
# play PRIME playlist
|
|
#
|
|
play_prime_playlist()
|
|
{
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X POST -d "{\"asin\":\"${ASIN}\"}"\
|
|
"https://${ALEXA}/api/prime/prime-playlist-queue-and-play?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}&mediaOwnerCustomerId=${MEDIAOWNERCUSTOMERID}"
|
|
}
|
|
|
|
#
|
|
# play PRIME station
|
|
#
|
|
play_prime_station()
|
|
{
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X POST -d "{\"seed\":\"{\\\"type\\\":\\\"KEY\\\",\\\"seedId\\\":\\\"${SEEDID}\\\"}\",\"stationName\":\"none\",\"seedType\":\"KEY\"}"\
|
|
"https://${ALEXA}/api/gotham/queue-and-play?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}&mediaOwnerCustomerId=${MEDIAOWNERCUSTOMERID}"
|
|
}
|
|
|
|
#
|
|
# play PRIME historical queue
|
|
#
|
|
play_prime_hist_queue()
|
|
{
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X POST -d "{\"deviceType\":\"${DEVICETYPE}\",\"deviceSerialNumber\":\"${DEVICESERIALNUMBER}\",\"mediaOwnerCustomerId\":\"${MEDIAOWNERCUSTOMERID}\",\"queueId\":\"${HIST}\",\"service\":null,\"trackSource\":\"TRACK\"}"\
|
|
"https://${ALEXA}/api/media/play-historical-queue"
|
|
}
|
|
|
|
#
|
|
# show library tracks
|
|
#
|
|
show_library()
|
|
{
|
|
OFFSET="";
|
|
SIZE=50;
|
|
TOTAL=0;
|
|
FILE=${TMP}/.alexa.${TYPE}.list
|
|
|
|
if [ ! -f ${FILE} ] ; then
|
|
echo -n '{"playlist":{"entryList":[' > ${FILE}
|
|
|
|
while [ 50 -le ${SIZE} ] ; do
|
|
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
|
|
"https://${ALEXA}/api/cloudplayer/playlists/${TYPE}-V0-OBJECTID?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}&size=${SIZE}&offset=${OFFSET}&mediaOwnerCustomerId=${MEDIAOWNERCUSTOMERID}" > ${FILE}.tmp
|
|
|
|
OFFSET=$(jq -r '.nextResultsToken' ${FILE}.tmp)
|
|
SIZE=$(jq -r '.playlist | .trackCount' ${FILE}.tmp)
|
|
jq -r -c '.playlist | .entryList' ${FILE}.tmp >> ${FILE}
|
|
echo "," >> ${FILE}
|
|
TOTAL=$((TOTAL+SIZE))
|
|
done
|
|
echo "[]],\"trackCount\":\"${TOTAL}\"}}" >> ${FILE}
|
|
rm -f ${FILE}.tmp
|
|
fi
|
|
jq -r '.playlist.trackCount' ${FILE}
|
|
jq '.playlist.entryList[] | .[]' ${FILE}
|
|
}
|
|
|
|
#
|
|
# show Prime stations and playlists
|
|
#
|
|
show_prime()
|
|
{
|
|
FILE=${TMP}/.alexa.${PRIME}.list
|
|
|
|
if [ ! -f ${FILE} ] ; then
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
|
|
"https://${ALEXA}/api/prime/{$PRIME}?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}&mediaOwnerCustomerId=${MEDIAOWNERCUSTOMERID}" > ${FILE}
|
|
|
|
if [ "$PRIME" = "prime-playlist-browse-nodes" ] ; then
|
|
for I in $(jq -r '.primePlaylistBrowseNodeList[].subNodes[].nodeId' ${FILE} 2>/dev/null) ; do
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
|
|
"https://${ALEXA}/api/prime/prime-playlists-by-browse-node?browseNodeId=${I}&deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}&mediaOwnerCustomerId=${MEDIAOWNERCUSTOMERID}" >> ${FILE}
|
|
done
|
|
fi
|
|
fi
|
|
jq '.' ${FILE}
|
|
}
|
|
|
|
#
|
|
# current queue
|
|
#
|
|
show_queue()
|
|
{
|
|
PARENT=""
|
|
PARENTID=$(jq --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .parentClusters[0]' ${DEVLIST})
|
|
if [ "$PARENTID" != "null" ] ; then
|
|
PARENTDEVICE=$(jq --arg serial ${PARENTID} -r '.devices[] | select(.serialNumber == $serial) | .deviceType' ${DEVLIST})
|
|
PARENT="&lemurId=${PARENTID}&lemurDeviceType=${PARENTDEVICE}"
|
|
fi
|
|
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
|
|
"https://${ALEXA}/api/np/player?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}${PARENT}" | jq '.'
|
|
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
|
|
"https://${ALEXA}/api/media/state?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}" | jq '.'
|
|
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
|
|
"https://${ALEXA}/api/np/queue?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}" | jq '.'
|
|
}
|
|
|
|
#
|
|
# deletes a multiroom device
|
|
#
|
|
delete_multiroom()
|
|
{
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X DELETE \
|
|
"https://${ALEXA}/api/lemur/tail/${DEVICESERIALNUMBER}"
|
|
}
|
|
|
|
#
|
|
# creates a multiroom device
|
|
#
|
|
create_multiroom()
|
|
{
|
|
JSON="{\"id\":null,\"name\":\"${LEMUR}\",\"members\":["
|
|
for DEVICE in $CHILD ; do
|
|
set_var
|
|
JSON="${JSON}{\"dsn\":\"${DEVICESERIALNUMBER}\",\"deviceType\":\"${DEVICETYPE}\"},"
|
|
done
|
|
JSON="${JSON%,}]}"
|
|
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X POST -d "${JSON}" \
|
|
"https://${ALEXA}/api/lemur/tail"
|
|
}
|
|
|
|
#
|
|
# list bluetooth devices
|
|
#
|
|
list_bluetooth()
|
|
{
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
|
|
"https://${ALEXA}/api/bluetooth?cached=false" | jq --arg serial "${DEVICESERIALNUMBER}" -r '.bluetoothStates[] | select(.deviceSerialNumber == $serial) | "\(.pairedDeviceList[]?.address) \(.pairedDeviceList[]?.friendlyName)"'
|
|
}
|
|
|
|
#
|
|
# connect bluetooth device
|
|
#
|
|
connect_bluetooth()
|
|
{
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X POST -d "{\"bluetoothDeviceAddress\":\"${BLUETOOTH}\"}"\
|
|
"https://${ALEXA}/api/bluetooth/pair-sink/${DEVICETYPE}/${DEVICESERIALNUMBER}"
|
|
}
|
|
|
|
#
|
|
# disconnect bluetooth device
|
|
#
|
|
disconnect_bluetooth()
|
|
{
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X POST \
|
|
"https://${ALEXA}/api/bluetooth/disconnect-sink/${DEVICETYPE}/${DEVICESERIALNUMBER}"
|
|
}
|
|
|
|
#
|
|
# device that sent the last command
|
|
# (by Markus Wennesheimer)
|
|
#
|
|
last_alexa()
|
|
{
|
|
${CURL} ${OPTS} -s -b ${COOKIE} -A "Mozilla/5.0" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
-H "Content-Type: application/json; charset=UTF-8" -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
|
|
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
|
|
"https://${ALEXA}/api/activities?startTime=&size=1&offset=1" | jq -r '.activities[0].sourceDeviceIds[0].serialNumber' | xargs -i jq -r --arg device {} '.devices[] | select( .serialNumber == $device) | .accountName' ${DEVLIST}
|
|
# Serial number: | jq -r '.activities[0].sourceDeviceIds[0].serialNumber'
|
|
# Device name: | jq -r '.activities[0].sourceDeviceIds[0].serialNumber' | xargs -i jq -r --arg device {} '.devices[] | select( .serialNumber == $device) | .accountName' ${DEVLIST}
|
|
}
|
|
|
|
#
|
|
# logout
|
|
#
|
|
log_off()
|
|
{
|
|
${CURL} ${OPTS} -s -c ${COOKIE} -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
|
|
https://${ALEXA}/logout > /dev/null
|
|
|
|
rm -f ${DEVLIST}
|
|
rm -f ${COOKIE}
|
|
rm -f ${TMP}/.alexa.*.list
|
|
}
|
|
|
|
if [ -z "$LASTALEXA" -a -z "$BLUETOOTH" -a -z "$LEMUR" -a -z "$PLIST" -a -z "$HIST" -a -z "$SEEDID" -a -z "$ASIN" -a -z "$PRIME" -a -z "$TYPE" -a -z "$QUEUE" -a -z "$LIST" -a -z "$COMMAND" -a -z "$STATIONID" -a -z "$SONG" -a -n "$LOGOFF" ] ; then
|
|
echo "only logout option present, logging off ..."
|
|
log_off
|
|
exit 0
|
|
fi
|
|
|
|
if [ ! -f ${COOKIE} ] ; then
|
|
echo "cookie does not exist. logging in ..."
|
|
log_in
|
|
fi
|
|
|
|
check_status
|
|
if [ $? -eq 0 ] ; then
|
|
echo "cookie expired, logging in again ..."
|
|
log_in
|
|
check_status
|
|
if [ $? -eq 0 ] ; then
|
|
echo "log in failed, aborting"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if [ ! -f ${DEVLIST} ] ; then
|
|
echo "device list does not exist. downloading ..."
|
|
get_devlist
|
|
if [ ! -f ${DEVLIST} ] ; then
|
|
echo "failed to download device list, aborting"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if [ -n "$COMMAND" -o -n "$QUEUE" ] ; then
|
|
if [ "${DEVICE}" = "ALL" ] ; then
|
|
for DEVICE in $(jq -r '.devices[] | select( .deviceFamily == "ECHO" or .deviceFamily == "KNIGHT" or .deviceFamily == "ROOK" or .deviceFamily == "WHA") | .accountName' ${DEVLIST} | sed -r 's/ /%20/g') ; do
|
|
set_var
|
|
if [ -n "$COMMAND" ] ; then
|
|
echo "sending cmd:${COMMAND} to dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} customerid:${MEDIAOWNERCUSTOMERID}"
|
|
run_cmd
|
|
else
|
|
echo "queue info for dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER}"
|
|
show_queue
|
|
fi
|
|
done
|
|
else
|
|
set_var
|
|
if [ -n "$COMMAND" ] ; then
|
|
echo "sending cmd:${COMMAND} to dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} customerid:${MEDIAOWNERCUSTOMERID}"
|
|
run_cmd
|
|
else
|
|
echo "queue info for dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER}"
|
|
show_queue
|
|
fi
|
|
fi
|
|
elif [ -n "$LEMUR" ] ; then
|
|
DEVICESERIALNUMBER=$(jq --arg device "${LEMUR}" -r '.devices[] | select(.accountName == $device and .deviceFamily == "WHA") | .serialNumber' ${DEVLIST})
|
|
if [ -n "$DEVICESERIALNUMBER" ] ; then
|
|
delete_multiroom
|
|
else
|
|
if [ -z "$CHILD" ] ; then
|
|
echo "ERROR: ${LEMUR} is no multiroom device. Cannot delete ${LEMUR}".
|
|
exit 1
|
|
fi
|
|
fi
|
|
if [ -z "$CHILD" ] ; then
|
|
echo "Deleted multi room dev:${LEMUR} serial:${DEVICESERIALNUMBER}"
|
|
else
|
|
echo "Creating multi room dev:${LEMUR} member_dev(s):${CHILD}"
|
|
create_multiroom
|
|
fi
|
|
rm -f ${DEVLIST}
|
|
get_devlist
|
|
elif [ -n "$BLUETOOTH" ] ; then
|
|
if [ "$BLUETOOTH" = "list" -o "$BLUETOOTH" = "List" -o "$BLUETOOTH" = "LIST" ] ; then
|
|
if [ "${DEVICE}" = "ALL" ] ; then
|
|
for DEVICE in $(jq -r '.devices[] | select( .deviceFamily == "ECHO" or .deviceFamily == "KNIGHT" or .deviceFamily == "ROOK" or .deviceFamily == "WHA") | .accountName' ${DEVLIST} | sed -r 's/ /%20/g') ; do
|
|
set_var
|
|
echo "bluetooth devices for dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER}:"
|
|
list_bluetooth
|
|
done
|
|
else
|
|
set_var
|
|
echo "bluetooth devices for dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER}:"
|
|
list_bluetooth
|
|
fi
|
|
elif [ "$BLUETOOTH" = "null" ] ; then
|
|
set_var
|
|
echo "disconnecting dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} from bluetooth"
|
|
disconnect_bluetooth
|
|
else
|
|
set_var
|
|
echo "connecting dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} to bluetooth device:${BLUETOOTH}"
|
|
connect_bluetooth
|
|
fi
|
|
elif [ -n "$STATIONID" ] ; then
|
|
set_var
|
|
echo "playing stationID:${STATIONID} on dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} mediaownerid:${MEDIAOWNERCUSTOMERID}"
|
|
play_radio
|
|
elif [ -n "$SONG" ] ; then
|
|
set_var
|
|
echo "playing library track:${SONG} on dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} mediaownerid:${MEDIAOWNERCUSTOMERID}"
|
|
play_song
|
|
elif [ -n "$PLIST" ] ; then
|
|
set_var
|
|
echo "playing library playlist:${PLIST} on dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} mediaownerid:${MEDIAOWNERCUSTOMERID}"
|
|
play_playlist
|
|
elif [ -n "$LIST" ] ; then
|
|
echo "the following devices exist in your account:"
|
|
list_devices
|
|
elif [ -n "$TYPE" ] ; then
|
|
set_var
|
|
echo -n "the following songs exist in your ${TYPE} library: "
|
|
show_library
|
|
elif [ -n "$PRIME" ] ; then
|
|
set_var
|
|
echo "the following songs exist in your PRIME ${PRIME}:"
|
|
show_prime
|
|
elif [ -n "$ASIN" ] ; then
|
|
set_var
|
|
echo "playing PRIME playlist ${ASIN}"
|
|
play_prime_playlist
|
|
elif [ -n "$SEEDID" ] ; then
|
|
set_var
|
|
echo "playing PRIME station ${SEEDID}"
|
|
play_prime_station
|
|
elif [ -n "$HIST" ] ; then
|
|
set_var
|
|
echo "playing PRIME historical queue ${HIST}"
|
|
play_prime_hist_queue
|
|
elif [ -n "$LASTALEXA" ] ; then
|
|
last_alexa
|
|
else
|
|
echo "no alexa command received"
|
|
fi
|
|
|
|
if [ -n "$LOGOFF" ] ; then
|
|
echo "logout option present, logging off ..."
|
|
log_off
|
|
fi
|