alexa_remotectl 0.2.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bfe02b279946e6fa20e4615f417bbfa52e8128987b630338ae08d86d3e82374e
4
- data.tar.gz: f8be3e2e607a59f7592a36810455ae49383750f1e8755cb7fab28edbf83ba219
3
+ metadata.gz: 9b1f56f3518e257c26d3d00ac9e63dde021474827abb5461fdb11114f95196a2
4
+ data.tar.gz: 3dbe1a051f41b9b11f77e0f82c392f90c72d23ee4ba0314cc6ebc3c0deb31adc
5
5
  SHA512:
6
- metadata.gz: add9df3f63dc5f001ce55703de6e7b579ce646bf713a40a541843eca6ca6fc752a03209209f15c3cdc714bc5a066477381f2f746e6d0d1608c096e9cfcf35973
7
- data.tar.gz: 00a8dc58950293d74b42b924c83e4fadfea64f4a70eff6a42489c0d2b8048deac4e76ede59f4c6da594355a44a9c70c3dfe1a5d0f2ea07ebe8a08582713bd04f
6
+ metadata.gz: ff774816c05f4c379b0563f83ff5b9036161c58975438898723d2460aadbb29fe554fa6b84f6c5c12208fb1e375ccdaccac5d006944b7262c321c9a5b4abe724
7
+ data.tar.gz: 236d52c95e7421ee51af2d425523ddb85d193290398b4886bfae7c718a8e16f6b1450a316301dc8a077ba0436d59ecb2b7faa301041865ff179505a3001c3594
checksums.yaml.gz.sig CHANGED
@@ -1 +1,2 @@
1
- j^�II6��QrI㎞�_T ���� �<���c���8$�j���p&KFFD<'247��_��i��di���[S�F�}��k�:a'0E�ݹ�o��di�_ ��<Y',���O�E��Z�bw�ݺ �2�م�2`b��9XXw��f��^`4E���^!P���`�0"�.U��|��x6�,��J5���Ⲍ'N|Q
1
+ t$45Y!%=�zo����V�[�X&�F ǡ�wh)���aU%��Sdd(C�߅�/�k�b�r�x�&�J]r��c9k��h)/E� Jz�?4���w_Kc� �h�.+�S�W��/O�8��G���q��XR����%�#yz=2�wg����lJ4~jVO7YxSFH`�����v�Z��X�&r��%�~�J��t/�
2
+ �@\x=M�� �/���,�۶�L�^�� yz*�p ���q��{����9S�����ժ{��*A���V�q�K��?��)�*�*�oR+Pm[{޼!.Aⓡ��7�S��|�%�F ~�q�8p}������+�E�}�Zn������_/�a �}5���?��y�Kt����-���(Z7;>�O
@@ -8,6 +8,7 @@
8
8
  require 'net/http'
9
9
  require 'uri'
10
10
  require 'clipboard'
11
+ require 'json'
11
12
 
12
13
  # Use the CodeWizard with the cURL command you've copied using Developer
13
14
  # tools on Alexa's SPA page (within the web browser).
@@ -57,44 +58,173 @@ end
57
58
 
58
59
  class AlexaRemoteCtl
59
60
 
60
- def initialize(domain: 'alexa.amazon.co.uk', device: {}, cookie: '')
61
+ def initialize(domain: 'alexa.amazon.co.uk', device: {}, cookie: '',
62
+ customerid: '')
61
63
 
62
- @domain, @device, @cookie = domain, device, cookie
64
+ @domain, @device, @cookie, @customerid = domain, device, cookie, customerid
63
65
 
64
66
  end
65
67
 
68
+ def info()
69
+ device_player()[:playerInfo]
70
+ end
71
+
72
+ def list_ebooks()
73
+ get_json '/api/ebooks/library', "mediaOwnerCustomerId=#{@customerid}" +
74
+ "&nextToken=&size=50"
75
+ end
76
+
77
+ def mute?()
78
+ info()[:volume][:muted]
79
+ end
80
+
81
+ alias muted? mute?
82
+
83
+ # skip to the next music track
84
+ def next
85
+ pp_cmd('Next')
86
+ end
87
+
66
88
  def pause
67
- device_cmd('Pause')
89
+ pp_cmd('Pause')
68
90
  end
69
91
 
70
92
  def play
71
- device_cmd('Play')
93
+ pp_cmd('Play')
94
+ end
95
+
96
+ def play_ebook(id)
97
+
98
+ serialno = @device[:serialno]
99
+ type = @device[:type]
100
+
101
+ url = "https://#{@domain}/api/ebooks/queue-and-play?"
102
+
103
+ body = {
104
+ 'asin' => id,
105
+ 'deviceType' => type,
106
+ 'deviceSerialNumber' => serialno,
107
+ 'mediaOwnerCustomerId' => @customerid
108
+ }.to_json
109
+
110
+ post_request url, body
111
+
112
+ end
113
+
114
+ def play_hq(id)
115
+ device_phq(id)
116
+ end
117
+
118
+ def playing?()
119
+ info()[:state] == 'PLAYING'
120
+ end
121
+
122
+ # Artist name
123
+ #
124
+ def text1()
125
+ info()[:infoText][:subText1]
126
+ end
127
+
128
+ # music station
129
+ #
130
+ def text2()
131
+ info()[:infoText][:subText2]
132
+ end
133
+
134
+ # music track title
135
+ #
136
+ def title()
137
+ info()[:infoText][:title]
138
+ end
139
+
140
+ def vol()
141
+ info()[:volume][:volume]
142
+ end
143
+
144
+ def vol=(n)
145
+
146
+ return unless n.between? 0, 40
147
+
148
+ body = '{"type":"VolumeLevelCommand","volumeLevel":' + n.to_s \
149
+ + ',"contentFocusClientId":null}'
150
+ device_cmd(body)
72
151
  end
73
152
 
74
153
  private
75
154
 
76
- def device_cmd(cmd)
155
+ # play, pause, or next
156
+ #
157
+ def pp_cmd(s)
158
+ body = '{"type":"' + s + 'Command","contentFocusClientId":null}'
159
+ device_cmd body
160
+ end
161
+
162
+ def device_cmd(body)
77
163
 
78
164
  serialno = @device[:serialno]
79
165
  type = @device[:type]
80
166
 
81
- url = "https://#{@domain}/api/np/command?deviceSerialNumber=#{serialno}&deviceType=#{type}"
82
- uri = URI.parse(url)
83
- request = Net::HTTP::Post.new(uri)
84
- request.body = '{"type":"' + cmd + 'Command","contentFocusClientId":null}'
85
- request.content_type = "application/x-www-form-urlencoded; charset=UTF-8"
167
+ url = "https://#{@domain}/api/np/command?deviceSerial" +
168
+ "Number=#{serialno}&deviceType=#{type}"
169
+ post_command url, body
170
+
171
+ end
172
+
173
+ # play historical queue (PHQ)
174
+ #
175
+ def device_phq(queueid)
176
+
177
+ serialno = @device[:serialno]
178
+ type = @device[:type]
179
+
180
+ url = "https://#{@domain}/api/media/play-historical-queue"
181
+
182
+ body = {
183
+ 'deviceType' => type,
184
+ 'deviceSerialNumber' => serialno,
185
+ 'queueId' => queueid,
186
+ 'startTime' => nil,
187
+ 'service' => nil,
188
+ 'trackSource' => nil,
189
+ 'mediaOwnerCustomerId' => @customerid
190
+ }.to_json
191
+
192
+ post_request url, body
193
+
194
+ end
195
+
196
+ def device_player()
197
+ get_json '/api/np/player'
198
+ end
199
+
200
+ def get_json(uri, params='')
201
+
202
+ serialno = @device[:serialno]
203
+ type = @device[:type]
204
+
205
+ url = "https://#{@domain}#{uri}?deviceSerial" +
206
+ "Number=#{serialno}&deviceType=#{type}"
207
+ url += '&' + params if params.length > 1
208
+
209
+ r = get_request url
210
+ JSON.parse(r.body, symbolize_names: true)
211
+
212
+ end
213
+
214
+ def make_response(uri, request)
86
215
 
87
216
  request["Accept"] = "application/json, text/javascript, */*; q=0.01"
88
217
  request["Accept-Language"] = "en-GB,en-US;q=0.9,en;q=0.8"
89
218
  request["Connection"] = "keep-alive"
90
- request["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8"
91
219
  request["Cookie"] = @cookie
92
- request["Origin"] = "https://" + @domain
220
+
93
221
  request["Referer"] = "https://#{@domain}/spa/index.html"
94
222
  request["Sec-Fetch-Dest"] = "empty"
95
223
  request["Sec-Fetch-Mode"] = "cors"
96
224
  request["Sec-Fetch-Site"] = "same-origin"
97
- request["User-Agent"] = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36"
225
+ request["User-Agent"] = "Mozilla/5.0 (X11; Linux x86_64) " +
226
+ "AppleWebKit/537.36 (KHTML, like Gecko) " +
227
+ "Chrome/101.0.4951.64 Safari/537.36"
98
228
  request["X-Requested-With"] = "XMLHttpRequest"
99
229
  request["csrf"] = "-990908140"
100
230
  request["dnt"] = "1"
@@ -110,8 +240,118 @@ class AlexaRemoteCtl
110
240
  http.request(request)
111
241
  end
112
242
 
243
+ end
244
+
245
+ def post_command(url, body='')
246
+
247
+ uri = URI.parse(url)
248
+ request = Net::HTTP::Post.new(uri)
249
+ request.body = body
250
+ request.content_type = "application/x-www-form-urlencoded; charset=UTF-8"
251
+ request["Origin"] = "https://" + @domain
252
+
253
+ response = make_response(uri, request)
254
+
255
+ # response.code
256
+ # response.body
257
+ end
258
+
259
+ def get_request(url)
260
+
261
+ uri = URI.parse(url)
262
+ request = Net::HTTP::Get.new(uri)
263
+ response = make_response(uri, request)
264
+
113
265
  # response.code
114
266
  # response.body
115
267
 
116
268
  end
269
+
270
+
271
+ def post_request(url, body='')
272
+
273
+ uri = URI.parse(url)
274
+ request = Net::HTTP::Post.new(uri)
275
+ request.body = body
276
+ response = make_response(uri, request)
277
+
278
+ # response.code
279
+ # response.body
280
+
281
+ end
282
+
283
+ end
284
+
285
+ class AlexaDevices
286
+
287
+ # devices = [[{*serialno*, *type*}, label], ...]
288
+ # note: label can be any identifier you choose e.g. kitchen
289
+ #
290
+ def initialize(devicesx=[], devices: devicesx,
291
+ domain: 'alexa.amazon.co.uk', cookie: '', customerid: '')
292
+
293
+ @devices, @domain, @cookie = devices, domain, cookie
294
+ @customerid = customerid
295
+
296
+ end
297
+
298
+ def playing()
299
+
300
+ @devices.map do |device, label|
301
+ alexa = get_alexa device
302
+ alexa.playing? ? [alexa, label] : nil
303
+ end.compact
304
+
305
+ end
306
+
307
+ def pause(id=nil)
308
+
309
+ a = playing()
310
+
311
+ if id then
312
+
313
+ alexa, _ = a.find {|_, label| label.to_sym == id.to_sym}
314
+ alexa.pause
315
+
316
+ else
317
+
318
+ a.each do |alexa, label|
319
+ puts 'Pausing @' + label.inspect
320
+ alexa.pause
321
+ end
322
+
323
+ end
324
+ end
325
+
326
+ def play(id=nil)
327
+
328
+ a = @devices
329
+
330
+ if id then
331
+
332
+ device, _ = a.find {|_, label| label.to_sym == id.to_sym}
333
+ alexa = get_alexa device
334
+ alexa.play
335
+
336
+ else
337
+
338
+ a.each do |device, label|
339
+
340
+ puts 'Pausing @' + label.inspect
341
+ alexa = get_alexa device
342
+ alexa.play
343
+
344
+ end
345
+
346
+ end
347
+ end
348
+
349
+ private
350
+
351
+ def get_alexa(device)
352
+
353
+ AlexaRemoteCtl.new(cookie: @cookie, device: device,
354
+ customerid: @customerid)
355
+ end
356
+
117
357
  end
data.tar.gz.sig CHANGED
Binary file
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.2.0
4
+ version: 0.4.1
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-18 00:00:00.000000000 Z
38
+ date: 2022-05-22 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: clipboard
metadata.gz.sig CHANGED
Binary file