@@ -360,6 +360,40 @@ def _loadData(self, data):
360360 # Private attrs as we dont want a reload.
361361 self ._total_size = None
362362
363+ def fetchItems (self , ekey , cls = None , container_start = None , container_size = None , ** kwargs ):
364+ """ Load the specified key to find and build all items with the specified tag
365+ and attrs. See :func:`~plexapi.base.PlexObject.fetchItem` for more details
366+ on how this is used.
367+
368+ Parameters:
369+ container_start (None, int): offset to get a subset of the data
370+ container_size (None, int): How many items in data
371+
372+ """
373+ url_kw = {}
374+ if container_start is not None :
375+ url_kw ["X-Plex-Container-Start" ] = container_start
376+ if container_size is not None :
377+ url_kw ["X-Plex-Container-Size" ] = container_size
378+
379+ if ekey is None :
380+ raise BadRequest ('ekey was not provided' )
381+ data = self ._server .query (ekey , params = url_kw )
382+
383+ if '/all' in ekey :
384+ # totalSize is only included in the xml response
385+ # if container size is used.
386+ total_size = data .attrib .get ("totalSize" ) or data .attrib .get ("size" )
387+ self ._total_size = utils .cast (int , total_size )
388+
389+ items = self .findItems (data , cls , ekey , ** kwargs )
390+
391+ librarySectionID = data .attrib .get ('librarySectionID' )
392+ if librarySectionID :
393+ for item in items :
394+ item .librarySectionID = librarySectionID
395+ return items
396+
363397 @property
364398 def totalSize (self ):
365399 if self ._total_size is None :
@@ -505,9 +539,9 @@ def listChoices(self, category, libtype=None, **kwargs):
505539 key = '/library/sections/%s/%s%s' % (self .key , category , utils .joinArgs (args ))
506540 return self .fetchItems (key , cls = FilterChoice )
507541
508- def search (self , title = None , sort = None , maxresults = 999999 , libtype = None , ** kwargs ):
509- """ Search the library. If there are many results, they will be fetched from the server
510- in batches of X_PLEX_CONTAINER_SIZE amounts . If you're only looking for the first <num>
542+ def search (self , title = None , sort = None , maxresults = None ,
543+ libtype = None , container_start = 0 , container_size = X_PLEX_CONTAINER_SIZE , ** kwargs ):
544+ """ Search the library. The http requests will be batched in container_size . If you're only looking for the first <num>
511545 results, it would be wise to set the maxresults option to that amount so this functions
512546 doesn't iterate over all results on the server.
513547
@@ -518,6 +552,8 @@ def search(self, title=None, sort=None, maxresults=999999, libtype=None, **kwarg
518552 maxresults (int): Only return the specified number of results (optional).
519553 libtype (str): Filter results to a spcifiec libtype (movie, show, episode, artist,
520554 album, track; optional).
555+ container_start (int): default 0
556+ container_size (int): default X_PLEX_CONTAINER_SIZE in your config file.
521557 **kwargs (dict): Any of the available filters for the current library section. Partial string
522558 matches allowed. Multiple matches OR together. Negative filtering also possible, just add an
523559 exclamation mark to the end of filter name, e.g. `resolution!=1x1`.
@@ -549,15 +585,37 @@ def search(self, title=None, sort=None, maxresults=999999, libtype=None, **kwarg
549585 args ['sort' ] = self ._cleanSearchSort (sort )
550586 if libtype is not None :
551587 args ['type' ] = utils .searchType (libtype )
552- # iterate over the results
553- results , subresults = [], '_init'
554- args ['X-Plex-Container-Start' ] = 0
555- args ['X-Plex-Container-Size' ] = min (X_PLEX_CONTAINER_SIZE , maxresults )
556- while subresults and maxresults > len (results ):
588+
589+ results = []
590+ subresults = []
591+ offset = container_start
592+
593+ if maxresults is not None :
594+ container_size = min (container_size , maxresults )
595+ while True :
557596 key = '/library/sections/%s/all%s' % (self .key , utils .joinArgs (args ))
558- subresults = self .fetchItems (key )
559- results += subresults [:maxresults - len (results )]
560- args ['X-Plex-Container-Start' ] += args ['X-Plex-Container-Size' ]
597+ subresults = self .fetchItems (key , container_start = container_start ,
598+ container_size = container_size )
599+ if not len (subresults ):
600+ if offset > self .totalSize :
601+ log .info ("container_start is higher then the number of items in the library" )
602+ break
603+
604+ results .extend (subresults )
605+
606+ # self.totalSize is not used as a condition in the while loop as
607+ # this require a additional http request.
608+ # self.totalSize is updated from .fetchItems
609+ wanted_number_of_items = self .totalSize - offset
610+ if maxresults is not None :
611+ wanted_number_of_items = min (maxresults , wanted_number_of_items )
612+ container_size = min (container_size , maxresults - len (results ))
613+
614+ if wanted_number_of_items <= len (results ):
615+ break
616+
617+ container_start += container_size
618+
561619 return results
562620
563621 def _cleanSearchFilter (self , category , value , libtype = None ):
0 commit comments