PR #142 Implemented refresh_token cookie exchange

This commit is contained in:
Alex 2021-10-07 20:52:51 +02:00 committed by GitHub
commit cee93ebec0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -70,6 +70,10 @@
# 2021-09-02: v0.19 Playing TuneIn works again using new entertainment API endpoint # 2021-09-02: v0.19 Playing TuneIn works again using new entertainment API endpoint
# Added playmusic (Alexa.Music.PlaySearchPhrase) as command, for available channels use "-c" # Added playmusic (Alexa.Music.PlaySearchPhrase) as command, for available channels use "-c"
# Note: playmusic is not multi-room capable, doing so might lead to unexpected results # Note: playmusic is not multi-room capable, doing so might lead to unexpected results
# 2021-09-13: v0.20 implemented device registration refresh_token cookie exchange flow as an alternative
# to logging in
# 2021-09-15: v0.20a optimized speak commands to use less JQ. This is useful in low-resource environments
# 2021-10-07: v0.20b fixed different cookie naming for amazon.com
# #
### ###
# #
@ -88,6 +92,10 @@ SET_MFA_SECRET=''
# something like: # something like:
# 1234 5678 9ABC DEFG HIJK LMNO PQRS TUVW XYZ0 1234 5678 9ABC DEFG # 1234 5678 9ABC DEFG HIJK LMNO PQRS TUVW XYZ0 1234 5678 9ABC DEFG
# this can be obtained by doing the device registration login flow
# e.g. from here: https://github.com/Apollon77/alexa-cookie/
SET_REFRESH_TOKEN=''
SET_LANGUAGE='de,en-US;q=0.7,en;q=0.3' SET_LANGUAGE='de,en-US;q=0.7,en;q=0.3'
#SET_LANGUAGE='en-US' #SET_LANGUAGE='en-US'
@ -116,6 +124,9 @@ SET_BROWSER='Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:1.0) bash-script/1.0'
# oathtool command line tool # oathtool command line tool
SET_OATHTOOL='/usr/bin/oathtool' SET_OATHTOOL='/usr/bin/oathtool'
# jq binary
SET_JQ='/usr/bin/jq'
# tmp path # tmp path
SET_TMP="/tmp" SET_TMP="/tmp"
@ -143,6 +154,7 @@ SET_VOLMAXAGE="1"
EMAIL=${EMAIL:-$SET_EMAIL} EMAIL=${EMAIL:-$SET_EMAIL}
PASSWORD=${PASSWORD:-$SET_PASSWORD} PASSWORD=${PASSWORD:-$SET_PASSWORD}
MFA_SECRET=${MFA_SECRET:-$SET_MFA_SECRET} MFA_SECRET=${MFA_SECRET:-$SET_MFA_SECRET}
REFRESH_TOKEN=${REFRESH_TOKEN:-$SET_REFRESH_TOKEN}
AMAZON=${AMAZON:-$SET_AMAZON} AMAZON=${AMAZON:-$SET_AMAZON}
ALEXA=${ALEXA:-$SET_ALEXA} ALEXA=${ALEXA:-$SET_ALEXA}
LANGUAGE=${LANGUAGE:-$SET_LANGUAGE} LANGUAGE=${LANGUAGE:-$SET_LANGUAGE}
@ -152,6 +164,7 @@ OPTS=${OPTS:-$SET_OPTS}
TTS_LOCALE=${TTS_LOCALE:-$SET_TTS_LOCALE} TTS_LOCALE=${TTS_LOCALE:-$SET_TTS_LOCALE}
TMP=${TMP:-$SET_TMP} TMP=${TMP:-$SET_TMP}
OATHTOOL=${OATHTOOL:-$SET_OATHTOOL} OATHTOOL=${OATHTOOL:-$SET_OATHTOOL}
JQ=${JQ:-$SET_JQ}
SPEAKVOL=${SPEAKVOL:-$SET_SPEAKVOL} SPEAKVOL=${SPEAKVOL:-$SET_SPEAKVOL}
NORMALVOL=${NORMALVOL:-$SET_NORMALVOL} NORMALVOL=${NORMALVOL:-$SET_NORMALVOL}
VOLMAXAGE=${VOLMAXAGE:-$SET_VOLMAXAGE} VOLMAXAGE=${VOLMAXAGE:-$SET_VOLMAXAGE}
@ -160,7 +173,7 @@ DEVICEVOLSPEAK=${DEVICEVOLSPEAK:-$SET_DEVICEVOLSPEAK}
DEVICEVOLNORMAL=${DEVICEVOLNORMAL:-$SET_DEVICEVOLNORMAL} DEVICEVOLNORMAL=${DEVICEVOLNORMAL:-$SET_DEVICEVOLNORMAL}
COOKIE="${TMP}/.alexa.cookie" COOKIE="${TMP}/.alexa.cookie"
DEVLIST="${TMP}/.alexa.devicelist.json" DEVLIST="${TMP}/.alexa.devicelist"
GUIVERSION=0 GUIVERSION=0
@ -231,7 +244,7 @@ usage()
while [ "$#" -gt 0 ] ; do while [ "$#" -gt 0 ] ; do
case "$1" in case "$1" in
--version) --version)
echo "v0.19" echo "v0.20b"
exit 0 exit 0
;; ;;
-d) -d)
@ -284,7 +297,7 @@ while [ "$#" -gt 0 ] ; do
# stationIDs are "s1234" or "s12345" # stationIDs are "s1234" or "s12345"
if [ -n "${STATIONID##s[0-9][0-9][0-9][0-9]*}" -a -n "${STATIONID##p[0-9][0-9][0-9][0-9]*}" ] ; then if [ -n "${STATIONID##s[0-9][0-9][0-9][0-9]*}" -a -n "${STATIONID##p[0-9][0-9][0-9][0-9]*}" ] ; then
# search for station name # 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') 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 if [ -z "$STATIONID" ] ; then
echo "ERROR: no Station \"$2\" found on TuneIn" echo "ERROR: no Station \"$2\" found on TuneIn"
exit 1 exit 1
@ -496,10 +509,11 @@ log_in()
# #
################################################################ ################################################################
rm -f ${DEVLIST} rm -f ${DEVLIST}.json
rm -f ${COOKIE} rm -f ${COOKIE}
rm -f ${TMP}/.alexa.*.list rm -f ${TMP}/.alexa.*.list
if [ -z "${REFRESH_TOKEN}" ] ; then
# #
# get first cookie and write redirection target into referer # get first cookie and write redirection target into referer
# #
@ -548,6 +562,26 @@ if [ -z "$(grep 'Location: https://alexa.*html' ${TMP}/.alexa.header2)" ] ; then
exit 1 exit 1
fi fi
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"
else
# ${CURL} ${OPTS} -s -X POST --data "app_name=Amazon%20Alexa&requested_token_type=auth_cookies&domain=www.${AMAZON}&source_token_type=refresh_token" --data-urlencode "source_token=${REFRESH_TOKEN}" -H "x-amzn-identity-auth-domain: api.${AMAZON}" https://api.${AMAZON}/ap/exchangetoken/cookies | ${JQ} -r '.response.tokens.cookies | to_entries[] | .key as $domain | .value[] | map_values(if . == true then "TRUE" elif . == false then "FALSE" else . end) | .Expires |= ( strptime("%d %b %Y %H:%M:%S %Z") | mktime ) | [(if .HttpOnly=="TRUE" then ("#HttpOnly_" + $domain) else $domain end), "TRUE", .Path, .Secure, .Expires, .Name, .Value] | @tsv' > ${COOKIE}
# work around for cookies valid beyond 2038-01-19 on 32bit systems
${CURL} ${OPTS} -s -X POST --data "app_name=Amazon%20Alexa&requested_token_type=auth_cookies&domain=www.${AMAZON}&source_token_type=refresh_token" --data-urlencode "source_token=${REFRESH_TOKEN}" -H "x-amzn-identity-auth-domain: api.${AMAZON}" https://api.${AMAZON}/ap/exchangetoken/cookies > ${COOKIE}.json
sed -e "$(cat ${COOKIE}.json | ${JQ} -r '.response.tokens.cookies | to_entries[] | .key as $domain | .value[] | .Expires' | awk '$3 >= 2038 { print "s/"$1" "$2" "$3" "$4" "$5"/"$1" "$2" "2037" "$4" "$5"/g" ;}')" ${COOKIE}.json |\
${JQ} -r '.response.tokens.cookies | to_entries[] | .key as $domain | .value[] | map_values(if . == true then "TRUE" elif . == false then "FALSE" else . end) | .Expires |= ( strptime("%d %b %Y %H:%M:%S %Z") | mktime ) | [(if .HttpOnly=="TRUE" then ("#HttpOnly_" + $domain) else $domain end), "TRUE", .Path, .Secure, .Expires, .Name, .Value] | @tsv' > ${COOKIE}
if [ -z "$(grep "\.${AMAZON}.*\sat-" ${COOKIE})" ] ; then
echo "ERROR: cookie retrieval with refresh_token didn't work"
exit 1
fi
rm -rf ${COOKIE}.json
fi
# #
# get CSRF # get CSRF
# #
@ -555,27 +589,21 @@ ${CURL} ${OPTS} -s -c ${COOKIE} -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Con
-H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\ -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
https://${ALEXA}/api/language > /dev/null https://${ALEXA}/api/language > /dev/null
if [ -z "$(grep ".${AMAZON}.*csrf" ${COOKIE})" ] ; then if [ -z "$(grep "\.${AMAZON}.*\scsrf" ${COOKIE})" ] ; then
echo "trying to get CSRF from handlebars" echo "trying to get CSRF from handlebars"
${CURL} ${OPTS} -s -c ${COOKIE} -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\ ${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}"\ -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
https://${ALEXA}/templates/oobe/d-device-pick.handlebars > /dev/null https://${ALEXA}/templates/oobe/d-device-pick.handlebars > /dev/null
fi fi
if [ -z "$(grep ".${AMAZON}.*csrf" ${COOKIE})" ] ; then if [ -z "$(grep "\.${AMAZON}.*\scsrf" ${COOKIE})" ] ; then
echo "trying to get CSRF from devices-v2" echo "trying to get CSRF from devices-v2"
${CURL} ${OPTS} -s -c ${COOKIE} -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\ ${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}"\ -H "Referer: https://alexa.${AMAZON}/spa/index.html" -H "Origin: https://alexa.${AMAZON}"\
https://${ALEXA}/api/devices-v2/device?cached=false > /dev/null https://${ALEXA}/api/devices-v2/device?cached=false > /dev/null
fi fi
rm -f "${TMP}/.alexa.login" if [ -z "$(grep "\.${AMAZON}.*\scsrf" ${COOKIE})" ] ; then
rm -f "${TMP}/.alexa.header"
rm -f "${TMP}/.alexa.header2"
rm -f "${TMP}/.alexa.postdata"
rm -f "${TMP}/.alexa.postdata2"
if [ -z "$(grep ".${AMAZON}.*csrf" ${COOKIE})" ] ; then
echo "ERROR: no CSRF cookie received" echo "ERROR: no CSRF cookie received"
exit 1 exit 1
fi fi
@ -589,7 +617,10 @@ get_devlist()
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\ ${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 "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})"\ -H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})"\
"https://${ALEXA}/api/devices-v2/device?cached=false" > ${DEVLIST} "https://${ALEXA}/api/devices-v2/device?cached=false" > ${DEVLIST}.json
${JQ} -r '.devices[] | "\(.accountName)=\(.deviceType)=\(.serialNumber)=\(.deviceFamily)"' ${DEVLIST}.json > ${DEVLIST}.txt
${JQ} -r '.devices[] | select(.deviceFamily == "WHA") | "\(.accountName)=\(.clusterMembers[])"' ${DEVLIST}.json > ${DEVLIST}_wha.txt
} }
check_status() check_status()
@ -618,18 +649,21 @@ set_var()
if [ -z "${DEVICE}" ] ; then if [ -z "${DEVICE}" ] ; then
# if no device was supplied, use the first Echo(dot) in device list # if no device was supplied, use the first Echo(dot) in device list
echo "setting default device to:" echo -n "setting default device to: "
DEVICE=$(jq -r '[ .devices[] | select(.deviceFamily == "ECHO" or .deviceFamily == "KNIGHT" or .deviceFamily == "ROOK" ) | .accountName] | .[0]' ${DEVLIST}) DEVICE=$(grep -m 1 -E "ECHO|KNIGHT|ROOK" ${DEVLIST}.txt | cut -d'=' -f1)
echo ${DEVICE} echo ${DEVICE}
fi fi
DEVICETYPE=$(jq --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .deviceType' ${DEVLIST}) DEVICESERIALNUMBER=$(grep -m 1 "${DEVICE}" ${DEVLIST}.txt)
DEVICESERIALNUMBER=$(jq --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .serialNumber' ${DEVLIST}) DEVICESERIALNUMBER=${DEVICESERIALNUMBER#*=}
DEVICEFAMILY=$(jq --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .deviceFamily' ${DEVLIST})
DEVICEFAMILY=${DEVICESERIALNUMBER##*=}
DEVICETYPE=${DEVICESERIALNUMBER%%=*}
DEVICESERIALNUMBER=${DEVICESERIALNUMBER#*=}
DEVICESERIALNUMBER=${DEVICESERIALNUMBER%=*}
# customerId is now retrieved from the logged in user # customerId is now retrieved from the logged in user
# the customerId in the device list is always from the user registering the device initially # 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}) # MEDIAOWNERCUSTOMERID=$(${JQ} --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .deviceOwnerCustomerId' ${DEVLIST}.json)
if [ -z "${DEVICESERIALNUMBER}" ] ; then if [ -z "${DEVICESERIALNUMBER}" ] ; then
echo "ERROR: unkown device dev:${DEVICE}" echo "ERROR: unkown device dev:${DEVICE}"
@ -642,7 +676,7 @@ set_var()
# #
list_devices() list_devices()
{ {
jq -r '.devices[].accountName' ${DEVLIST} ${JQ} -r '.devices[].accountName' ${DEVLIST}.json
} }
# #
@ -662,7 +696,7 @@ sanitize_search()
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\ ${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 "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}" \ -H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X POST -d "${JSON}" \
"https://${ALEXA}/api/behaviors/operation/validate" | jq -r '.operationPayload.sanitizedSearchPhrase' "https://${ALEXA}/api/behaviors/operation/validate" | ${JQ} -r '.operationPayload.sanitizedSearchPhrase'
} }
# #
@ -706,16 +740,16 @@ if [ -n "${SEQUENCECMD}" ] ; then
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \ -H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
"https://${ALEXA}/api/behaviors/v2/automations?limit=200" > "${TMP}/.alexa.automation" "https://${ALEXA}/api/behaviors/v2/automations?limit=200" > "${TMP}/.alexa.automation"
AUTOMATION=$(jq --arg utterance "${UTTERANCE}" -r '.[] | select( .triggers[].payload.utterance == $utterance) | .automationId' "${TMP}/.alexa.automation") AUTOMATION=$(${JQ} --arg utterance "${UTTERANCE}" -r '.[] | select( .triggers[].payload.utterance == $utterance) | .automationId' "${TMP}/.alexa.automation")
if [ -z "${AUTOMATION}" ] ; then if [ -z "${AUTOMATION}" ] ; then
AUTOMATION=$(jq --arg utterance "${UTTERANCE}" -r '.[] | select( .name == $utterance) | .automationId' "${TMP}/.alexa.automation") AUTOMATION=$(${JQ} --arg utterance "${UTTERANCE}" -r '.[] | select( .name == $utterance) | .automationId' "${TMP}/.alexa.automation")
if [ -z "${AUTOMATION}" ] ; then if [ -z "${AUTOMATION}" ] ; then
echo "ERROR: no such utterance '${UTTERANCE}' in Alexa routines" echo "ERROR: no such utterance '${UTTERANCE}' in Alexa routines"
rm -f "${TMP}/.alexa.automation" rm -f "${TMP}/.alexa.automation"
exit 1 exit 1
fi fi
fi fi
SEQUENCE=$(jq --arg automation "${AUTOMATION}" -r -c '.[] | select( .automationId == $automation) | .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") SEQUENCE=$(${JQ} --arg automation "${AUTOMATION}" -r -c '.[] | select( .automationId == $automation) | .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")
rm -f "${TMP}/.alexa.automation" rm -f "${TMP}/.alexa.automation"
ALEXACMD='{"behaviorId":"'${AUTOMATION}'","sequenceJson":"'${SEQUENCE}'","status":"ENABLED"}' ALEXACMD='{"behaviorId":"'${AUTOMATION}'","sequenceJson":"'${SEQUENCE}'","status":"ENABLED"}'
@ -732,15 +766,15 @@ if [ -n "${SEQUENCECMD}" ] ; then
# iterate over member devices if target is multiroom # iterate over member devices if target is multiroom
# !!! this is no true multi-room - it just tries to play on every member device in parallel !!! # !!! this is no true multi-room - it just tries to play on every member device in parallel !!!
if [ "${DEVICEFAMILY}" = "WHA" ] ; then if [ "${DEVICEFAMILY}" = "WHA" ] ; then
MEMBERDEVICESERIALS=$(jq --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .clusterMembers[]' ${DEVLIST}) MEMBERDEVICESERIALS=$(grep "${DEVICE}" ${DEVLIST}_wha.txt | cut -d'=' -f 2)
for DEVICESERIALNUMBER in $MEMBERDEVICESERIALS ; do for DEVICESERIALNUMBER in $MEMBERDEVICESERIALS ; do
DEVICETYPE=$(jq --arg device "${DEVICESERIALNUMBER}" -r '.devices[] | select(.serialNumber == $device) | .deviceType' ${DEVLIST}) DEVICETYPE=$(grep "${DEVICESERIALNUMBER}" ${DEVLIST}.txt | cut -d'=' -f 2)
NODESTOEXECUTE=$(add_node "$(node)" "${NODESTOEXECUTE}") NODESTOEXECUTE=$(add_node "$(node)" "${NODESTOEXECUTE}")
# add volume setting per device - the WHA volume is unrelyable # add volume setting per device - the WHA volume is unrelyable
# don't set volume if Alexa.Music.PlaySearchPhrase is used # don't set volume if Alexa.Music.PlaySearchPhrase is used
if [ \( $SPEAKVOL -gt 0 -o -n "${DEVICEVOLSPEAK}" \) -a "${SEQUENCECMD}" != "Alexa.Music.PlaySearchPhrase" ] ; then if [ \( $SPEAKVOL -gt 0 -o -n "${DEVICEVOLSPEAK}" \) -a "${SEQUENCECMD}" != "Alexa.Music.PlaySearchPhrase" ] ; then
DEVICE=$(jq --arg device "${DEVICESERIALNUMBER}" -r '.devices[] | select(.serialNumber == $device) | .accountName' ${DEVLIST}) DEVICE=$(grep "${DEVICESERIALNUMBER}" ${DEVLIST}.txt | cut -d'=' -f 1)
get_volumes get_volumes
VOLUMEPRENODESTOEXECUTE=$(add_node $(node Alexa.DeviceControls.Volume ',\"value\":\"'${SVOL}'\"') ${VOLUMEPRENODESTOEXECUTE}) VOLUMEPRENODESTOEXECUTE=$(add_node $(node Alexa.DeviceControls.Volume ',\"value\":\"'${SVOL}'\"') ${VOLUMEPRENODESTOEXECUTE})
VOLUMEPOSTNODESTOEXECUTE=$(add_node $(node Alexa.DeviceControls.Volume ',\"value\":\"'${VOL}'\"') ${VOLUMEPOSTNODESTOEXECUTE}) VOLUMEPOSTNODESTOEXECUTE=$(add_node $(node Alexa.DeviceControls.Volume ',\"value\":\"'${VOL}'\"') ${VOLUMEPOSTNODESTOEXECUTE})
@ -883,17 +917,17 @@ ${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep
-H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \ -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 "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) OFFSET=$(${JQ} -r '.nextResultsToken' ${FILE}.tmp)
SIZE=$(jq -r '.playlist | .trackCount' ${FILE}.tmp) SIZE=$(${JQ} -r '.playlist | .trackCount' ${FILE}.tmp)
jq -r -c '.playlist | .entryList' ${FILE}.tmp >> ${FILE} ${JQ} -r -c '.playlist | .entryList' ${FILE}.tmp >> ${FILE}
echo "," >> ${FILE} echo "," >> ${FILE}
TOTAL=$((TOTAL+SIZE)) TOTAL=$((TOTAL+SIZE))
done done
echo "[]],\"trackCount\":\"${TOTAL}\"}}" >> ${FILE} echo "[]],\"trackCount\":\"${TOTAL}\"}}" >> ${FILE}
rm -f ${FILE}.tmp rm -f ${FILE}.tmp
fi fi
jq -r '.playlist.trackCount' ${FILE} ${JQ} -r '.playlist.trackCount' ${FILE}
jq '.playlist.entryList[] | .[]' ${FILE} ${JQ} '.playlist.entryList[] | .[]' ${FILE}
} }
# #
@ -910,7 +944,7 @@ ${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep
"https://${ALEXA}/api/prime/{$PRIME}?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}&mediaOwnerCustomerId=${MEDIAOWNERCUSTOMERID}" > ${FILE} "https://${ALEXA}/api/prime/{$PRIME}?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}&mediaOwnerCustomerId=${MEDIAOWNERCUSTOMERID}" > ${FILE}
if [ "$PRIME" = "prime-playlist-browse-nodes" ] ; then if [ "$PRIME" = "prime-playlist-browse-nodes" ] ; then
for I in $(jq -r '.primePlaylistBrowseNodeList[].subNodes[].nodeId' ${FILE} 2>/dev/null) ; do 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\ ${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 "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 \ -H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
@ -918,7 +952,7 @@ ${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep
done done
fi fi
fi fi
jq '.' ${FILE} ${JQ} '.' ${FILE}
} }
# #
@ -927,26 +961,26 @@ ${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep
show_queue() show_queue()
{ {
PARENT="" PARENT=""
PARENTID=$(jq --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .parentClusters[0]' ${DEVLIST}) PARENTID=$(${JQ} --arg device "${DEVICE}" -r '.devices[] | select(.accountName == $device) | .parentClusters[0]' ${DEVLIST}.json)
if [ "$PARENTID" != "null" ] ; then if [ "$PARENTID" != "null" ] ; then
PARENTDEVICE=$(jq --arg serial ${PARENTID} -r '.devices[] | select(.serialNumber == $serial) | .deviceType' ${DEVLIST}) PARENTDEVICE=$(${JQ} --arg serial ${PARENTID} -r '.devices[] | select(.serialNumber == $serial) | .deviceType' ${DEVLIST}.json)
PARENT="&lemurId=${PARENTID}&lemurDeviceType=${PARENTDEVICE}" PARENT="&lemurId=${PARENTID}&lemurDeviceType=${PARENTDEVICE}"
fi fi
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\ ${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 "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 \ -H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
"https://${ALEXA}/api/np/player?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}${PARENT}" | jq '.' "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\ ${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 "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 \ -H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
"https://${ALEXA}/api/media/state?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}" | jq '.' "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\ ${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 "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 \ -H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
"https://${ALEXA}/api/np/queue?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}" | jq '.' "https://${ALEXA}/api/np/queue?deviceSerialNumber=${DEVICESERIALNUMBER}&deviceType=${DEVICETYPE}" | ${JQ} '.'
} }
get_music_channels() get_music_channels()
@ -954,7 +988,7 @@ get_music_channels()
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\ ${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 "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 \ -H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
"https://${ALEXA}/api/behaviors/entities?skillId=amzn1.ask.1p.music" | jq -r '.[] | select( .supportedProperties[] == "Alexa.Music.PlaySearchPhrase" ) | "\(.id) - \(.displayName) \(.description)"' "https://${ALEXA}/api/behaviors/entities?skillId=amzn1.ask.1p.music" | ${JQ} -r '.[] | select( .supportedProperties[] == "Alexa.Music.PlaySearchPhrase" ) | "\(.id) - \(.displayName) \(.description)"'
} }
# #
@ -1020,7 +1054,7 @@ get_volume()
VOL=$(${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\ VOL=$(${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 "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 \ -H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET \
"https://${ALEXA}/api/devices/deviceType/dsn/audio/v1/allDeviceVolumes" | jq -r --arg device "${DEVICESERIALNUMBER}" '.volumes[] | "\(.dsn) \(.speakerVolume) \(.speakerMuted)"') "https://${ALEXA}/api/devices/deviceType/dsn/audio/v1/allDeviceVolumes" | ${JQ} -r --arg device "${DEVICESERIALNUMBER}" '.volumes[] | "\(.dsn) \(.speakerVolume) \(.speakerMuted)"')
if [ -n "${VOL}" ] ; then if [ -n "${VOL}" ] ; then
# write volume and mute state to file # write volume and mute state to file
@ -1092,7 +1126,7 @@ list_bluetooth()
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\ ${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 "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 \ -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)"' "https://${ALEXA}/api/bluetooth?cached=false" | ${JQ} --arg serial "${DEVICESERIALNUMBER}" -r '.bluetoothStates[] | select(.deviceSerialNumber == $serial) | "\(.pairedDeviceList[]?.address) \(.pairedDeviceList[]?.friendlyName)"'
} }
# #
@ -1126,9 +1160,9 @@ last_alexa()
${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\ ${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 "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\ -H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET\
"https://${ALEXA}/api/activities?startTime=&size=10&offset=1" | jq -r '[.activities[] | select( .activityStatus == "SUCCESS" )][0] | .sourceDeviceIds[0].serialNumber' | xargs -i jq -r --arg device {} '.devices[] | select( .serialNumber == $device) | .accountName' ${DEVLIST} "https://${ALEXA}/api/activities?startTime=&size=10&offset=1" | ${JQ} -r '[.activities[] | select( .activityStatus == "SUCCESS" )][0] | .sourceDeviceIds[0].serialNumber' | xargs -i ${JQ} -r --arg device {} '.devices[] | select( .serialNumber == $device) | .accountName' ${DEVLIST}.json
# Serial number: | jq -r '[.activities[] | select( .activityStatus == "SUCCESS" )][0] | .sourceDeviceIds[0].serialNumber' # Serial number: | ${JQ} -r '[.activities[] | select( .activityStatus == "SUCCESS" )][0] | .sourceDeviceIds[0].serialNumber'
# Device name: | jq -r '[.activities[] | select( .activityStatus == "SUCCESS" )][0] | .sourceDeviceIds[0].serialNumber' | xargs -i jq -r --arg device {} '.devices[] | select( .serialNumber == $device) | .accountName' ${DEVLIST} # Device name: | ${JQ} -r '[.activities[] | select( .activityStatus == "SUCCESS" )][0] | .sourceDeviceIds[0].serialNumber' | xargs -i ${JQ} -r --arg device {} '.devices[] | select( .serialNumber == $device) | .accountName' ${DEVLIST}.json
} }
# #
@ -1137,15 +1171,15 @@ ${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep
# #
last_command() last_command()
{ {
SERIALNUMBER=$(jq -r --arg device "$DEVICE" '.devices[] | select( .accountName == $device ) | .serialNumber' ${DEVLIST}) SERIALNUMBER=$(${JQ} -r --arg device "$DEVICE" '.devices[] | select( .accountName == $device ) | .serialNumber' ${DEVLIST}.json)
ACTIVITIES=$(${CURL} ${OPTS} -s -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\ ACTIVITIES=$(${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 "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\ -H "csrf: $(awk "\$0 ~/.${AMAZON}.*csrf[ \\s\\t]+/ {print \$7}" ${COOKIE})" -X GET\
"https://${ALEXA}/api/activities?startTime=&size=10&offset=1") "https://${ALEXA}/api/activities?startTime=&size=10&offset=1")
if [ -z "$DEVICE" ] ; then if [ -z "$DEVICE" ] ; then
echo "$ACTIVITIES" | jq -r '[.activities[] | select( .activityStatus == "SUCCESS" )][0] | .description' | jq -r .summary echo "$ACTIVITIES" | ${JQ} -r '[.activities[] | select( .activityStatus == "SUCCESS" )][0] | .description' | ${JQ} -r .summary
else else
echo "$ACTIVITIES" | jq -r --arg serialnumber "$SERIALNUMBER" '[.activities[] | select( .activityStatus == "SUCCESS" ) | select( .sourceDeviceIds[].serialNumber == $serialnumber)][0] | .description' | jq -r .summary echo "$ACTIVITIES" | ${JQ} -r --arg serialnumber "$SERIALNUMBER" '[.activities[] | select( .activityStatus == "SUCCESS" ) | select( .sourceDeviceIds[].serialNumber == $serialnumber)][0] | .description' | ${JQ} -r .summary
fi fi
} }
@ -1157,7 +1191,9 @@ log_off()
${CURL} ${OPTS} -s -c ${COOKIE} -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\ ${CURL} ${OPTS} -s -c ${COOKIE} -b ${COOKIE} -A "${BROWSER}" -H "DNT: 1" -H "Connection: keep-alive" -L\
https://${ALEXA}/logout > /dev/null https://${ALEXA}/logout > /dev/null
rm -f ${DEVLIST} rm -f ${DEVLIST}.json
rm -f ${DEVLIST}.txt
rm -f ${DEVLIST}_wha.txt
rm -f ${COOKIE} rm -f ${COOKIE}
rm -f ${TMP}/.alexa.*.list rm -f ${TMP}/.alexa.*.list
rm -f ${TMP}/.alexa.volume.* rm -f ${TMP}/.alexa.volume.*
@ -1185,10 +1221,10 @@ if [ $? -eq 0 ] ; then
fi fi
fi fi
if [ ! -f ${DEVLIST} ] ; then if [ ! -f ${DEVLIST}.json ] ; then
echo "device list does not exist. downloading ..." echo "device list does not exist. downloading ..."
get_devlist get_devlist
if [ ! -f ${DEVLIST} ] ; then if [ ! -f ${DEVLIST}.json ] ; then
echo "failed to download device list, aborting" echo "failed to download device list, aborting"
exit 1 exit 1
fi fi
@ -1206,7 +1242,7 @@ fi
if [ -n "$COMMAND" -o -n "$QUEUE" -o -n "$NOTIFICATIONS" -o -n "$GETVOL" ] ; then if [ -n "$COMMAND" -o -n "$QUEUE" -o -n "$NOTIFICATIONS" -o -n "$GETVOL" ] ; then
if [ "${DEVICE}" = "ALL" ] ; then if [ "${DEVICE}" = "ALL" ] ; then
for DEVICE in $( jq -r '.devices[] | select( ( .deviceFamily == "ECHO" or .deviceFamily == "KNIGHT" or .deviceFamily == "ROOK" or .deviceFamily == "WHA" ) and .online == true ) | .accountName' ${DEVLIST} | sed -r 's/ /%20/g') ; do for DEVICE in $( ${JQ} -r '.devices[] | select( ( .deviceFamily == "ECHO" or .deviceFamily == "KNIGHT" or .deviceFamily == "ROOK" or .deviceFamily == "WHA" ) and .online == true ) | .accountName' ${DEVLIST}.json | sed -r 's/ /%20/g') ; do
set_var set_var
if [ -n "$COMMAND" ] ; then if [ -n "$COMMAND" ] ; then
echo "sending cmd:${COMMAND} to dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} customerid:${MEDIAOWNERCUSTOMERID}" echo "sending cmd:${COMMAND} to dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER} customerid:${MEDIAOWNERCUSTOMERID}"
@ -1245,7 +1281,7 @@ if [ -n "$COMMAND" -o -n "$QUEUE" -o -n "$NOTIFICATIONS" -o -n "$GETVOL" ] ; the
fi fi
fi fi
elif [ -n "$LEMUR" ] ; then elif [ -n "$LEMUR" ] ; then
DEVICESERIALNUMBER=$(jq --arg device "${LEMUR}" -r '.devices[] | select(.accountName == $device and .deviceFamily == "WHA") | .serialNumber' ${DEVLIST}) DEVICESERIALNUMBER=$(${JQ} --arg device "${LEMUR}" -r '.devices[] | select(.accountName == $device and .deviceFamily == "WHA") | .serialNumber' ${DEVLIST}.json)
if [ -n "$DEVICESERIALNUMBER" ] ; then if [ -n "$DEVICESERIALNUMBER" ] ; then
delete_multiroom delete_multiroom
else else
@ -1261,12 +1297,14 @@ elif [ -n "$LEMUR" ] ; then
create_multiroom create_multiroom
echo echo
fi fi
rm -f ${DEVLIST} rm -f ${DEVLIST}.json
rm -f ${DEVLIST}.txt
rm -f ${DEVLIST}_wha.txt
get_devlist get_devlist
elif [ -n "$BLUETOOTH" ] ; then elif [ -n "$BLUETOOTH" ] ; then
if [ "$BLUETOOTH" = "list" -o "$BLUETOOTH" = "List" -o "$BLUETOOTH" = "LIST" ] ; then if [ "$BLUETOOTH" = "list" -o "$BLUETOOTH" = "List" -o "$BLUETOOTH" = "LIST" ] ; then
if [ "${DEVICE}" = "ALL" ] ; 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 for DEVICE in $(${JQ} -r '.devices[] | select( .deviceFamily == "ECHO" or .deviceFamily == "KNIGHT" or .deviceFamily == "ROOK" or .deviceFamily == "WHA") | .accountName' ${DEVLIST}.json | sed -r 's/ /%20/g') ; do
set_var set_var
echo "bluetooth devices for dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER}:" echo "bluetooth devices for dev:${DEVICE} type:${DEVICETYPE} serial:${DEVICESERIALNUMBER}:"
list_bluetooth list_bluetooth