예제 #1
0
파일: libmal.py 프로젝트: kondra/trackma
 def add_show(self, item):
     """Adds a new show in the server"""
     self.check_credentials()
     self.msg.info(self.name, "Adding show %s..." % item['title'])
     
     xml = self._build_xml(item)
     
     # Send the XML as POST data to the MyAnimeList API
     values = {'data': xml}
     data = self._urlencode(values)
     try:
         response = self.opener.open(self.url + self.mediatype + "list/add/" + str(item['id']) + ".xml", data)
         return True
     except urllib2.HTTPError, e:
         raise utils.APIError('Error adding: ' + str(e.code))
예제 #2
0
    def update_show(self, item):
        """Sends a show update to the server"""
        self.check_credentials()
        self.msg.info(self.name, "Updating show %s..." % item['title'])

        xml = self._build_xml(item)

        # Send the XML as POST data to the MyAnimeList API
        values = {'data': xml}
        data = self._urlencode(values)
        try:
            self.opener.open(
                self.url + self.mediatype + "list/update/" + str(item['id']) +
                ".xml", data)
        except urllib2.HTTPError, e:
            raise utils.APIError('Error updating: ' + str(e.code))
예제 #3
0
    def check_credentials(self):
        self.msg.info(self.name, 'Logging in...')

        try:
            response = self.opener.open(
                "http://melative.com/api/account/verify_credentials.json")
            self.logged_in = True

            # Parse user information
            data = json.load(response)

            self.username = data['name']
            self.userid = data['id']

            return True
        except urllib2.HTTPError, e:
            raise utils.APIError("Incorrect credentials.")
예제 #4
0
    def add_show(self, item):
        """Adds a new show in the server"""
        self.check_credentials()
        self.msg.info(self.name, "Adding show %s..." % item['title'])

        data = self._build_data(item)

        try:
            data = self._request('POST',
                                 self.prefix + "/library-entries",
                                 body=data,
                                 auth=True)

            data_json = json.loads(data)
            return int(data_json['data']['id'])
        except urllib.request.HTTPError as e:
            raise utils.APIError('Error adding: ' + str(e.code))
예제 #5
0
파일: libmal.py 프로젝트: kondra/trackma
 def search(self, criteria):
     """Searches MyAnimeList database for the queried show"""
     self.msg.info(self.name, "Searching for %s..." % criteria)
     
     # Send the urlencoded query to the search API
     query = self._urlencode({'q': criteria})
     data = self._request(self.url + self.mediatype + "/search.xml?" + query)
     
     # Load the results into XML
     try:
         root = ET.ElementTree().parse(data, parser=self._make_parser())
     except ET.ParseError, e:
         if e.code == 3:
             # Empty document; no results
             return []
         else:
             raise utils.APIError("Parser error: %s" % repr(e.message))
예제 #6
0
파일: libmal.py 프로젝트: kondra/trackma
    def request_info(self, itemlist):
        resultdict = dict()
        for item in itemlist:
            # Search for it only if it hasn't been found earlier
            if item['id'] not in resultdict:
                infos = self.search(item['title'])
                for info in infos:
                    showid = info['id']
                    resultdict[showid] = info

        itemids = [ show['id'] for show in itemlist ]

        try:
            reslist = [ resultdict[itemid] for itemid in itemids ]
        except KeyError:
            raise utils.APIError('There was a problem getting the show details.')

        return reslist
예제 #7
0
파일: libhb.py 프로젝트: Zerokami/trackma
    def update_show(self, item):
        """Sends a show update to the server"""
        self.check_credentials()
        self.msg.info(self.name, "Updating show %s..." % item['title'])

        # Send the POST data to the Hummingbird API
        values = {'auth_token': self.auth}

        # Update necessary keys
        if 'my_progress' in item.keys():
            values['episodes_watched'] = item['my_progress']
        if 'my_status' in item.keys():
            values['status'] = item['my_status']
        if 'my_score' in item.keys():
            values['sane_rating_update'] = item['my_score']

        try:
            self._request("/libraries/%s" % item['id'], post=values)
        except urllib2.HTTPError, e:
            raise utils.APIError('Error updating: ' + str(e.code))
