spotifywebapiPython 1.0.26__py3-none-any.whl → 1.0.28__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 (24) hide show
  1. {spotifywebapiPython-1.0.26.dist-info → spotifywebapiPython-1.0.28.dist-info}/METADATA +1 -1
  2. {spotifywebapiPython-1.0.26.dist-info → spotifywebapiPython-1.0.28.dist-info}/RECORD +24 -24
  3. spotifywebapipython/const.py +26 -2
  4. spotifywebapipython/docs/__init__.html +27 -3
  5. spotifywebapipython/docs/index.html +2 -2
  6. spotifywebapipython/docs/search.js +1 -1
  7. spotifywebapipython/docs/spotifywebapiPython/const.html +75 -3
  8. spotifywebapipython/docs/spotifywebapiPython/saappmessages.html +4 -4
  9. spotifywebapipython/docs/spotifywebapiPython/sautils.html +2 -2
  10. spotifywebapipython/docs/spotifywebapiPython/spotifyapierror.html +2 -2
  11. spotifywebapipython/docs/spotifywebapiPython/spotifyapimessage.html +2 -2
  12. spotifywebapipython/docs/spotifywebapiPython/spotifyauthtoken.html +2 -2
  13. spotifywebapipython/docs/spotifywebapiPython/spotifyclient.html +2113 -331
  14. spotifywebapipython/docs/spotifywebapiPython/spotifydiscovery.html +2 -2
  15. spotifywebapipython/docs/spotifywebapiPython/spotifywebapiauthenticationerror.html +2 -2
  16. spotifywebapipython/docs/spotifywebapiPython/spotifywebapierror.html +2 -2
  17. spotifywebapipython/models/category.py +11 -0
  18. spotifywebapipython/models/pageobject.py +77 -4
  19. spotifywebapipython/models/searchresponse.py +86 -50
  20. spotifywebapipython/saappmessages.py +3 -3
  21. spotifywebapipython/spotifyclient.py +2938 -364
  22. {spotifywebapiPython-1.0.26.dist-info → spotifywebapiPython-1.0.28.dist-info}/LICENSE +0 -0
  23. {spotifywebapiPython-1.0.26.dist-info → spotifywebapiPython-1.0.28.dist-info}/WHEEL +0 -0
  24. {spotifywebapiPython-1.0.26.dist-info → spotifywebapiPython-1.0.28.dist-info}/top_level.txt +0 -0
@@ -3,7 +3,6 @@ import base64
3
3
  import json
4
4
  from io import BytesIO
5
5
  from oauthlib.oauth2 import BackendApplicationClient, WebApplicationClient
6
- #from requests import Response
7
6
  from typing import Tuple, Callable
8
7
  from urllib3 import PoolManager, Timeout, HTTPResponse
9
8
  from urllib.parse import urlencode
@@ -12,7 +11,7 @@ from urllib.parse import urlencode
12
11
  from .oauthcli import AuthClient
13
12
  from .models import *
14
13
  from .models import UserProfile as UserProfileCurrentUser
15
- from .sautils import export
14
+ from .sautils import export, GetUnixTimestampMSFromUtcNow
16
15
  from .saappmessages import SAAppMessages
17
16
  from .spotifyapierror import SpotifyApiError
18
17
  from .spotifyapimessage import SpotifyApiMessage
@@ -22,12 +21,16 @@ from .spotifywebapierror import SpotifyWebApiError
22
21
  from .const import (
23
22
  SPOTIFY_API_AUTHORIZE_URL,
24
23
  SPOTIFY_API_TOKEN_URL,
24
+ SPOTIFY_DEFAULT_MARKET,
25
25
  SPOTIFY_WEBAPI_URL_BASE,
26
26
  TRACE_METHOD_RESULT,
27
27
  TRACE_METHOD_RESULT_TYPE,
28
28
  TRACE_METHOD_RESULT_TYPE_CACHED,
29
+ TRACE_METHOD_RESULT_TYPE_PAGE,
29
30
  TRACE_MSG_AUTHTOKEN_CREATE,
31
+ TRACE_MSG_AUTOPAGING_NEXT,
30
32
  TRACE_MSG_USERPROFILE,
33
+ TRACE_WARN_SPOTIFY_SEARCH_NO_MARKET,
31
34
  )
32
35
 
33
36
  CACHE_SOURCE_CACHED:str = "cached"
@@ -231,6 +234,51 @@ class SpotifyClient:
231
234
  return self._UserProfile
232
235
 
233
236
 
237
+ def _CheckForNextPage(self,
238
+ pageObj:PageObject,
239
+ resultItemsCount,
240
+ limit:int,
241
+ limitTotal:int,
242
+ urlParms:dict,
243
+ ) -> bool:
244
+ """
245
+ Modifies paging object and urlParms to point to the next page of data, if one
246
+ can be accessed.
247
+
248
+ Returns:
249
+ False if there are no more pages to process;
250
+ otherwise, True to safely process the next page of results.
251
+ """
252
+ # anymore page results?
253
+ if (pageObj.Next is None) or (resultItemsCount >= limitTotal) or (pageObj.Offset >= limitTotal):
254
+ # no - all pages were processed, or limit total reached.
255
+ return False
256
+ else:
257
+ # yes - prepare to retrieve the next page of results.
258
+ # if next page potential item count exceeds limit total, then limit to the difference.
259
+ pageObj.Offset = pageObj.Offset + pageObj.Limit
260
+ if (pageObj.Offset + pageObj.Limit) > limitTotal:
261
+ pageObj.Limit = limitTotal - pageObj.Offset
262
+
263
+ # the following can occur if the Spotify Web API does not return any items but has
264
+ # the 'next' value set to point to the next page of data. I noticed this happens
265
+ # when the API cannot resolve a market (or country code) value (e.g. the UserProfile
266
+ # Country property is not set and no market argument was supplied). Regardless, we
267
+ # will check for it here in case.
268
+ if pageObj.Limit <= 0:
269
+ pageObj.Limit = limit
270
+
271
+ # modify paging-related request parameters for next page of items.
272
+ urlParms['limit'] = pageObj.Limit
273
+ urlParms['offset'] = pageObj.Offset
274
+
275
+ # trace.
276
+ _logsi.LogVerbose(TRACE_MSG_AUTOPAGING_NEXT % pageObj.PagingInfo)
277
+
278
+ # indicate next page can be processed.
279
+ return True
280
+
281
+
234
282
  def _CheckResponseForErrors(self, msg:SpotifyApiMessage, response:HTTPResponse) -> None:
235
283
  """
236
284
  Checks the Spotify Web API response for errors.
@@ -397,6 +445,35 @@ class SpotifyClient:
397
445
  msg.ResponseData = responseData
398
446
 
399
447
 
448
+ def _ValidateMarket(self,
449
+ market:str,
450
+ ) -> str:
451
+ """
452
+ Validates that a market (aka country code) value has either been supplied, or exists
453
+ in the UserProfile.Country value and returns a value of 'US' if not supplied; otherwise,
454
+ the market aregument value is returned.
455
+
456
+ If a market argument was not specified and the user profile does not have a country code
457
+ set, then it causes the Spotify Web API search to return odd results. For example, the
458
+ items collection will return no items, but the `total` and `next` values are populated
459
+ like there are more results. It's almost like it found the results, but it won't return
460
+ the actual items due to market / country restrictions or something.
461
+ """
462
+ # if user profile contains a country value then spotify web api will use it if no
463
+ # market argument was supplied.
464
+ if (self.UserProfile.Country is not None):
465
+ return market
466
+
467
+ # if a non-null and non-empty string was supplied then assume it's a valid market.
468
+ # we will let the Spotify Web API tell us if it's not a valid code.
469
+ if (market is not None and len(market.strip()) > 0):
470
+ return market
471
+
472
+ # otherwise, defult the value.
473
+ _logsi.LogVerbose("A market value was not supplied for the request, and the user profile did not contain a country code value (e.g. public access token is in effect). Defaulting value to '%s'." % SPOTIFY_DEFAULT_MARKET)
474
+ return SPOTIFY_DEFAULT_MARKET
475
+
476
+
400
477
  def MakeRequest(self, method:str, msg:SpotifyApiMessage) -> int:
401
478
  """
402
479
  Performs a generic Spotify Web API request.
@@ -2117,6 +2194,9 @@ class SpotifyClient:
2117
2194
  apiMethodParms.AppendKeyValue("market", market)
2118
2195
  _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information for a single album", apiMethodParms)
2119
2196
 
2197
+ # ensure market was either supplied or implied; default if neither.
2198
+ market = self._ValidateMarket(market)
2199
+
2120
2200
  # build spotify web api request parameters.
2121
2201
  urlParms:dict = {}
2122
2202
  if market is not None:
@@ -2152,6 +2232,7 @@ class SpotifyClient:
2152
2232
  limit:int=20,
2153
2233
  offset:int=0,
2154
2234
  market:str=None,
2235
+ limitTotal:int=None
2155
2236
  ) -> AlbumPageSaved:
2156
2237
  """
2157
2238
  Get a list of the albums saved in the current Spotify user's 'Your Library'.
@@ -2160,10 +2241,10 @@ class SpotifyClient:
2160
2241
 
2161
2242
  Args:
2162
2243
  limit (int):
2163
- The maximum number of items to return.
2244
+ The maximum number of items to return in a page of items.
2164
2245
  Default: 20, Range: 1 to 50.
2165
2246
  offset (int):
2166
- The index of the first item to return.
2247
+ The page index offset of the first item to return.
2167
2248
  Use with limit to get the next set of items.
2168
2249
  Default: 0 (the first item).
2169
2250
  market (str):
@@ -2174,6 +2255,12 @@ class SpotifyClient:
2174
2255
  Note: If neither market or user country are provided, the content is considered unavailable for the client.
2175
2256
  Users can view the country that is associated with their account in the account settings.
2176
2257
  Example: `ES`
2258
+ limitTotal (int):
2259
+ The maximum number of items to return for the request.
2260
+ If specified, this argument overrides the limit and offset argument values
2261
+ and paging is automatically used to retrieve all available items up to the
2262
+ maximum number specified.
2263
+ Default: None (disabled)
2177
2264
 
2178
2265
  Returns:
2179
2266
  An `AlbumPageSaved` object that contains saved album information.
@@ -2186,11 +2273,17 @@ class SpotifyClient:
2186
2273
  If the method fails for any other reason.
2187
2274
 
2188
2275
  <details>
2189
- <summary>Sample Code</summary>
2276
+ <summary>Sample Code - Manual Paging</summary>
2190
2277
  ```python
2191
2278
  .. include:: ../docs/include/samplecode/SpotifyClient/GetAlbumFavorites.py
2192
2279
  ```
2193
2280
  </details>
2281
+ <details>
2282
+ <summary>Sample Code - Auto Paging</summary>
2283
+ ```python
2284
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetAlbumFavorites_AutoPaging.py
2285
+ ```
2286
+ </details>
2194
2287
  """
2195
2288
  apiMethodName:str = 'GetAlbumFavorites'
2196
2289
  apiMethodParms:SIMethodParmListContext = None
@@ -2202,6 +2295,8 @@ class SpotifyClient:
2202
2295
  apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
2203
2296
  apiMethodParms.AppendKeyValue("limit", limit)
2204
2297
  apiMethodParms.AppendKeyValue("offset", offset)
2298
+ apiMethodParms.AppendKeyValue("market", market)
2299
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
2205
2300
  _logsi.LogMethodParmList(SILevel.Verbose, "Get a list of the user's album favorites", apiMethodParms)
2206
2301
 
2207
2302
  # validations.
@@ -2209,6 +2304,19 @@ class SpotifyClient:
2209
2304
  limit = 20
2210
2305
  if offset is None:
2211
2306
  offset = 0
2307
+ if not isinstance(limitTotal, int):
2308
+ limitTotal = 0
2309
+
2310
+ # are we auto-paging? if so, then use max limit.
2311
+ if limitTotal > 0:
2312
+ limit = 50
2313
+ #limit = 2 # TEST TODO
2314
+ if limit > limitTotal:
2315
+ limit = limitTotal
2316
+ result = AlbumPageSaved()
2317
+
2318
+ # ensure market was either supplied or implied; default if neither.
2319
+ market = self._ValidateMarket(market)
2212
2320
 
2213
2321
  # build spotify web api request parameters.
2214
2322
  urlParms:dict = \
@@ -2219,15 +2327,49 @@ class SpotifyClient:
2219
2327
  if market is not None:
2220
2328
  urlParms['market'] = market
2221
2329
 
2222
- # execute spotify web api request.
2223
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/albums')
2224
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
2225
- msg.UrlParameters = urlParms
2226
- self.MakeRequest('GET', msg)
2330
+ # handle pagination, as spotify limits us to a set # of items returned per response.
2331
+ while True:
2227
2332
 
2228
- # process results.
2229
- result = AlbumPageSaved(root=msg.ResponseData)
2333
+ # execute spotify web api request.
2334
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/albums')
2335
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
2336
+ msg.UrlParameters = urlParms
2337
+ self.MakeRequest('GET', msg)
2338
+
2339
+ # process results.
2340
+ pageObj = AlbumPageSaved(root=msg.ResponseData)
2230
2341
 
2342
+ # trace.
2343
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
2344
+
2345
+ # was limit total argument specified?
2346
+ if (limitTotal <= 0):
2347
+
2348
+ # no - just return the initial page of results.
2349
+ result = pageObj
2350
+ break
2351
+
2352
+ else:
2353
+
2354
+ # append page of items to final results.
2355
+ item:AlbumSaved
2356
+ for item in pageObj.Items:
2357
+ result.Items.append(item)
2358
+ result.Limit = result.ItemsCount
2359
+ if result.ItemsCount >= limitTotal:
2360
+ break
2361
+
2362
+ # anymore pages to process? if not, then exit the loop.
2363
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
2364
+ break
2365
+
2366
+ # update result object with final paging details.
2367
+ result.Total = pageObj.Total
2368
+
2369
+ # sort items on Name property, ascending order.
2370
+ if len(result.Items) > 0:
2371
+ result.Items.sort(key=lambda x: (x.Album.Name or "").lower(), reverse=False)
2372
+
2231
2373
  # trace.
2232
2374
  _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
2233
2375
  return result
@@ -2249,6 +2391,7 @@ class SpotifyClient:
2249
2391
  limit:int=20,
2250
2392
  offset:int=0,
2251
2393
  country:str=None,
2394
+ limitTotal:int=None
2252
2395
  ) -> AlbumPageSimplified:
2253
2396
  """
2254
2397
  Get a list of new album releases featured in Spotify (shown, for example, on a
@@ -2256,10 +2399,10 @@ class SpotifyClient:
2256
2399
 
2257
2400
  Args:
2258
2401
  limit (int):
2259
- The maximum number of items to return.
2402
+ The maximum number of items to return in a page of items.
2260
2403
  Default: 20, Range: 1 to 50.
2261
2404
  offset (int):
2262
- The index of the first item to return.
2405
+ The page index offset of the first item to return.
2263
2406
  Use with limit to get the next set of items.
2264
2407
  Default: 0 (the first item).
2265
2408
  country (str):
@@ -2267,6 +2410,12 @@ class SpotifyClient:
2267
2410
  Provide this parameter if you want the list of returned items to be relevant to a
2268
2411
  particular country. If omitted, the returned items will be relevant to all countries.
2269
2412
  Example: `SE`
2413
+ limitTotal (int):
2414
+ The maximum number of items to return for the request.
2415
+ If specified, this argument overrides the limit and offset argument values
2416
+ and paging is automatically used to retrieve all available items up to the
2417
+ maximum number specified.
2418
+ Default: None (disabled)
2270
2419
 
2271
2420
  Returns:
2272
2421
  An `AlbumPageSimplified` object that contains simplified album information.
@@ -2279,11 +2428,17 @@ class SpotifyClient:
2279
2428
  If the method fails for any other reason.
2280
2429
 
2281
2430
  <details>
2282
- <summary>Sample Code</summary>
2431
+ <summary>Sample Code - Manual Paging</summary>
2283
2432
  ```python
2284
2433
  .. include:: ../docs/include/samplecode/SpotifyClient/GetAlbumNewReleases.py
2285
2434
  ```
2286
2435
  </details>
2436
+ <details>
2437
+ <summary>Sample Code - Auto Paging</summary>
2438
+ ```python
2439
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetAlbumNewReleases_AutoPaging.py
2440
+ ```
2441
+ </details>
2287
2442
  """
2288
2443
  apiMethodName:str = 'GetAlbumNewReleases'
2289
2444
  apiMethodParms:SIMethodParmListContext = None
@@ -2296,6 +2451,7 @@ class SpotifyClient:
2296
2451
  apiMethodParms.AppendKeyValue("limit", limit)
2297
2452
  apiMethodParms.AppendKeyValue("offset", offset)
2298
2453
  apiMethodParms.AppendKeyValue("country", country)
2454
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
2299
2455
  _logsi.LogMethodParmList(SILevel.Verbose, "Get a list of new album releases", apiMethodParms)
2300
2456
 
2301
2457
  # validations.
@@ -2303,6 +2459,16 @@ class SpotifyClient:
2303
2459
  limit = 20
2304
2460
  if offset is None:
2305
2461
  offset = 0
2462
+ if not isinstance(limitTotal, int):
2463
+ limitTotal = 0
2464
+
2465
+ # are we auto-paging? if so, then use max limit.
2466
+ if limitTotal > 0:
2467
+ limit = 50
2468
+ #limit = 2 # TEST TODO
2469
+ if limit > limitTotal:
2470
+ limit = limitTotal
2471
+ result = AlbumPageSimplified()
2306
2472
 
2307
2473
  # build spotify web api request parameters.
2308
2474
  urlParms:dict = \
@@ -2313,16 +2479,50 @@ class SpotifyClient:
2313
2479
  if country is not None:
2314
2480
  urlParms['country'] = country
2315
2481
 
2316
- # execute spotify web api request.
2317
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/browse/new-releases')
2318
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
2319
- msg.UrlParameters = urlParms
2320
- self.MakeRequest('GET', msg)
2482
+ # handle pagination, as spotify limits us to a set # of items returned per response.
2483
+ while True:
2321
2484
 
2322
- # process results.
2323
- item:dict = msg.ResponseData.get('albums', None)
2324
- if item is not None:
2325
- result = AlbumPageSimplified(root=item)
2485
+ # execute spotify web api request.
2486
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/browse/new-releases')
2487
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
2488
+ msg.UrlParameters = urlParms
2489
+ self.MakeRequest('GET', msg)
2490
+
2491
+ # process results.
2492
+ item:dict = msg.ResponseData.get('albums', None)
2493
+ if item is not None:
2494
+ pageObj = AlbumPageSimplified(root=item)
2495
+
2496
+ # trace.
2497
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
2498
+
2499
+ # was limit total argument specified?
2500
+ if (limitTotal <= 0):
2501
+
2502
+ # no - just return the initial page of results.
2503
+ result = pageObj
2504
+ break
2505
+
2506
+ else:
2507
+
2508
+ # append page of items to final results.
2509
+ item:AlbumSimplified
2510
+ for item in pageObj.Items:
2511
+ result.Items.append(item)
2512
+ result.Limit = result.ItemsCount
2513
+ if result.ItemsCount >= limitTotal:
2514
+ break
2515
+
2516
+ # anymore pages to process? if not, then exit the loop.
2517
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
2518
+ break
2519
+
2520
+ # update result object with final paging details.
2521
+ result.Total = pageObj.Total
2522
+
2523
+ # sort items on Name property, ascending order.
2524
+ if len(result.Items) > 0:
2525
+ result.Items.sort(key=lambda x: (x.Name or "").lower(), reverse=False)
2326
2526
 
2327
2527
  # trace.
2328
2528
  _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
@@ -2391,6 +2591,9 @@ class SpotifyClient:
2391
2591
  apiMethodParms.AppendKeyValue("market", market)
2392
2592
  _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information for multiple albums", apiMethodParms)
2393
2593
 
2594
+ # ensure market was either supplied or implied; default if neither.
2595
+ market = self._ValidateMarket(market)
2596
+
2394
2597
  # build spotify web api request parameters.
2395
2598
  urlParms:dict = \
2396
2599
  {
@@ -2432,6 +2635,7 @@ class SpotifyClient:
2432
2635
  limit:int=20,
2433
2636
  offset:int=0,
2434
2637
  market:str=None,
2638
+ limitTotal:int=None
2435
2639
  ) -> TrackPageSimplified:
2436
2640
  """
2437
2641
  Get Spotify catalog information about an album's tracks.
@@ -2443,7 +2647,7 @@ class SpotifyClient:
2443
2647
  The Spotify ID of the album.
2444
2648
  Example: `6vc9OTcyd3hyzabCmsdnwE`
2445
2649
  limit (int):
2446
- The maximum number of items to return.
2650
+ The maximum number of items to return in a page of items.
2447
2651
  Default: 20, Range: 1 to 50.
2448
2652
  offset (int):
2449
2653
  The index of the first item to return; use with limit to get the next set of items.
@@ -2456,6 +2660,12 @@ class SpotifyClient:
2456
2660
  Note: If neither market or user country are provided, the content is considered unavailable for the client.
2457
2661
  Users can view the country that is associated with their account in the account settings.
2458
2662
  Example: `ES`
2663
+ limitTotal (int):
2664
+ The maximum number of items to return for the request.
2665
+ If specified, this argument overrides the limit and offset argument values
2666
+ and paging is automatically used to retrieve all available items up to the
2667
+ maximum number specified.
2668
+ Default: None (disabled)
2459
2669
 
2460
2670
  Returns:
2461
2671
  A `TrackPageSimplified` object that contains simplified track information for the albumId.
@@ -2468,11 +2678,17 @@ class SpotifyClient:
2468
2678
  If the method fails for any other reason.
2469
2679
 
2470
2680
  <details>
2471
- <summary>Sample Code</summary>
2681
+ <summary>Sample Code - Manual Paging</summary>
2472
2682
  ```python
2473
2683
  .. include:: ../docs/include/samplecode/SpotifyClient/GetAlbumTracks.py
2474
2684
  ```
2475
2685
  </details>
2686
+ <details>
2687
+ <summary>Sample Code - Auto Paging</summary>
2688
+ ```python
2689
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetAlbumTracks_AutoPaging.py
2690
+ ```
2691
+ </details>
2476
2692
  """
2477
2693
  apiMethodName:str = 'GetAlbumTracks'
2478
2694
  apiMethodParms:SIMethodParmListContext = None
@@ -2486,6 +2702,7 @@ class SpotifyClient:
2486
2702
  apiMethodParms.AppendKeyValue("limit", limit)
2487
2703
  apiMethodParms.AppendKeyValue("offset", offset)
2488
2704
  apiMethodParms.AppendKeyValue("market", market)
2705
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
2489
2706
  _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information about an album's tracks", apiMethodParms)
2490
2707
 
2491
2708
  # validations.
@@ -2493,6 +2710,19 @@ class SpotifyClient:
2493
2710
  limit = 20
2494
2711
  if offset is None:
2495
2712
  offset = 0
2713
+ if not isinstance(limitTotal, int):
2714
+ limitTotal = 0
2715
+
2716
+ # are we auto-paging? if so, then use max limit.
2717
+ if limitTotal > 0:
2718
+ limit = 50
2719
+ #limit = 2 # TEST TODO
2720
+ if limit > limitTotal:
2721
+ limit = limitTotal
2722
+ result = TrackPageSimplified()
2723
+
2724
+ # ensure market was either supplied or implied; default if neither.
2725
+ market = self._ValidateMarket(market)
2496
2726
 
2497
2727
  # build spotify web api request parameters.
2498
2728
  urlParms:dict = \
@@ -2503,14 +2733,46 @@ class SpotifyClient:
2503
2733
  if market is not None:
2504
2734
  urlParms['market'] = market
2505
2735
 
2506
- # execute spotify web api request.
2507
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/albums/{id}/tracks'.format(id=albumId))
2508
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
2509
- msg.UrlParameters = urlParms
2510
- self.MakeRequest('GET', msg)
2736
+ # handle pagination, as spotify limits us to a set # of items returned per response.
2737
+ while True:
2511
2738
 
