Repository: Flexget/Flexget

Issue:
AniList plugin only loads the first page
### Expected behaviour:

Using the AniList plugin on my account (`username: Kazakuri`) should create 840 entries with completed status

### Actual behaviour:

It creates 50 entries.

### Steps to reproduce:

1. Use the AniList input plugin with an account that has more than 50 entries of a given status.
2. Observe results.

#### Config:
```yaml
    tasks:
  example:
    anilist:
      username: kazakuri
      status:
        - completed
      release_status:
        - finished
```
  
#### Log:
<details>
 <summary>(click to expand)</summary>

```
2019-10-26 23:09 VERBOSE  input_cache   example          Restored entries from cache
2019-10-26 23:09 VERBOSE  details       example          Produced 50 entries.
2019-10-26 23:09 WARNING  task          example          Task does not have any filter plugins to accept entries. You need at least one to accept the entries you  want.
2019-10-26 23:09 VERBOSE  details       example          Summary - Accepted: 0 (Rejected: 0 Undecided: 50 Failed: 0)
2019-10-26 23:09 WARNING  task          example          Task doesn't have any output plugins, you should add (at least) one!
```
</details>

### Additional information:

- FlexGet version: 2.21.32
- Python version: 3.7.5
- Installation method: pip
- Using daemon (yes/no): no
- OS and version: Alpine Linux 3.10

The [query being built](https://github.com/Flexget/Flexget/blob/ea11cdccce95c6513d8be9978bdd9d0baeb88b7b/flexget/plugins/input/anilist.py#L96) wraps the `MediaList` type with the `Page` type, but by design the `Page` type limits the response to 50 entries.

### Possible Solutions 

#### Querying Each Page

You can query the number of pages in the same query and use that to iterate over all the available pages in a loop.

#### Using MediaListCollection and Querying Each Chunk

Instead of using `Page` With `MediaList`, you can query with `MediaListCollection` instead to retrieve up to 500 entries per chunk.




Discussion:

Resolving patch:
diff --git a/flexget/plugins/input/anilist.py b/flexget/plugins/input/anilist.py
--- a/flexget/plugins/input/anilist.py
+++ b/flexget/plugins/input/anilist.py
@@ -67,7 +67,6 @@ class AniList(object):
 
     @cached('anilist', persist='2 hours')
     def on_task_input(self, task, config):
-        entries = []
         if isinstance(config, str):
             config = {'username': config}
         selected_list_status = config['status'] if 'status' in config else ['current', 'planning']
@@ -83,66 +82,66 @@ def on_task_input(self, task, config):
         if not isinstance(selected_formats, list):
             selected_formats = [selected_formats]
 
-        log.debug('selected_list_status: %s' % selected_list_status)
-        log.debug('selected_release_status: %s' % selected_release_status)
-        log.debug('selected_formats: %s' % selected_formats)
+        log.debug('Selected List Status: %s' % selected_list_status)
+        log.debug('Selected Release Status: %s' % selected_release_status)
+        log.debug('Selected Formats: %s' % selected_formats)
 
-        req_query = ('fragment aniList on MediaList{ media{ status, title{ romaji, english }, synonyms, siteUrl, '
-                    'idMal, format, episodes, trailer{ site, id }, coverImage{ large }, bannerImage, genres, '
-                    'tags{ name }, externalLinks{ site, url }}} query ($user: String){')
         req_variables = {'user': config['username']}
-
-        for s in selected_list_status:
-            req_query += ('%s: Page {mediaList(userName: $user, type: ANIME, status: %s) {...aniList}}' % (
-                s.capitalize(), s.upper()))
-        req_query += '}'
-
-        try:
-            list_response = task.requests.post(
-                'https://graphql.anilist.co', json={'query': req_query, 'variables': req_variables}
-            )
-        except RequestException as e:
-            raise plugin.PluginError('Error reading list - {url}'.format(url=e))
-
-        try:
-            list_json = list_response.json()['data']
-        except ValueError:
-            raise plugin.PluginError('Invalid JSON response')
-
-        log.debug('JSON output: %s' % list_json)
-        for list_status in list_json:
-            for anime in list_json[list_status]['mediaList']:
-                anime = anime['media']
-                has_selected_release_status = (
-                    anime['status'].lower() in selected_release_status
-                    or 'all' in selected_release_status
-                )
-                has_selected_type = (
-                    anime['format'].lower() in selected_formats
-                    or 'all' in selected_formats
+        req_chunk = 1
+        req_fields = ('status, title{ romaji, english }, synonyms, siteUrl, idMal, format, episodes, '
+                    'trailer{ site, id }, coverImage{ large }, bannerImage, genres, tags{ name }, '
+                    'externalLinks{ site, url }')
+        while req_chunk:
+            req_query = ('query ($user: String){collection: MediaListCollection(userName: $user, type: ANIME, '
+                        'perChunk: 500, chunk: %s, status_in: [%s]){ hasNextChunk, statuses: lists { list: entries { '
+                        'anime: media { %s }}}}}' % (req_chunk, ', '.join([s.upper() for s in selected_list_status]), 
+                        req_fields))
+
+            try:
+                list_response = task.requests.post(
+                    'https://graphql.anilist.co', json={'query': req_query, 'variables': req_variables}
                 )
-                if has_selected_type and has_selected_release_status:
-                    entries.append(
-                        Entry(
-                            title = anime['title']['romaji'],
-                            alternate_name = [anime['title']['english']] + anime['synonyms'],
-                            url = anime['siteUrl'],
-                            al_release_status = anime['status'].capitalize(),
-                            al_list_status = list_status,
-                            al_idMal = anime['idMal'],
-                            al_format = anime['format'],
-                            al_episodes = anime['episodes'],
-                            al_trailer = (TRAILER_SOURCE[anime['trailer']['site']]
-                                + anime['trailer']['id'] if anime['trailer'] else ''),
-                            al_cover = anime['coverImage']['large'],
-                            al_banner = anime['bannerImage'],
-                            al_genres = anime['genres'],
-                            al_tags = [t['name'] for t in anime['tags']],
-                            al_title = anime['title'],
-                            al_links = anime['externalLinks']
+            except RequestException as e:
+                raise plugin.PluginError('Error reading list - {url}'.format(url=e))
+
+            try:
+                list_response = list_response.json()['data']
+                log.debug('JSON output: %s' % list_response)
+                for list_status in list_response['collection']['statuses']:
+                    for anime in list_status['list']:
+                        anime = anime['anime']
+                        has_selected_release_status = (
+                            anime['status'].lower() in selected_release_status
+                            or 'all' in selected_release_status
                         )
-                    )
-        return entries
+                        has_selected_type = (
+                            anime['format'].lower() in selected_formats
+                            or 'all' in selected_formats
+                        )
+                        if has_selected_type and has_selected_release_status:
+                            entry = Entry()
+                            entry['title'] = anime['title']['romaji']
+                            entry['al_title'] = anime['title']
+                            entry['al_format'] = anime['format']
+                            entry['al_release_status'] = anime['status'].capitalize()
+                            entry['al_list_status'] = list_status
+                            entry['alternate_name'] = [anime['title']['english']] + anime['synonyms']
+                            entry['url'] = anime['siteUrl']
+                            entry['al_idMal'] = anime['idMal']
+                            entry['al_episodes'] = anime['episodes']
+                            entry['al_trailer'] = (TRAILER_SOURCE[anime['trailer']['site']]
+                                + anime['trailer']['id'] if anime['trailer'] else '')
+                            entry['al_cover'] = anime['coverImage']['large']
+                            entry['al_banner'] = anime['bannerImage']
+                            entry['al_genres'] = anime['genres']
+                            entry['al_tags'] = [t['name'] for t in anime['tags']]
+                            entry['al_links'] = anime['externalLinks']
+                            if entry.isvalid():
+                                yield entry
+                req_chunk = req_chunk + 1 if list_response['collection']['hasNextChunk'] else False
+
+            except ValueError:
+                raise plugin.PluginError('Invalid JSON response')
 
 
 @event('plugin.register')


Test patch: