spotifywebapiPython 1.0.242__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.
Files changed (138) hide show
  1. spotifywebapipython/__init__.py +35 -0
  2. spotifywebapipython/const.py +114 -0
  3. spotifywebapipython/docs/__init__.html +2156 -0
  4. spotifywebapipython/docs/codecopy.js +70 -0
  5. spotifywebapipython/docs/index.html +514 -0
  6. spotifywebapipython/docs/search.js +46 -0
  7. spotifywebapipython/docs/spotifywebapipython/const.html +636 -0
  8. spotifywebapipython/docs/spotifywebapipython/saappmessages.html +540 -0
  9. spotifywebapipython/docs/spotifywebapipython/sautils.html +620 -0
  10. spotifywebapipython/docs/spotifywebapipython/spotifyapierror.html +341 -0
  11. spotifywebapipython/docs/spotifywebapipython/spotifyapimessage.html +598 -0
  12. spotifywebapipython/docs/spotifywebapipython/spotifyauthtoken.html +612 -0
  13. spotifywebapipython/docs/spotifywebapipython/spotifyclient.html +16557 -0
  14. spotifywebapipython/docs/spotifywebapipython/spotifydiscovery.html +518 -0
  15. spotifywebapipython/docs/spotifywebapipython/spotifywebapiauthenticationerror.html +421 -0
  16. spotifywebapipython/docs/spotifywebapipython/spotifywebapierror.html +400 -0
  17. spotifywebapipython/docs/spotifywebapipython/spotifywebplayertoken.html +635 -0
  18. spotifywebapipython/docs/spotifywebapipython.ico +0 -0
  19. spotifywebapipython/docs/spotifywebapipython_OLD.ico +0 -0
  20. spotifywebapipython/models/__init__.py +121 -0
  21. spotifywebapipython/models/album.py +170 -0
  22. spotifywebapipython/models/albumpagesaved.py +85 -0
  23. spotifywebapipython/models/albumpagesimplified.py +88 -0
  24. spotifywebapipython/models/albumsaved.py +102 -0
  25. spotifywebapipython/models/albumsimplified.py +308 -0
  26. spotifywebapipython/models/artist.py +146 -0
  27. spotifywebapipython/models/artistinfo.py +282 -0
  28. spotifywebapipython/models/artistinfotourevent.py +127 -0
  29. spotifywebapipython/models/artistpage.py +70 -0
  30. spotifywebapipython/models/artistsimplified.py +163 -0
  31. spotifywebapipython/models/audiobook.py +87 -0
  32. spotifywebapipython/models/audiobookpagesimplified.py +88 -0
  33. spotifywebapipython/models/audiobooksimplified.py +362 -0
  34. spotifywebapipython/models/audiofeatures.py +333 -0
  35. spotifywebapipython/models/author.py +67 -0
  36. spotifywebapipython/models/category.py +168 -0
  37. spotifywebapipython/models/categorypage.py +70 -0
  38. spotifywebapipython/models/chapter.py +84 -0
  39. spotifywebapipython/models/chapterpagesimplified.py +88 -0
  40. spotifywebapipython/models/chaptersimplified.py +387 -0
  41. spotifywebapipython/models/context.py +113 -0
  42. spotifywebapipython/models/copyright.py +79 -0
  43. spotifywebapipython/models/device.py +301 -0
  44. spotifywebapipython/models/episode.py +84 -0
  45. spotifywebapipython/models/episodepagesaved.py +85 -0
  46. spotifywebapipython/models/episodepagesimplified.py +88 -0
  47. spotifywebapipython/models/episodesaved.py +99 -0
  48. spotifywebapipython/models/episodesimplified.py +370 -0
  49. spotifywebapipython/models/explicitcontent.py +80 -0
  50. spotifywebapipython/models/externalids.py +91 -0
  51. spotifywebapipython/models/externalurls.py +104 -0
  52. spotifywebapipython/models/followers.py +81 -0
  53. spotifywebapipython/models/imageobject.py +193 -0
  54. spotifywebapipython/models/imagevibrantcolors.py +182 -0
  55. spotifywebapipython/models/linkedfrom.py +165 -0
  56. spotifywebapipython/models/narrator.py +67 -0
  57. spotifywebapipython/models/owner.py +162 -0
  58. spotifywebapipython/models/pageobject.py +343 -0
  59. spotifywebapipython/models/playeractions.py +196 -0
  60. spotifywebapipython/models/playerlastplayedinfo.py +334 -0
  61. spotifywebapipython/models/playerplaystate.py +467 -0
  62. spotifywebapipython/models/playerqueueinfo.py +207 -0
  63. spotifywebapipython/models/playhistory.py +136 -0
  64. spotifywebapipython/models/playhistorypage.py +85 -0
  65. spotifywebapipython/models/playlist.py +125 -0
  66. spotifywebapipython/models/playlistpage.py +85 -0
  67. spotifywebapipython/models/playlistpagesimplified.py +107 -0
  68. spotifywebapipython/models/playlistsimplified.py +334 -0
  69. spotifywebapipython/models/playlisttrack.py +143 -0
  70. spotifywebapipython/models/playlisttracksummary.py +80 -0
  71. spotifywebapipython/models/recommendationseed.py +135 -0
  72. spotifywebapipython/models/restrictions.py +86 -0
  73. spotifywebapipython/models/resumepoint.py +79 -0
  74. spotifywebapipython/models/searchresponse.py +391 -0
  75. spotifywebapipython/models/searchresultbase.py +299 -0
  76. spotifywebapipython/models/show.py +87 -0
  77. spotifywebapipython/models/showpagesaved.py +85 -0
  78. spotifywebapipython/models/showpagesimplified.py +88 -0
  79. spotifywebapipython/models/showsaved.py +99 -0
  80. spotifywebapipython/models/showsimplified.py +320 -0
  81. spotifywebapipython/models/spotifyconnectdevice.py +321 -0
  82. spotifywebapipython/models/spotifyconnectdevices.py +441 -0
  83. spotifywebapipython/models/track.py +142 -0
  84. spotifywebapipython/models/trackpage.py +110 -0
  85. spotifywebapipython/models/trackpagesaved.py +85 -0
  86. spotifywebapipython/models/trackpagesimplified.py +88 -0
  87. spotifywebapipython/models/trackrecommendations.py +88 -0
  88. spotifywebapipython/models/tracksaved.py +99 -0
  89. spotifywebapipython/models/tracksimplified.py +398 -0
  90. spotifywebapipython/models/userprofile.py +184 -0
  91. spotifywebapipython/models/userprofilesimplified.py +206 -0
  92. spotifywebapipython/models/zeroconfdiscoveryresult.py +592 -0
  93. spotifywebapipython/models/zeroconfproperty.py +93 -0
  94. spotifywebapipython/oauthcli/__init__.py +7 -0
  95. spotifywebapipython/oauthcli/authclient.py +1229 -0
  96. spotifywebapipython/saappmessages.py +86 -0
  97. spotifywebapipython/sautils.py +285 -0
  98. spotifywebapipython/spotifyapierror.py +66 -0
  99. spotifywebapipython/spotifyapimessage.py +269 -0
  100. spotifywebapipython/spotifyauthtoken.py +264 -0
  101. spotifywebapipython/spotifyclient.py +17885 -0
  102. spotifywebapipython/spotifyconnect/__init__.py +19 -0
  103. spotifywebapipython/spotifyconnect/spotifyconnectdeviceeventargs.py +67 -0
  104. spotifywebapipython/spotifyconnect/spotifyconnectdirectorytask.py +2564 -0
  105. spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastapptask.py +467 -0
  106. spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastcontroller.py +701 -0
  107. spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastlistener.py +359 -0
  108. spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastmultizonelistener.py +212 -0
  109. spotifywebapipython/spotifyconnect/spotifyconnectzeroconfexceptions.py +20 -0
  110. spotifywebapipython/spotifyconnect/spotifyconnectzeroconflistener.py +335 -0
  111. spotifywebapipython/spotifydiscovery.py +473 -0
  112. spotifywebapipython/spotifymediatypes.py +53 -0
  113. spotifywebapipython/spotifywebapiauthenticationerror.py +122 -0
  114. spotifywebapipython/spotifywebapierror.py +106 -0
  115. spotifywebapipython/spotifywebplayertoken.py +743 -0
  116. spotifywebapipython/vibrant/__init__.py +17 -0
  117. spotifywebapipython/vibrant/generator.py +261 -0
  118. spotifywebapipython/vibrant/image.py +100 -0
  119. spotifywebapipython/vibrant/main.py +34 -0
  120. spotifywebapipython/vibrant/models.py +93 -0
  121. spotifywebapipython/vibrant/utils.py +56 -0
  122. spotifywebapipython/zeroconfapi/__init__.py +23 -0
  123. spotifywebapipython/zeroconfapi/authenticationtypes.py +38 -0
  124. spotifywebapipython/zeroconfapi/blobbuilder.py +370 -0
  125. spotifywebapipython/zeroconfapi/credentials.py +37 -0
  126. spotifywebapipython/zeroconfapi/cryptodiffiehellman.py +89 -0
  127. spotifywebapipython/zeroconfapi/helpers.py +64 -0
  128. spotifywebapipython/zeroconfapi/spotifyzeroconfapierror.py +108 -0
  129. spotifywebapipython/zeroconfapi/zeroconfconnect.py +1327 -0
  130. spotifywebapipython/zeroconfapi/zeroconfgetinfo.py +572 -0
  131. spotifywebapipython/zeroconfapi/zeroconfgetinfoalias.py +109 -0
  132. spotifywebapipython/zeroconfapi/zeroconfgetinfodrmmediaformat.py +90 -0
  133. spotifywebapipython/zeroconfapi/zeroconfresponse.py +195 -0
  134. spotifywebapipython-1.0.242.dist-info/LICENSE +22 -0
  135. spotifywebapipython-1.0.242.dist-info/METADATA +219 -0
  136. spotifywebapipython-1.0.242.dist-info/RECORD +138 -0
  137. spotifywebapipython-1.0.242.dist-info/WHEEL +5 -0
  138. spotifywebapipython-1.0.242.dist-info/top_level.txt +1 -0