2512
- # process results.
2513
- result = TrackPageSimplified(root=msg.ResponseData)
2739
+ # execute spotify web api request.
2740
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/albums/{id}/tracks'.format(id=albumId))
2741
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
2742
+ msg.UrlParameters = urlParms
2743
+ self.MakeRequest('GET', msg)
2744
+
2745
+ # process results.
2746
+ pageObj = TrackPageSimplified(root=msg.ResponseData)
2747
+
2748
+ # trace.
2749
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
2750
+
2751
+ # was limit total argument specified?
2752
+ if (limitTotal <= 0):
2753
+
2754
+ # no - just return the initial page of results.
2755
+ result = pageObj
2756
+ break
2757
+
2758
+ else:
2759
+
2760
+ # append page of items to final results.
2761
+ item:TrackSimplified
2762
+ for item in pageObj.Items:
2763
+ result.Items.append(item)
2764
+ result.Limit = result.ItemsCount
2765
+ if result.ItemsCount >= limitTotal:
2766
+ break
2767
+
2768
+ # anymore pages to process? if not, then exit the loop.
2769
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
2770
+ break
2771
+
2772
+ # update result object with final paging details.
2773
+ result.Total = pageObj.Total
2774
+
2775
+ # do not sort items, as they are in playable order.
2514
2776
 
2515
2777
  # trace.
2516
2778
  _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
@@ -2538,7 +2800,7 @@ class SpotifyClient:
2538
2800
  Args:
2539
2801
  artistId (str):
2540
2802
  The Spotify ID of the artist.
2541
- Example: `0TnOYISbd1XYRBk9myaseg`
2803
+ Example: `6APm8EjxOHSYM5B4i3vT3q`
2542
2804
 
2543
2805
  Returns:
2544
2806
  An `Artist` object that contains the artist details.
@@ -2598,22 +2860,23 @@ class SpotifyClient:
2598
2860
  include_groups:str='album',
2599
2861
  limit:int=20,
2600
2862
  offset:int=0,
2601
- market:str=None
2602
- ) -> list[Album]:
2863
+ market:str=None,
2864
+ limitTotal:int=None
2865
+ ) -> AlbumPageSimplified:
2603
2866
  """
2604
2867
  Get Spotify catalog information about an artist's albums.
2605
2868
 
2606
2869
  Args:
2607
2870
  artistId (str):
2608
2871
  The Spotify ID of the artist.
2609
- Example: `0TnOYISbd1XYRBk9myaseg`
2872
+ Example: `6APm8EjxOHSYM5B4i3vT3q`
2610
2873
  include_groups (str):
2611
2874
  A comma-separated list of keywords that will be used to filter the response.
2612
2875
  If not supplied, all album types will be returned.
2613
2876
  Valid values are: `album`, `single`, `appears_on`, `compilation`
2614
2877
  Example: `single,appears_on`
2615
2878
  limit (int):
2616
- The maximum number of items to return.
2879
+ The maximum number of items to return in a page of items.
2617
2880
  Default: 20, Range: 1 to 50.
2618
2881
  offset (int):
2619
2882
  The index of the first item to return; use with limit to get the next set of items.
@@ -2626,9 +2889,15 @@ class SpotifyClient:
2626
2889
  Note: If neither market or user country are provided, the content is considered unavailable for the client.
2627
2890
  Users can view the country that is associated with their account in the account settings.
2628
2891
  Example: `ES`
2892
+ limitTotal (int):
2893
+ The maximum number of items to return for the request.
2894
+ If specified, this argument overrides the limit and offset argument values
2895
+ and paging is automatically used to retrieve all available items up to the
2896
+ maximum number specified.
2897
+ Default: None (disabled)
2629
2898
 
2630
2899
  Returns:
2631
- A list of `Album` objects that contain the album details.
2900
+ An `AlbumPageSimplified` object of matching results.
2632
2901
 
2633
2902
  Raises:
2634
2903
  SpotifyWebApiError:
@@ -2638,11 +2907,17 @@ class SpotifyClient:
2638
2907
  If the method fails for any other reason.
2639
2908
 
2640
2909
  <details>
2641
- <summary>Sample Code</summary>
2910
+ <summary>Sample Code - Manual Paging</summary>
2642
2911
  ```python
2643
2912
  .. include:: ../docs/include/samplecode/SpotifyClient/GetArtistAlbums.py
2644
2913
  ```
2645
2914
  </details>
2915
+ <details>
2916
+ <summary>Sample Code - auto Paging</summary>
2917
+ ```python
2918
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetArtistAlbums_AutoPaging.py
2919
+ ```
2920
+ </details>
2646
2921
  """
2647
2922
  apiMethodName:str = 'GetArtistAlbums'
2648
2923
  apiMethodParms:SIMethodParmListContext = None
@@ -2657,6 +2932,7 @@ class SpotifyClient:
2657
2932
  apiMethodParms.AppendKeyValue("limit", limit)
2658
2933
  apiMethodParms.AppendKeyValue("offset", offset)
2659
2934
  apiMethodParms.AppendKeyValue("market", market)
2935
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
2660
2936
  _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information about an artist's albums", apiMethodParms)
2661
2937
 
2662
2938
  # validations.
@@ -2664,6 +2940,19 @@ class SpotifyClient:
2664
2940
  limit = 20
2665
2941
  if offset is None:
2666
2942
  offset = 0
2943
+ if not isinstance(limitTotal, int):
2944
+ limitTotal = 0
2945
+
2946
+ # are we auto-paging? if so, then use max limit.
2947
+ if limitTotal > 0:
2948
+ limit = 50
2949
+ #limit = 5 # TEST TODO
2950
+ if limit > limitTotal:
2951
+ limit = limitTotal
2952
+ result = AlbumPageSimplified()
2953
+
2954
+ # ensure market was either supplied or implied; default if neither.
2955
+ market = self._ValidateMarket(market)
2667
2956
 
2668
2957
  # build spotify web api request parameters.
2669
2958
  urlParms:dict = \
@@ -2675,14 +2964,48 @@ class SpotifyClient:
2675
2964
  if market is not None:
2676
2965
  urlParms['market'] = market
2677
2966
 
2678
- # execute spotify web api request.
2679
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/artists/{id}/albums'.format(id=artistId))
2680
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
2681
- msg.UrlParameters = urlParms
2682
- self.MakeRequest('GET', msg)
2967
+ # handle pagination, as spotify limits us to a set # of items returned per response.
2968
+ while True:
2683
2969
 
2684
- # process results.
2685
- result = AlbumPageSimplified(root=msg.ResponseData)
2970
+ # execute spotify web api request.
2971
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/artists/{id}/albums'.format(id=artistId))
2972
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
2973
+ msg.UrlParameters = urlParms
2974
+ self.MakeRequest('GET', msg)
2975
+
2976
+ # process results.
2977
+ pageObj = AlbumPageSimplified(root=msg.ResponseData)
2978
+
2979
+ # trace.
2980
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
2981
+
2982
+ # was limit total argument specified?
2983
+ if (limitTotal <= 0):
2984
+
2985
+ # no - just return the initial page of results.
2986
+ result = pageObj
2987
+ break
2988
+
2989
+ else:
2990
+
2991
+ # append page of items to final results.
2992
+ item:AlbumSimplified
2993
+ for item in pageObj.Items:
2994
+ result.Items.append(item)
2995
+ result.Limit = result.ItemsCount
2996
+ if result.ItemsCount >= limitTotal:
2997
+ break
2998
+
2999
+ # anymore pages to process? if not, then exit the loop.
3000
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
3001
+ break
3002
+
3003
+ # update result object with final paging details.
3004
+ result.Total = pageObj.Total
3005
+
3006
+ # sort items on Name property, ascending order.
3007
+ if len(result.Items) > 0:
3008
+ result.Items.sort(key=lambda x: (x.Name or "").lower(), reverse=False)
2686
3009
 
2687
3010
  # trace.
2688
3011
  _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
@@ -2711,7 +3034,7 @@ class SpotifyClient:
2711
3034
  Args:
2712
3035
  artistId (str):
2713
3036
  The Spotify ID of the artist.
2714
- Example: `0TnOYISbd1XYRBk9myaseg`
3037
+ Example: `6APm8EjxOHSYM5B4i3vT3q`
2715
3038
 
2716
3039
  Returns:
2717
3040
  A list of `Artist` objects that contain the artist details.
@@ -2845,6 +3168,7 @@ class SpotifyClient:
2845
3168
  def GetArtistsFollowed(self,
2846
3169
  after:str=None,
2847
3170
  limit:int=20,
3171
+ limitTotal:int=None
2848
3172
  ) -> ArtistPage:
2849
3173
  """
2850
3174
  Get the current user's followed artists.
@@ -2853,10 +3177,16 @@ class SpotifyClient:
2853
3177
  after (str):
2854
3178
  The last artist ID retrieved from the previous request, or null for
2855
3179
  the first request.
2856
- Example: `0I2XqVXqHScXjHhk6AYYRe`
3180
+ Example: `6APm8EjxOHSYM5B4i3vT3q`
2857
3181
  limit (int):
2858
- The maximum number of items to return.
3182
+ The maximum number of items to return in a page of items.
2859
3183
  Default: 20, Range: 1 to 50.
3184
+ limitTotal (int):
3185
+ The maximum number of items to return for the request.
3186
+ If specified, this argument overrides the limit and offset argument values
3187
+ and paging is automatically used to retrieve all available items up to the
3188
+ maximum number specified.
3189
+ Default: None (disabled)
2860
3190
 
2861
3191
  Returns:
2862
3192
  An `ArtistPage` object of matching results.
@@ -2869,11 +3199,17 @@ class SpotifyClient:
2869
3199
  If the method fails for any other reason.
2870
3200
 
2871
3201
  <details>
2872
- <summary>Sample Code</summary>
3202
+ <summary>Sample Code - Manual Paging</summary>
2873
3203
  ```python
2874
3204
  .. include:: ../docs/include/samplecode/SpotifyClient/GetArtistsFollowed.py
2875
3205
  ```
2876
3206
  </details>
3207
+ <details>
3208
+ <summary>Sample Code - Auto Paging</summary>
3209
+ ```python
3210
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetArtistsFollowed_AutoPaging.py
3211
+ ```
3212
+ </details>
2877
3213
  """
2878
3214
  apiMethodName:str = 'GetArtistsFollowed'
2879
3215
  apiMethodParms:SIMethodParmListContext = None
@@ -2885,8 +3221,23 @@ class SpotifyClient:
2885
3221
  apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
2886
3222
  apiMethodParms.AppendKeyValue("after", after)
2887
3223
  apiMethodParms.AppendKeyValue("limit", limit)
3224
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
2888
3225
  _logsi.LogMethodParmList(SILevel.Verbose, "Get the current user's followed artists", apiMethodParms)
2889
3226
 
3227
+ # validations.
3228
+ if limit is None:
3229
+ limit = 20
3230
+ if not isinstance(limitTotal, int):
3231
+ limitTotal = 0
3232
+
3233
+ # are we auto-paging? if so, then use max limit.
3234
+ if limitTotal > 0:
3235
+ limit = 50
3236
+ #limit = 5 # TEST TODO
3237
+ if limit > limitTotal:
3238
+ limit = limitTotal
3239
+ result = ArtistPage()
3240
+
2890
3241
  # build spotify web api request parameters.
2891
3242
  urlParms:dict = \
2892
3243
  {
@@ -2896,16 +3247,62 @@ class SpotifyClient:
2896
3247
  if after is not None:
2897
3248
  urlParms['after'] = after
2898
3249
 
2899
- # execute spotify web api request.
2900
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/following')
2901
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
2902
- msg.UrlParameters = urlParms
2903
- self.MakeRequest('GET', msg)
3250
+ # handle pagination, as spotify limits us to a set # of items returned per response.
3251
+ while True:
2904
3252
 
2905
- # process results.
2906
- item:dict = msg.ResponseData.get('artists',{})
2907
- if item is not None:
2908
- result = ArtistPage(root=item)
3253
+ # execute spotify web api request.
3254
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/following')
3255
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
3256
+ msg.UrlParameters = urlParms
3257
+ self.MakeRequest('GET', msg)
3258
+
3259
+ # process results.
3260
+ item:dict = msg.ResponseData.get('artists',{})
3261
+ if item is not None:
3262
+ pageObj = ArtistPage(root=item)
3263
+
3264
+ # trace.
3265
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
3266
+
3267
+ # was limit total argument specified?
3268
+ if (limitTotal <= 0):
3269
+
3270
+ # no - just return the initial page of results.
3271
+ result = pageObj
3272
+ break
3273
+
3274
+ else:
3275
+
3276
+ # append page of items to final results.
3277
+ item:Artist
3278
+ for item in pageObj.Items:
3279
+ result.Items.append(item)
3280
+ result.Limit = result.ItemsCount
3281
+ if result.ItemsCount >= limitTotal:
3282
+ break
3283
+
3284
+ # anymore page results?
3285
+ if (pageObj.Next is None) or (result.ItemsCount >= limitTotal):
3286
+ # no - all pages were processed, or limit total reached.
3287
+ break
3288
+ else:
3289
+ # yes - retrieve the next page of results.
3290
+ pageObj.CursorAfter = item.Id
3291
+
3292
+ # modify paging-related request parameters for next page of items.
3293
+ urlParms['limit'] = pageObj.Limit
3294
+ urlParms['after'] = pageObj.CursorAfter
3295
+
3296
+ # trace.
3297
+ _logsi.LogVerbose(TRACE_MSG_AUTOPAGING_NEXT % pageObj.PagingInfo)
3298
+
3299
+ # update result object with final paging details.
3300
+ result.Total = pageObj.Total
3301
+ result.CursorAfter = pageObj.CursorAfter
3302
+
3303
+ # sort items on Name property, ascending order.
3304
+ if len(result.Items) > 0:
3305
+ result.Items.sort(key=lambda x: (x.Name or "").lower(), reverse=False)
2909
3306
 
2910
3307
  # trace.
2911
3308
  _logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
@@ -2934,7 +3331,7 @@ class SpotifyClient:
2934
3331
  Args:
2935
3332
  artistId (str):
2936
3333
  The Spotify ID of the artist.
2937
- Example: `0TnOYISbd1XYRBk9myaseg`
3334
+ Example: `6APm8EjxOHSYM5B4i3vT3q`
2938
3335
  market (str):
2939
3336
  An ISO 3166-1 alpha-2 country code. If a country code is specified, only content that
2940
3337
  is available in that market will be returned. If a valid user access token is specified
@@ -2973,6 +3370,9 @@ class SpotifyClient:
2973
3370
  apiMethodParms.AppendKeyValue("market", market)
2974
3371
  _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information about an artist's top tracks", apiMethodParms)
2975
3372
 
3373
+ # ensure market was either supplied or implied; default if neither.
3374
+ market = self._ValidateMarket(market)
3375
+
2976
3376
  # build spotify web api request parameters.
2977
3377
  urlParms:dict = {}
2978
3378
  if market is not None:
@@ -3062,6 +3462,9 @@ class SpotifyClient:
3062
3462
  apiMethodParms.AppendKeyValue("market", market)
3063
3463
  _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information for a single audiobook", apiMethodParms)
3064
3464
 
3465
+ # ensure market was either supplied or implied; default if neither.
3466
+ market = self._ValidateMarket(market)
3467
+
3065
3468
  # build spotify web api request parameters.
3066
3469
  urlParms:dict = {}
3067
3470
  if market is not None:
@@ -3097,7 +3500,8 @@ class SpotifyClient:
3097
3500
  audiobookId:str,
3098
3501
  limit:int=20,
3099
3502
  offset:int=0,
3100
- market:str=None
3503
+ market:str=None,
3504
+ limitTotal:int=None
3101
3505
  ) -> ChapterPageSimplified:
3102
3506
  """
3103
3507
  Get Spotify catalog information about an audiobook's chapters.
@@ -3109,7 +3513,7 @@ class SpotifyClient:
3109
3513
  The Spotify ID for the audiobook.
3110
3514
  Example: `74aydHJKgYz3AIq3jjBSv1`
3111
3515
  limit (int):
3112
- The maximum number of items to return.
3516
+ The maximum number of items to return in a page of items.
3113
3517
  Default: 20, Range: 1 to 50.
3114
3518
  offset (int):
3115
3519
  The index of the first item to return; use with limit to get the next set of items.
@@ -3122,6 +3526,12 @@ class SpotifyClient:
3122
3526
  Note: If neither market or user country are provided, the content is considered unavailable for the client.
3123
3527
  Users can view the country that is associated with their account in the account settings.
3124
3528
  Example: `ES`
3529
+ limitTotal (int):
3530
+ The maximum number of items to return for the request.
3531
+ If specified, this argument overrides the limit and offset argument values
3532
+ and paging is automatically used to retrieve all available items up to the
3533
+ maximum number specified.
3534
+ Default: None (disabled)
3125
3535
 
3126
3536
  Returns:
3127
3537
  A `ChapterPageSimplified` object that contains simplified track information for the audiobookId.
@@ -3134,11 +3544,17 @@ class SpotifyClient:
3134
3544
  If the method fails for any other reason.
3135
3545
 
3136
3546
  <details>
3137
- <summary>Sample Code</summary>
3547
+ <summary>Sample Code - Manual Paging</summary>
3138
3548
  ```python
3139
3549
  .. include:: ../docs/include/samplecode/SpotifyClient/GetAudiobookChapters.py
3140
3550
  ```
3141
3551
  </details>
3552
+ <details>
3553
+ <summary>Sample Code - Auto Paging</summary>
3554
+ ```python
3555
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetAudiobookChapters_AutoPaging.py
3556
+ ```
3557
+ </details>
3142
3558
  """
3143
3559
  apiMethodName:str = 'GetAudiobookChapters'
3144
3560
  apiMethodParms:SIMethodParmListContext = None
@@ -3152,6 +3568,7 @@ class SpotifyClient:
3152
3568
  apiMethodParms.AppendKeyValue("limit", limit)
3153
3569
  apiMethodParms.AppendKeyValue("offset", offset)
3154
3570
  apiMethodParms.AppendKeyValue("market", market)
3571
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
3155
3572
  _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information about an audiobook's chapters", apiMethodParms)
3156
3573
 
3157
3574
  # validations.
@@ -3159,6 +3576,19 @@ class SpotifyClient:
3159
3576
  limit = 20
3160
3577
  if offset is None:
3161
3578
  offset = 0
3579
+ if not isinstance(limitTotal, int):
3580
+ limitTotal = 0
3581
+
3582
+ # are we auto-paging? if so, then use max limit.
3583
+ if limitTotal > 0:
3584
+ limit = 50
3585
+ #limit = 2 # TEST TODO
3586
+ if limit > limitTotal:
3587
+ limit = limitTotal
3588
+ result = ChapterPageSimplified()
3589
+
3590
+ # ensure market was either supplied or implied; default if neither.
3591
+ market = self._ValidateMarket(market)
3162
3592
 
3163
3593
  # build spotify web api request parameters.
3164
3594
  urlParms:dict = \
@@ -3169,14 +3599,46 @@ class SpotifyClient:
3169
3599
  if market is not None:
3170
3600
  urlParms['market'] = market
3171
3601
 
3172
- # execute spotify web api request.
3173
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/audiobooks/{id}/chapters'.format(id=audiobookId))
3174
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
3175
- msg.UrlParameters = urlParms
3176
- self.MakeRequest('GET', msg)
3602
+ # handle pagination, as spotify limits us to a set # of items returned per response.
3603
+ while True:
3177
3604
 
3178
- # process results.
3179
- result = ChapterPageSimplified(root=msg.ResponseData)
3605
+ # execute spotify web api request.
3606
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/audiobooks/{id}/chapters'.format(id=audiobookId))
3607
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
3608
+ msg.UrlParameters = urlParms
3609
+ self.MakeRequest('GET', msg)
3610
+
3611
+ # process results.
3612
+ pageObj = ChapterPageSimplified(root=msg.ResponseData)
3613
+
3614
+ # trace.
3615
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
3616
+
3617
+ # was limit total argument specified?
3618
+ if (limitTotal <= 0):
3619
+
3620
+ # no - just return the initial page of results.
3621
+ result = pageObj
3622
+ break
3623
+
3624
+ else:
3625
+
3626
+ # append page of items to final results.
3627
+ item:ChapterSimplified
3628
+ for item in pageObj.Items:
3629
+ result.Items.append(item)
3630
+ result.Limit = result.ItemsCount
3631
+ if result.ItemsCount >= limitTotal:
3632
+ break
3633
+
3634
+ # anymore pages to process? if not, then exit the loop.
3635
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
3636
+ break
3637
+
3638
+ # update result object with final paging details.
3639
+ result.Total = pageObj.Total
3640
+
3641
+ # no sorting, as chapters are in playable order.
3180
3642
 
3181
3643
  # trace.
3182
3644
  _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
@@ -3198,6 +3660,7 @@ class SpotifyClient:
3198
3660
  def GetAudiobookFavorites(self,
3199
3661
  limit:int=20,
3200
3662
  offset:int=0,
3663
+ limitTotal:int=None
3201
3664
  ) -> AudiobookPageSimplified:
3202
3665
  """
3203
3666
  Get a list of the audiobooks saved in the current Spotify user's 'Your Library'.
@@ -3206,12 +3669,18 @@ class SpotifyClient:
3206
3669
 
3207
3670
  Args:
3208
3671
  limit (int):
3209
- The maximum number of items to return.
3672
+ The maximum number of items to return in a page of items.
3210
3673
  Default: 20, Range: 1 to 50.
3211
3674
  offset (int):
3212
- The index of the first item to return.
3675
+ The page index offset of the first item to return.
3213
3676
  Use with limit to get the next set of items.
3214
3677
  Default: 0 (the first item).
3678
+ limitTotal (int):
3679
+ The maximum number of items to return for the request.
3680
+ If specified, this argument overrides the limit and offset argument values
3681
+ and paging is automatically used to retrieve all available items up to the
3682
+ maximum number specified.
3683
+ Default: None (disabled)
3215
3684
 
3216
3685
  Returns:
3217
3686
  An `AudiobookPageSimplified` object that contains saved audiobook information.
@@ -3224,11 +3693,17 @@ class SpotifyClient:
3224
3693
  If the method fails for any other reason.
3225
3694
 
3226
3695
  <details>
3227
- <summary>Sample Code</summary>
3696
+ <summary>Sample Code - Manual Paging</summary>
3228
3697
  ```python
3229
3698
  .. include:: ../docs/include/samplecode/SpotifyClient/GetAudiobookFavorites.py
3230
3699
  ```
3231
3700
  </details>
3701
+ <details>
3702
+ <summary>Sample Code - Auto Paging</summary>
3703
+ ```python
3704
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetAudiobookFavorites_AutoPaging.py
3705
+ ```
3706
+ </details>
3232
3707
  """
3233
3708
  apiMethodName:str = 'GetAudiobookFavorites'
3234
3709
  apiMethodParms:SIMethodParmListContext = None
@@ -3240,6 +3715,7 @@ class SpotifyClient:
3240
3715
  apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
3241
3716
  apiMethodParms.AppendKeyValue("limit", limit)
3242
3717
  apiMethodParms.AppendKeyValue("offset", offset)
3718
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
3243
3719
  _logsi.LogMethodParmList(SILevel.Verbose, "Get a list of the users audiobook favorites", apiMethodParms)
3244
3720
 
3245
3721
  # validations.
@@ -3247,6 +3723,16 @@ class SpotifyClient:
3247
3723
  limit = 20
3248
3724
  if offset is None:
3249
3725
  offset = 0
3726
+ if not isinstance(limitTotal, int):
3727
+ limitTotal = 0
3728
+
3729
+ # are we auto-paging? if so, then use max limit.
3730
+ if limitTotal > 0:
3731
+ limit = 50
3732
+ #limit = 2 # TEST TODO
3733
+ if limit > limitTotal:
3734
+ limit = limitTotal
3735
+ result = AudiobookPageSimplified()
3250
3736
 
3251
3737
  # build spotify web api request parameters.
3252
3738
  urlParms:dict = \
@@ -3255,15 +3741,49 @@ class SpotifyClient:
3255
3741
  'offset': offset,
