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
@@ -14,6 +14,7 @@ from lxml.etree import fromstring, Element
14
14
  from .oauthcli import AuthClient
15
15
  from .models import *
16
16
  from .models import UserProfile as UserProfileCurrentUser
17
+ from .models.zeroconfblobbuilder import int_to_b64str
17
18
  from .sautils import export, GetUnixTimestampMSFromUtcNow, _xmlGetInnerText
18
19
  from .saappmessages import SAAppMessages
19
20
  from .spotifyapierror import SpotifyApiError
@@ -40,6 +41,8 @@ from .const import (
40
41
  CACHE_SOURCE_CACHED:str = "cached"
41
42
  CACHE_SOURCE_CURRENT:str = "current"
42
43
 
44
+ SPOTIFY_DJ_PLAYLIST_ID = "37i9dqzf1eykqdzj48dyyq"
45
+
43
46
  # get smartinspect logger reference; create a new session for this module name.
44
47
  from smartinspectpython.siauto import SIAuto, SILevel, SISession, SIMethodParmListContext, SISourceId
45
48
  import logging
@@ -454,6 +457,19 @@ class SpotifyClient:
454
457
 
455
458
  elif responseData is not None:
456
459
 
460
+ # if response is a string (e.g. html response) and is not in the 2xx range then
461
+ # we will assume it's an error, even though no json 'error' response body was returned!
462
+ # this is usually due to a '503 Server Error' response.
463
+ if (response.status > 299) and (isinstance(responseData, str)):
464
+
465
+ errCode = response.status
466
+ errMessage = response.reason
467
+
468
+ if responseUTF8 is not None:
469
+ errMessage = responseUTF8
470
+
471
+ raise SpotifyWebApiError(errCode, errMessage, msg.MethodName, response.reason, _logsi)
472
+
457
473
  # does json response contain error details?
458
474
  if CONST_ERROR in responseData:
459
475
 
@@ -669,7 +685,8 @@ class SpotifyClient:
669
685
  uri:str = msg.Uri
670
686
  if (uri == self.SpotifyApiTokenUrl) \
671
687
  or (uri == self.SpotifyApiAuthorizeUrl) \
672
- or (uri.startswith('https:')):
688
+ or (uri.startswith('https:')) \
689
+ or (uri.startswith('http:')):
673
690
  url = uri
674
691
  else:
675
692
  url = f'{self.SpotifyWebApiUrlBase}{uri}'
@@ -705,9 +722,13 @@ class SpotifyClient:
705
722
  # call the appropriate poolmanager request method.
706
723
  if msg.HasUrlParameters:
707
724
 
708
- # add querystring parameters to url.
725
+ # add querystring parameters to url; if url already has a partial parm
726
+ # string (e.g. has a '?xxx=...') then use the append separator (e.g. '...&xxx=...').
709
727
  urlQS:str = urlencode(msg.UrlParameters)
710
- url = url + '?' + urlQS
728
+ urlParmSep:str = '?'
729
+ if (url.find('?') > 0):
730
+ urlParmSep = '&'
731
+ url = url + urlParmSep + urlQS
711
732
 
712
733
  _logsi.LogDictionary(SILevel.Verbose, "SpotifyClient http request: '%s' (with urlparms)" % (url), msg.UrlParameters, prettyPrint=True)
713
734
  response = self._Manager.request_encode_url(method, url, headers=msg.RequestHeaders)
@@ -793,9 +814,10 @@ class SpotifyClient:
793
814
  The uri of the item to add to the queue; must be a track or an episode uri.
794
815
  Example: `spotify:track:4iV5W9uYEdYUVa79Axb7Rh`
795
816
  deviceId (str):
796
- The id of the device this command is targeting.
817
+ The id or name of the device this command is targeting.
797
818
  If not supplied, the user's currently active device is the target.
798
- Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
819
+ Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
820
+ Example: `Web Player (Chrome)`
799
821
 
800
822
  Raises:
801
823
  SpotifyWebApiError:
@@ -826,6 +848,10 @@ class SpotifyClient:
826
848
  apiMethodParms.AppendKeyValue("deviceId", deviceId)
827
849
  _logsi.LogMethodParmList(SILevel.Verbose, "Add item to playback queue", apiMethodParms)
828
850
 
851
+ # check for device name; convert to an id if a name was supplied.
852
+ deviceId = self.PlayerConvertDeviceNameToId(deviceId)
853
+
854
+ # build spotify web api request parameters.
829
855
  urlParms:dict = \
830
856
  {
831
857
  'uri': uri
@@ -5826,7 +5852,7 @@ class SpotifyClient:
5826
5852
  result = item
5827
5853
  break
5828
5854
 
5829
- # if no match by id, then try to macth by device name.
5855
+ # if no match by id, then try to match by device name.
5830
5856
  if result is None:
5831
5857
  for item in devices:
5832
5858
  if deviceId == item.Name.lower():
@@ -5850,6 +5876,115 @@ class SpotifyClient:
5850
5876
  _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
5851
5877
 
5852
5878
 
5879
+ def PlayerConvertDeviceNameToId(self,
5880
+ value:str,
5881
+ refresh:bool=False
5882
+ ) -> str:
5883
+ """
5884
+ Converts a Spotify Connect player device name to it's equivalent id value if
5885
+ the value is a device name. If the value is a device id, then the value is
5886
+ returned as-is.
5887
+
5888
+ This method requires the `user-read-playback-state` scope.
5889
+
5890
+ Args:
5891
+ value (str):
5892
+ The device id or name value to check.
5893
+ refresh (bool):
5894
+ True to resolve the device real-time from the spotify web api device list;
5895
+ otherwise, False (default) to use the cached device list to resolve the device.
5896
+
5897
+ Returns:
5898
+ One of the following:
5899
+ - if value is a device id, then the value is returned as-is; no device list
5900
+ lookup is performed, and the value is assumed to be a valid device id.
5901
+ - if value is not a device id, then it is assumed to be a name; a device list
5902
+ lookup is performed to retrieve it's device id. if found, then the id is
5903
+ returned; otherwise, the value is returned as-is with the understanding that
5904
+ subsequent operations will fail since it's not in the device list.
5905
+
5906
+ Raises:
5907
+ SpotifyWebApiError:
5908
+ If the Spotify Web API request was for a non-authorization service
5909
+ and the response contains error information.
5910
+ SpotifApiError:
5911
+ If the method fails for any other reason.
5912
+
5913
+ The id for the first match found on the device name will be returned if multiple devices
5914
+ are found in the Spotify Connect player device list that have the same name (with different
5915
+ id's). Care should be taken to make device names unique if using device names for
5916
+ methods that require a device id or name.
5917
+
5918
+ If the `refresh` argument is specified, then the `ConfigurationCache` is updated with
5919
+ the latest Spotify Connect player device list. Use the `refresh` argument (with False
5920
+ value) to retrieve the cached value and avoid the spotify web api request. This results
5921
+ in better performance.
5922
+
5923
+ <details>
5924
+ <summary>Sample Code</summary>
5925
+ ```python
5926
+ .. include:: ../docs/include/samplecode/SpotifyClient/PlayerConvertDeviceNameToId.py
5927
+ ```
5928
+ </details>
5929
+ """
5930
+ apiMethodName:str = 'PlayerConvertDeviceNameToId'
5931
+ apiMethodParms:SIMethodParmListContext = None
5932
+
5933
+ try:
5934
+
5935
+ # trace.
5936
+ apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
5937
+ apiMethodParms.AppendKeyValue("value", value)
5938
+ apiMethodParms.AppendKeyValue("refresh", refresh)
5939
+ _logsi.LogMethodParmList(SILevel.Verbose, "Checking Spotify Connect Player device for name", apiMethodParms)
5940
+
5941
+ # if nothing specified then just use it as-is.
5942
+ if (value is None) or (len(value.strip()) == 0):
5943
+ _logsi.LogVerbose("Device ID not specified; active device will be used")
5944
+ return value
5945
+
5946
+ try:
5947
+
5948
+ # is this a hex string value?
5949
+ intValue:int = int(str(value), 16)
5950
+
5951
+ # if it IS a hex string, then it should have been converted to a number.
5952
+ # at this point we can assume it's a device id. in this case, just return it.
5953
+ # note that we will NOT perform a lookup in the device list
5954
+ _logsi.LogVerbose("Device id '%s' was specified, and will be used as-is" % value)
5955
+ if intValue is not None:
5956
+ return value
5957
+ return value
5958
+
5959
+ except Exception:
5960
+
5961
+ # the above will fail if it's a device name.
5962
+ pass
5963
+
5964
+ # try resolving the device name to a device id value.
5965
+ device:Device = self.GetPlayerDevice(value, refresh)
5966
+ if device is not None:
5967
+ _logsi.LogVerbose("Converted device name '%s' to device id '%s'" % (value, device.Id))
5968
+ return device.Id
5969
+
5970
+ # if a name could not be found in the Spotify Connect Player devices then just
5971
+ # return the value as-is.
5972
+ _logsi.LogVerbose("Device name '%s' could not be found in the Spotify Connect Device list; subsequent actions will probably fail using this device name" % value)
5973
+ return value
5974
+
5975
+ except SpotifyWebApiError: raise # pass handled exceptions on thru
5976
+ except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
5977
+ except Exception as ex:
5978
+
5979
+ # format unhandled exception.
5980
+ raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
5981
+
5982
+ finally:
5983
+
5984
+ # trace.
5985
+ _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
5986
+
5987
+
5853
5988
  def GetPlayerDevices(self,
5854
5989
  refresh:bool=True
5855
5990
  ) -> list[Device]:
@@ -6437,6 +6572,27 @@ class SpotifyClient:
6437
6572
 
6438
6573
  # ensure market was either supplied or implied; default if neither.
6439
6574
  market = self._ValidateMarket(market)
6575
+
6576
+ # was the Spotify DJ playlist specified?
6577
+ # the DJ is not fully integrated with the playlist API, so the GET request will fail.
6578
+ # we will manually build a basic playlist object to return for the playlist.
6579
+ if (playlistId is not None) and (playlistId.lower() == SPOTIFY_DJ_PLAYLIST_ID):
6580
+
6581
+ # build basic playlist response.
6582
+ result = Playlist()
6583
+ result._Collaborative = False
6584
+ result._Description = 'Spotify DJ Playlist'
6585
+ result._ExternalUrls._Spotify = 'https://open.spotify.com/playlist/%s' % playlistId
6586
+ result._Id = playlistId
6587
+ result._Name = 'DJ'
6588
+ result._Public = False
6589
+ result._Type = 'playlist'
6590
+ result._Uri = 'spotify:playlist:%s' % playlistId
6591
+
6592
+ # trace.
6593
+ _logsi.LogVerbose("Spotify DJ Playlist detected; request will be bypassed, and a basic PlayList object returned")
6594
+ _logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
6595
+ return result
6440
6596
 
6441
6597
  # build spotify web api request parameters.
6442
6598
  urlParms:dict = {}
@@ -8868,9 +9024,10 @@ class SpotifyClient:
8868
9024
 
8869
9025
  Args:
8870
9026
  deviceId (str):
8871
- The id of the device this command is targeting.
9027
+ The id or name of the device this command is targeting.
8872
9028
  If not supplied, the user's currently active device is the target.
8873
- Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9029
+ Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9030
+ Example: `Web Player (Chrome)`
8874
9031
  delay (float):
8875
9032
  Time delay (in seconds) to wait AFTER issuing the command to the player.
8876
9033
  This delay will give the spotify web api time to process the change before
@@ -8909,6 +9066,9 @@ class SpotifyClient:
8909
9066
  # validations.
8910
9067
  delay = self._ValidateDelay(delay, 0.50, 10)
8911
9068
 
9069
+ # check for device name; convert to an id if a name was supplied.
9070
+ deviceId = self.PlayerConvertDeviceNameToId(deviceId)
9071
+
8912
9072
  # build spotify web api request parameters.
8913
9073
  urlParms:dict = {}
8914
9074
  if deviceId is not None:
@@ -8979,9 +9139,10 @@ class SpotifyClient:
8979
9139
  Default is `0`.
8980
9140
  Example: `25000`
8981
9141
  deviceId (str):
8982
- The id of the device this command is targeting.
9142
+ The id or name of the device this command is targeting.
8983
9143
  If not supplied, the user's currently active device is the target.
8984
- Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9144
+ Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9145
+ Example: `Web Player (Chrome)`
8985
9146
  delay (float):
8986
9147
  Time delay (in seconds) to wait AFTER issuing the command to the player.
8987
9148
  This delay will give the spotify web api time to process the change before
@@ -9038,6 +9199,9 @@ class SpotifyClient:
9038
9199
  # validations.
9039
9200
  delay = self._ValidateDelay(delay, 0.50, 10)
9040
9201
 
9202
+ # check for device name; convert to an id if a name was supplied.
9203
+ deviceId = self.PlayerConvertDeviceNameToId(deviceId)
9204
+
9041
9205
  # build spotify web api request parameters.
9042
9206
  reqData:dict = \
9043
9207
  {
@@ -9093,9 +9257,10 @@ class SpotifyClient:
9093
9257
 
9094
9258
  Args:
9095
9259
  deviceId (str):
9096
- The id of the device this command is targeting.
9260
+ The id or name of the device this command is targeting.
9097
9261
  If not supplied, the user's currently active device is the target.
9098
- Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9262
+ Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9263
+ Example: `Web Player (Chrome)`
9099
9264
  shuffle (bool):
9100
9265
  True to set player shuffle mode to on; otherwise, False for no shuffle.
9101
9266
  delay (float):
@@ -9150,6 +9315,9 @@ class SpotifyClient:
9150
9315
  for trackSaved in tracks.Items:
9151
9316
  arrUris.append(trackSaved.Track.Uri)
9152
9317
 
9318
+ # check for device name; convert to an id if a name was supplied.
9319
+ deviceId = self.PlayerConvertDeviceNameToId(deviceId)
9320
+
9153
9321
  # set desired shuffle mode.
9154
9322
  self.PlayerSetShuffleMode(shuffle, deviceId, delay)
9155
9323
 
@@ -9198,9 +9366,10 @@ class SpotifyClient:
9198
9366
  Default is `0`.
9199
9367
  Example: `25000`
9200
9368
  deviceId (str):
9201
- The id of the device this command is targeting.
9369
+ The id or name of the device this command is targeting.
9202
9370
  If not supplied, the user's currently active device is the target.
9203
- Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9371
+ Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9372
+ Example: `Web Player (Chrome)`
9204
9373
  delay (float):
9205
9374
  Time delay (in seconds) to wait AFTER issuing the command to the player.
9206
9375
  This delay will give the spotify web api time to process the change before
@@ -9251,6 +9420,9 @@ class SpotifyClient:
9251
9420
  for idx in range(0, len(arrUris)):
9252
9421
  arrUris[idx] = arrUris[idx].strip()
9253
9422
 
9423
+ # check for device name; convert to an id if a name was supplied.
9424
+ deviceId = self.PlayerConvertDeviceNameToId(deviceId)
9425
+
9254
9426
  # build spotify web api request parameters.
9255
9427
  reqData:dict = \
9256
9428
  {
@@ -9303,9 +9475,10 @@ class SpotifyClient:
9303
9475
 
9304
9476
  Args:
9305
9477
  deviceId (str):
9306
- The id of the device this command is targeting.
9478
+ The id or name of the device this command is targeting.
9307
9479
  If not supplied, the user's currently active device is the target.
9308
- Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9480
+ Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9481
+ Example: `Web Player (Chrome)`
9309
9482
  delay (float):
9310
9483
  Time delay (in seconds) to wait AFTER issuing the command to the player.
9311
9484
  This delay will give the spotify web api time to process the change before
@@ -9344,6 +9517,9 @@ class SpotifyClient:
9344
9517
  # validations.
9345
9518
  delay = self._ValidateDelay(delay, 0.50, 10)
9346
9519
 
9520
+ # check for device name; convert to an id if a name was supplied.
9521
+ deviceId = self.PlayerConvertDeviceNameToId(deviceId)
9522
+
9347
9523
  # build spotify web api request parameters.
9348
9524
  urlParms:dict = {}
9349
9525
  if deviceId is not None:
@@ -9395,9 +9571,10 @@ class SpotifyClient:
9395
9571
  player to start playing the next song.
9396
9572
  Example: `25000`
9397
9573
  deviceId (str):
9398
- The id of the device this command is targeting.
9574
+ The id or name of the device this command is targeting.
9399
9575
  If not supplied, the user's currently active device is the target.
9400
- Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9576
+ Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9577
+ Example: `Web Player (Chrome)`
9401
9578
  delay (float):
9402
9579
  Time delay (in seconds) to wait AFTER issuing the command to the player.
9403
9580
  This delay will give the spotify web api time to process the change before
@@ -9437,6 +9614,9 @@ class SpotifyClient:
9437
9614
  # validations.
9438
9615
  delay = self._ValidateDelay(delay, 0.50, 10)
9439
9616
 
9617
+ # check for device name; convert to an id if a name was supplied.
9618
+ deviceId = self.PlayerConvertDeviceNameToId(deviceId)
9619
+
9440
9620
  # build spotify web api request parameters.
9441
9621
  urlParms:dict = \
9442
9622
  {
@@ -9484,9 +9664,10 @@ class SpotifyClient:
9484
9664
 
9485
9665
  Args:
9486
9666
  deviceId (str):
9487
- The id of the device this command is targeting.
9667
+ The id or name of the device this command is targeting.
9488
9668
  If not supplied, the user's currently active device is the target.
9489
- Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9669
+ Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9670
+ Example: `Web Player (Chrome)`
9490
9671
  delay (float):
9491
9672
  Time delay (in seconds) to wait AFTER issuing the command to the player.
9492
9673
  This delay will give the spotify web api time to process the change before
@@ -9525,6 +9706,9 @@ class SpotifyClient:
9525
9706
  # validations.
9526
9707
  delay = self._ValidateDelay(delay, 0.50, 10)
9527
9708
 
9709
+ # check for device name; convert to an id if a name was supplied.
9710
+ deviceId = self.PlayerConvertDeviceNameToId(deviceId)
9711
+
9528
9712
  # build spotify web api request parameters.
9529
9713
  urlParms:dict = {}
9530
9714
  if deviceId is not None:
@@ -9569,9 +9753,10 @@ class SpotifyClient:
9569
9753
 
9570
9754
  Args:
9571
9755
  deviceId (str):
9572
- The id of the device this command is targeting.
9756
+ The id or name of the device this command is targeting.
9573
9757
  If not supplied, the user's currently active device is the target.
9574
- Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9758
+ Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9759
+ Example: `Web Player (Chrome)`
9575
9760
  delay (float):
9576
9761
  Time delay (in seconds) to wait AFTER issuing the command to the player.
9577
9762
  This delay will give the spotify web api time to process the change before
@@ -9610,6 +9795,9 @@ class SpotifyClient:
9610
9795
  # validations.
9611
9796
  delay = self._ValidateDelay(delay, 0.50, 10)
9612
9797
 
9798
+ # check for device name; convert to an id if a name was supplied.
9799
+ deviceId = self.PlayerConvertDeviceNameToId(deviceId)
9800
+
9613
9801
  # build spotify web api request parameters.
9614
9802
  urlParms:dict = {}
9615
9803
  if deviceId is not None:
@@ -9661,9 +9849,10 @@ class SpotifyClient:
9661
9849
  - `off` - will turn repeat off.
9662
9850
  Default: `off`
9663
9851
  deviceId (str):
9664
- The id of the device this command is targeting.
9852
+ The id or name of the device this command is targeting.
9665
9853
  If not supplied, the user's currently active device is the target.
9666
- Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9854
+ Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9855
+ Example: `Web Player (Chrome)`
9667
9856
  delay (float):
9668
9857
  Time delay (in seconds) to wait AFTER issuing the command to the player.
9669
9858
  This delay will give the spotify web api time to process the change before
@@ -9703,6 +9892,9 @@ class SpotifyClient:
9703
9892
  # validations.
9704
9893
  delay = self._ValidateDelay(delay, 0.50, 10)
9705
9894
 
9895
+ # check for device name; convert to an id if a name was supplied.
9896
+ deviceId = self.PlayerConvertDeviceNameToId(deviceId)
9897
+
9706
9898
  # build spotify web api request parameters.
9707
9899
  urlParms:dict = \
9708
9900
  {
@@ -9756,9 +9948,10 @@ class SpotifyClient:
9756
9948
  - `False` - Do not shuffle user's playback.
9757
9949
  Default: `False`
9758
9950
  deviceId (str):
9759
- The id of the device this command is targeting.
9951
+ The id or name of the device this command is targeting.
9760
9952
  If not supplied, the user's currently active device is the target.
9761
- Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9953
+ Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
9954
+ Example: `Web Player (Chrome)`
9762
9955
  delay (float):
9763
9956
  Time delay (in seconds) to wait AFTER issuing the command to the player.
9764
9957
  This delay will give the spotify web api time to process the change before
@@ -9798,6 +9991,9 @@ class SpotifyClient:
9798
9991
  # validations.
9799
9992
  delay = self._ValidateDelay(delay, 0.50, 10)
9800
9993
 
9994
+ # check for device name; convert to an id if a name was supplied.
9995
+ deviceId = self.PlayerConvertDeviceNameToId(deviceId)
9996
+
9801
9997
  # build spotify web api request parameters.
9802
9998
  urlParms:dict = \
9803
9999
  {
@@ -9850,9 +10046,10 @@ class SpotifyClient:
9850
10046
  Must be a value from 0 to 100 inclusive.
9851
10047
  Example: `50`
9852
10048
  deviceId (str):
9853
- The id of the device this command is targeting.
10049
+ The id or name of the device this command is targeting.
9854
10050
  If not supplied, the user's currently active device is the target.
9855
- Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
10051
+ Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
10052
+ Example: `Web Player (Chrome)`
9856
10053
  delay (float):
9857
10054
  Time delay (in seconds) to wait AFTER issuing the command to the player.
9858
10055
  This delay will give the spotify web api time to process the change before
@@ -9892,6 +10089,9 @@ class SpotifyClient:
9892
10089
  # validations.
9893
10090
  delay = self._ValidateDelay(delay, 0.50, 10)
9894
10091
 
10092
+ # check for device name; convert to an id if a name was supplied.
10093
+ deviceId = self.PlayerConvertDeviceNameToId(deviceId)
10094
+
9895
10095
  # build spotify web api request parameters.
9896
10096
  urlParms:dict = \
9897
10097
  {
@@ -9940,8 +10140,9 @@ class SpotifyClient:
9940
10140
 
9941
10141
  Args:
9942
10142
  deviceId (str):
9943
- The id of the device on which playback should be started/transferred.
9944
- Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
10143
+ The id or name of the device on which playback should be started/transferred.
10144
+ Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
10145
+ Example: `Web Player (Chrome)`
9945
10146
  play (bool):
9946
10147
  The transfer method:
9947
10148
  - `True` - ensure playback happens on new device.
@@ -9985,6 +10186,9 @@ class SpotifyClient:
9985
10186
 
9986
10187
  # validations.
9987
10188
  delay = self._ValidateDelay(delay, 0.50, 10)
10189
+
10190
+ # check for device name; convert to an id if a name was supplied.
10191
+ deviceId = self.PlayerConvertDeviceNameToId(deviceId)
9988
10192
 
9989
10193
  # build spotify web api request parameters.
9990
10194
  reqData:dict = \
@@ -10038,8 +10242,8 @@ class SpotifyClient:
10038
10242
  Args:
10039
10243
  defaultDeviceId (str):
10040
10244
  The id of the device on which playback should be started/transferred if there is
10041
- currently no active device.
10042
- Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
10245
+ currently no active device.
10246
+ Example: `0d1841b0976bae2a3a310dd74c0f3df354899bc8`
10043
10247
  play (bool):
10044
10248
  The transfer method:
10045
10249
  - `True` - ensure playback happens on new device.
@@ -13615,3 +13819,251 @@ class SpotifyClient:
13615
13819
 
13616
13820
  # trace.
13617
13821
  _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
13822
+
13823
+
13824
+
13825
+ def ZeroconfGetInformation(self,
13826
+ actionUrl:str,
13827
+ ) -> ZeroconfGetInfo:
13828
+ """
13829
+ Retrieve Spotify Connect device information from the Spotify Zeroconf API `getInfo` endpoint.
13830
+
13831
+ Args:
13832
+ actionUrl (str):
13833
+ The Zeroconf action url to issue the request to.
13834
+ Example: `http://192.168.1.80:8200/zc?action=getInfo`
13835
+
13836
+ Returns:
13837
+ An `ZeroconfGetInfo` object that contains the response.
13838
+
13839
+ Raises:
13840
+ SpotifyWebApiError:
13841
+ If the Spotify Web API request was for a non-authorization service
13842
+ and the response contains error information.
13843
+ SpotifApiError:
13844
+ If the method fails for any other reason.
13845
+
13846
+ <details>
13847
+ <summary>Sample Code</summary>
13848
+ ```python
13849
+ .. include:: ../docs/include/samplecode/SpotifyClient/ZeroconfGetInformation.py
13850
+ ```
13851
+ </details>
13852
+ """
13853
+ apiMethodName:str = 'ZeroconfGetInformation'
13854
+ apiMethodParms:SIMethodParmListContext = None
13855
+ result:ZeroconfGetInfo = None
13856
+
13857
+ try:
13858
+
13859
+ # trace.
13860
+ apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
13861
+ apiMethodParms.AppendKeyValue("actionUrl", actionUrl)
13862
+ _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify Zeroconf getInfo response", apiMethodParms)
13863
+
13864
+ # execute spotify zeroconf api request.
13865
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, actionUrl)
13866
+ self.MakeRequest('GET', msg)
13867
+
13868
+ # process results.
13869
+ result = ZeroconfGetInfo(root=msg.ResponseData)
13870
+
13871
+ # trace.
13872
+ _logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
13873
+ return result
13874
+
13875
+ except SpotifyWebApiError: raise # pass handled exceptions on thru
13876
+ except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
13877
+ except Exception as ex:
13878
+
13879
+ # format unhandled exception.
13880
+ raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
13881
+
13882
+ finally:
13883
+
13884
+ # trace.
13885
+ _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
13886
+
13887
+
13888
+ def ZeroconfResetUsers(self,
13889
+ actionUrl:str,
13890
+ ) -> ZeroconfResponse:
13891
+ """
13892
+ Reset users for a Spotify Connect device by calling the Spotify Zeroconf API `resetUsers` endpoint.
13893
+
13894
+ Args:
13895
+ actionUrl (str):
13896
+ The Zeroconf action url to issue the request to.
13897
+ Example: `http://192.168.1.80:8200/zc?action=resetUsers`
13898
+
13899
+ Returns:
13900
+ An `ZeroconfResponse` object that contains the response.
13901
+
13902
+ Raises:
13903
+ SpotifyWebApiError:
13904
+ If the Spotify Web API request was for a non-authorization service
13905
+ and the response contains error information.
13906
+ SpotifApiError:
13907
+ If the method fails for any other reason.
13908
+
13909
+ <details>
13910
+ <summary>Sample Code</summary>
13911
+ ```python
13912
+ .. include:: ../docs/include/samplecode/SpotifyClient/ZeroconfResetUsers.py
13913
+ ```
13914
+ </details>
13915
+ """
13916
+ apiMethodName:str = 'ZeroconfResetUsers'
13917
+ apiMethodParms:SIMethodParmListContext = None
13918
+ result:ZeroconfResponse = None
13919
+
13920
+ try:
13921
+
13922
+ # trace.
13923
+ apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
13924
+ apiMethodParms.AppendKeyValue("actionUrl", actionUrl)
13925
+ _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify Zeroconf GetInfo response", apiMethodParms)
13926
+
13927
+ # execute spotify zeroconf api request.
13928
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, actionUrl)
13929
+ self.MakeRequest('GET', msg)
13930
+
13931
+ # process results.
13932
+ result = ZeroconfResponse(root=msg.ResponseData)
13933
+
13934
+ # trace.
13935
+ _logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
13936
+ return result
13937
+
13938
+ except SpotifyWebApiError: raise # pass handled exceptions on thru
13939
+ except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
13940
+ except Exception as ex:
13941
+
13942
+ # format unhandled exception.
13943
+ raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
13944
+
13945
+ finally:
13946
+
13947
+ # trace.
13948
+ _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
13949
+
13950
+
13951
+ def ZeroconfAddUser(self,
13952
+ actionUrl:str,
13953
+ getInfoResponse:ZeroconfGetInfo,
13954
+ username:str,
13955
+ password:str,
13956
+ ) -> ZeroconfResponse:
13957
+ """
13958
+ Add a user to a Spotify Connect device by calling the Spotify Zeroconf API `addUser` endpoint.
13959
+
13960
+ Args:
13961
+ actionUrl (str):
13962
+ The Zeroconf action url to issue the request to.
13963
+ Example: `http://192.168.1.80:8200/zc?action=addUser&version=1.0`
13964
+
13965
+ Returns:
13966
+ An `ZeroconfResponse` object that contains the response.
13967
+
13968
+ Raises:
13969
+ SpotifyWebApiError:
13970
+ If the Spotify Web API request was for a non-authorization service
13971
+ and the response contains error information.
13972
+ SpotifApiError:
13973
+ If the method fails for any other reason.
13974
+
13975
+ <details>
13976
+ <summary>Sample Code</summary>
13977
+ ```python
13978
+ .. include:: ../docs/include/samplecode/SpotifyClient/ZeroconfGetInformation.py
13979
+ ```
13980
+ </details>
13981
+ """
13982
+ apiMethodName:str = 'ZeroconfAddUser'
13983
+ apiMethodParms:SIMethodParmListContext = None
13984
+ result:ZeroconfResponse = None
13985
+
13986
+ try:
13987
+
13988
+ # trace.
13989
+ apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
13990
+ apiMethodParms.AppendKeyValue("actionUrl", actionUrl)
13991
+ apiMethodParms.AppendKeyValue("getInfoResponse", getInfoResponse)
13992
+ apiMethodParms.AppendKeyValue("username", username)
13993
+ apiMethodParms.AppendKeyValue("password", password)
13994
+ _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify Zeroconf addUser response", apiMethodParms)
13995
+
13996
+ raise NotImplemented()
13997
+
13998
+ # build credentials object.
13999
+ self.credentials = ZeroconfCredentials(username, password)
14000
+
14001
+ # build authentication blob.
14002
+ builder = ZeroconfBlobBuilder(self.credentials, getInfoResponse.DeviceId, getInfoResponse.PublicKey)
14003
+ blob = builder.build()
14004
+
14005
+ # # call zeroconf to add the user to the device.
14006
+ # r = self._add_user(
14007
+ # self.credentials.username.decode('ascii'),
14008
+ # int_to_b64str(builder.dh_keys.public_key),
14009
+ # blob)
14010
+
14011
+ # def _add_user(self, username: str, client_key: str, blob: str): # -> bool
14012
+ # respone = requests.post(
14013
+ # self.uri,
14014
+ # headers={
14015
+ # 'Content-Type': 'application/x-www-form-urlencoded'
14016
+ # },
14017
+ # params={
14018
+ # 'action': 'addUser',
14019
+ # 'userName': username,
14020
+ # 'clientKey': client_key,
14021
+ # 'blob': blob
14022
+ # }
14023
+ # )
14024
+ # return respone
14025
+
14026
+ # build spotify zeroconf addUser parameters.
14027
+ urlParms:dict = \
14028
+ {
14029
+ 'userName': self.credentials.username.decode('ascii'),
14030
+ 'clientKey': int_to_b64str(builder.dh_keys.public_key),
14031
+ 'blob': blob,
14032
+ 'deviceId': getInfoResponse.DeviceId,
14033
+ 'deviceName': getInfoResponse.RemoteName,
14034
+ 'loginId': 'xxxxxxxxxxx',
14035
+ }
14036
+
14037
+ # let params = [
14038
+ # 3 ("action", "addUser"),
14039
+ # 3 ("userName", username),
14040
+ # 3 ("blob", blob),
14041
+ # 3 ("clientKey", my_public_key),
14042
+ # ("deviceId", &device_id),
14043
+ # ("deviceName", "spotify-connect"),
14044
+ # ("loginId", &login_id),
14045
+
14046
+
14047
+ # execute spotify zeroconf api request.
14048
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, actionUrl)
14049
+ msg.UrlParameters = urlParms
14050
+ self.MakeRequest('POST', msg)
14051
+
14052
+ # process results.
14053
+ result = ZeroconfResponse(root=msg.ResponseData)
14054
+
14055
+ # trace.
14056
+ _logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
14057
+ return result
14058
+
14059
+ except SpotifyWebApiError: raise # pass handled exceptions on thru
14060
+ except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
14061
+ except Exception as ex:
14062
+
14063
+ # format unhandled exception.
14064
+ raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
14065
+
14066
+ finally:
14067
+
14068
+ # trace.
14069
+ _logsi.LeaveMethod(SILevel.Debug, apiMethodName)