@@ -0,0 +1,441 @@
1
+ # external package imports.
2
+ from datetime import datetime
3
+ from typing import Iterator
4
+
5
+ # our package imports.
6
+ from ..sautils import export
7
+ from .device import Device
8
+ from .spotifyconnectdevice import SpotifyConnectDevice
9
+ from .playerplaystate import PlayerPlayState
10
+ from .zeroconfdiscoveryresult import ZeroconfDiscoveryResult
11
+ from spotifywebapipython.zeroconfapi import ZeroconfGetInfo, ZeroconfGetInfoAlias
12
+
13
+ # get smartinspect logger reference; create a new session for this module name.
14
+ from smartinspectpython.siauto import SIAuto, SILevel, SISession, SIMethodParmListContext, SIColors
15
+ import logging
16
+
17
+ _logsi:SISession = SIAuto.Si.GetSession(__name__)
18
+ if (_logsi == None):
19
+ _logsi = SIAuto.Si.AddSession(__name__, True)
20
+ _logsi.SystemLogger = logging.getLogger(__name__)
21
+
22
+
23
+ @export
24
+ class SpotifyConnectDevices():
25
+ """
26
+ Spotify Connect Devices collection.
27
+ """
28
+
29
+ def __init__(self) -> None:
30
+ """
31
+ Initializes a new instance of the class.
32
+ """
33
+ self._DateLastRefreshed:int = 0
34
+ self._Items:list[SpotifyConnectDevice] = []
35
+
36
+
37
+ def __getitem__(self, key) -> SpotifyConnectDevice:
38
+ return self._Items[key]
39
+
40
+
41
+ def __iter__(self) -> Iterator:
42
+ return iter(self._Items)
43
+
44
+
45
+ def __len__(self) -> int:
46
+ return len(self._Items)
47
+
48
+
49
+ def __repr__(self) -> str:
50
+ return self.ToString()
51
+
52
+
53
+ def __str__(self) -> str:
54
+ return self.ToString()
55
+
56
+
57
+ @property
58
+ def AgeLastRefreshed(self) -> float:
59
+ """
60
+ Number of seconds between the current date time and the `DateLastRefreshed` property value.
61
+ """
62
+ return (datetime.utcnow().timestamp() - self._DateLastRefreshed)
63
+
64
+
65
+ @property
66
+ def DateLastRefreshed(self) -> float:
67
+ """
68
+ Date and time the device list was last refreshed, in unix epoch format (e.g. 1669123919.331225).
69
+ """
70
+ return self._DateLastRefreshed
71
+
72
+ @DateLastRefreshed.setter
73
+ def DateLastRefreshed(self, value:float):
74
+ """
75
+ Sets the DateLastRefreshed property value.
76
+ """
77
+ if isinstance(value, float):
78
+ self._DateLastRefreshed = value
79
+
80
+
81
+ @property
82
+ def Items(self) -> list[SpotifyConnectDevice]:
83
+ """
84
+ Array of `SpotifyConnectDevice` objects.
85
+ """
86
+ return self._Items
87
+
88
+
89
+ @property
90
+ def ItemsCount(self) -> int:
91
+ """
92
+ Number of objects in the `Items` property array.
93
+ """
94
+ if self._Items is not None:
95
+ return len(self._Items)
96
+ return 0
97
+
98
+
99
+ def ContainsDeviceId(self, value:str) -> bool:
100
+ """
101
+ Returns True if the `Items` collection contains the specified device id value;
102
+ otherwise, False.
103
+
104
+ Alias entries (if any) are also compared.
105
+ """
106
+ scDevice:SpotifyConnectDevice = self.GetDeviceById(value)
107
+ if scDevice is not None:
108
+ return True
109
+ return False
110
+
111
+
112
+ def ContainsDeviceName(self, value:str) -> bool:
113
+ """
114
+ Returns True if the `Items` collection contains the specified device name value;
115
+ otherwise, False.
116
+
117
+ Alias entries (if any) are also compared.
118
+ """
119
+ scDevice:SpotifyConnectDevice = self.GetDeviceByName(value)
120
+ if scDevice is not None:
121
+ return True
122
+ return False
123
+
124
+
125
+ def ContainsZeroconfEndpointGetInformation(self, value:str) -> bool:
126
+ """
127
+ Returns True if the `Items` collection contains the specified Zeroconf getInfo Endpoint url value;
128
+ otherwise, False.
129
+ """
130
+ result:bool = False
131
+ if value is None:
132
+ return result
133
+
134
+ # convert case for comparison.
135
+ value = value.lower()
136
+
137
+ # process all discovered devices.
138
+ scDevice:SpotifyConnectDevice
139
+ for scDevice in self._Items:
140
+ if (scDevice.DiscoveryResult.ZeroconfApiEndpointGetInformation.lower() == value):
141
+ result = True
142
+ break
143
+ return result
144
+
145
+
146
+ def GetDeviceByDiscoveryKey(self, value:str) -> SpotifyConnectDevice:
147
+ """
148
+ Returns a `SpotifyConnectDevice` instance if the `Items` collection contains the specified
149
+ device zeroconf discovery results key value; otherwise, None.
150
+ """
151
+ result:SpotifyConnectDevice = None
152
+ if value is None:
153
+ return result
154
+
155
+ # convert case for comparison.
156
+ value = value.lower()
157
+
158
+ # process all devices, comparing discovery keys.
159
+ for i in range(len(self._Items)):
160
+ if (self._Items[i].DiscoveryResult is not None):
161
+ if (self._Items[i].DiscoveryResult.Key is not None):
162
+ if (self._Items[i].DiscoveryResult.Key.lower() == value):
163
+ result = self._Items[i]
164
+ break
165
+ return result
166
+
167
+
168
+ def GetDeviceById(self, value:str) -> SpotifyConnectDevice:
169
+ """
170
+ Returns a `SpotifyConnectDevice` instance if the `Items` collection contains the specified
171
+ device id value; otherwise, None.
172
+
173
+ All Spotify Connect Zeroconf GetInfo response `DeviceId` entries are checked
174
+ first; if not resolved, then base device `Id` entries are checked. We do it
175
+ this way in case a Spotify Connect Zeroconf GetInfo response has not been
176
+ recevied for a device yet.
177
+ """
178
+ result:SpotifyConnectDevice = None
179
+ if value is None:
180
+ return result
181
+ if value == "":
182
+ return result
183
+
184
+ # convert case for comparison.
185
+ value = value.lower()
186
+
187
+ # process all discovered devices.
188
+ scDevice:SpotifyConnectDevice
189
+ for scDevice in self._Items:
190
+
191
+ # check for id in the Spotify Connect Zeroconf GetInfo response.
192
+ if (scDevice.DeviceInfo.DeviceId is not None):
193
+ if (scDevice.DeviceInfo.DeviceId.lower() == value):
194
+ result = scDevice
195
+ _logsi.LogVerbose("GetDeviceById found SpotifyConnectDevices collection entry: %s (DeviceInfo.DeviceId)" % scDevice.Title)
196
+ break
197
+
198
+
199
+ # if not resolved, then check for id in the base device definition.
200
+ if (result is None):
201
+
202
+ # process all discovered devices.
203
+ scDevice:SpotifyConnectDevice
204
+ for scDevice in self._Items:
205
+
206
+ # check for id in the base device definition.
207
+ if (scDevice.Id is not None):
208
+ if (scDevice.Id.lower() == value):
209
+ result = scDevice
210
+ _logsi.LogVerbose("GetDeviceById found SpotifyConnectDevices collection entry: %s (Device.Id)" % scDevice.Title)
211
+ break
212
+
213
+ # trace.
214
+ if (result is None):
215
+ _logsi.LogVerbose("GetDeviceById could not find SpotifyConnectDevices collection entry: \"%s\"" % value)
216
+
217
+ return result
218
+
219
+
220
+ def GetDeviceByName(self, value:str) -> SpotifyConnectDevice:
221
+ """
222
+ Returns a `SpotifyConnectDevice` instance if the `Items` collection contains the specified
223
+ device name value; otherwise, None.
224
+
225
+ All Spotify Connect Zeroconf GetInfo response `RemoteName` / Zeroconf DiscoveryResult
226
+ `DeviceName` entries are checked first; if not resolved, then Spotify Connect Zeroconf
227
+ GetInfo `Alias` entries are checked. We do it this way in case an alias name is defined
228
+ for a Spotify Connect Zeroconf entry that already exists with the same name (e.g. the
229
+ RemoteName entry will take precedence).
230
+ """
231
+ result:SpotifyConnectDevice = None
232
+ if value is None:
233
+ return result
234
+ if value == "":
235
+ return result
236
+
237
+ # convert case for comparison.
238
+ value = value.lower()
239
+
240
+ # process all discovered devices.
241
+ scDevice:SpotifyConnectDevice
242
+ for scDevice in self._Items:
243
+
244
+ # match on `getInfo` RemoteName value (if defined).
245
+ if (scDevice.DeviceInfo.RemoteName is not None):
246
+ if (scDevice.DeviceInfo.RemoteName.lower() == value):
247
+ result = scDevice
248
+ _logsi.LogVerbose("GetDeviceByName found SpotifyConnectDevices collection entry: %s (DeviceInfo.RemoteName)" % scDevice.Title)
249
+ break
250
+
251
+ # match on Zeroconf DeviceName value (if defined).
252
+ if (scDevice.DiscoveryResult.DeviceName is not None):
253
+ if (scDevice.DiscoveryResult.DeviceName.lower() == value):
254
+ result = scDevice
255
+ _logsi.LogVerbose("GetDeviceByName found SpotifyConnectDevices collection entry: %s (DiscoveryResult.DeviceName)" % scDevice.Title)
256
+ break
257
+
258
+ # if not resolved, then search by alias name.
259
+ if (result is None):
260
+
261
+ # process all discovered devices.
262
+ scDevice:SpotifyConnectDevice
263
+ for scDevice in self._Items:
264
+
265
+ # search aliases (if defined).
266
+ if (scDevice.DeviceInfo.HasAliases):
267
+ scAlias:ZeroconfGetInfoAlias
268
+ for scAlias in scDevice.DeviceInfo.Aliases:
269
+ if (scAlias.Name is not None):
270
+ if (scAlias.Name.lower() == value):
271
+ result = scDevice
272
+ _logsi.LogVerbose("GetDeviceByName found SpotifyConnectDevices collection entry: %s (DeviceInfo.Aliases)" % scDevice.Title)
273
+ break
274
+ if result is not None:
275
+ break
276
+
277
+ # trace.
278
+ if (result is None):
279
+ _logsi.LogVerbose("GetDeviceByName could not find SpotifyConnectDevices collection entry: \"%s\"" % value)
280
+
281
+ return result
282
+
283
+
284
+ def GetDeviceByNameAndId(self, deviceName:str, deviceId:str) -> int:
285
+ """
286
+ Returns a `SpotifyConnectDevice` instance if the `Items` collection contains the specified
287
+ device name and id value; otherwise, None.
288
+
289
+ Alias entries (if any) are NOT compared.
290
+ """
291
+ result:SpotifyConnectDevice = None
292
+ if deviceName is None:
293
+ return result
294
+ if deviceId is None:
295
+ return deviceId
296
+
297
+ # convert case for comparison.
298
+ deviceName = deviceName.lower()
299
+ deviceId = deviceId.lower()
300
+
301
+ # process all devices, comparing device name and id.
302
+ scDevice:SpotifyConnectDevice
303
+ for scDevice in self._Items:
304
+ if (scDevice.Name is not None) and (scDevice.Id is not None):
305
+ if (scDevice.Name.lower() == deviceName) and (scDevice.Id.lower() == deviceId):
306
+ result = scDevice
307
+ _logsi.LogVerbose("GetDeviceByNameAndId found SpotifyConnectDevices collection entry: %s" % scDevice.Title)
308
+ break
309
+
310
+ # trace.
311
+ if (result is None):
312
+ _logsi.LogVerbose("GetDeviceByNameAndId could not find SpotifyConnectDevices collection entry: \"%s\" (%s)" % (deviceName, deviceId))
313
+
314
+ return result
315
+
316
+
317
+ def GetDeviceIndexByDiscoveryKey(self, value:str) -> int:
318
+ """
319
+ Returns the index of the `Items` collection entry that contains
320
+ the specified device zeroconf discovery results key value if found;
321
+ otherwise, -1.
322
+ """
323
+ result:int = -1
324
+ if value is None:
325
+ return result
326
+
327
+ # convert case for comparison.
328
+ value = value.lower()
329
+
330
+ # process all devices, comparing discovery keys.
331
+ for i in range(len(self._Items)):
332
+ if (self._Items[i].DiscoveryResult is not None):
333
+ if (self._Items[i].DiscoveryResult.Key is not None):
334
+ if (self._Items[i].DiscoveryResult.Key.lower() == value):
335
+ result = i
336
+ break
337
+ return result
338
+
339
+
340
+ def GetDeviceIndexByDiscoveryName(self, value:str) -> int:
341
+ """
342
+ Returns the index of the `Items` collection entry that contains
343
+ the specified device zeroconf discovery results name value if found;
344
+ otherwise, -1.
345
+ """
346
+ result:int = -1
347
+ if value is None:
348
+ return result
349
+
350
+ # convert case for comparison.
351
+ value = value.lower()
352
+
353
+ # process all devices, comparing discovery keys.
354
+ for i in range(len(self._Items)):
355
+ if (self._Items[i].DiscoveryResult is not None):
356
+ if (self._Items[i].DiscoveryResult.Name is not None):
357
+ if (self._Items[i].DiscoveryResult.Name.lower() == value):
358
+ result = i
359
+ break
360
+ return result
361
+
362
+
363
+ def GetDeviceList(self) -> list[Device]:
364
+ """
365
+ Returns a list of `Device` objects that can be used to build a selection list
366
+ of available devices.
367
+
368
+ Note that the `Device` object has the following properties populated:
369
+ Id, Name, IsActive, Type.
370
+ """
371
+ result:list[Device] = []
372
+
373
+ # process all discovered devices.
374
+ scDevice:SpotifyConnectDevice
375
+ for scDevice in self._Items:
376
+
377
+ # map device information details.
378
+ info:ZeroconfGetInfo = scDevice.DeviceInfo
379
+
380
+ # create new mock device.
381
+ device = Device()
382
+ device.Type = info.DeviceType
383
+
384
+ # are aliases being used (RemoteName is null if so)?
385
+ if info.RemoteName is None:
386
+
387
+ # if aliases are defined, then use the alias details.
388
+ infoAlias:ZeroconfGetInfoAlias
389
+ for infoAlias in info.Aliases:
390
+ device.Id = infoAlias.Id
391
+ device.Name = infoAlias.Name
392
+
393
+ else:
394
+
395
+ # if no aliases then use the remote name and id.
396
+ device.Id = info.DeviceId
397
+ device.Name = info.RemoteName
398
+
399
+ # append device to results.
400
+ result.append(device)
401
+
402
+ # sort items on Name property, ascending order.
403
+ if len(result) > 0:
404
+ result.sort(key=lambda x: (x.Name or "").lower(), reverse=False)
405
+
406
+ return result
407
+
408
+
409
+ def ToDictionary(self) -> dict:
410
+ """
411
+ Returns a dictionary representation of the class.
412
+ """
413
+ result:dict = \
414
+ {
415
+ 'AgeLastRefreshed': self.AgeLastRefreshed,
416
+ 'DateLastRefreshed': self._DateLastRefreshed,
417
+ 'ItemsCount': self.ItemsCount,
418
+ 'Items': [ item.ToDictionary() for item in self._Items ],
419
+ }
420
+
421
+ return result
422
+
423
+
424
+ def ToString(self, includeItems:bool=False) -> str:
425
+ """
426
+ Returns a displayable string representation of the class.
427
+
428
+ Args:
429
+ includeItems (bool):
430
+ True to include the Items collection of objects; otherwise, False
431
+ to only return base properties.
432
+ """
433
+ msg:str = 'Items Count=%s' % (str(self.ItemsCount))
434
+ msg:str = '%s, DateLastRefreshed=%s' % (msg, str(self._DateLastRefreshed))
435
+
436
+ if (includeItems):
437
+ item:SpotifyConnectDevice
438
+ for item in self._Items:
439
+ msg = "%s\n- %s" % (msg, item.ToString(True))
440
+
441
+ return msg
@@ -0,0 +1,142 @@
1
+ # external package imports.
2
+
3
+ # our package imports.
4
+ from ..sautils import export
5
+ from .album import Album
6
+ from .externalids import ExternalIds
7
+ from .tracksimplified import TrackSimplified
8
+
9
+ @export
10
+ class Track(TrackSimplified):
11
+ """
12
+ Spotify Web API Track object.
13
+ """
14
+
15
+ def __init__(self, root:dict=None) -> None:
16
+ """
17
+ Initializes a new instance of the class.
18
+
19
+ Args:
20
+ root (dict):
21
+ Spotify Web API JSON response in dictionary format, used to load object
22
+ attributes; otherwise, None to not load attributes.
23
+ """
24
+ # initialize base class.
25
+ super().__init__(root=root)
26
+
27
+ self._Album:Album = None
28
+ self._ExternalIds:ExternalIds = None
29
+ self._Popularity:int = None
30
+
31
+ if (root is None):
32
+
33
+ pass
34
+
35
+ else:
36
+
37
+ self._Popularity = root.get('popularity', None)
38
+
39
+ # process all collections and objects.
40
+ item:dict = root.get('album',None)
41
+ if item is not None:
42
+ self._Album = Album(root=item)
43
+
44
+ item:dict = root.get('external_ids',None)
45
+ if item is not None:
46
+ self._ExternalIds = ExternalIds(root=item)
47
+
48
+
49
+ def __repr__(self) -> str:
50
+ return self.ToString()
51
+
52
+
53
+ def __str__(self) -> str:
54
+ return self.ToString()
55
+
56
+
57
+ @property
58
+ def Album(self) -> Album:
59
+ """
60
+ The album on which the track appears.
61
+
62
+ The album object includes a link in href to full information about the album.
63
+ """
64
+ return self._Album
65
+
66
+
67
+ @property
68
+ def ExternalIds(self) -> ExternalIds:
69
+ """
70
+ Known external ID's for the track.
71
+ """
72
+ return self._ExternalIds
73
+
74
+
75
+ @property
76
+ def ImageUrl(self) -> str:
77
+ """
78
+ Gets the first image url in the album `Images` list, if images are defined;
79
+ otherwise, null.
80
+ """
81
+ if self._Album is not None:
82
+ return self._Album.ImageUrl
83
+ return None
84
+
85
+
86
+ @property
87
+ def Popularity(self) -> int:
88
+ """
89
+ The popularity of the track. The value will be between 0 and 100, with 100 being the most popular.
90
+
91
+ The popularity of a track is a value between 0 and 100, with 100 being the most popular.
92
+ The popularity is calculated by algorithm and is based, in the most part, on the total number
93
+ of plays the track has had and how recent those plays are. Generally speaking, songs that are
94
+ being played a lot now will have a higher popularity than songs that were played a lot in the past.
95
+
96
+ Duplicate tracks (e.g. the same track from a single and an album) are rated independently.
97
+ Artist and album popularity is derived mathematically from track popularity.
98
+
99
+ Note: the popularity value may lag actual popularity by a few days: the value is not updated in real time.
100
+ """
101
+ return self._Popularity
102
+
103
+
104
+ def ToDictionary(self) -> dict:
105
+ """
106
+ Returns a dictionary representation of the class.
107
+ """
108
+ # get base class result.
109
+ resultBase:dict = super().ToDictionary()
110
+
111
+ album:dict = {}
112
+ if self._Album is not None:
113
+ album = self._Album.ToDictionary()
114
+
115
+ externalIds:dict = {}
116
+ if self._ExternalIds is not None:
117
+ externalIds = self._ExternalIds.ToDictionary()
118
+
119
+ result:dict = \
120
+ {
121
+ 'album': album,
122
+ 'external_ids': externalIds,
123
+ 'popularity': self._Popularity,
124
+ 'image_url': self.ImageUrl,
125
+ }
126
+
127
+ # combine base class results with these results.
128
+ resultBase.update(result)
129
+
130
+ # return a sorted dictionary.
131
+ return dict(sorted(resultBase.items()))
132
+
133
+
134
+ def ToString(self) -> str:
135
+ """
136
+ Returns a displayable string representation of the class.
137
+ """
138
+ msg:str = 'Track: %s' % super().ToString(False)
139
+ if self._Album is not None: msg = '%s\n Album="%s"' % (msg, str(self._Album.Name))
140
+ #if self._ExternalIds is not None: msg = '%s\n %s' % (msg, str(self._ExternalIds))
141
+ if self._Popularity is not None: msg = '%s\n Popularity="%s"' % (msg, str(self._Popularity))
142
+ return msg
@@ -0,0 +1,110 @@
1
+ # external package imports.
2
+
3
+ # our package imports.
4
+ from ..sautils import export
5
+ from .track import Track
6
+ from .pageobject import PageObject
7
+
8
+ @export
9
+ class TrackPage(PageObject):
10
+ """
11
+ Spotify Web API TrackPage object.
12
+
13
+ This allows for multiple pages of `Track` objects to be navigated.
14
+ """
15
+
16
+ def __init__(self, root:dict=None) -> None:
17
+ """
18
+ Initializes a new instance of the class.
19
+
20
+ Args:
21
+ root (dict):
22
+ Spotify Web API JSON response in dictionary format, used to load object
23
+ attributes; otherwise, None to not load attributes.
24
+ """
25
+ # initialize base class.
26
+ super().__init__(root=root)
27
+
28
+ # initialize storage.
29
+ self._Items:list[Track] = []
30
+
31
+ if (root is None):
32
+
33
+ pass
34
+
35
+ else:
36
+
37
+ # process all collections and objects.
38
+ items:list = root.get('items',None)
39
+ if items is not None:
40
+ for item in items:
41
+ if item is not None:
42
+ self._Items.append(Track(root=item))
43
+
44
+
45
+ def __repr__(self) -> str:
46
+ return self.ToString()
47
+
48
+
49
+ def __str__(self) -> str:
50
+ return self.ToString()
51
+
52
+
53
+ @property
54
+ def Items(self) -> list[Track]:
55
+ """
56
+ Array of `Track` objects.
57
+ """
58
+ return self._Items
59
+
60
+
61
+ def GetUris(self, afterUri:str=None) -> str:
62
+ """
63
+ Gets a comma-delimited list of uri's contained in the underlying `Items` list.
64
+
65
+ args:
66
+ afterUri (str):
67
+ If specified, the process will look for this uri before adding subsequent
68
+ uri's to the returned results. This allows you to skip uri's that have
69
+ recently been played.
70
+
71
+ This is a convenience method so one does not have to loop through the `Items`
72
+ array of PlayHistory objects to get the list of uri's.
73
+ """
74
+ result:str = ""
75
+ addUri:bool = False
76
+ item:Track
77
+
78
+ # add uri's from the beginning if no `afterUri` argument was passed.
79
+ if (afterUri is None) or (len(afterUri.strip()) == 0):
80
+ addUri = True
81
+
82
+ for item in self._Items:
83
+
84
+ if (not addUri):
85
+
86
+ # check for `afterUri` match; if found, we will start adding uri's
87
+ # to the list with the next item.
88
+ if (afterUri == item.Uri):
89
+ addUri = True
90
+
91
+ elif (addUri):
92
+
93
+ # add item uri to the list.
94
+ if (len(result) > 0):
95
+ result += ","
96
+ result += item.Uri
97
+
98
+ return result
99
+
100
+
101
+ def ToString(self, includeItems:bool=False) -> str:
102
+ """
103
+ Returns a displayable string representation of the class.
104
+
105
+ Args:
106
+ includeItems (bool):
107
+ True to include the Items collection of objects; otherwise, False
108
+ to only return base properties.
109
+ """
110
+ return 'TrackPage: %s' % super().ToString(includeItems)