예제 #8
0
파일: libmal.py 프로젝트: kondra/trackma
    def check_credentials(self):
        """Checks if credentials are correct; returns True or False."""
        if self.logged_in:
            return True     # Already logged in
        
        self.msg.info(self.name, 'Logging in...')
        try:
            response = self._request(self.url + "account/verify_credentials.xml")
            root = ET.ElementTree().parse(response, parser=self._make_parser())
            (userid, username) = self._parse_credentials(root)
            self.username = username

            self._set_userconfig('userid', userid)
            self._set_userconfig('username', username)
            self._emit_signal('userconfig_changed')

            self.logged_in = True
            return True
        except urllib2.HTTPError, e:
            raise utils.APIError("Incorrect credentials.")
예제 #9
0
    def search(self, criteria):
        self.check_credentials()

        self.msg.info(self.name, "Searching for {}...".format(criteria))
        param = {'access_token': self._get_userconfig('access_token')}
        data = self._request("GET", "{0}/search/{1}".format(self.mediatype, criteria), get=param)

        if type(data) == dict:
            # In case of error API returns a small JSON payload
            # which translates into a dict with the key 'error'
            # instead of a list.
            if data['error']['messages'][0] == 'No Results.':
                data = []
            else:
                raise utils.APIError("Error while searching for \
                        {0}: {1}".format(criteria, str(data)))

        showlist = []
        for item in data:
            show = utils.show()
            showid = item['id']
            showdata = {
                'id': showid,
                'title': item['title_romaji'],
                'aliases': [item['title_english']],
                'type': item['type'],
                'status': item[self.airing_str],
                'my_status': self.media_info()['status_start'],
                'total': item[self.total_str],
                'image': item['image_url_lge'],
                'image_thumb': item['image_url_med'],
                'url': str("https://anilist.co/%s/%d" % (self.mediatype, showid)),
            }
            show.update({k:v for k,v in showdata.items() if v})

            showlist.append( show )

        return showlist
예제 #10
0
    def _sendcmd(self, cmd, options=None):
        """Send a VNDB compatible command and return the response data"""
        msg = cmd
        if options:
            msg += " " + json.dumps(options, separators=(',', ':'))
        msg = msg.encode('utf-8')
        msg += b"\x04"  # EOT

        # Send message
        self.s.sendall(msg)

        # Construct response
        lines = []
        while True:
            line = self.s.recv(65536)
            if line.endswith(b"\x04"):
                line = line.strip(b"\x04")
                lines.append(line)
                response = b"".join(lines).decode('utf-8')
                break
            else:
                lines.append(line)

        # Separate into response name and JSON data
        _resp = response.split(' ', 1)
        name = _resp[0]
        try:
            data = json.loads(_resp[1])
        except IndexError:
            data = None

        # Treat error as an exception
        if name == 'error':
            raise utils.APIError(data['msg'])

        return (name, data)
예제 #11
0
파일: libmal.py 프로젝트: kondra/trackma
 def fetch_list(self):
     """Queries the full list from the remote server.
     Returns the list if successful, False otherwise."""
     self.check_credentials()
     self.msg.info(self.name, 'Downloading list...')
     
     try:
         # Get an XML list from MyAnimeList API
         data = self._request("http://myanimelist.net/malappinfo.php?u="+self.username+"&status=all&type="+self.mediatype)
         
         # Parse the XML data and load it into a dictionary
         # using the proper function (anime or manga)
         root = ET.ElementTree().parse(data, parser=self._make_parser())
         
         if self.mediatype == 'anime':
             self.msg.info(self.name, 'Parsing anime list...')
             return self._parse_anime(root)
         elif self.mediatype == 'manga':
             self.msg.info(self.name, 'Parsing manga list...')
             return self._parse_manga(root)
         else:
             raise utils.APIFatal('Attempted to parse unsupported media type.')
     except urllib2.HTTPError, e:
         raise utils.APIError("Error getting list.")
