spotifywebapiPython 1.0.35__py3-none-any.whl → 1.0.147__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 (91) hide show
  1. {spotifywebapiPython-1.0.35.dist-info → spotifywebapiPython-1.0.147.dist-info}/LICENSE +1 -1
  2. {spotifywebapiPython-1.0.35.dist-info → spotifywebapiPython-1.0.147.dist-info}/METADATA +7 -6
  3. spotifywebapiPython-1.0.147.dist-info/RECORD +117 -0
  4. spotifywebapipython/__init__.py +2 -0
  5. spotifywebapipython/const.py +19 -1
  6. spotifywebapipython/docs/__init__.html +799 -3
  7. spotifywebapipython/docs/index.html +21 -3
  8. spotifywebapipython/docs/search.js +1 -1
  9. spotifywebapipython/docs/{spotifywebapiPython → spotifywebapipython}/const.html +72 -4
  10. spotifywebapipython/docs/{spotifywebapiPython → spotifywebapipython}/saappmessages.html +77 -3
  11. spotifywebapipython/docs/{spotifywebapiPython → spotifywebapipython}/sautils.html +63 -3
  12. spotifywebapipython/docs/{spotifywebapiPython → spotifywebapipython}/spotifyapierror.html +3 -3
  13. spotifywebapipython/docs/{spotifywebapiPython → spotifywebapipython}/spotifyapimessage.html +20 -3
  14. spotifywebapipython/docs/{spotifywebapiPython → spotifywebapipython}/spotifyauthtoken.html +39 -3
  15. spotifywebapipython/docs/{spotifywebapiPython → spotifywebapipython}/spotifyclient.html +2553 -364
  16. spotifywebapipython/docs/{spotifywebapiPython → spotifywebapipython}/spotifydiscovery.html +85 -52
  17. spotifywebapipython/docs/{spotifywebapiPython → spotifywebapipython}/spotifywebapiauthenticationerror.html +3 -3
  18. spotifywebapipython/docs/{spotifywebapiPython → spotifywebapipython}/spotifywebapierror.html +3 -3
  19. spotifywebapipython/models/__init__.py +8 -0
  20. spotifywebapipython/models/albumpagesaved.py +2 -1
  21. spotifywebapipython/models/albumpagesimplified.py +2 -1
  22. spotifywebapipython/models/albumsimplified.py +4 -5
  23. spotifywebapipython/models/artist.py +4 -5
  24. spotifywebapipython/models/artistinfo.py +282 -0
  25. spotifywebapipython/models/artistinfotourevent.py +127 -0
  26. spotifywebapipython/models/artistpage.py +2 -1
  27. spotifywebapipython/models/artistsimplified.py +4 -0
  28. spotifywebapipython/models/audiobookpagesimplified.py +2 -1
  29. spotifywebapipython/models/audiobooksimplified.py +4 -5
  30. spotifywebapipython/models/category.py +16 -0
  31. spotifywebapipython/models/categorypage.py +2 -1
  32. spotifywebapipython/models/chapterpagesimplified.py +2 -1
  33. spotifywebapipython/models/chaptersimplified.py +6 -7
  34. spotifywebapipython/models/context.py +1 -3
  35. spotifywebapipython/models/device.py +85 -2
  36. spotifywebapipython/models/episodepagesaved.py +2 -1
  37. spotifywebapipython/models/episodepagesimplified.py +2 -1
  38. spotifywebapipython/models/episodesaved.py +2 -2
  39. spotifywebapipython/models/episodesimplified.py +5 -6
  40. spotifywebapipython/models/imageobject.py +98 -0
  41. spotifywebapipython/models/pageobject.py +29 -4
  42. spotifywebapipython/models/playeractions.py +33 -11
  43. spotifywebapipython/models/playerplaystate.py +128 -13
  44. spotifywebapipython/models/playerqueueinfo.py +61 -4
  45. spotifywebapipython/models/playhistorypage.py +2 -1
  46. spotifywebapipython/models/playlist.py +6 -3
  47. spotifywebapipython/models/playlistpage.py +2 -1
  48. spotifywebapipython/models/playlistpagesimplified.py +2 -1
  49. spotifywebapipython/models/playlistsimplified.py +49 -7
  50. spotifywebapipython/models/playlisttrack.py +1 -0
  51. spotifywebapipython/models/playlisttracksummary.py +3 -1
  52. spotifywebapipython/models/searchresponse.py +1 -1
  53. spotifywebapipython/models/showpagesaved.py +2 -1
  54. spotifywebapipython/models/showpagesimplified.py +2 -1
  55. spotifywebapipython/models/showsaved.py +2 -2
  56. spotifywebapipython/models/showsimplified.py +8 -5
  57. spotifywebapipython/models/spotifyconnectdevice.py +188 -0
  58. spotifywebapipython/models/spotifyconnectdevices.py +628 -0
  59. spotifywebapipython/models/track.py +2 -1
  60. spotifywebapipython/models/trackpage.py +42 -1
  61. spotifywebapipython/models/trackpagesaved.py +2 -1
  62. spotifywebapipython/models/trackpagesimplified.py +2 -1
  63. spotifywebapipython/models/trackrecommendations.py +5 -5
  64. spotifywebapipython/models/tracksimplified.py +10 -3
  65. spotifywebapipython/models/userprofile.py +25 -1
  66. spotifywebapipython/models/userprofilesimplified.py +4 -5
  67. spotifywebapipython/models/zeroconfdiscoveryresult.py +599 -0
  68. spotifywebapipython/models/zeroconfproperty.py +93 -0
  69. spotifywebapipython/oauthcli/authclient.py +119 -19
  70. spotifywebapipython/saappmessages.py +21 -1
  71. spotifywebapipython/sautils.py +88 -1
  72. spotifywebapipython/spotifyapimessage.py +18 -1
  73. spotifywebapipython/spotifyauthtoken.py +26 -0
  74. spotifywebapipython/spotifyclient.py +4311 -525
  75. spotifywebapipython/spotifyconnectdeviceeventargs.py +67 -0
  76. spotifywebapipython/spotifydiscovery.py +326 -136
  77. spotifywebapipython/zeroconfapi/__init__.py +23 -0
  78. spotifywebapipython/zeroconfapi/authenticationtypes.py +38 -0
  79. spotifywebapipython/zeroconfapi/blobbuilder.py +370 -0
  80. spotifywebapipython/zeroconfapi/credentials.py +37 -0
  81. spotifywebapipython/zeroconfapi/cryptodiffiehellman.py +89 -0
  82. spotifywebapipython/zeroconfapi/helpers.py +64 -0
  83. spotifywebapipython/zeroconfapi/spotifyzeroconfapierror.py +108 -0
  84. spotifywebapipython/zeroconfapi/zeroconfconnect.py +1315 -0
  85. spotifywebapipython/zeroconfapi/zeroconfgetinfo.py +619 -0
  86. spotifywebapipython/zeroconfapi/zeroconfgetinfoalias.py +105 -0
  87. spotifywebapipython/zeroconfapi/zeroconfgetinfodrmmediaformat.py +90 -0
  88. spotifywebapipython/zeroconfapi/zeroconfresponse.py +141 -0
  89. spotifywebapiPython-1.0.35.dist-info/RECORD +0 -98
  90. {spotifywebapiPython-1.0.35.dist-info → spotifywebapiPython-1.0.147.dist-info}/WHEEL +0 -0
  91. {spotifywebapiPython-1.0.35.dist-info → spotifywebapiPython-1.0.147.dist-info}/top_level.txt +0 -0
