spotifywebapiPython 1.0.156__py3-none-any.whl → 1.0.158__py3-none-any.whl
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.
Potentially problematic release.
This version of spotifywebapiPython might be problematic. Click here for more details.
- {spotifywebapiPython-1.0.156.dist-info → spotifywebapiPython-1.0.158.dist-info}/METADATA +1 -1
- {spotifywebapiPython-1.0.156.dist-info → spotifywebapiPython-1.0.158.dist-info}/RECORD +24 -24
- spotifywebapipython/const.py +1 -1
- spotifywebapipython/docs/__init__.html +14 -2
- spotifywebapipython/docs/index.html +2 -2
- spotifywebapipython/docs/search.js +1 -1
- spotifywebapipython/docs/spotifywebapipython/const.html +3 -3
- spotifywebapipython/docs/spotifywebapipython/saappmessages.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/sautils.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifyapierror.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifyapimessage.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifyauthtoken.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifyclient.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifydiscovery.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifywebapiauthenticationerror.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifywebapierror.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifywebplayertoken.html +2 -2
- spotifywebapipython/spotifyclient.py +5 -6
- spotifywebapipython/spotifyconnect/spotifyconnectdirectorytask.py +24 -19
- spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastapptask.py +84 -75
- spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastcontroller.py +14 -12
- {spotifywebapiPython-1.0.156.dist-info → spotifywebapiPython-1.0.158.dist-info}/LICENSE +0 -0
- {spotifywebapiPython-1.0.156.dist-info → spotifywebapiPython-1.0.158.dist-info}/WHEEL +0 -0
- {spotifywebapiPython-1.0.156.dist-info → spotifywebapiPython-1.0.158.dist-info}/top_level.txt +0 -0
|
@@ -4,11 +4,9 @@ import threading
|
|
|
4
4
|
import time
|
|
5
5
|
|
|
6
6
|
# our package imports.
|
|
7
|
-
from .spotifyconnectzeroconfcastcontroller import SpotifyConnectZeroconfCastController
|
|
8
|
-
from .spotifyconnectzeroconfexceptions import SpotifyConnectZeroconfPlaybackTransferError
|
|
9
|
-
#from spotifywebapipython import SpotifyClient
|
|
10
|
-
from spotifywebapipython.zeroconfapi import ZeroconfGetInfo, ZeroconfResponse
|
|
7
|
+
from .spotifyconnectzeroconfcastcontroller import SpotifyConnectZeroconfCastController, TYPE_LAUNCH_ERROR
|
|
11
8
|
from spotifywebapipython.spotifywebplayertoken import SpotifyWebPlayerToken
|
|
9
|
+
from spotifywebapipython.zeroconfapi import ZeroconfGetInfo, ZeroconfResponse
|
|
12
10
|
|
|
13
11
|
# get smartinspect logger reference; create a new session for this module name.
|
|
14
12
|
from smartinspectpython.siauto import SIAuto, SILevel, SISession
|
|
@@ -118,42 +116,27 @@ class SpotifyConnectZeroconfCastAppTask(threading.Thread):
|
|
|
118
116
|
return self._TransferPlayback
|
|
119
117
|
|
|
120
118
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
application is running on the Chromecast devive; otherwise, None.
|
|
126
|
-
"""
|
|
127
|
-
if (self._SpotifyConnectZeroconfCastController is None):
|
|
128
|
-
return None
|
|
129
|
-
return self._SpotifyConnectZeroconfCastController.zeroconfGetInfo
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
@property
|
|
133
|
-
def ZeroconfResponseObject(self) -> ZeroconfResponse:
|
|
134
|
-
"""
|
|
135
|
-
Returns the Chromecast Spotify Connect zeroconf response, if the Spotify
|
|
136
|
-
application returned one; otherwise, None.
|
|
119
|
+
def _CallGetInfoResponseReceivedCallback(
|
|
120
|
+
self,
|
|
121
|
+
zcResponse:ZeroconfGetInfo=None,
|
|
122
|
+
) -> None:
|
|
137
123
|
"""
|
|
138
|
-
|
|
139
|
-
return None
|
|
140
|
-
return self._SpotifyConnectZeroconfCastController.zeroconfResponse
|
|
124
|
+
Executes the callback to process the zeroconf getInfo response from the cast app task.
|
|
141
125
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
If defined, call the callback to process the zeroconf getInfo response from the cast app task.
|
|
126
|
+
Args:
|
|
127
|
+
zcResponse (ZeroconfGetInfo):
|
|
128
|
+
Zeroconf getInfo response object.
|
|
146
129
|
"""
|
|
147
|
-
# was
|
|
130
|
+
# was the callback defined?
|
|
148
131
|
if (self._GetInfoResponseReceivedCallback):
|
|
149
132
|
|
|
150
133
|
try:
|
|
151
134
|
|
|
152
135
|
# trace.
|
|
153
|
-
_logsi.LogVerbose("%s - Zeroconf getInfoResponse received; Spotify Connect info: \"%s\" (%s)" % (self.name,
|
|
136
|
+
_logsi.LogVerbose("%s - Zeroconf getInfoResponse received; Spotify Connect info: \"%s\" (%s)" % (self.name, zcResponse.RemoteName, zcResponse.DeviceId))
|
|
154
137
|
|
|
155
138
|
# invoke callback to process the GetInfoResponse data.
|
|
156
|
-
self._GetInfoResponseReceivedCallback(self._CastDevice.uuid,
|
|
139
|
+
self._GetInfoResponseReceivedCallback(self._CastDevice.uuid, zcResponse)
|
|
157
140
|
|
|
158
141
|
except Exception as ex:
|
|
159
142
|
|
|
@@ -162,21 +145,27 @@ class SpotifyConnectZeroconfCastAppTask(threading.Thread):
|
|
|
162
145
|
#ignore exceptions, as there is nothing we can do about them!
|
|
163
146
|
|
|
164
147
|
|
|
165
|
-
|
|
166
|
-
|
|
148
|
+
def _CallZeroconfResponseReceivedCallback(
|
|
149
|
+
self,
|
|
150
|
+
zcResponse:ZeroconfResponse=None,
|
|
151
|
+
) -> None:
|
|
167
152
|
"""
|
|
168
|
-
|
|
153
|
+
Executes the callback to process the various zeroconf responses from the cast app task.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
zcResponse (ZeroconfResponse):
|
|
157
|
+
Zeroconf response object.
|
|
169
158
|
"""
|
|
170
|
-
# was
|
|
159
|
+
# was the callback defined?
|
|
171
160
|
if (self._ZeroconfResponseReceivedCallback):
|
|
172
161
|
|
|
173
162
|
try:
|
|
174
163
|
|
|
175
164
|
# trace.
|
|
176
|
-
_logsi.LogVerbose("%s - Zeroconf \"%s\" received; Spotify Connect response: \"%s\" (%s)" % (self.name,
|
|
165
|
+
_logsi.LogVerbose("%s - Zeroconf \"%s\" received; Spotify Connect response: \"%s\" (%s)" % (self.name, zcResponse.ResponseSource, zcResponse.StatusString, zcResponse.Status))
|
|
177
166
|
|
|
178
167
|
# invoke callback to process the ZeroconfResponse data.
|
|
179
|
-
self._ZeroconfResponseReceivedCallback(self._CastDevice.uuid,
|
|
168
|
+
self._ZeroconfResponseReceivedCallback(self._CastDevice.uuid, zcResponse)
|
|
180
169
|
|
|
181
170
|
except Exception as ex:
|
|
182
171
|
|
|
@@ -188,6 +177,9 @@ class SpotifyConnectZeroconfCastAppTask(threading.Thread):
|
|
|
188
177
|
def run(self):
|
|
189
178
|
"""
|
|
190
179
|
The task to perform on a seperate thread.
|
|
180
|
+
|
|
181
|
+
Note that any exceptions must be processed via a call to _PostLaunchErrorEvent, if you
|
|
182
|
+
want the exception to be see by the user; just raising an exception will only log it!
|
|
191
183
|
"""
|
|
192
184
|
try:
|
|
193
185
|
|
|
@@ -220,32 +212,24 @@ class SpotifyConnectZeroconfCastAppTask(threading.Thread):
|
|
|
220
212
|
# at this point the cast app should be either fully launched, or an error
|
|
221
213
|
# occured while trying to launch.
|
|
222
214
|
|
|
223
|
-
#
|
|
224
|
-
if (self.
|
|
225
|
-
|
|
226
|
-
try:
|
|
215
|
+
# did an error occur?
|
|
216
|
+
if (not self._SpotifyConnectZeroconfCastController.isLaunched):
|
|
227
217
|
|
|
228
|
-
|
|
229
|
-
|
|
218
|
+
# was it a launchError or getInfoError?
|
|
219
|
+
if (not self._SpotifyConnectZeroconfCastController.isAddUserError):
|
|
220
|
+
self._CallZeroconfResponseReceivedCallback(self._SpotifyConnectZeroconfCastController.zeroconfResponse)
|
|
221
|
+
_logsi.LogException("%s - Failed to launch spotify controller due to timeout" % (self.name), None, logToSystemLogger=False)
|
|
222
|
+
return
|
|
230
223
|
|
|
231
|
-
|
|
232
|
-
|
|
224
|
+
# if getInfoResponse was received, then execute callback to process the getInfoResponse.
|
|
225
|
+
if (not self._SpotifyConnectZeroconfCastController.isGetInfoError) and (self._SpotifyConnectZeroconfCastController.zeroconfGetInfo is not None):
|
|
226
|
+
self._CallGetInfoResponseReceivedCallback(self._SpotifyConnectZeroconfCastController.zeroconfGetInfo)
|
|
233
227
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
_logsi.LogException("
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
# check for launch or getInfoError errors.
|
|
241
|
-
if (not self._SpotifyConnectZeroconfCastController.isLaunched) and (not self._SpotifyConnectZeroconfCastController.isAddUserError):
|
|
242
|
-
self._CallZeroconfResponseReceivedCallback()
|
|
243
|
-
raise ValueError("%s - Failed to launch spotify controller due to timeout" % (self.name))
|
|
244
|
-
|
|
245
|
-
# check for addUserError errors.
|
|
246
|
-
if (not self._SpotifyConnectZeroconfCastController.isLaunched) and (self._SpotifyConnectZeroconfCastController.isAddUserError):
|
|
247
|
-
self._CallZeroconfResponseReceivedCallback()
|
|
248
|
-
raise ValueError("%s - Failed to launch spotify controller due to credentials error" % (self.name))
|
|
228
|
+
# was it a addUserError? if so, then sp_dc / sp_key credentials are probably bad.
|
|
229
|
+
if (self._SpotifyConnectZeroconfCastController.isAddUserError):
|
|
230
|
+
self._CallZeroconfResponseReceivedCallback(self._SpotifyConnectZeroconfCastController.zeroconfResponse)
|
|
231
|
+
_logsi.LogException("%s - Failed to launch spotify controller due to credentials error" % (self.name), None, logToSystemLogger=False)
|
|
232
|
+
return
|
|
249
233
|
|
|
250
234
|
# at this point the cast app launch was successful; the following steps were performed:
|
|
251
235
|
# - issues a Spotify Connect Zeroconf `getInfo` request to retrieve info about the device.
|
|
@@ -258,10 +242,10 @@ class SpotifyConnectZeroconfCastAppTask(threading.Thread):
|
|
|
258
242
|
# as well as AFTER the call to `addUser` (no need to call `getInfo` again AFTER addUser).
|
|
259
243
|
|
|
260
244
|
# call the callback to process the getInfoResponse.
|
|
261
|
-
self._CallGetInfoResponseReceivedCallback()
|
|
245
|
+
self._CallGetInfoResponseReceivedCallback(self._SpotifyConnectZeroconfCastController.zeroconfGetInfo)
|
|
262
246
|
|
|
263
247
|
# call the callback to process the addUserResponse.
|
|
264
|
-
self._CallZeroconfResponseReceivedCallback()
|
|
248
|
+
self._CallZeroconfResponseReceivedCallback(self._SpotifyConnectZeroconfCastController.zeroconfResponse)
|
|
265
249
|
|
|
266
250
|
# trace.
|
|
267
251
|
_logsi.LogVerbose("%s - User is logged in to Spotify Cast App; waiting for transfer playback ..." % (self.name))
|
|
@@ -271,7 +255,8 @@ class SpotifyConnectZeroconfCastAppTask(threading.Thread):
|
|
|
271
255
|
|
|
272
256
|
# transfer playback to the Chromecast device.
|
|
273
257
|
_logsi.LogVerbose("%s - Transferring playback for loginId \"%s\"" % (self.name, self.SpotifyClientInstance.SpotifyConnectLoginId))
|
|
274
|
-
self.
|
|
258
|
+
deviceId:str = self._SpotifyConnectZeroconfCastController.zeroconfGetInfo.DeviceId
|
|
259
|
+
self.SpotifyClientInstance.PlayerTransferPlayback(deviceId, play=True, refreshDeviceList=False)
|
|
275
260
|
|
|
276
261
|
# the cast device will receive a Chromecast message of payload type `transferSuccess`
|
|
277
262
|
# on successful transfer of playback; this will set the `isPlaybackTransferred` flag to True.
|
|
@@ -284,17 +269,19 @@ class SpotifyConnectZeroconfCastAppTask(threading.Thread):
|
|
|
284
269
|
while counter < (timeout + 1):
|
|
285
270
|
if (self._SpotifyConnectZeroconfCastController.waitPlaybackTransfer.wait(1)):
|
|
286
271
|
if (self._SpotifyConnectZeroconfCastController.isPlaybackTransferError):
|
|
287
|
-
|
|
272
|
+
self._PostLaunchErrorEvent(1001, "Playback transfer error: %s" % (self._SpotifyConnectZeroconfCastController.zeroconfResponse.StatusString))
|
|
273
|
+
return
|
|
288
274
|
break
|
|
289
275
|
if (counter >= timeout):
|
|
290
|
-
|
|
276
|
+
self._PostLaunchErrorEvent(1002, "Playback transfer error - Timed out waiting for playback transfer to device.")
|
|
277
|
+
return
|
|
291
278
|
counter += 1
|
|
292
279
|
|
|
293
280
|
# update task status.
|
|
294
281
|
_logsi.LogVerbose("%s - Transfer Playback complete for loginId \"%s\"" % (self.name, self.SpotifyClientInstance.SpotifyConnectLoginId))
|
|
295
282
|
|
|
296
283
|
# call the callback to process the transferSuccess or transferError.
|
|
297
|
-
self._CallZeroconfResponseReceivedCallback()
|
|
284
|
+
self._CallZeroconfResponseReceivedCallback(self._SpotifyConnectZeroconfCastController.zeroconfResponse)
|
|
298
285
|
|
|
299
286
|
# event loop; we have to keep this thread active in order to keep the
|
|
300
287
|
# Spotify App on the Chromecast device active and available.
|
|
@@ -309,20 +296,16 @@ class SpotifyConnectZeroconfCastAppTask(threading.Thread):
|
|
|
309
296
|
# trace.
|
|
310
297
|
_logsi.LogVerbose("%s - Thread task was stopped" % (self.name))
|
|
311
298
|
|
|
312
|
-
except SpotifyConnectZeroconfPlaybackTransferError as ex:
|
|
313
|
-
|
|
314
|
-
# trace.
|
|
315
|
-
_logsi.LogError(str(ex))
|
|
316
|
-
_logsi.LogVerbose("%s - Thread task is ending due to error" % (self.name))
|
|
317
|
-
|
|
318
299
|
except Exception as ex:
|
|
319
300
|
|
|
301
|
+
# post launchError event with exception details.
|
|
302
|
+
# this will also log a trace message.
|
|
303
|
+
self._PostLaunchErrorEvent(1000, str(ex))
|
|
304
|
+
|
|
320
305
|
# trace.
|
|
321
|
-
_logsi.LogException("%s - Exception: %s" % (self.name, str(ex)), ex, logToSystemLogger=False)
|
|
322
306
|
_logsi.LogVerbose("%s - Thread task is ending due to exception" % (self.name))
|
|
323
|
-
|
|
324
|
-
#
|
|
325
|
-
raise
|
|
307
|
+
|
|
308
|
+
#ignore exceptions, as there is nothing we can do about them!
|
|
326
309
|
|
|
327
310
|
finally:
|
|
328
311
|
|
|
@@ -334,3 +317,29 @@ class SpotifyConnectZeroconfCastAppTask(threading.Thread):
|
|
|
334
317
|
self._SpotifyConnectZeroconfCastController.tear_down()
|
|
335
318
|
except:
|
|
336
319
|
pass
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def _PostLaunchErrorEvent(
|
|
323
|
+
self,
|
|
324
|
+
returnCode:int,
|
|
325
|
+
message:str
|
|
326
|
+
) -> None:
|
|
327
|
+
"""
|
|
328
|
+
Formats a `launchError` Zeroconf Response, and executes the callback.
|
|
329
|
+
"""
|
|
330
|
+
try:
|
|
331
|
+
|
|
332
|
+
# trace.
|
|
333
|
+
_logsi.LogError("%s - LaunchError event; (%s) %s" % (self.name, returnCode, message), logToSystemLogger=False)
|
|
334
|
+
|
|
335
|
+
# post launchError event with error details.
|
|
336
|
+
response:ZeroconfResponse = ZeroconfResponse()
|
|
337
|
+
response.ResponseSource = TYPE_LAUNCH_ERROR
|
|
338
|
+
response.Status = returnCode
|
|
339
|
+
response.StatusString = message
|
|
340
|
+
self._CallZeroconfResponseReceivedCallback(response)
|
|
341
|
+
|
|
342
|
+
except:
|
|
343
|
+
|
|
344
|
+
# ignore exceptions, as there is nothing we can do about them.
|
|
345
|
+
pass
|
|
@@ -38,8 +38,10 @@ TYPE_GET_INFO_RESPONSE = "getInfoResponse"
|
|
|
38
38
|
TYPE_ADD_USER = "addUser"
|
|
39
39
|
TYPE_ADD_USER_RESPONSE = "addUserResponse"
|
|
40
40
|
TYPE_ADD_USER_ERROR = "addUserError"
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
TYPE_TRANSFER_SUCCESS = "transferSuccess"
|
|
42
|
+
TYPE_TRANSFER_ERROR = "transferError"
|
|
43
|
+
# not an actual Google Cast zeroconf response; used by this api to denote a launch / config error.
|
|
44
|
+
TYPE_LAUNCH_ERROR = "launchError"
|
|
43
45
|
|
|
44
46
|
SPOTIFY_WEB_API_DEVICEAUTH_REFRESH = "https://spclient.wg.spotify.com/device-auth/v1/refresh"
|
|
45
47
|
|
|
@@ -144,26 +146,26 @@ class SpotifyConnectZeroconfCastController(BaseController):
|
|
|
144
146
|
# launch the spotify app on the device.
|
|
145
147
|
# this will perform the following steps, initiated via the callback function:
|
|
146
148
|
# - issues a Spotify Connect Zeroconf `getInfo` request to retrieve info about the device.
|
|
147
|
-
# - waits for a `getInfoResponse` message and processes the results.
|
|
149
|
+
# - waits for a `getInfoResponse` (or `getInfoError`) message and processes the results.
|
|
148
150
|
# - issues a Spotify Connect Zeroconf `addUser` request to login the user to Spotify Connect.
|
|
149
151
|
# - waits for a `addUserResponse` (or `addUserError`) message and processes the results.
|
|
150
152
|
self.launch(callback_function=callback)
|
|
151
153
|
|
|
152
|
-
# wait for the launched spotify app to fully initialize.
|
|
153
|
-
#
|
|
154
|
+
# wait for the launched spotify app to fully initialize. this occurs when we receive one
|
|
155
|
+
# of the following messages: `addUserResponse`, `addUserError`, `getInfoError`, `launchError`.
|
|
154
156
|
counter = 0
|
|
155
157
|
while counter < (timeout + 1):
|
|
156
158
|
if (self.waitAddUser.wait(1)):
|
|
157
|
-
if (self.isAddUserError):
|
|
158
|
-
raise SpotifyZeroconfApiError(self.zeroconfResponse.Status, "AddUser request failed", "launch_app", self.zeroconfResponse.StatusString)
|
|
159
159
|
break
|
|
160
|
-
if (self.isGetInfoError):
|
|
161
|
-
raise SpotifyZeroconfApiError(self.zeroconfResponse.Status, "GetInformation request failed", "launch_app", self.zeroconfResponse.StatusString)
|
|
162
160
|
if (counter >= timeout):
|
|
163
161
|
raise SpotifyZeroconfApiError(0, "Timed out while waiting for a response", "launch_app", "timeout")
|
|
164
162
|
counter += 1
|
|
165
163
|
|
|
166
|
-
#
|
|
164
|
+
# check for error conditions.
|
|
165
|
+
if (self.isAddUserError):
|
|
166
|
+
raise SpotifyZeroconfApiError(self.zeroconfResponse.Status, "AddUser request failed", "launch_app", self.zeroconfResponse.StatusString)
|
|
167
|
+
if (self.isGetInfoError):
|
|
168
|
+
raise SpotifyZeroconfApiError(self.zeroconfResponse.Status, "GetInformation request failed", "launch_app", self.zeroconfResponse.StatusString)
|
|
167
169
|
if (not self.isLaunched):
|
|
168
170
|
raise SpotifyConnectZeroconfLaunchError("Spotify Cast App could not be launched")
|
|
169
171
|
|
|
@@ -336,7 +338,7 @@ class SpotifyConnectZeroconfCastController(BaseController):
|
|
|
336
338
|
return True
|
|
337
339
|
|
|
338
340
|
# was playback transferred to the device?
|
|
339
|
-
if payloadDataType ==
|
|
341
|
+
if payloadDataType == TYPE_TRANSFER_SUCCESS:
|
|
340
342
|
|
|
341
343
|
# example payload response (Nest Speaker):
|
|
342
344
|
# { 'type': 'transferSuccess',
|
|
@@ -354,7 +356,7 @@ class SpotifyConnectZeroconfCastController(BaseController):
|
|
|
354
356
|
return True
|
|
355
357
|
|
|
356
358
|
# did an error occur transferring playback to the device?
|
|
357
|
-
if payloadDataType ==
|
|
359
|
+
if payloadDataType == TYPE_TRANSFER_ERROR:
|
|
358
360
|
|
|
359
361
|
# example payload response (Nest Speaker):
|
|
360
362
|
# { 'type': 'transferError',
|
|
File without changes
|
|
File without changes
|
{spotifywebapiPython-1.0.156.dist-info → spotifywebapiPython-1.0.158.dist-info}/top_level.txt
RENAMED
|
File without changes
|