3256
3742
  }
3257
3743
 
3258
- # execute spotify web api request.
3259
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/audiobooks')
3260
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
3261
- msg.UrlParameters = urlParms
3262
- self.MakeRequest('GET', msg)
3744
+ # handle pagination, as spotify limits us to a set # of items returned per response.
3745
+ while True:
3263
3746
 
3264
- # process results.
3265
- result = AudiobookPageSimplified(root=msg.ResponseData)
3747
+ # execute spotify web api request.
3748
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/audiobooks')
3749
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
3750
+ msg.UrlParameters = urlParms
3751
+ self.MakeRequest('GET', msg)
3752
+
3753
+ # process results.
3754
+ pageObj = AudiobookPageSimplified(root=msg.ResponseData)
3266
3755
 
3756
+ # trace.
3757
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
3758
+
3759
+ # was limit total argument specified?
3760
+ if (limitTotal <= 0):
3761
+
3762
+ # no - just return the initial page of results.
3763
+ result = pageObj
3764
+ break
3765
+
3766
+ else:
3767
+
3768
+ # append page of items to final results.
3769
+ item:AudiobookSimplified
3770
+ for item in pageObj.Items:
3771
+ result.Items.append(item)
3772
+ result.Limit = result.ItemsCount
3773
+ if result.ItemsCount >= limitTotal:
3774
+ break
3775
+
3776
+ # anymore pages to process? if not, then exit the loop.
3777
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
3778
+ break
3779
+
3780
+ # update result object with final paging details.
3781
+ result.Total = pageObj.Total
3782
+
3783
+ # sort items on Name property, ascending order.
3784
+ if len(result.Items) > 0:
3785
+ result.Items.sort(key=lambda x: (x.Name or "").lower(), reverse=False)
3786
+
3267
3787
  # trace.
3268
3788
  _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
3269
3789
  return result
@@ -3336,6 +3856,9 @@ class SpotifyClient:
3336
3856
  apiMethodParms.AppendKeyValue("market", market)
3337
3857
  _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information for multiple audiobooks", apiMethodParms)
3338
3858
 
3859
+ # ensure market was either supplied or implied; default if neither.
3860
+ market = self._ValidateMarket(market)
3861
+
3339
3862
  # build spotify web api request parameters.
3340
3863
  urlParms:dict = \
3341
3864
  {
@@ -3490,21 +4013,22 @@ class SpotifyClient:
3490
4013
  _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
3491
4014
 
3492
4015
 
3493
- def GetBrowseCategorysPage(self,
3494
- limit:int=50,
3495
- offset:int=0,
3496
- country:str=None,
3497
- locale:str=None,
3498
- ) -> CategoryPage:
4016
+ def GetBrowseCategorys(self,
4017
+ limit:int=20,
4018
+ offset:int=0,
4019
+ country:str=None,
4020
+ locale:str=None,
4021
+ limitTotal:int=None
4022
+ ) -> CategoryPage:
3499
4023
  """
3500
4024
  Get a page of categories used to tag items in Spotify.
3501
4025
 
3502
4026
  Args:
3503
4027
  limit (int):
3504
- The maximum number of items to return.
3505
- Default: 50, Range: 1 to 50.
4028
+ The maximum number of items to return in a page of items.
4029
+ Default: 20, Range: 1 to 50.
3506
4030
  offset (int):
3507
- The index of the first item to return.
4031
+ The page index offset of the first item to return.
3508
4032
  Use with limit to get the next set of items.
3509
4033
  Default: 0 (the first item).
3510
4034
  country (str):
@@ -3522,6 +4046,12 @@ class SpotifyClient:
3522
4046
  the country parameter, may give odd results if not carefully matched. For example country=`SE` and
3523
4047
  locale=`de_DE` will return a list of categories relevant to Sweden but as German language strings.
3524
4048
  Example: `sv_SE`
4049
+ limitTotal (int):
4050
+ The maximum number of items to return for the request.
4051
+ If specified, this argument overrides the limit and offset argument values
4052
+ and paging is automatically used to retrieve all available items up to the
4053
+ maximum number specified.
4054
+ Default: None (disabled)
3525
4055
 
3526
4056
  Returns:
3527
4057
  A `CategoryPage` object that contains a page of category details.
@@ -3534,13 +4064,19 @@ class SpotifyClient:
3534
4064
  If the method fails for any other reason.
3535
4065
 
3536
4066
  <details>
3537
- <summary>Sample Code</summary>
4067
+ <summary>Sample Code - Manual Paging</summary>
4068
+ ```python
4069
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetBrowseCategorys.py
4070
+ ```
4071
+ </details>
4072
+ <details>
4073
+ <summary>Sample Code - Auto Paging</summary>
3538
4074
  ```python
3539
- .. include:: ../docs/include/samplecode/SpotifyClient/GetBrowseCategorysPage.py
4075
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetBrowseCategorys_AutoPaging.py
3540
4076
  ```
3541
4077
  </details>
3542
4078
  """
3543
- apiMethodName:str = 'GetBrowseCategorysPage'
4079
+ apiMethodName:str = 'GetBrowseCategorys'
3544
4080
  apiMethodParms:SIMethodParmListContext = None
3545
4081
  result:CategoryPage = None
3546
4082
 
@@ -3552,13 +4088,24 @@ class SpotifyClient:
3552
4088
  apiMethodParms.AppendKeyValue("offset", offset)
3553
4089
  apiMethodParms.AppendKeyValue("country", country)
3554
4090
  apiMethodParms.AppendKeyValue("locale", locale)
4091
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
3555
4092
  _logsi.LogMethodParmList(SILevel.Verbose, "Get a page of categories used to tag items in Spotify", apiMethodParms)
3556
4093
 
3557
4094
  # validations.
3558
4095
  if limit is None:
3559
- limit = 50
4096
+ limit = 20
3560
4097
  if offset is None:
3561
4098
  offset = 0
4099
+ if not isinstance(limitTotal, int):
4100
+ limitTotal = 0
4101
+
4102
+ # are we auto-paging? if so, then use max limit.
4103
+ if limitTotal > 0:
4104
+ limit = 50
4105
+ #limit = 2 # TEST TODO
4106
+ if limit > limitTotal:
4107
+ limit = limitTotal
4108
+ result = CategoryPage()
3562
4109
 
3563
4110
  # build spotify web api request parameters.
3564
4111
  urlParms:dict = \
@@ -3571,16 +4118,50 @@ class SpotifyClient:
3571
4118
  if locale is not None:
3572
4119
  urlParms['locale'] = str(locale)
3573
4120
 
3574
- # execute spotify web api request.
3575
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/browse/categories')
3576
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
3577
- msg.UrlParameters = urlParms
3578
- self.MakeRequest('GET', msg)
4121
+ # handle pagination, as spotify limits us to a set # of items returned per response.
4122
+ while True:
3579
4123
 
3580
- # process results.
3581
- item:dict = msg.ResponseData.get('categories',None)
3582
- if item is not None:
3583
- result = CategoryPage(root=item)
4124
+ # execute spotify web api request.
4125
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/browse/categories')
4126
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
4127
+ msg.UrlParameters = urlParms
4128
+ self.MakeRequest('GET', msg)
4129
+
4130
+ # process results.
4131
+ item:dict = msg.ResponseData.get('categories',None)
4132
+ if item is not None:
4133
+ pageObj = CategoryPage(root=item)
4134
+
4135
+ # trace.
4136
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
4137
+
4138
+ # was limit total argument specified?
4139
+ if (limitTotal <= 0):
4140
+
4141
+ # no - just return the initial page of results.
4142
+ result = pageObj
4143
+ break
4144
+
4145
+ else:
4146
+
4147
+ # append page of items to final results.
4148
+ item:Category
4149
+ for item in pageObj.Items:
4150
+ result.Items.append(item)
4151
+ result.Limit = result.ItemsCount
4152
+ if result.ItemsCount >= limitTotal:
4153
+ break
4154
+
4155
+ # anymore pages to process? if not, then exit the loop.
4156
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
4157
+ break
4158
+
4159
+ # update result object with final paging details.
4160
+ result.Total = pageObj.Total
4161
+
4162
+ # sort items on Name property, ascending order.
4163
+ if len(result.Items) > 0:
4164
+ result.Items.sort(key=lambda x: (x.Name or "").lower(), reverse=False)
3584
4165
 
3585
4166
  # trace.
3586
4167
  _logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
@@ -3599,11 +4180,11 @@ class SpotifyClient:
3599
4180
  _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
3600
4181
 
3601
4182
 
3602
- def GetBrowseCategorys(self,
3603
- country:str=None,
3604
- locale:str=None,
3605
- refresh:bool=True,
3606
- ) -> list[Category]:
4183
+ def GetBrowseCategorysList(self,
4184
+ country:str=None,
4185
+ locale:str=None,
4186
+ refresh:bool=True,
4187
+ ) -> list[Category]:
3607
4188
  """
3608
4189
  Get a sorted list of ALL categories used to tag items in Spotify.
3609
4190
 
@@ -3644,11 +4225,11 @@ class SpotifyClient:
3644
4225
  <details>
3645
4226
  <summary>Sample Code</summary>
3646
4227
  ```python
3647
- .. include:: ../docs/include/samplecode/SpotifyClient/GetBrowseCategorys.py
4228
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetBrowseCategorysList.py
3648
4229
  ```
3649
4230
  </details>
3650
4231
  """
3651
- apiMethodName:str = 'GetBrowseCategorys'
4232
+ apiMethodName:str = 'GetBrowseCategorysList'
3652
4233
  apiMethodParms:SIMethodParmListContext = None
3653
4234
  result:list[Category] = []
3654
4235
  cacheDesc:str = CACHE_SOURCE_CURRENT
@@ -3659,6 +4240,7 @@ class SpotifyClient:
3659
4240
  apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
3660
4241
  apiMethodParms.AppendKeyValue("country", country)
3661
4242
  apiMethodParms.AppendKeyValue("locale", locale)
4243
+ apiMethodParms.AppendKeyValue("refresh", refresh)
3662
4244
  _logsi.LogMethodParmList(SILevel.Verbose, "Get a sorted list of ALL browse categories", apiMethodParms)
3663
4245
 
3664
4246
  # can we use the cached value?
@@ -3669,29 +4251,14 @@ class SpotifyClient:
3669
4251
 
3670
4252
  else:
3671
4253
 
3672
- # get a page of categories used to tag items in Spotify
3673
- pageObj:CategoryPage = self.GetBrowseCategorysPage(country=country, locale=locale, limit=50)
3674
-
3675
- # handle pagination, as spotify limits us to a set # of items returned per response.
3676
- while True:
3677
-
3678
- # add category details to return list.
3679
- category:Category
3680
- for category in pageObj.Items:
3681
- result.append(category)
3682
-
3683
- # anymore page results?
3684
- if pageObj.Next is None:
3685
- # no - all pages were processed.
3686
- break
3687
- else:
3688
- # yes - retrieve the next page of results.
3689
- pageObj = self.GetBrowseCategorysPage(country=country, locale=locale, offset=pageObj.Offset + pageObj.Limit, limit=pageObj.Limit)
4254
+ # get all categories (return list is already sorted).
4255
+ pageObj:CategoryPage = self.GetBrowseCategorys(country=country, locale=locale, limitTotal=1000)
3690
4256
 
3691
- # sort items on Name property, ascending order.
3692
- if len(result) > 0:
3693
- result.sort(key=lambda x: (x.Name or "").lower(), reverse=False)
3694
-
4257
+ # add category details to return list.
4258
+ category:Category
4259
+ for category in pageObj.Items:
4260
+ result.append(category)
4261
+
3695
4262
  # update cache.
3696
4263
  self._ConfigurationCache[apiMethodName] = result
3697
4264
 
@@ -3717,6 +4284,7 @@ class SpotifyClient:
3717
4284
  limit:int=20,
3718
4285
  offset:int=0,
3719
4286
  country:str=None,
4287
+ limitTotal:int=None
3720
4288
  ) -> Tuple[PlaylistPageSimplified, str]:
3721
4289
  """
3722
4290
  Get a list of Spotify playlists tagged with a particular category.
@@ -3726,10 +4294,10 @@ class SpotifyClient:
3726
4294
  The Spotify category ID for the category.
3727
4295
  Example: `dinner`
3728
4296
  limit (int):
3729
- The maximum number of items to return.
4297
+ The maximum number of items to return in a page of items.
3730
4298
  Default: 20, Range: 1 to 50.
3731
4299
  offset (int):
3732
- The index of the first item to return.
4300
+ The page index offset of the first item to return.
3733
4301
  Use with limit to get the next set of items.
3734
4302
  Default: 0 (the first item).
3735
4303
  country (str):
@@ -3737,6 +4305,12 @@ class SpotifyClient:
3737
4305
  Provide this parameter if you want the list of returned items to be relevant to a
3738
4306
  particular country. If omitted, the returned items will be relevant to all countries.
3739
4307
  Example: `SE`
4308
+ limitTotal (int):
4309
+ The maximum number of items to return for the request.
4310
+ If specified, this argument overrides the limit and offset argument values
4311
+ and paging is automatically used to retrieve all available items up to the
4312
+ maximum number specified.
4313
+ Default: None (disabled)
3740
4314
 
3741
4315
  Returns:
3742
4316
  A tuple of 2 objects:
@@ -3751,11 +4325,17 @@ class SpotifyClient:
3751
4325
  If the method fails for any other reason.
3752
4326
 
3753
4327
  <details>
3754
- <summary>Sample Code</summary>
4328
+ <summary>Sample Code - Manual Paging</summary>
3755
4329
  ```python
3756
4330
  .. include:: ../docs/include/samplecode/SpotifyClient/GetCategoryPlaylists.py
3757
4331
  ```
3758
4332
  </details>
4333
+ <details>
4334
+ <summary>Sample Code - Auto Paging</summary>
4335
+ ```python
4336
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetCategoryPlaylists_AutoPaging.py
4337
+ ```
4338
+ </details>
3759
4339
  """
3760
4340
  apiMethodName:str = 'GetCategoryPlaylists'
3761
4341
  apiMethodParms:SIMethodParmListContext = None
@@ -3770,6 +4350,7 @@ class SpotifyClient:
3770
4350
  apiMethodParms.AppendKeyValue("limit", limit)
3771
4351
  apiMethodParms.AppendKeyValue("offset", offset)
3772
4352
  apiMethodParms.AppendKeyValue("country", country)
4353
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
3773
4354
  _logsi.LogMethodParmList(SILevel.Verbose, "Get a list of Spotify playlists tagged with a particular category", apiMethodParms)
3774
4355
 
3775
4356
  # validations.
@@ -3777,6 +4358,16 @@ class SpotifyClient:
3777
4358
  limit = 20
3778
4359
  if offset is None:
3779
4360
  offset = 0
4361
+ if not isinstance(limitTotal, int):
4362
+ limitTotal = 0
4363
+
4364
+ # are we auto-paging? if so, then use max limit.
4365
+ if limitTotal > 0:
4366
+ limit = 50
4367
+ #limit = 2 # TEST TODO
4368
+ if limit > limitTotal:
4369
+ limit = limitTotal
4370
+ result = PlaylistPageSimplified()
3780
4371
 
3781
4372
  # build spotify web api request parameters.
3782
4373
  urlParms:dict = \
@@ -3788,18 +4379,52 @@ class SpotifyClient:
3788
4379
  if country is not None:
3789
4380
  urlParms['country'] = str(country)
3790
4381
 
3791
- # execute spotify web api request.
3792
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/browse/categories/{category_id}/playlists'.format(category_id=categoryId))
3793
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
3794
- msg.UrlParameters = urlParms
3795
- self.MakeRequest('GET', msg)
4382
+ # handle pagination, as spotify limits us to a set # of items returned per response.
4383
+ while True:
3796
4384
 
3797
- # process results.
3798
- resultMessage = msg.ResponseData.get('message','unknown')
3799
- item = msg.ResponseData.get('playlists',None)
3800
- if item is not None:
3801
- result = PlaylistPageSimplified(root=item)
4385
+ # execute spotify web api request.
4386
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/browse/categories/{category_id}/playlists'.format(category_id=categoryId))
4387
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
4388
+ msg.UrlParameters = urlParms
4389
+ self.MakeRequest('GET', msg)
4390
+
4391
+ # process results.
4392
+ resultMessage = msg.ResponseData.get('message','unknown')
4393
+ item = msg.ResponseData.get('playlists',None)
4394
+ if item is not None:
4395
+ pageObj = PlaylistPageSimplified(root=item)
3802
4396
 
4397
+ # trace.
4398
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
4399
+
4400
+ # was limit total argument specified?
4401
+ if (limitTotal <= 0):
4402
+
4403
+ # no - just return the initial page of results.
4404
+ result = pageObj
4405
+ break
4406
+
4407
+ else:
4408
+
4409
+ # append page of items to final results.
4410
+ item:PlaylistSimplified
4411
+ for item in pageObj.Items:
4412
+ result.Items.append(item)
4413
+ result.Limit = result.ItemsCount
4414
+ if result.ItemsCount >= limitTotal:
4415
+ break
4416
+
4417
+ # anymore pages to process? if not, then exit the loop.
4418
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
4419
+ break
4420
+
4421
+ # update result object with final paging details.
4422
+ result.Total = pageObj.Total
4423
+
4424
+ # sort items on Name property, ascending order.
4425
+ if len(result.Items) > 0:
4426
+ result.Items.sort(key=lambda x: (x.Name or "").lower(), reverse=False)
4427
+
3803
4428
  # trace.
3804
4429
  _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
3805
4430
  return result, resultMessage
@@ -3873,6 +4498,9 @@ class SpotifyClient:
3873
4498
  apiMethodParms.AppendKeyValue("market", market)
3874
4499
  _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information for a single audiobook chapter", apiMethodParms)
3875
4500
 
4501
+ # ensure market was either supplied or implied; default if neither.
4502
+ market = self._ValidateMarket(market)
4503
+
3876
4504
  # build spotify web api request parameters.
3877
4505
  urlParms:dict = {}
3878
4506
  if market is not None:
@@ -3959,6 +4587,9 @@ class SpotifyClient:
3959
4587
  apiMethodParms.AppendKeyValue("market", market)
3960
4588
  _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information for multiple chapters", apiMethodParms)
3961
4589
 
4590
+ # ensure market was either supplied or implied; default if neither.
4591
+ market = self._ValidateMarket(market)
4592
+
3962
4593
  # build spotify web api request parameters.
3963
4594
  urlParms:dict = \
3964
4595
  {
@@ -4051,6 +4682,9 @@ class SpotifyClient:
4051
4682
  apiMethodParms.AppendKeyValue("market", market)
4052
4683
  _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information for a single episode", apiMethodParms)
4053
4684
 
4685
+ # ensure market was either supplied or implied; default if neither.
4686
+ market = self._ValidateMarket(market)
4687
+
4054
4688
  # build spotify web api request parameters.
4055
4689
  urlParms:dict = {}
4056
4690
  if market is not None:
@@ -4085,6 +4719,7 @@ class SpotifyClient:
4085
4719
  def GetEpisodeFavorites(self,
4086
4720
  limit:int=20,
4087
4721
  offset:int=0,
4722
+ limitTotal:int=None
4088
4723
  ) -> EpisodePageSaved:
4089
4724
  """
4090
4725
  Get a list of the episodes saved in the current Spotify user's 'Your Library'.
@@ -4093,12 +4728,18 @@ class SpotifyClient:
4093
4728
 
4094
4729
  Args:
4095
4730
  limit (int):
4096
- The maximum number of items to return.
4731
+ The maximum number of items to return in a page of items.
4097
4732
  Default: 20, Range: 1 to 50.
4098
4733
  offset (int):
4099
- The index of the first item to return.
4734
+ The page index offset of the first item to return.
4100
4735
  Use with limit to get the next set of items.
4101
4736
  Default: 0 (the first item).
4737
+ limitTotal (int):
4738
+ The maximum number of items to return for the request.
4739
+ If specified, this argument overrides the limit and offset argument values
4740
+ and paging is automatically used to retrieve all available items up to the
4741
+ maximum number specified.
4742
+ Default: None (disabled)
4102
4743
 
4103
4744
  Returns:
4104
4745
  An `EpisodePageSaved` object that contains saved episode information.
@@ -4111,11 +4752,17 @@ class SpotifyClient:
4111
4752
  If the method fails for any other reason.
4112
4753
 
4113
4754
  <details>
4114
- <summary>Sample Code</summary>
4755
+ <summary>Sample Code - Manual Paging</summary>
4115
4756
  ```python
4116
4757
  .. include:: ../docs/include/samplecode/SpotifyClient/GetEpisodeFavorites.py
4117
4758
  ```
4118
4759
  </details>
4760
+ <details>
4761
+ <summary>Sample Code - Auto Paging</summary>
4762
+ ```python
4763
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetEpisodeFavorites_AutoPaging.py
4764
+ ```
4765
+ </details>
4119
4766
  """
4120
4767
  apiMethodName:str = 'GetEpisodeFavorites'
4121
4768
  apiMethodParms:SIMethodParmListContext = None
@@ -4127,6 +4774,7 @@ class SpotifyClient:
4127
4774
  apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
4128
4775
  apiMethodParms.AppendKeyValue("limit", limit)
4129
4776
  apiMethodParms.AppendKeyValue("offset", offset)
4777
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
4130
4778
  _logsi.LogMethodParmList(SILevel.Verbose, "Get a list of the users episode favorites", apiMethodParms)
4131
4779
 
4132
4780
  # validations.
@@ -4134,6 +4782,16 @@ class SpotifyClient:
4134
4782
  limit = 20
4135
4783
  if offset is None:
4136
4784
  offset = 0
4785
+ if not isinstance(limitTotal, int):
4786
+ limitTotal = 0
4787
+
4788
+ # are we auto-paging? if so, then use max limit.
4789
+ if limitTotal > 0:
4790
+ limit = 50
4791
+ #limit = 1 # TEST TODO
4792
+ if limit > limitTotal:
4793
+ limit = limitTotal
4794
+ result = EpisodePageSaved()
4137
4795
 
4138
4796
  # build spotify web api request parameters.
4139
4797
  urlParms:dict = \
@@ -4142,14 +4800,48 @@ class SpotifyClient:
4142
4800
  'offset': offset,
4143
4801
  }
4144
4802
 
4145
- # execute spotify web api request.
4146
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/episodes')
4147
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
4148
- msg.UrlParameters = urlParms
4149
- self.MakeRequest('GET', msg)
4803
+ # handle pagination, as spotify limits us to a set # of items returned per response.
4804
+ while True:
4150
4805
 
4151
- # process results.
4152
- result = EpisodePageSaved(root=msg.ResponseData)
4806
+ # execute spotify web api request.
4807
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/episodes')
4808
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
4809
+ msg.UrlParameters = urlParms
4810
+ self.MakeRequest('GET', msg)
4811
+
4812
+ # process results.
4813
+ pageObj = EpisodePageSaved(root=msg.ResponseData)
4814
+
4815
+ # trace.
4816
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
4817
+
4818
+ # was limit total argument specified?
4819
+ if (limitTotal <= 0):
4820
+
4821
+ # no - just return the initial page of results.
4822
+ result = pageObj
4823
+ break
4824
+
4825
+ else:
4826
+
4827
+ # append page of items to final results.
4828
+ item:EpisodeSaved
4829
+ for item in pageObj.Items:
4830
+ result.Items.append(item)
4831
+ result.Limit = result.ItemsCount
4832
+ if result.ItemsCount >= limitTotal:
4833
+ break
4834
+
4835
+ # anymore pages to process? if not, then exit the loop.
4836
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
4837
+ break
4838
+
4839
+ # update result object with final paging details.
4840
+ result.Total = pageObj.Total
4841
+
4842
+ # sort items on Name property, ascending order.
4843
+ if len(result.Items) > 0:
4844
+ result.Items.sort(key=lambda x: (x.Episode.Name or "").lower(), reverse=False)
4153
4845
 
4154
4846
  # trace.
4155
4847
  _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
@@ -4223,6 +4915,9 @@ class SpotifyClient:
4223
4915
  apiMethodParms.AppendKeyValue("market", market)
4224
4916
  _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information for multiple episodes", apiMethodParms)
4225
4917
 
4918
+ # ensure market was either supplied or implied; default if neither.
4919
+ market = self._ValidateMarket(market)
4920
+
4226
4921
  # build spotify web api request parameters.
4227
4922
  urlParms:dict = \
4228
4923
  {
@@ -4264,17 +4959,18 @@ class SpotifyClient:
4264
4959
  offset:int=0,
4265
4960
  country:str=None,
4266
4961
  locale:str=None,
4267
- timestamp:str=None
4962
+ timestamp:str=None,
4963
+ limitTotal:int=None
4268
4964
  ) -> Tuple[PlaylistPageSimplified, str]:
4269
4965
  """
4270
4966
  Get a list of Spotify featured playlists (shown, for example, on a Spotify player's 'Browse' tab).
4271
4967
 
4272
4968
  Args:
4273
4969
  limit (int):
4274
- The maximum number of items to return.
4970
+ The maximum number of items to return in a page of items.
4275
4971
  Default: 20, Range: 1 to 50.
4276
4972
  offset (int):
4277
- The index of the first item to return.
4973
+ The page index offset of the first item to return.
4278
4974
  Use with limit to get the next set of items.
4279
4975
  Default: 0 (the first item).
4280
4976
  country (str):
@@ -4300,6 +4996,12 @@ class SpotifyClient:
4300
4996
  If there were no featured playlists (or there is no data) at the specified time, the response will
4301
4997
  revert to the current UTC time.
4302
4998
  Example: `2023-10-23T09:00:00`
4999
+ limitTotal (int):
5000
+ The maximum number of items to return for the request.
5001
+ If specified, this argument overrides the limit and offset argument values
5002
+ and paging is automatically used to retrieve all available items up to the
5003
+ maximum number specified.
5004
+ Default: None (disabled)
4303
5005
 
4304
5006
  Returns:
4305
5007
  A tuple of 2 objects:
@@ -4314,11 +5016,17 @@ class SpotifyClient:
4314
5016
  If the method fails for any other reason.
4315
5017
 
4316
5018
  <details>
4317
- <summary>Sample Code</summary>
5019
+ <summary>Sample Code - Manual Paging</summary>
4318
5020
  ```python
4319
5021
  .. include:: ../docs/include/samplecode/SpotifyClient/GetFeaturedPlaylists.py
4320
5022
  ```
4321
5023
  </details>
5024
+ <details>
5025
+ <summary>Sample Code - Auto Paging</summary>
5026
+ ```python
5027
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetFeaturedPlaylists_AutoPaging.py
5028
+ ```
5029
+ </details>
4322
5030
  """
4323
5031
  apiMethodName:str = 'GetFeaturedPlaylists'
4324
5032
  apiMethodParms:SIMethodParmListContext = None
@@ -4334,6 +5042,7 @@ class SpotifyClient:
4334
5042
  apiMethodParms.AppendKeyValue("country", country)
4335
5043
  apiMethodParms.AppendKeyValue("locale", locale)
4336
5044
  apiMethodParms.AppendKeyValue("timestamp", timestamp)
5045
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
4337
5046
  _logsi.LogMethodParmList(SILevel.Verbose, "Get a list of Spotify featured playlists", apiMethodParms)
4338
5047
 
4339
5048
  # validations.
@@ -4341,6 +5050,16 @@ class SpotifyClient:
4341
5050
  limit = 20
4342
5051
  if offset is None:
4343
5052
  offset = 0
5053
+ if not isinstance(limitTotal, int):
5054
+ limitTotal = 0
5055
+
5056
+ # are we auto-paging? if so, then use max limit.
5057
+ if limitTotal > 0:
5058
+ limit = 50
5059
+ #limit = 2 # TEST TODO
5060
+ if limit > limitTotal:
5061
+ limit = limitTotal
5062
+ result = PlaylistPageSimplified()
4344
5063
 
4345
5064
  # build spotify web api request parameters.
4346
5065
  urlParms:dict = \
@@ -4355,18 +5074,52 @@ class SpotifyClient:
4355
5074
  if timestamp is not None:
4356
5075
  urlParms['timestamp'] = timestamp
4357
5076
 
4358
- # execute spotify web api request.
4359
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/browse/featured-playlists')
4360
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
4361
- msg.UrlParameters = urlParms
4362
- self.MakeRequest('GET', msg)
5077
+ # handle pagination, as spotify limits us to a set # of items returned per response.
5078
+ while True:
4363
5079
 
4364
- # process results.
4365
- resultMessage = msg.ResponseData.get('message','unknown')
4366
- item = msg.ResponseData.get('playlists',None)
4367
- if item is not None:
4368
- result = PlaylistPageSimplified(root=item)
5080
+ # execute spotify web api request.
5081
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/browse/featured-playlists')
5082
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
5083
+ msg.UrlParameters = urlParms
5084
+ self.MakeRequest('GET', msg)
5085
+
5086
+ # process results.
5087
+ resultMessage = msg.ResponseData.get('message','unknown')
5088
+ item = msg.ResponseData.get('playlists',None)
5089
+ if item is not None:
5090
+ pageObj = PlaylistPageSimplified(root=item)
4369
5091
 
5092
+ # trace.
5093
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
5094
+
5095
+ # was limit total argument specified?
5096
+ if (limitTotal <= 0):
5097
+
5098
+ # no - just return the initial page of results.
5099
+ result = pageObj
5100
+ break
5101
+
5102
+ else:
5103
+
5104
+ # append page of items to final results.
5105
+ item:PlaylistSimplified
5106
+ for item in pageObj.Items:
5107
+ result.Items.append(item)
5108
+ result.Limit = result.ItemsCount
5109
+ if result.ItemsCount >= limitTotal:
5110
+ break
5111
+
5112
+ # anymore pages to process? if not, then exit the loop.
5113
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
5114
+ break
5115
+
5116
+ # update result object with final paging details.
5117
+ result.Total = pageObj.Total
5118
+
5119
+ # sort items on Name property, ascending order.
5120
+ if len(result.Items) > 0:
5121
+ result.Items.sort(key=lambda x: (x.Name or "").lower(), reverse=False)
5122
+
4370
5123
  # trace.
4371
5124
  _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
4372
5125
  return result, resultMessage
@@ -4480,17 +5233,10 @@ class SpotifyClient:
4480
5233
 
4481
5234
  No exceptions are raised with this method.
4482
5235
  """
4483
- apiMethodName:str = 'GetIdFromUri'
4484
- apiMethodParms:SIMethodParmListContext = None
4485
5236
  result:str = None
4486
5237
 
4487
5238
  try:
4488
5239
 
4489
- # trace.
4490
- apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
4491
- apiMethodParms.AppendKeyValue("uri", uri)
4492
- _logsi.LogMethodParmList(SILevel.Verbose, "Get Id portion of a Spotify Uri value", apiMethodParms)
4493
-
4494
5240
  # validations.
4495
5241
  if uri is None or len(uri.strip()) == 0:
4496
5242
  return result
@@ -4502,19 +5248,12 @@ class SpotifyClient:
4502
5248
  if idx > -1:
4503
5249
  result = uri[idx+1:]
4504
5250
 
4505
- # trace.
4506
- _logsi.LogValue(SILevel.Verbose, 'Spotify Id', result)
4507
5251
  return result
4508
5252
 
4509
5253
  except Exception:
4510
5254
 
4511
5255
  return None
4512
5256
 
4513
- finally:
4514
-
4515
- # trace.
4516
- _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
4517
-
4518
5257
 
4519
5258
  def GetMarkets(self,
4520
5259
  refresh:bool=True
@@ -4827,6 +5566,9 @@ class SpotifyClient:
4827
5566
  apiMethodParms.AppendKeyValue("market", market)
4828
5567
  _logsi.LogMethodParmList(SILevel.Verbose, "Get the object currently being played on the user's Spotify account", apiMethodParms)
4829
5568
 
5569
+ # ensure market was either supplied or implied; default if neither.
5570
+ market = self._ValidateMarket(market)
5571
+
4830
5572
  # build spotify web api request parameters.
4831
5573
  urlParms:dict = {}
4832
5574
  if market is not None:
@@ -4915,6 +5657,9 @@ class SpotifyClient:
4915
5657
  apiMethodParms.AppendKeyValue("market", market)
4916
5658
  _logsi.LogMethodParmList(SILevel.Verbose, "Get the user's current playback state", apiMethodParms)
4917
5659
 
5660
+ # ensure market was either supplied or implied; default if neither.
5661
+ market = self._ValidateMarket(market)
5662
+
4918
5663
  # build spotify web api request parameters.
4919
5664
  urlParms:dict = {}
4920
5665
  if market is not None:
@@ -5018,7 +5763,7 @@ class SpotifyClient:
5018
5763
 
5019
5764
  Args:
5020
5765
  limit (int):
5021
- The maximum number of items to return.
5766
+ The maximum number of items to return in a page of items.
5022
5767
  Default: `20`, Range: `1` to `50`.
5023
5768
  after (int):
5024
5769
  Returns all items after (but not including) this cursor position, which is
@@ -5035,6 +5780,9 @@ class SpotifyClient:
5035
5780
 
5036
5781
  The `after` and `before` arguments are based upon local time (not UTC time). Recently
5037
5782
  played item history uses a local timestamp, and NOT a UTC timestamp.
5783
+
5784
+ If both `after` and `before` arguments are null (or zero), then an `after` value
5785
+ is generated that will retrieve recently played tracks for the past 24 hours.
5038
5786
 
5039
5787
  Returns:
5040
5788
  A `PlayHistoryPage` object that contains the recently played items.
@@ -5072,15 +5820,31 @@ class SpotifyClient:
5072
5820
  apiMethodParms.AppendKeyValue("after", after)
5073
5821
  apiMethodParms.AppendKeyValue("before", before)
5074
5822
  _logsi.LogMethodParmList(SILevel.Verbose, "Get tracks from the current user's recently played tracks", apiMethodParms)
5823
+
5824
+ # validations.
5825
+ if after is None:
5826
+ after = 0
5827
+ if (not isinstance(after,int)):
5828
+ after = int(after)
5829
+
5830
+ if before is None:
5831
+ before = 0
5832
+ if (not isinstance(before,int)):
5833
+ before = int(before)
5834
+
5835
+ # if no after or before, then get all tracks played within the past 24 hours.
5836
+ if (after == 0) and (before == 0):
5837
+ after = GetUnixTimestampMSFromUtcNow(hours=-24)
5838
+ _logsi.LogVerbose("Defaulting to retrieve play history for the past 24 hours (after = %d)" % after)
5075
5839
 
5076
5840
  # build spotify web api request parameters.
5077
5841
  urlParms:dict = \
5078
5842
  {
5079
5843
  'limit': limit,
5080
5844
  }
5081
- if after is not None:
5845
+ if after > 0:
5082
5846
  urlParms['after'] = after
5083
- if before is not None:
5847
+ if before > 0:
5084
5848
  urlParms['before'] = before
5085
5849
 
5086
5850
  # execute spotify web api request.
@@ -5182,6 +5946,9 @@ class SpotifyClient:
5182
5946
  apiMethodParms.AppendKeyValue("additionalTypes", additionalTypes)
5183
5947
  _logsi.LogMethodParmList(SILevel.Verbose, "Get a playlist owned by a Spotify user", apiMethodParms)
5184
5948
 
5949
+ # ensure market was either supplied or implied; default if neither.
5950
+ market = self._ValidateMarket(market)
5951
+
5185
5952
  # build spotify web api request parameters.
5186
5953
  urlParms:dict = {}
5187
5954
  if market is not None:
@@ -5291,7 +6058,8 @@ class SpotifyClient:
5291
6058
  offset:int=0,
5292
6059
  market:str=None,
5293
6060
  fields:str=None,
5294
- additionalTypes:str=None
6061
+ additionalTypes:str=None,
6062
+ limitTotal:int=None
5295
6063
  ) -> PlaylistPage:
5296
6064
  """
5297
6065
  Get full details of the items of a playlist owned by a Spotify user.
@@ -5303,10 +6071,10 @@ class SpotifyClient:
5303
6071
  The Spotify ID of the playlist.
5304
6072
  Example: `5v5ETK9WFXAnGQ3MRubKuE`
5305
6073
  limit (int):
5306
- The maximum number of items to return.
6074
+ The maximum number of items to return in a page of items.
5307
6075
  Default: 50, Range: 1 to 50.
5308
6076
  offset (int):
5309
- The index of the first item to return.
6077
+ The page index offset of the first item to return.
5310
6078
  Use with limit to get the next set of items.
5311
6079
  Default: 0 (the first item).
5312
6080
  market (str):
@@ -5337,6 +6105,12 @@ class SpotifyClient:
5337
6105
  Note: This parameter was introduced to allow existing clients to maintain their current behaviour
5338
6106
  and might be deprecated in the future. In addition to providing this parameter, make sure that your
5339
6107
  client properly handles cases of new types in the future by checking against the type field of each object.
6108
+ limitTotal (int):
6109
+ The maximum number of items to return for the request.
6110
+ If specified, this argument overrides the limit and offset argument values
6111
+ and paging is automatically used to retrieve all available items up to the
6112
+ maximum number specified.
6113
+ Default: None (disabled)
5340
6114
 
5341
6115
  Returns:
5342
6116
  A `Playlist` object that contains the playlist details.
@@ -5349,11 +6123,17 @@ class SpotifyClient:
5349
6123
  If the method fails for any other reason.
5350
6124
 
5351
6125
  <details>
5352
- <summary>Sample Code</summary>
6126
+ <summary>Sample Code - Manual Paging</summary>
5353
6127
  ```python
5354
6128
  .. include:: ../docs/include/samplecode/SpotifyClient/GetPlaylistItems.py
5355
6129
  ```
5356
6130
  </details>
6131
+ <details>
6132
+ <summary>Sample Code - Auto Paging</summary>
6133
+ ```python
6134
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetPlaylistItems_AutoPaging.py
6135
+ ```
6136
+ </details>
5357
6137
  """
5358
6138
  apiMethodName:str = 'GetPlaylistItems'
5359
6139
  apiMethodParms:SIMethodParmListContext = None
@@ -5369,6 +6149,7 @@ class SpotifyClient:
5369
6149
  apiMethodParms.AppendKeyValue("market", market)
5370
6150
  apiMethodParms.AppendKeyValue("fields", fields)
5371
6151
  apiMethodParms.AppendKeyValue("additionalTypes", additionalTypes)
6152
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
5372
6153
  _logsi.LogMethodParmList(SILevel.Verbose, "Get full details of the items of a playlist owned by a Spotify user", apiMethodParms)
5373
6154
 
5374
6155
  # validations.
@@ -5376,6 +6157,19 @@ class SpotifyClient:
5376
6157
  limit = 20
5377
6158
  if offset is None:
5378
6159
  offset = 0
6160
+ if not isinstance(limitTotal, int):
6161
+ limitTotal = 0
6162
+
6163
+ # are we auto-paging? if so, then use max limit.
6164
+ if limitTotal > 0:
6165
+ limit = 50
6166
+ #limit = 2 # TEST TODO
6167
+ if limit > limitTotal:
6168
+ limit = limitTotal
6169
+ result = PlaylistPage()
6170
+
6171
+ # ensure market was either supplied or implied; default if neither.
6172
+ market = self._ValidateMarket(market)
5379
6173
 
5380
6174
  # build spotify web api request parameters.
5381
6175
  urlParms:dict = \
@@ -5390,17 +6184,49 @@ class SpotifyClient:
5390
6184
  if additionalTypes is not None:
5391
6185
  urlParms['additional_types'] = additionalTypes
5392
6186
 
5393
- # execute spotify web api request.
5394
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/playlists/{id}/tracks'.format(id=playlistId))
5395
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
5396
- msg.UrlParameters = urlParms
5397
- self.MakeRequest('GET', msg)
6187
+ # handle pagination, as spotify limits us to a set # of items returned per response.
6188
+ while True:
5398
6189
 
5399
- # process results.
5400
- result = PlaylistPage(root=msg.ResponseData)
5401
-
6190
+ # execute spotify web api request.
6191
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/playlists/{id}/tracks'.format(id=playlistId))
6192
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
6193
+ msg.UrlParameters = urlParms
6194
+ self.MakeRequest('GET', msg)
6195
+
6196
+ # process results.
6197
+ pageObj = PlaylistPage(root=msg.ResponseData)
6198
+
6199
+ # trace.
6200
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
6201
+
6202
+ # was limit total argument specified?
6203
+ if (limitTotal <= 0):
6204
+
6205
+ # no - just return the initial page of results.
6206
+ result = pageObj
6207
+ break
6208
+
6209
+ else:
6210
+
6211
+ # append page of items to final results.
6212
+ item:PlaylistTrack
6213
+ for item in pageObj.Items:
6214
+ result.Items.append(item)
6215
+ result.Limit = result.ItemsCount
6216
+ if result.ItemsCount >= limitTotal:
6217
+ break
6218
+
6219
+ # anymore pages to process? if not, then exit the loop.
6220
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
6221
+ break
6222
+
6223
+ # update result object with final paging details.
6224
+ result.Total = pageObj.Total
6225
+
6226
+ # do not sort this list, as it is in play order.
6227
+
5402
6228
  # trace.
5403
- _logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
6229
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
5404
6230
  return result
5405
6231
 
5406
6232
  except SpotifyWebApiError: raise # pass handled exceptions on thru
@@ -5419,6 +6245,7 @@ class SpotifyClient:
5419
6245
  def GetPlaylistFavorites(self,
5420
6246
  limit:int=20,
5421
6247
  offset:int=0,
6248
+ limitTotal:int=None
5422
6249
  ) -> PlaylistPageSimplified:
5423
6250
  """
5424
6251
  Get a list of the playlists owned or followed by the current Spotify user.
@@ -5427,12 +6254,18 @@ class SpotifyClient:
5427
6254
 
5428
6255
  Args:
5429
6256
  limit (int):
5430
- The maximum number of items to return.
6257
+ The maximum number of items to return in a page of items.
5431
6258
  Default: 20, Range: 1 to 50.
5432
6259
  offset (int):
5433
- The index of the first item to return.
6260
+ The page index offset of the first item to return.
5434
6261
  Use with limit to get the next set of items.
5435
6262
  Default: 0 (the first item).
6263
+ limitTotal (int):
6264
+ The maximum number of items to return for the request.
6265
+ If specified, this argument overrides the limit and offset argument values
6266
+ and paging is automatically used to retrieve all available items up to the
6267
+ maximum number specified.
6268
+ Default: None (disabled)
5436
6269
 
5437
6270
  Returns:
5438
6271
  An `PlaylistPageSimplified` object that contains playlist information.
@@ -5445,11 +6278,17 @@ class SpotifyClient:
5445
6278
  If the method fails for any other reason.
5446
6279
 
5447
6280
  <details>
5448
- <summary>Sample Code</summary>
6281
+ <summary>Sample Code - Manual Paging</summary>
5449
6282
  ```python
5450
6283
  .. include:: ../docs/include/samplecode/SpotifyClient/GetPlaylistFavorites.py
5451
6284
  ```
5452
6285
  </details>
6286
+ <details>
6287
+ <summary>Sample Code - Auto Paging</summary>
6288
+ ```python
6289
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetPlaylistFavorites_AutoPaging.py
6290
+ ```
6291
+ </details>
5453
6292
  """
5454
6293
  apiMethodName:str = 'GetPlaylistFavorites'
5455
6294
  apiMethodParms:SIMethodParmListContext = None
@@ -5461,6 +6300,7 @@ class SpotifyClient:
5461
6300
  apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
5462
6301
  apiMethodParms.AppendKeyValue("limit", limit)
5463
6302
  apiMethodParms.AppendKeyValue("offset", offset)
6303
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
5464
6304
  _logsi.LogMethodParmList(SILevel.Verbose, "Get a list of the users playlist favorites", apiMethodParms)
5465
6305
 
5466
6306
  # validations.
@@ -5468,6 +6308,16 @@ class SpotifyClient:
5468
6308
  limit = 20
5469
6309
  if offset is None:
5470
6310
  offset = 0
6311
+ if not isinstance(limitTotal, int):
6312
+ limitTotal = 0
6313
+
6314
+ # are we auto-paging? if so, then use max limit.
6315
+ if limitTotal > 0:
6316
+ limit = 50
6317
+ #limit = 2 # TEST TODO
6318
+ if limit > limitTotal:
6319
+ limit = limitTotal
6320
+ result = PlaylistPageSimplified()
5471
6321
 
5472
6322
  # build spotify web api request parameters.
5473
6323
  urlParms:dict = \
@@ -5476,14 +6326,48 @@ class SpotifyClient:
5476
6326
  'offset': offset,
5477
6327
  }
5478
6328
 
5479
- # execute spotify web api request.
5480
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/playlists')
5481
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
5482
- msg.UrlParameters = urlParms
5483
- self.MakeRequest('GET', msg)
6329
+ # handle pagination, as spotify limits us to a set # of items returned per response.
6330
+ while True:
5484
6331
 
5485
- # process results.
5486
- result = PlaylistPageSimplified(root=msg.ResponseData)
6332
+ # execute spotify web api request.
6333
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/playlists')
6334
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
6335
+ msg.UrlParameters = urlParms
6336
+ self.MakeRequest('GET', msg)
6337
+
6338
+ # process results.
6339
+ pageObj = PlaylistPageSimplified(root=msg.ResponseData)
6340
+
6341
+ # trace.
6342
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
6343
+
6344
+ # was limit total argument specified?
6345
+ if (limitTotal <= 0):
6346
+
6347
+ # no - just return the initial page of results.
6348
+ result = pageObj
6349
+ break
6350
+
6351
+ else:
6352
+
6353
+ # append page of items to final results.
6354
+ item:PlaylistSimplified
6355
+ for item in pageObj.Items:
6356
+ result.Items.append(item)
6357
+ result.Limit = result.ItemsCount
6358
+ if result.ItemsCount >= limitTotal:
6359
+ break
6360
+
6361
+ # anymore pages to process? if not, then exit the loop.
6362
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
6363
+ break
6364
+
6365
+ # update result object with final paging details.
6366
+ result.Total = pageObj.Total
6367
+
6368
+ # sort items on Name property, ascending order.
6369
+ if len(result.Items) > 0:
6370
+ result.Items.sort(key=lambda x: (x.Name or "").lower(), reverse=False)
5487
6371
 
5488
6372
  # trace.
5489
6373
  _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
@@ -5506,6 +6390,7 @@ class SpotifyClient:
5506
6390
  userId:str,
5507
6391
  limit:int=20,
5508
6392
  offset:int=0,
6393
+ limitTotal:int=None
5509
6394
  ) -> PlaylistPageSimplified:
5510
6395
  """
5511
6396
  Get a list of the playlists owned or followed by a Spotify user.
@@ -5517,12 +6402,18 @@ class SpotifyClient:
5517
6402
  The user's Spotify user ID.
5518
6403
  Example: `smedjan`
5519
6404
  limit (int):
5520
- The maximum number of items to return.
6405
+ The maximum number of items to return in a page of items.
5521
6406
  Default: 20, Range: 1 to 50.
5522
6407
  offset (int):
5523
- The index of the first item to return.
6408
+ The page index offset of the first item to return.
5524
6409
  Use with limit to get the next set of items.
5525
6410
  Default: 0 (the first item).
6411
+ limitTotal (int):
6412
+ The maximum number of items to return for the request.
6413
+ If specified, this argument overrides the limit and offset argument values
6414
+ and paging is automatically used to retrieve all available items up to the
6415
+ maximum number specified.
6416
+ Default: None (disabled)
5526
6417
 
5527
6418
  Returns:
5528
6419
  An `PlaylistPageSimplified` object that contains playlist information.
@@ -5535,11 +6426,17 @@ class SpotifyClient:
5535
6426
  If the method fails for any other reason.
5536
6427
 
5537
6428
  <details>
5538
- <summary>Sample Code</summary>
6429
+ <summary>Sample Code - Manual Paging</summary>
5539
6430
  ```python
5540
6431
  .. include:: ../docs/include/samplecode/SpotifyClient/GetPlaylistsForUser.py
5541
6432
  ```