@@ -28,6 +28,7 @@ class PlayerPlayState:
28
28
  """
29
29
  self._Actions:PlayerActions = None
30
30
  self._Context:Context = None
31
+ self._ItemType:str = None
31
32
  self._CurrentlyPlayingType:str = None
32
33
  self._Device:Device = None
33
34
  self._Item:object = None
@@ -37,6 +38,9 @@ class PlayerPlayState:
37
38
  self._ShuffleState:bool = None
38
39
  self._SmartShuffle:bool = None
39
40
  self._Timestamp:int = None
41
+
42
+ # helper properties, not part of the Spotify Web API interface.
43
+ self._IsEmpty:bool = True
40
44
 
41
45
  if (root is None):
42
46
 
@@ -55,7 +59,9 @@ class PlayerPlayState:
55
59
  # process all collections and objects.
56
60
  item:dict = root.get('actions',None)
57
61
  if item is not None:
58
- self._Actions = PlayerActions(root=item)
62
+ disallows:dict = item.get('disallows')
63
+ if disallows is not None:
64
+ self._Actions = PlayerActions(root=disallows)
59
65
 
60
66
  item:dict = root.get('context',None)
61
67
  if item is not None:
@@ -72,7 +78,31 @@ class PlayerPlayState:
72
78
  elif self._CurrentlyPlayingType == 'episode':
73
79
  self._Item = Episode(root=item)
74
80
 
75
-
81
+ # if root contains keys, then assume it is NOT empty.
82
+ if (len(root) > 0):
83
+ self._IsEmpty = False
84
+
85
+ # post load validations.
86
+ if self._Actions is None:
87
+ self._Actions = PlayerActions()
88
+ if self._Device is None:
89
+ self._Device = Device()
90
+ if self._CurrentlyPlayingType is None:
91
+ self._CurrentlyPlayingType = 'unknown'
92
+ if self._IsPlaying is None:
93
+ self._IsPlaying = False
94
+ if self._ProgressMS is None:
95
+ self._ProgressMS = 0
96
+ if self._RepeatState is None:
97
+ self._RepeatState = 'off'
98
+ if self._ShuffleState is None:
99
+ self._ShuffleState = False
100
+ if self._SmartShuffle is None:
101
+ self._SmartShuffle = False
102
+ if self._Timestamp is None:
103
+ self._Timestamp = 0
104
+
105
+
76
106
  def __repr__(self) -> str:
77
107
  return self.ToString()
78
108
 
@@ -126,6 +156,27 @@ class PlayerPlayState:
126
156
  return self._Item
127
157
 
128
158
 
159
+ @property
160
+ def ItemType(self) -> str:
161
+ """
162
+ The type of the currently playing episode; can be null.
163
+ This value will be null if the `Item` property value is null.
164
+
165
+ If not null, it can be one of `audiobook` or `podcast`.
166
+
167
+ Note that this is not a Spotify Web API property; it is loaded from our API so
168
+ that the type of episode can be determined programatically (e.g. audiobook or podcast).
169
+ """
170
+ return self._ItemType
171
+
172
+ @ItemType.setter
173
+ def ItemType(self, value:str):
174
+ """
175
+ Sets the ItemType property value.
176
+ """
177
+ self._ItemType = value
178
+
179
+
129
180
  @property
130
181
  def IsAdvertisement(self) -> bool:
131
182
  """
@@ -136,6 +187,39 @@ class PlayerPlayState:
136
187
  return False
137
188
 
138
189
 
190
+ @property
191
+ def IsEmpty(self) -> bool:
192
+ """
193
+ True if Spotify playstate returned an empty response; otherwise, false.
194
+
195
+ Note that for Sonos devices, the Spotify Web API reports an empty playstate since
196
+ the SoCo API is actually controlling player.
197
+
198
+ This is a helper property, and is not part of the Spotify Web API specification.
199
+ """
200
+ return self._IsEmpty
201
+
202
+ @IsEmpty.setter
203
+ def IsEmpty(self, value:bool):
204
+ """
205
+ Sets the IsEmpty property value.
206
+ """
207
+ if isinstance(value, bool):
208
+ self._IsEmpty = value
209
+
210
+
211
+ @property
212
+ def IsMuted(self) -> bool:
213
+ """
214
+ True if the player device volume is zero (muted) OR there is no device;
215
+ otherwise, false.
216
+ """
217
+ if self._Device is None:
218
+ return True
219
+ else:
220
+ return self._Device.IsMuted
221
+
222
+
139
223
  @property
140
224
  def IsPlaying(self) -> bool:
141
225
  """
@@ -148,7 +232,7 @@ class PlayerPlayState:
148
232
  """
149
233
  Sets the IsPlaying property value.
150
234
  """
151
- if value is None or isinstance(value, bool):
235
+ if isinstance(value, bool):
152
236
  self._IsPlaying = value
153
237
 
154
238
 
@@ -159,9 +243,9 @@ class PlayerPlayState:
159
243
 
160
244
  The `RepeatState` property contains the actual repeat setting.
161
245
  """
162
- if self._RepeatState is None or self._RepeatState == 'off':
163
- return False
164
- return True
246
+ if self._RepeatState != 'off':
247
+ return True
248
+ return False
165
249
 
166
250
 
167
251
  @property
@@ -169,9 +253,19 @@ class PlayerPlayState:
169
253
  """
170
254
  True if shuffle play is enabled; otherwise, False.
171
255
  """
172
- if self.ShuffleState is None or self.ShuffleState == 'off':
173
- return False
174
- return True
256
+ if (self.ShuffleState == 'on') or (self.ShuffleState == True):
257
+ return True
258
+ return False
259
+
260
+
261
+ @property
262
+ def IsSmartShuffleEnabled(self) -> bool:
263
+ """
264
+ True if smart shuffle play is enabled; otherwise, False.
265
+ """
266
+ if (self.SmartShuffle == 'on' or self.SmartShuffle == True):
267
+ return True
268
+ return False
175
269
 
176
270
 
177
271
  @property
@@ -181,6 +275,14 @@ class PlayerPlayState:
181
275
  """
182
276
  return self._ProgressMS
183
277
 
278
+ @ProgressMS.setter
279
+ def ProgressMS(self, value:int):
280
+ """
281
+ Sets the ProgressMS property value.
282
+ """
283
+ if isinstance(value, int):
284
+ self._ProgressMS = value
285
+
184
286
 
185
287
  @property
186
288
  def RepeatState(self) -> str:
@@ -191,17 +293,17 @@ class PlayerPlayState:
191
293
 
192
294
 
193
295
  @property
194
- def ShuffleState(self) -> str:
296
+ def ShuffleState(self) -> bool:
195
297
  """
196
- If shuffle is `on` or `off`.
298
+ If shuffle is enabled, True or False.
197
299
  """
198
300
  return self._ShuffleState
199
301
 
200
302
 
201
303
  @property
202
- def SmartShuffle(self) -> str:
304
+ def SmartShuffle(self) -> bool:
203
305
  """
204
- If smart shuffle is `on` or `off`.
306
+ If smart shuffle is enabled, True or False.
205
307
  """
206
308
  return self._SmartShuffle
207
309
 
@@ -237,6 +339,14 @@ class PlayerPlayState:
237
339
  """
238
340
  return self._Timestamp
239
341
 
342
+ @Timestamp.setter
343
+ def Timestamp(self, value:int):
344
+ """
345
+ Sets the Timestamp property value.
346
+ """
347
+ if isinstance(value, int):
348
+ self._Timestamp = value
349
+
240
350
 
241
351
  def ToDictionary(self) -> dict:
