2017-12-08 10:03:23 +01:00
#!/bin/sh
#
# Amazon Alexa Remote Control (PLAIN shell)
# alex(at)loetzimmer.de
#
2021-05-27 23:05:30 +02:00
# 2021-01-28: v0.17c (for updates see http://blog.loetzimmer.de/2017/10/amazon-alexa-hort-auf-die-shell-echo.html)
2021-09-02 15:19:46 +02:00
# 2021-09-02: v0.17d includes fixes for playing tunein (base64 required)
2021-05-27 23:05:30 +02:00
#
# !!! THIS IS THE FINAL VERSION !!!
#
# Due to JQ being widely available across platforms there is no need to expose oneself to the hacks
# required when parsing JSON with BASH.
2017-12-08 10:03:23 +01:00
#
###
#
# (no BASHisms were used, should run with any shell)
# - requires cURL for web communication
2018-01-10 08:24:36 +01:00
# - (GNU) sed and awk for extraction
2021-09-02 15:19:46 +02:00
# - base64 for B64 encoding (make sure "-w 0" option is available on your platform)
2019-08-05 21:31:11 +02:00
# - oathtool as OATH one-time password tool (optional for two-factor authentication)
2017-12-08 10:03:23 +01:00
#
##########################################
2019-01-23 00:07:58 +01:00
SET_EMAIL = 'amazon_account@email.address'
SET_PASSWORD = 'Very_Secret_Amazon_Account_Password'
2019-07-08 21:12:09 +02:00
SET_MFA_SECRET = ''
# something like:
# 1234 5678 9ABC DEFG HIJK LMNO PQRS TUVW XYZ0 1234 5678 9ABC DEFG
2017-12-08 10:03:23 +01:00
2019-03-24 19:51:43 +01:00
SET_LANGUAGE = 'de,en-US;q=0.7,en;q=0.3'
#SET_LANGUAGE='en-US'
2017-12-08 10:03:23 +01:00
2019-02-11 00:14:48 +01:00
SET_TTS_LOCALE = 'de-DE'
2019-01-23 00:07:58 +01:00
SET_AMAZON = 'amazon.de'
#SET_AMAZON='amazon.com'
SET_ALEXA = 'alexa.amazon.de'
#SET_ALEXA='pitangui.amazon.com'
2017-12-08 10:03:23 +01:00
# cURL binary
2019-01-23 00:07:58 +01:00
SET_CURL = '/usr/bin/curl'
2017-12-08 10:03:23 +01:00
# 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
2018-03-09 18:53:33 +01:00
# --http1.1 : cURL defaults to HTTP/2 on HTTPS connections if available
2019-01-23 00:07:58 +01:00
SET_OPTS = '--compressed --http1.1'
#SET_OPTS='-k --compressed --http1.1'
2017-12-08 10:03:23 +01:00
2018-01-28 18:33:16 +01:00
# browser identity
2019-01-23 00:07:58 +01:00
SET_BROWSER = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:1.0) bash-script/1.0'
2019-02-10 20:04:11 +01:00
#SET_BROWSER='Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0'
2019-01-23 00:07:58 +01:00
2019-07-08 22:41:22 +02:00
# oathtool command line tool
SET_OATHTOOL = '/usr/bin/oathtool'
2019-07-08 21:12:09 +02:00
2019-01-23 00:07:58 +01:00
# tmp path
SET_TMP = "/tmp"
2018-01-28 18:33:16 +01:00
2020-02-03 21:58:45 +01:00
# Volume for speak commands (a SPEAKVOL of 0 leaves the volume settings untouched)
2020-02-09 20:53:03 +01:00
SET_SPEAKVOL = "0"
2019-08-05 21:31:11 +02:00
# if no current playing volume can be determined, fall back to normal volume
SET_NORMALVOL = "10"
2019-12-30 22:51:36 +01:00
# Device specific volumes (overriding the above)
2020-12-12 21:43:28 +01:00
SET_DEVICEVOLNAME = "EchoDot2ndGen Echo1stGen"
2019-12-30 22:51:36 +01:00
SET_DEVICEVOLSPEAK = "100 30"
SET_DEVICEVOLNORMAL = "100 20"
2017-12-08 10:03:23 +01:00
###########################################
# nothing to configure below here
#
2019-01-23 00:07:58 +01:00
# retrieving environment variables if any are set
EMAIL = ${ EMAIL :- $SET_EMAIL }
PASSWORD = ${ PASSWORD :- $SET_PASSWORD }
2019-03-24 19:51:43 +01:00
MFA_SECRET = ${ MFA_SECRET :- $SET_MFA_SECRET }
2019-01-23 00:07:58 +01:00
AMAZON = ${ AMAZON :- $SET_AMAZON }
ALEXA = ${ ALEXA :- $SET_ALEXA }
LANGUAGE = ${ LANGUAGE :- $SET_LANGUAGE }
BROWSER = ${ BROWSER :- $SET_BROWSER }
CURL = ${ CURL :- $SET_CURL }
OPTS = ${ OPTS :- $SET_OPTS }
2019-02-11 00:14:48 +01:00
TTS_LOCALE = ${ TTS_LOCALE :- $SET_TTS_LOCALE }
2019-01-23 00:07:58 +01:00
TMP = ${ TMP :- $SET_TMP }
2019-07-08 23:39:09 +02:00
OATHTOOL = ${ OATHTOOL :- $SET_OATHTOOL }
2019-08-05 21:31:11 +02:00
SPEAKVOL = ${ SPEAKVOL :- $SET_SPEAKVOL }
NORMALVOL = ${ NORMALVOL :- $SET_NORMALVOL }
2019-12-30 22:51:36 +01:00
DEVICEVOLNAME = ${ DEVICEVOLNAME :- $SET_DEVICEVOLNAME }
DEVICEVOLSPEAK = ${ DEVICEVOLSPEAK :- $SET_DEVICEVOLSPEAK }
DEVICEVOLNORMAL = ${ DEVICEVOLNORMAL :- $SET_DEVICEVOLNORMAL }
2019-01-23 00:07:58 +01:00
2017-12-08 10:03:23 +01:00
COOKIE = " ${ TMP } /.alexa.cookie "
DEVLIST = " ${ TMP } /.alexa.devicelist.json "
DEVTXT = " ${ TMP } /.alexa.devicelist.txt "
2019-02-10 20:04:11 +01:00
DEVALL = " ${ TMP } /.alexa.devicelist.all "
2017-12-08 10:03:23 +01:00
GUIVERSION = 0
LIST = ""
LOGOFF = ""
COMMAND = ""
2018-06-18 17:56:30 +02:00
TTS = ""
SEQUENCECMD = ""
2019-08-05 21:31:11 +02:00
SEQUENCEVAL = ""
2017-12-08 10:03:23 +01:00
STATIONID = ""
QUEUE = ""
SONG = ""
2018-06-18 17:56:30 +02:00
ALBUM = ""
ARTIST = ""
2017-12-08 10:03:23 +01:00
ASIN = ""
SEEDID = ""
HIST = ""
LEMUR = ""
CHILD = ""
PLIST = ""
BLUETOOTH = ""
2018-03-01 22:35:22 +01:00
LASTALEXA = ""
2020-01-08 21:34:53 +01:00
NOTIFICATIONS = ""
2017-12-08 10:03:23 +01:00
usage( )
{
2019-01-23 00:07:58 +01:00
echo " $0 [-d <device>|ALL] -e <pause|play|next|prev|fwd|rwd|shuffle|repeat|vol:<0-100>> | "
2020-01-08 21:34:53 +01:00
echo " -b [list|<\"AA:BB:CC:DD:EE:FF\">] | -q | -n | -r <\"station name\"|stationid> |"
2018-06-18 17:56:30 +02:00
echo " -s <trackID|'Artist' 'Album'> | -t <ASIN> | -u <seedID> | -v <queueID> | -w <playlistId> |"
echo " -a | -m <multiroom_device> [device_1 .. device_X] | -lastalexa | -l | -h"
echo
echo " -e : run command, additional SEQUENCECMDs:"
2020-02-09 20:53:03 +01:00
echo " weather,traffic,flashbriefing,goodmorning,singasong,tellstory,"
2020-12-12 21:43:28 +01:00
echo " speak:'<text>',sound:<soundeffect_name>,"
echo " textcommand:'<anything you would otherwise say to Alexa>'"
2018-01-10 08:24:36 +01:00
echo " -b : connect/disconnect/list bluetooth device"
2019-02-10 20:04:11 +01:00
echo " -q : query queue"
2019-08-25 17:48:35 +02:00
echo " -n : query notifications"
2017-12-08 10:03:23 +01:00
echo " -r : play tunein radio"
2018-06-18 17:56:30 +02:00
echo " -s : play library track/library album"
2017-12-08 10:03:23 +01:00
echo " -t : play Prime playlist"
echo " -u : play Prime station"
echo " -v : play Prime historical queue"
echo " -w : play library playlist"
echo " -a : list available devices"
echo " -m : delete multiroom and/or create new multiroom containing devices"
2018-03-01 22:35:22 +01:00
echo " -lastalexa : print serial number that received the last voice command"
2020-01-22 09:41:16 +01:00
echo " -login : Logs in, without further command"
2017-12-08 10:03:23 +01:00
echo " -l : logoff"
echo " -h : help"
}
while [ " $# " -gt 0 ] ; do
case " $1 " in
2020-01-20 20:28:05 +01:00
--version)
2021-09-02 15:19:46 +02:00
echo "v0.17d"
2020-01-20 20:28:05 +01:00
exit 0
; ;
2017-12-08 10:03:23 +01:00
-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
; ;
-s)
if [ " ${ 2 #- } " != " ${ 2 } " -o -z " $2 " ] ; then
echo " ERROR: missing argument for ${ 1 } "
usage
exit 1
fi
SONG = $2
shift
2018-06-18 17:56:30 +02:00
if [ " ${ 2 #- } " = " ${ 2 } " -a -n " $2 " ] ; then
ALBUM = $2
ARTIST = $SONG
shift
fi
2017-12-08 10:03:23 +01:00
; ;
-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
; ;
-d)
if [ " ${ 2 #- } " != " ${ 2 } " -o -z " $2 " ] ; then
echo " ERROR: missing argument for ${ 1 } "
usage
exit 1
fi
DEVICE = $2
shift
; ;
2020-01-22 09:41:16 +01:00
-login)
LOGIN = "true"
; ;
2017-12-08 10:03:23 +01:00
-l)
LOGOFF = "true"
; ;
-a)
LIST = "true"
; ;
-q)
QUEUE = "true"
; ;
2019-08-25 17:48:35 +02:00
-n)
NOTIFICATIONS = "true"
; ;
2018-03-01 22:35:22 +01:00
-lastalexa)
LASTALEXA = "true"
; ;
2017-12-08 10:03:23 +01:00
-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"}'
; ;
2019-01-23 00:07:58 +01:00
repeat)
COMMAND = '{"type":"RepeatCommand","repeat":true}'
; ;
2017-12-08 10:03:23 +01:00
vol:*)
VOL = ${ COMMAND ##* : }
# volume as integer!
if [ $VOL -le 100 -a $VOL -ge 0 ] ; then
2019-08-05 21:31:11 +02:00
# COMMAND='{"type":"VolumeLevelCommand","volumeLevel":'${VOL}'}'
SEQUENCECMD = 'Alexa.DeviceControls.Volume'
SEQUENCEVAL = ',\"value\":\"' ${ VOL } '\"'
2017-12-08 10:03:23 +01:00
else
echo "ERROR: volume should be an integer between 0 and 100"
usage
exit 1
fi
; ;
2020-12-12 21:43:28 +01:00
textcommand:*)
SEQUENCECMD = 'Alexa.TextCommand\",\"skillId\":\"amzn1.ask.1p.tellalexa'
SEQUENCEVAL = $( echo ${ COMMAND ##textcommand : } | sed -r s/\" /\' /g)
SEQUENCEVAL = ',\"text\":\"' ${ SEQUENCEVAL } '\"'
; ;
2018-06-18 17:56:30 +02:00
speak:*)
2019-02-14 20:52:11 +01:00
TTS = $( echo ${ COMMAND ##* : } | sed -r 's/["\\]/ /g' )
2020-02-03 21:58:45 +01:00
TTS = ',\"textToSpeak\":\"' ${ TTS } '\"'
SEQUENCECMD = 'Alexa.Speak'
SEQUENCEVAL = $TTS
2018-06-18 17:56:30 +02:00
; ;
2020-02-09 20:53:03 +01:00
sound:*)
SEQUENCECMD = 'Alexa.Sound'
SEQUENCEVAL = ',\"soundStringId\":\"' ${ COMMAND ##sound : } '\"'
; ;
2018-06-18 17:56:30 +02:00
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'
; ;
2017-12-08 10:03:23 +01:00
"" )
; ;
*)
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 ${ DEVTXT }
2019-02-10 20:04:11 +01:00
rm -f ${ DEVALL }
2017-12-08 10:03:23 +01:00
rm -f ${ COOKIE }
#
# get first cookie and write redirection target into referer
#
2018-01-28 18:33:16 +01:00
${ 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\
2017-12-08 10:03:23 +01:00
https://alexa.${ AMAZON } | grep "hidden" | sed 's/hidden/\n/g' | grep "value=\"" | sed -r 's/^.*name="([^"]+)".*value="([^"]+)".*/\1=\2\&/g' > " ${ TMP } /.alexa.postdata "
#
2018-03-01 22:35:22 +01:00
# login empty to generate session
2017-12-08 10:03:23 +01:00
#
2018-01-28 18:33:16 +01:00
${ 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\
2017-12-08 10:03:23 +01:00
-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 "
2019-03-24 19:51:43 +01:00
#
2019-03-24 22:31:48 +01:00
# add OTP if using MFA
2019-03-24 19:51:43 +01:00
#
2019-07-08 21:12:09 +02:00
if [ -n " ${ MFA_SECRET } " ] ; then
2019-07-08 22:41:22 +02:00
OTP = $( ${ OATHTOOL } -b --totp " ${ MFA_SECRET } " )
2019-03-24 19:51:43 +01:00
PASSWORD = " ${ PASSWORD } ${ OTP } "
fi
2017-12-08 10:03:23 +01:00
#
# login with filled out form
# !!! referer now contains session in URL
#
2018-03-01 22:35:22 +01:00
${ 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 "
2017-12-08 10:03:23 +01:00
2018-03-01 22:35:22 +01:00
# 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) "
2019-03-24 19:51:43 +01:00
echo
echo " To avoid issues with captcha, try using Multi-Factor Authentication."
echo " To do so, first set up Two-Step Verification on your Amazon account, then"
echo " configure this script (or the environment) with your MFA secret."
echo " Support for Multi-Factor Authentication requires 'oathtool' to be installed."
2018-03-01 22:35:22 +01:00
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
2017-12-08 10:03:23 +01:00
#
# get CSRF
#
2018-01-28 18:33:16 +01:00
${ CURL } ${ OPTS } -s -c ${ COOKIE } -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2017-12-08 10:03:23 +01:00
-H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
2019-06-28 23:14:00 +02:00
https://${ ALEXA } /api/language > /dev/null
if [ -z " $( grep " . ${ AMAZON } .*csrf " ${ COOKIE } ) " ] ; then
echo "trying to get CSRF from handlebars"
${ 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 } /templates/oobe/d-device-pick.handlebars > /dev/null
fi
if [ -z " $( grep " . ${ AMAZON } .*csrf " ${ COOKIE } ) " ] ; then
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\
-H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
https://${ ALEXA } /api/devices-v2/device?cached= false > /dev/null
fi
2017-12-08 10:03:23 +01:00
2018-03-01 22:35:22 +01:00
rm -f " ${ TMP } /.alexa.login "
2017-12-08 10:03:23 +01:00
rm -f " ${ TMP } /.alexa.header "
2018-03-01 22:35:22 +01:00
rm -f " ${ TMP } /.alexa.header2 "
2017-12-08 10:03:23 +01:00
rm -f " ${ TMP } /.alexa.postdata "
rm -f " ${ TMP } /.alexa.postdata2 "
2019-06-28 23:14:00 +02:00
if [ -z " $( grep " . ${ AMAZON } .*csrf " ${ COOKIE } ) " ] ; then
echo "ERROR: no CSRF cookie received"
exit 1
fi
2017-12-08 10:03:23 +01:00
}
#
# get JSON device list
#
get_devlist( )
{
2018-01-28 18:33:16 +01:00
${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2017-12-08 10:03:23 +01:00
-H "Content-Type: application/json; charset=UTF-8" -H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
2017-12-19 09:43:52 +01:00
-H " csrf: $( awk " \$0 ~/. ${ AMAZON } .*csrf[ \\s\\t]+/ {print \$7} " ${ COOKIE } ) " \
2017-12-08 10:03:23 +01:00
" https:// ${ ALEXA } /api/devices-v2/device?cached=false " > ${ DEVLIST }
if [ ! -f ${ DEVTXT } ] ; then
cat ${ DEVLIST } | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k = "text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' > ${ DEVTXT }
fi
2019-02-10 20:04:11 +01:00
# create a file that contains valid device names for the "ALL" device
ATTR = "accountName"
NAME = $( grep ${ ATTR } \| ${ DEVTXT } | sed " s/^.* ${ ATTR } |// " | sed 's/ /_/g' )
ATTR = "deviceFamily"
FAMILY = $( grep ${ ATTR } \| ${ DEVTXT } | sed " s/^.* ${ ATTR } |// " | sed 's/ /_/g' )
IDX = 0
for N in $NAME ; do
C = 0
for F in $FAMILY ; do
if [ $C -eq $IDX ] ; then
if [ " $F " = "WHA" -o " $F " = "ECHO" -o " $F " = "KNIGHT" -o " $F " = "ROOK" ] ; then
echo ${ N } >> ${ DEVALL }
fi
break
fi
C = $(( C+1))
done
IDX = $(( IDX+1))
done
2017-12-08 10:03:23 +01:00
}
check_status( )
{
#
# bootstrap with GUI-Version writes GUI version to cookie
# returns among other the current authentication state
#
2019-01-23 01:00:37 +01:00
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' )
2017-12-08 10:03:23 +01:00
if [ " $AUTHSTATUS " = "true" ] ; then
return 1
fi
return 0
}
#
# set device specific variables from JSON device list
#
set_var( )
{
ATTR = "accountName"
2019-02-10 20:04:11 +01:00
NAME = $( grep ${ ATTR } \| ${ DEVTXT } | sed " s/^.* ${ ATTR } |// " | sed 's/ /_/g' )
2017-12-08 10:03:23 +01:00
ATTR = "deviceType"
2019-02-10 20:04:11 +01:00
TYPE = $( grep ${ ATTR } \| ${ DEVTXT } | sed " s/^.* ${ ATTR } |// " | sed 's/ /_/g' )
2017-12-08 10:03:23 +01:00
ATTR = "serialNumber"
2019-02-10 20:04:11 +01:00
SERIAL = $( grep ${ ATTR } \| ${ DEVTXT } | sed " s/^.* ${ ATTR } |// " | sed 's/ /_/g' )
2017-12-08 10:03:23 +01:00
2019-01-23 01:00:37 +01:00
# ATTR="deviceOwnerCustomerId"
2019-02-10 20:04:11 +01:00
# MEDIAID=`grep ${ATTR}\| ${DEVTXT} | sed "s/^.*${ATTR}|//" | sed 's/ /_/g')
2017-12-08 10:03:23 +01:00
ATTR = "deviceFamily"
2019-02-10 20:04:11 +01:00
FAMILY = $( grep ${ ATTR } \| ${ DEVTXT } | sed " s/^.* ${ ATTR } |// " | sed 's/ /_/g' )
2017-12-08 10:03:23 +01:00
2019-12-30 22:51:36 +01:00
ATTR = "online"
ONLINE = $( grep ${ ATTR } \: ${ DEVTXT } | sed " s/^.* ${ ATTR } :// " )
2017-12-08 10:03:23 +01:00
if [ -z " ${ DEVICE } " ] ; then
# if no device was supplied, use the first Echo(dot) in device list
2019-02-10 20:04:11 +01:00
IDX = 0
for F in $FAMILY ; do
if [ " $F " = "ECHO" -o " $F " = "KNIGHT" -o " $F " = "ROOK" ] ; then
break;
2017-12-08 10:03:23 +01:00
fi
IDX = $(( IDX+1))
done
C = 0
2019-02-10 20:04:11 +01:00
for N in $NAME ; do
2017-12-08 10:03:23 +01:00
if [ $C -eq $IDX ] ; then
2019-02-10 20:04:11 +01:00
DEVICE = $N
2017-12-08 10:03:23 +01:00
break
fi
C = $(( C+1))
done
echo "setting default device to:"
echo ${ DEVICE }
else
DEVICE = ` echo $DEVICE | sed 's/ /_/g' `
IDX = 0
2019-02-10 20:04:11 +01:00
for N in $NAME ; do
if [ " $N " = " $DEVICE " ] ; then
2017-12-08 10:03:23 +01:00
break;
fi
IDX = $(( IDX+1))
done
fi
2019-01-23 01:00:37 +01:00
# customerId is now retrieved from the logged in user
# the customerId in the device list is always from the user registering the device initially
# C=0
# for I in $MEDIAID ; do
# if [ $C -eq $IDX ] ; then
# MEDIAOWNERCUSTOMERID=$I
# break
# fi
# C=$((C+1))
# done
2017-12-08 10:03:23 +01:00
C = 0
2019-02-10 20:04:11 +01:00
for T in $TYPE ; do
2017-12-08 10:03:23 +01:00
if [ $C -eq $IDX ] ; then
2019-02-10 20:04:11 +01:00
DEVICETYPE = $T
2017-12-08 10:03:23 +01:00
break
fi
C = $(( C+1))
done
C = 0
2019-02-10 20:04:11 +01:00
for S in $SERIAL ; do
2017-12-08 10:03:23 +01:00
if [ $C -eq $IDX ] ; then
2019-02-10 20:04:11 +01:00
DEVICESERIALNUMBER = $S
2017-12-08 10:03:23 +01:00
break
fi
C = $(( C+1))
done
2019-12-30 22:51:36 +01:00
C = 0
for F in $FAMILY ; do
if [ $C -eq $IDX ] ; then
DEVICEFAMILY = $F
break
fi
C = $(( C+1))
done
C = 0
for O in $ONLINE ; do
if [ $C -eq $IDX ] ; then
DEVICESTATE = $O
break
fi
C = $(( C+1))
done
2017-12-08 10:03:23 +01:00
if [ -z " ${ DEVICESERIALNUMBER } " ] ; then
echo " ERROR: unkown device dev: ${ DEVICE } "
exit 1
fi
}
#
# execute command
2018-06-18 17:56:30 +02:00
# (SequenceCommands by Michael Geramb and Ralf Otto)
2017-12-08 10:03:23 +01:00
#
run_cmd( )
{
2019-08-05 21:31:11 +02:00
if [ -n " ${ SEQUENCECMD } " ] ; then
2020-12-12 21:43:28 +01:00
if echo $COMMAND | grep -q -E "weather|traffic|flashbriefing|goodmorning|singasong|tellstory|speak|sound|textcommand" ; then
2019-12-30 22:51:36 +01:00
if [ " ${ DEVICEFAMILY } " = "WHA" ] ; then
echo " Skipping unsupported command: ${ COMMAND } on dev: ${ DEVICE } type: ${ DEVICETYPE } serial: ${ DEVICESERIALNUMBER } family: ${ DEVICEFAMILY } "
return
fi
2020-02-03 21:58:45 +01:00
fi
# the speak command is treated differently if $SPEAKVOL > 0
2020-12-12 22:46:40 +01:00
if [ -n " ${ TTS } " -a $SPEAKVOL -gt 0 ] || [ " ${ COMMAND %% : * } " = 'sound' -a $SPEAKVOL -gt 0 ] ; then
2019-12-30 22:51:36 +01:00
SVOL = $SPEAKVOL
# Not using arrays here in order to be compatible with non-Bash
# Get the list position of the current device type
IDX = 0
for D in $DEVICEVOLNAME ; do
if [ " ${ D } " = " ${ DEVICE } " ] ; then
break;
fi
IDX = $(( IDX+1))
done
# get the speak volume at that position
C = 0
for D in $DEVICEVOLSPEAK ; do
if [ $C -eq $IDX ] ; then
if [ -n " ${ D } " ] ; then SVOL = $D ; fi
break
fi
C = $(( C+1))
done
2019-08-05 21:31:11 +02:00
# try to retrieve the "currently playing" volume
VOL = $( ${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2018-06-18 17:56:30 +02:00
-H "Content-Type: application/json; charset=UTF-8" -H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
2019-08-05 21:31:11 +02:00
-H " csrf: $( awk " \$0 ~/. ${ AMAZON } .*csrf[ \\s\\t]+/ {print \$7} " ${ COOKIE } ) " -X GET \
" https:// ${ ALEXA } /api/media/state?deviceSerialNumber= ${ DEVICESERIALNUMBER } &deviceType= ${ DEVICETYPE } " | grep 'volume' | sed -r 's/^.*"volume":\s*([0-9]+)[^0-9]*$/\1/g' )
2019-12-30 22:51:36 +01:00
# in order to prevent a "Rate exceeded" we need to delay the command
sleep 1
2019-08-05 21:31:11 +02:00
2019-12-30 22:51:36 +01:00
if [ -z " ${ VOL } " ] ; then
# get the normal volume of the current device type
C = 0
for D in $DEVICEVOLNORMAL ; do
if [ $C -eq $IDX ] ; then
VOL = $D
break
fi
C = $(( C+1))
done
# if the volume is still undefined, use $NORMALVOL
if [ -z " ${ VOL } " ] ; then
VOL = $NORMALVOL
fi
fi
2020-12-12 22:46:40 +01:00
ALEXACMD = '{"behaviorId":"PREVIEW","sequenceJson":"{\"@type\":\"com.amazon.alexa.behaviors.model.Sequence\",\"startNode\":{\"@type\":\"com.amazon.alexa.behaviors.model.SerialNode\",\"nodesToExecute\":[{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"Alexa.DeviceControls.Volume\",\"operationPayload\":{\"deviceType\":\"' ${ DEVICETYPE } '\",\"deviceSerialNumber\":\"' ${ DEVICESERIALNUMBER } '\",\"customerId\":\"' ${ MEDIAOWNERCUSTOMERID } '\",\"locale\":\"' ${ TTS_LOCALE } '\",\"value\":\"' ${ SVOL } '\"}},{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"' ${ SEQUENCECMD } '\",\"operationPayload\":{\"deviceType\":\"' ${ DEVICETYPE } '\",\"deviceSerialNumber\":\"' ${ DEVICESERIALNUMBER } '\",\"customerId\":\"' ${ MEDIAOWNERCUSTOMERID } '\",\"locale\":\"' ${ TTS_LOCALE } '\"' ${ SEQUENCEVAL } '}},{\"@type\":\"com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode\",\"type\":\"Alexa.DeviceControls.Volume\",\"operationPayload\":{\"deviceType\":\"' ${ DEVICETYPE } '\",\"deviceSerialNumber\":\"' ${ DEVICESERIALNUMBER } '\",\"customerId\":\"' ${ MEDIAOWNERCUSTOMERID } '\",\"locale\":\"' ${ TTS_LOCALE } '\",\"value\":\"' ${ VOL } '\"}}]}}","status":"ENABLED"}'
2019-08-05 21:31:11 +02:00
else
ALEXACMD = '{"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 } '\",\"customerId\":\"' ${ MEDIAOWNERCUSTOMERID } '\",\"locale\":\"' ${ TTS_LOCALE } '\"' ${ SEQUENCEVAL } '}}}","status":"ENABLED"}'
fi
# Due to some weird shell-escape-behavior the command has to be written to a file before POSTing it
echo $ALEXACMD > " ${ TMP } /.alexa.cmd "
${ 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 @" ${ TMP } /.alexa.cmd " \
" https:// ${ ALEXA } /api/behaviors/preview "
2019-02-03 22:48:03 +01:00
2019-08-05 21:31:11 +02:00
rm -f " ${ TMP } /.alexa.cmd "
2019-02-03 22:48:03 +01:00
2018-06-18 17:56:30 +02:00
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
2017-12-08 10:03:23 +01:00
}
#
# play TuneIn radio station
#
play_radio( )
{
2021-09-02 15:19:46 +02:00
JSON = '{"contentToken":"music:' $( echo '["music/tuneIn/stationId","' ${ STATIONID } '"]|{"previousPageId":"TuneIn_SEARCH"}' | base64 -w 0| base64 -w 0 ) '"}'
${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2017-12-08 10:03:23 +01:00
-H "Content-Type: application/json; charset=UTF-8" -H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
2021-09-02 15:19:46 +02:00
-H " csrf: $( awk " \$0 ~/. ${ AMAZON } .*csrf[ \\s\\t]+/ {print \$7} " ${ COOKIE } ) " -X PUT -d " ${ JSON } " \
" https:// ${ ALEXA } /api/entertainment/v1/player/queue?deviceSerialNumber= ${ DEVICESERIALNUMBER } &deviceType= ${ DEVICETYPE } "
2017-12-08 10:03:23 +01:00
}
#
# play library track
#
play_song( )
{
2018-06-18 17:56:30 +02:00
if [ -z " ${ ALBUM } " ] ; then
JSON = " {\"trackId\":\" ${ SONG } \",\"playQueuePrime\":true} "
else
JSON = " {\"albumArtistName\":\" ${ ARTIST } \",\"albumName\":\" ${ ALBUM } \"} "
fi
2018-01-28 18:33:16 +01:00
${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2017-12-08 10:03:23 +01:00
-H "Content-Type: application/json; charset=UTF-8" -H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
2018-06-18 17:56:30 +02:00
-H " csrf: $( awk " \$0 ~/. ${ AMAZON } .*csrf[ \\s\\t]+/ {print \$7} " ${ COOKIE } ) " -X POST -d " ${ JSON } " \
2017-12-08 10:03:23 +01:00
" https:// ${ ALEXA } /api/cloudplayer/queue-and-play?deviceSerialNumber= ${ DEVICESERIALNUMBER } &deviceType= ${ DEVICETYPE } &mediaOwnerCustomerId= ${ MEDIAOWNERCUSTOMERID } &shuffle=false "
}
#
# play library playlist
#
play_playlist( )
{
2018-01-28 18:33:16 +01:00
${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2017-12-08 10:03:23 +01:00
-H "Content-Type: application/json; charset=UTF-8" -H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
2017-12-19 09:43:52 +01:00
-H " csrf: $( awk " \$0 ~/. ${ AMAZON } .*csrf[ \\s\\t]+/ {print \$7} " ${ COOKIE } ) " -X POST -d " {\"playlistId\":\" ${ PLIST } \",\"playQueuePrime\":true} " \
2017-12-08 10:03:23 +01:00
" https:// ${ ALEXA } /api/cloudplayer/queue-and-play?deviceSerialNumber= ${ DEVICESERIALNUMBER } &deviceType= ${ DEVICETYPE } &mediaOwnerCustomerId= ${ MEDIAOWNERCUSTOMERID } &shuffle=false "
}
#
# play PRIME playlist
#
play_prime_playlist( )
{
2018-01-28 18:33:16 +01:00
${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2017-12-08 10:03:23 +01:00
-H "Content-Type: application/json; charset=UTF-8" -H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
2017-12-19 09:43:52 +01:00
-H " csrf: $( awk " \$0 ~/. ${ AMAZON } .*csrf[ \\s\\t]+/ {print \$7} " ${ COOKIE } ) " -X POST -d " {\"asin\":\" ${ ASIN } \"} " \
2017-12-08 10:03:23 +01:00
" https:// ${ ALEXA } /api/prime/prime-playlist-queue-and-play?deviceSerialNumber= ${ DEVICESERIALNUMBER } &deviceType= ${ DEVICETYPE } &mediaOwnerCustomerId= ${ MEDIAOWNERCUSTOMERID } "
}
#
# play PRIME station
#
play_prime_station( )
{
2018-01-28 18:33:16 +01:00
${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2017-12-08 10:03:23 +01:00
-H "Content-Type: application/json; charset=UTF-8" -H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
2017-12-19 09:43:52 +01:00
-H " csrf: $( awk " \$0 ~/. ${ AMAZON } .*csrf[ \\s\\t]+/ {print \$7} " ${ COOKIE } ) " -X POST -d " {\"seed\":\"{\\\"type\\\":\\\"KEY\\\",\\\"seedId\\\":\\\" ${ SEEDID } \\\"}\",\"stationName\":\"none\",\"seedType\":\"KEY\"} " \
2017-12-08 10:03:23 +01:00
" https:// ${ ALEXA } /api/gotham/queue-and-play?deviceSerialNumber= ${ DEVICESERIALNUMBER } &deviceType= ${ DEVICETYPE } &mediaOwnerCustomerId= ${ MEDIAOWNERCUSTOMERID } "
}
#
# play PRIME historical queue
#
play_prime_hist_queue( )
{
2018-01-28 18:33:16 +01:00
${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2017-12-08 10:03:23 +01:00
-H "Content-Type: application/json; charset=UTF-8" -H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
2017-12-19 09:43:52 +01:00
-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\"} " \
2017-12-08 10:03:23 +01:00
" https:// ${ ALEXA } /api/media/play-historical-queue "
}
#
# current queue
#
show_queue( )
{
echo "/api/np/player"
2018-01-28 18:33:16 +01:00
${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2017-12-08 10:03:23 +01:00
-H "Content-Type: application/json; charset=UTF-8" -H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
2017-12-19 09:43:52 +01:00
-H " csrf: $( awk " \$0 ~/. ${ AMAZON } .*csrf[ \\s\\t]+/ {print \$7} " ${ COOKIE } ) " -X GET \
2017-12-08 10:03:23 +01:00
" https:// ${ ALEXA } /api/np/player?deviceSerialNumber= ${ DEVICESERIALNUMBER } &deviceType= ${ DEVICETYPE } "
echo
echo "/api/np/queue"
2018-01-28 18:33:16 +01:00
${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2017-12-08 10:03:23 +01:00
-H "Content-Type: application/json; charset=UTF-8" -H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
2017-12-19 09:43:52 +01:00
-H " csrf: $( awk " \$0 ~/. ${ AMAZON } .*csrf[ \\s\\t]+/ {print \$7} " ${ COOKIE } ) " -X GET \
2017-12-08 10:03:23 +01:00
" https:// ${ ALEXA } /api/np/queue?deviceSerialNumber= ${ DEVICESERIALNUMBER } &deviceType= ${ DEVICETYPE } "
echo
echo "/api/media/state"
2018-01-28 18:33:16 +01:00
${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2017-12-08 10:03:23 +01:00
-H "Content-Type: application/json; charset=UTF-8" -H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
2017-12-19 09:43:52 +01:00
-H " csrf: $( awk " \$0 ~/. ${ AMAZON } .*csrf[ \\s\\t]+/ {print \$7} " ${ COOKIE } ) " -X GET \
2017-12-08 10:03:23 +01:00
" https:// ${ ALEXA } /api/media/state?deviceSerialNumber= ${ DEVICESERIALNUMBER } &deviceType= ${ DEVICETYPE } "
echo
}
2019-08-25 17:48:35 +02:00
#
# show notifications and alarms
#
show_notifications( )
{
echo "/api/notifications"
${ 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/notifications?deviceSerialNumber= ${ DEVICESERIALNUMBER } &deviceType= ${ DEVICETYPE } "
echo
}
2017-12-08 10:03:23 +01:00
#
# deletes a multiroom device
#
delete_multiroom( )
{
2018-01-28 18:33:16 +01:00
${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2017-12-08 10:03:23 +01:00
-H "Content-Type: application/json; charset=UTF-8" -H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
2017-12-19 09:43:52 +01:00
-H " csrf: $( awk " \$0 ~/. ${ AMAZON } .*csrf[ \\s\\t]+/ {print \$7} " ${ COOKIE } ) " -X DELETE \
2017-12-08 10:03:23 +01:00
" 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 %, } ]} "
2018-01-28 18:33:16 +01:00
${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2017-12-08 10:03:23 +01:00
-H "Content-Type: application/json; charset=UTF-8" -H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
2017-12-19 09:43:52 +01:00
-H " csrf: $( awk " \$0 ~/. ${ AMAZON } .*csrf[ \\s\\t]+/ {print \$7} " ${ COOKIE } ) " -X POST -d " ${ JSON } " \
2017-12-08 10:03:23 +01:00
" https:// ${ ALEXA } /api/lemur/tail "
}
2018-01-10 08:24:36 +01:00
#
# list bluetooth devices
#
list_bluetooth( )
{
2018-01-28 18:33:16 +01:00
${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2018-01-10 08:24:36 +01:00
-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 "
}
2017-12-08 10:03:23 +01:00
#
# connect bluetooth device
#
connect_bluetooth( )
{
2018-01-28 18:33:16 +01:00
${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2017-12-08 10:03:23 +01:00
-H "Content-Type: application/json; charset=UTF-8" -H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
2017-12-19 09:43:52 +01:00
-H " csrf: $( awk " \$0 ~/. ${ AMAZON } .*csrf[ \\s\\t]+/ {print \$7} " ${ COOKIE } ) " -X POST -d " {\"bluetoothDeviceAddress\":\" ${ BLUETOOTH } \"} " \
2017-12-08 10:03:23 +01:00
" https:// ${ ALEXA } /api/bluetooth/pair-sink/ ${ DEVICETYPE } / ${ DEVICESERIALNUMBER } "
}
#
# disconnect bluetooth device
#
disconnect_bluetooth( )
{
2018-01-28 18:33:16 +01:00
${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2017-12-08 10:03:23 +01:00
-H "Content-Type: application/json; charset=UTF-8" -H " Referer: https://alexa. ${ AMAZON } /spa/index.html " -H " Origin: https://alexa. ${ AMAZON } " \
2017-12-19 09:43:52 +01:00
-H " csrf: $( awk " \$0 ~/. ${ AMAZON } .*csrf[ \\s\\t]+/ {print \$7} " ${ COOKIE } ) " -X POST \
2017-12-08 10:03:23 +01:00
" https:// ${ ALEXA } /api/bluetooth/disconnect-sink/ ${ DEVICETYPE } / ${ DEVICESERIALNUMBER } "
}
2018-03-01 22:35:22 +01:00
#
# device that sent the last command
# (by Markus Wennesheimer)
#
last_alexa( )
{
2020-07-07 23:32:47 +02:00
${ CURL } ${ OPTS } -s -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2018-03-01 22:35:22 +01:00
-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 " | sed -r 's/^.*serialNumber":"([^"]+)".*$/\1/'
}
2017-12-08 10:03:23 +01:00
#
# logout
#
log_off( )
{
2018-01-28 18:33:16 +01:00
${ CURL } ${ OPTS } -s -c ${ COOKIE } -b ${ COOKIE } -A " ${ BROWSER } " -H "DNT: 1" -H "Connection: keep-alive" -L\
2017-12-08 10:03:23 +01:00
https://${ ALEXA } /logout > /dev/null
rm -f ${ DEVLIST }
rm -f ${ DEVTXT }
2019-02-10 20:04:11 +01:00
rm -f ${ DEVALL }
2017-12-08 10:03:23 +01:00
rm -f ${ COOKIE }
}
2019-08-25 17:53:37 +02:00
if [ -z " $LASTALEXA " -a -z " $BLUETOOTH " -a -z " $LEMUR " -a -z " $PLIST " -a -z " $HIST " -a -z " $SEEDID " -a -z " $ASIN " -a -z " $QUEUE " -a -z " $NOTIFICATIONS " -a -z " $COMMAND " -a -z " $STATIONID " -a -z " $SONG " -a -n " $LOGOFF " ] ; then
2017-12-08 10:03:23 +01:00
echo "only logout option present, logging off ..."
log_off
exit 0
fi
if [ ! -f ${ COOKIE } ] ; then
2018-03-01 22:35:22 +01:00
echo "cookie does not exist. logging in ..."
2017-12-08 10:03:23 +01:00
log_in
fi
check_status
if [ $? -eq 0 ] ; then
echo "cookie expired, logging in again ..."
log_in
2018-01-10 08:24:36 +01:00
check_status
if [ $? -eq 0 ] ; then
echo "log in failed, aborting"
exit 1
fi
2017-12-08 10:03:23 +01:00
fi
2019-02-10 20:04:11 +01:00
if [ ! -f ${ DEVTXT } -o ! -f ${ DEVALL } ] ; then
2018-03-01 22:35:22 +01:00
echo "device list does not exist. downloading ..."
2017-12-20 18:55:59 +01:00
get_devlist
2018-01-10 08:24:36 +01:00
if [ ! -f ${ DEVTXT } ] ; then
echo "failed to download device list, aborting"
exit 1
fi
2017-12-20 18:55:59 +01:00
fi
2020-01-22 09:41:16 +01:00
if [ -n " $LOGIN " ] ; then
echo "logged in"
exit 0
fi
2020-01-08 21:34:53 +01:00
if [ -n " $COMMAND " -o -n " $QUEUE " -o -n " $NOTIFICATIONS " ] ; then
2019-02-10 20:04:11 +01:00
if [ " ${ DEVICE } " = "ALL" ] ; then
while IFS = read -r DEVICE ; do
set_var
2019-12-30 22:51:36 +01:00
if [ " $DEVICESTATE " = "true" ] ; then
if [ -n " $COMMAND " ] ; then
echo " sending cmd: ${ COMMAND } to dev: ${ DEVICE } type: ${ DEVICETYPE } serial: ${ DEVICESERIALNUMBER } customerid: ${ MEDIAOWNERCUSTOMERID } "
run_cmd
# in order to prevent a "Rate exceeded" we need to delay the command
sleep 1
echo
2020-01-08 21:34:53 +01:00
elif [ -n " $NOTIFICATIONS " ] ; then
echo " notifications info for dev: ${ DEVICE } type: ${ DEVICETYPE } serial: ${ DEVICESERIALNUMBER } "
show_notifications
2019-12-30 22:51:36 +01:00
else
echo " queue info for dev: ${ DEVICE } type: ${ DEVICETYPE } serial: ${ DEVICESERIALNUMBER } "
show_queue
echo
fi
2019-02-10 20:04:11 +01:00
fi
done < ${ DEVALL }
else
2019-02-11 00:14:48 +01:00
set_var
2019-02-10 20:04:11 +01:00
if [ -n " $COMMAND " ] ; then
echo " sending cmd: ${ COMMAND } to dev: ${ DEVICE } type: ${ DEVICETYPE } serial: ${ DEVICESERIALNUMBER } customerid: ${ MEDIAOWNERCUSTOMERID } "
run_cmd
2019-02-11 00:14:48 +01:00
echo
2020-01-08 21:34:53 +01:00
elif [ -n " $NOTIFICATIONS " ] ; then
echo " notifications info for dev: ${ DEVICE } type: ${ DEVICETYPE } serial: ${ DEVICESERIALNUMBER } "
show_notifications
2019-02-11 00:14:48 +01:00
else
echo " queue info for dev: ${ DEVICE } type: ${ DEVICETYPE } serial: ${ DEVICESERIALNUMBER } "
show_queue
echo
2019-02-10 20:04:11 +01:00
fi
2017-12-08 10:03:23 +01:00
fi
elif [ -n " $LEMUR " ] ; then
DEVICE = " ${ LEMUR } "
set_var
if [ -n " $DEVICESERIALNUMBER " ] ; then
delete_multiroom
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
2019-02-11 00:14:48 +01:00
echo
2017-12-08 10:03:23 +01:00
fi
rm -f ${ DEVLIST }
2019-02-10 20:04:11 +01:00
rm -f ${ DEVALL }
2017-12-08 10:03:23 +01:00
rm -f ${ DEVTXT }
get_devlist
elif [ -n " $BLUETOOTH " ] ; then
2019-02-10 20:04:11 +01:00
if [ " $BLUETOOTH " = "list" -o " $BLUETOOTH " = "List" -o " $BLUETOOTH " = "LIST" ] ; then
if [ " ${ DEVICE } " = "ALL" ] ; then
while IFS = read -r DEVICE ; do
set_var
echo "bluetooth api list:"
list_bluetooth
2019-02-11 00:14:48 +01:00
echo
2019-02-10 20:04:11 +01:00
done < ${ DEVALL }
else
set_var
echo "bluetooth api list:"
list_bluetooth
2019-02-11 00:14:48 +01:00
echo
2019-02-10 20:04:11 +01:00
fi
elif [ " $BLUETOOTH " = "null" ] ; then
set_var
2017-12-08 10:03:23 +01:00
echo " disconnecting dev: ${ DEVICE } type: ${ DEVICETYPE } serial: ${ DEVICESERIALNUMBER } from bluetooth "
disconnect_bluetooth
2019-02-11 00:14:48 +01:00
echo
2017-12-08 10:03:23 +01:00
else
2019-02-10 20:04:11 +01:00
set_var
2017-12-08 10:03:23 +01:00
echo " connecting dev: ${ DEVICE } type: ${ DEVICETYPE } serial: ${ DEVICESERIALNUMBER } to bluetooth device: ${ BLUETOOTH } "
connect_bluetooth
2019-02-11 00:14:48 +01:00
echo
2017-12-08 10:03:23 +01:00
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 " $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 " $LIST " ] ; then
ATTR = "accountName"
echo "the following devices exist in your account:"
grep ${ ATTR } \| ${ DEVTXT } | sed " s/^.* ${ ATTR } |// " | sed 's/ /_/g'
2018-03-01 22:35:22 +01:00
elif [ -n " $LASTALEXA " ] ; then
last_alexa
2017-12-08 10:03:23 +01:00
else
echo "no alexa command received"
fi
if [ -n " $LOGOFF " ] ; then
echo "logout option present, logging off ..."
log_off
fi