spotifywebapiPython 1.0.147__py3-none-any.whl → 1.0.149__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.147.dist-info → spotifywebapiPython-1.0.149.dist-info}/METADATA +5 -9
- {spotifywebapiPython-1.0.147.dist-info → spotifywebapiPython-1.0.149.dist-info}/RECORD +38 -29
- spotifywebapipython/__init__.py +0 -2
- spotifywebapipython/const.py +1 -1
- spotifywebapipython/docs/__init__.html +25 -4
- spotifywebapipython/docs/index.html +26 -2
- spotifywebapipython/docs/search.js +1 -1
- spotifywebapipython/docs/spotifywebapipython/const.html +3 -3
- spotifywebapipython/docs/spotifywebapipython/saappmessages.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/sautils.html +8 -8
- spotifywebapipython/docs/spotifywebapipython/spotifyapierror.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifyapimessage.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifyauthtoken.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifyclient.html +514 -741
- spotifywebapipython/docs/spotifywebapipython/spotifydiscovery.html +3 -3
- spotifywebapipython/docs/spotifywebapipython/spotifywebapiauthenticationerror.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifywebapierror.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifywebplayertoken.html +466 -0
- spotifywebapipython/models/spotifyconnectdevice.py +84 -4
- spotifywebapipython/models/spotifyconnectdevices.py +16 -307
- spotifywebapipython/models/zeroconfdiscoveryresult.py +0 -41
- spotifywebapipython/sautils.py +0 -1
- spotifywebapipython/spotifyclient.py +1384 -1835
- spotifywebapipython/spotifyconnect/__init__.py +19 -0
- spotifywebapipython/{spotifyconnectdeviceeventargs.py → spotifyconnect/spotifyconnectdeviceeventargs.py} +1 -1
- spotifywebapipython/spotifyconnect/spotifyconnectdirectorytask.py +1967 -0
- spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastapptask.py +336 -0
- spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastcontroller.py +609 -0
- spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastlistener.py +316 -0
- spotifywebapipython/spotifyconnect/spotifyconnectzeroconfexceptions.py +10 -0
- spotifywebapipython/spotifyconnect/spotifyconnectzeroconflistener.py +335 -0
- spotifywebapipython/spotifydiscovery.py +0 -1
- spotifywebapipython/spotifywebplayertoken.py +344 -0
- spotifywebapipython/zeroconfapi/zeroconfgetinfo.py +4 -52
- spotifywebapipython/zeroconfapi/zeroconfresponse.py +8 -0
- {spotifywebapiPython-1.0.147.dist-info → spotifywebapiPython-1.0.149.dist-info}/LICENSE +0 -0
- {spotifywebapiPython-1.0.147.dist-info → spotifywebapiPython-1.0.149.dist-info}/WHEEL +0 -0
- {spotifywebapiPython-1.0.147.dist-info → spotifywebapiPython-1.0.149.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
# external package imports.
|
|
2
|
+
from datetime import datetime, timedelta, timezone
|
|
3
|
+
import json
|
|
4
|
+
import os.path
|
|
5
|
+
import platformdirs
|
|
6
|
+
import requests
|
|
7
|
+
import time
|
|
8
|
+
from tokenize import TokenError
|
|
9
|
+
|
|
10
|
+
# our package imports.
|
|
11
|
+
from .const import (
|
|
12
|
+
SPOTIFY_WEBUI_URL_BASE,
|
|
13
|
+
SPOTIFYWEBAPIPYTHON_TOKEN_CACHE_FILE,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# get smartinspect logger reference; create a new session for this module name.
|
|
17
|
+
from smartinspectpython.siauto import SIAuto, SILevel, SISession, SIMethodParmListContext
|
|
18
|
+
import logging
|
|
19
|
+
_logsi:SISession = SIAuto.Si.GetSession(__name__)
|
|
20
|
+
if (_logsi == None):
|
|
21
|
+
_logsi = SIAuto.Si.AddSession(__name__, True)
|
|
22
|
+
_logsi.SystemLogger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
SPOTIFY_WEBUI_URL_GET_ACCESS_TOKEN = SPOTIFY_WEBUI_URL_BASE + "/get_access_token"
|
|
26
|
+
""" Url used to get access token. """
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class SpotifyWebPlayerToken:
|
|
30
|
+
"""
|
|
31
|
+
Represents a Spotify web player token for an account.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
clientId:str=None,
|
|
37
|
+
profileId:str=None,
|
|
38
|
+
tokenProviderId:str=None,
|
|
39
|
+
tokenStorageDir:str=None,
|
|
40
|
+
tokenStorageFile:str=None,
|
|
41
|
+
) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Initializes a new instance of the class.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
clientId (str):
|
|
47
|
+
The unique identifier of the application.
|
|
48
|
+
A null value will default to `Shared`.
|
|
49
|
+
Default: `Shared`
|
|
50
|
+
profileId (str):
|
|
51
|
+
Profile identifier used when loading / storing the token to disk.
|
|
52
|
+
A null value will default to `Shared`.
|
|
53
|
+
Default: `Shared`
|
|
54
|
+
tokenProviderId (str):
|
|
55
|
+
Provider identifier used when storing the token to disk.
|
|
56
|
+
A null value will default to `Shared`.
|
|
57
|
+
Default: `Shared`
|
|
58
|
+
tokenStorageDir (str):
|
|
59
|
+
The directory path that will contain the Token Cache file.
|
|
60
|
+
A null value will default to the platform specific storage location:
|
|
61
|
+
Example for Windows OS = `C:\\ProgramData\\SpotifyWebApiPython`
|
|
62
|
+
tokenStorageFile (str):
|
|
63
|
+
The filename and extension of the Token Cache file.
|
|
64
|
+
Default is `tokens.json`.
|
|
65
|
+
"""
|
|
66
|
+
# validations.
|
|
67
|
+
if clientId is None:
|
|
68
|
+
clientId = "Shared"
|
|
69
|
+
if profileId is None:
|
|
70
|
+
profileId = 'Shared'
|
|
71
|
+
|
|
72
|
+
# verify token storage directory exists.
|
|
73
|
+
if tokenStorageDir is None:
|
|
74
|
+
tokenStorageDir = platformdirs.site_config_dir('SpotifyWebApiPython', ensure_exists=True, appauthor=False)
|
|
75
|
+
os.makedirs(tokenStorageDir, exist_ok=True) # succeeds even if directory exists.
|
|
76
|
+
|
|
77
|
+
# verify token storage filename was specified.
|
|
78
|
+
if tokenStorageFile is None:
|
|
79
|
+
tokenStorageFile = SPOTIFYWEBAPIPYTHON_TOKEN_CACHE_FILE
|
|
80
|
+
|
|
81
|
+
# if token providerId not set, then default to shared.
|
|
82
|
+
if tokenProviderId is None:
|
|
83
|
+
tokenProviderId = 'SpotifyWebPlayerCookieCredentials'
|
|
84
|
+
|
|
85
|
+
# initializa storage.
|
|
86
|
+
self._AccessToken = None
|
|
87
|
+
self._ClientId:str = clientId
|
|
88
|
+
self._ExpiresAt:int = 0
|
|
89
|
+
self._ExpireDateTimeUtc:datetime = None
|
|
90
|
+
self._ExpiresIn:int = 0
|
|
91
|
+
self._IsAnonymous:bool = False
|
|
92
|
+
self._ProfileId:str = profileId
|
|
93
|
+
self._TokenProviderId:str = tokenProviderId
|
|
94
|
+
self._TokenStorageDir:str = tokenStorageDir
|
|
95
|
+
self._TokenStorageFile:str = tokenStorageFile
|
|
96
|
+
self._TokenStoragePath:str = os.path.join(tokenStorageDir, tokenStorageFile)
|
|
97
|
+
|
|
98
|
+
# load cookie credentials from the token storage file.
|
|
99
|
+
token:dict = self._LoadCookieCredentials()
|
|
100
|
+
|
|
101
|
+
# get Spotify Web Player access token from stored Spotify Web Player cookie credentials.
|
|
102
|
+
self.GetAccessTokenFromCookieCredentials()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def AccessToken(self) -> str:
|
|
107
|
+
"""
|
|
108
|
+
An access token that can be provided to a Spotify Web Player application.
|
|
109
|
+
"""
|
|
110
|
+
return self._AccessToken
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def ClientId(self) -> str:
|
|
115
|
+
"""
|
|
116
|
+
The unique identifier of the application.
|
|
117
|
+
"""
|
|
118
|
+
return self._ClientId
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def ExpiresAt(self) -> int:
|
|
123
|
+
"""
|
|
124
|
+
DateTime (in epoch seconds) that the authorization token will expire.
|
|
125
|
+
"""
|
|
126
|
+
return self._ExpiresAt
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def ExpireDateTimeUtc(self) -> datetime:
|
|
131
|
+
"""
|
|
132
|
+
DateTime (in UTC format) that the authorization token will expire.
|
|
133
|
+
"""
|
|
134
|
+
return self._ExpireDateTimeUtc
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def ExpiresIn(self) -> int:
|
|
139
|
+
"""
|
|
140
|
+
The time period (in seconds) for which the access token is valid.
|
|
141
|
+
"""
|
|
142
|
+
return self._ExpiresIn
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def IsExpired(self) -> bool:
|
|
147
|
+
"""
|
|
148
|
+
Returns true if the token has expired; otherwise, False if not expired.
|
|
149
|
+
"""
|
|
150
|
+
if self._ExpiresAt is not None:
|
|
151
|
+
nowsecs:int = int(time.time())
|
|
152
|
+
# subtract 30 seconds in case we are right at the edge of expiring.
|
|
153
|
+
if (nowsecs + 30) > self._ExpiresAt:
|
|
154
|
+
return True
|
|
155
|
+
return False
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@property
|
|
159
|
+
def ProfileId(self) -> str:
|
|
160
|
+
"""
|
|
161
|
+
Profile identifier used when loading / storing the token to disk.
|
|
162
|
+
"""
|
|
163
|
+
return self._ProfileId
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _LoadCookieCredentials(self) -> dict:
|
|
167
|
+
"""
|
|
168
|
+
Loads a token from the token storage file for the ProviderId / ClientId key.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
A token dictionary, if one was found in the token storage file for the
|
|
172
|
+
specified ProviderId and ClientId key; otherwise, null.
|
|
173
|
+
"""
|
|
174
|
+
apiMethodName:str = '_LoadCookieCredentials'
|
|
175
|
+
apiMethodParms:SIMethodParmListContext = None
|
|
176
|
+
|
|
177
|
+
try:
|
|
178
|
+
|
|
179
|
+
# trace.
|
|
180
|
+
apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
|
|
181
|
+
_logsi.LogMethodParmList(SILevel.Verbose, "Loading Spotify Web Player cookie credentials from token storage", apiMethodParms)
|
|
182
|
+
|
|
183
|
+
# formulate token storage key.
|
|
184
|
+
tokenKey:str = f'{self._TokenProviderId}/{self._ClientId}/{self._ProfileId}'
|
|
185
|
+
_logsi.LogVerbose("Cookie credentials storage key: \"%s\"" % (tokenKey))
|
|
186
|
+
_logsi.LogVerbose("Cookie credentials storage file path: \"%s\"" % (self._TokenStoragePath))
|
|
187
|
+
|
|
188
|
+
# does the token storage file exist?
|
|
189
|
+
if os.path.exists(self._TokenStoragePath):
|
|
190
|
+
|
|
191
|
+
# open the token storage file, and load it's contents.
|
|
192
|
+
_logsi.LogVerbose("Opening cookie credentials token storage file")
|
|
193
|
+
with open(self._TokenStoragePath, 'r') as f:
|
|
194
|
+
|
|
195
|
+
tokens = json.load(f)
|
|
196
|
+
|
|
197
|
+
# if token key exists then load the token.
|
|
198
|
+
if tokenKey in tokens:
|
|
199
|
+
_logsi.LogDictionary(SILevel.Verbose, "Cookie credentials were loaded from token storage file for provider: \"%s\"" % (tokenKey), tokens[tokenKey], prettyPrint=True)
|
|
200
|
+
|
|
201
|
+
# parse token for cookie data parameters.
|
|
202
|
+
token:dict = tokens[tokenKey]
|
|
203
|
+
self._sp_dc:str = token.get("sp_dc", None)
|
|
204
|
+
self._sp_key:str = token.get("sp_key", None)
|
|
205
|
+
|
|
206
|
+
# validation.
|
|
207
|
+
if (self._sp_dc is None):
|
|
208
|
+
raise TokenError("Cookie credentials storage key \"%s\" did not contain an \"sp_dc\" key value" % (tokenKey))
|
|
209
|
+
if (self._sp_key is None):
|
|
210
|
+
raise TokenError("Cookie credentials storage key \"%s\" did not contain an \"sp_key\" key value" % (tokenKey))
|
|
211
|
+
|
|
212
|
+
# return token to caller.
|
|
213
|
+
return tokens[tokenKey]
|
|
214
|
+
|
|
215
|
+
# if we make it here, then it denotes that a token was not found
|
|
216
|
+
# for the specified key.
|
|
217
|
+
raise TokenError("Cookie credentials storage key not found: \"%s\"" % (tokenKey))
|
|
218
|
+
|
|
219
|
+
except TokenError as ex:
|
|
220
|
+
|
|
221
|
+
# trace.
|
|
222
|
+
_logsi.LogException(str(ex), ex, logToSystemLogger=False)
|
|
223
|
+
raise
|
|
224
|
+
|
|
225
|
+
except Exception as ex:
|
|
226
|
+
|
|
227
|
+
# trace.
|
|
228
|
+
_logsi.LogException("Could not load Spotify Web Player cookie credentials", ex, logToSystemLogger=False)
|
|
229
|
+
raise TokenError(str(ex))
|
|
230
|
+
|
|
231
|
+
finally:
|
|
232
|
+
|
|
233
|
+
# trace.
|
|
234
|
+
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def GetAccessTokenFromCookieCredentials(self) -> None:
|
|
238
|
+
"""
|
|
239
|
+
Get Spotify Web Player access token from stored Spotify Web Player cookie
|
|
240
|
+
credentials.
|
|
241
|
+
|
|
242
|
+
This will create a new session to the "https://open.spotify.com" url, passing
|
|
243
|
+
it the stored cookie credentials.
|
|
244
|
+
"""
|
|
245
|
+
apiMethodName:str = 'GetAccessTokenFromCookieCredentials'
|
|
246
|
+
apiMethodParms:SIMethodParmListContext = None
|
|
247
|
+
tracePrefix:str = 'SpotifyWebPlayerAccessToken exchange'
|
|
248
|
+
|
|
249
|
+
try:
|
|
250
|
+
|
|
251
|
+
# trace.
|
|
252
|
+
apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
|
|
253
|
+
apiMethodParms.AppendKeyValue("sp_dc", self._sp_dc)
|
|
254
|
+
apiMethodParms.AppendKeyValue("sp_key", self._sp_key)
|
|
255
|
+
_logsi.LogMethodParmList(SILevel.Verbose, "Exchange Spotify Web Player cookie credentials for OAuth2 authorization access token", apiMethodParms)
|
|
256
|
+
|
|
257
|
+
# create a session, using the specified header and generated cookie data.
|
|
258
|
+
session = requests.Session()
|
|
259
|
+
reqHeaders = {'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36"}
|
|
260
|
+
reqCookies = {'sp_dc': self._sp_dc, 'sp_key': self._sp_key}
|
|
261
|
+
reqParms={
|
|
262
|
+
"reason": "transport",
|
|
263
|
+
"productType": "web_player",
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
# trace.
|
|
267
|
+
_logsi.LogVerbose("Exchanging Spotify Web Player cookie credentials for OAuth2 authorization access token")
|
|
268
|
+
_logsi.LogDictionary(SILevel.Verbose, "%s http request: \"%s\" (cookies)" % (tracePrefix, SPOTIFY_WEBUI_URL_GET_ACCESS_TOKEN), reqCookies)
|
|
269
|
+
_logsi.LogDictionary(SILevel.Debug, "%s http request: \"%s\" (headers)" % (tracePrefix, SPOTIFY_WEBUI_URL_GET_ACCESS_TOKEN), reqHeaders)
|
|
270
|
+
_logsi.LogDictionary(SILevel.Verbose, "%s http request: \"%s\" (parms)" % (tracePrefix, SPOTIFY_WEBUI_URL_GET_ACCESS_TOKEN), reqParms)
|
|
271
|
+
|
|
272
|
+
# convert the spotify web player cookie credentials to an access token.
|
|
273
|
+
response = session.get(
|
|
274
|
+
SPOTIFY_WEBUI_URL_GET_ACCESS_TOKEN,
|
|
275
|
+
cookies=reqCookies,
|
|
276
|
+
headers=reqHeaders,
|
|
277
|
+
params=reqParms,
|
|
278
|
+
allow_redirects=False,
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
# trace.
|
|
282
|
+
if _logsi.IsOn(SILevel.Debug):
|
|
283
|
+
_logsi.LogObject(SILevel.Debug, "%s http response object - type=\"%s\", module=\"%s\"" % (tracePrefix, type(response).__name__, type(response).__module__), response)
|
|
284
|
+
|
|
285
|
+
# trace.
|
|
286
|
+
if _logsi.IsOn(SILevel.Debug):
|
|
287
|
+
_logsi.LogObject(SILevel.Debug, "%s http response [%s-%s] (response)" % (tracePrefix, response.status_code, response.reason), response)
|
|
288
|
+
if (response.headers):
|
|
289
|
+
_logsi.LogCollection(SILevel.Debug, "%s http response [%s-%s] (headers)" % (tracePrefix, response.status_code, response.reason), response.headers.items())
|
|
290
|
+
|
|
291
|
+
# raise exception if we could not get the access token, or if a redirect occured.
|
|
292
|
+
# the redirect usually indicates the sp_dc and sp_key are expired, and it's redirecting to a login page.
|
|
293
|
+
if (response.status_code == 302 and response.headers["Location"] == "/get_access_token?reason=transport&productType=web_player&_authfailed=1"):
|
|
294
|
+
_logsi.LogError("Unsuccessful token request, received code 302 and Location header %s. sp_dc and sp_key could be expired. Please update values in token storage file.", response.headers["Location"])
|
|
295
|
+
raise TokenError("Expired sp_dc, sp_key; please update values in token storage file")
|
|
296
|
+
if response.status_code != 200:
|
|
297
|
+
_logsi.LogVerbose("Unsuccessful token request, received code %i", response.status_code)
|
|
298
|
+
raise TokenError("Token exchange request failed: %s - %s" % (response.status_code, response.reason))
|
|
299
|
+
|
|
300
|
+
# load request response.
|
|
301
|
+
data = response.content.decode('utf-8')
|
|
302
|
+
responseData = json.loads(data)
|
|
303
|
+
|
|
304
|
+
# trace.
|
|
305
|
+
if _logsi.IsOn(SILevel.Verbose):
|
|
306
|
+
if isinstance(responseData, dict):
|
|
307
|
+
_logsi.LogDictionary(SILevel.Verbose, "%s http response [%s-%s] (json dict)" % (tracePrefix, response.status_code, response.reason), responseData, prettyPrint=True)
|
|
308
|
+
elif isinstance(responseData, list):
|
|
309
|
+
_logsi.LogArray(SILevel.Verbose, "%s http response [%s-%s] (json array)" % (tracePrefix, response.status_code, response.reason), responseData)
|
|
310
|
+
else:
|
|
311
|
+
_logsi.LogObject(SILevel.Verbose, "%s http response [%s-%s] (json object)" % (tracePrefix, response.status_code, response.reason), responseData)
|
|
312
|
+
|
|
313
|
+
# process the access token information.
|
|
314
|
+
self._AccessToken = responseData.get('accessToken', None)
|
|
315
|
+
self._ExpiresAt = int(responseData.get('accessTokenExpirationTimestampMs', 0)) // 1000
|
|
316
|
+
self._ExpiresIn = self._ExpiresAt - int(time.time())
|
|
317
|
+
self._IsAnonymous = bool(responseData.get('isAnonymous', False))
|
|
318
|
+
|
|
319
|
+
# set non-JSON response properties.
|
|
320
|
+
# calculate expire time based on ExpiresAt (epoch) seconds.
|
|
321
|
+
self._ExpireDateTimeUtc = datetime.utcfromtimestamp(self._ExpiresAt)
|
|
322
|
+
|
|
323
|
+
# the following can be used if the `datetime.utcfromtimestamp` is ever removed from python:
|
|
324
|
+
# unix_epoch = datetime(1970, 1, 1)
|
|
325
|
+
# dtUtcNow:datetime = datetime.now(timezone.utc)
|
|
326
|
+
# self._ExpireDateTimeUtc = dtUtcNow + timedelta(seconds=self._ExpiresIn)
|
|
327
|
+
|
|
328
|
+
# trace.
|
|
329
|
+
_logsi.LogObject(SILevel.Verbose, "Spotify Web Player access token object", self, excludeNonPublic=True)
|
|
330
|
+
|
|
331
|
+
except requests.TooManyRedirects as ex:
|
|
332
|
+
|
|
333
|
+
_logsi.LogException("Could not get Spotify Web Player access token; sp_dc and sp_key could be expired; Please update values in token storage file", ex, logToSystemLogger=False)
|
|
334
|
+
raise TokenError("Expired sp_dc, sp_key")
|
|
335
|
+
|
|
336
|
+
except Exception as ex:
|
|
337
|
+
|
|
338
|
+
_logsi.LogException("Could not get Spotify Web Player access token", ex, logToSystemLogger=False)
|
|
339
|
+
raise TokenError("Could not get Spotify Web Player access token")
|
|
340
|
+
|
|
341
|
+
finally:
|
|
342
|
+
|
|
343
|
+
# trace.
|
|
344
|
+
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)
|
|
@@ -31,7 +31,7 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
31
31
|
self._Availability:str = ""
|
|
32
32
|
self._BrandDisplayName:str = None
|
|
33
33
|
self._ClientId:str = None
|
|
34
|
-
self._DeviceId:str =
|
|
34
|
+
self._DeviceId:str = ""
|
|
35
35
|
self._DeviceType:str = None
|
|
36
36
|
self._GroupStatus:str = None
|
|
37
37
|
self._LibraryVersion:str = None
|
|
@@ -47,10 +47,6 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
47
47
|
self._Version:str = None
|
|
48
48
|
self._VoiceSupport:str = None
|
|
49
49
|
|
|
50
|
-
# non-Spotify properties.
|
|
51
|
-
self._IsActiveDevice:bool = None
|
|
52
|
-
self._IsInDeviceList:bool = None
|
|
53
|
-
|
|
54
50
|
if (root is None):
|
|
55
51
|
|
|
56
52
|
pass
|
|
@@ -62,7 +58,7 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
62
58
|
self._Availability = root.get('availability', "")
|
|
63
59
|
self._BrandDisplayName = root.get('brandDisplayName', None)
|
|
64
60
|
self._ClientId = root.get('clientID', None)
|
|
65
|
-
self._DeviceId = root.get('deviceID',
|
|
61
|
+
self._DeviceId = root.get('deviceID', "")
|
|
66
62
|
self._DeviceType = root.get('deviceType', None)
|
|
67
63
|
self._GroupStatus = root.get('groupStatus', None)
|
|
68
64
|
self._LibraryVersion = root.get('libraryVersion', None)
|
|
@@ -121,7 +117,7 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
121
117
|
Sets the ActiveUser property value.
|
|
122
118
|
"""
|
|
123
119
|
if (isinstance(value, str)) or (value is None):
|
|
124
|
-
self._ActiveUser = value
|
|
120
|
+
self._ActiveUser = value or ""
|
|
125
121
|
|
|
126
122
|
|
|
127
123
|
@property
|
|
@@ -203,7 +199,7 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
203
199
|
Sets the DeviceId property value.
|
|
204
200
|
"""
|
|
205
201
|
if (isinstance(value, str)) or (value is None):
|
|
206
|
-
self._DeviceId = value
|
|
202
|
+
self._DeviceId = value or ""
|
|
207
203
|
|
|
208
204
|
|
|
209
205
|
@property
|
|
@@ -448,44 +444,6 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
448
444
|
return self._VoiceSupport
|
|
449
445
|
|
|
450
446
|
|
|
451
|
-
# non-Spotify properties.
|
|
452
|
-
|
|
453
|
-
@property
|
|
454
|
-
def IsActiveDevice(self) -> bool:
|
|
455
|
-
"""
|
|
456
|
-
Returns True if this device is the currently active device;
|
|
457
|
-
otherwise, False.
|
|
458
|
-
"""
|
|
459
|
-
return self._IsActiveDevice
|
|
460
|
-
|
|
461
|
-
@IsActiveDevice.setter
|
|
462
|
-
def IsActiveDevice(self, value:bool):
|
|
463
|
-
"""
|
|
464
|
-
Sets the IsActiveDevice property value.
|
|
465
|
-
"""
|
|
466
|
-
if isinstance(value, bool):
|
|
467
|
-
self._IsActiveDevice = value
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
@property
|
|
471
|
-
def IsInDeviceList(self) -> bool:
|
|
472
|
-
"""
|
|
473
|
-
Returns the status of active device list verification:
|
|
474
|
-
* None - device list verification has not been performed for this device.
|
|
475
|
-
* True - device is a member of the active device list.
|
|
476
|
-
* False - device is NOT a member of the active device list.
|
|
477
|
-
"""
|
|
478
|
-
return self._IsInDeviceList
|
|
479
|
-
|
|
480
|
-
@IsInDeviceList.setter
|
|
481
|
-
def IsInDeviceList(self, value:bool):
|
|
482
|
-
"""
|
|
483
|
-
Sets the IsInDeviceList property value.
|
|
484
|
-
"""
|
|
485
|
-
if isinstance(value, bool):
|
|
486
|
-
self._IsInDeviceList = value
|
|
487
|
-
|
|
488
|
-
|
|
489
447
|
def Equals(self, obj) -> bool:
|
|
490
448
|
"""
|
|
491
449
|
Returns true if the specified object instance contains the same argument
|
|
@@ -522,8 +480,6 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
522
480
|
|
|
523
481
|
# don't compare the following:
|
|
524
482
|
# self._Aliases:list[ZeroconfGetInfoAlias] = []
|
|
525
|
-
# self._IsActiveDevice:bool = None
|
|
526
|
-
# self._IsInDeviceList:bool = None
|
|
527
483
|
# self._SupportedDrmMediaFormats:list[ZeroconfGetInfoDrmMediaFormat] = []
|
|
528
484
|
|
|
529
485
|
# objects attributes are equal.
|
|
@@ -566,8 +522,6 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
566
522
|
'HasAliases': self.HasAliases,
|
|
567
523
|
'IsAvailable': self.IsAvailable,
|
|
568
524
|
'IsBrandSonos': self.IsBrandSonos,
|
|
569
|
-
'IsActiveDevice': self._IsActiveDevice,
|
|
570
|
-
'IsInDeviceList': self._IsInDeviceList,
|
|
571
525
|
}
|
|
572
526
|
|
|
573
527
|
# combine base class results with these results.
|
|
@@ -614,6 +568,4 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
614
568
|
if self._TokenType is not None: msg = '%s\n TokenType="%s"' % (msg, str(self._TokenType))
|
|
615
569
|
if self._Version is not None: msg = '%s\n Version="%s"' % (msg, str(self._Version))
|
|
616
570
|
if self._VoiceSupport is not None: msg = '%s\n VoiceSupport="%s"' % (msg, str(self._VoiceSupport))
|
|
617
|
-
if self._IsActiveDevice is not None: msg = '%s\n IsActiveDevice="%s"' % (msg, str(self._IsActiveDevice))
|
|
618
|
-
if self._IsInDeviceList is not None: msg = '%s\n IsInDeviceList="%s"' % (msg, str(self._IsInDeviceList))
|
|
619
571
|
return msg
|
|
@@ -53,6 +53,14 @@ class ZeroconfResponse:
|
|
|
53
53
|
"""
|
|
54
54
|
return self._ResponseSource
|
|
55
55
|
|
|
56
|
+
@ResponseSource.setter
|
|
57
|
+
def ResponseSource(self, value:str):
|
|
58
|
+
"""
|
|
59
|
+
Sets the ResponseSource property value.
|
|
60
|
+
"""
|
|
61
|
+
if (isinstance(value, str)) or (value is None):
|
|
62
|
+
self._ResponseSource = value or ""
|
|
63
|
+
|
|
56
64
|
|
|
57
65
|
@property
|
|
58
66
|
def SpotifyError(self) -> int:
|
|
File without changes
|
|
File without changes
|
{spotifywebapiPython-1.0.147.dist-info → spotifywebapiPython-1.0.149.dist-info}/top_level.txt
RENAMED
|
File without changes
|