5542
6433
  </details>
6434
+ <details>
6435
+ <summary>Sample Code - Auto Paging</summary>
6436
+ ```python
6437
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetPlaylistsForUser_AutoPaging.py
6438
+ ```
6439
+ </details>
5543
6440
  """
5544
6441
  apiMethodName:str = 'GetPlaylistsForUser'
5545
6442
  apiMethodParms:SIMethodParmListContext = None
@@ -5552,6 +6449,7 @@ class SpotifyClient:
5552
6449
  apiMethodParms.AppendKeyValue("userId", userId)
5553
6450
  apiMethodParms.AppendKeyValue("limit", limit)
5554
6451
  apiMethodParms.AppendKeyValue("offset", offset)
6452
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
5555
6453
  _logsi.LogMethodParmList(SILevel.Verbose, "Get a list of the playlists owned or followed by a Spotify user", apiMethodParms)
5556
6454
 
5557
6455
  # validations.
@@ -5559,6 +6457,16 @@ class SpotifyClient:
5559
6457
  limit = 20
5560
6458
  if offset is None:
5561
6459
  offset = 0
6460
+ if not isinstance(limitTotal, int):
6461
+ limitTotal = 0
6462
+
6463
+ # are we auto-paging? if so, then use max limit.
6464
+ if limitTotal > 0:
6465
+ limit = 50
6466
+ #limit = 2 # TEST TODO
6467
+ if limit > limitTotal:
6468
+ limit = limitTotal
6469
+ result = PlaylistPageSimplified()
5562
6470
 
5563
6471
  # build spotify web api request parameters.
5564
6472
  urlParms:dict = \
@@ -5568,14 +6476,48 @@ class SpotifyClient:
5568
6476
  'offset': offset,
5569
6477
  }
5570
6478
 
5571
- # execute spotify web api request.
5572
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/users/{user_id}/playlists'.format(user_id=userId))
5573
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
5574
- msg.UrlParameters = urlParms
5575
- self.MakeRequest('GET', msg)
6479
+ # handle pagination, as spotify limits us to a set # of items returned per response.
6480
+ while True:
5576
6481
 
5577
- # process results.
5578
- result = PlaylistPageSimplified(root=msg.ResponseData)
6482
+ # execute spotify web api request.
6483
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/users/{user_id}/playlists'.format(user_id=userId))
6484
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
6485
+ msg.UrlParameters = urlParms
6486
+ self.MakeRequest('GET', msg)
6487
+
6488
+ # process results.
6489
+ pageObj = PlaylistPageSimplified(root=msg.ResponseData)
6490
+
6491
+ # trace.
6492
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
6493
+
6494
+ # was limit total argument specified?
6495
+ if (limitTotal <= 0):
6496
+
6497
+ # no - just return the initial page of results.
6498
+ result = pageObj
6499
+ break
6500
+
6501
+ else:
6502
+
6503
+ # append page of items to final results.
6504
+ item:PlaylistSimplified
6505
+ for item in pageObj.Items:
6506
+ result.Items.append(item)
6507
+ result.Limit = result.ItemsCount
6508
+ if result.ItemsCount >= limitTotal:
6509
+ break
6510
+
6511
+ # anymore pages to process? if not, then exit the loop.
6512
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
6513
+ break
6514
+
6515
+ # update result object with final paging details.
6516
+ result.Total = pageObj.Total
6517
+
6518
+ # sort items on Name property, ascending order.
6519
+ if len(result.Items) > 0:
6520
+ result.Items.sort(key=lambda x: (x.Name or "").lower(), reverse=False)
5579
6521
 
5580
6522
  # trace.
5581
6523
  _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
@@ -5648,6 +6590,9 @@ class SpotifyClient:
5648
6590
  apiMethodParms.AppendKeyValue("market", market)
5649
6591
  _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information for a single show", apiMethodParms)
5650
6592
 
6593
+ # ensure market was either supplied or implied; default if neither.
6594
+ market = self._ValidateMarket(market)
6595
+
5651
6596
  # build spotify web api request parameters.
5652
6597
  urlParms:dict = {}
5653
6598
  if market is not None:
@@ -5683,7 +6628,8 @@ class SpotifyClient:
5683
6628
  showId:str,
5684
6629
  limit:int=20,
5685
6630
  offset:int=0,
5686
- market:str=None
6631
+ market:str=None,
6632
+ limitTotal:int=None
5687
6633
  ) -> EpisodePageSimplified:
5688
6634
  """
5689
6635
  Get Spotify catalog information about a show's episodes.
@@ -5695,7 +6641,7 @@ class SpotifyClient:
5695
6641
  The Spotify ID for the show.
5696
6642
  Example: `38bS44xjbVVZ3No3ByF1dJ`
5697
6643
  limit (int):
5698
- The maximum number of items to return.
6644
+ The maximum number of items to return in a page of items.
5699
6645
  Default: 20, Range: 1 to 50.
5700
6646
  offset (int):
5701
6647
  The index of the first item to return; use with limit to get the next set of items.
@@ -5708,6 +6654,12 @@ class SpotifyClient:
5708
6654
  Note: If neither market or user country are provided, the content is considered unavailable for the client.
5709
6655
  Users can view the country that is associated with their account in the account settings.
5710
6656
  Example: `ES`
6657
+ limitTotal (int):
6658
+ The maximum number of items to return for the request.
6659
+ If specified, this argument overrides the limit and offset argument values
6660
+ and paging is automatically used to retrieve all available items up to the
6661
+ maximum number specified.
6662
+ Default: None (disabled)
5711
6663
 
5712
6664
  Returns:
5713
6665
  A `EpisodePageSimplified` object that contains simplified track information for the showId.
@@ -5720,11 +6672,17 @@ class SpotifyClient:
5720
6672
  If the method fails for any other reason.
5721
6673
 
5722
6674
  <details>
5723
- <summary>Sample Code</summary>
6675
+ <summary>Sample Code - Manual Paging</summary>
5724
6676
  ```python
5725
6677
  .. include:: ../docs/include/samplecode/SpotifyClient/GetShowEpisodes.py
5726
6678
  ```
5727
6679
  </details>
6680
+ <details>
6681
+ <summary>Sample Code - Auto Paging</summary>
6682
+ ```python
6683
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetShowEpisodes_AutoPaging.py
6684
+ ```
6685
+ </details>
5728
6686
  """
5729
6687
  apiMethodName:str = 'GetShowEpisodes'
5730
6688
  apiMethodParms:SIMethodParmListContext = None
@@ -5738,6 +6696,7 @@ class SpotifyClient:
5738
6696
  apiMethodParms.AppendKeyValue("limit", limit)
5739
6697
  apiMethodParms.AppendKeyValue("offset", offset)
5740
6698
  apiMethodParms.AppendKeyValue("market", market)
6699
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
5741
6700
  _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information about a show's episodes", apiMethodParms)
5742
6701
 
5743
6702
  # validations.
@@ -5745,6 +6704,19 @@ class SpotifyClient:
5745
6704
  limit = 20
5746
6705
  if offset is None:
5747
6706
  offset = 0
6707
+ if not isinstance(limitTotal, int):
6708
+ limitTotal = 0
6709
+
6710
+ # are we auto-paging? if so, then use max limit.
6711
+ if limitTotal > 0:
6712
+ limit = 50
6713
+ #limit = 2 # TEST TODO
6714
+ if limit > limitTotal:
6715
+ limit = limitTotal
6716
+ result = EpisodePageSimplified()
6717
+
6718
+ # ensure market was either supplied or implied; default if neither.
6719
+ market = self._ValidateMarket(market)
5748
6720
 
5749
6721
  # build spotify web api request parameters.
5750
6722
  urlParms:dict = \
@@ -5755,14 +6727,46 @@ class SpotifyClient:
5755
6727
  if market is not None:
5756
6728
  urlParms['market'] = market
5757
6729
 
5758
- # execute spotify web api request.
5759
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/shows/{id}/episodes'.format(id=showId))
5760
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
5761
- msg.UrlParameters = urlParms
5762
- self.MakeRequest('GET', msg)
6730
+ # handle pagination, as spotify limits us to a set # of items returned per response.
6731
+ while True:
5763
6732
 
5764
- # process results.
5765
- result = EpisodePageSimplified(root=msg.ResponseData)
6733
+ # execute spotify web api request.
6734
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/shows/{id}/episodes'.format(id=showId))
6735
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
6736
+ msg.UrlParameters = urlParms
6737
+ self.MakeRequest('GET', msg)
6738
+
6739
+ # process results.
6740
+ pageObj = EpisodePageSimplified(root=msg.ResponseData)
6741
+
6742
+ # trace.
6743
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
6744
+
6745
+ # was limit total argument specified?
6746
+ if (limitTotal <= 0):
6747
+
6748
+ # no - just return the initial page of results.
6749
+ result = pageObj
6750
+ break
6751
+
6752
+ else:
6753
+
6754
+ # append page of items to final results.
6755
+ item:EpisodeSimplified
6756
+ for item in pageObj.Items:
6757
+ result.Items.append(item)
6758
+ result.Limit = result.ItemsCount
6759
+ if result.ItemsCount >= limitTotal:
6760
+ break
6761
+
6762
+ # anymore pages to process? if not, then exit the loop.
6763
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
6764
+ break
6765
+
6766
+ # update result object with final paging details.
6767
+ result.Total = pageObj.Total
6768
+
6769
+ # no sort, as items are in playable order.
5766
6770
 
5767
6771
  # trace.
5768
6772
  _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
@@ -5784,6 +6788,7 @@ class SpotifyClient:
5784
6788
  def GetShowFavorites(self,
5785
6789
  limit:int=20,
5786
6790
  offset:int=0,
6791
+ limitTotal:int=None
5787
6792
  ) -> ShowPageSaved:
5788
6793
  """
5789
6794
  Get a list of the shows saved in the current Spotify user's 'Your Library'.
@@ -5792,12 +6797,18 @@ class SpotifyClient:
5792
6797
 
5793
6798
  Args:
5794
6799
  limit (int):
5795
- The maximum number of items to return.
6800
+ The maximum number of items to return in a page of items.
5796
6801
  Default: 20, Range: 1 to 50.
5797
6802
  offset (int):
5798
- The index of the first item to return.
6803
+ The page index offset of the first item to return.
5799
6804
  Use with limit to get the next set of items.
5800
6805
  Default: 0 (the first item).
6806
+ limitTotal (int):
6807
+ The maximum number of items to return for the request.
6808
+ If specified, this argument overrides the limit and offset argument values
6809
+ and paging is automatically used to retrieve all available items up to the
6810
+ maximum number specified.
6811
+ Default: None (disabled)
5801
6812
 
5802
6813
  Returns:
5803
6814
  An `ShowPageSaved` object that contains saved show information.
@@ -5810,11 +6821,17 @@ class SpotifyClient:
5810
6821
  If the method fails for any other reason.
5811
6822
 
5812
6823
  <details>
5813
- <summary>Sample Code</summary>
6824
+ <summary>Sample Code - Manual Paging</summary>
5814
6825
  ```python
5815
6826
  .. include:: ../docs/include/samplecode/SpotifyClient/GetShowFavorites.py
5816
6827
  ```
5817
6828
  </details>
6829
+ <details>
6830
+ <summary>Sample Code - Auto Paging</summary>
6831
+ ```python
6832
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetShowFavorites_AutoPaging.py
6833
+ ```
6834
+ </details>
5818
6835
  """
5819
6836
  apiMethodName:str = 'GetShowFavorites'
5820
6837
  apiMethodParms:SIMethodParmListContext = None
@@ -5826,6 +6843,7 @@ class SpotifyClient:
5826
6843
  apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
5827
6844
  apiMethodParms.AppendKeyValue("limit", limit)
5828
6845
  apiMethodParms.AppendKeyValue("offset", offset)
6846
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
5829
6847
  _logsi.LogMethodParmList(SILevel.Verbose, "Get a list of the users show favorites", apiMethodParms)
5830
6848
 
5831
6849
  # validations.
@@ -5833,6 +6851,16 @@ class SpotifyClient:
5833
6851
  limit = 20
5834
6852
  if offset is None:
5835
6853
  offset = 0
6854
+ if not isinstance(limitTotal, int):
6855
+ limitTotal = 0
6856
+
6857
+ # are we auto-paging? if so, then use max limit.
6858
+ if limitTotal > 0:
6859
+ limit = 50
6860
+ #limit = 2 # TEST TODO
6861
+ if limit > limitTotal:
6862
+ limit = limitTotal
6863
+ result = ShowPageSaved()
5836
6864
 
5837
6865
  # build spotify web api request parameters.
5838
6866
  urlParms:dict = \
@@ -5841,14 +6869,48 @@ class SpotifyClient:
5841
6869
  'offset': offset,
5842
6870
  }
5843
6871
 
5844
- # execute spotify web api request.
5845
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/shows')
5846
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
5847
- msg.UrlParameters = urlParms
5848
- self.MakeRequest('GET', msg)
6872
+ # handle pagination, as spotify limits us to a set # of items returned per response.
6873
+ while True:
5849
6874
 
5850
- # process results.
5851
- result = ShowPageSaved(root=msg.ResponseData)
6875
+ # execute spotify web api request.
6876
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/shows')
6877
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
6878
+ msg.UrlParameters = urlParms
6879
+ self.MakeRequest('GET', msg)
6880
+
6881
+ # process results.
6882
+ pageObj = ShowPageSaved(root=msg.ResponseData)
6883
+
6884
+ # trace.
6885
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
6886
+
6887
+ # was limit total argument specified?
6888
+ if (limitTotal <= 0):
6889
+
6890
+ # no - just return the initial page of results.
6891
+ result = pageObj
6892
+ break
6893
+
6894
+ else:
6895
+
6896
+ # append page of items to final results.
6897
+ item:AlbumSaved
6898
+ for item in pageObj.Items:
6899
+ result.Items.append(item)
6900
+ result.Limit = result.ItemsCount
6901
+ if result.ItemsCount >= limitTotal:
6902
+ break
6903
+
6904
+ # anymore pages to process? if not, then exit the loop.
6905
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
6906
+ break
6907
+
6908
+ # update result object with final paging details.
6909
+ result.Total = pageObj.Total
6910
+
6911
+ # sort items on Name property, ascending order.
6912
+ if len(result.Items) > 0:
6913
+ result.Items.sort(key=lambda x: (x.Show.Name or "").lower(), reverse=False)
5852
6914
 
5853
6915
  # trace.
5854
6916
  _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
@@ -5922,6 +6984,9 @@ class SpotifyClient:
5922
6984
  apiMethodParms.AppendKeyValue("market", market)
5923
6985
  _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information for multiple shows", apiMethodParms)
5924
6986
 
6987
+ # ensure market was either supplied or implied; default if neither.
6988
+ market = self._ValidateMarket(market)
6989
+
5925
6990
  # build spotify web api request parameters.
5926
6991
  urlParms:dict = \
5927
6992
  {
@@ -6090,6 +7155,7 @@ class SpotifyClient:
6090
7155
  limit:int=20,
6091
7156
  offset:int=0,
6092
7157
  market:str=None,
7158
+ limitTotal:int=None
6093
7159
  ) -> TrackPageSaved:
6094
7160
  """
6095
7161
  Get a list of the tracks saved in the current Spotify user's 'Your Library'.
@@ -6098,10 +7164,10 @@ class SpotifyClient:
6098
7164
 
6099
7165
  Args:
6100
7166
  limit (int):
6101
- The maximum number of items to return.
7167
+ The maximum number of items to return in a page of items.
6102
7168
  Default: 20, Range: 1 to 50.
6103
7169
  offset (int):
6104
- The index of the first item to return.
7170
+ The page index offset of the first item to return.
6105
7171
  Use with limit to get the next set of items.
6106
7172
  Default: 0 (the first item).
6107
7173
  market (str):
@@ -6112,6 +7178,12 @@ class SpotifyClient:
6112
7178
  Note: If neither market or user country are provided, the content is considered unavailable for the client.
6113
7179
  Users can view the country that is associated with their account in the account settings.
6114
7180
  Example: `ES`
7181
+ limitTotal (int):
7182
+ The maximum number of items to return for the request.
7183
+ If specified, this argument overrides the limit and offset argument values
7184
+ and paging is automatically used to retrieve all available items up to the
7185
+ maximum number specified.
7186
+ Default: None (disabled)
6115
7187
 
6116
7188
  Returns:
6117
7189
  An `TrackPageSaved` object that contains saved track information.
@@ -6124,11 +7196,17 @@ class SpotifyClient:
6124
7196
  If the method fails for any other reason.
6125
7197
 
6126
7198
  <details>
6127
- <summary>Sample Code</summary>
7199
+ <summary>Sample Code - Manual Paging</summary>
6128
7200
  ```python
6129
7201
  .. include:: ../docs/include/samplecode/SpotifyClient/GetTrackFavorites.py
6130
7202
  ```
6131
7203
  </details>
7204
+ <details>
7205
+ <summary>Sample Code - Auto Paging</summary>
7206
+ ```python
7207
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetTrackFavorites_AutoPaging.py
7208
+ ```
7209
+ </details>
6132
7210
  """
6133
7211
  apiMethodName:str = 'GetTrackFavorites'
6134
7212
  apiMethodParms:SIMethodParmListContext = None
@@ -6141,6 +7219,7 @@ class SpotifyClient:
6141
7219
  apiMethodParms.AppendKeyValue("limit", limit)
6142
7220
  apiMethodParms.AppendKeyValue("offset", offset)
6143
7221
  apiMethodParms.AppendKeyValue("market", market)
7222
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
6144
7223
  _logsi.LogMethodParmList(SILevel.Verbose, "Get a list of the users track favorites", apiMethodParms)
6145
7224
 
6146
7225
  # validations.
@@ -6148,6 +7227,19 @@ class SpotifyClient:
6148
7227
  limit = 20
6149
7228
  if offset is None:
6150
7229
  offset = 0
7230
+ if not isinstance(limitTotal, int):
7231
+ limitTotal = 0
7232
+
7233
+ # are we auto-paging? if so, then use max limit.
7234
+ if limitTotal > 0:
7235
+ limit = 50
7236
+ #limit = 2 # TEST TODO
7237
+ if limit > limitTotal:
7238
+ limit = limitTotal
7239
+ result = TrackPageSaved()
7240
+
7241
+ # ensure market was either supplied or implied; default if neither.
7242
+ market = self._ValidateMarket(market)
6151
7243
 
6152
7244
  # build spotify web api request parameters.
6153
7245
  urlParms:dict = \
@@ -6158,15 +7250,49 @@ class SpotifyClient:
6158
7250
  if market is not None:
6159
7251
  urlParms['market'] = market
6160
7252
 
6161
- # execute spotify web api request.
6162
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/tracks')
6163
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
6164
- msg.UrlParameters = urlParms
6165
- self.MakeRequest('GET', msg)
7253
+ # handle pagination, as spotify limits us to a set # of items returned per response.
7254
+ while True:
6166
7255
 
6167
- # process results.
6168
- result = TrackPageSaved(root=msg.ResponseData)
7256
+ # execute spotify web api request.
7257
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/tracks')
7258
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
7259
+ msg.UrlParameters = urlParms
7260
+ self.MakeRequest('GET', msg)
7261
+
7262
+ # process results.
7263
+ pageObj = TrackPageSaved(root=msg.ResponseData)
6169
7264
 
7265
+ # trace.
7266
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
7267
+
7268
+ # was limit total argument specified?
7269
+ if (limitTotal <= 0):
7270
+
7271
+ # no - just return the initial page of results.
7272
+ result = pageObj
7273
+ break
7274
+
7275
+ else:
7276
+
7277
+ # append page of items to final results.
7278
+ item:TrackSaved
7279
+ for item in pageObj.Items:
7280
+ result.Items.append(item)
7281
+ result.Limit = result.ItemsCount
7282
+ if result.ItemsCount >= limitTotal:
7283
+ break
7284
+
7285
+ # anymore pages to process? if not, then exit the loop.
7286
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
7287
+ break
7288
+
7289
+ # update result object with final paging details.
7290
+ result.Total = pageObj.Total
7291
+
7292
+ # sort items on Name property, ascending order.
7293
+ if len(result.Items) > 0:
7294
+ result.Items.sort(key=lambda x: (x.Track.Name or "").lower(), reverse=False)
7295
+
6170
7296
  # trace.
6171
7297
  _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
6172
7298
  return result
@@ -6234,6 +7360,9 @@ class SpotifyClient:
6234
7360
  apiMethodParms.AppendKeyValue("market", market)
6235
7361
  _logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information for multiple tracks", apiMethodParms)
6236
7362
 
7363
+ # ensure market was either supplied or implied; default if neither.
7364
+ market = self._ValidateMarket(market)
7365
+
6237
7366
  # build spotify web api request parameters.
6238
7367
  urlParms:dict = \
6239
7368
  {
@@ -6373,7 +7502,7 @@ class SpotifyClient:
6373
7502
 
6374
7503
  Args:
6375
7504
  limit (int):
6376
- The maximum number of items to return.
7505
+ The maximum number of items to return in a page of items.
6377
7506
  Default: 20, Range: 1 to 50.
6378
7507
  market (str):
6379
7508
  An ISO 3166-1 alpha-2 country code. If a country code is specified, only content that
@@ -6604,6 +7733,9 @@ class SpotifyClient:
6604
7733
  apiMethodParms.AppendKeyValue("targetValence", targetValence)
6605
7734
  _logsi.LogMethodParmList(SILevel.Verbose, "Get track recommendations for specified criteria", apiMethodParms)
6606
7735
 
7736
+ # ensure market was either supplied or implied; default if neither.
7737
+ market = self._ValidateMarket(market)
7738
+
6607
7739
  # build spotify web api request parameters.
6608
7740
  urlParms:dict = \
6609
7741
  {
@@ -6759,17 +7891,10 @@ class SpotifyClient:
6759
7891
 
6760
7892
  No exceptions are raised with this method.
6761
7893
  """
6762
- apiMethodName:str = 'GetTypeFromUri'
6763
- apiMethodParms:SIMethodParmListContext = None
6764
7894
  result:str = None
6765
7895
 
6766
7896
  try:
6767
7897
 
6768
- # trace.
6769
- apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
6770
- apiMethodParms.AppendKeyValue("uri", uri)
6771
- _logsi.LogMethodParmList(SILevel.Verbose, "Get Type portion of a Spotify Uri value", apiMethodParms)
6772
-
6773
7898
  # validations.
6774
7899
  if uri is None or len(uri.strip()) == 0:
6775
7900
  return result
@@ -6785,8 +7910,6 @@ class SpotifyClient:
6785
7910
  if idxEnd > -1:
6786
7911
  result = uri[idxStart+1:idxEnd]
6787
7912
 
6788
- # trace.
6789
- _logsi.LogValue(SILevel.Verbose, 'Spotify Type', result)
6790
7913
  return result
6791
7914
 
6792
7915
  except Exception as ex:
@@ -6794,11 +7917,6 @@ class SpotifyClient:
6794
7917
  _logsi.LogWarning("GetTypeFromUri failed: %s" % str(ex))
6795
7918
  return None
6796
7919
 
6797
- finally:
6798
-
6799
- # trace.
6800
- _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
6801
-
6802
7920
 
6803
7921
  def GetUsersCurrentProfile(self,
6804
7922
  refresh:bool=True
@@ -6948,7 +8066,8 @@ class SpotifyClient:
6948
8066
  def GetUsersTopArtists(self,
6949
8067
  timeRange:str='medium_term',
6950
8068
  limit:int=20,
6951
- offset:int=0
8069
+ offset:int=0,
8070
+ limitTotal:int=None
6952
8071
  ) -> ArtistPage:
6953
8072
  """
6954
8073
  Get the current user's top artists based on calculated affinity.
@@ -6963,12 +8082,18 @@ class SpotifyClient:
6963
8082
  Default: `medium_term`
6964
8083
  Example: `long_term`
6965
8084
  limit (int):
6966
- The maximum number of items to return.
8085
+ The maximum number of items to return in a page of items.
6967
8086
  Default: 20, Range: 1 to 50.
6968
8087
  offset (int):
6969
- The index of the first item to return.
8088
+ The page index offset of the first item to return.
6970
8089
  Use with limit to get the next set of items.
6971
8090
  Default: 0 (the first item), Range: 0 to 1000
8091
+ limitTotal (int):
8092
+ The maximum number of items to return for the request.
8093
+ If specified, this argument overrides the limit and offset argument values
8094
+ and paging is automatically used to retrieve all available items up to the
8095
+ maximum number specified.
8096
+ Default: None (disabled)
6972
8097
 
6973
8098
  Returns:
6974
8099
  An `ArtistPage` object of matching results.
@@ -6981,11 +8106,17 @@ class SpotifyClient:
6981
8106
  If the method fails for any other reason.
6982
8107
 
6983
8108
  <details>
6984
- <summary>Sample Code</summary>
8109
+ <summary>Sample Code - Manual Paging</summary>
6985
8110
  ```python
6986
8111
  .. include:: ../docs/include/samplecode/SpotifyClient/GetUsersTopArtists.py
6987
8112
  ```
6988
8113
  </details>
8114
+ <details>
8115
+ <summary>Sample Code - Auto Paging</summary>
8116
+ ```python
8117
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetUsersTopArtists_AutoPaging.py
8118
+ ```
8119
+ </details>
6989
8120
  """
6990
8121
  apiMethodName:str = 'GetUsersTopArtists'
6991
8122
  apiMethodParms:SIMethodParmListContext = None
@@ -6998,6 +8129,7 @@ class SpotifyClient:
6998
8129
  apiMethodParms.AppendKeyValue("timeRange", timeRange)
6999
8130
  apiMethodParms.AppendKeyValue("limit", limit)
7000
8131
  apiMethodParms.AppendKeyValue("offset", offset)
8132
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
7001
8133
  _logsi.LogMethodParmList(SILevel.Verbose, "Get the current user's top artists", apiMethodParms)
7002
8134
 
7003
8135
  # validations.
@@ -7007,6 +8139,16 @@ class SpotifyClient:
7007
8139
  limit = 20
7008
8140
  if offset is None:
7009
8141
  offset = 0
8142
+ if not isinstance(limitTotal, int):
8143
+ limitTotal = 0
8144
+
8145
+ # are we auto-paging? if so, then use max limit.
8146
+ if limitTotal > 0:
8147
+ limit = 50
8148
+ #limit = 20 # TEST TODO
8149
+ if limit > limitTotal:
8150
+ limit = limitTotal
8151
+ result = ArtistPage()
7010
8152
 
7011
8153
  # build spotify web api request parameters.
7012
8154
  urlParms:dict = \
@@ -7016,17 +8158,51 @@ class SpotifyClient:
7016
8158
  'offset': offset,
7017
8159
  }
7018
8160
 
7019
- # execute spotify web api request.
7020
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/top/artists')
7021
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
7022
- msg.UrlParameters = urlParms
7023
- self.MakeRequest('GET', msg)
8161
+ # handle pagination, as spotify limits us to a set # of items returned per response.
8162
+ while True:
7024
8163
 
7025
- # process results.
7026
- result = ArtistPage(root=msg.ResponseData)
8164
+ # execute spotify web api request.
8165
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/top/artists')
8166
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
8167
+ msg.UrlParameters = urlParms
8168
+ self.MakeRequest('GET', msg)
8169
+
8170
+ # process results.
8171
+ pageObj = ArtistPage(root=msg.ResponseData)
8172
+
8173
+ # trace.
8174
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
8175
+
8176
+ # was limit total argument specified?
8177
+ if (limitTotal <= 0):
8178
+
8179
+ # no - just return the initial page of results.
8180
+ result = pageObj
8181
+ break
8182
+
8183
+ else:
8184
+
8185
+ # append page of items to final results.
8186
+ item:Artist
8187
+ for item in pageObj.Items:
8188
+ result.Items.append(item)
8189
+ result.Limit = result.ItemsCount
8190
+ if result.ItemsCount >= limitTotal:
8191
+ break
8192
+
8193
+ # anymore pages to process? if not, then exit the loop.
8194
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
8195
+ break
8196
+
8197
+ # update result object with final paging details.
8198
+ result.Total = pageObj.Total
8199
+
8200
+ # sort items on Name property, ascending order.
8201
+ if len(result.Items) > 0:
8202
+ result.Items.sort(key=lambda x: (x.Name or "").lower(), reverse=False)
7027
8203
 
7028
8204
  # trace.
7029
- _logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
8205
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
7030
8206
  return result
7031
8207
 
7032
8208
  except SpotifyWebApiError: raise # pass handled exceptions on thru
@@ -7045,7 +8221,8 @@ class SpotifyClient:
7045
8221
  def GetUsersTopTracks(self,
7046
8222
  timeRange:str='medium_term',
7047
8223
  limit:int=20,
7048
- offset:int=0
8224
+ offset:int=0,
8225
+ limitTotal:int=None
7049
8226
  ) -> TrackPage:
7050
8227
  """
7051
8228
  Get the current user's top tracks based on calculated affinity.
@@ -7060,12 +8237,18 @@ class SpotifyClient:
7060
8237
  Default: `medium_term`
7061
8238
  Example: `long_term`
7062
8239
  limit (int):
7063
- The maximum number of items to return.
8240
+ The maximum number of items to return in a page of items.
7064
8241
  Default: 20, Range: 1 to 50.
7065
8242
  offset (int):
7066
- The index of the first item to return.
8243
+ The page index offset of the first item to return.
7067
8244
  Use with limit to get the next set of items.
7068
- Default: 0 (the first item), Range: 0 to 1000
8245
+ Default: 0 (the first item).
8246
+ limitTotal (int):
8247
+ The maximum number of items to return for the request.
8248
+ If specified, this argument overrides the limit and offset argument values
8249
+ and paging is automatically used to retrieve all available items up to the
8250
+ maximum number specified.
8251
+ Default: None (disabled)
7069
8252
 
7070
8253
  Returns:
7071
8254
  An `TrackPage` object of matching results.
@@ -7078,11 +8261,17 @@ class SpotifyClient:
7078
8261
  If the method fails for any other reason.
7079
8262
 
7080
8263
  <details>
7081
- <summary>Sample Code</summary>
8264
+ <summary>Sample Code - Manual Paging</summary>
7082
8265
  ```python
7083
8266
  .. include:: ../docs/include/samplecode/SpotifyClient/GetUsersTopTracks.py
7084
8267
  ```
7085
8268
  </details>
8269
+ <details>
8270
+ <summary>Sample Code - Auto Paging</summary>
8271
+ ```python
8272
+ .. include:: ../docs/include/samplecode/SpotifyClient/GetUsersTopTracks_AutoPaging.py
8273
+ ```
8274
+ </details>
7086
8275
  """
7087
8276
  apiMethodName:str = 'GetUsersTopTracks'
7088
8277
  apiMethodParms:SIMethodParmListContext = None
@@ -7095,6 +8284,7 @@ class SpotifyClient:
7095
8284
  apiMethodParms.AppendKeyValue("timeRange", timeRange)
7096
8285
  apiMethodParms.AppendKeyValue("limit", limit)
7097
8286
  apiMethodParms.AppendKeyValue("offset", offset)
8287
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
7098
8288
  _logsi.LogMethodParmList(SILevel.Verbose, "Get the current user's top tracks", apiMethodParms)
7099
8289
 
7100
8290
  # validations.
@@ -7104,6 +8294,16 @@ class SpotifyClient:
7104
8294
  limit = 20
7105
8295
  if offset is None:
7106
8296
  offset = 0
8297
+ if not isinstance(limitTotal, int):
8298
+ limitTotal = 0
8299
+
8300
+ # are we auto-paging? if so, then use max limit.
8301
+ if limitTotal > 0:
8302
+ limit = 50
8303
+ #limit = 10 # TEST TODO
8304
+ if limit > limitTotal:
8305
+ limit = limitTotal
8306
+ result = TrackPage()
7107
8307
 
7108
8308
  # build spotify web api request parameters.
7109
8309
  urlParms:dict = \
@@ -7113,17 +8313,51 @@ class SpotifyClient:
7113
8313
  'offset': offset,
7114
8314
  }
7115
8315
 
7116
- # execute spotify web api request.
7117
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/top/tracks')
7118
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
7119
- msg.UrlParameters = urlParms
7120
- self.MakeRequest('GET', msg)
8316
+ # handle pagination, as spotify limits us to a set # of items returned per response.
8317
+ while True:
7121
8318
 
7122
- # process results.
7123
- result = TrackPage(root=msg.ResponseData)
8319
+ # execute spotify web api request.
8320
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/top/tracks')
8321
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
8322
+ msg.UrlParameters = urlParms
8323
+ self.MakeRequest('GET', msg)
8324
+
8325
+ # process results.
8326
+ pageObj = TrackPage(root=msg.ResponseData)
8327
+
8328
+ # trace.
8329
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
8330
+
8331
+ # was limit total argument specified?
8332
+ if (limitTotal <= 0):
8333
+
8334
+ # no - just return the initial page of results.
8335
+ result = pageObj
8336
+ break
8337
+
8338
+ else:
8339
+
8340
+ # append page of items to final results.
8341
+ item:Track
8342
+ for item in pageObj.Items:
8343
+ result.Items.append(item)
8344
+ result.Limit = result.ItemsCount
8345
+ if result.ItemsCount >= limitTotal:
8346
+ break
8347
+
8348
+ # anymore pages to process? if not, then exit the loop.
8349
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
8350
+ break
8351
+
8352
+ # update result object with final paging details.
8353
+ result.Total = pageObj.Total
8354
+
8355
+ # sort items on Name property, ascending order.
8356
+ if len(result.Items) > 0:
8357
+ result.Items.sort(key=lambda x: (x.Name or "").lower(), reverse=False)
7124
8358
 
7125
8359
  # trace.
7126
- _logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
8360
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
7127
8361
  return result
7128
8362
 
7129
8363
  except SpotifyWebApiError: raise # pass handled exceptions on thru
@@ -9223,18 +10457,192 @@ class SpotifyClient:
9223
10457
  _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
9224
10458
 
9225
10459
 
9226
- def Search(self,
9227
- criteria:str,
9228
- criteriaType:str,
9229
- limit:int=20,
9230
- offset:int=0,
9231
- market:str=None,
9232
- includeExternal:str=None
9233
- ) -> SearchResponse:
9234
- """
9235
- Get Spotify catalog information about albums, artists, playlists, tracks, shows, episodes
9236
- or audiobooks that match a keyword string. Audiobooks are only available within the US, UK,
9237
- Canada, Ireland, New Zealand and Australia markets.
10460
+ # def Search(self,
10461
+ # criteria:str,
10462
+ # criteriaType:str,
10463
+ # limit:int=20,
10464
+ # offset:int=0,
10465
+ # market:str=None,
10466
+ # includeExternal:str=None,
10467
+ # ) -> SearchResponse:
10468
+ # """
10469
+ # Get Spotify catalog information about albums, artists, playlists, tracks, shows, episodes
10470
+ # or audiobooks that match a keyword string. Audiobooks are only available within the US, UK,
10471
+ # Canada, Ireland, New Zealand and Australia markets.
10472
+
10473
+ # Args:
10474
+ # criteria (str):
10475
+ # Your search query.
10476
+ # You can narrow down your search using field filters.
10477
+ # The available filters are album, artist, track, year, upc, tag:hipster, tag:new,
10478
+ # isrc, and genre. Each field filter only applies to certain result types.
10479
+ # The artist and year filters can be used while searching albums, artists and tracks.
10480
+ # You can filter on a single year or a range (e.g. 1955-1960).
10481
+ # The album filter can be used while searching albums and tracks.
10482
+ # The genre filter can be used while searching artists and tracks.
10483
+ # The isrc and track filters can be used while searching tracks.
10484
+ # The upc, tag:new and tag:hipster filters can only be used while searching albums.
10485
+ # The tag:new filter will return albums released in the past two weeks and tag:hipster
10486
+ # can be used to return only albums with the lowest 10% popularity.
10487
+ # criteriaType (str):
10488
+ # A comma-separated list of item types to search across.
10489
+ # Search results include hits from all the specified item types.
10490
+ # For example: "album,track" returns both albums and tracks matching criteria argument.
10491
+ # Allowed values: "album", "artist", "playlist", "track", "show", "episode", "audiobook".
10492
+ # limit (int):
10493
+ # The maximum number of items to return in a page of items.
10494
+ # Default: 20, Range: 1 to 50.
10495
+ # offset (int):
10496
+ # The page index offset of the first item to return.
10497
+ # Use with limit to get the next set of items.
10498
+ # Default: 0 (the first item). Range: 0 to 1000.
10499
+ # market (str):
10500
+ # An ISO 3166-1 alpha-2 country code. If a country code is specified, only content that
10501
+ # is available in that market will be returned. If a valid user access token is specified
10502
+ # in the request header, the country associated with the user account will take priority over
10503
+ # this parameter.
10504
+ # Note: If neither market or user country are provided, the content is considered unavailable for the client.
10505
+ # Users can view the country that is associated with their account in the account settings.
10506
+ # Example: `ES`
10507
+ # includeExternal (str):
10508
+ # If "audio" is specified it signals that the client can play externally hosted audio content, and
10509
+ # marks the content as playable in the response. By default externally hosted audio content is marked
10510
+ # as unplayable in the response.
10511
+ # Allowed values: "audio"
10512
+
10513
+ # Returns:
10514
+ # A `SearchResponse` object that contains the search results.
10515
+
10516
+ # Raises:
10517
+ # SpotifyWebApiError:
10518
+ # If the Spotify Web API request was for a non-authorization service
10519
+ # and the response contains error information.
10520
+ # SpotifApiError:
10521
+ # If the method fails for any other reason.
10522
+
10523
+ # Note the offset limitation of 1000 entries; this effectively limits you to 1,050 maximum
10524
+ # entries that you can return with a search.
10525
+
10526
+ # <details>
10527
+ # <summary>Sample Code - Search Albums</summary>
10528
+ # ```python
10529
+ # .. include:: ../docs/include/samplecode/SpotifyClient/SearchAlbums.py
10530
+ # ```
10531
+ # </details>
10532
+
10533
+ # <details>
10534
+ # <summary>Sample Code - Search Artists</summary>
10535
+ # ```python
10536
+ # .. include:: ../docs/include/samplecode/SpotifyClient/SearchArtists.py
10537
+ # ```
10538
+ # </details>
10539
+
10540
+ # <details>
10541
+ # <summary>Sample Code - Search Audiobooks</summary>
10542
+ # ```python
10543
+ # .. include:: ../docs/include/samplecode/SpotifyClient/SearchAudiobooks.py
10544
+ # ```
10545
+ # </details>
10546
+
10547
+ # <details>
10548
+ # <summary>Sample Code - Search Episodes</summary>
10549
+ # ```python
10550
+ # .. include:: ../docs/include/samplecode/SpotifyClient/SearchEpisodes.py
10551
+ # ```
10552
+ # </details>
10553
+
10554
+ # <details>
10555
+ # <summary>Sample Code - Search Playlists</summary>
10556
+ # ```python
10557
+ # .. include:: ../docs/include/samplecode/SpotifyClient/SearchPlaylists.py
10558
+ # ```
10559
+ # </details>
10560
+
10561
+ # <details>
10562
+ # <summary>Sample Code - Search Shows</summary>
10563
+ # ```python
10564
+ # .. include:: ../docs/include/samplecode/SpotifyClient/SearchShows.py
10565
+ # ```
10566
+ # </details>
10567
+
10568
+ # <details>
10569
+ # <summary>Sample Code - Search Tracks</summary>
10570
+ # ```python
10571
+ # .. include:: ../docs/include/samplecode/SpotifyClient/SearchTracks.py
10572
+ # ```
10573
+ # </details>
10574
+ # """
10575
+ # apiMethodName:str = 'Search'
10576
+ # apiMethodParms:SIMethodParmListContext = None
10577
+ # result:SearchResponse = None
10578
+
10579
+ # try:
10580
+
10581
+ # # trace.
10582
+ # apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
10583
+ # apiMethodParms.AppendKeyValue("criteria", criteria)
10584
+ # apiMethodParms.AppendKeyValue("criteriaType", criteriaType)
10585
+ # apiMethodParms.AppendKeyValue("limit", limit)
10586
+ # apiMethodParms.AppendKeyValue("offset", offset)
10587
+ # apiMethodParms.AppendKeyValue("market", market)
10588
+ # apiMethodParms.AppendKeyValue("includeExternal", includeExternal)
10589
+ # _logsi.LogMethodParmList(SILevel.Verbose, "Searching Spotify catalog for information.", apiMethodParms)
10590
+
10591
+ # # validations.
10592
+ # if limit is None:
10593
+ # limit = 20
10594
+ # if offset is None:
10595
+ # offset = 0
10596
+
10597
+ # # build spotify web api request parameters.
10598
+ # urlParms:dict = \
10599
+ # {
10600
+ # 'q': criteria,
10601
+ # 'type': criteriaType,
10602
+ # 'limit': limit,
10603
+ # 'offset': offset,
10604
+ # }
10605
+ # if market is not None:
10606
+ # urlParms['market'] = market
10607
+ # if includeExternal is not None:
10608
+ # urlParms['include_external'] = includeExternal
10609
+
10610
+ # # execute spotify web api request.
10611
+ # msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/search')
10612
+ # msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
10613
+ # msg.UrlParameters = urlParms
10614
+ # self.MakeRequest('GET', msg)
10615
+
10616
+ # # process results.
10617
+ # result = SearchResponse(criteria, criteriaType, root=msg.ResponseData)
10618
+
10619
+ # # trace.
10620
+ # _logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
10621
+ # return result
10622
+
10623
+ # except SpotifyWebApiError: raise # pass handled exceptions on thru
10624
+ # except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
10625
+ # except Exception as ex:
10626
+
10627
+ # # format unhandled exception.
10628
+ # raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
10629
+
10630
+ # finally:
10631
+
10632
+ # # trace.
10633
+ # _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
10634
+
10635
+
10636
+ def SearchAlbums(self,
10637
+ criteria:str,
10638
+ limit:int=20,
10639
+ offset:int=0,
10640
+ market:str=None,
10641
+ includeExternal:str=None,
10642
+ limitTotal:int=None
10643
+ ) -> SearchResponse:
10644
+ """
10645
+ Get Spotify catalog information about Albums that match a keyword string.
9238
10646
 
9239
10647
  Args:
9240
10648
  criteria (str):
@@ -9250,18 +10658,13 @@ class SpotifyClient:
9250
10658
  The upc, tag:new and tag:hipster filters can only be used while searching albums.
9251
10659
  The tag:new filter will return albums released in the past two weeks and tag:hipster
9252
10660
  can be used to return only albums with the lowest 10% popularity.
9253
- criteriaType (str):
9254
- A comma-separated list of item types to search across.
9255
- Search results include hits from all the specified item types.
9256
- For example: "album,track" returns both albums and tracks matching criteria argument.
9257
- Allowed values: "album", "artist", "playlist", "track", "show", "episode", "audiobook".
9258
10661
  limit (int):
9259
- The maximum number of items to return.
10662
+ The maximum number of items to return in a page of items.
9260
10663
  Default: 20, Range: 1 to 50.
9261
10664
  offset (int):
9262
- The index of the first item to return.
10665
+ The page index offset of the first item to return.
9263
10666
  Use with limit to get the next set of items.
9264
- Default: 0 (the first item), Range: 0 to 1000
10667
+ Default: 0 (the first item). Range: 0 to 1000.
9265
10668
  market (str):
9266
10669
  An ISO 3166-1 alpha-2 country code. If a country code is specified, only content that
9267
10670
  is available in that market will be returned. If a valid user access token is specified
@@ -9275,6 +10678,12 @@ class SpotifyClient:
9275
10678
  marks the content as playable in the response. By default externally hosted audio content is marked
9276
10679
  as unplayable in the response.
9277
10680
  Allowed values: "audio"
10681
+ limitTotal (int):
10682
+ The maximum number of items to return for the request.
10683
+ If specified, this argument overrides the limit and offset argument values
10684
+ and paging is automatically used to retrieve all available items up to the
10685
+ maximum number specified.
10686
+ Default: None (disabled)
9278
10687
 
9279
10688
  Returns:
9280
10689
  A `SearchResponse` object that contains the search results.
@@ -9286,61 +10695,26 @@ class SpotifyClient:
9286
10695
  SpotifApiError:
9287
10696
  If the method fails for any other reason.
9288
10697
 
9289
- Note the offset limitation of 1000 entries; this effectively limits you to 1,050 maximum
9290
- entries that you can return with a search.
10698
+ Note that Spotify Web API automatically limits you to 1,000 max entries per type that can
10699
+ be returned with a search.
9291
10700
 
9292
10701
  <details>
9293
- <summary>Sample Code - Search Albums</summary>
10702
+ <summary>Sample Code - Manual Paging</summary>
9294
10703
  ```python
9295
10704
  .. include:: ../docs/include/samplecode/SpotifyClient/SearchAlbums.py
9296
10705
  ```
9297
10706
  </details>
9298
-
9299
- <details>
9300
- <summary>Sample Code - Search Artists</summary>
9301
- ```python
9302
- .. include:: ../docs/include/samplecode/SpotifyClient/SearchArtists.py
9303
- ```
9304
- </details>
9305
-
9306
- <details>
9307
- <summary>Sample Code - Search Audiobooks</summary>
9308
- ```python
9309
- .. include:: ../docs/include/samplecode/SpotifyClient/SearchAudiobooks.py
9310
- ```
9311
- </details>
9312
-
9313
- <details>
9314
- <summary>Sample Code - Search Episodes</summary>
9315
- ```python
9316
- .. include:: ../docs/include/samplecode/SpotifyClient/SearchEpisodes.py
9317
- ```
9318
- </details>
9319
-
9320
- <details>
9321
- <summary>Sample Code - Search Playlists</summary>
9322
- ```python
9323
- .. include:: ../docs/include/samplecode/SpotifyClient/SearchPlaylists.py
9324
- ```
9325
- </details>
9326
-
9327
- <details>
9328
- <summary>Sample Code - Search Shows</summary>
9329
- ```python
9330
- .. include:: ../docs/include/samplecode/SpotifyClient/SearchShows.py
9331
- ```
9332
- </details>
9333
-
9334
10707
  <details>
9335
- <summary>Sample Code - Search Tracks</summary>
10708
+ <summary>Sample Code - Auto Paging</summary>
9336
10709
  ```python
9337
- .. include:: ../docs/include/samplecode/SpotifyClient/SearchTracks.py
10710
+ .. include:: ../docs/include/samplecode/SpotifyClient/SearchAlbums_AutoPaging.py
9338
10711
  ```
9339
10712
  </details>
9340
10713
  """
9341
- apiMethodName:str = 'Search'
10714
+ apiMethodName:str = 'SearchAlbums'
9342
10715
  apiMethodParms:SIMethodParmListContext = None
9343
- result:SearchResponse = None
10716
+ criteriaType:str = 'album'
10717
+ result:AlbumPageSimplified = None
9344
10718
 
9345
10719
  try:
9346
10720
 
@@ -9352,13 +10726,26 @@ class SpotifyClient:
9352
10726
  apiMethodParms.AppendKeyValue("offset", offset)
9353
10727
  apiMethodParms.AppendKeyValue("market", market)
9354
10728
  apiMethodParms.AppendKeyValue("includeExternal", includeExternal)
9355
- _logsi.LogMethodParmList(SILevel.Verbose, "Searching Spotify catalog for information.", apiMethodParms)
10729
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
10730
+ _logsi.LogMethodParmList(SILevel.Verbose, "Searching Spotify catalog for %s information" % criteriaType, apiMethodParms)
9356
10731
 
9357
10732
  # validations.
9358
10733
  if limit is None:
9359
10734
  limit = 20
9360
10735
  if offset is None:
9361
10736
  offset = 0
10737
+ if not isinstance(limitTotal, int):
10738
+ limitTotal = 0
10739
+
10740
+ # are we auto-paging? if so, then use max limit.
10741
+ if limitTotal > 0:
10742
+ limit = 50
10743
+ if limit > limitTotal:
10744
+ limit = limitTotal
10745
+ result = AlbumPageSimplified()
10746
+
10747
+ # ensure market was either supplied or implied; default if neither.
10748
+ market = self._ValidateMarket(market)
9362
10749
 