예제 #12
0
class libanilist(lib):
    """
    API class to communicate with Anilist

    Website: http://anilist.co

    messenger: Messenger object to send useful messages to
    """
    name = 'libanilist'
    msg = None
    logged_in = False

    api_info = {'name': 'Anilist', 'version': '1', 'merge': False}
    mediatypes = dict()
    mediatypes['anime'] = {
        'has_progress':
        True,
        'can_add':
        True,
        'can_delete':
        True,
        'can_score':
        True,
        'can_status':
        True,
        'can_update':
        True,
        'can_play':
        True,
        'status_start':
        'watching',
        'status_finish':
        'completed',
        'statuses':
        ['watching', 'completed', 'on-hold', 'dropped', 'plan to watch'],
        'statuses_dict': {
            'watching': 'Watching',
            'completed': 'Completed',
            'on-hold': 'On Hold',
            'dropped': 'Dropped',
            'plan to watch': 'Plan to Watch'
        },
        'score_max':
        100,
        'score_step':
        1,
    }
    mediatypes['manga'] = {
        'has_progress': True,
        'can_add': True,
        'can_delete': True,
        'can_score': True,
        'can_status': True,
        'can_update': True,
        'can_play': False,
        'status_start': 'reading',
        'status_finish': 'completed',
        'statuses':
        ['reading', 'completed', 'on-hold', 'dropped', 'plan to read'],
        'statuses_dict': {
            'reading': 'Reading',
            'completed': 'Completed',
            'on-hold': 'On Hold',
            'dropped': 'Dropped',
            'plan to read': 'Plan to Read'
        },
        'score_max': 100,
        'score_step': 1,
    }
    default_mediatype = 'anime'

    # Supported signals for the data handler
    signals = {
        'show_info_changed': None,
    }

    url = "http://anilist.co/api/"
    client_id = "z411-gdjc3"
    _client_secret = "MyzwuYoMqPPglXwCTcexG1i"

    def __init__(self, messenger, account, userconfig):
        """Initializes the API"""
        super(libanilist, self).__init__(messenger, account, userconfig)

        self.pin = account['password'].strip()
        self.userid = userconfig['userid']

        if len(self.pin) != 40:
            raise utils.APIFatal("Invalid PIN.")

        if self.mediatype == 'manga':
            self.total_str = "total_chapters"
            self.watched_str = "chapters_read"
            self.airing_str = "publishing_status"
            self.status_translate = {
                'publishing': 1,
                'finished': 2,
                'not yet published': 3,
            }
        else:
            self.total_str = "total_episodes"
            self.watched_str = "episodes_watched"
            self.airing_str = "airing_status"
            self.status_translate = {
                'currently airing': 1,
                'finished airing': 2,
                'not yet aired': 3,
            }

        #handler=urllib2.HTTPHandler(debuglevel=1)
        #self.opener = urllib2.build_opener(handler)
        self.opener = urllib2.build_opener()
        self.opener.addheaders = [('User-agent', 'Trackma/0.1')]

    def _request(self, method, url, get=None, post=None, auth=False):
        if get:
            url = "{}?{}".format(url, urllib.urlencode(get))
        if post:
            post = urllib.urlencode(post)

        request = urllib2.Request(self.url + url, post)
        request.get_method = lambda: method

        if auth:
            request.add_header('Content-Type',
                               'application/x-www-form-urlencoded')
            request.add_header(
                'Authorization', '{0} {1}'.format(
                    self._get_userconfig('token_type').capitalize(),
                    self._get_userconfig('access_token'),
                ))

        try:
            response = self.opener.open(request, timeout=10)
            return json.load(response)
        except urllib2.HTTPError, e:
            if e.code == 400:
                raise utils.APIError(
                    "Invalid PIN. It is either probably expired or meant for another application."
                )
            else:
                raise utils.APIError("Connection error: %s" % e)
        except socket.timeout:
            raise utils.APIError("Connection timed out.")
예제 #13
0
    def fetch_list(self):
        """Queries the full list from the remote server.
        Returns the list if successful, False otherwise."""
        self.check_credentials()
        self.msg.info(self.name, 'Downloading list...')

        try:
            showlist = dict()
            infolist = list()

            # Get first page and continue from there
            params = {
                "filter[user_id]":
                self._get_userconfig('userid'),
                "filter[kind]":
                self.mediatype,
                # "include": self.mediatype, # TODO : This returns a 500 for some reason.
                "include":
                "media",
                # TODO : List for manga should be different
                f"fields[{self.mediatype}]":
                ','.join([
                    'id', 'slug', 'canonicalTitle', 'titles', 'episodeCount' if
                    self.mediatype in ['anime', 'drama'] else 'chapterCount',
                    'description', 'status', 'tba', 'subtype', 'posterImage',
                    'startDate', 'endDate', 'abbreviatedTitles',
                    'averageRating', 'popularityRank', 'ratingRank',
                    'ageRating', 'ageRatingGuide', 'userCount',
                    'favoritesCount'
                ]),
                "page[limit]":
                "250",
            }

            if self.mediatype == 'anime':
                params['fields[anime]'] += ',nsfw'

            if self.mediatype == 'manga':
                params['fields[manga]'] += ',serialization'

            url = "{}/library-entries?{}".format(
                self.prefix, urllib.parse.urlencode(params))
            i = 1

            while url:
                self.msg.info(self.name, 'Getting page {}...'.format(i))

                data = self._request('GET', url)
                data_json = json.loads(data)

                #print(json.dumps(data_json, sort_keys=True, indent=2))
                # return []

                entries = data_json['data']
                links = data_json['links']

                for entry in entries:
                    # TODO : Including the mediatype returns a 500 for some reason.
                    #showid = int(entry['relationships'][self.mediatype]['data']['id'])
                    showid = int(entry['relationships']['media']['data']['id'])
                    status = entry['attributes']['status']
                    rating = entry['attributes']['ratingTwenty']

                    showlist[showid] = utils.show()
                    showlist[showid].update({
                        'id':
                        showid,
                        'my_id':
                        entry['id'],
                        'my_progress':
                        entry['attributes']['progress'],
                        'my_score':
                        float(rating) / 4.00 if rating is not None else 0.0,
                        'my_status':
                        entry['attributes']['status'],
                        'my_start_date':
                        self._iso2date(entry['attributes']['startedAt']),
                        'my_finish_date':
                        self._iso2date(entry['attributes']['finishedAt']),
                    })

                if 'included' in data_json:
                    medias = data_json['included']
                    for media in medias:
                        info = self._parse_info(media)
                        infolist.append(info)

                    self._emit_signal('show_info_changed', infolist)

                url = links.get('next')
                i += 1

            return showlist
        except urllib.request.HTTPError as e:
            raise utils.APIError("Error getting list (HTTPError): %s" %
                                 e.read())
        except urllib.error.URLError as e:
            raise utils.APIError("Error getting list (URLError): %s" %
                                 e.reason)
예제 #14
0
파일: libmal.py 프로젝트: kondra/trackma
         # Parse the XML data and load it into a dictionary
         # using the proper function (anime or manga)
         root = ET.ElementTree().parse(data, parser=self._make_parser())
         
         if self.mediatype == 'anime':
             self.msg.info(self.name, 'Parsing anime list...')
             return self._parse_anime(root)
         elif self.mediatype == 'manga':
             self.msg.info(self.name, 'Parsing manga list...')
             return self._parse_manga(root)
         else:
             raise utils.APIFatal('Attempted to parse unsupported media type.')
     except urllib2.HTTPError, e:
         raise utils.APIError("Error getting list.")
     except IOError, e:
         raise utils.APIError("Error reading list: %s" % e.message)
 
 def add_show(self, item):
     """Adds a new show in the server"""
     self.check_credentials()
     self.msg.info(self.name, "Adding show %s..." % item['title'])
     
     xml = self._build_xml(item)
     
     # Send the XML as POST data to the MyAnimeList API
     values = {'data': xml}
     data = self._urlencode(values)
     try:
         response = self.opener.open(self.url + self.mediatype + "list/add/" + str(item['id']) + ".xml", data)
         return True
     except urllib2.HTTPError, e:
예제 #15
0
class libmal(lib):
    """
    API class to communicate with MyAnimeList
    Should inherit a base library interface.

    Website: http://www.myanimelist.net
    API documentation: http://myanimelist.net/modules.php?go=api
    Designed by: Garrett Gyssler (http://myanimelist.net/profile/Xinil)

    """
    name = 'libmal'

    username = ''  # TODO Must be filled by check_credentials
    logged_in = False
    opener = None

    api_info = {
        'name': 'MyAnimeList',
        'shortname': 'mal',
        'version': 'v0.3',
        'merge': False
    }

    default_mediatype = 'anime'
    mediatypes = dict()
    mediatypes['anime'] = {
        'has_progress': True,
        'can_add': True,
        'can_delete': True,
        'can_score': True,
        'can_status': True,
        'can_update': True,
        'can_play': True,
        'can_date': True,
        'status_start': 1,
        'status_finish': 2,
        'statuses': [1, 2, 3, 4, 6],
        'statuses_dict': {
            1: 'Watching',
            2: 'Completed',
            3: 'On Hold',
            4: 'Dropped',
            6: 'Plan to Watch'
        },
        'score_max': 10,
        'score_step': 1,
    }
    mediatypes['manga'] = {
        'has_progress': True,
        'can_add': True,
        'can_delete': True,
        'can_score': True,
        'can_status': True,
        'can_update': True,
        'can_play': False,
        'can_date': True,
        'status_start': 1,
        'status_finish': 2,
        'statuses': [1, 2, 3, 4, 6],
        'statuses_dict': {
            1: 'Reading',
            2: 'Completed',
            3: 'On Hold',
            4: 'Dropped',
            6: 'Plan to Read'
        },
        'score_max': 10,
        'score_step': 1,
    }

    # Authorized User-Agent for Trackma
    url = 'http://myanimelist.net/api/'
    useragent = 'api-team-f894427cc1c571f79da49605ef8b112f'

    def __init__(self, messenger, account, userconfig):
        """Initializes the useragent through credentials."""
        # Since MyAnimeList uses a cookie we just create a HTTP Auth handler
        # together with the urllib2 opener.
        super(libmal, self).__init__(messenger, account, userconfig)

        auth_string = 'Basic ' + base64.encodestring(
            '%s:%s' %
            (account['username'], account['password'])).replace('\n', '')

        self.username = self._get_userconfig('username')
        self.opener = urllib2.build_opener()
        self.opener.addheaders = [
            ('User-Agent', self.useragent),
            ('Authorization', auth_string),
        ]

    def _request(self, url):
        """
        Requests the page as gzip and uncompresses it

        Returns a stream object

        """
        try:
            request = urllib2.Request(url)
            request.add_header('Accept-Encoding', 'gzip')
            response = self.opener.open(request, timeout=10)
        except urllib2.HTTPError, e:
            if e.code == 401:
                raise utils.APIError(
                    "Unauthorized. Please check if your username and password are correct."
                    "\n\nPlease note that you might also be getting this error if you have "
                    "non-alphanumeric characters in your password due to an upstream "
                    "MAL bug (#138).")
            else:
                raise utils.APIError("HTTP error %d: %s" % (e.code, e.reason))
        except urllib2.URLError, e:
            raise utils.APIError("Connection error: %s" % e)
