spotifywebapiPython 1.0.58__py3-none-any.whl → 1.0.60__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 (24) hide show
  1. {spotifywebapiPython-1.0.58.dist-info → spotifywebapiPython-1.0.60.dist-info}/METADATA +1 -1
  2. {spotifywebapiPython-1.0.58.dist-info → spotifywebapiPython-1.0.60.dist-info}/RECORD +24 -24
  3. spotifywebapipython/const.py +1 -1
  4. spotifywebapipython/docs/__init__.html +18 -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 +16 -7
  14. spotifywebapipython/docs/spotifywebapiPython/spotifydiscovery.html +5 -5
  15. spotifywebapipython/docs/spotifywebapiPython/spotifywebapiauthenticationerror.html +2 -2
  16. spotifywebapipython/docs/spotifywebapiPython/spotifywebapierror.html +2 -2
  17. spotifywebapipython/models/spotifyconnectdevices.py +2 -1
  18. spotifywebapipython/models/zeroconfdiscoveryresult.py +36 -12
  19. spotifywebapipython/spotifyclient.py +90 -43
  20. spotifywebapipython/spotifydiscovery.py +52 -56
  21. spotifywebapipython/zeroconfapi/zeroconfconnect.py +38 -50
  22. {spotifywebapiPython-1.0.58.dist-info → spotifywebapiPython-1.0.60.dist-info}/LICENSE +0 -0
  23. {spotifywebapiPython-1.0.58.dist-info → spotifywebapiPython-1.0.60.dist-info}/WHEEL +0 -0
  24. {spotifywebapiPython-1.0.58.dist-info → spotifywebapiPython-1.0.60.dist-info}/top_level.txt +0 -0
@@ -5955,7 +5955,8 @@ class SpotifyClient:
5955
5955
  to the local network. A Spotify Zeroconf API `getInfo` call is then issued for each device
5956
5956
  that was found to retrieve device information. A Spotify Zeroconf API `addUser` call is also
5957
5957
  issued for each device that does not have an active user context established, OR if the currently
5958
- active user context does not match the `SpotifyConnectUsername` argument specified on the class constructor.
5958
+ active user context does not match the `SpotifyConnectUsername` argument specified on the class
5959
+ constructor and the `verifyUserContext` argument is True.
5959
5960
 
5960
5961
  The user context switch is bypassed if the `verifyUserContext` argument is False. If the user context
5961
5962
  is to be switched, then a Disconnect will be issued if a user context is active on the device followed
@@ -6042,7 +6043,10 @@ class SpotifyClient:
6042
6043
  zcfResult:ZeroconfResponse
6043
6044
 
6044
6045
  # create a ZeroconfConnect object to access the device.