242
352
  """
@@ -260,6 +370,7 @@ class PlayerPlayState:
260
370
 
261
371
  result:dict = \
262
372
  {
373
+ 'is_empty': self._IsEmpty,
263
374
  'actions': actions,
264
375
  'context': context,
265
376
  'currently_playing_type': self._CurrentlyPlayingType,
@@ -270,6 +381,7 @@ class PlayerPlayState:
270
381
  'shuffle_state': self._ShuffleState,
271
382
  'smart_shuffle': self._SmartShuffle,
272
383
  'timestamp': self._Timestamp,
384
+ 'item_type': self._ItemType,
273
385
  'item': item,
274
386
  }
275
387
  return result
@@ -282,13 +394,16 @@ class PlayerPlayState:
282
394
  msg:str = 'PlayerPlayState:'
283
395
  #if self._Actions is not None: msg = '%s\n %s' % (msg, str(self._Actions))
284
396
  if self._CurrentlyPlayingType is not None: msg = '%s\n CurrentlyPlayingType="%s"' % (msg, str(self._CurrentlyPlayingType))
397
+ if self._ItemType is not None: msg = '%s\n ItemType="%s"' % (msg, str(self._ItemType))
285
398
  if self._Device is not None: msg = '%s\n Device Name="%s"' % (msg, str(self._Device.Name))
286
399
  #if self._Context is not None: msg = '%s\n %s' % (msg, str(self._Context))
287
400
  #if self._Item is not None: msg = '%s\n %s' % (msg, str(self._Item))
401
+ if self.IsMuted is not None: msg = '%s\n IsMuted="%s"' % (msg, str(self.IsMuted))
288
402
  if self._IsPlaying is not None: msg = '%s\n IsPlaying="%s"' % (msg, str(self._IsPlaying))
289
403
  if self._ProgressMS is not None: msg = '%s\n ProgressMS="%s"' % (msg, str(self._ProgressMS))
290
404
  if self._RepeatState is not None: msg = '%s\n RepeatState="%s"' % (msg, str(self._RepeatState))
291
405
  if self._ShuffleState is not None: msg = '%s\n ShuffleState="%s"' % (msg, str(self._ShuffleState))
292
406
  if self._SmartShuffle is not None: msg = '%s\n SmartShuffle="%s"' % (msg, str(self._SmartShuffle))
293
407
  if self._Timestamp is not None: msg = '%s\n Timestamp="%s"' % (msg, str(self._Timestamp))
408
+ msg = '%s\n IsEmpty="%s"' % (msg, str(self.IsEmpty))
294
409
  return msg
@@ -24,6 +24,7 @@ class PlayerQueueInfo:
24
24
  """
25
25
  self._CurrentlyPlaying:object = None
26
26
  self._CurrentlyPlayingType:str = None
27
+ self._DateLastRefreshed:float = 0
27
28
  self._Queue:list[object] = []
28
29
 
29
30
  if (root is None):
@@ -42,15 +43,25 @@ class PlayerQueueInfo:
42
43
  elif self._CurrentlyPlayingType == 'episode':
43
44
  self._CurrentlyPlaying = Episode(root=item)
44
45
 
46
+ # for some reason, the Spotify Web API will return up to 10 duplicate items
47
+ # with the same information! for example:
48
+ # - if there is only 1 item in the queue, then 10 duplicate items are returned by the Spotify Web API.
49
+ # - if there are 5 items in the queue, then 5 duplicate items are returned by the Spotify Web API.
50
+ # we will check for this scenario, and only return non-duplicate items if so.
45
51
  items:list = root.get('queue',None)
46
52
  if items is not None:
47
53
  for item in items:
54
+
48
55
  itemType = item.get('type','unknown')
49
56
  if itemType == 'track':
50
- self._Queue.append(Track(root=item))
57
+ track:Track = Track(root=item)
58
+ if (track) and (not self.ContainsUri(track.Uri)):
59
+ self._Queue.append(track)
51
60
  elif itemType == 'episode':
52
- self._Queue.append(Episode(root=item))
53
-
61
+ episode:Episode = Episode(root=item)
62
+ if (episode) and (not self.ContainsUri(episode.Uri)):
63
+ self._Queue.append(episode)
64
+
54
65
 
55
66
  def __repr__(self) -> str:
56
67
  return self.ToString()
@@ -78,6 +89,30 @@ class PlayerQueueInfo:
78
89
  return self._CurrentlyPlayingType
79
90
 
80
91
 
92
+ @property
93
+ def DateLastRefreshed(self) -> float:
94
+ """
95
+ Date and time items were was last refreshed, in unix epoch format (e.g. 1669123919.331225).
96
+ A value of zero indicates the date was unknown.
97
+
98
+ Note that this attribute does not exist in the Spotify Web API;
99
+ it was added here for convenience.
100
+ """
101
+ return self._DateLastRefreshed
102
+
103
+ @DateLastRefreshed.setter
104
+ def DateLastRefreshed(self, value:float):
105
+ """
106
+ Sets the DateLastRefreshed property value.
107
+ """
108
+ if (value is None):
109
+ self._DateLastRefreshed = 0
110
+ elif isinstance(value, float):
111
+ self._DateLastRefreshed = value
112
+ elif isinstance(value, int):
113
+ self._DateLastRefreshed = float(value)
114
+
115
+
81
116
  @property
82
117
  def Queue(self) -> list[object]:
83
118
  """
@@ -122,6 +157,26 @@ class PlayerQueueInfo:
122
157
  return result
123
158
 
124
159
 
160
+ def ContainsUri(self, uri:str) -> bool:
161
+ """
162
+ Checks the `Queue` collection to see if an item already exists with the
163
+ specified Uri value.
164
+
165
+ Returns True if the specified Uri value exists in the collection; otherwise, False.
166
+ """
167
+ result:bool = False
168
+
169
+ if (uri is None):
170
+ return result
171
+
172
+ for item in self._Queue:
173
+ if item.Uri == uri:
174
+ result = True
175
+ break
176
+
177
+ return result
178
+
179
+
125
180
  def ToDictionary(self) -> dict:
126
181
  """
127
182
  Returns a dictionary representation of the class.
@@ -132,8 +187,9 @@ class PlayerQueueInfo:
132
187
 
133
188
  result:dict = \
134
189
  {
135
- 'currently_playing': currentlyPlaying,
190
+ 'date_last_refreshed': self._DateLastRefreshed,
136
191
  'currently_playing_type': self._CurrentlyPlayingType,
192
+ 'currently_playing': currentlyPlaying,
137
193
  'queue': [ item.ToDictionary() for item in self._Queue ],
138
194
  }
139
195
  return result
@@ -146,4 +202,5 @@ class PlayerQueueInfo:
146
202
  msg:str = 'PlayerQueueInfo:'
147
203
  if self._CurrentlyPlayingType is not None: msg = '%s\n CurrentlyPlayingType="%s"' % (msg, str(self._CurrentlyPlayingType))
148
204
  if self.QueueCount is not None: msg = '%s\n QueueCount="%s"' % (msg, str(self.QueueCount))
205
+ msg = '%s\n DateLastRefreshed=%s' % (msg, str(self._DateLastRefreshed))
149
206
  return msg
@@ -39,7 +39,8 @@ class PlayHistoryPage(PageObject):
39
39
  items:list = root.get('items',None)
40
40
  if items is not None:
41
41
  for item in items:
42
- self._Items.append(PlayHistory(root=item))
42
+ if item is not None:
43
+ self._Items.append(PlayHistory(root=item))
43
44
 
44
45
 
45
46
  def __repr__(self) -> str:
@@ -31,7 +31,10 @@ class Playlist(PlaylistSimplified):
31
31
 
32
32
  if (root is None):
33
33
 
34
- pass
34
+ # if not building the class from json response, then initialize various properties as
35
+ # the playlist is probably being built manually.
36
+ self._Followers = Followers()
37
+ self._Tracks = PlaylistPage()
35
38
 
36
39
  else:
37
40
 
@@ -73,9 +76,9 @@ class Playlist(PlaylistSimplified):
73
76
 
74
77
  def GetTracks(self) -> list[Track]:
75
78
  """
76
- Gets a list of all tracks contained in the underlying `Items` list.
79
+ Gets a list of all tracks contained in the underlying `Tracks.Items` list.
77
80
 
78
- This is a convenience method so one does not have to loop through the `Items`
81
+ This is a convenience method so one does not have to loop through the `Tracks.Items`
79
82
  array of PlaylistPage objects to get the list of tracks.
80
83
  """
81
84
  result:list[Track] = []
@@ -39,7 +39,8 @@ class PlaylistPage(PageObject):
39
39
  items:list = root.get('items',None)
40
40
  if items is not None:
41
41
  for item in items:
42
- self._Items.append(PlaylistTrack(root=item))
42
+ if item is not None:
43
+ self._Items.append(PlaylistTrack(root=item))
43
44
 
44
45
 
45
46
  def __repr__(self) -> str:
@@ -38,7 +38,8 @@ class PlaylistPageSimplified(PageObject):
38
38
  items:list = root.get('items',None)
39
39
  if items is not None:
40
40
  for item in items:
41
- self._Items.append(PlaylistSimplified(root=item))
41
+ if item is not None:
42
+ self._Items.append(PlaylistSimplified(root=item))
42
43
 
43
44
 
44
45
  def __repr__(self) -> str:
@@ -38,7 +38,10 @@ class PlaylistSimplified:
38
38
 
39
39
  if (root is None):