예제 #16
0
    def search(self, criteria):
        """Searches MyAnimeList database for the queried show"""
        self.msg.info(self.name, "Searching for %s..." % criteria)

        # Send the urlencoded query to the search API
        query = urllib.parse.urlencode({'q': criteria})
        data = self._request(self.url + self.mediatype + "/search.xml?" +
                             query)

        # Load the results into XML
        try:
            root = self._parse_xml(data)
        except ET.ParseError as e:
            if e.code == 3:
                # Empty document; no results
                return []
            else:
                raise utils.APIError("Parser error: %r" % e)
        except IOError:
            raise utils.APIError("IO error: %r" % e)

        # Use the correct tag name for episodes
        if self.mediatype == 'manga':
            episodes_str = 'chapters'
        else:
            episodes_str = 'episodes'

        # Since the MAL API returns the status as a string, and
        # we handle statuses as integers, we need to convert them
        if self.mediatype == 'anime':
            status_translate = {
                'Currently Airing': utils.STATUS_AIRING,
                'Finished Airing': utils.STATUS_FINISHED,
                'Not yet aired': utils.STATUS_NOTYET
            }
        elif self.mediatype == 'manga':
            status_translate = {
                'Publishing': utils.STATUS_AIRING,
                'Finished': utils.STATUS_AIRING
            }

        entries = list()
        for child in root.iter('entry'):
            show = utils.show()
            showid = int(child.find('id').text)
            show.update({
                'id':
                showid,
                'title':
                child.find('title').text,
                'type':
                child.find('type').text,
                'status':
                status_translate[child.find(
                    'status').text],  # TODO : This should return an int!
                'total':
                int(child.find(episodes_str).text),
                'image':
                child.find('image').text,
                'url':
                "https://myanimelist.net/anime/%d" % showid,
                'start_date':
                self._str2date(child.find('start_date').text),
                'end_date':
                self._str2date(child.find('end_date').text),
                'extra': [
                    ('English', child.find('english').text),
                    ('Synonyms', child.find('synonyms').text),
                    ('Synopsis',
                     self._translate_synopsis(child.find('synopsis').text)),
                    (episodes_str.title(), child.find(episodes_str).text),
                    ('Type', child.find('type').text),
                    ('Score', child.find('score').text),
                    ('Status', child.find('status').text),
                    ('Start date', child.find('start_date').text),
                    ('End date', child.find('end_date').text),
                ]
            })
            entries.append(show)

        self._emit_signal('show_info_changed', entries)
        return entries
예제 #17
0
    def fetch_list(self):
        """Queries the full list from the remote server.
        Returns the list if successful, False otherwise."""
        self.check_credentials()
        self.msg.info(self.name, 'Downloading list...')

        try:
            showlist = dict()
            infolist = list()

            # Get first page and continue from there
            params = {
                "filter[user_id]": self._get_userconfig('userid'),
                "filter[kind]": self.mediatype,
                #"include": self.mediatype, # TODO : This returns a 500 for some reason.
                "include": "media",
                # TODO : List for manga should be different
                "fields[anime]": "id,slug,canonicalTitle,titles,episodeCount,synopsis,subtype,posterImage,startDate,endDate",
                "page[limit]": "250",
            }

            url = "{}/library-entries?{}".format(self.prefix, urllib.parse.urlencode(params))
            i = 1

            while url:
                self.msg.info(self.name, 'Getting page {}...'.format(i))

                data = self._request('GET', url)
                data_json = json.loads(data)

                #print(json.dumps(data_json, sort_keys=True, indent=2))
                #return []

                entries = data_json['data']
                links = data_json['links']

                for entry in entries:
                    # TODO : Including the mediatype returns a 500 for some reason.
                    #showid = int(entry['relationships'][self.mediatype]['data']['id'])
                    showid = int(entry['relationships']['media']['data']['id'])
                    status = entry['attributes']['status']
                    rating = entry['attributes']['rating']

                    showlist[showid] = utils.show()
                    showlist[showid].update({
                        'id': showid,
                        'my_id': entry['id'],
                        'my_progress': entry['attributes']['progress'],
                        'my_score': float(rating) if rating is not None else 0.0,
                        'my_status': entry['attributes']['status'],
                        'my_start_date': self._iso2date(entry['attributes']['startedAt']),
                        'my_finish_date': self._iso2date(entry['attributes']['finishedAt']),
                    })

                if 'included' in data_json:
                    medias = data_json['included']
                    for media in medias:
                        info = self._parse_info(media)
                        infolist.append(info)

                    self._emit_signal('show_info_changed', infolist)

                url = links.get('next')
                i += 1

            return showlist
        except urllib.request.HTTPError as e:
            raise utils.APIError("Error getting list.")
