Repository: Flexget/Flexget

Issue:
my_anime_list plugin is no longer functional
### Expected behaviour:
plugin retrieves list of anime from your animelist.

### Actual behaviour:
Returns error: 
`Error during input plugin my_anime_list: Error finding list on url: https://myanimelist.net/malappinfo.php?status=all&type=anime&u=viggy96`
'viggy96' being my MAL username.
### Steps to reproduce:
 run 'flexget execute' on any config that uses the my_anime_list plugin.

### Config
```
variables: variables.yml

templates:
  global:
    transmission:
      host: localhost
      port: 9091
      username: '{? transmission.username ?}'
      password: '{? transmission.password ?}'
      addpaused: no
      magnetization_timeout: 120
      ratio: 20.0
    content_filter:
      require:
        - '*.mkv'
      reject:
        - '*.wmv'
        - '*.mp4'
        - '*.avi'
        - '/\W*(raws)\W*/gi'
        - '/\W*(multi)\W*/gi'

  seasonal_anime_and_specials:
    transmission:
      path: /home/box/Downloads/Anime/{{series_name | pathscrub('windows') | trim}}
      content_filename: "{{series_name}} - {{series_id}} [{{quality | replace('h264', '') | replace('aac', '') | trim}}]"
    trakt_lookup: yes
    configure_series:
      settings:
        quality: 720p
        ep_regexp:
          - (\d+)
        season_packs: yes
      from:
        my_anime_list:
          username: '{? mal.username ?}'
          status:
            - watching
            - plan_to_watch
          type: 
            - series
            - ova
            - special
            - ona
    series:
      settings:
        groupa:
          quality: 720p
          ep_regexp:
            - (\d+)
          season_packs: yes 
      groupa:
        - 'Gintama'
        - 'Shokugeki no Souma: San no Sara - Toutsuki Ressha-hen':
            alternate_name: 'Shokugeki no Soma S3'

  anime_movies:
    transmission: 
      path: /home/box/Downloads/Anime/{{movie_name | pathscrub('windows') | trim}}
      content_filename: "{{movie_name | pathscrub('windows')}} - [{{quality | replace('webdl', '') | replace('dts', '') | replace('ac3', '') |  replace('aac', '') | trim}}]"
    configure_series:
      settings:
        timeframe: 24 hours
        target: 1080p h265
        quality: 720p
      from:
        my_anime_list:
          username: '{? mal.username ?}'
          status:
            - watching
            - plan_to_watch
          type: movie

  tv_shows:
    transmission:
      path: /home/box/Downloads/TV/{{series_name}}
      main_file_only: yes
      main_file_ratio: 0.90
      content_filename: "{{series_name}} - {{series_id}} [{{quality | replace('hdtv', '') | replace('webrip', '') | replace('webdl', '') | trim}}]"
    series:
      - 'Adam Ruins Everything'
      - 'Altered Carbon'
      - 'Archer (2009)'
      - 'BattleBots'
      - 'Bill Nye Saves the World'
      - 'Black Mirror'
      - 'Elementary'
      - 'Last Week Tonight With John Oliver'
      - 'Our Cartoon President'
      - 'Sherlock'
      - 'Star Trek: Discovery'
      - 'The Grand Tour'
      - 'The Orville'
      - 'The Simpsons'
      - 'Westworld'

tasks:
  horriblesubs:
    rss: http://horriblesubs.info/rss.php?res=720
    template: seasonal_anime_and_specials
    remember_rejected: yes
    version_checker: yes
    priority: 1
  nyaa_movies:
    rss: https://nyaa.si/?page=rss&c=1_2&f=0
    template: anime_movies
    remember_rejected: yes
    priority: 2
  tv:
    rss: http://showrss.info/user/159252.rss?magnets=true&namespaces=true&name=null&quality=null&re=null
    template: tv_shows
    remember_rejected: yes
    priority: 3
```

### Additional information:

- FlexGet version:
- Python version: 2.7.14
- Installation method: pip
- Using daemon (yes/no): no
- OS and version: Ubuntu Server 16.04.3 LTS


Discussion:
Does anyone know in what form the response from 'malappinfo.php' took? I'm willing to work on it as I relied on this plugin a lot...

Resolving patch:
diff --git a/flexget/plugins/input/my_anime_list.py b/flexget/plugins/input/my_anime_list.py
--- a/flexget/plugins/input/my_anime_list.py
+++ b/flexget/plugins/input/my_anime_list.py
@@ -2,7 +2,6 @@
 from builtins import *  # noqa pylint: disable=unused-import, redefined-builtin
 
 import logging
-import xml.etree.ElementTree as ET
 
 from flexget import plugin
 from flexget.config_schema import one_or_more
@@ -12,24 +11,26 @@
 from flexget.utils.requests import RequestException
 
 log = logging.getLogger('my_anime_list')
-STATUS = {
-    '1': 'watching',
-    '2': 'completed',
-    '3': 'on_hold',
-    '4': 'dropped',
-    '6': 'plan_to_watch',
-}
 