40
40
 
41
- pass
41
+ # if not building the class from json response, then initialize various properties as
42
+ # the playlist is probably being built manually.
43
+ self._ExternalUrls = ExternalUrls()
44
+ self._Tracks = PlaylistTrackSummary()
42
45
 
43
46
  else:
44
47
 
@@ -116,6 +119,14 @@ class PlaylistSimplified:
116
119
  Only returned for modified, verified playlists; otherwise null.
117
120
  """
118
121
  return self._Description
122
+
123
+ @Description.setter
124
+ def Description(self, value:str):
125
+ """
126
+ Sets the Description property value.
127
+ """
128
+ if isinstance(value, str):
129
+ self._Description = value
119
130
 
120
131
 
121
132
  @property
@@ -137,12 +148,20 @@ class PlaylistSimplified:
137
148
  @property
138
149
  def Id(self) -> str:
139
150
  """
140
- The Spotify user ID for the playlist.
151
+ The Spotify ID for the playlist.
141
152
 
142
153
  Example: `5v5ETK9WFXAnGQ3MRubKuE`
143
154
  """
144
155
  return self._Id
145
156
 
157
+ @Id.setter
158
+ def Id(self, value:str):
159
+ """
160
+ Sets the Id property value.
161
+ """
162
+ if isinstance(value, str):
163
+ self._Id = value
164
+
146
165
 
147
166
  @property
148
167
  def Images(self) -> list[ImageObject]:
@@ -159,12 +178,10 @@ class PlaylistSimplified:
159
178
  @property
160
179
  def ImageUrl(self) -> str:
161
180
  """
162
- Gets the first image url in the `Images` list, if images are defined;
163
- otherwise, null.
181
+ Returns the highest resolution order image from the `Images` list, if images
182
+ are defined; otherwise, null.
164
183
  """
165
- if len(self._Images) > 0:
166
- return self._Images[0].Url
167
- return None
184
+ return ImageObject.GetImageHighestResolution(self._Images)
168
185
 
169
186
 
170
187
  @property
@@ -174,6 +191,14 @@ class PlaylistSimplified:
174
191
  """
175
192
  return self._Name
176
193
 
194
+ @Name.setter
195
+ def Name(self, value:str):
196
+ """
197
+ Sets the Name property value.
198
+ """
199
+ if isinstance(value, str):
200
+ self._Name = value
201
+
177
202
 
178
203
  @property
179
204
  def Owner(self) -> Owner:
@@ -219,6 +244,14 @@ class PlaylistSimplified:
219
244
  """
220
245
  return self._Type
221
246
 
247
+ @Type.setter
248
+ def Type(self, value:str):
249
+ """
250
+ Sets the Type property value.
251
+ """
252
+ if isinstance(value, str):
253
+ self._Type = value
254
+
222
255
 
223
256
  @property
224
257
  def Uri(self) -> str:
@@ -229,6 +262,14 @@ class PlaylistSimplified:
229
262
  """
230
263
  return self._Uri
231
264
 
265
+ @Uri.setter
266
+ def Uri(self, value:str):
267
+ """
268
+ Sets the Uri property value.
269
+ """
270
+ if isinstance(value, str):
271
+ self._Uri = value
272
+
232
273
 
233
274
  def ToDictionary(self) -> dict:
234
275
  """
@@ -253,6 +294,7 @@ class PlaylistSimplified:
253
294
  'external_urls': externalUrls,
254
295
  'href': self._Href,
255
296
  'id': self._Id,
297
+ 'image_url': self.ImageUrl,
256
298
  'images': [ item.ToDictionary() for item in self._Images ],
257
299
  'name': self._Name,
258
300
  'owner': owner,
@@ -116,6 +116,7 @@ class PlaylistTrack:
116
116
  {
117
117
  'added_at': self._AddedAt,
118
118
  'added_by': addedBy,
119
+ 'image_url': self.ImageUrl,
119
120
  'is_local': self._IsLocal,
120
121
  'track': track
121
122
  }
@@ -23,7 +23,9 @@ class PlaylistTrackSummary:
23
23
 
24
24
  if (root is None):
25
25
 
26
- pass
26
+ # if not building the class from json response, then initialize various properties as
27
+ # the playlist is probably being built manually.
28
+ self._Total = 0
27
29
 
28
30
  else:
29
31
 
@@ -106,7 +106,7 @@ class SearchResponse:
106
106
  return self._Albums
107
107
 
108
108
  @Albums.setter
109
- def Albums(self, value:str):
109
+ def Albums(self, value:AlbumPageSimplified):
110
110
  """
