alexa_remotectl 0.1.0 → 0.4.0
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 +207 -8
- data.tar.gz.sig +2 -2
- metadata +23 -3
- metadata.gz.sig +2 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d3641c9d28ab824390ab0dc3aebec594eb204fdb0d09f8536ded7a7efd541e62
|
4
|
+
data.tar.gz: 8afb412ab356140e1289d1df7b49487bbc72e2b0d0593f43106f32dc8e643683
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7bf863c6ae5e8d4426a32d0b57b0c763aaff8534a0bc379eb3a30e0aaaebb564317d6463b4ab0025133d8b720721315a10c7dc00473c70bb79f4567d1961d1d9
|
7
|
+
data.tar.gz: eb8b72c82327e56afc915dbe0ed2400a05db3ea061c5ae478e61b9cfc7f8e36e3f0f0c4b73908a97e45280f618bab40a9645a7d6f02429bc8f7400675d92e0f1
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/lib/alexa_remotectl.rb
CHANGED
@@ -7,7 +7,54 @@
|
|
7
7
|
|
8
8
|
require 'net/http'
|
9
9
|
require 'uri'
|
10
|
+
require 'clipboard'
|
11
|
+
require 'json'
|
10
12
|
|
13
|
+
# Use the CodeWizard with the cURL command you've copied using Developer
|
14
|
+
# tools on Alexa's SPA page (within the web browser).
|
15
|
+
#
|
16
|
+
# note: to find the correct url to convert, try clickin on pause or play to
|
17
|
+
# invoke an AJAX request
|
18
|
+
|
19
|
+
class CodeWizard
|
20
|
+
|
21
|
+
def initialize(s='')
|
22
|
+
|
23
|
+
return 'no curl command found' unless s =~ /curl/
|
24
|
+
|
25
|
+
cookie, serialno, type = parse(s)
|
26
|
+
|
27
|
+
@s =<<EOF
|
28
|
+
require 'alexa_remotectl'
|
29
|
+
|
30
|
+
cookie = '#{cookie}'
|
31
|
+
device = {serialno: '#{serialno}', type: '#{type}'}
|
32
|
+
alexa = AlexaRemoteCtl.new(cookie: cookie, device: device)
|
33
|
+
alexa.pause
|
34
|
+
#alexa.play
|
35
|
+
EOF
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s()
|
40
|
+
Clipboard.copy @s
|
41
|
+
puts 'copied to clipboard'
|
42
|
+
|
43
|
+
@s
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def parse(s)
|
49
|
+
|
50
|
+
serialno = s[/deviceSerialNumber=(\w+)/,1]
|
51
|
+
type = s[/deviceType=(\w+)/,1]
|
52
|
+
cookie = s[/Cookie: ([^']+)/,1]
|
53
|
+
|
54
|
+
[cookie, serialno, type]
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
11
58
|
|
12
59
|
class AlexaRemoteCtl
|
13
60
|
|
@@ -17,33 +64,100 @@ class AlexaRemoteCtl
|
|
17
64
|
|
18
65
|
end
|
19
66
|
|
67
|
+
def info()
|
68
|
+
device_player()[:playerInfo]
|
69
|
+
end
|
70
|
+
|
71
|
+
def mute?()
|
72
|
+
info()[:volume][:muted]
|
73
|
+
end
|
74
|
+
|
75
|
+
alias muted? mute?
|
76
|
+
|
77
|
+
# skip to the next music track
|
78
|
+
def next
|
79
|
+
pp_cmd('Next')
|
80
|
+
end
|
81
|
+
|
20
82
|
def pause
|
21
|
-
|
83
|
+
pp_cmd('Pause')
|
22
84
|
end
|
23
85
|
|
24
86
|
def play
|
25
|
-
|
87
|
+
pp_cmd('Play')
|
88
|
+
end
|
89
|
+
|
90
|
+
def playing?()
|
91
|
+
info()[:state] == 'PLAYING'
|
92
|
+
end
|
93
|
+
|
94
|
+
# Artist name
|
95
|
+
#
|
96
|
+
def text1()
|
97
|
+
info()[:infoText][:subText1]
|
98
|
+
end
|
99
|
+
|
100
|
+
# music station
|
101
|
+
#
|
102
|
+
def text2()
|
103
|
+
info()[:infoText][:subText2]
|
104
|
+
end
|
105
|
+
|
106
|
+
# music track title
|
107
|
+
#
|
108
|
+
def title()
|
109
|
+
info()[:infoText][:title]
|
110
|
+
end
|
111
|
+
|
112
|
+
def vol()
|
113
|
+
info()[:volume][:volume]
|
114
|
+
end
|
115
|
+
|
116
|
+
def vol=(n)
|
117
|
+
|
118
|
+
return unless n.between? 0, 40
|
119
|
+
|
120
|
+
body = '{"type":"VolumeLevelCommand","volumeLevel":' + n.to_s \
|
121
|
+
+ ',"contentFocusClientId":null}'
|
122
|
+
device_cmd(body)
|
26
123
|
end
|
27
124
|
|
28
125
|
private
|
29
126
|
|
30
|
-
|
127
|
+
# play, pause, or next
|
128
|
+
#
|
129
|
+
def pp_cmd(s)
|
130
|
+
body = '{"type":"' + s + 'Command","contentFocusClientId":null}'
|
131
|
+
device_cmd body
|
132
|
+
end
|
133
|
+
|
134
|
+
def device_cmd(body)
|
31
135
|
|
32
136
|
serialno = @device[:serialno]
|
33
137
|
type = @device[:type]
|
34
138
|
|
35
139
|
url = "https://#{@domain}/api/np/command?deviceSerialNumber=#{serialno}&deviceType=#{type}"
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
140
|
+
post_command url, body
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
def device_player()
|
145
|
+
serialno = @device[:serialno]
|
146
|
+
type = @device[:type]
|
147
|
+
|
148
|
+
url = "https://#{@domain}/api/np/player?deviceSerialNumber=#{serialno}&deviceType=#{type}"
|
149
|
+
r = post_request url
|
150
|
+
JSON.parse(r.body, symbolize_names: true)
|
151
|
+
end
|
152
|
+
|
153
|
+
def make_response(uri, request)
|
40
154
|
|
41
155
|
request["Accept"] = "application/json, text/javascript, */*; q=0.01"
|
42
156
|
request["Accept-Language"] = "en-GB,en-US;q=0.9,en;q=0.8"
|
43
157
|
request["Connection"] = "keep-alive"
|
44
158
|
request["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8"
|
45
159
|
request["Cookie"] = @cookie
|
46
|
-
|
160
|
+
|
47
161
|
request["Referer"] = "https://#{@domain}/spa/index.html"
|
48
162
|
request["Sec-Fetch-Dest"] = "empty"
|
49
163
|
request["Sec-Fetch-Mode"] = "cors"
|
@@ -64,8 +178,93 @@ class AlexaRemoteCtl
|
|
64
178
|
http.request(request)
|
65
179
|
end
|
66
180
|
|
181
|
+
end
|
182
|
+
|
183
|
+
def post_command(url, body='')
|
184
|
+
uri = URI.parse(url)
|
185
|
+
request = Net::HTTP::Post.new(uri)
|
186
|
+
request.body = body
|
187
|
+
request.content_type = "application/x-www-form-urlencoded; charset=UTF-8"
|
188
|
+
request["Origin"] = "https://" + @domain
|
189
|
+
|
190
|
+
response = make_response(uri, request)
|
191
|
+
|
67
192
|
# response.code
|
68
193
|
# response.body
|
194
|
+
end
|
195
|
+
|
196
|
+
def post_request(url)
|
197
|
+
|
198
|
+
uri = URI.parse(url)
|
199
|
+
request = Net::HTTP::Get.new(uri)
|
200
|
+
response = make_response(uri, request)
|
201
|
+
|
202
|
+
# response.code
|
203
|
+
# response.body
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
class AlexaDevices
|
210
|
+
|
211
|
+
# devices = [[{*serialno*, *type*}, label], ...]
|
212
|
+
# note: label can be any identifier you choose e.g. kitchen
|
213
|
+
#
|
214
|
+
def initialize(devicesx=[], devices: devicesx,
|
215
|
+
domain: 'alexa.amazon.co.uk', cookie: '')
|
216
|
+
|
217
|
+
@devices, @domain, @cookie = devices, domain, cookie
|
69
218
|
|
70
219
|
end
|
220
|
+
|
221
|
+
def playing()
|
222
|
+
|
223
|
+
@devices.map do |device, label|
|
224
|
+
alexa = AlexaRemoteCtl.new(cookie: @cookie, device: device)
|
225
|
+
alexa.playing? ? [alexa, label] : nil
|
226
|
+
end.compact
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
def pause(id=nil)
|
231
|
+
|
232
|
+
a = playing()
|
233
|
+
|
234
|
+
if id then
|
235
|
+
|
236
|
+
alexa, _ = a.find {|_, label| label.to_sym == id.to_sym}
|
237
|
+
alexa.pause
|
238
|
+
|
239
|
+
else
|
240
|
+
|
241
|
+
a.each do |alexa, label|
|
242
|
+
puts 'Pausing @' + label.inspect
|
243
|
+
alexa.pause
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def play(id=nil)
|
250
|
+
|
251
|
+
a = @devices
|
252
|
+
|
253
|
+
if id then
|
254
|
+
|
255
|
+
device, _ = a.find {|_, label| label.to_sym == id.to_sym}
|
256
|
+
alexa = AlexaRemoteCtl.new(cookie: @cookie, device: device)
|
257
|
+
alexa.play
|
258
|
+
|
259
|
+
else
|
260
|
+
|
261
|
+
a.each do |device, label|
|
262
|
+
puts 'Pausing @' + label.inspect
|
263
|
+
alexa = AlexaRemoteCtl.new(cookie: @cookie, device: device)
|
264
|
+
alexa.play
|
265
|
+
end
|
266
|
+
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
71
270
|
end
|
data.tar.gz.sig
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
q
|
2
|
-
|
1
|
+
q�!O��,>�n���$�}���1t�?(��y���?��Ҥ��d]R
|
2
|
+
���]�],�\]��v4#�K^²Ed�ϟ�LO��WT�ո{�|ݬrCRR�P���[�����,a�lxm�Ł�<�q���T���_
|
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
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Robertson
|
@@ -35,8 +35,28 @@ cert_chain:
|
|
35
35
|
d/gEwBtUmduwWZNX2NOJehf8s1cnH9OBP7s1ziHjdkZCgkQm3QewRRcdfZeYwFi6
|
36
36
|
4kVEcApgAgd+04ctE6uiRn5o
|
37
37
|
-----END CERTIFICATE-----
|
38
|
-
date: 2022-05-
|
39
|
-
dependencies:
|
38
|
+
date: 2022-05-22 00:00:00.000000000 Z
|
39
|
+
dependencies:
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: clipboard
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.3'
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 1.3.6
|
50
|
+
type: :runtime
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - "~>"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '1.3'
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 1.3.6
|
40
60
|
description:
|
41
61
|
email: digital.robertson@gmail.com
|
42
62
|
executables: []
|
metadata.gz.sig
CHANGED
@@ -1,5 +1,2 @@
|
|
1
|
-
-4�
|
2
|
-
|
3
|
-
�9�O��P���� Y����B�R4�`�Љ�Br��פ0�Lڵ��-�=���Můf�H�'!`۫���x���p����"�$��´�PJ����S�����^����F>���BM�b���ѩ�wy���au§�W�N��k���(���4�)�,�.��}I�����x�M�XI�� �����
|
4
|
-
b�z�Y3n��]�uh
|
5
|
-
&54]@^���r��N�t��"#^1��M��yHp\}����M���>�K�9Y��zT�jF��ʽ�4�
|
1
|
+
�tS��'-'9VN)�Y����>��4�����@o�
|
2
|
+
4�h��Wt�5�F�@�J��E"(�:E�wq9��;����gC��A�{�p�%p�Ay{�{u�(�^������dǤ�+Q9j]*�Y�+Ts��=ٗ�h���ng<"�����������
|