spotifywebapiPython 1.0.47__py3-none-any.whl → 1.0.49__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.47.dist-info → spotifywebapiPython-1.0.49.dist-info}/METADATA +1 -1
- {spotifywebapiPython-1.0.47.dist-info → spotifywebapiPython-1.0.49.dist-info}/RECORD +24 -24
- spotifywebapipython/const.py +1 -1
- spotifywebapipython/docs/__init__.html +19 -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 +303 -3
- spotifywebapipython/docs/spotifywebapiPython/spotifydiscovery.html +15 -72
- spotifywebapipython/docs/spotifywebapiPython/spotifywebapiauthenticationerror.html +2 -2
- spotifywebapipython/docs/spotifywebapiPython/spotifywebapierror.html +2 -2
- spotifywebapipython/models/userprofile.py +24 -0
- spotifywebapipython/spotifyclient.py +497 -8
- spotifywebapipython/spotifydiscovery.py +27 -83
- spotifywebapipython/zeroconfapi/zeroconfconnect.py +10 -0
- spotifywebapipython/zeroconfapi/zeroconfgetinfo.py +21 -3
- {spotifywebapiPython-1.0.47.dist-info → spotifywebapiPython-1.0.49.dist-info}/LICENSE +0 -0
- {spotifywebapiPython-1.0.47.dist-info → spotifywebapiPython-1.0.49.dist-info}/WHEEL +0 -0
- {spotifywebapiPython-1.0.47.dist-info → spotifywebapiPython-1.0.49.dist-info}/top_level.txt +0 -0
|
@@ -8,9 +8,9 @@ from zeroconf import Zeroconf, ServiceBrowser, ServiceInfo, ServiceStateChange,
|
|
|
8
8
|
|
|
9
9
|
# our package imports.
|
|
10
10
|
from .saappmessages import SAAppMessages
|
|
11
|
+
from .spotifyapierror import SpotifyApiError
|
|
11
12
|
from .sautils import export
|
|
12
13
|
from .models.device import Device
|
|
13
|
-
from .spotifyclient import SpotifyClient, SpotifyApiError
|
|
14
14
|
from .models import ZeroconfDiscoveryResult, ZeroconfProperty
|
|
15
15
|
|
|
16
16
|
# get smartinspect logger reference; create a new session for this module name.
|
|
@@ -32,43 +32,40 @@ class SpotifyDiscovery:
|
|
|
32
32
|
Click the **Sample Code** links in the individual methods for sample code examples.
|
|
33
33
|
"""
|
|
34
34
|
|
|
35
|
-
def __init__(
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
zeroconfClient:Zeroconf=None,
|
|
38
|
+
printToConsole:bool=False
|
|
39
|
+
) -> None:
|
|
36
40
|
"""
|
|
37
41
|
Initializes a new instance of the class.
|
|
38
42
|
|
|
39
43
|
Args:
|
|
40
|
-
|
|
41
|
-
A
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
areDevicesVerified (bool):
|
|
45
|
-
True to create a `SpotifyClient` instance for discovered devices, which
|
|
46
|
-
verifies that the device can be accessed and basic information obtained
|
|
47
|
-
about its capabilities; otherwise, False to just identify the IPV4 Address,
|
|
48
|
-
Port, and Device Name.
|
|
49
|
-
Default is False.
|
|
44
|
+
zeroconfClient (Zeroconf)
|
|
45
|
+
A Zeroconf client instance that will be used to discover Spotify Connect devices,
|
|
46
|
+
or null to create a new instance of Zeroconf.
|
|
47
|
+
Default is null.
|
|
50
48
|
printToConsole (bool):
|
|
51
49
|
True to print discovered device information to the console as the devices
|
|
52
50
|
are discovered; otherwise, False to not print anything to the console.
|
|
53
51
|
Default is False.
|
|
54
|
-
|
|
55
|
-
Specify False for the `areDevicesVerified` argument if you want to speed up
|
|
56
|
-
device discovery, as it takes extra time to verify device connections as they
|
|
57
|
-
are discovered.
|
|
58
52
|
"""
|
|
59
53
|
# validations.
|
|
60
|
-
if
|
|
61
|
-
raise SpotifyApiError(SAAppMessages.ARGUMENT_TYPE_ERROR % ("__init__", '
|
|
62
|
-
|
|
63
|
-
|
|
54
|
+
if zeroconfClient is not None and (not isinstance(zeroconfClient, Zeroconf)):
|
|
55
|
+
raise SpotifyApiError(SAAppMessages.ARGUMENT_TYPE_ERROR % ("__init__", 'zeroconfClient', 'Zeroconf', type(zeroconfClient).__name__), logsi=_logsi)
|
|
56
|
+
|
|
57
|
+
# create the zeroconf client if one was not specified.
|
|
58
|
+
if zeroconfClient is None:
|
|
59
|
+
_logsi.LogVerbose("Creating new Zeroconf instance for discovery")
|
|
60
|
+
zeroconfClient = Zeroconf()
|
|
61
|
+
else:
|
|
62
|
+
_logsi.LogObject(SILevel.Verbose, "Using existing Zeroconf instance for discovery", zeroconfClient)
|
|
64
63
|
|
|
65
64
|
# initialize instance properties.
|
|
66
|
-
self._AreDevicesVerified:bool = areDevicesVerified
|
|
67
65
|
self._DiscoveredDeviceNames:dict = {}
|
|
68
66
|
self._DiscoveryResults:list[ZeroconfDiscoveryResult] = []
|
|
69
67
|
self._PrintToConsole:bool = printToConsole
|
|
70
|
-
self.
|
|
71
|
-
self._VerifiedDevices:dict = {}
|
|
68
|
+
self._Zeroconf = zeroconfClient
|
|
72
69
|
|
|
73
70
|
|
|
74
71
|
def __getitem__(self, key):
|
|
@@ -92,21 +89,6 @@ class SpotifyDiscovery:
|
|
|
92
89
|
return self.ToString()
|
|
93
90
|
|
|
94
91
|
|
|
95
|
-
@property
|
|
96
|
-
def AreDevicesVerified(self) -> bool:
|
|
97
|
-
"""
|
|
98
|
-
Determines if a `Device` object is created for devices that are
|
|
99
|
-
discovered. This property is set by what is passed to the class constructor.
|
|
100
|
-
|
|
101
|
-
If False, then the `VerifiedDevices` property will be empty;
|
|
102
|
-
|
|
103
|
-
If True, then the `VerifiedDevices` property will contain a `Device`
|
|
104
|
-
instance for each device that was detected as part of the discovery process
|
|
105
|
-
and was found in the Spotify User's player devices list.
|
|
106
|
-
"""
|
|
107
|
-
return self._AreDevicesVerified
|
|
108
|
-
|
|
109
|
-
|
|
110
92
|
@property
|
|
111
93
|
def DiscoveredDeviceNames(self) -> dict:
|
|
112
94
|
"""
|
|
@@ -131,23 +113,6 @@ class SpotifyDiscovery:
|
|
|
131
113
|
return self._DiscoveryResults
|
|
132
114
|
|
|
133
115
|
|
|
134
|
-
@property
|
|
135
|
-
def VerifiedDevices(self) -> dict:
|
|
136
|
-
"""
|
|
137
|
-
A dictionary of discovered `Device` instances that were detected on the network.
|
|
138
|
-
|
|
139
|
-
This property is only populated if the `AreDevicesVerified` property is True.
|
|
140
|
-
|
|
141
|
-
Dictionary keys will be in the form of "address:port", where "address" is the device
|
|
142
|
-
ipv4 address and the "port" is the ipv4 port number the Spotify Connect device
|
|
143
|
-
is listening on.
|
|
144
|
-
|
|
145
|
-
Dictionary values will be `Device` instances that represent the discovered
|
|
146
|
-
device.
|
|
147
|
-
"""
|
|
148
|
-
return self._VerifiedDevices
|
|
149
|
-
|
|
150
|
-
|
|
151
116
|
def _OnServiceStateChange(self,
|
|
152
117
|
zeroconf:Zeroconf,
|
|
153
118
|
service_type:str,
|
|
@@ -230,19 +195,6 @@ class SpotifyDiscovery:
|
|
|
230
195
|
# add the device result to the list.
|
|
231
196
|
self._DiscoveryResults.append(result)
|
|
232
197
|
|
|
233
|
-
# are we verifying devices connections? if so, then create a SpotifyClient
|
|
234
|
-
# object, which will verify the connection and gather basic capabilities of the device.
|
|
235
|
-
# we will also add the SpotifyClient instance using the same key as the device name list.
|
|
236
|
-
if self._AreDevicesVerified == True:
|
|
237
|
-
|
|
238
|
-
if deviceKey not in self._VerifiedDevices.keys():
|
|
239
|
-
|
|
240
|
-
# get Spotify Connect player device by it's Name value.
|
|
241
|
-
device:Device = self._SpotifyClient.GetPlayerDevice(deviceName)
|
|
242
|
-
if device is not None:
|
|
243
|
-
self._VerifiedDevices[deviceKey] = device
|
|
244
|
-
result.SpotifyConnectIsInDeviceList = True
|
|
245
|
-
|
|
246
198
|
# trace.
|
|
247
199
|
_logsi.LogObject(SILevel.Verbose, "Discovered Spotify Connect device result: '%s' (%s:%i)" % (deviceName, deviceIpAddress, devicePort), result, excludeNonPublic=True)
|
|
248
200
|
#_logsi.LogArray(SILevel.Verbose, "Discovered Spotify Connect device result.Properties: '%s' (%s:%i)" % (deviceName, deviceIpAddress, devicePort), result.Properties)
|
|
@@ -256,19 +208,19 @@ class SpotifyDiscovery:
|
|
|
256
208
|
pass
|
|
257
209
|
|
|
258
210
|
|
|
259
|
-
def DiscoverDevices(self, timeout:
|
|
211
|
+
def DiscoverDevices(self, timeout:float=2) -> dict:
|
|
260
212
|
"""
|
|
261
213
|
Discover Spotify Connect devices on the local network via the
|
|
262
214
|
ZeroConf (aka MDNS) service.
|
|
263
215
|
|
|
264
216
|
Args:
|
|
265
|
-
timeout (
|
|
217
|
+
timeout (float):
|
|
266
218
|
Maximum amount of time to wait (in seconds) for the
|
|
267
219
|
discovery to complete.
|
|
268
|
-
Default is
|
|
220
|
+
Default is 2 seconds.
|
|
269
221
|
|
|
270
222
|
Returns:
|
|
271
|
-
A dictionary of
|
|
223
|
+
A dictionary of `ZeroconfDiscoveryResult` objects.
|
|
272
224
|
|
|
273
225
|
<details>
|
|
274
226
|
<summary>Sample Code</summary>
|
|
@@ -280,12 +232,9 @@ class SpotifyDiscovery:
|
|
|
280
232
|
# using Queue as a timer (timeout functionality).
|
|
281
233
|
discoveryQueueTimer = Queue()
|
|
282
234
|
|
|
283
|
-
# create the zeroconf service and our listener callback.
|
|
284
|
-
zeroconf:Zeroconf = Zeroconf()
|
|
285
|
-
|
|
286
235
|
# create the zeroconf service browser that will start device discovery.
|
|
287
236
|
_logsi.LogVerbose("Discovery of Spotify Connect devices via Zeroconf is starting ...")
|
|
288
|
-
ServiceBrowser(
|
|
237
|
+
ServiceBrowser(self._Zeroconf, "_spotify-connect._tcp.local.", handlers=[self._OnServiceStateChange])
|
|
289
238
|
|
|
290
239
|
try:
|
|
291
240
|
# give the ServiceBrowser time to discover
|
|
@@ -296,7 +245,7 @@ class SpotifyDiscovery:
|
|
|
296
245
|
# this is not really an exception, but more of an indicator that
|
|
297
246
|
# the timeout has been reached.
|
|
298
247
|
_logsi.LogVerbose("Discovery of Spotify Connect devices via Zeroconf has ended.")
|
|
299
|
-
|
|
248
|
+
|
|
300
249
|
return self._DiscoveredDeviceNames
|
|
301
250
|
|
|
302
251
|
|
|
@@ -315,11 +264,6 @@ class SpotifyDiscovery:
|
|
|
315
264
|
if includeItems == True:
|
|
316
265
|
|
|
317
266
|
for key, deviceName in self._DiscoveredDeviceNames.items():
|
|
318
|
-
|
|
319
|
-
verifiedStatus:str = ''
|
|
320
|
-
device = self._VerifiedDevices.get(key, None)
|
|
321
|
-
if device is not None:
|
|
322
|
-
verifiedStatus = ' (verified - ID=%s)' % device.Id
|
|
323
|
-
msg = "%s\n- %s - %s %s" % (msg, key, deviceName, verifiedStatus)
|
|
267
|
+
msg = "%s\n- %s - %s" % (msg, key, deviceName)
|
|
324
268
|
|
|
325
269
|
return msg
|
|
@@ -71,6 +71,8 @@ class ZeroconfConnect:
|
|
|
71
71
|
# validations.
|
|
72
72
|
if (version is None):
|
|
73
73
|
version = '1.0'
|
|
74
|
+
if (useSSL is None) or (not isinstance(useSSL,bool)):
|
|
75
|
+
useSSL = False
|
|
74
76
|
|
|
75
77
|
# initialize storage.
|
|
76
78
|
self._CPath:str = cpath
|
|
@@ -271,6 +273,8 @@ class ZeroconfConnect:
|
|
|
271
273
|
Args:
|
|
272
274
|
username (str):
|
|
273
275
|
Spotify Connect user name to login with.
|
|
276
|
+
This MUST match the account name (or one of them) that was used to configure Spotify Connect
|
|
277
|
+
on the manufacturer device.
|
|
274
278
|
password (str):
|
|
275
279
|
Spotify Connect user password to login with.
|
|
276
280
|
|
|
@@ -289,6 +293,12 @@ class ZeroconfConnect:
|
|
|
289
293
|
is able to perform the login attempt. You should issue a call to the Spotify Web API `Get Available Devices`
|
|
290
294
|
endpoint to check the current device list to ensure that the device id was successfully added or not.
|
|
291
295
|
|
|
296
|
+
Note that if you don't have a password setup for your Spotify account (e.g. you utilize the "Continue with Google"
|
|
297
|
+
or other non-password methods for login), then you will need to define a "device password" in order to use the
|
|
298
|
+
ZeroConf Connect service; use the [Spotify Set Device Password](https://www.spotify.com/uk/account/set-device-password/)
|
|
299
|
+
page to define a device password. You will then use your Spotify username and the device password to Connect
|
|
300
|
+
to the device.
|
|
301
|
+
|
|
292
302
|
<details>
|
|
293
303
|
<summary>Sample Code</summary>
|
|
294
304
|
```python
|
|
@@ -26,7 +26,7 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
26
26
|
|
|
27
27
|
# initialize our attributes.
|
|
28
28
|
self._AccountReq:str = None
|
|
29
|
-
self._ActiveUser:str =
|
|
29
|
+
self._ActiveUser:str = ""
|
|
30
30
|
self._Aliases:list[ZeroconfGetInfoAlias] = []
|
|
31
31
|
self._Availability:str = None
|
|
32
32
|
self._BrandDisplayName:str = None
|
|
@@ -54,7 +54,7 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
54
54
|
else:
|
|
55
55
|
|
|
56
56
|
self._AccountReq = root.get('accountReq', None)
|
|
57
|
-
self._ActiveUser = root.get('activeUser',
|
|
57
|
+
self._ActiveUser = root.get('activeUser', "")
|
|
58
58
|
self._Availability = root.get('availability', None)
|
|
59
59
|
self._BrandDisplayName = root.get('brandDisplayName', None)
|
|
60
60
|
self._ClientId = root.get('clientID', None)
|
|
@@ -106,7 +106,7 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
106
106
|
"""
|
|
107
107
|
Canonical username of the logged in user (e.g. "31l77y2123456789012345678901").
|
|
108
108
|
|
|
109
|
-
This value will be
|
|
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
112
|
|
|
@@ -192,6 +192,24 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
192
192
|
return self._GroupStatus
|
|
193
193
|
|
|
194
194
|
|
|
195
|
+
@property
|
|
196
|
+
def HasActiveUser(self) -> bool:
|
|
197
|
+
"""
|
|
198
|
+
Returns True if the device has an active user account specified;
|
|
199
|
+
otherwise, False.
|
|
200
|
+
"""
|
|
201
|
+
return (self._ActiveUser != "")
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@property
|
|
205
|
+
def HasAliases(self) -> bool:
|
|
206
|
+
"""
|
|
207
|
+
Returns True if the device has alias entries defined;
|
|
208
|
+
otherwise, False.
|
|
209
|
+
"""
|
|
210
|
+
return (len(self._Aliases) > 0)
|
|
211
|
+
|
|
212
|
+
|
|
195
213
|
@property
|
|
196
214
|
def LibraryVersion(self) -> str:
|
|
197
215
|
"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|