spotifywebapiPython 1.0.78__py3-none-any.whl → 1.0.80__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 (25) hide show
  1. {spotifywebapiPython-1.0.78.dist-info → spotifywebapiPython-1.0.80.dist-info}/METADATA +1 -1
  2. {spotifywebapiPython-1.0.78.dist-info → spotifywebapiPython-1.0.80.dist-info}/RECORD +25 -25
  3. spotifywebapipython/const.py +6 -1
  4. spotifywebapipython/docs/__init__.html +18 -3
  5. spotifywebapipython/docs/index.html +2 -2
  6. spotifywebapipython/docs/search.js +1 -1
  7. spotifywebapipython/docs/spotifywebapiPython/const.html +20 -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 +38 -2
  13. spotifywebapipython/docs/spotifywebapiPython/spotifyclient.html +168 -72
  14. spotifywebapipython/docs/spotifywebapiPython/spotifydiscovery.html +2 -2
  15. spotifywebapipython/docs/spotifywebapiPython/spotifywebapiauthenticationerror.html +2 -2
  16. spotifywebapipython/docs/spotifywebapiPython/spotifywebapierror.html +2 -2
  17. spotifywebapipython/models/spotifyconnectdevice.py +60 -1
  18. spotifywebapipython/models/spotifyconnectdevices.py +2 -0
  19. spotifywebapipython/spotifyauthtoken.py +26 -0
  20. spotifywebapipython/spotifyclient.py +440 -195
  21. spotifywebapipython/zeroconfapi/zeroconfconnect.py +52 -46
  22. spotifywebapipython/zeroconfapi/zeroconfgetinfoalias.py +8 -0
  23. {spotifywebapiPython-1.0.78.dist-info → spotifywebapiPython-1.0.80.dist-info}/LICENSE +0 -0
  24. {spotifywebapiPython-1.0.78.dist-info → spotifywebapiPython-1.0.80.dist-info}/WHEEL +0 -0
  25. {spotifywebapiPython-1.0.78.dist-info → spotifywebapiPython-1.0.80.dist-info}/top_level.txt +0 -0
@@ -20,6 +20,7 @@ from ..oauthcli.authclient import AuthClient
20
20
  from ..const import (
21
21
  SPOTIFY_API_AUTHORIZE_URL,
22
22
  SPOTIFY_API_TOKEN_URL,
23
+ SPOTIFY_DESKTOP_APP_CLIENT_ID,
23
24
  TRACE_METHOD_RESULT,
24
25
  TRACE_MSG_DELAY_DEVICE,
25
26
  )
@@ -60,6 +61,7 @@ class ZeroconfConnect:
60
61
  version:str=None,
61
62
  useSSL:bool=False,
62
63
  tokenStorageDir:str=None,
64
+ tokenAuthInBrowser:bool=False,
63
65
  ) -> None:
64
66
  """
65
67
  Initializes a new instance of the class.
@@ -85,6 +87,15 @@ class ZeroconfConnect:
85
87
  This is used for Spotify Connect devices that utilize the `authorization_code` token type.
86
88
  A null value will default to the platform specific storage location:
87
89
  Example for Windows OS = `C:\ProgramData\SpotifyWebApiPython`
90
+ tokenAuthInBrowser (bool):
91
+ True to allow authorization access token to be authorized if necessary via an
92
+ interactive browser; otherwise, False.
93
+ Default is False.
94
+
95
+ Set the `tokenAuthInBrowser` argument to False if your process does not allow user interaction
96
+ with the local default browser to approve authorization requests (e.g. if your process runs on
97
+ a server for instance). Set to True if you have a desktop / console application that allows
98
+ interactive access to the local default browser.
88
99
  """
89
100
  # validations.
90
101
  if (useSSL is None) or (not isinstance(useSSL,bool)):
@@ -97,6 +108,7 @@ class ZeroconfConnect:
97
108
  self._HostIpPort:int = hostIpPort
98
109
  self._HostIpAddress:str = hostIpAddress
99
110
  self._TokenStorageDir:str = tokenStorageDir
111
+ self._TokenAuthInBrowser:str = tokenAuthInBrowser
100
112
  self._UseSSL:bool = useSSL
101
113
  self._Version:str = version
102
114
 
@@ -130,6 +142,15 @@ class ZeroconfConnect:
130
142
  return self._HostIpPort
131
143
 
132
144
 
145
+ @property
146
+ def TokenAuthInBrowser(self) -> bool:
147
+ """
148
+ True to allow authorization access token to be authorized if necessary via an
149
+ interactive browser; otherwise, False.
150
+ """
151
+ return self._TokenAuthInBrowser
152
+
153
+
133
154
  @property
134
155
  def TokenStorageDir(self) -> str:
135
156
  """
@@ -530,7 +551,7 @@ class ZeroconfConnect:
530
551
  tokenType = info.TokenType
531
552
 
532
553
  # get authorization_code access token.
533
- blob:str = self._GetSpotifyConnectAuthorizationCodeToken(info)
554
+ blob:str = self._GetSpotifyConnectAuthorizationCodeToken(info, loginId=loginId)
534
555
 
535
556
  else:
536
557
 
@@ -598,6 +619,7 @@ class ZeroconfConnect:
598
619
  def _GetSpotifyConnectAuthorizationCodeToken(
599
620
  self,
600
621
  info:ZeroconfGetInfo,
622
+ loginId:str,
601
623
  ) -> str:
602
624
  """
603
625
  Exchange a Spotify access token for an authorization_code access token.
@@ -617,10 +639,12 @@ class ZeroconfConnect:
617
639
 
618
640
  # trace.
619
641
  apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
642
+ apiMethodParms.AppendKeyValue("loginId", loginId)
620
643
  apiMethodParms.AppendKeyValue("info.DeviceId", info.DeviceId)
621
644
  apiMethodParms.AppendKeyValue("info.RemoteName", info.RemoteName)
622
645
  apiMethodParms.AppendKeyValue("info.BrandDisplayName", info.BrandDisplayName)
623
646
  apiMethodParms.AppendKeyValue("info.ModelDisplayName", info.ModelDisplayName)
647
+ apiMethodParms.AppendKeyValue("self.TokenAuthInBrowser", self.TokenAuthInBrowser)
624
648
  _logsi.LogMethodParmList(SILevel.Verbose, "Preparing to generate a new authorization_code access token for Spotify Connect device: '%s' (%s)" % (info.RemoteName, info.DeviceId), apiMethodParms)
625
649
 
626
650
  # set variables for spotify authorization_code token generation.
@@ -629,40 +653,12 @@ class ZeroconfConnect:
629
653
  redirectUriPort:str = 4381
630
654
  redirectUriPath:str = '/login'
631
655
  authorizationType:str = 'Authorization Code PKCE'
632
- tokenProfileId:str = 'SpotifyDesktopApp_Scopes_Streaming' # 'SpotifyDesktopApp_Scopes_Streaming', 'SpotifyDesktopApp_Scopes_All', 'SpotifyDesktopApp_Scopes_NoExtras'
633
- SPOTIFY_DESKTOP_APP_CLIENT_ID:str = '65b708073fc0480ea92a077233ca87bd' # Spotify Desktop App client id
656
+ tokenProfileId:str = loginId
634
657
 
635
- # Spotify Desktop App scopes requested for Spotify Connect
658
+ # Spotify Desktop App scopes requested for Spotify Connect (streaming only as of 2024/08/13)
636
659
  SPOTIFY_SCOPES:list = \