9363
10750
  # build spotify web api request parameters.
9364
10751
  urlParms:dict = \
@@ -9373,18 +10760,1203 @@ class SpotifyClient:
9373
10760
  if includeExternal is not None:
9374
10761
  urlParms['include_external'] = includeExternal
9375
10762
 
9376
- # execute spotify web api request.
9377
- msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/search')
9378
- msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
9379
- msg.UrlParameters = urlParms
9380
- self.MakeRequest('GET', msg)
10763
+ # handle pagination, as spotify limits us to a set # of items returned per response.
10764
+ while True:
9381
10765
 
9382
- # process results.
9383
- result = SearchResponse(criteria, criteriaType, root=msg.ResponseData)
10766
+ # execute spotify web api request.
10767
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/search')
10768
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
10769
+ msg.UrlParameters = urlParms
10770
+ self.MakeRequest('GET', msg)
10771
+
10772
+ # process results.
10773
+ searchResponse:SearchResponse = SearchResponse(criteria, criteriaType, root=msg.ResponseData)
10774
+ pageObj = searchResponse.Albums
10775
+
10776
+ # trace.
10777
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
10778
+
10779
+ # was limit total argument specified?
10780
+ if (limitTotal <= 0):
10781
+
10782
+ # no - just return the initial page of results.
10783
+ result = pageObj
10784
+ break
10785
+
10786
+ else:
10787
+
10788
+ # append page of items to final results.
10789
+ item:AlbumSimplified
10790
+ for item in pageObj.Items:
10791
+ result.Items.append(item)
10792
+ result.Limit = result.ItemsCount
10793
+ if result.ItemsCount >= limitTotal:
10794
+ break
10795
+
10796
+ # anymore pages to process? if not, then exit the loop.
10797
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
10798
+ break
10799
+
10800
+ # update result object with final paging details.
10801
+ result.Total = pageObj.Total
10802
+
10803
+ # do not sort, as spotify uses intelligent AI to return results in its order.
9384
10804
 
9385
10805
  # trace.