-ANIME_TYPE = {
-    '0': 'unknown',
-    '1': 'series',
-    '2': 'ova',
-    '3': 'movie',
-    '4': 'special',
-    '5': 'ona',
-    '6': 'music'
+STATUS = {
+    'watching': 1,
+    'completed': 2,
+    'on_hold': 3,
+    'dropped': 4,
+    'plan_to_watch': 6,
+    'all': 7
 }
 
+ANIME_TYPE = [
+    'all',
+    'tv',
+    'ova',
+    'movie',
+    'special',
+    'ona',
+    'music',
+    'unknown'
+]
 
 class MyAnimeList(object):
     """" Creates entries for series and movies from MyAnimeList list
@@ -48,8 +49,8 @@ class MyAnimeList(object):
         'type': 'object',
         'properties': {
             'username': {'type': 'string'},
-            'status': one_or_more({'type': 'string', 'enum': list(STATUS.values())}, unique_items=True),
-            'type': one_or_more({'type': 'string', 'enum': list(ANIME_TYPE.values())}, unique_items=True)
+            'status': one_or_more({'type': 'string', 'enum': list(STATUS.keys()), 'default': 'all'}, unique_items=True),
+            'type': one_or_more({'type': 'string', 'enum': list(ANIME_TYPE), 'default': 'all'}, unique_items=True)
         },
         'required': ['username'],
         'additionalProperties': False
@@ -58,9 +59,8 @@ class MyAnimeList(object):
     @cached('my_anime_list', persist='2 hours')
     def on_task_input(self, task, config):
         entries = []
-        parameters = {'u': config['username'], 'status': 'all', 'type': 'anime'}
-        selected_status = config.get('status', list(STATUS.values()))
-        selected_types = config.get('type', list(ANIME_TYPE.values()))
+        selected_status = config['status']
+        selected_types = config['type']
 
         if not isinstance(selected_status, list):
             selected_status = [selected_status]
@@ -68,57 +68,31 @@ def on_task_input(self, task, config):
         if not isinstance(selected_types, list):
             selected_types = [selected_types]
 
+        selected_status = [STATUS[s] for s in selected_status]
+
         try:
-            list_response = task.requests.get('https://myanimelist.net/malappinfo.php', params=parameters)
+            list_response = task.requests.get('https://myanimelist.net/animelist/' + config['username'] + '/load.json')
         except RequestException as e:
             raise plugin.PluginError('Error finding list on url: {url}'.format(url=e.request.url))
 
         try:
-            tree = ET.fromstring(list_response.text.encode('utf-8'))
-            list_items = tree.findall('anime')
-        except ET.ParseError:
-            raise plugin.PluginError('Bad XML')
-
-        for item in list_items:
-            my_anime_list_id = item.findtext('series_animedb_id')
-            title = item.findtext('series_title').strip()
-            anime_type = ANIME_TYPE[item.findtext('series_type', 1)]
-            my_status = STATUS[item.findtext('my_status')]
-
-            my_tags = []
-            alternate_names = []
-            is_exact = False
-
-            for name in item.findtext('series_synonyms', '').split('; '):
-                stripped = name.strip()
-                if stripped and stripped is not title:
-                    alternate_names.append(name)
-
-            for tag in item.findtext('my_tags', '').split(','):
-                stripped = tag.strip()
-                if stripped:
-                    my_tags.append(stripped)
-                    if stripped is 'exact':
-                        is_exact = True
-
-            # if user has chosen a status or a type, match strictly, otherwise let it all through
-            wanted_status = not selected_status or my_status in selected_status
-            wanted_type = not selected_types or anime_type in selected_types
-
-            if wanted_status and wanted_type:
-                entry = Entry(title=title,
-                              url='https://myanimelist.net/anime/{}'.format(my_anime_list_id),
-                              configure_series_alternate_name=alternate_names,
-                              my_anime_list_type=anime_type,
-                              my_anime_list_status=my_status,
-                              my_anime_list_tags=my_tags)
-
-                if is_exact:
-                    entry['configure_series_exact'] = True
-
-                if entry.isvalid():
-                    entries.append(entry)
-
+            list_json = list_response.json()
+        except ValueError:
+            raise plugin.PluginError('Invalid JSON response')
+
+        for anime in list_json:
+            has_selected_status = anime["status"] in selected_status or config['status'] == 'all'
+            has_selected_type = anime["anime_media_type_string"].lower() in selected_types or config['type'] == 'all'
+            if has_selected_status and has_selected_type:
+                entries.append(
+                    Entry(
+                        title=anime["anime_title"],
+                        url="https://myanimelist.net" + anime["anime_url"],
+                        mal_name=anime["anime_title"],
+                        mal_poster=anime["anime_image_path"],
+                        mal_type=anime["anime_media_type_string"]
+                    )
+                )
         return entries
 
 


Test patch: