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.
- {spotifywebapiPython-1.0.78.dist-info → spotifywebapiPython-1.0.80.dist-info}/METADATA +1 -1
- {spotifywebapiPython-1.0.78.dist-info → spotifywebapiPython-1.0.80.dist-info}/RECORD +25 -25
- spotifywebapipython/const.py +6 -1
- spotifywebapipython/docs/__init__.html +18 -3
- spotifywebapipython/docs/index.html +2 -2
- spotifywebapipython/docs/search.js +1 -1
- spotifywebapipython/docs/spotifywebapiPython/const.html +20 -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 +38 -2
- spotifywebapipython/docs/spotifywebapiPython/spotifyclient.html +168 -72
- spotifywebapipython/docs/spotifywebapiPython/spotifydiscovery.html +2 -2
- spotifywebapipython/docs/spotifywebapiPython/spotifywebapiauthenticationerror.html +2 -2
- spotifywebapipython/docs/spotifywebapiPython/spotifywebapierror.html +2 -2
- spotifywebapipython/models/spotifyconnectdevice.py +60 -1
- spotifywebapipython/models/spotifyconnectdevices.py +2 -0
- spotifywebapipython/spotifyauthtoken.py +26 -0
- spotifywebapipython/spotifyclient.py +440 -195
- spotifywebapipython/zeroconfapi/zeroconfconnect.py +52 -46
- spotifywebapipython/zeroconfapi/zeroconfgetinfoalias.py +8 -0
- {spotifywebapiPython-1.0.78.dist-info → spotifywebapiPython-1.0.80.dist-info}/LICENSE +0 -0
- {spotifywebapiPython-1.0.78.dist-info → spotifywebapiPython-1.0.80.dist-info}/WHEEL +0 -0
- {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 =
|
|
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
|
-
#
|
|
682
|
-
#
|
|
683
|
-
#
|
|
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
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
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.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|