We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Anilist plugin crashes when relations.yuna.moe is unreachable
```
2022-02-16 05:42:37 DEBUG    utils.requests anime           POSTing URL https://relations.yuna.moe/api/ids with args () and kwargs {'data': None, 'json': {'anilist': 114099}, 'timeout': 30}
2022-02-16 05:42:38 VERBOSE  anilist       anime           Couldn't fetch additional IDs: 502 Server Error: Bad Gateway for url: https://relations.yuna.moe/api/ids
2022-02-16 05:42:38 CRITICAL task          anime           BUG: Unhandled error in plugin configure_series: local variable 'ids' referenced before assignment
(...)
UnboundLocalError: local variable 'ids' referenced before assignment
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/flexget/task.py", line 547, in __run_plugin
    result = method(*args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/flexget/event.py", line 20, in __call__
    return self.func(*args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/flexget/components/series/configure_series.py", line 61, in on_task_prepare
    for entry in result:
  File "/usr/local/lib/python3.10/site-packages/flexget/utils/cached_input.py", line 231, in __iter__
    for item in self.iterable:
  File "/usr/local/lib/python3.10/site-packages/flexget/plugins/input/anilist.py", line 155, in on_task_input
    if not ids or not isinstance(ids, dict):
UnboundLocalError: local variable 'ids' referenced before assignment
```
Anilist plugin crashes when relations.yuna.moe is unreachable
```
2022-02-16 05:42:37 DEBUG    utils.requests anime           POSTing URL https://relations.yuna.moe/api/ids with args () and kwargs {'data': None, 'json': {'anilist': 114099}, 'timeout': 30}
2022-02-16 05:42:38 VERBOSE  anilist       anime           Couldn't fetch additional IDs: 502 Server Error: Bad Gateway for url: https://relations.yuna.moe/api/ids
2022-02-16 05:42:38 CRITICAL task          anime           BUG: Unhandled error in plugin configure_series: local variable 'ids' referenced before assignment
(...)
UnboundLocalError: local variable 'ids' referenced before assignment
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/flexget/task.py", line 547, in __run_plugin
    result = method(*args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/flexget/event.py", line 20, in __call__
    return self.func(*args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/flexget/components/series/configure_series.py", line 61, in on_task_prepare
    for entry in result:
  File "/usr/local/lib/python3.10/site-packages/flexget/utils/cached_input.py", line 231, in __iter__
    for item in self.iterable:
  File "/usr/local/lib/python3.10/site-packages/flexget/plugins/input/anilist.py", line 155, in on_task_input
    if not ids or not isinstance(ids, dict):
UnboundLocalError: local variable 'ids' referenced before assignment
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `flexget/plugins/input/anilist.py`
Content:
```
1 from datetime import datetime
2 
3 from loguru import logger
4 
5 from flexget import plugin
6 from flexget.config_schema import one_or_more
7 from flexget.entry import Entry
8 from flexget.event import event
9 from flexget.utils.cached_input import cached
10 from flexget.utils.requests import RequestException
11 
12 logger = logger.bind(name='anilist')
13 
14 LIST_STATUS = ['current', 'planning', 'completed', 'dropped', 'paused', 'repeating']
15 
16 RELEASE_STATUS = ['finished', 'releasing', 'not_yet_released', 'cancelled', 'all']
17 
18 ANIME_FORMAT = ['tv', 'tv_short', 'movie', 'special', 'ova', 'ona', 'all']
19 
20 TRAILER_SOURCE = {
21     'youtube': 'https://www.youtube.com/embed/',
22     'dailymotion': 'https://www.dailymotion.com/embed/video/',
23 }
24 
25 
26 class AniList(object):
27     """ " Creates entries for series and movies from your AniList list
28 
29     Syntax:
30     anilist:
31       username: <string>
32       status:
33         - <current|planning|completed|dropped|paused|repeating>
34         - <current|planning|completed|dropped|paused|repeating>
35         ...
36       release_status:
37         - <all|finished|releasing|not_yet_released|cancelled>
38         - <finished|releasing|not_yet_released|cancelled>
39         ...
40       format:
41         - <all|tv|tv_short|movie|special|ova|ona>
42         - <tv|tv_short|movie|special|ova|ona>
43         ...
44       list:
45         - <string>
46         - <string>
47         ...
48     """
49 
50     schema = {
51         'oneOf': [
52             {'type': 'string'},
53             {
54                 'type': 'object',
55                 'properties': {
56                     'username': {'type': 'string'},
57                     'status': one_or_more(
58                         {'type': 'string', 'enum': LIST_STATUS}, unique_items=True
59                     ),
60                     'release_status': one_or_more(
61                         {'type': 'string', 'enum': RELEASE_STATUS}, unique_items=True
62                     ),
63                     'format': one_or_more(
64                         {'type': 'string', 'enum': ANIME_FORMAT}, unique_items=True
65                     ),
66                     'list': one_or_more({'type': 'string'}),
67                 },
68                 'required': ['username'],
69                 'additionalProperties': False,
70             },
71         ]
72     }
73 
74     @cached('anilist', persist='2 hours')
75     def on_task_input(self, task, config):
76         if isinstance(config, str):
77             config = {'username': config}
78         selected_list_status = config.get('status', ['current', 'planning'])
79         selected_release_status = config.get('release_status', ['all'])
80         selected_formats = config.get('format', ['all'])
81         selected_list_name = config.get('list', [])
82 
83         if not isinstance(selected_list_status, list):
84             selected_list_status = [selected_list_status]
85 
86         if not isinstance(selected_release_status, list):
87             selected_release_status = [selected_release_status]
88 
89         if not isinstance(selected_formats, list):
90             selected_formats = [selected_formats]
91 
92         if not isinstance(selected_list_name, list):
93             selected_list_name = [selected_list_name]
94         selected_list_name = [i.lower() for i in selected_list_name]
95 
96         logger.debug(f'Selected List Status: {selected_list_status}')
97         logger.debug(f'Selected Release Status: {selected_release_status}')
98         logger.debug(f'Selected Formats: {selected_formats}')
99 
100         req_variables = {'user': config['username']}
101         req_chunk = 1
102         req_fields = (
103             'id, status, title{ romaji, english }, synonyms, siteUrl, idMal, format, episodes, '
104             'trailer{ site, id }, coverImage{ large }, bannerImage, genres, tags{ name }, '
105             'externalLinks{ site, url }, startDate{ year, month, day }, endDate{ year, month, day}'
106         )
107         while req_chunk:
108             req_query = (
109                 f'query ($user: String){{ collection: MediaListCollection(userName: $user, '
110                 f'type: ANIME, perChunk: 500, chunk: {req_chunk}, status_in: '
111                 f'[{", ".join([s.upper() for s in selected_list_status])}]) {{ hasNextChunk, '
112                 f'statuses: lists{{ status, name, list: entries{{ anime: media{{ {req_fields}'
113                 f' }}}}}}}}}}'
114             )
115 
116             try:
117                 list_response = task.requests.post(
118                     'https://graphql.anilist.co',
119                     json={'query': req_query, 'variables': req_variables},
120                 )
121                 list_response = list_response.json()['data']
122             except RequestException as e:
123                 logger.error(f'Error reading list: {e}')
124                 break
125             except ValueError as e:
126                 logger.error(f'Invalid JSON response: {e}')
127                 break
128 
129             logger.trace(f'JSON output: {list_response}')
130             for list_status in list_response.get('collection', {}).get('statuses', []):
131                 if selected_list_name and (
132                     list_status.get('name')
133                     and list_status.get('name').lower() not in selected_list_name
134                 ):
135                     continue
136                 for anime in list_status['list']:
137                     anime = anime.get('anime')
138                     has_selected_release_status = (
139                         anime.get('status')
140                         and anime.get('status').lower() in selected_release_status
141                     ) or 'all' in selected_release_status
142                     has_selected_type = (
143                         anime.get('format') and anime.get('format').lower() in selected_formats
144                     ) or 'all' in selected_formats
145 
146                     if has_selected_type and has_selected_release_status:
147                         try:
148                             ids = task.requests.post(
149                                 'https://relations.yuna.moe/api/ids',
150                                 json={'anilist': anime.get('id')},
151                             ).json()
152                             logger.debug(f'Additional IDs: {ids}')
153                         except RequestException as e:
154                             logger.verbose(f'Couldn\'t fetch additional IDs: {e}')
155                         if not ids or not isinstance(ids, dict):
156                             ids = {}
157 
158                         logger.debug(f'Anime Entry: {anime}')
159                         entry = Entry()
160                         entry['al_id'] = anime.get('id', ids.get('anilist'))
161                         entry['anidb_id'] = ids.get('anidb')
162                         entry['kitsu_id'] = ids.get('kitsu')
163                         entry['mal_id'] = anime.get('idMal', ids.get('myanimelist'))
164                         entry['al_banner'] = anime.get('bannerImage')
165                         entry['al_cover'] = anime.get('coverImage', {}).get('large')
166                         entry['al_date_end'] = (
167                             datetime(
168                                 year=anime.get('endDate').get('year'),
169                                 month=(anime.get('endDate').get('month') or 1),
170                                 day=(anime.get('endDate').get('day') or 1),
171                             )
172                             if anime.get('endDate').get('year')
173                             else None
174                         )
175                         entry['al_date_start'] = (
176                             datetime(
177                                 year=anime.get('startDate').get('year'),
178                                 month=(anime.get('startDate').get('month') or 1),
179                                 day=(anime.get('startDate').get('day') or 1),
180                             )
181                             if anime.get('startDate').get('year')
182                             else None
183                         )
184                         entry['al_episodes'] = anime.get('episodes')
185                         entry['al_format'] = anime.get('format')
186                         entry['al_genres'] = anime.get('genres')
187                         entry['al_links'] = {
188                             item['site']: item['url'] for item in anime.get('externalLinks')
189                         }
190                         entry['al_list'] = list_status.get('name')
191                         entry['al_list_status'] = (
192                             list_status['status'].capitalize()
193                             if list_status.get('status')
194                             else None
195                         )
196                         entry['al_release_status'] = (
197                             anime['status'].capitalize() if anime.get('status') else None
198                         )
199                         entry['al_tags'] = [t.get('name') for t in anime.get('tags')]
200                         entry['al_title'] = anime.get('title')
201                         entry['al_trailer'] = (
202                             TRAILER_SOURCE[anime.get('trailer', {}).get('site')]
203                             + anime.get('trailer', {}).get('id')
204                             if anime.get('trailer')
205                             and anime.get('trailer').get('site') in TRAILER_SOURCE
206                             else None
207                         )
208                         entry['alternate_name'] = anime.get('synonyms', [])
209                         eng_title = anime.get('title', {}).get('english')
210                         if (
211                             eng_title
212                             and eng_title.lower() != anime.get('title', {}).get('romaji').lower()
213                             and eng_title not in entry['alternate_name']
214                         ):
215                             entry['alternate_name'].insert(0, eng_title)
216                         entry['series_name'] = entry['al_title'].get('romaji') or entry[
217                             'al_title'
218                         ].get('english')
219                         entry['title'] = entry['series_name']
220                         entry['url'] = anime.get('siteUrl')
221                         if entry.isvalid():
222                             yield entry
223             req_chunk = req_chunk + 1 if list_response['collection']['hasNextChunk'] else False
224 
225 
226 @event('plugin.register')
227 def register_plugin():
228     plugin.register(AniList, 'anilist', api_ver=2)
229
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

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
@@ -144,6 +144,7 @@
                     ) or 'all' in selected_formats
 
                     if has_selected_type and has_selected_release_status:
+                        ids = {}
                         try:
                             ids = task.requests.post(
                                 'https://relations.yuna.moe/api/ids',
@@ -152,7 +153,7 @@
                             logger.debug(f'Additional IDs: {ids}')
                         except RequestException as e:
                             logger.verbose(f'Couldn\'t fetch additional IDs: {e}')
-                        if not ids or not isinstance(ids, dict):
+                        if not isinstance(ids, dict):
                             ids = {}
 
                         logger.debug(f'Anime Entry: {anime}')

{"golden_diff": "diff --git a/flexget/plugins/input/anilist.py b/flexget/plugins/input/anilist.py\n--- a/flexget/plugins/input/anilist.py\n+++ b/flexget/plugins/input/anilist.py\n@@ -144,6 +144,7 @@\n                     ) or 'all' in selected_formats\n \n                     if has_selected_type and has_selected_release_status:\n+                        ids = {}\n                         try:\n                             ids = task.requests.post(\n                                 'https://relations.yuna.moe/api/ids',\n@@ -152,7 +153,7 @@\n                             logger.debug(f'Additional IDs: {ids}')\n                         except RequestException as e:\n                             logger.verbose(f'Couldn\\'t fetch additional IDs: {e}')\n-                        if not ids or not isinstance(ids, dict):\n+                        if not isinstance(ids, dict):\n                             ids = {}\n \n                         logger.debug(f'Anime Entry: {anime}')\n", "issue": "Anilist plugin crashes when relations.yuna.moe is unreachable\n```\r\n2022-02-16 05:42:37 DEBUG    utils.requests anime           POSTing URL https://relations.yuna.moe/api/ids with args () and kwargs {'data': None, 'json': {'anilist': 114099}, 'timeout': 30}\r\n2022-02-16 05:42:38 VERBOSE  anilist       anime           Couldn't fetch additional IDs: 502 Server Error: Bad Gateway for url: https://relations.yuna.moe/api/ids\r\n2022-02-16 05:42:38 CRITICAL task          anime           BUG: Unhandled error in plugin configure_series: local variable 'ids' referenced before assignment\r\n(...)\r\nUnboundLocalError: local variable 'ids' referenced before assignment\r\nTraceback (most recent call last):\r\n  File \"/usr/local/lib/python3.10/site-packages/flexget/task.py\", line 547, in __run_plugin\r\n    result = method(*args, **kwargs)\r\n  File \"/usr/local/lib/python3.10/site-packages/flexget/event.py\", line 20, in __call__\r\n    return self.func(*args, **kwargs)\r\n  File \"/usr/local/lib/python3.10/site-packages/flexget/components/series/configure_series.py\", line 61, in on_task_prepare\r\n    for entry in result:\r\n  File \"/usr/local/lib/python3.10/site-packages/flexget/utils/cached_input.py\", line 231, in __iter__\r\n    for item in self.iterable:\r\n  File \"/usr/local/lib/python3.10/site-packages/flexget/plugins/input/anilist.py\", line 155, in on_task_input\r\n    if not ids or not isinstance(ids, dict):\r\nUnboundLocalError: local variable 'ids' referenced before assignment\r\n```\nAnilist plugin crashes when relations.yuna.moe is unreachable\n```\r\n2022-02-16 05:42:37 DEBUG    utils.requests anime           POSTing URL https://relations.yuna.moe/api/ids with args () and kwargs {'data': None, 'json': {'anilist': 114099}, 'timeout': 30}\r\n2022-02-16 05:42:38 VERBOSE  anilist       anime           Couldn't fetch additional IDs: 502 Server Error: Bad Gateway for url: https://relations.yuna.moe/api/ids\r\n2022-02-16 05:42:38 CRITICAL task          anime           BUG: Unhandled error in plugin configure_series: local variable 'ids' referenced before assignment\r\n(...)\r\nUnboundLocalError: local variable 'ids' referenced before assignment\r\nTraceback (most recent call last):\r\n  File \"/usr/local/lib/python3.10/site-packages/flexget/task.py\", line 547, in __run_plugin\r\n    result = method(*args, **kwargs)\r\n  File \"/usr/local/lib/python3.10/site-packages/flexget/event.py\", line 20, in __call__\r\n    return self.func(*args, **kwargs)\r\n  File \"/usr/local/lib/python3.10/site-packages/flexget/components/series/configure_series.py\", line 61, in on_task_prepare\r\n    for entry in result:\r\n  File \"/usr/local/lib/python3.10/site-packages/flexget/utils/cached_input.py\", line 231, in __iter__\r\n    for item in self.iterable:\r\n  File \"/usr/local/lib/python3.10/site-packages/flexget/plugins/input/anilist.py\", line 155, in on_task_input\r\n    if not ids or not isinstance(ids, dict):\r\nUnboundLocalError: local variable 'ids' referenced before assignment\r\n```\n", "before_files": [{"content": "from datetime import datetime\n\nfrom loguru import logger\n\nfrom flexget import plugin\nfrom flexget.config_schema import one_or_more\nfrom flexget.entry import Entry\nfrom flexget.event import event\nfrom flexget.utils.cached_input import cached\nfrom flexget.utils.requests import RequestException\n\nlogger = logger.bind(name='anilist')\n\nLIST_STATUS = ['current', 'planning', 'completed', 'dropped', 'paused', 'repeating']\n\nRELEASE_STATUS = ['finished', 'releasing', 'not_yet_released', 'cancelled', 'all']\n\nANIME_FORMAT = ['tv', 'tv_short', 'movie', 'special', 'ova', 'ona', 'all']\n\nTRAILER_SOURCE = {\n    'youtube': 'https://www.youtube.com/embed/',\n    'dailymotion': 'https://www.dailymotion.com/embed/video/',\n}\n\n\nclass AniList(object):\n    \"\"\" \" Creates entries for series and movies from your AniList list\n\n    Syntax:\n    anilist:\n      username: <string>\n      status:\n        - <current|planning|completed|dropped|paused|repeating>\n        - <current|planning|completed|dropped|paused|repeating>\n        ...\n      release_status:\n        - <all|finished|releasing|not_yet_released|cancelled>\n        - <finished|releasing|not_yet_released|cancelled>\n        ...\n      format:\n        - <all|tv|tv_short|movie|special|ova|ona>\n        - <tv|tv_short|movie|special|ova|ona>\n        ...\n      list:\n        - <string>\n        - <string>\n        ...\n    \"\"\"\n\n    schema = {\n        'oneOf': [\n            {'type': 'string'},\n            {\n                'type': 'object',\n                'properties': {\n                    'username': {'type': 'string'},\n                    'status': one_or_more(\n                        {'type': 'string', 'enum': LIST_STATUS}, unique_items=True\n                    ),\n                    'release_status': one_or_more(\n                        {'type': 'string', 'enum': RELEASE_STATUS}, unique_items=True\n                    ),\n                    'format': one_or_more(\n                        {'type': 'string', 'enum': ANIME_FORMAT}, unique_items=True\n                    ),\n                    'list': one_or_more({'type': 'string'}),\n                },\n                'required': ['username'],\n                'additionalProperties': False,\n            },\n        ]\n    }\n\n    @cached('anilist', persist='2 hours')\n    def on_task_input(self, task, config):\n        if isinstance(config, str):\n            config = {'username': config}\n        selected_list_status = config.get('status', ['current', 'planning'])\n        selected_release_status = config.get('release_status', ['all'])\n        selected_formats = config.get('format', ['all'])\n        selected_list_name = config.get('list', [])\n\n        if not isinstance(selected_list_status, list):\n            selected_list_status = [selected_list_status]\n\n        if not isinstance(selected_release_status, list):\n            selected_release_status = [selected_release_status]\n\n        if not isinstance(selected_formats, list):\n            selected_formats = [selected_formats]\n\n        if not isinstance(selected_list_name, list):\n            selected_list_name = [selected_list_name]\n        selected_list_name = [i.lower() for i in selected_list_name]\n\n        logger.debug(f'Selected List Status: {selected_list_status}')\n        logger.debug(f'Selected Release Status: {selected_release_status}')\n        logger.debug(f'Selected Formats: {selected_formats}')\n\n        req_variables = {'user': config['username']}\n        req_chunk = 1\n        req_fields = (\n            'id, status, title{ romaji, english }, synonyms, siteUrl, idMal, format, episodes, '\n            'trailer{ site, id }, coverImage{ large }, bannerImage, genres, tags{ name }, '\n            'externalLinks{ site, url }, startDate{ year, month, day }, endDate{ year, month, day}'\n        )\n        while req_chunk:\n            req_query = (\n                f'query ($user: String){{ collection: MediaListCollection(userName: $user, '\n                f'type: ANIME, perChunk: 500, chunk: {req_chunk}, status_in: '\n                f'[{\", \".join([s.upper() for s in selected_list_status])}]) {{ hasNextChunk, '\n                f'statuses: lists{{ status, name, list: entries{{ anime: media{{ {req_fields}'\n                f' }}}}}}}}}}'\n            )\n\n            try:\n                list_response = task.requests.post(\n                    'https://graphql.anilist.co',\n                    json={'query': req_query, 'variables': req_variables},\n                )\n                list_response = list_response.json()['data']\n            except RequestException as e:\n                logger.error(f'Error reading list: {e}')\n                break\n            except ValueError as e:\n                logger.error(f'Invalid JSON response: {e}')\n                break\n\n            logger.trace(f'JSON output: {list_response}')\n            for list_status in list_response.get('collection', {}).get('statuses', []):\n                if selected_list_name and (\n                    list_status.get('name')\n                    and list_status.get('name').lower() not in selected_list_name\n                ):\n                    continue\n                for anime in list_status['list']:\n                    anime = anime.get('anime')\n                    has_selected_release_status = (\n                        anime.get('status')\n                        and anime.get('status').lower() in selected_release_status\n                    ) or 'all' in selected_release_status\n                    has_selected_type = (\n                        anime.get('format') and anime.get('format').lower() in selected_formats\n                    ) or 'all' in selected_formats\n\n                    if has_selected_type and has_selected_release_status:\n                        try:\n                            ids = task.requests.post(\n                                'https://relations.yuna.moe/api/ids',\n                                json={'anilist': anime.get('id')},\n                            ).json()\n                            logger.debug(f'Additional IDs: {ids}')\n                        except RequestException as e:\n                            logger.verbose(f'Couldn\\'t fetch additional IDs: {e}')\n                        if not ids or not isinstance(ids, dict):\n                            ids = {}\n\n                        logger.debug(f'Anime Entry: {anime}')\n                        entry = Entry()\n                        entry['al_id'] = anime.get('id', ids.get('anilist'))\n                        entry['anidb_id'] = ids.get('anidb')\n                        entry['kitsu_id'] = ids.get('kitsu')\n                        entry['mal_id'] = anime.get('idMal', ids.get('myanimelist'))\n                        entry['al_banner'] = anime.get('bannerImage')\n                        entry['al_cover'] = anime.get('coverImage', {}).get('large')\n                        entry['al_date_end'] = (\n                            datetime(\n                                year=anime.get('endDate').get('year'),\n                                month=(anime.get('endDate').get('month') or 1),\n                                day=(anime.get('endDate').get('day') or 1),\n                            )\n                            if anime.get('endDate').get('year')\n                            else None\n                        )\n                        entry['al_date_start'] = (\n                            datetime(\n                                year=anime.get('startDate').get('year'),\n                                month=(anime.get('startDate').get('month') or 1),\n                                day=(anime.get('startDate').get('day') or 1),\n                            )\n                            if anime.get('startDate').get('year')\n                            else None\n                        )\n                        entry['al_episodes'] = anime.get('episodes')\n                        entry['al_format'] = anime.get('format')\n                        entry['al_genres'] = anime.get('genres')\n                        entry['al_links'] = {\n                            item['site']: item['url'] for item in anime.get('externalLinks')\n                        }\n                        entry['al_list'] = list_status.get('name')\n                        entry['al_list_status'] = (\n                            list_status['status'].capitalize()\n                            if list_status.get('status')\n                            else None\n                        )\n                        entry['al_release_status'] = (\n                            anime['status'].capitalize() if anime.get('status') else None\n                        )\n                        entry['al_tags'] = [t.get('name') for t in anime.get('tags')]\n                        entry['al_title'] = anime.get('title')\n                        entry['al_trailer'] = (\n                            TRAILER_SOURCE[anime.get('trailer', {}).get('site')]\n                            + anime.get('trailer', {}).get('id')\n                            if anime.get('trailer')\n                            and anime.get('trailer').get('site') in TRAILER_SOURCE\n                            else None\n                        )\n                        entry['alternate_name'] = anime.get('synonyms', [])\n                        eng_title = anime.get('title', {}).get('english')\n                        if (\n                            eng_title\n                            and eng_title.lower() != anime.get('title', {}).get('romaji').lower()\n                            and eng_title not in entry['alternate_name']\n                        ):\n                            entry['alternate_name'].insert(0, eng_title)\n                        entry['series_name'] = entry['al_title'].get('romaji') or entry[\n                            'al_title'\n                        ].get('english')\n                        entry['title'] = entry['series_name']\n                        entry['url'] = anime.get('siteUrl')\n                        if entry.isvalid():\n                            yield entry\n            req_chunk = req_chunk + 1 if list_response['collection']['hasNextChunk'] else False\n\n\n@event('plugin.register')\ndef register_plugin():\n    plugin.register(AniList, 'anilist', api_ver=2)\n", "path": "flexget/plugins/input/anilist.py"}], "after_files": [{"content": "from datetime import datetime\n\nfrom loguru import logger\n\nfrom flexget import plugin\nfrom flexget.config_schema import one_or_more\nfrom flexget.entry import Entry\nfrom flexget.event import event\nfrom flexget.utils.cached_input import cached\nfrom flexget.utils.requests import RequestException\n\nlogger = logger.bind(name='anilist')\n\nLIST_STATUS = ['current', 'planning', 'completed', 'dropped', 'paused', 'repeating']\n\nRELEASE_STATUS = ['finished', 'releasing', 'not_yet_released', 'cancelled', 'all']\n\nANIME_FORMAT = ['tv', 'tv_short', 'movie', 'special', 'ova', 'ona', 'all']\n\nTRAILER_SOURCE = {\n    'youtube': 'https://www.youtube.com/embed/',\n    'dailymotion': 'https://www.dailymotion.com/embed/video/',\n}\n\n\nclass AniList(object):\n    \"\"\" \" Creates entries for series and movies from your AniList list\n\n    Syntax:\n    anilist:\n      username: <string>\n      status:\n        - <current|planning|completed|dropped|paused|repeating>\n        - <current|planning|completed|dropped|paused|repeating>\n        ...\n      release_status:\n        - <all|finished|releasing|not_yet_released|cancelled>\n        - <finished|releasing|not_yet_released|cancelled>\n        ...\n      format:\n        - <all|tv|tv_short|movie|special|ova|ona>\n        - <tv|tv_short|movie|special|ova|ona>\n        ...\n      list:\n        - <string>\n        - <string>\n        ...\n    \"\"\"\n\n    schema = {\n        'oneOf': [\n            {'type': 'string'},\n            {\n                'type': 'object',\n                'properties': {\n                    'username': {'type': 'string'},\n                    'status': one_or_more(\n                        {'type': 'string', 'enum': LIST_STATUS}, unique_items=True\n                    ),\n                    'release_status': one_or_more(\n                        {'type': 'string', 'enum': RELEASE_STATUS}, unique_items=True\n                    ),\n                    'format': one_or_more(\n                        {'type': 'string', 'enum': ANIME_FORMAT}, unique_items=True\n                    ),\n                    'list': one_or_more({'type': 'string'}),\n                },\n                'required': ['username'],\n                'additionalProperties': False,\n            },\n        ]\n    }\n\n    @cached('anilist', persist='2 hours')\n    def on_task_input(self, task, config):\n        if isinstance(config, str):\n            config = {'username': config}\n        selected_list_status = config.get('status', ['current', 'planning'])\n        selected_release_status = config.get('release_status', ['all'])\n        selected_formats = config.get('format', ['all'])\n        selected_list_name = config.get('list', [])\n\n        if not isinstance(selected_list_status, list):\n            selected_list_status = [selected_list_status]\n\n        if not isinstance(selected_release_status, list):\n            selected_release_status = [selected_release_status]\n\n        if not isinstance(selected_formats, list):\n            selected_formats = [selected_formats]\n\n        if not isinstance(selected_list_name, list):\n            selected_list_name = [selected_list_name]\n        selected_list_name = [i.lower() for i in selected_list_name]\n\n        logger.debug(f'Selected List Status: {selected_list_status}')\n        logger.debug(f'Selected Release Status: {selected_release_status}')\n        logger.debug(f'Selected Formats: {selected_formats}')\n\n        req_variables = {'user': config['username']}\n        req_chunk = 1\n        req_fields = (\n            'id, status, title{ romaji, english }, synonyms, siteUrl, idMal, format, episodes, '\n            'trailer{ site, id }, coverImage{ large }, bannerImage, genres, tags{ name }, '\n            'externalLinks{ site, url }, startDate{ year, month, day }, endDate{ year, month, day}'\n        )\n        while req_chunk:\n            req_query = (\n                f'query ($user: String){{ collection: MediaListCollection(userName: $user, '\n                f'type: ANIME, perChunk: 500, chunk: {req_chunk}, status_in: '\n                f'[{\", \".join([s.upper() for s in selected_list_status])}]) {{ hasNextChunk, '\n                f'statuses: lists{{ status, name, list: entries{{ anime: media{{ {req_fields}'\n                f' }}}}}}}}}}'\n            )\n\n            try:\n                list_response = task.requests.post(\n                    'https://graphql.anilist.co',\n                    json={'query': req_query, 'variables': req_variables},\n                )\n                list_response = list_response.json()['data']\n            except RequestException as e:\n                logger.error(f'Error reading list: {e}')\n                break\n            except ValueError as e:\n                logger.error(f'Invalid JSON response: {e}')\n                break\n\n            logger.trace(f'JSON output: {list_response}')\n            for list_status in list_response.get('collection', {}).get('statuses', []):\n                if selected_list_name and (\n                    list_status.get('name')\n                    and list_status.get('name').lower() not in selected_list_name\n                ):\n                    continue\n                for anime in list_status['list']:\n                    anime = anime.get('anime')\n                    has_selected_release_status = (\n                        anime.get('status')\n                        and anime.get('status').lower() in selected_release_status\n                    ) or 'all' in selected_release_status\n                    has_selected_type = (\n                        anime.get('format') and anime.get('format').lower() in selected_formats\n                    ) or 'all' in selected_formats\n\n                    if has_selected_type and has_selected_release_status:\n                        ids = {}\n                        try:\n                            ids = task.requests.post(\n                                'https://relations.yuna.moe/api/ids',\n                                json={'anilist': anime.get('id')},\n                            ).json()\n                            logger.debug(f'Additional IDs: {ids}')\n                        except RequestException as e:\n                            logger.verbose(f'Couldn\\'t fetch additional IDs: {e}')\n                        if not isinstance(ids, dict):\n                            ids = {}\n\n                        logger.debug(f'Anime Entry: {anime}')\n                        entry = Entry()\n                        entry['al_id'] = anime.get('id', ids.get('anilist'))\n                        entry['anidb_id'] = ids.get('anidb')\n                        entry['kitsu_id'] = ids.get('kitsu')\n                        entry['mal_id'] = anime.get('idMal', ids.get('myanimelist'))\n                        entry['al_banner'] = anime.get('bannerImage')\n                        entry['al_cover'] = anime.get('coverImage', {}).get('large')\n                        entry['al_date_end'] = (\n                            datetime(\n                                year=anime.get('endDate').get('year'),\n                                month=(anime.get('endDate').get('month') or 1),\n                                day=(anime.get('endDate').get('day') or 1),\n                            )\n                            if anime.get('endDate').get('year')\n                            else None\n                        )\n                        entry['al_date_start'] = (\n                            datetime(\n                                year=anime.get('startDate').get('year'),\n                                month=(anime.get('startDate').get('month') or 1),\n                                day=(anime.get('startDate').get('day') or 1),\n                            )\n                            if anime.get('startDate').get('year')\n                            else None\n                        )\n                        entry['al_episodes'] = anime.get('episodes')\n                        entry['al_format'] = anime.get('format')\n                        entry['al_genres'] = anime.get('genres')\n                        entry['al_links'] = {\n                            item['site']: item['url'] for item in anime.get('externalLinks')\n                        }\n                        entry['al_list'] = list_status.get('name')\n                        entry['al_list_status'] = (\n                            list_status['status'].capitalize()\n                            if list_status.get('status')\n                            else None\n                        )\n                        entry['al_release_status'] = (\n                            anime['status'].capitalize() if anime.get('status') else None\n                        )\n                        entry['al_tags'] = [t.get('name') for t in anime.get('tags')]\n                        entry['al_title'] = anime.get('title')\n                        entry['al_trailer'] = (\n                            TRAILER_SOURCE[anime.get('trailer', {}).get('site')]\n                            + anime.get('trailer', {}).get('id')\n                            if anime.get('trailer')\n                            and anime.get('trailer').get('site') in TRAILER_SOURCE\n                            else None\n                        )\n                        entry['alternate_name'] = anime.get('synonyms', [])\n                        eng_title = anime.get('title', {}).get('english')\n                        if (\n                            eng_title\n                            and eng_title.lower() != anime.get('title', {}).get('romaji').lower()\n                            and eng_title not in entry['alternate_name']\n                        ):\n                            entry['alternate_name'].insert(0, eng_title)\n                        entry['series_name'] = entry['al_title'].get('romaji') or entry[\n                            'al_title'\n                        ].get('english')\n                        entry['title'] = entry['series_name']\n                        entry['url'] = anime.get('siteUrl')\n                        if entry.isvalid():\n                            yield entry\n            req_chunk = req_chunk + 1 if list_response['collection']['hasNextChunk'] else False\n\n\n@event('plugin.register')\ndef register_plugin():\n    plugin.register(AniList, 'anilist', api_ver=2)\n", "path": "flexget/plugins/input/anilist.py"}]}