637
660
  [
638
- # 'playlist-modify-private',
639
- # 'playlist-modify-public',
640
- # 'playlist-read-collaborative',
641
- # 'playlist-read-private',
642
- # 'ugc-image-upload',
643
- # 'user-follow-modify',
644
- # 'user-follow-read',
645
- # 'user-library-modify',
646
- # 'user-library-read',
647
- # 'user-modify-playback-state',
648
- # 'user-read-currently-playing',
649
- # 'user-read-email',
650
- # 'user-read-playback-position',
651
- # 'user-read-playback-state',
652
- # 'user-read-private',
653
- # 'user-read-recently-played',
654
- # 'user-top-read',
655
- # *** streaming scope
656
661
  'streaming',
657
- # *** extra scopes used by spotify desktop player
658
- # 'app-remote-control',
659
- # 'playlist-modify',
660
- # 'playlist-read',
661
- # 'user-modify',
662
- # 'user-modify-private',
663
- # 'user-personalized',
664
- # 'user-read-birthdate',
665
- # 'user-read-play-history',
666
662
  ]
667
663
 
668
664
  # create oauth provider for spotify authentication code with pkce.
@@ -678,26 +674,36 @@ class ZeroconfConnect:
678
674
  tokenProfileId=tokenProfileId,
679
675
  )
680
676
 
681
- # force the user to logon to spotify to authorize the application access if we
682
- # do not have an authorized access token, or if the calling application requested
683
- # us (by force) to re-authorize, or if the scope has changed.
677
+ # raise an exception if the authorization token is not present, or the scope has changed.
678
+ # the user must create the authorization token outside of this process, as the Spotify
679
+ # authorization token is driven by responding to a web request for access using OAuth.
680
+ # as this process is running on a server, there is no way for the user to respond to the
681
+ # request (e.g. via browser nor command-line).
684
682
  isAuthorized = authClient.IsAuthorized
685
683
  _logsi.LogVerbose('Checking OAuth2 authorization status: IsAuthorized=%s' % isAuthorized)
686
684
 
687
685
  if (isAuthorized == False):
686
+
687
+ # can the user interact with a local default browser to authorize the request?
688
+ if self.TokenAuthInBrowser:
689
+
690
+ # at this point, we need a new authorization token.
691
+ # the user has up to 2 minutes to respond to the request by copying / pasting the
692
+ # message / auth approval url from the system log into a browser window that is
693
+ # running on the local machine.
694
+ _logsi.LogVerbose('Preparing to retrieve a new OAuth2 authorization access token')
695
+ authClient.AuthorizeWithServer(
696
+ host=redirectUriHost,
697
+ port=redirectUriPort,
698
+ redirect_uri_path=redirectUriPath,
699
+ open_browser=True,
700
+ timeout_seconds=120
701
+ )
688
702
 
689
- # at this point, we need a new authorization token.
690
- # the user has up to 2 minutes to respond to the request by copying / pasting the
691
- # message / auth approval url from the system log into a browser window that is
692
- # running on the local machine.
693
- _logsi.LogVerbose('Preparing to retrieve a new OAuth2 authorization access token')
694
- authClient.AuthorizeWithServer(
695
- host=redirectUriHost,
696
- port=redirectUriPort,
697
- redirect_uri_path=redirectUriPath,
698
- open_browser=False,
699
- timeout_seconds=120
700
- )
703
+ else:
704
+
705
+ # user cannot approve the request - raise an exception.
706
+ raise SpotifyZeroconfApiError(401, 'Spotify Desktop Client Application access token was not authorized', apiMethodName, 'Token Not Authorized', _logsi)
701
707
 
702
708
  else:
703
709
 
@@ -65,6 +65,14 @@ class ZeroconfGetInfoAlias:
65
65
  return self._Name
66
66
 
67
67
 
68
+ @property
69
+ def Title(self) -> str:
70
+ """
71
+ Alias name and id value (e.g. '"Bose-ST10-1" (30fbc80e35598f3c242f2120413c943dfd9715fe)').
72
+ """
73
+ return '"%s" (%s)' & (self._Name, self._Id)
74
+
75
+
68
76
  def ToDictionary(self) -> dict:
69
77
  """
70
78
  Returns a dictionary representation of the class.