alexa_remotectl 0.4.0 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/alexa_remotectl.rb +154 -38
- data.tar.gz.sig +3 -2
- metadata +2 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3390f693c5318ae22b5c79fbe464dacd839ef331c4d3f2a07e9aeed38229be2
|
4
|
+
data.tar.gz: adb89f569f0f47f88304c5032b963e171c556d340f928dd70de0437318c9b09f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 874e773c33e46ab1843c655ba49f138ffff68f9ef7a088cf550f5791c3e6fa567545f1e1a8fab52083b860c3c512ffdebd86f312059c2fc9d1e5def5a9881539
|
7
|
+
data.tar.gz: f0f91e9861f1cd68e3d2494341f6bbc28f2d482d5766b124b66f65e9cab60fa34d03f199516bc1f75936320e620096f40d9b33c9a98dfb2991575529c1736bbe
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/lib/alexa_remotectl.rb
CHANGED
@@ -22,14 +22,15 @@ class CodeWizard
|
|
22
22
|
|
23
23
|
return 'no curl command found' unless s =~ /curl/
|
24
24
|
|
25
|
-
cookie, serialno, type = parse(s)
|
25
|
+
cookie, csrf, serialno, type = parse(s)
|
26
26
|
|
27
27
|
@s =<<EOF
|
28
28
|
require 'alexa_remotectl'
|
29
29
|
|
30
30
|
cookie = '#{cookie}'
|
31
|
+
csrf = '#{csrf}'
|
31
32
|
device = {serialno: '#{serialno}', type: '#{type}'}
|
32
|
-
alexa = AlexaRemoteCtl.new(cookie: cookie, device: device)
|
33
|
+
alexa = AlexaRemoteCtl.new(cookie: cookie, csrf: csrf, device: device)
|
33
34
|
alexa.pause
|
34
35
|
#alexa.play
|
35
36
|
EOF
|
@@ -50,17 +51,22 @@ EOF
|
|
50
51
|
serialno = s[/deviceSerialNumber=(\w+)/,1]
|
51
52
|
type = s[/deviceType=(\w+)/,1]
|
52
53
|
cookie = s[/Cookie: ([^']+)/,1]
|
54
|
+
csrf = s[/csrf: ([^']+)/,1]
|
53
55
|
|
54
|
-
[cookie, serialno, type]
|
56
|
+
[cookie, csrf, serialno, type]
|
55
57
|
|
56
58
|
end
|
57
59
|
end
|
58
60
|
|
59
61
|
class AlexaRemoteCtl
|
60
62
|
|
61
|
-
|
63
|
+
# note: Added the Cross-site request forgery (crsf) variable
|
64
|
+
#
|
65
|
+
def initialize(domain: 'alexa.amazon.co.uk', device: {}, cookie: '',
|
66
|
+
customerid: '', csrf: '')
|
62
67
|
|
63
|
-
@domain, @device, @cookie = domain, device, cookie
|
68
|
+
@domain, @device, @cookie, @customerid = domain, device, cookie, customerid
|
69
|
+
@csrf = csrf
|
64
70
|
|
65
71
|
end
|
66
72
|
|
@@ -68,6 +74,17 @@ class AlexaRemoteCtl
|
|
68
74
|
device_player()[:playerInfo]
|
69
75
|
end
|
70
76
|
|
77
|
+
def list_ebooks()
|
78
|
+
get_json '/api/ebooks/library', "mediaOwnerCustomerId=#{@customerid}" +
|
79
|
+
"&nextToken=&size=50"
|
80
|
+
end
|
81
|
+
|
82
|
+
# list historical queue (hq)
|
83
|
+
#
|
84
|
+
def list_hq()
|
85
|
+
get_json '/api/media/historical-queue', "size=50&offset=-1"
|
86
|
+
end
|
87
|
+
|
71
88
|
def mute?()
|
72
89
|
info()[:volume][:muted]
|
73
90
|
end
|
@@ -87,6 +104,31 @@ class AlexaRemoteCtl
|
|
87
104
|
pp_cmd('Play')
|
88
105
|
end
|
89
106
|
|
107
|
+
def play_ebook(id)
|
108
|
+
|
109
|
+
serialno = @device[:serialno]
|
110
|
+
type = @device[:type]
|
111
|
+
|
112
|
+
url = "https://#{@domain}/api/ebooks/queue-and-play?"
|
113
|
+
|
114
|
+
body = {
|
115
|
+
'asin' => id,
|
116
|
+
'deviceType' => type,
|
117
|
+
'deviceSerialNumber' => serialno,
|
118
|
+
'mediaOwnerCustomerId' => @customerid
|
119
|
+
}.to_json
|
120
|
+
|
121
|
+
post_request url, body
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
# play historical queue
|
126
|
+
# note: You can find the queueid from an entry in the list_hq() result
|
127
|
+
#
|
128
|
+
def play_hq(queueid)
|
129
|
+
device_phq(queueid)
|
130
|
+
end
|
131
|
+
|
90
132
|
def playing?()
|
91
133
|
info()[:state] == 'PLAYING'
|
92
134
|
end
|
@@ -136,18 +178,51 @@ class AlexaRemoteCtl
|
|
136
178
|
serialno = @device[:serialno]
|
137
179
|
type = @device[:type]
|
138
180
|
|
139
|
-
url = "https://#{@domain}/api/np/command?
|
181
|
+
url = "https://#{@domain}/api/np/command?deviceSerial" +
|
182
|
+
"Number=#{serialno}&deviceType=#{type}"
|
140
183
|
post_command url, body
|
141
184
|
|
142
185
|
end
|
143
186
|
|
187
|
+
# play historical queue (PHQ)
|
188
|
+
#
|
189
|
+
def device_phq(queueid)
|
190
|
+
|
191
|
+
serialno = @device[:serialno]
|
192
|
+
type = @device[:type]
|
193
|
+
|
194
|
+
url = "https://#{@domain}/api/media/play-historical-queue"
|
195
|
+
|
196
|
+
body = {
|
197
|
+
'deviceType' => type,
|
198
|
+
'deviceSerialNumber' => serialno,
|
199
|
+
'queueId' => queueid,
|
200
|
+
'startTime' => nil,
|
201
|
+
'service' => nil,
|
202
|
+
'trackSource' => nil,
|
203
|
+
'mediaOwnerCustomerId' => @customerid
|
204
|
+
}.to_json
|
205
|
+
|
206
|
+
post_request url, body
|
207
|
+
|
208
|
+
end
|
209
|
+
|
144
210
|
def device_player()
|
211
|
+
get_json '/api/np/player'
|
212
|
+
end
|
213
|
+
|
214
|
+
def get_json(uri, params='')
|
215
|
+
|
145
216
|
serialno = @device[:serialno]
|
146
217
|
type = @device[:type]
|
147
218
|
|
148
|
-
url = "https://#{@domain}
|
149
|
-
|
219
|
+
url = "https://#{@domain}#{uri}?deviceSerial" +
|
220
|
+
"Number=#{serialno}&deviceType=#{type}"
|
221
|
+
url += '&' + params if params.length > 1
|
222
|
+
|
223
|
+
r = get_request url
|
150
224
|
JSON.parse(r.body, symbolize_names: true)
|
225
|
+
|
151
226
|
end
|
152
227
|
|
153
228
|
def make_response(uri, request)
|
@@ -155,16 +230,17 @@ class AlexaRemoteCtl
|
|
155
230
|
request["Accept"] = "application/json, text/javascript, */*; q=0.01"
|
156
231
|
request["Accept-Language"] = "en-GB,en-US;q=0.9,en;q=0.8"
|
157
232
|
request["Connection"] = "keep-alive"
|
158
|
-
request["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8"
|
159
233
|
request["Cookie"] = @cookie
|
160
234
|
|
161
235
|
request["Referer"] = "https://#{@domain}/spa/index.html"
|
162
236
|
request["Sec-Fetch-Dest"] = "empty"
|
163
237
|
request["Sec-Fetch-Mode"] = "cors"
|
164
238
|
request["Sec-Fetch-Site"] = "same-origin"
|
165
|
-
request["User-Agent"] = "Mozilla/5.0 (X11; Linux x86_64)
|
239
|
+
request["User-Agent"] = "Mozilla/5.0 (X11; Linux x86_64) " +
|
240
|
+
"AppleWebKit/537.36 (KHTML, like Gecko) " +
|
241
|
+
"Chrome/101.0.4951.64 Safari/537.36"
|
166
242
|
request["X-Requested-With"] = "XMLHttpRequest"
|
167
|
-
request["csrf"] =
|
243
|
+
request["csrf"] = @csrf
|
168
244
|
request["dnt"] = "1"
|
169
245
|
request["sec-ch-ua"] = "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"101\""
|
170
246
|
request["sec-ch-ua-mobile"] = "?0"
|
@@ -181,6 +257,7 @@ class AlexaRemoteCtl
|
|
181
257
|
end
|
182
258
|
|
183
259
|
def post_command(url, body='')
|
260
|
+
|
184
261
|
uri = URI.parse(url)
|
185
262
|
request = Net::HTTP::Post.new(uri)
|
186
263
|
request.body = body
|
@@ -193,7 +270,7 @@ class AlexaRemoteCtl
|
|
193
270
|
# response.body
|
194
271
|
end
|
195
272
|
|
196
|
-
def
|
273
|
+
def get_request(url)
|
197
274
|
|
198
275
|
uri = URI.parse(url)
|
199
276
|
request = Net::HTTP::Get.new(uri)
|
@@ -204,6 +281,19 @@ class AlexaRemoteCtl
|
|
204
281
|
|
205
282
|
end
|
206
283
|
|
284
|
+
|
285
|
+
def post_request(url, body='')
|
286
|
+
|
287
|
+
uri = URI.parse(url)
|
288
|
+
request = Net::HTTP::Post.new(uri)
|
289
|
+
request.body = body
|
290
|
+
response = make_response(uri, request)
|
291
|
+
|
292
|
+
# response.code
|
293
|
+
# response.body
|
294
|
+
|
295
|
+
end
|
296
|
+
|
207
297
|
end
|
208
298
|
|
209
299
|
class AlexaDevices
|
@@ -212,59 +302,85 @@ class AlexaDevices
|
|
212
302
|
# note: label can be any identifier you choose e.g. kitchen
|
213
303
|
#
|
214
304
|
def initialize(devicesx=[], devices: devicesx,
|
215
|
-
domain: 'alexa.amazon.co.uk', cookie: ''
|
305
|
+
domain: 'alexa.amazon.co.uk', cookie: '', customerid: '',
|
306
|
+
csrf: '', debug: false)
|
216
307
|
|
217
308
|
@devices, @domain, @cookie = devices, domain, cookie
|
309
|
+
@customerid, @csrf, @debug = customerid, csrf, debug
|
218
310
|
|
219
311
|
end
|
220
312
|
|
313
|
+
def info(id=nil) invoke(:info, id) end
|
314
|
+
def list_ebooks(id) invoke(:list_ebooks, id) end
|
315
|
+
def list_hq(id=nil) invoke(:list_hq, id) end
|
316
|
+
def mute?(id=nil) invoke2(:mute?, id) end
|
317
|
+
def next(id) invoke2(:next, id) end
|
318
|
+
|
221
319
|
def playing()
|
222
320
|
|
223
|
-
@devices.map do |device, label|
|
224
|
-
alexa = AlexaRemoteCtl.new(cookie: @cookie, device: device)
|
225
|
-
alexa.playing? ? [alexa, label] : nil
|
226
|
-
end.compact
|
321
|
+
devices = @devices.map do |device, label|
|
227
322
|
|
228
|
-
|
323
|
+
puts 'label: ' + label.inspect if @debug
|
324
|
+
puts 'device: ' + device.inspect if @debug
|
229
325
|
|
230
|
-
|
326
|
+
alexa = get_alexa device
|
327
|
+
alexa.playing? ? [alexa, label] : nil
|
231
328
|
|
232
|
-
|
329
|
+
end.compact
|
233
330
|
|
234
|
-
if
|
331
|
+
puts 'devices: ' + devices.inspect if @debug
|
332
|
+
return devices
|
235
333
|
|
236
|
-
|
237
|
-
alexa.pause
|
334
|
+
end
|
238
335
|
|
239
|
-
|
336
|
+
def pause(id=nil) invoke2(:pause, id) end
|
337
|
+
def play(id) invoke(:play, id) end
|
338
|
+
def play_ebook(id) invoke(:list_hq, id) end
|
339
|
+
def play_hq(id,qid) invoke(:play_hq, id, qid) end
|
340
|
+
def playing?(id=nil) invoke(:playing, id) end
|
341
|
+
def text1(id=nil) invoke2(:text1, id) end
|
342
|
+
def text2(id=nil) invoke2(:text2, id) end
|
343
|
+
def title(id=nil) invoke2(:title, id) end
|
344
|
+
def vol(id=nil) invoke(:vol, id) end
|
345
|
+
def vol=(id=nil) invoke(:vol=, id) end
|
240
346
|
|
241
|
-
|
242
|
-
puts 'Pausing @' + label.inspect
|
243
|
-
alexa.pause
|
244
|
-
end
|
347
|
+
private
|
245
348
|
|
246
|
-
|
247
|
-
end
|
349
|
+
def get_alexa(device)
|
248
350
|
|
249
|
-
|
351
|
+
AlexaRemoteCtl.new(cookie: @cookie, device: device,
|
352
|
+
customerid: @customerid, csrf: @csrf)
|
353
|
+
end
|
250
354
|
|
251
|
-
|
355
|
+
def apply_cmd(a, cmd, id, args)
|
252
356
|
|
253
357
|
if id then
|
254
358
|
|
255
359
|
device, _ = a.find {|_, label| label.to_sym == id.to_sym}
|
256
|
-
alexa =
|
257
|
-
alexa.
|
360
|
+
alexa = get_alexa device
|
361
|
+
alexa.method(cmd).call(*args)
|
258
362
|
|
259
363
|
else
|
260
364
|
|
261
|
-
a.
|
262
|
-
|
263
|
-
|
264
|
-
alexa
|
365
|
+
a.map do |device, label|
|
366
|
+
|
367
|
+
puts cmd.to_s + ' @' + label.inspect
|
368
|
+
alexa = get_alexa device
|
369
|
+
alexa.method(cmd).call(*args)
|
370
|
+
|
265
371
|
end
|
266
372
|
|
267
373
|
end
|
268
374
|
end
|
269
375
|
|
376
|
+
def invoke(cmd, id, *args)
|
377
|
+
apply_cmd(@devices, cmd, id, args)
|
378
|
+
end
|
379
|
+
|
380
|
+
# apply command to an Alexa device which is currently playing
|
381
|
+
#
|
382
|
+
def invoke2(cmd, id, *args)
|
383
|
+
apply_cmd(playing(), cmd, id, args)
|
384
|
+
end
|
385
|
+
|
270
386
|
end
|
data.tar.gz.sig
CHANGED
@@ -1,2 +1,3 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
:�c>j<�;Iy6A�-=�i)�+4��b�
|
2
|
+
�"M�b�*��+�jM`|����L_WM�+ѫ�5�GX�T�E>u�T�ehK�[oO�P�ф�^e�)�MƢฮ�$����k�I�9�~b��Ӭ*�Ȩ+�22��,GA-��*ϑ`�[V��8�3ݽ�snf�՜L
|
3
|
+
�
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alexa_remotectl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Robertson
|
@@ -35,7 +35,7 @@ cert_chain:
|
|
35
35
|
d/gEwBtUmduwWZNX2NOJehf8s1cnH9OBP7s1ziHjdkZCgkQm3QewRRcdfZeYwFi6
|
36
36
|
4kVEcApgAgd+04ctE6uiRn5o
|
37
37
|
-----END CERTIFICATE-----
|
38
|
-
date: 2022-05-
|
38
|
+
date: 2022-05-23 00:00:00.000000000 Z
|
39
39
|
dependencies:
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: clipboard
|
metadata.gz.sig
CHANGED
Binary file
|