spotifywebapiPython 1.0.42__py3-none-any.whl → 1.0.44__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.

Files changed (33) hide show
  1. {spotifywebapiPython-1.0.42.dist-info → spotifywebapiPython-1.0.44.dist-info}/METADATA +1 -1
  2. {spotifywebapiPython-1.0.42.dist-info → spotifywebapiPython-1.0.44.dist-info}/RECORD +33 -26
  3. spotifywebapipython/const.py +1 -1
  4. spotifywebapipython/docs/__init__.html +24 -2
  5. spotifywebapipython/docs/index.html +2 -2
  6. spotifywebapipython/docs/search.js +1 -1
  7. spotifywebapipython/docs/spotifywebapiPython/const.html +3 -3
  8. spotifywebapipython/docs/spotifywebapiPython/saappmessages.html +2 -2
  9. spotifywebapipython/docs/spotifywebapiPython/sautils.html +2 -2
  10. spotifywebapipython/docs/spotifywebapiPython/spotifyapierror.html +2 -2
  11. spotifywebapipython/docs/spotifywebapiPython/spotifyapimessage.html +2 -2
  12. spotifywebapipython/docs/spotifywebapiPython/spotifyauthtoken.html +2 -2
  13. spotifywebapipython/docs/spotifywebapiPython/spotifyclient.html +376 -36
  14. spotifywebapipython/docs/spotifywebapiPython/spotifydiscovery.html +45 -2
  15. spotifywebapipython/docs/spotifywebapiPython/spotifywebapiauthenticationerror.html +2 -2
  16. spotifywebapipython/docs/spotifywebapiPython/spotifywebapierror.html +2 -2
  17. spotifywebapipython/models/__init__.py +14 -0
  18. spotifywebapipython/models/playlist.py +4 -1
  19. spotifywebapipython/models/playlistsimplified.py +4 -1
  20. spotifywebapipython/models/playlisttracksummary.py +3 -1
  21. spotifywebapipython/models/searchresponse.py +1 -1
  22. spotifywebapipython/models/zeroconfblobbuilder.py +144 -0
  23. spotifywebapipython/models/zeroconfdiscoveryresult.py +451 -0
  24. spotifywebapipython/models/zeroconfgetinfo.py +359 -0
  25. spotifywebapipython/models/zeroconfgetinfoalias.py +96 -0
  26. spotifywebapipython/models/zeroconfgetinfodrmmediaformat.py +90 -0
  27. spotifywebapipython/models/zeroconfproperty.py +93 -0
  28. spotifywebapipython/models/zeroconfresponse.py +108 -0
  29. spotifywebapipython/spotifyclient.py +484 -32
  30. spotifywebapipython/spotifydiscovery.py +98 -11
  31. {spotifywebapiPython-1.0.42.dist-info → spotifywebapiPython-1.0.44.dist-info}/LICENSE +0 -0
  32. {spotifywebapiPython-1.0.42.dist-info → spotifywebapiPython-1.0.44.dist-info}/WHEEL +0 -0
  33. {spotifywebapiPython-1.0.42.dist-info → spotifywebapiPython-1.0.44.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,7 @@ try:
3
3
  from queue import Queue, Empty
4
4
  except ImportError:
5
5
  from Queue import Queue, Empty
6
+ from time import sleep
6
7
  from zeroconf import Zeroconf, ServiceBrowser, ServiceInfo, ServiceStateChange, IPVersion
7
8
 
8
9
  # our package imports.
@@ -10,6 +11,7 @@ from .saappmessages import SAAppMessages
10
11
  from .sautils import export
11
12
  from .models.device import Device
12
13
  from .spotifyclient import SpotifyClient, SpotifyApiError
14
+ from .models import ZeroconfDiscoveryResult, ZeroconfProperty
13
15
 
14
16
  # get smartinspect logger reference; create a new session for this module name.
15
17
  from smartinspectpython.siauto import SIAuto, SILevel, SISession
@@ -63,6 +65,7 @@ class SpotifyDiscovery:
63
65
  # initialize instance properties.
64
66
  self._AreDevicesVerified:bool = areDevicesVerified
65
67
  self._DiscoveredDeviceNames:dict = {}
68
+ self._DiscoveryResults:list[ZeroconfDiscoveryResult] = []
66
69
  self._PrintToConsole:bool = printToConsole
67
70
  self._SpotifyClient:SpotifyClient = spotifyClient
68
71
  self._VerifiedDevices:dict = {}
@@ -119,6 +122,15 @@ class SpotifyDiscovery:
119
122
  return self._DiscoveredDeviceNames
120
123
 
121
124
 
125
+ @property
126
+ def DiscoveryResults(self) -> list[ZeroconfDiscoveryResult]:
127
+ """
128
+ An array of `ZeroconfDiscoveryResult` items that contain discovery details for
129
+ each service that was discovered.
130
+ """
131
+ return self._DiscoveryResults
132
+
133
+
122
134
  @property
123
135
  def VerifiedDevices(self) -> dict:
124
136
  """
@@ -170,6 +182,23 @@ class SpotifyDiscovery:
170
182
  # create device instances for each ipv4 address found.
171
183
  for deviceIpAddress in ipAddressList:
172
184
 
185
+ # create new result instance.
186
+ result:ZeroconfDiscoveryResult = ZeroconfDiscoveryResult()
187
+ result.DeviceName = deviceName
188
+ result.Domain = '.local'
189
+ result.HostIpv4Address = deviceIpAddress
190
+ result.HostIpPort = serviceInfo.port
191
+ result.HostTTL = serviceInfo.host_ttl
192
+ result.Key = serviceInfo.key
193
+ result.Name = serviceInfo.name
194
+ result.OtherTTL = serviceInfo.other_ttl
195
+ result.Priority = serviceInfo.priority
196
+ result.Server = serviceInfo.server
197
+ result.ServerKey = serviceInfo.server_key
198
+ result.ServiceInfo = serviceInfo
199
+ result.ServiceType = serviceType
200
+ result.Weight = serviceInfo.weight
201
+
173
202
  devicePort:int = serviceInfo.port
174
203
  deviceKey:str = '%s:%i' % (deviceIpAddress, devicePort)
175
204
  _logsi.LogVerbose("Discovered Spotify Connect device: %s - %s" % (deviceKey, deviceName))
@@ -177,20 +206,30 @@ class SpotifyDiscovery:
177
206
  print("Discovered Spotify Connect device: %s - %s" % (deviceKey, deviceName))
178
207
  _logsi.LogObject(SILevel.Verbose, "Discovered Spotify Connect device ServiceInfo: %s - %s" % (deviceKey, deviceName), serviceInfo)
179
208
 
180
- # # trace service info propertys if desired.
181
- # # note that the property keys and values must first be decoded to utf-8 encoding.
182
- # if _logsi.IsOn(SILevel.Verbose):
183
- # if serviceInfo.properties is not None:
184
- # dspProperties:dict = {}
185
- # for key, value in serviceInfo.properties.items():
186
- # dspProperties[key.decode('utf-8')] = value.decode('utf-8')
187
- # _logsi.LogDictionary(SILevel.Verbose, "Discovered Spotify Connect device ServiceInfo.Properties: '%s' (%s:%i)" % (deviceName, deviceIpAddress, devicePort), dspProperties)
209
+ # process service info propertys.
210
+ # note that the property keys and values must first be decoded to utf-8 encoding.
211
+ if serviceInfo.properties is not None:
212
+ dspProperties:dict = {}
213
+ for key, value in serviceInfo.properties.items():
214
+ keyStr = key.decode('utf-8')
215
+ valueStr = value.decode('utf-8')
216
+ result.Properties.append(ZeroconfProperty(keyStr, valueStr))
217
+ dspProperties[keyStr] = valueStr
218
+ # check for Spotify Connect common properties.
219
+ if keyStr.lower() == 'cpath':
220
+ result.SpotifyConnectCPath = valueStr
221
+ elif keyStr.lower() == 'version':
222
+ result.SpotifyConnectVersion = valueStr
223
+ _logsi.LogDictionary(SILevel.Verbose, "Discovered Spotify Connect device ServiceInfo.Properties: '%s' (%s:%i)" % (deviceName, deviceIpAddress, devicePort), dspProperties)
188
224
 
189
225
  # add the device name to the list (if not already added) using its
190
226
  # ipv4 address and port number as the key.
191
227
  if deviceKey not in self._DiscoveredDeviceNames.keys():
192
228
  self._DiscoveredDeviceNames[deviceKey] = deviceName
193
229
 
230
+ # add the device result to the list.
231
+ self._DiscoveryResults.append(result)
232
+
194
233
  # are we verifying devices connections? if so, then create a SpotifyClient
195
234
  # object, which will verify the connection and gather basic capabilities of the device.
196
235
  # we will also add the SpotifyClient instance using the same key as the device name list.
@@ -198,12 +237,15 @@ class SpotifyDiscovery:
198
237
 
199
238
  if deviceKey not in self._VerifiedDevices.keys():
200
239
 
201
- #device:SpotifyClient = SpotifyClient(host=deviceIpAddress, port=devicePort)
202
-
203
240
  # get Spotify Connect player device by it's Name value.
204
241
  device:Device = self._SpotifyClient.GetPlayerDevice(deviceName)
205
242
  if device is not None:
206
243
  self._VerifiedDevices[deviceKey] = device
244
+ result.SpotifyConnectIsInDeviceList = True
245
+
246
+ # trace.
247
+ _logsi.LogObject(SILevel.Verbose, "Discovered Spotify Connect device result: '%s' (%s:%i)" % (deviceName, deviceIpAddress, devicePort), result, excludeNonPublic=True)
248
+ #_logsi.LogArray(SILevel.Verbose, "Discovered Spotify Connect device result.Properties: '%s' (%s:%i)" % (deviceName, deviceIpAddress, devicePort), result.Properties)
207
249
 
208
250
  elif (serviceStateChange is ServiceStateChange.Removed):
209
251
  _logsi.LogVerbose("Discovered Spotify Connect device removal (ignored): '%s' (%s:%s)", serviceName, serviceType, serviceStateChange)
@@ -258,6 +300,52 @@ class SpotifyDiscovery:
258
300
  return self._DiscoveredDeviceNames
259
301
 
260
302
 
303
+ def BroadcastService(self, serviceInfo:ServiceInfo, port:int=5353) -> None:
304
+ """
305
+ Generate a Zeroconf / mDNS broadcast to announce a service, and sends the broadcast out.
306
+
307
+ Args:
308
+ serviceInfo (ServiceInfo):
309
+ Service information to broadcast.
310
+ port (int):
311
+ mDNS port number to send the broadcast on.
312
+ Default is 5353.
313
+ """
314
+ try:
315
+
316
+ # create the zeroconf service.
317
+ zeroconf:Zeroconf = Zeroconf(ip_version=IPVersion.V4Only)
318
+
319
+ # # TEST TODO - hardcoded serviceinfo properties for testing.
320
+ # serviceType:str = '_spotify-connect._tcp.local.'
321
+ # serviceName:str = 'Bose-ST10-95._spotify-connect._tcp.local.'
322
+ # parsedAddresses:list[str] = ['192.168.1.82']
323
+ # port:int = 8200
324
+ # hostTTL:int = 120
325
+ # priority:int = 0
326
+ # otherTTL:int = 4500
327
+ # server:str = 'Bose-SM2-987bf3244-95.local.'
328
+ # weight:int = 0
329
+ # properties:dict = {b'CPath': b'/zc', b'VERSION': b'1.0'}
330
+
331
+ # # create the zeroconf serviceinfo object.
332
+ # zcfServiceInfo:ServiceInfo = ServiceInfo(serviceType, serviceName, port, weight, priority, properties, server, hostTTL, otherTTL, parsed_addresses=parsedAddresses)
333
+
334
+ # generate a broadcast packet to announce the service.
335
+ _logsi.LogVerbose("Generating Zeroconf Service Broadcast for service: '%s'" % serviceInfo.name)
336
+ dnsOutgoing = zeroconf.generate_service_broadcast(serviceInfo, serviceInfo.host_ttl, True)
337
+
338
+ # send the broadcast packet.
339
+ _logsi.LogVerbose("Sending Zeroconf Service Broadcast for service: '%s'" % serviceInfo.name)
340
+ zeroconf.send(dnsOutgoing, addr=None, port=port)
341
+
342
+ except Exception as ex:
343
+
344
+ # this is not really an exception, but more of an indicator that
345
+ # the timeout has been reached.
346
+ _logsi.LogException("Zeroconf Broadcast Service exception: %s" % str(ex), ex, logToSystemLogger=False)
347
+
348
+
261
349
  def ToString(self, includeItems:bool=False) -> str:
262
350
  """
263
351
  Returns a displayable string representation of the class.
@@ -273,7 +361,6 @@ class SpotifyDiscovery:
273
361
  if includeItems == True:
274
362
 
275
363
  for key, deviceName in self._DiscoveredDeviceNames.items():
276
-
277
364
  device:Device
278
365
  verifiedStatus:str = ''
279
366
  device = self._VerifiedDevices.get(key, None)