예제 #18
0
class libshikimori(lib):
    """
    API class to communicate with Shikimori

    Website: http://shikimori.org

    messenger: Messenger object to send useful messages to
    """
    name = 'libshikimori'
    msg = None
    logged_in = False

    api_info = {
        'name': 'Shikimori',
        'shortname': 'shikimori',
        'version': '1',
        'merge': False
    }
    mediatypes = dict()
    mediatypes['anime'] = {
        'has_progress': True,
        'can_add': True,
        'can_delete': True,
        'can_score': True,
        'can_status': True,
        'can_update': True,
        'can_play': True,
        'status_start': 1,
        'status_finish': 2,
        'statuses': [1, 2, 3, 9, 4, 0],
        'statuses_dict': {
            1: 'Watching',
            2: 'Completed',
            3: 'On-Hold',
            9: 'Rewatching',
            4: 'Dropped',
            0: 'Plan to Watch'
        },
        'score_max': 10,
        'score_step': 1,
    }
    mediatypes['manga'] = {
        'has_progress': True,
        'can_add': True,
        'can_delete': True,
        'can_score': True,
        'can_status': True,
        'can_update': True,
        'can_play': False,
        'status_start': 1,
        'status_finish': 2,
        'statuses': [1, 2, 3, 9, 4, 0],
        'statuses_dict': {
            1: 'Reading',
            2: 'Completed',
            3: 'On-Hold',
            9: 'Rereading',
            4: 'Dropped',
            0: 'Plan to Read'
        },
        'score_max': 10,
        'score_step': 1,
    }
    default_mediatype = 'anime'

    # Supported signals for the data handler
    signals = {
        'show_info_changed': None,
    }

    url = "http://shikimori.org"

    def __init__(self, messenger, account, userconfig):
        """Initializes the API"""
        super(libshikimori, self).__init__(messenger, account, userconfig)

        self.username = account['username']
        self.password = account['password']
        self.userid = userconfig['userid']

        if not self.password:
            raise utils.APIFatal("No password.")

        if self.mediatype == 'manga':
            self.total_str = "chapters"
            self.watched_str = "chapters"
            self.airing_str = "publishing_status"
            self.status_translate = {
                'publishing': utils.STATUS_AIRING,
                'finished': utils.STATUS_FINISHED,
                'not yet published': utils.STATUS_NOTYET,
                'cancelled': utils.STATUS_CANCELLED,
            }
        else:
            self.total_str = "episodes"
            self.watched_str = "episodes"
            self.airing_str = "airing_status"
            self.status_translate = {
                'currently airing': utils.STATUS_AIRING,
                'finished airing': utils.STATUS_FINISHED,
                'not yet aired': utils.STATUS_NOTYET,
                'cancelled': utils.STATUS_CANCELLED,
            }

        #handler=urllib2.HTTPHandler(debuglevel=1)
        #self.opener = urllib2.build_opener(handler)
        self.opener = urllib2.build_opener()
        self.opener.addheaders = [('User-agent', 'Trackma/0.4')]

    def _request(self,
                 method,
                 url,
                 get=None,
                 post=None,
                 jsondata=None,
                 auth=False):
        if get:
            url = "{}?{}".format(url, urllib.urlencode(get))
        if post:
            post = urllib.urlencode(post)
        if jsondata:
            post = json.dumps(jsondata, separators=(',', ':'))

        request = urllib2.Request(self.url + url, post)
        request.get_method = lambda: method

        if auth:
            request.add_header('Content-Type', 'application/json')
            request.add_header('X-User-Nickname', self.username)
            request.add_header('X-User-Api-Access-Token',
                               self._get_userconfig('access_token'))

        try:
            response = self.opener.open(request, timeout=10)
            return json.load(response)
        except urllib2.HTTPError, e:
            if e.code == 400:
                raise utils.APIError("400")
            else:
                raise utils.APIError("Connection error: %s" % e)
        except socket.timeout:
            raise utils.APIError("Connection timed out.")