spotifywebapiPython 1.0.50__py3-none-any.whl → 1.0.52__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.50.dist-info → spotifywebapiPython-1.0.52.dist-info}/METADATA +1 -1
- {spotifywebapiPython-1.0.50.dist-info → spotifywebapiPython-1.0.52.dist-info}/RECORD +27 -25
- 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 +111 -3
- spotifywebapipython/docs/spotifywebapiPython/spotifydiscovery.html +2 -2
- spotifywebapipython/docs/spotifywebapiPython/spotifywebapiauthenticationerror.html +2 -2
- spotifywebapipython/docs/spotifywebapiPython/spotifywebapierror.html +2 -2
- spotifywebapipython/models/__init__.py +2 -0
- spotifywebapipython/models/device.py +50 -0
- spotifywebapipython/models/spotifyconnectdevice.py +93 -0
- spotifywebapipython/models/spotifyconnectdevices.py +240 -0
- spotifywebapipython/models/zeroconfdiscoveryresult.py +13 -5
- spotifywebapipython/spotifyclient.py +144 -36
- spotifywebapipython/zeroconfapi/zeroconfgetinfo.py +32 -0
- spotifywebapipython/zeroconfapi/zeroconfresponse.py +24 -0
- {spotifywebapiPython-1.0.50.dist-info → spotifywebapiPython-1.0.52.dist-info}/LICENSE +0 -0
- {spotifywebapiPython-1.0.50.dist-info → spotifywebapiPython-1.0.52.dist-info}/WHEEL +0 -0
- {spotifywebapiPython-1.0.50.dist-info → spotifywebapiPython-1.0.52.dist-info}/top_level.txt +0 -0
|
@@ -5946,7 +5946,7 @@ class SpotifyClient:
|
|
|
5946
5946
|
self,
|
|
5947
5947
|
verifyUserContext:bool=False,
|
|
5948
5948
|
delay:float=0.50,
|
|
5949
|
-
) ->
|
|
5949
|
+
) -> str:
|
|
5950
5950
|
"""
|
|
5951
5951
|
Activates all Spotify Connect player devices, and (optionally) switches the active user
|
|
5952
5952
|
context to the current user context.
|
|
@@ -5963,6 +5963,9 @@ class SpotifyClient:
|
|
|
5963
5963
|
another command is issued.
|
|
5964
5964
|
Default is 0.50; value range is 0 - 10.
|
|
5965
5965
|
|
|
5966
|
+
Returns:
|
|
5967
|
+
A string that contains status text.
|
|
5968
|
+
|
|
5966
5969
|
Raises:
|
|
5967
5970
|
SpotifyWebApiError:
|
|
5968
5971
|
If the Spotify Web API request was for a non-authorization service
|
|
@@ -6015,40 +6018,38 @@ class SpotifyClient:
|
|
|
6015
6018
|
|
|
6016
6019
|
deviceActiveUser:str = None
|
|
6017
6020
|
deviceIdResult:str = None
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
discovery.DiscoverDevices(timeout=self._SpotifyConnectDiscoveryTimeout)
|
|
6021
|
+
discoverResult:ZeroconfDiscoveryResult
|
|
6022
|
+
info:ZeroconfGetInfo
|
|
6023
|
+
scDevice:SpotifyConnectDevice
|
|
6024
|
+
|
|
6025
|
+
# get all Spotify Connect available devices on the network.
|
|
6026
|
+
scDevices:SpotifyConnectDevices = self.GetSpotifyConnectDevices()
|
|
6025
6027
|
|
|
6026
6028
|
# process all discovered devices.
|
|
6027
|
-
|
|
6028
|
-
for discoverResult in discovery.DiscoveryResults:
|
|
6029
|
+
for scDevice in scDevices:
|
|
6029
6030
|
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
zconn:ZeroconfConnect = ZeroconfConnect(discoverResult.HostIpv4Address,
|
|
6033
|
-
discoverResult.HostIpPort,
|
|
6034
|
-
discoverResult.SpotifyConnectCPath,
|
|
6035
|
-
useSSL=False)
|
|
6036
|
-
info:ZeroconfGetInfo = zconn.GetInformation()
|
|
6031
|
+
discoverResult = scDevice.DiscoveryResult
|
|
6032
|
+
info = scDevice.DeviceInfo
|
|
6037
6033
|
|
|
6038
6034
|
# store the currently active user of the device, in case we need to switch users later on.
|
|
6039
6035
|
deviceActiveUser = info.ActiveUser.lower()
|
|
6040
6036
|
deviceIdResult = info.DeviceId
|
|
6041
6037
|
|
|
6042
|
-
status:str = "INACTIVE"
|
|
6038
|
+
status:str = "INACTIVE, "
|
|
6043
6039
|
if (info.HasActiveUser):
|
|
6044
6040
|
status = "ACTIVE, "
|
|
6045
6041
|
|
|
6046
6042
|
# did we resolve the device id?
|
|
6047
6043
|
if deviceIdResult is not None:
|
|
6048
6044
|
|
|
6045
|
+
# is this a dynamic device? if so, then we can't control it.
|
|
6046
|
+
if (discoverResult.IsDynamicDevice):
|
|
6047
|
+
_logsi.LogVerbose("Spotify Connect Device id '%s' (%s) is a dynamic device; we cannot control it" % (deviceIdResult, info.RemoteName))
|
|
6048
|
+
status = status + "dynamic device, cannot switch user context"
|
|
6049
|
+
|
|
6049
6050
|
# does our Spotify Connect user account need to take control of the device?
|
|
6050
6051
|
# if not, then we are done.
|
|
6051
|
-
|
|
6052
|
+
elif (deviceActiveUser == self._SpotifyConnectUsername.lower()): # or (deviceActiveUser == self.UserProfile.Id.lower()):
|
|
6052
6053
|
_logsi.LogVerbose("Spotify Connect user context '%s' was verified for Device id '%s'; switch not necessary" % (deviceActiveUser, deviceIdResult))
|
|
6053
6054
|
status = status + "user context switch not needed"
|
|
6054
6055
|
|
|
@@ -6060,6 +6061,12 @@ class SpotifyClient:
|
|
|
6060
6061
|
|
|
6061
6062
|
else:
|
|
6062
6063
|
zcfResult:ZeroconfResponse
|
|
6064
|
+
|
|
6065
|
+
# create a ZeroconfConnect object to access the device.
|
|
6066
|
+
zconn:ZeroconfConnect = ZeroconfConnect(discoverResult.HostIpv4Address,
|
|
6067
|
+
discoverResult.HostIpPort,
|
|
6068
|
+
discoverResult.SpotifyConnectCPath,
|
|
6069
|
+
useSSL=False)
|
|
6063
6070
|
|
|
6064
6071
|
# if a different user context has control of the device then we need to disconnect
|
|
6065
6072
|
# the current user context before connecting a different user.
|
|
@@ -7890,6 +7897,102 @@ class SpotifyClient:
|
|
|
7890
7897
|
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)
|
|
7891
7898
|
|
|
7892
7899
|
|
|
7900
|
+
def GetSpotifyConnectDevices(
|
|
7901
|
+
self,
|
|
7902
|
+
) -> SpotifyConnectDevices:
|
|
7903
|
+
"""
|
|
7904
|
+
Get information about all available Spotify Connect player devices.
|
|
7905
|
+
|
|
7906
|
+
Returns:
|
|
7907
|
+
A `SpotifyConnectDevices` object that contain the discovery results
|
|
7908
|
+
as well as the `getInfo` result for each found device.
|
|
7909
|
+
|
|
7910
|
+
Raises:
|
|
7911
|
+
SpotifyWebApiError:
|
|
7912
|
+
If the Spotify Web API request was for a non-authorization service
|
|
7913
|
+
and the response contains error information.
|
|
7914
|
+
SpotifyZeroconfApiError:
|
|
7915
|
+
If the Spotify Zeroconf API request faild for any reason.
|
|
7916
|
+
SpotifApiError:
|
|
7917
|
+
If the method fails for any other reason.
|
|
7918
|
+
|
|
7919
|
+
This method is similar to the `GetPlayerDevices` method, but it contains ALL
|
|
7920
|
+
available Spotify Connect devices that are known to the local network (versus
|
|
7921
|
+
just the devices known to a specific user).
|
|
7922
|
+
|
|
7923
|
+
It will also call the `GetPlayerDevices` method, in case we have any dynamic devices.
|
|
7924
|
+
Dynamic devices are Spotify Connect devices that are not found in Zeroconf discovery
|
|
7925
|
+
process, but still exist in the player device list. These are usually Spotify Connect
|
|
7926
|
+
web or mobile players with temporary device id's.
|
|
7927
|
+
|
|
7928
|
+
<details>
|
|
7929
|
+
<summary>Sample Code</summary>
|
|
7930
|
+
```python
|
|
7931
|
+
.. include:: ../docs/include/samplecode/SpotifyClient/GetSpotifyConnectDevices.py
|
|
7932
|
+
```
|
|
7933
|
+
</details>
|
|
7934
|
+
"""
|
|
7935
|
+
apiMethodName:str = 'GetSpotifyConnectDevices'
|
|
7936
|
+
result:SpotifyConnectDevices = SpotifyConnectDevices()
|
|
7937
|
+
|
|
7938
|
+
try:
|
|
7939
|
+
|
|
7940
|
+
# trace.
|
|
7941
|
+
_logsi.EnterMethod(SILevel.Debug, apiMethodName)
|
|
7942
|
+
|
|
7943
|
+
# discover Spotify Connect devices on the network, waiting up to the specified timeout
|
|
7944
|
+
# for all devices to be discovered. this will return all Spotify Connect devices that
|
|
7945
|
+
# are currently powered on, and are registered to Zeroconf / mDNS.
|
|
7946
|
+
_logsi.LogVerbose("Discovering Spotify Connect devices on the local network")
|
|
7947
|
+
discovery:SpotifyDiscovery = SpotifyDiscovery(self._ZeroconfClient, printToConsole=False)
|
|
7948
|
+
discovery.DiscoverDevices(timeout=self._SpotifyConnectDiscoveryTimeout)
|
|
7949
|
+
|
|
7950
|
+
# process all discovered devices.
|
|
7951
|
+
discoverResult:ZeroconfDiscoveryResult
|
|
7952
|
+
for discoverResult in discovery.DiscoveryResults:
|
|
7953
|
+
|
|
7954
|
+
# get the id from the device via the zeroconf API getInfo endpoint, as the id is not
|
|
7955
|
+
# returned in the zeroconf discovery result.
|
|
7956
|
+
zconn:ZeroconfConnect = ZeroconfConnect(discoverResult.HostIpv4Address,
|
|
7957
|
+
discoverResult.HostIpPort,
|
|
7958
|
+
discoverResult.SpotifyConnectCPath,
|
|
7959
|
+
useSSL=False)
|
|
7960
|
+
info:ZeroconfGetInfo = zconn.GetInformation()
|
|
7961
|
+
|
|
7962
|
+
# create new spotify connect device object.
|
|
7963
|
+
scDevice:SpotifyConnectDevice = SpotifyConnectDevice()
|
|
7964
|
+
scDevice.DiscoveryResult = discoverResult
|
|
7965
|
+
scDevice.DeviceInfo = info
|
|
7966
|
+
result.Items.append(scDevice)
|
|
7967
|
+
|
|
7968
|
+
# we will also call the GetPlayerDevices method, in case we have any dynamic devices.
|
|
7969
|
+
# dynamic devices are Spotify Connect devices that are not found in Zeroconf discovery
|
|
7970
|
+
# process, but still exist in the player device list. these are usually Spotify Connect
|
|
7971
|
+
# web or mobile players with temporary device id's.
|
|
7972
|
+
devices:list[Device] = self.GetPlayerDevices(True)
|
|
7973
|
+
|
|
7974
|
+
device:Device
|
|
7975
|
+
for device in devices:
|
|
7976
|
+
if not result.ContainsDeviceId(device.Id):
|
|
7977
|
+
result.AddDynamicDevice(device, self.UserProfile.Id)
|
|
7978
|
+
|
|
7979
|
+
# trace.
|
|
7980
|
+
_logsi.LogArray(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result)
|
|
7981
|
+
return result
|
|
7982
|
+
|
|
7983
|
+
except SpotifyZeroconfApiError: raise # pass handled exceptions on thru
|
|
7984
|
+
except SpotifyApiError: raise # pass handled exceptions on thru
|
|
7985
|
+
except Exception as ex:
|
|
7986
|
+
|
|
7987
|
+
# format unhandled exception.
|
|
7988
|
+
raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
|
|
7989
|
+
|
|
7990
|
+
finally:
|
|
7991
|
+
|
|
7992
|
+
# trace.
|
|
7993
|
+
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)
|
|
7994
|
+
|
|
7995
|
+
|
|
7893
7996
|
def GetTrack(self,
|
|
7894
7997
|
trackId:str,
|
|
7895
7998
|
) -> Track:
|
|
@@ -10185,33 +10288,27 @@ class SpotifyClient:
|
|
|
10185
10288
|
# determine if the device value specified is a name (e.g. "Bose-ST10-1") or
|
|
10186
10289
|
# an id (e.g. "30fbc80e35598f3c242f2120413c943dfd9715fe").
|
|
10187
10290
|
isDeviceId:bool = SpotifyClient.IsDeviceId(deviceValue)
|
|
10291
|
+
|
|
10188
10292
|
deviceValueCompare:str = deviceValue.lower()
|
|
10189
10293
|
deviceActiveUser:str = None
|
|
10190
|
-
|
|
10191
|
-
|
|
10192
|
-
|
|
10193
|
-
|
|
10194
|
-
|
|
10195
|
-
|
|
10196
|
-
discovery.DiscoverDevices(timeout=self._SpotifyConnectDiscoveryTimeout)
|
|
10294
|
+
discoverResult:ZeroconfDiscoveryResult
|
|
10295
|
+
info:ZeroconfGetInfo
|
|
10296
|
+
scDevice:SpotifyConnectDevice
|
|
10297
|
+
|
|
10298
|
+
# get all Spotify Connect available devices on the network.
|
|
10299
|
+
scDevices:SpotifyConnectDevices = self.GetSpotifyConnectDevices()
|
|
10197
10300
|
|
|
10198
10301
|
# process all discovered devices.
|
|
10199
|
-
|
|
10200
|
-
for discoverResult in discovery.DiscoveryResults:
|
|
10302
|
+
for scDevice in scDevices:
|
|
10201
10303
|
|
|
10202
|
-
|
|
10203
|
-
|
|
10204
|
-
zconn:ZeroconfConnect = ZeroconfConnect(discoverResult.HostIpv4Address,
|
|
10205
|
-
discoverResult.HostIpPort,
|
|
10206
|
-
discoverResult.SpotifyConnectCPath,
|
|
10207
|
-
useSSL=False)
|
|
10208
|
-
info:ZeroconfGetInfo = zconn.GetInformation()
|
|
10304
|
+
discoverResult = scDevice.DiscoveryResult
|
|
10305
|
+
info = scDevice.DeviceInfo
|
|
10209
10306
|
|
|
10210
10307
|
# store the currently active user of the device, in case we need to switch users later on.
|
|
10211
10308
|
deviceActiveUser = info.ActiveUser.lower()
|
|
10212
10309
|
|
|
10213
10310
|
# are aliases being used (RemoteName is null if so)?
|
|
10214
|
-
if info.
|
|
10311
|
+
if info.HasAliases:
|
|
10215
10312
|
|
|
10216
10313
|
# if aliases are defined for the device, then we have to check each alias for a match.
|
|
10217
10314
|
infoAlias:ZeroconfGetInfoAlias
|
|
@@ -10244,6 +10341,11 @@ class SpotifyClient:
|
|
|
10244
10341
|
# did we resolve the device id?
|
|
10245
10342
|
if deviceIdResult is not None:
|
|
10246
10343
|
|
|
10344
|
+
# is this a dynamic device? if so, then we can't control it.
|
|
10345
|
+
if (discoverResult.IsDynamicDevice):
|
|
10346
|
+
_logsi.LogVerbose("Spotify Connect Device '%s' (%s) is a dynamic device; we cannot control it" % (info.RemoteName, deviceIdResult))
|
|
10347
|
+
break
|
|
10348
|
+
|
|
10247
10349
|
# did caller request user context switch bypass?
|
|
10248
10350
|
# if so, then just return the device id.
|
|
10249
10351
|
if (not verifyUserContext):
|
|
@@ -10264,6 +10366,12 @@ class SpotifyClient:
|
|
|
10264
10366
|
|
|
10265
10367
|
zcfResult:ZeroconfResponse
|
|
10266
10368
|
|
|
10369
|
+
# create a ZeroconfConnect object to access the device.
|
|
10370
|
+
zconn:ZeroconfConnect = ZeroconfConnect(discoverResult.HostIpv4Address,
|
|
10371
|
+
discoverResult.HostIpPort,
|
|
10372
|
+
discoverResult.SpotifyConnectCPath,
|
|
10373
|
+
useSSL=False)
|
|
10374
|
+
|
|
10267
10375
|
# if a different user context has control of the device then we need to disconnect
|
|
10268
10376
|
# the current user context before connecting a different user.
|
|
10269
10377
|
if (info.HasActiveUser):
|
|
@@ -109,6 +109,14 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
109
109
|
This value will be an empty string if there is no user logged into the device.
|
|
110
110
|
"""
|
|
111
111
|
return self._ActiveUser
|
|
112
|
+
|
|
113
|
+
@ActiveUser.setter
|
|
114
|
+
def ActiveUser(self, value:str):
|
|
115
|
+
"""
|
|
116
|
+
Sets the ActiveUser property value.
|
|
117
|
+
"""
|
|
118
|
+
if isinstance(value, str):
|
|
119
|
+
self._ActiveUser = value
|
|
112
120
|
|
|
113
121
|
|
|
114
122
|
@property
|
|
@@ -158,6 +166,14 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
158
166
|
Unique device ID used for ZeroConf logins (e.g. "30fbc80e35598f3c242f2120413c943dfd9715fe").
|
|
159
167
|
"""
|
|
160
168
|
return self._DeviceId
|
|
169
|
+
|
|
170
|
+
@DeviceId.setter
|
|
171
|
+
def DeviceId(self, value:str):
|
|
172
|
+
"""
|
|
173
|
+
Sets the DeviceId property value.
|
|
174
|
+
"""
|
|
175
|
+
if isinstance(value, str):
|
|
176
|
+
self._DeviceId = value
|
|
161
177
|
|
|
162
178
|
|
|
163
179
|
@property
|
|
@@ -182,6 +198,14 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
182
198
|
- kSpDeviceTypeChromebook Chromebook.
|
|
183
199
|
"""
|
|
184
200
|
return self._DeviceType
|
|
201
|
+
|
|
202
|
+
@DeviceType.setter
|
|
203
|
+
def DeviceType(self, value:str):
|
|
204
|
+
"""
|
|
205
|
+
Sets the DeviceType property value.
|
|
206
|
+
"""
|
|
207
|
+
if isinstance(value, str):
|
|
208
|
+
self._DeviceType = value
|
|
185
209
|
|
|
186
210
|
|
|
187
211
|
@property
|
|
@@ -253,6 +277,14 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
253
277
|
Please refer to the `Aliases` property for more information.
|
|
254
278
|
"""
|
|
255
279
|
return self._RemoteName
|
|
280
|
+
|
|
281
|
+
@RemoteName.setter
|
|
282
|
+
def RemoteName(self, value:str):
|
|
283
|
+
"""
|
|
284
|
+
Sets the RemoteName property value.
|
|
285
|
+
"""
|
|
286
|
+
if isinstance(value, str):
|
|
287
|
+
self._RemoteName = value
|
|
256
288
|
|
|
257
289
|
|
|
258
290
|
@property
|
|
@@ -57,6 +57,14 @@ class ZeroconfResponse:
|
|
|
57
57
|
The last error code returned by a Spotify API call or the SpCallbackError() callback (e.g. 0, -119, etc).
|
|
58
58
|
"""
|
|
59
59
|
return self._SpotifyError
|
|
60
|
+
|
|
61
|
+
@SpotifyError.setter
|
|
62
|
+
def SpotifyError(self, value:int):
|
|
63
|
+
"""
|
|
64
|
+
Sets the SpotifyError property value.
|
|
65
|
+
"""
|
|
66
|
+
if isinstance(value, int):
|
|
67
|
+
self._SpotifyError = value
|
|
60
68
|
|
|
61
69
|
|
|
62
70
|
@property
|
|
@@ -65,6 +73,14 @@ class ZeroconfResponse:
|
|
|
65
73
|
A code indicating the result of the operation (e.g. 101, 402, etc).
|
|
66
74
|
"""
|
|
67
75
|
return self._Status
|
|
76
|
+
|
|
77
|
+
@Status.setter
|
|
78
|
+
def Status(self, value:int):
|
|
79
|
+
"""
|
|
80
|
+
Sets the Status property value.
|
|
81
|
+
"""
|
|
82
|
+
if isinstance(value, int):
|
|
83
|
+
self._Status = value
|
|
68
84
|
|
|
69
85
|
|
|
70
86
|
@property
|
|
@@ -73,6 +89,14 @@ class ZeroconfResponse:
|
|
|
73
89
|
The string describing the status code (e.g. "OK", "ERROR-SPOTIFY-ERROR", etc).
|
|
74
90
|
"""
|
|
75
91
|
return self._StatusString
|
|
92
|
+
|
|
93
|
+
@StatusString.setter
|
|
94
|
+
def StatusString(self, value:str):
|
|
95
|
+
"""
|
|
96
|
+
Sets the StatusString property value.
|
|
97
|
+
"""
|
|
98
|
+
if isinstance(value, str):
|
|
99
|
+
self._StatusString = value
|
|
76
100
|
|
|
77
101
|
|
|
78
102
|
def ToDictionary(self) -> dict:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|