9386
- _logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
9387
- return result
10806
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
10807
+
10808
+ # return a search response object.
10809
+ response:SearchResponse = SearchResponse(criteria, criteriaType)
10810
+ response.Albums = result
10811
+ return response
10812
+
10813
+ except SpotifyWebApiError: raise # pass handled exceptions on thru
10814
+ except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
10815
+ except Exception as ex:
10816
+
10817
+ # format unhandled exception.
10818
+ raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
10819
+
10820
+ finally:
10821
+
10822
+ # trace.
10823
+ _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
10824
+
10825
+
10826
+ def SearchArtists(self,
10827
+ criteria:str,
10828
+ limit:int=20,
10829
+ offset:int=0,
10830
+ market:str=None,
10831
+ includeExternal:str=None,
10832
+ limitTotal:int=None
10833
+ ) -> SearchResponse:
10834
+ """
10835
+ Get Spotify catalog information about Artists that match a keyword string.
10836
+
10837
+ Args:
10838
+ criteria (str):
10839
+ Your search query.
10840
+ You can narrow down your search using field filters.
10841
+ The available filters are album, artist, track, year, upc, tag:hipster, tag:new,
10842
+ isrc, and genre. Each field filter only applies to certain result types.
10843
+ The artist and year filters can be used while searching albums, artists and tracks.
10844
+ You can filter on a single year or a range (e.g. 1955-1960).
10845
+ The album filter can be used while searching albums and tracks.
10846
+ The genre filter can be used while searching artists and tracks.
10847
+ The isrc and track filters can be used while searching tracks.
10848
+ The upc, tag:new and tag:hipster filters can only be used while searching albums.
10849
+ The tag:new filter will return albums released in the past two weeks and tag:hipster
10850
+ can be used to return only albums with the lowest 10% popularity.
10851
+ limit (int):
10852
+ The maximum number of items to return in a page of items.
10853
+ Default: 20, Range: 1 to 50.
10854
+ offset (int):
10855
+ The page index offset of the first item to return.
10856
+ Use with limit to get the next set of items.
10857
+ Default: 0 (the first item). Range: 0 to 1000.
10858
+ market (str):
10859
+ An ISO 3166-1 alpha-2 country code. If a country code is specified, only content that
10860
+ is available in that market will be returned. If a valid user access token is specified
10861
+ in the request header, the country associated with the user account will take priority over
10862
+ this parameter.
10863
+ Note: If neither market or user country are provided, the content is considered unavailable for the client.
10864
+ Users can view the country that is associated with their account in the account settings.
10865
+ Example: `ES`
10866
+ includeExternal (str):
10867
+ If "audio" is specified it signals that the client can play externally hosted audio content, and
10868
+ marks the content as playable in the response. By default externally hosted audio content is marked
10869
+ as unplayable in the response.
10870
+ Allowed values: "audio"
10871
+ limitTotal (int):
10872
+ The maximum number of items to return for the request.
10873
+ If specified, this argument overrides the limit and offset argument values
10874
+ and paging is automatically used to retrieve all available items up to the
10875
+ maximum number specified.
10876
+ Default: None (disabled)
10877
+
10878
+ Returns:
10879
+ A `SearchResponse` object that contains the search results.
10880
+
10881
+ Raises:
10882
+ SpotifyWebApiError:
10883
+ If the Spotify Web API request was for a non-authorization service
10884
+ and the response contains error information.
10885
+ SpotifApiError:
10886
+ If the method fails for any other reason.
10887
+
10888
+ Note that Spotify Web API automatically limits you to 1,000 max entries per type that can
10889
+ be returned with a search.
10890
+
10891
+ <details>
10892
+ <summary>Sample Code - Manual Paging</summary>
10893
+ ```python
10894
+ .. include:: ../docs/include/samplecode/SpotifyClient/SearchArtists.py
10895
+ ```
10896
+ </details>
10897
+ <details>
10898
+ <summary>Sample Code - Auto Paging</summary>
10899
+ ```python
10900
+ .. include:: ../docs/include/samplecode/SpotifyClient/SearchArtists_AutoPaging.py
10901
+ ```
10902
+ </details>
10903
+ """
10904
+ apiMethodName:str = 'SearchArtists'
10905
+ apiMethodParms:SIMethodParmListContext = None
10906
+ criteriaType:str = 'artist'
10907
+ result:ArtistPage = None
10908
+
10909
+ try:
10910
+
10911
+ # trace.
10912
+ apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
10913
+ apiMethodParms.AppendKeyValue("criteria", criteria)
10914
+ apiMethodParms.AppendKeyValue("criteriaType", criteriaType)
10915
+ apiMethodParms.AppendKeyValue("limit", limit)
10916
+ apiMethodParms.AppendKeyValue("offset", offset)
10917
+ apiMethodParms.AppendKeyValue("market", market)
10918
+ apiMethodParms.AppendKeyValue("includeExternal", includeExternal)
10919
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
10920
+ _logsi.LogMethodParmList(SILevel.Verbose, "Searching Spotify catalog for %s information" % criteriaType, apiMethodParms)
10921
+
10922
+ # validations.
10923
+ if limit is None:
10924
+ limit = 20
10925
+ if offset is None:
10926
+ offset = 0
10927
+ if not isinstance(limitTotal, int):
10928
+ limitTotal = 0
10929
+
10930
+ # are we auto-paging? if so, then use max limit.
10931
+ if limitTotal > 0:
10932
+ limit = 50
10933
+ if limit > limitTotal:
10934
+ limit = limitTotal
10935
+ result = ArtistPage()
10936
+
10937
+ # ensure market was either supplied or implied; default if neither.
10938
+ market = self._ValidateMarket(market)
10939
+
10940
+ # build spotify web api request parameters.
10941
+ urlParms:dict = \
10942
+ {
10943
+ 'q': criteria,
10944
+ 'type': criteriaType,
10945
+ 'limit': limit,
10946
+ 'offset': offset,
10947
+ }
10948
+ if market is not None:
10949
+ urlParms['market'] = market
10950
+ if includeExternal is not None:
10951
+ urlParms['include_external'] = includeExternal
10952
+
10953
+ # handle pagination, as spotify limits us to a set # of items returned per response.
10954
+ while True:
10955
+
10956
+ # execute spotify web api request.
10957
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/search')
10958
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
10959
+ msg.UrlParameters = urlParms
10960
+ self.MakeRequest('GET', msg)
10961
+
10962
+ # process results.
10963
+ searchResponse:SearchResponse = SearchResponse(criteria, criteriaType, root=msg.ResponseData)
10964
+ pageObj = searchResponse.Artists
10965
+
10966
+ # trace.
10967
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
10968
+
10969
+ # was limit total argument specified?
10970
+ if (limitTotal <= 0):
10971
+
10972
+ # no - just return the initial page of results.
10973
+ result = pageObj
10974
+ break
10975
+
10976
+ else:
10977
+
10978
+ # append page of items to final results.
10979
+ item:Artist
10980
+ for item in pageObj.Items:
10981
+ result.Items.append(item)
10982
+ result.Limit = result.ItemsCount
10983
+ if result.ItemsCount >= limitTotal:
10984
+ break
10985
+
10986
+ # anymore pages to process? if not, then exit the loop.
10987
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
10988
+ break
10989
+
10990
+ # update result object with final paging details.
10991
+ result.Total = pageObj.Total
10992
+
10993
+ # do not sort, as spotify uses intelligent AI to return results in its order.
10994
+
10995
+ # trace.
10996
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
10997
+
10998
+ # return a search response object.
10999
+ response:SearchResponse = SearchResponse(criteria, criteriaType)
11000
+ response.Artists = result
11001
+ return response
11002
+
11003
+ except SpotifyWebApiError: raise # pass handled exceptions on thru
11004
+ except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
11005
+ except Exception as ex:
11006
+
11007
+ # format unhandled exception.
11008
+ raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
11009
+
11010
+ finally:
11011
+
11012
+ # trace.
11013
+ _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
11014
+
11015
+
11016
+ def SearchAudiobooks(self,
11017
+ criteria:str,
11018
+ limit:int=20,
11019
+ offset:int=0,
11020
+ market:str=None,
11021
+ includeExternal:str=None,
11022
+ limitTotal:int=None
11023
+ ) -> SearchResponse:
11024
+ """
11025
+ Get Spotify catalog information about Audiobooks that match a keyword string.
11026
+
11027
+ Args:
11028
+ criteria (str):
11029
+ Your search query.
11030
+ You can narrow down your search using field filters.
11031
+ The available filters are album, artist, track, year, upc, tag:hipster, tag:new,
11032
+ isrc, and genre. Each field filter only applies to certain result types.
11033
+ The artist and year filters can be used while searching albums, artists and tracks.
11034
+ You can filter on a single year or a range (e.g. 1955-1960).
11035
+ The album filter can be used while searching albums and tracks.
11036
+ The genre filter can be used while searching artists and tracks.
11037
+ The isrc and track filters can be used while searching tracks.
11038
+ The upc, tag:new and tag:hipster filters can only be used while searching albums.
11039
+ The tag:new filter will return albums released in the past two weeks and tag:hipster
11040
+ can be used to return only albums with the lowest 10% popularity.
11041
+ limit (int):
11042
+ The maximum number of items to return in a page of items.
11043
+ Default: 20, Range: 1 to 50.
11044
+ offset (int):
11045
+ The page index offset of the first item to return.
11046
+ Use with limit to get the next set of items.
11047
+ Default: 0 (the first item). Range: 0 to 1000.
11048
+ market (str):
11049
+ An ISO 3166-1 alpha-2 country code. If a country code is specified, only content that
11050
+ is available in that market will be returned. If a valid user access token is specified
11051
+ in the request header, the country associated with the user account will take priority over
11052
+ this parameter.
11053
+ Note: If neither market or user country are provided, the content is considered unavailable for the client.
11054
+ Users can view the country that is associated with their account in the account settings.
11055
+ Example: `ES`
11056
+ includeExternal (str):
11057
+ If "audio" is specified it signals that the client can play externally hosted audio content, and
11058
+ marks the content as playable in the response. By default externally hosted audio content is marked
11059
+ as unplayable in the response.
11060
+ Allowed values: "audio"
11061
+ limitTotal (int):
11062
+ The maximum number of items to return for the request.
11063
+ If specified, this argument overrides the limit and offset argument values
11064
+ and paging is automatically used to retrieve all available items up to the
11065
+ maximum number specified.
11066
+ Default: None (disabled)
11067
+
11068
+ Returns:
11069
+ A `SearchResponse` object that contains the search results.
11070
+
11071
+ Raises:
11072
+ SpotifyWebApiError:
11073
+ If the Spotify Web API request was for a non-authorization service
11074
+ and the response contains error information.
11075
+ SpotifApiError:
11076
+ If the method fails for any other reason.
11077
+
11078
+ Audiobooks are only available within the US, UK, Canada, Ireland, New Zealand and Australia markets.
11079
+
11080
+ Note that Spotify Web API automatically limits you to 1,000 max entries per type that can
11081
+ be returned with a search.
11082
+
11083
+ <details>
11084
+ <summary>Sample Code - Manual Paging</summary>
11085
+ ```python
11086
+ .. include:: ../docs/include/samplecode/SpotifyClient/SearchAudiobooks.py
11087
+ ```
11088
+ </details>
11089
+ <details>
11090
+ <summary>Sample Code - Auto Paging</summary>
11091
+ ```python
11092
+ .. include:: ../docs/include/samplecode/SpotifyClient/SearchAudiobooks_AutoPaging.py
11093
+ ```
11094
+ </details>
11095
+ """
11096
+ apiMethodName:str = 'SearchAudiobooks'
11097
+ apiMethodParms:SIMethodParmListContext = None
11098
+ criteriaType:str = 'audiobook'
11099
+ result:AudiobookPageSimplified = None
11100
+
11101
+ try:
11102
+
11103
+ # trace.
11104
+ apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
11105
+ apiMethodParms.AppendKeyValue("criteria", criteria)
11106
+ apiMethodParms.AppendKeyValue("criteriaType", criteriaType)
11107
+ apiMethodParms.AppendKeyValue("limit", limit)
11108
+ apiMethodParms.AppendKeyValue("offset", offset)
11109
+ apiMethodParms.AppendKeyValue("market", market)
11110
+ apiMethodParms.AppendKeyValue("includeExternal", includeExternal)
11111
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
11112
+ _logsi.LogMethodParmList(SILevel.Verbose, "Searching Spotify catalog for %s information" % criteriaType, apiMethodParms)
11113
+
11114
+ # validations.
11115
+ if limit is None:
11116
+ limit = 20
11117
+ if offset is None:
11118
+ offset = 0
11119
+ if not isinstance(limitTotal, int):
11120
+ limitTotal = 0
11121
+
11122
+ # are we auto-paging? if so, then use max limit.
11123
+ if limitTotal > 0:
11124
+ limit = 50
11125
+ if limit > limitTotal:
11126
+ limit = limitTotal
11127
+ result = AudiobookPageSimplified()
11128
+
11129
+ # ensure market was either supplied or implied; default if neither.
11130
+ market = self._ValidateMarket(market)
11131
+
11132
+ # build spotify web api request parameters.
11133
+ urlParms:dict = \
11134
+ {
11135
+ 'q': criteria,
11136
+ 'type': criteriaType,
11137
+ 'limit': limit,
11138
+ 'offset': offset,
11139
+ }
11140
+ if market is not None:
11141
+ urlParms['market'] = market
11142
+ if includeExternal is not None:
11143
+ urlParms['include_external'] = includeExternal
11144
+
11145
+ # handle pagination, as spotify limits us to a set # of items returned per response.
11146
+ while True:
11147
+
11148
+ # execute spotify web api request.
11149
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/search')
11150
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
11151
+ msg.UrlParameters = urlParms
11152
+ self.MakeRequest('GET', msg)
11153
+
11154
+ # process results.
11155
+ searchResponse:SearchResponse = SearchResponse(criteria, criteriaType, root=msg.ResponseData)
11156
+ pageObj = searchResponse.Audiobooks
11157
+
11158
+ # trace.
11159
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
11160
+
11161
+ # was limit total argument specified?
11162
+ if (limitTotal <= 0):
11163
+
11164
+ # no - just return the initial page of results.
11165
+ result = pageObj
11166
+ break
11167
+
11168
+ else:
11169
+
11170
+ # append page of items to final results.
11171
+ item:AudiobookSimplified
11172
+ for item in pageObj.Items:
11173
+ result.Items.append(item)
11174
+ result.Limit = result.ItemsCount
11175
+ if result.ItemsCount >= limitTotal:
11176
+ break
11177
+
11178
+ # anymore pages to process? if not, then exit the loop.
11179
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
11180
+ break
11181
+
11182
+ # update result object with final paging details.
11183
+ result.Total = pageObj.Total
11184
+
11185
+ # do not sort, as spotify uses intelligent AI to return results in its order.
11186
+
11187
+ # trace.
11188
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
11189
+
11190
+ # return a search response object.
11191
+ response:SearchResponse = SearchResponse(criteria, criteriaType)
11192
+ response.Audiobooks = result
11193
+ return response
11194
+
11195
+ except SpotifyWebApiError: raise # pass handled exceptions on thru
11196
+ except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
11197
+ except Exception as ex:
11198
+
11199
+ # format unhandled exception.
11200
+ raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
11201
+
11202
+ finally:
11203
+
11204
+ # trace.
11205
+ _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
11206
+
11207
+
11208
+ def SearchEpisodes(self,
11209
+ criteria:str,
11210
+ limit:int=20,
11211
+ offset:int=0,
11212
+ market:str=None,
11213
+ includeExternal:str=None,
11214
+ limitTotal:int=None
11215
+ ) -> SearchResponse:
11216
+ """
11217
+ Get Spotify catalog information about Episodes that match a keyword string.
11218
+
11219
+ Args:
11220
+ criteria (str):
11221
+ Your search query.
11222
+ You can narrow down your search using field filters.
11223
+ The available filters are album, artist, track, year, upc, tag:hipster, tag:new,
11224
+ isrc, and genre. Each field filter only applies to certain result types.
11225
+ The artist and year filters can be used while searching albums, artists and tracks.
11226
+ You can filter on a single year or a range (e.g. 1955-1960).
11227
+ The album filter can be used while searching albums and tracks.
11228
+ The genre filter can be used while searching artists and tracks.
11229
+ The isrc and track filters can be used while searching tracks.
11230
+ The upc, tag:new and tag:hipster filters can only be used while searching albums.
11231
+ The tag:new filter will return albums released in the past two weeks and tag:hipster
11232
+ can be used to return only albums with the lowest 10% popularity.
11233
+ limit (int):
11234
+ The maximum number of items to return in a page of items.
11235
+ Default: 20, Range: 1 to 50.
11236
+ offset (int):
11237
+ The page index offset of the first item to return.
11238
+ Use with limit to get the next set of items.
11239
+ Default: 0 (the first item). Range: 0 to 1000.
11240
+ market (str):
11241
+ An ISO 3166-1 alpha-2 country code. If a country code is specified, only content that
11242
+ is available in that market will be returned. If a valid user access token is specified
11243
+ in the request header, the country associated with the user account will take priority over
11244
+ this parameter.
11245
+ Note: If neither market or user country are provided, the content is considered unavailable for the client.
11246
+ Users can view the country that is associated with their account in the account settings.
11247
+ Example: `ES`
11248
+ includeExternal (str):
11249
+ If "audio" is specified it signals that the client can play externally hosted audio content, and
11250
+ marks the content as playable in the response. By default externally hosted audio content is marked
11251
+ as unplayable in the response.
11252
+ Allowed values: "audio"
11253
+ limitTotal (int):
11254
+ The maximum number of items to return for the request.
11255
+ If specified, this argument overrides the limit and offset argument values
11256
+ and paging is automatically used to retrieve all available items up to the
11257
+ maximum number specified.
11258
+ Default: None (disabled)
11259
+
11260
+ Returns:
11261
+ A `SearchResponse` object that contains the search results.
11262
+
11263
+ Raises:
11264
+ SpotifyWebApiError:
11265
+ If the Spotify Web API request was for a non-authorization service
11266
+ and the response contains error information.
11267
+ SpotifApiError:
11268
+ If the method fails for any other reason.
11269
+
11270
+ Note that Spotify Web API automatically limits you to 1,000 max entries per type that can
11271
+ be returned with a search.
11272
+
11273
+ <details>
11274
+ <summary>Sample Code - Manual Paging</summary>
11275
+ ```python
11276
+ .. include:: ../docs/include/samplecode/SpotifyClient/SearchEpisodes.py
11277
+ ```
11278
+ </details>
11279
+ <details>
11280
+ <summary>Sample Code - Auto Paging</summary>
11281
+ ```python
11282
+ .. include:: ../docs/include/samplecode/SpotifyClient/SearchEpisodes_AutoPaging.py
11283
+ ```
11284
+ </details>
11285
+ """
11286
+ apiMethodName:str = 'SearchEpisodes'
11287
+ apiMethodParms:SIMethodParmListContext = None
11288
+ criteriaType:str = 'episode'
11289
+ result:EpisodePageSimplified = None
11290
+
11291
+ try:
11292
+
11293
+ # trace.
11294
+ apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
11295
+ apiMethodParms.AppendKeyValue("criteria", criteria)
11296
+ apiMethodParms.AppendKeyValue("criteriaType", criteriaType)
11297
+ apiMethodParms.AppendKeyValue("limit", limit)
11298
+ apiMethodParms.AppendKeyValue("offset", offset)
11299
+ apiMethodParms.AppendKeyValue("market", market)
11300
+ apiMethodParms.AppendKeyValue("includeExternal", includeExternal)
11301
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
11302
+ _logsi.LogMethodParmList(SILevel.Verbose, "Searching Spotify catalog for %s information" % criteriaType, apiMethodParms)
11303
+
11304
+ # validations.
11305
+ if limit is None:
11306
+ limit = 20
11307
+ if offset is None:
11308
+ offset = 0
11309
+ if not isinstance(limitTotal, int):
11310
+ limitTotal = 0
11311
+
11312
+ # are we auto-paging? if so, then use max limit.
11313
+ if limitTotal > 0:
11314
+ limit = 50
11315
+ if limit > limitTotal:
11316
+ limit = limitTotal
11317
+ result = EpisodePageSimplified()
11318
+
11319
+ # ensure market was either supplied or implied; default if neither.
11320
+ market = self._ValidateMarket(market)
11321
+
11322
+ # build spotify web api request parameters.
11323
+ urlParms:dict = \
11324
+ {
11325
+ 'q': criteria,
11326
+ 'type': criteriaType,
11327
+ 'limit': limit,
11328
+ 'offset': offset,
11329
+ }
11330
+ if market is not None:
11331
+ urlParms['market'] = market
11332
+ if includeExternal is not None:
11333
+ urlParms['include_external'] = includeExternal
11334
+
11335
+ # handle pagination, as spotify limits us to a set # of items returned per response.
11336
+ while True:
11337
+
11338
+ # execute spotify web api request.
11339
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/search')
11340
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
11341
+ msg.UrlParameters = urlParms
11342
+ self.MakeRequest('GET', msg)
11343
+
11344
+ # process results.
11345
+ searchResponse:SearchResponse = SearchResponse(criteria, criteriaType, root=msg.ResponseData)
11346
+ pageObj = searchResponse.Episodes
11347
+
11348
+ # trace.
11349
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
11350
+
11351
+ # was limit total argument specified?
11352
+ if (limitTotal <= 0):
11353
+
11354
+ # no - just return the initial page of results.
11355
+ result = pageObj
11356
+ break
11357
+
11358
+ else:
11359
+
11360
+ # append page of items to final results.
11361
+ item:EpisodeSimplified
11362
+ for item in pageObj.Items:
11363
+ result.Items.append(item)
11364
+ result.Limit = result.ItemsCount
11365
+ if result.ItemsCount >= limitTotal:
11366
+ break
11367
+
11368
+ # anymore pages to process? if not, then exit the loop.
11369
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
11370
+ break
11371
+
11372
+ # update result object with final paging details.
11373
+ result.Total = pageObj.Total
11374
+
11375
+ # do not sort, as spotify uses intelligent AI to return results in its order.
11376
+
11377
+ # trace.
11378
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
11379
+
11380
+ # return a search response object.
11381
+ response:SearchResponse = SearchResponse(criteria, criteriaType)
11382
+ response.Episodes = result
11383
+ return response
11384
+
11385
+ except SpotifyWebApiError: raise # pass handled exceptions on thru
11386
+ except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
11387
+ except Exception as ex:
11388
+
11389
+ # format unhandled exception.
11390
+ raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
11391
+
11392
+ finally:
11393
+
11394
+ # trace.
11395
+ _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
11396
+
11397
+
11398
+ def SearchPlaylists(self,
11399
+ criteria:str,
11400
+ limit:int=20,
11401
+ offset:int=0,
11402
+ market:str=None,
11403
+ includeExternal:str=None,
11404
+ limitTotal:int=None
11405
+ ) -> SearchResponse:
11406
+ """
11407
+ Get Spotify catalog information about Playlists that match a keyword string.
11408
+
11409
+ Args:
11410
+ criteria (str):
11411
+ Your search query.
11412
+ You can narrow down your search using field filters.
11413
+ The available filters are album, artist, track, year, upc, tag:hipster, tag:new,
11414
+ isrc, and genre. Each field filter only applies to certain result types.
11415
+ The artist and year filters can be used while searching albums, artists and tracks.
11416
+ You can filter on a single year or a range (e.g. 1955-1960).
11417
+ The album filter can be used while searching albums and tracks.
11418
+ The genre filter can be used while searching artists and tracks.
11419
+ The isrc and track filters can be used while searching tracks.
11420
+ The upc, tag:new and tag:hipster filters can only be used while searching albums.
11421
+ The tag:new filter will return albums released in the past two weeks and tag:hipster
11422
+ can be used to return only albums with the lowest 10% popularity.
11423
+ limit (int):
11424
+ The maximum number of items to return in a page of items.
11425
+ Default: 20, Range: 1 to 50.
11426
+ offset (int):
11427
+ The page index offset of the first item to return.
11428
+ Use with limit to get the next set of items.
11429
+ Default: 0 (the first item). Range: 0 to 1000.
11430
+ market (str):
11431
+ An ISO 3166-1 alpha-2 country code. If a country code is specified, only content that
11432
+ is available in that market will be returned. If a valid user access token is specified
11433
+ in the request header, the country associated with the user account will take priority over
11434
+ this parameter.
11435
+ Note: If neither market or user country are provided, the content is considered unavailable for the client.
11436
+ Users can view the country that is associated with their account in the account settings.
11437
+ Example: `ES`
11438
+ includeExternal (str):
11439
+ If "audio" is specified it signals that the client can play externally hosted audio content, and
11440
+ marks the content as playable in the response. By default externally hosted audio content is marked
11441
+ as unplayable in the response.
11442
+ Allowed values: "audio"
11443
+ limitTotal (int):
11444
+ The maximum number of items to return for the request.
11445
+ If specified, this argument overrides the limit and offset argument values
11446
+ and paging is automatically used to retrieve all available items up to the
11447
+ maximum number specified.
11448
+ Default: None (disabled)
11449
+
11450
+ Returns:
11451
+ A `SearchResponse` object that contains the search results.
11452
+
11453
+ Raises:
11454
+ SpotifyWebApiError:
11455
+ If the Spotify Web API request was for a non-authorization service
11456
+ and the response contains error information.
11457
+ SpotifApiError:
11458
+ If the method fails for any other reason.
11459
+
11460
+ Note that Spotify Web API automatically limits you to 1,000 max entries per type that can
11461
+ be returned with a search.
11462
+
11463
+ <details>
11464
+ <summary>Sample Code - Manual Paging</summary>
11465
+ ```python
11466
+ .. include:: ../docs/include/samplecode/SpotifyClient/SearchPlaylists.py
11467
+ ```
11468
+ </details>
11469
+ <details>
11470
+ <summary>Sample Code - Auto Paging</summary>
11471
+ ```python
11472
+ .. include:: ../docs/include/samplecode/SpotifyClient/SearchPlaylists_AutoPaging.py
11473
+ ```
11474
+ </details>
11475
+ <details>
11476
+ <summary>Sample Code - Spotify Generated, Daily Mix</summary>
11477
+ ```python
11478
+ .. include:: ../docs/include/samplecode/SpotifyClient/SearchPlaylists_Spotify_DailyMix.py
11479
+ ```
11480
+ </details>
11481
+ """
11482
+ apiMethodName:str = 'SearchPlaylists'
11483
+ apiMethodParms:SIMethodParmListContext = None
11484
+ criteriaType:str = 'playlist'
11485
+ result:PlaylistPageSimplified = None
11486
+
11487
+ try:
11488
+
11489
+ # trace.
11490
+ apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
11491
+ apiMethodParms.AppendKeyValue("criteria", criteria)
11492
+ apiMethodParms.AppendKeyValue("criteriaType", criteriaType)
11493
+ apiMethodParms.AppendKeyValue("limit", limit)
11494
+ apiMethodParms.AppendKeyValue("offset", offset)
11495
+ apiMethodParms.AppendKeyValue("market", market)
11496
+ apiMethodParms.AppendKeyValue("includeExternal", includeExternal)
11497
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
11498
+ _logsi.LogMethodParmList(SILevel.Verbose, "Searching Spotify catalog for %s information" % criteriaType, apiMethodParms)
11499
+
11500
+ # validations.
11501
+ if limit is None:
11502
+ limit = 20
11503
+ if offset is None:
11504
+ offset = 0
11505
+ if not isinstance(limitTotal, int):
11506
+ limitTotal = 0
11507
+
11508
+ # are we auto-paging? if so, then use max limit.
11509
+ if limitTotal > 0:
11510
+ limit = 50
11511
+ if limit > limitTotal:
11512
+ limit = limitTotal
11513
+ result = PlaylistPageSimplified()
11514
+
11515
+ # ensure market was either supplied or implied; default if neither.
11516
+ market = self._ValidateMarket(market)
11517
+
11518
+ # build spotify web api request parameters.
11519
+ urlParms:dict = \
11520
+ {
11521
+ 'q': criteria,
11522
+ 'type': criteriaType,
11523
+ 'limit': limit,
11524
+ 'offset': offset,
11525
+ }
11526
+ if market is not None:
11527
+ urlParms['market'] = market
11528
+ if includeExternal is not None:
11529
+ urlParms['include_external'] = includeExternal
11530
+
11531
+ # handle pagination, as spotify limits us to a set # of items returned per response.
11532
+ while True:
11533
+
11534
+ # execute spotify web api request.
11535
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/search')
11536
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
11537
+ msg.UrlParameters = urlParms
11538
+ self.MakeRequest('GET', msg)
11539
+
11540
+ # process results.
11541
+ searchResponse:SearchResponse = SearchResponse(criteria, criteriaType, root=msg.ResponseData)
11542
+ pageObj = searchResponse.Playlists
11543
+
11544
+ # trace.
11545
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
11546
+
11547
+ # was limit total argument specified?
11548
+ if (limitTotal <= 0):
11549
+
11550
+ # no - just return the initial page of results.
11551
+ result = pageObj
11552
+ break
11553
+
11554
+ else:
11555
+
11556
+ # append page of items to final results.
11557
+ item:PlaylistSimplified
11558
+ for item in pageObj.Items:
11559
+ result.Items.append(item)
11560
+ result.Limit = result.ItemsCount
11561
+ if result.ItemsCount >= limitTotal:
11562
+ break
11563
+
11564
+ # anymore pages to process? if not, then exit the loop.
11565
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
11566
+ break
11567
+
11568
+ # update result object with final paging details.
11569
+ result.Total = pageObj.Total
11570
+
11571
+ # do not sort, as spotify uses intelligent AI to return results in its order.
11572
+
11573
+ # trace.
11574
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
11575
+
11576
+ # return a search response object.
11577
+ response:SearchResponse = SearchResponse(criteria, criteriaType)
11578
+ response.Playlists = result
11579
+ return response
11580
+
11581
+ except SpotifyWebApiError: raise # pass handled exceptions on thru
11582
+ except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
11583
+ except Exception as ex:
11584
+
11585
+ # format unhandled exception.
11586
+ raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
11587
+
11588
+ finally:
11589
+
11590
+ # trace.
11591
+ _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
11592
+
11593
+
11594
+ def SearchShows(self,
11595
+ criteria:str,
11596
+ limit:int=20,
11597
+ offset:int=0,
11598
+ market:str=None,
11599
+ includeExternal:str=None,
11600
+ limitTotal:int=None
11601
+ ) -> SearchResponse:
11602
+ """
11603
+ Get Spotify catalog information about Shows that match a keyword string.
11604
+
11605
+ Args:
11606
+ criteria (str):
11607
+ Your search query.
11608
+ You can narrow down your search using field filters.
11609
+ The available filters are album, artist, track, year, upc, tag:hipster, tag:new,
11610
+ isrc, and genre. Each field filter only applies to certain result types.
11611
+ The artist and year filters can be used while searching albums, artists and tracks.
11612
+ You can filter on a single year or a range (e.g. 1955-1960).
11613
+ The album filter can be used while searching albums and tracks.
11614
+ The genre filter can be used while searching artists and tracks.
11615
+ The isrc and track filters can be used while searching tracks.
11616
+ The upc, tag:new and tag:hipster filters can only be used while searching albums.
11617
+ The tag:new filter will return albums released in the past two weeks and tag:hipster
11618
+ can be used to return only albums with the lowest 10% popularity.
11619
+ limit (int):
11620
+ The maximum number of items to return in a page of items.
11621
+ Default: 20, Range: 1 to 50.
11622
+ offset (int):
11623
+ The page index offset of the first item to return.
11624
+ Use with limit to get the next set of items.
11625
+ Default: 0 (the first item). Range: 0 to 1000.
11626
+ market (str):
11627
+ An ISO 3166-1 alpha-2 country code. If a country code is specified, only content that
11628
+ is available in that market will be returned. If a valid user access token is specified
11629
+ in the request header, the country associated with the user account will take priority over
11630
+ this parameter.
11631
+ Note: If neither market or user country are provided, the content is considered unavailable for the client.
11632
+ Users can view the country that is associated with their account in the account settings.
11633
+ Example: `ES`
11634
+ includeExternal (str):
11635
+ If "audio" is specified it signals that the client can play externally hosted audio content, and
11636
+ marks the content as playable in the response. By default externally hosted audio content is marked
11637
+ as unplayable in the response.
11638
+ Allowed values: "audio"
11639
+ limitTotal (int):
11640
+ The maximum number of items to return for the request.
11641
+ If specified, this argument overrides the limit and offset argument values
11642
+ and paging is automatically used to retrieve all available items up to the
11643
+ maximum number specified.
11644
+ Default: None (disabled)
11645
+
11646
+ Returns:
11647
+ A `SearchResponse` object that contains the search results.
11648
+
11649
+ Raises:
11650
+ SpotifyWebApiError:
11651
+ If the Spotify Web API request was for a non-authorization service
11652
+ and the response contains error information.
11653
+ SpotifApiError:
11654
+ If the method fails for any other reason.
11655
+
11656
+ Note that Spotify Web API automatically limits you to 1,000 max entries per type that can
11657
+ be returned with a search.
11658
+
11659
+ <details>
11660
+ <summary>Sample Code - Manual Paging</summary>
11661
+ ```python
11662
+ .. include:: ../docs/include/samplecode/SpotifyClient/SearchShows.py
11663
+ ```
11664
+ </details>
11665
+ <details>
11666
+ <summary>Sample Code - Auto Paging</summary>
11667
+ ```python
11668
+ .. include:: ../docs/include/samplecode/SpotifyClient/SearchShows_AutoPaging.py
11669
+ ```
11670
+ </details>
11671
+ """
11672
+ apiMethodName:str = 'SearchShows'
11673
+ apiMethodParms:SIMethodParmListContext = None
11674
+ criteriaType:str = 'show'
11675
+ result:ShowPageSimplified = None
11676
+
11677
+ try:
11678
+
11679
+ # trace.
11680
+ apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
11681
+ apiMethodParms.AppendKeyValue("criteria", criteria)
11682
+ apiMethodParms.AppendKeyValue("criteriaType", criteriaType)
11683
+ apiMethodParms.AppendKeyValue("limit", limit)
11684
+ apiMethodParms.AppendKeyValue("offset", offset)
11685
+ apiMethodParms.AppendKeyValue("market", market)
11686
+ apiMethodParms.AppendKeyValue("includeExternal", includeExternal)
11687
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
11688
+ _logsi.LogMethodParmList(SILevel.Verbose, "Searching Spotify catalog for %s information" % criteriaType, apiMethodParms)
11689
+
11690
+ # validations.
11691
+ if limit is None:
11692
+ limit = 20
11693
+ if offset is None:
11694
+ offset = 0
11695
+ if not isinstance(limitTotal, int):
11696
+ limitTotal = 0
11697
+
11698
+ # are we auto-paging? if so, then use max limit.
11699
+ if limitTotal > 0:
11700
+ limit = 50
11701
+ if limit > limitTotal:
11702
+ limit = limitTotal
11703
+ result = ShowPageSimplified()
11704
+
11705
+ # ensure market was either supplied or implied; default if neither.
11706
+ market = self._ValidateMarket(market)
11707
+
11708
+ # build spotify web api request parameters.
11709
+ urlParms:dict = \
11710
+ {
11711
+ 'q': criteria,
11712
+ 'type': criteriaType,
11713
+ 'limit': limit,
11714
+ 'offset': offset,
11715
+ }
11716
+ if market is not None:
11717
+ urlParms['market'] = market
11718
+ if includeExternal is not None:
11719
+ urlParms['include_external'] = includeExternal
11720
+
11721
+ # handle pagination, as spotify limits us to a set # of items returned per response.
11722
+ while True:
11723
+
11724
+ # execute spotify web api request.
11725
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/search')
11726
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
11727
+ msg.UrlParameters = urlParms
11728
+ self.MakeRequest('GET', msg)
11729
+
11730
+ # process results.
11731
+ searchResponse:SearchResponse = SearchResponse(criteria, criteriaType, root=msg.ResponseData)
11732
+ pageObj = searchResponse.Shows
11733
+
11734
+ # trace.
11735
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
11736
+
11737
+ # was limit total argument specified?
11738
+ if (limitTotal <= 0):
11739
+
11740
+ # no - just return the initial page of results.
11741
+ result = pageObj
11742
+ break
11743
+
11744
+ else:
11745
+
11746
+ # append page of items to final results.
11747
+ item:ShowSimplified
11748
+ for item in pageObj.Items:
11749
+ result.Items.append(item)
11750
+ result.Limit = result.ItemsCount
11751
+ if result.ItemsCount >= limitTotal:
11752
+ break
11753
+
11754
+ # anymore pages to process? if not, then exit the loop.
11755
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
11756
+ break
11757
+
11758
+ # update result object with final paging details.
11759
+ result.Total = pageObj.Total
11760
+
11761
+ # do not sort, as spotify uses intelligent AI to return results in its order.
11762
+
11763
+ # trace.
11764
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
11765
+
11766
+ # return a search response object.
11767
+ response:SearchResponse = SearchResponse(criteria, criteriaType)
11768
+ response.Shows = result
11769
+ return response
11770
+
11771
+ except SpotifyWebApiError: raise # pass handled exceptions on thru
11772
+ except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
11773
+ except Exception as ex:
11774
+
11775
+ # format unhandled exception.
11776
+ raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
11777
+
11778
+ finally:
11779
+
11780
+ # trace.
11781
+ _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
11782
+
11783
+
11784
+ def SearchTracks(self,
11785
+ criteria:str,
11786
+ limit:int=20,
11787
+ offset:int=0,
11788
+ market:str=None,
11789
+ includeExternal:str=None,
11790
+ limitTotal:int=None
11791
+ ) -> SearchResponse:
11792
+ """
11793
+ Get Spotify catalog information about Tracks that match a keyword string.
11794
+
11795
+ Args:
11796
+ criteria (str):
11797
+ Your search query.
11798
+ You can narrow down your search using field filters.
11799
+ The available filters are album, artist, track, year, upc, tag:hipster, tag:new,
11800
+ isrc, and genre. Each field filter only applies to certain result types.
11801
+ The artist and year filters can be used while searching albums, artists and tracks.
11802
+ You can filter on a single year or a range (e.g. 1955-1960).
11803
+ The album filter can be used while searching albums and tracks.
11804
+ The genre filter can be used while searching artists and tracks.
11805
+ The isrc and track filters can be used while searching tracks.
11806
+ The upc, tag:new and tag:hipster filters can only be used while searching albums.
11807
+ The tag:new filter will return albums released in the past two weeks and tag:hipster
11808
+ can be used to return only albums with the lowest 10% popularity.
11809
+ limit (int):
11810
+ The maximum number of items to return in a page of items.
11811
+ Default: 20, Range: 1 to 50.
11812
+ offset (int):
11813
+ The page index offset of the first item to return.
11814
+ Use with limit to get the next set of items.
11815
+ Default: 0 (the first item). Range: 0 to 1000.
11816
+ market (str):
11817
+ An ISO 3166-1 alpha-2 country code. If a country code is specified, only content that
11818
+ is available in that market will be returned. If a valid user access token is specified
11819
+ in the request header, the country associated with the user account will take priority over
11820
+ this parameter.
11821
+ Note: If neither market or user country are provided, the content is considered unavailable for the client.
11822
+ Users can view the country that is associated with their account in the account settings.
11823
+ Example: `ES`
11824
+ includeExternal (str):
11825
+ If "audio" is specified it signals that the client can play externally hosted audio content, and
11826
+ marks the content as playable in the response. By default externally hosted audio content is marked
11827
+ as unplayable in the response.
11828
+ Allowed values: "audio"
11829
+ limitTotal (int):
11830
+ The maximum number of items to return for the request.
11831
+ If specified, this argument overrides the limit and offset argument values
11832
+ and paging is automatically used to retrieve all available items up to the
11833
+ maximum number specified.
11834
+ Default: None (disabled)
11835
+
11836
+ Returns:
11837
+ A `SearchResponse` object that contains the search results.
11838
+
11839
+ Raises:
11840
+ SpotifyWebApiError:
11841
+ If the Spotify Web API request was for a non-authorization service
11842
+ and the response contains error information.
11843
+ SpotifApiError:
11844
+ If the method fails for any other reason.
11845
+
11846
+ Note that Spotify Web API automatically limits you to 1,000 max entries per type that can
11847
+ be returned with a search.
11848
+
11849
+ <details>
11850
+ <summary>Sample Code - Manual Paging</summary>
11851
+ ```python
11852
+ .. include:: ../docs/include/samplecode/SpotifyClient/SearchTracks.py
11853
+ ```
11854
+ </details>
11855
+ <details>
11856
+ <summary>Sample Code - Auto Paging</summary>
11857
+ ```python
11858
+ .. include:: ../docs/include/samplecode/SpotifyClient/SearchTracks_AutoPaging.py
11859
+ ```
11860
+ </details>
11861
+ """
11862
+ apiMethodName:str = 'SearchTracks'
11863
+ apiMethodParms:SIMethodParmListContext = None
11864
+ criteriaType:str = 'track'
11865
+ result:TrackPage = None
11866
+
11867
+ try:
11868
+
11869
+ # trace.
11870
+ apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
11871
+ apiMethodParms.AppendKeyValue("criteria", criteria)
11872
+ apiMethodParms.AppendKeyValue("criteriaType", criteriaType)
11873
+ apiMethodParms.AppendKeyValue("limit", limit)
11874
+ apiMethodParms.AppendKeyValue("offset", offset)
11875
+ apiMethodParms.AppendKeyValue("market", market)
11876
+ apiMethodParms.AppendKeyValue("includeExternal", includeExternal)
11877
+ apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
11878
+ _logsi.LogMethodParmList(SILevel.Verbose, "Searching Spotify catalog for %s information" % criteriaType, apiMethodParms)
11879
+
11880
+ # validations.
11881
+ if limit is None:
11882
+ limit = 20
11883
+ if offset is None:
11884
+ offset = 0
11885
+ if not isinstance(limitTotal, int):
11886
+ limitTotal = 0
11887
+
11888
+ # are we auto-paging? if so, then use max limit.
11889
+ if limitTotal > 0:
11890
+ limit = 50
11891
+ if limit > limitTotal:
11892
+ limit = limitTotal
11893
+ result = TrackPage()
11894
+
11895
+ # ensure market was either supplied or implied; default if neither.
11896
+ market = self._ValidateMarket(market)
11897
+
11898
+ # build spotify web api request parameters.
11899
+ urlParms:dict = \
11900
+ {
11901
+ 'q': criteria,
11902
+ 'type': criteriaType,
11903
+ 'limit': limit,
11904
+ 'offset': offset,
11905
+ }
11906
+ if market is not None:
11907
+ urlParms['market'] = market
11908
+ if includeExternal is not None:
11909
+ urlParms['include_external'] = includeExternal
11910
+
11911
+ # handle pagination, as spotify limits us to a set # of items returned per response.
11912
+ while True:
11913
+
11914
+ # execute spotify web api request.
11915
+ msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/search')
11916
+ msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
11917
+ msg.UrlParameters = urlParms
11918
+ self.MakeRequest('GET', msg)
11919
+
11920
+ # process results.
11921
+ searchResponse:SearchResponse = SearchResponse(criteria, criteriaType, root=msg.ResponseData)
11922
+ pageObj = searchResponse.Tracks
11923
+
11924
+ # trace.
11925
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE_PAGE + pageObj.PagingInfo) % (apiMethodName, type(pageObj).__name__), pageObj, excludeNonPublic=True)
11926
+
11927
+ # was limit total argument specified?
11928
+ if (limitTotal <= 0):
11929
+
11930
+ # no - just return the initial page of results.
11931
+ result = pageObj
11932
+ break
11933
+
11934
+ else:
11935
+
11936
+ # append page of items to final results.
11937
+ item:Track
11938
+ for item in pageObj.Items:
11939
+ result.Items.append(item)
11940
+ result.Limit = result.ItemsCount
11941
+ if result.ItemsCount >= limitTotal:
11942
+ break
11943
+
11944
+ # anymore pages to process? if not, then exit the loop.
11945
+ if not self._CheckForNextPage(pageObj, result.ItemsCount, limit, limitTotal, urlParms):
11946
+ break
11947
+
11948
+ # update result object with final paging details.
11949
+ result.Total = pageObj.Total
11950
+
11951
+ # do not sort, as spotify uses intelligent AI to return results in its order.
11952
+
11953
+ # trace.
11954
+ _logsi.LogObject(SILevel.Verbose, (TRACE_METHOD_RESULT_TYPE + result.PagingInfo) % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
11955
+
11956
+ # return a search response object.
11957
+ response:SearchResponse = SearchResponse(criteria, criteriaType)
11958
+ response.Tracks = result
11959
+ return response
9388
11960
 
9389
11961
  except SpotifyWebApiError: raise # pass handled exceptions on thru
9390
11962
  except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
@@ -9817,14 +12389,16 @@ class SpotifyClient:
9817
12389
 
9818
12390
  # note that we cannot retrieve spotify user basic details, as the client credentials
9819
12391
  # authentication type does not utilize an authorization token. in this case, we will
9820
- # build a "public access" user profile, just so we have something there.
12392
+ # build a "public access" user profile, just so we have something there.
12393
+ #
12394
+ # also note that we do not set a value for Country, as some endpoints require a country
12395
+ # (or market) code in order to work properly (e.g. any of the Search... methods).
9821
12396
  userProfile:UserProfile = UserProfile()
9822
12397
  userProfile._DisplayName = 'Public Access'
9823
12398
  userProfile._Followers = Followers()
9824
12399
  userProfile._Followers._Total = 0
9825
12400
  userProfile._Id = 'unknown'
9826
12401
  userProfile._Uri = 'spotify.user.' + userProfile._Id
9827
- userProfile._Country = 'unknown'
9828
12402
  self._UserProfile = userProfile
9829
12403
 
9830
12404
  # trace.