6045
- zconn:ZeroconfConnect = ZeroconfConnect(discoverResult.HostIpv4Address,
6046
+ # note that we are using the "HostIpAddress" property value here, with "Server" as a fallback.
6047
+ # the "Server" property is an alias, which must be resolved via a DNS lookup under
6048
+ # the covers and adds a significant delay (2-3 seconds!) to the activation time.
6049
+ zconn:ZeroconfConnect = ZeroconfConnect(discoverResult.HostIpAddress,
6046
6050
  discoverResult.HostIpPort,
6047
6051
  discoverResult.SpotifyConnectCPath,
6048
6052
  useSSL=False)
@@ -7953,7 +7957,10 @@ class SpotifyClient:
7953
7957
 
7954
7958
  # get the id from the device via the zeroconf API getInfo endpoint, as the id is not
7955
7959
  # returned in the zeroconf discovery result.
7956
- zconn:ZeroconfConnect = ZeroconfConnect(discoverResult.HostIpv4Address,
7960
+ # note that we are using the "HostIpAddress" property value here, with "Server" as a fallback.
7961
+ # the "Server" property is an alias, which must be resolved via a DNS lookup under
7962
+ # the covers and adds a significant delay (2-3 seconds!) to the activation time.
7963
+ zconn:ZeroconfConnect = ZeroconfConnect(discoverResult.HostIpAddress,
7957
7964
  discoverResult.HostIpPort,
7958
7965
  discoverResult.SpotifyConnectCPath,
7959
7966
  useSSL=False)
@@ -7967,7 +7974,7 @@ class SpotifyClient:
7967
7974
 
7968
7975
  # we will also call the GetPlayerDevices method, in case we have any dynamic devices.
7969
7976
  # 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
7977
+ # process, but exist in the player device list. these are usually Spotify Connect
7971
7978
  # web or mobile players with temporary device id's.
7972
7979
  devices:list[Device] = self.GetPlayerDevices(True)
7973
7980
 
@@ -9467,14 +9474,16 @@ class SpotifyClient:
9467
9474
  _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
9468
9475
 
9469
9476
 
9470
- def PlayerMediaPlayContext(self,
9471
- contextUri:str,
9472
- offsetUri:str=None,
9473
- offsetPosition:int=None,
9474
- positionMS:int=0,
9475
- deviceId:str=None,
9476
- delay:float=0.50
9477
- ) -> None:
9477
+ def PlayerMediaPlayContext(
9478
+ self,
9479
+ contextUri:str,
9480
+ offsetUri:str=None,
9481
+ offsetPosition:int=None,
9482
+ positionMS:int=0,
9483
+ deviceId:str=None,
9484
+ delay:float=0.50,
9485
+ resolveDeviceId:bool=True,
9486
+ ) -> None:
9478
9487
  """
9479
9488
  Start playing one or more tracks of the specified context on a Spotify Connect device.
9480
9489
 
@@ -9513,6 +9522,9 @@ class SpotifyClient:
9513
9522
  This delay will give the spotify web api time to process the change before
9514
9523
  another command is issued.
9515
9524
  Default is 0.50; value range is 0 - 10.
9525
+ resolveDeviceId (bool):
9526
+ True to resolve the supplied `deviceId` value; otherwise, False not resolve the `deviceId`
9527
+ value as it has already been resolved.
9516
9528
 
9517
9529
  Raises:
9518
9530
  SpotifyWebApiError:
@@ -9559,14 +9571,18 @@ class SpotifyClient:
9559
9571
  apiMethodParms.AppendKeyValue("positionMS", positionMS)
9560
9572
  apiMethodParms.AppendKeyValue("deviceId", deviceId)
9561
9573
  apiMethodParms.AppendKeyValue("delay", delay)
9574
+ apiMethodParms.AppendKeyValue("resolveDeviceId", resolveDeviceId)
9562
9575
  _logsi.LogMethodParmList(SILevel.Verbose, "Spotify Connect device play context", apiMethodParms)
9563
9576
 
9564
9577
  # validations.
9565
9578
  delay = validateDelay(delay, 0.50, 10)
9566
9579
 
9567
- # ensure the specified device id / name is active and available, and
9568
- # the user context is set correctly.
9569
- deviceId = self.PlayerResolveDeviceId(deviceId, verifyUserContext=True)
9580
+ # has the device id been resolved?
9581
+ if (resolveDeviceId):
9582
+
9583
+ # ensure the specified device id / name is active and available, and
9584
+ # the user context is set correctly.
9585
+ deviceId = self.PlayerResolveDeviceId(deviceId, verifyUserContext=True)
9570
9586
 
9571
9587
  # build spotify web api request parameters.
9572
9588
  reqData:dict = \
@@ -9613,11 +9629,13 @@ class SpotifyClient:
9613
9629
  _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
9614
9630
 
9615
9631
 
9616
- def PlayerMediaPlayTrackFavorites(self,
9617
- deviceId:str=None,
9618
- shuffle:bool=True,
9619
- delay:float=0.50
9620
- ) -> None:
9632
+ def PlayerMediaPlayTrackFavorites(
9633
+ self,
9634
+ deviceId:str=None,
9635
+ shuffle:bool=True,
9636
+ delay:float=0.50,
9637
+ resolveDeviceId:bool=True,
9638
+ ) -> None:
9621
9639
  """
9622
9640
  Get a list of the tracks saved in the current Spotify user's 'Your Library'
9623
9641
  and starts playing them.
@@ -9635,6 +9653,9 @@ class SpotifyClient:
9635
9653
  This delay will give the spotify web api time to process the change before
9636
9654
  another command is issued.
9637
9655
  Default is 0.50; value range is 0 - 10.
9656
+ resolveDeviceId (bool):
9657
+ True to resolve the supplied `deviceId` value; otherwise, False not resolve the `deviceId`
9658
+ value as it has already been resolved.
9638
9659
 
9639
9660
  Raises:
9640
9661
  SpotifyWebApiError:
@@ -9665,6 +9686,7 @@ class SpotifyClient:
9665
9686
  apiMethodParms.AppendKeyValue("deviceId", deviceId)
9666
9687
  apiMethodParms.AppendKeyValue("shuffle", shuffle)
9667
9688
  apiMethodParms.AppendKeyValue("delay", delay)
9689
+ apiMethodParms.AppendKeyValue("resolveDeviceId", resolveDeviceId)
9668
9690
  _logsi.LogMethodParmList(SILevel.Verbose, "Spotify Connect device play track favorites", apiMethodParms)
9669
9691
 
9670
9692
  # validations.
@@ -9682,15 +9704,19 @@ class SpotifyClient:
9682
9704
  for trackSaved in tracks.Items:
9683
9705
  arrUris.append(trackSaved.Track.Uri)
9684
9706
 
9685
- # ensure the specified device id / name is active and available, and
9686
- # the user context is set correctly.
9687
- deviceId = self.PlayerResolveDeviceId(deviceId, verifyUserContext=True)
9707
+ # has the device id been resolved?
9708
+ if (resolveDeviceId):
9709
+
9710
+ # ensure the specified device id / name is active and available, and
9711
+ # the user context is set correctly.
9712
+ deviceId = self.PlayerResolveDeviceId(deviceId, verifyUserContext=True)
9688
9713
 
9689
9714
  # set desired shuffle mode.
9690
9715
  self.PlayerSetShuffleMode(shuffle, deviceId, delay)
9691
9716
 
9692
9717
  # play the tracks.
9693
- self.PlayerMediaPlayTracks(arrUris, deviceId=deviceId, delay=delay)
9718
+ # indicate device id has already been resolved.
9719
+ self.PlayerMediaPlayTracks(arrUris, deviceId=deviceId, delay=delay, resolveDeviceId=False)
9694
9720
 
9695
9721
  # process results.
9696
9722
  # no results to process - this is pass or fail.
@@ -9710,12 +9736,14 @@ class SpotifyClient:
9710
9736
  _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
9711
9737
 
9712
9738
 
9713
- def PlayerMediaPlayTracks(self,
9714
- uris:list[str],
9715
- positionMS:int=0,
9716
- deviceId:str=None,
9717
- delay:float=0.50
9718
- ) -> None:
9739
+ def PlayerMediaPlayTracks(
9740
+ self,
9741
+ uris:list[str],
9742
+ positionMS:int=0,
9743
+ deviceId:str=None,
9744
+ delay:float=0.50,
9745
+ resolveDeviceId:bool=True,
9746
+ ) -> None:
9719
9747
  """
9720
9748
  Start playing one or more tracks on the specified Spotify Connect device.
9721
9749
 
@@ -9744,6 +9772,9 @@ class SpotifyClient:
9744
9772
  This delay will give the spotify web api time to process the change before
9745
9773
  another command is issued.
9746
9774
  Default is 0.50; value range is 0 - 10.
9775
+ resolveDeviceId (bool):
9776
+ True to resolve the supplied `deviceId` value; otherwise, False not resolve the `deviceId`
9777
+ value as it has already been resolved.
9747
9778
 
9748
9779
  Raises:
9749
9780
  SpotifyWebApiError:
@@ -9774,6 +9805,7 @@ class SpotifyClient:
9774
9805
  apiMethodParms.AppendKeyValue("positionMS", positionMS)
9775
9806
  apiMethodParms.AppendKeyValue("deviceId", deviceId)
9776
9807
  apiMethodParms.AppendKeyValue("delay", delay)
9808
+ apiMethodParms.AppendKeyValue("resolveDeviceId", resolveDeviceId)
9777
9809
  _logsi.LogMethodParmList(SILevel.Verbose, "Spotify Connect device play tracks", apiMethodParms)
9778
9810
 
9779
9811
  # validations.
@@ -9788,10 +9820,13 @@ class SpotifyClient:
9788
9820
  arrUris = uris.split(',')
9789
9821
  for idx in range(0, len(arrUris)):
9790
9822
  arrUris[idx] = arrUris[idx].strip()
9823
+
9824
+ # has the device id been resolved?
9825
+ if (resolveDeviceId):
9791
9826
 
9792
- # ensure the specified device id / name is active and available, and
9793
- # the user context is set correctly.
9794
- deviceId = self.PlayerResolveDeviceId(deviceId, verifyUserContext=True)
9827
+ # ensure the specified device id / name is active and available, and
9828
+ # the user context is set correctly.
9829
+ deviceId = self.PlayerResolveDeviceId(deviceId, verifyUserContext=True)
9795
9830
 
9796
9831
  # build spotify web api request parameters.
9797
9832
  reqData:dict = \
@@ -10378,7 +10413,10 @@ class SpotifyClient:
10378
10413
  zcfResult:ZeroconfResponse
10379
10414
 
10380
10415
  # create a ZeroconfConnect object to access the device.
10381
- zconn:ZeroconfConnect = ZeroconfConnect(discoverResult.HostIpv4Address,
10416
+ # note that we are using the "HostIpAddress" property value here, with "Server" as a fallback.
10417
+ # the "Server" property is an alias, which must be resolved via a DNS lookup under
10418
+ # the covers and adds a significant delay (2-3 seconds!) to the activation time.
10419
+ zconn:ZeroconfConnect = ZeroconfConnect(discoverResult.HostIpAddress,
10382
10420
  discoverResult.HostIpPort,
10383
10421
  discoverResult.SpotifyConnectCPath,
10384
10422
  useSSL=False)
@@ -10424,7 +10462,7 @@ class SpotifyClient:
10424
10462
 
10425
10463
  # did we resolve the device id?
10426
10464
  if deviceIdResult is None:
10427
- _logsi.LogWarning("Spotify Connect Device '%s' could not be found; please ensure that the specified device is powered on and available on the local network" % (deviceValue))
10465
+ _logsi.LogWarning("Spotify Connect device name '%s' could not be resolved; please ensure that the specified device is powered on and available on the local network" % (deviceValue))
10428
10466
 
10429
10467
  # return the resolved device id.
10430
10468
  return deviceIdResult
@@ -10739,11 +10777,13 @@ class SpotifyClient:
10739
10777
  _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
10740
10778
 
10741
10779
 
10742
- def PlayerTransferPlayback(self,
10743
- deviceId:str=None,
10744
- play:bool=True,
10745
- delay:float=0.50
10746
- ) -> None:
10780
+ def PlayerTransferPlayback(
10781
+ self,
10782
+ deviceId:str=None,
10783
+ play:bool=True,
10784
+ delay:float=0.50,
10785
+ resolveDeviceId:bool=True,
10786
+ ) -> None:
10747
10787
  """
10748
10788
  Transfer playback to a new Spotify Connect device and optionally begin playback.
10749
10789
 
@@ -10764,6 +10804,9 @@ class SpotifyClient:
10764
10804
  This delay will give the spotify web api time to process the change before
10765
10805
  another command is issued.
10766
10806
  Default is 0.50; value range is 0 - 10.
10807
+ resolveDeviceId (bool):
10808
+ True to resolve the supplied `deviceId` value; otherwise, False not resolve the `deviceId`
10809
+ value as it has already been resolved.
10767
10810
 
10768
10811
  Raises:
10769
10812
  SpotifyWebApiError:
@@ -10793,14 +10836,18 @@ class SpotifyClient:
10793
10836
  apiMethodParms.AppendKeyValue("deviceId", deviceId)
10794
10837
  apiMethodParms.AppendKeyValue("play", play)
10795
10838
  apiMethodParms.AppendKeyValue("delay", delay)
10839
+ apiMethodParms.AppendKeyValue("resolveDeviceId", resolveDeviceId)
10796
10840
  _logsi.LogMethodParmList(SILevel.Verbose, "Transfer playback to a new Spotify Connect device", apiMethodParms)
10797
10841
 
10798
10842
  # validations.
10799
10843
  delay = validateDelay(delay, 0.50, 10)
10800
10844
 
10801
- # ensure the specified device id / name is active and available, and
10802
- # the user context is set correctly.
10803
- deviceId = self.PlayerResolveDeviceId(deviceId, verifyUserContext=True)
10845
+ # has the device id been resolved?
10846
+ if (resolveDeviceId):
10847
+
10848
+ # ensure the specified device id / name is active and available, and
10849
+ # the user context is set correctly.
10850
+ deviceId = self.PlayerResolveDeviceId(deviceId, verifyUserContext=True)
10804
10851
 
10805
10852
  # build spotify web api request parameters.
10806
10853
  reqData:dict = \
@@ -94,9 +94,9 @@ class SpotifyDiscovery:
94
94
  """
95
95
  A dictionary of discovered device names that were detected by the discovery process.
96
96
 
97
- Dictionary keys will be in the form of "address:port", where "address" is the device
98
- ipv4 address and the "port" is the ipv4 port number the Spotify Connect device
99
- is listening on.
97
+ Dictionary keys will be in the form of "'name' (address:port)", where "name" is the
98
+ device name, "address" is the device server address and the "port" is the ipv4 port
99
+ number the Spotify Connect device is listening on.
100
100
 
101
101
  Dictionary values will be the device names (e.g. "Web Player (Chrome)", etc.). This SHOULD
102
102
  match the name of the device as displayed in the Spotify App, but is not guaranteed.
@@ -152,60 +152,56 @@ class SpotifyDiscovery:
152
152
  if (ipAddressList is None):
153
153
  return
154
154
 
155
- # create device instances for each ipv4 address found.
156
- for deviceIpAddress in ipAddressList:
155
+ # create new result instance.
156
+ result:ZeroconfDiscoveryResult = ZeroconfDiscoveryResult()
157
+ result.DeviceName = deviceName
158
+ result.Domain = '.local'
159
+ for item in ipAddressList:
160
+ result.HostIpAddresses.append(item)
161
+ result.HostIpPort = serviceInfo.port
162
+ result.HostTTL = serviceInfo.host_ttl
163
+ result.Key = serviceInfo.key
164
+ result.Name = serviceInfo.name
165
+ result.OtherTTL = serviceInfo.other_ttl
166
+ result.Priority = serviceInfo.priority
167
+ result.Server = serviceInfo.server
168
+ result.ServerKey = serviceInfo.server_key
169
+ result.ServiceInfo = serviceInfo
170
+ result.ServiceType = serviceType
171
+ result.Weight = serviceInfo.weight
157
172
 
158
- # create new result instance.
159
- result:ZeroconfDiscoveryResult = ZeroconfDiscoveryResult()
160
- result.DeviceName = deviceName
161
- result.Domain = '.local'
162
- result.HostIpv4Address = deviceIpAddress
163
- result.HostIpPort = serviceInfo.port
164
- result.HostTTL = serviceInfo.host_ttl
165
- result.Key = serviceInfo.key
166
- result.Name = serviceInfo.name
167
- result.OtherTTL = serviceInfo.other_ttl
168
- result.Priority = serviceInfo.priority
169
- result.Server = serviceInfo.server
170
- result.ServerKey = serviceInfo.server_key
171
- result.ServiceInfo = serviceInfo
172
- result.ServiceType = serviceType
173
- result.Weight = serviceInfo.weight
173
+ # formulate a unique key for this device.
174
+ deviceKey:str = "'%s' (%s:%i)" % (deviceName, result.HostIpAddress, result.HostIpPort)
175
+ _logsi.LogVerbose("Discovered Spotify Connect device: %s %s" % (deviceKey, result.HostIpAddresses))
176
+ if (self._PrintToConsole == True):
177
+ print("Discovered Spotify Connect device: %s [%s]" % (deviceKey, result.HostIpAddresses))
178
+ _logsi.LogObject(SILevel.Verbose, "Discovered Spotify Connect device ServiceInfo: %s" % (deviceKey), serviceInfo)
174
179
 
175
- devicePort:int = serviceInfo.port
176
- deviceKey:str = '%s:%i' % (deviceIpAddress, devicePort)
177
- _logsi.LogVerbose("Discovered Spotify Connect device: %s - %s" % (deviceKey, deviceName))
178
- if (self._PrintToConsole == True):
179
- print("Discovered Spotify Connect device: %s - %s" % (deviceKey, deviceName))
180
- _logsi.LogObject(SILevel.Verbose, "Discovered Spotify Connect device ServiceInfo: %s - %s" % (deviceKey, deviceName), serviceInfo)
181
-
182
- # process service info propertys.
183
- # note that the property keys and values must first be decoded to utf-8 encoding.
184
- if serviceInfo.properties is not None:
185
- dspProperties:dict = {}
186
- for key, value in serviceInfo.properties.items():
187
- keyStr = key.decode('utf-8')
188
- valueStr = value.decode('utf-8')
189
- result.Properties.append(ZeroconfProperty(keyStr, valueStr))
190
- dspProperties[keyStr] = valueStr
191
- # check for Spotify Connect common properties.
192
- if keyStr.lower() == 'cpath':
193
- result.SpotifyConnectCPath = valueStr
194
- elif keyStr.lower() == 'version':
195
- result.SpotifyConnectVersion = valueStr
196
- _logsi.LogDictionary(SILevel.Verbose, "Discovered Spotify Connect device ServiceInfo.Properties: '%s' (%s:%i)" % (deviceName, deviceIpAddress, devicePort), dspProperties)
197
-
198
- # add the device name to the list (if not already added) using its
199
- # ipv4 address and port number as the key.
200
- if deviceKey not in self._DiscoveredDeviceNames.keys():
201
- self._DiscoveredDeviceNames[deviceKey] = deviceName
202
-
203
- # add the device result to the list.
204
- self._DiscoveryResults.append(result)
205
-
206
- # trace.
207
- _logsi.LogObject(SILevel.Verbose, "Discovered Spotify Connect device result: '%s' (%s:%i)" % (deviceName, deviceIpAddress, devicePort), result, excludeNonPublic=True)
208
- #_logsi.LogArray(SILevel.Verbose, "Discovered Spotify Connect device result.Properties: '%s' (%s:%i)" % (deviceName, deviceIpAddress, devicePort), result.Properties)
180
+ # process service info propertys.
181
+ # note that the property keys and values must first be decoded to utf-8 encoding.
182
+ if serviceInfo.properties is not None:
183
+ dspProperties:dict = {}
184
+ for key, value in serviceInfo.properties.items():
185
+ keyStr = key.decode('utf-8')
186
+ valueStr = value.decode('utf-8')
187
+ result.Properties.append(ZeroconfProperty(keyStr, valueStr))
188
+ dspProperties[keyStr] = valueStr
189
+ # check for Spotify Connect common properties.
190
+ if keyStr.lower() == 'cpath':
191
+ result.SpotifyConnectCPath = valueStr
192
+ elif keyStr.lower() == 'version':
193
+ result.SpotifyConnectVersion = valueStr
194
+ _logsi.LogDictionary(SILevel.Verbose, "Discovered Spotify Connect device ServiceInfo.Properties: %s" % (deviceKey), dspProperties)
195
+
196
+ # add the device name to the list (if not already added).
197
+ if deviceKey not in self._DiscoveredDeviceNames.keys():
198
+ self._DiscoveredDeviceNames[deviceKey] = deviceName
199
+
200
+ # add the device result to the list.
201
+ self._DiscoveryResults.append(result)
202
+
203
+ # trace.
204
+ _logsi.LogObject(SILevel.Verbose, "Discovered Spotify Connect device result: %s" % (deviceKey), result, excludeNonPublic=True)
209
205
 
210
206
  elif (serviceStateChange is ServiceStateChange.Removed):
211
207
  _logsi.LogVerbose("Discovered Spotify Connect device removal (ignored): '%s' (%s:%s)", serviceName, serviceType, serviceStateChange)
@@ -272,6 +268,6 @@ class SpotifyDiscovery:
272
268
  if includeItems == True:
273
269
 
274
270
  for key, deviceName in self._DiscoveredDeviceNames.items():
275
- msg = "%s\n- %s - %s" % (msg, key, deviceName)
271
+ msg = "%s\n- %s" % (msg, key)
276
272
 
277
273
  return msg
@@ -14,6 +14,7 @@ from .zeroconfgetinfo import ZeroconfGetInfo
14
14
  from ..saappmessages import SAAppMessages
15
15
  from ..sautils import export, validateDelay
16
16
  from ..spotifyapierror import SpotifyApiError
17
+ from ..spotifywebapierror import SpotifyWebApiError
17
18
  from ..const import (
18
19
  TRACE_MSG_DELAY_DEVICE,
19
20
  )
@@ -41,8 +42,8 @@ class ZeroconfConnect:
41
42
  """
42
43
 
43
44
  def __init__(self,
44
- hostIpv4Address:str,
45
- hostIpPort:str,
45
+ hostIpAddress:str,
46
+ hostIpPort:int,
46
47
  cpath:str,
47
48
  version:str='1.0',
48
49
  useSSL:bool=False
@@ -51,9 +52,9 @@ class ZeroconfConnect:
51
52
  Initializes a new instance of the class.
52
53
 
53
54
  Args:
54
- hostIpv4Address (str):
55
- IPV4 address (as a string) at which the Spotify Connect Zeroconf API can be reached
56
- on the Spotify Connect device (e.g. "192.168.1.81").
55
+ hostIpAddress (str):
56
+ IP address or alias at which the Spotify Connect Zeroconf API can be reached
57
+ on the Spotify Connect device (e.g. "192.168.1.81", "Bose-SM2-341513fbeeae.local.", etc).
57
58
  hostIpPort (int):
58
59
  Port number (as an integer) at which the Spotify Connect Zeroconf API can be reached
59
60
  on the Spotify Connect device (e.g. "8200").
@@ -80,7 +81,7 @@ class ZeroconfConnect:
80
81
  # initialize storage.
81
82
  self._CPath:str = cpath
82
83
  self._HostIpPort:int = hostIpPort
83
- self._HostIpv4Address:str = hostIpv4Address
84
+ self._HostIpAddress:str = hostIpAddress
84
85
  self._UseSSL:bool = useSSL
85
86
  self._Version:str = version
86
87
 
@@ -97,12 +98,12 @@ class ZeroconfConnect:
97
98
 
98
99
 
99
100
  @property
100
- def HostIpv4Address(self) -> str:
101
+ def HostIpAddress(self) -> str:
101
102
  """
102
- IPV4 address (as a string) at which the Spotify Connect Zeroconf API can be reached
103
- on the Spotify Connect device (e.g. "192.168.1.81").
103
+ IP address or alias at which the Spotify Connect Zeroconf API can be reached
104
+ on the Spotify Connect device (e.g. "192.168.1.81", "Bose-SM2-341513fbeeae.local.", etc).
104
105
  """
105
- return self._HostIpv4Address
106
+ return self._HostIpAddress
106
107
 
107
108
 
108
109
  @property
@@ -191,43 +192,30 @@ class ZeroconfConnect:
191
192
  if (response.headers):
192
193
  _logsi.LogCollection(SILevel.Debug, "ZeroconfConnect http response [%s-%s]: '%s' (headers)" % (response.status_code, response.reason, responseUrl), response.headers.items())
193
194
 
194
- if response.content is not None:
195
+ # do we have response data?
196
+ if (response.content is not None) and (len(response.content) > 0):
195
197
 
196
- # do response headers contain a content-type value?
197
- # if so, we will use it to determine how to convert the response data.
198
- if response.headers:
199
- if 'content-type' in response.headers:
200
- contentType = response.headers['content-type']
201
-
202
- # do we have response data?
203
- if len(response.content) == 0:
204
-
205
- # some requests will not return a response, which is ok.
206
- responseData = None
207
- _logsi.LogVerbose("ZeroconfConnect http response [%s-%s]: '%s' (no data)" % (response.status_code, response.reason, responseUrl))
208
-
209
- elif (contentType is not None) and (contentType.find('json') > -1):
210
-
211
- # response is json.
212
- # do not use the "response.json()" method to parse JSON responses, as it is unreliable!
213
- data = response.content.decode('utf-8')
214
- responseData = json.loads(data)
215
-
216
- if _logsi.IsOn(SILevel.Verbose):
217
- if isinstance(responseData, dict):
218
- _logsi.LogDictionary(SILevel.Verbose, "ZeroconfConnect http response [%s-%s]: '%s' (json dict)" % (response.status_code, response.reason, responseUrl), responseData)
219
- elif isinstance(responseData, list):
220
- _logsi.LogArray(SILevel.Verbose, "ZeroconfConnect http response [%s-%s]: '%s' (json array)" % (response.status_code, response.reason, responseUrl), responseData)
221
- else:
222
- _logsi.LogObject(SILevel.Verbose, "ZeroconfConnect http response [%s-%s]: '%s' (json object)" % (response.status_code, response.reason, responseUrl), responseData)
223
-
224
- else:
198
+ # convert response to JSON object.
199
+ # ALL Spotify Connect Zeroconf API responses SHOULD be JSON format!
200
+ # do not use the "response.json()" method to parse JSON responses, as it is unreliable!
201
+ data = response.content.decode('utf-8')
202
+ responseData = json.loads(data)
225
203
 
226
- # no - treat it as utf-8 encoded data.
227
- responseUTF8 = response.content.decode('utf-8')
228
- _logsi.LogText(SILevel.Error, "ZeroconfConnect http response [%s-%s]: '%s' (utf-8)" % (response.status_code, response.reason, responseUrl), responseUTF8)
229
- responseData = responseUTF8
230
-
204
+ if _logsi.IsOn(SILevel.Verbose):
205
+ if isinstance(responseData, dict):
206
+ _logsi.LogDictionary(SILevel.Verbose, "ZeroconfConnect http response [%s-%s]: '%s' (json dict)" % (response.status_code, response.reason, responseUrl), responseData)
207
+ elif isinstance(responseData, list):
208
+ _logsi.LogArray(SILevel.Verbose, "ZeroconfConnect http response [%s-%s]: '%s' (json array)" % (response.status_code, response.reason, responseUrl), responseData)
209
+ else:
210
+ _logsi.LogObject(SILevel.Verbose, "ZeroconfConnect http response [%s-%s]: '%s' (json object)" % (response.status_code, response.reason, responseUrl), responseData)
211
+ pass
212
+
213
+ else:
214
+
215
+ # raise an exception, as we are expecting a JSON-formatted response!
216
+ errMessage = response.content.decode('utf-8')
217
+ raise SpotifyWebApiError(response.status_code, errMessage, methodName, response.reason, _logsi)
218
+
231
219
  except SpotifyZeroconfApiError: raise # pass handled exceptions on thru
232
220
  except SpotifyApiError: raise # pass handled exceptions on thru
233
221
  except Exception as ex:
@@ -325,7 +313,7 @@ class ZeroconfConnect:
325
313
 
326
314
  # trace.
327
315
  apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
328
- apiMethodParms.AppendKeyValue("HostIpv4Address", self._HostIpv4Address)
316
+ apiMethodParms.AppendKeyValue("HostIpAddress", self._HostIpAddress)
329
317
  apiMethodParms.AppendKeyValue("HostIpPort", self._HostIpPort)
330
318
  apiMethodParms.AppendKeyValue("CPath", self._CPath)
331
319
  apiMethodParms.AppendKeyValue("Version", self._Version)
@@ -440,7 +428,7 @@ class ZeroconfConnect:
440
428
 
441
429
  # trace.
442
430
  apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
443
- apiMethodParms.AppendKeyValue("HostIpv4Address", self._HostIpv4Address)
431
+ apiMethodParms.AppendKeyValue("HostIpAddress", self._HostIpAddress)
444
432
  apiMethodParms.AppendKeyValue("HostIpPort", self._HostIpPort)
445
433
  apiMethodParms.AppendKeyValue("CPath", self._CPath)
446
434
  apiMethodParms.AppendKeyValue("Version", self._Version)
@@ -512,7 +500,7 @@ class ZeroconfConnect:
512
500
 
513
501
  return "{protocol}://{ip}:{port}{cpath}".format(
514
502
  protocol=protocol,
515
- ip=self._HostIpv4Address,
503
+ ip=self._HostIpAddress,
516
504
  port=self._HostIpPort,
517
505
  cpath=self._CPath,
518
506
  )
@@ -546,7 +534,7 @@ class ZeroconfConnect:
546
534
 
547
535
  # trace.
548
536
  apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
549
- apiMethodParms.AppendKeyValue("HostIpv4Address", self._HostIpv4Address)
537
+ apiMethodParms.AppendKeyValue("HostIpAddress", self._HostIpAddress)
550
538
  apiMethodParms.AppendKeyValue("HostIpPort", self._HostIpPort)
551
539
  apiMethodParms.AppendKeyValue("CPath", self._CPath)
552
540
  apiMethodParms.AppendKeyValue("Version", self._Version)
@@ -573,7 +561,7 @@ class ZeroconfConnect:
573
561
  result = ZeroconfGetInfo(root=responseData)
574
562
 
575
563
  # trace.
576
- _logsi.LogObject(SILevel.Verbose, '%s result - type="%s"' % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
564
+ _logsi.LogObject(SILevel.Verbose, '%s result (%s) - "%s" (%s)' % (apiMethodName, type(result).__name__, result.RemoteName, result.DeviceId), result, excludeNonPublic=True)
577
565
  return result
578
566
 
579
567
  except SpotifyZeroconfApiError: raise # pass handled exceptions on thru