111
111
  Sets the Albums property value.
112
112
  """
@@ -39,7 +39,8 @@ class ShowPageSaved(PageObject):
39
39
  items:list = root.get('items',None)
40
40
  if items is not None:
41
41
  for item in items:
42
- self._Items.append(ShowSaved(root=item))
42
+ if item is not None:
43
+ self._Items.append(ShowSaved(root=item))
43
44
 
44
45
 
45
46
  def __repr__(self) -> str:
@@ -38,7 +38,8 @@ class ShowPageSimplified(PageObject):
38
38
  items:list = root.get('items',None)
39
39
  if items is not None:
40
40
  for item in items:
41
- self._Items.append(ShowSimplified(root=item))
41
+ if item is not None:
42
+ self._Items.append(ShowSimplified(root=item))
42
43
 
43
44
 
44
45
  def __repr__(self) -> str:
@@ -51,8 +51,8 @@ class ShowSaved:
51
51
 
52
52
  Timestamps are returned in ISO 8601 format as Coordinated Universal Time (UTC) with a zero
53
53
  offset: YYYY-MM-DDTHH:MM:SSZ. If the time is imprecise (for example, the date/time of an
54
- album release), an additional field indicates the precision; see for example, release_date
55
- in an album object.
54
+ episode release), an additional field indicates the precision; see for example, release_date
55
+ in an episode object.
56
56
  """
57
57
  return self._AddedAt
58
58
 
@@ -130,7 +130,7 @@ class ShowSimplified:
130
130
  @property
131
131
  def Explicit(self) -> bool:
132
132
  """
133
- Whether or not the show has explicit lyrics (true = yes it does; false = no it does not OR unknown).
133
+ Whether or not the show has explicit content (true = yes it does; false = no it does not OR unknown).
134
134
  """
135
135
  return self._Explicit
136
136
 
@@ -147,6 +147,7 @@ class ShowSimplified:
147
147
  def Href(self) -> str:
148
148
  """
149
149
  A link to the Web API endpoint providing full details of the show.
150
+ Example: `https://api.spotify.com/v1/shows/3IM0lmZxpFAY7CwMuv9H4g?locale=en-US%2Cen%3Bq%3D0.9`
150
151
  """
151
152
  return self._Href
152
153
 
@@ -164,6 +165,7 @@ class ShowSimplified:
164
165
  def Id(self) -> str:
165
166
  """
166
167
  The Spotify ID for the show.
168
+ Example: `3IM0lmZxpFAY7CwMuv9H4g`
167
169
  """
168
170
  return self._Id
169
171
 
@@ -182,10 +184,8 @@ class ShowSimplified:
182
184
  Gets the first image url in the `Images` list, if images are defined;
183
185
  otherwise, null.
184
186
  """
185
- if len(self._Images) > 0:
186
- return self._Images[0].Url
187
- return None
188
-
187
+ return ImageObject.GetImageHighestResolution(self._Images)
188
+
189
189
 
190
190
  @property
191
191
  def IsExternallyHosted(self) -> bool:
@@ -210,6 +210,8 @@ class ShowSimplified:
210
210
  def MediaType(self) -> str:
211
211
  """
212
212
  The media type of the show.
213
+
214
+ Example: `audio`
213
215
  """
214
216
  return self._MediaType
215
217
 
@@ -272,6 +274,7 @@ class ShowSimplified:
272
274
  'href': self._Href,
273
275
  'html_description': self._HtmlDescription,
274
276
  'id': self._Id,
277
+ 'image_url': self.ImageUrl,
275
278
  'images': [ item.ToDictionary() for item in self._Images ],
276
279
  'is_externally_hosted': self._IsExternallyHosted,
277
280
  'languages': [ item for item in self._Languages ],