#!/usr/bin/env python # coding=utf-8 # # This file is part of aDBa. # # aDBa is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # aDBa is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with aDBa. If not, see <http://www.gnu.org/licenses/>. from random import shuffle class AniDBMaper: blacklist = ('unused', 'retired', 'reserved') def getAnimeBitsA(self, amask): map = self.getAnimeMapA() return self._getBitChain(map, amask) def getAnimeCodesA(self, aBitChain): amap = self.getAnimeMapA() return self._getCodes(amap, aBitChain) def getFileBitsF(self, fmask): fmap = self.getFileMapF() return self._getBitChain(fmap, fmask) def getFileCodesF(self, bitChainF): fmap = self.getFileMapF() return self._getCodes(fmap, bitChainF) def getFileBitsA(self, amask): amap = self.getFileMapA() return self._getBitChain(amap, amask) def getFileCodesA(self, bitChainA): amap = self.getFileMapA() return self._getCodes(amap, bitChainA) def _getBitChain(self, map, wanted): """Return an hex string with the correct bit set corresponding to the wanted fields in the map """ bit = 0 for index, field in enumerate(map): if field in wanted and field not in self.blacklist: bit ^= 1 << len(map) - index - 1 bit = str(hex(bit)).lstrip("0x").rstrip("L") bit = ''.join(["0" for unused in range(int(len(map) / 4) - len(bit))]) + bit return bit @staticmethod def _getCodes(map, bit_chain): """Returns a list with the corresponding fields as set in the bitChain (hex string) """ code_list = [] bit_chain = int(bit_chain, 16) map_length = len(map) for i in reversed(list(range(map_length))): if bit_chain & (2 ** i): code_list.append(map[map_length - i - 1]) return code_list @staticmethod def getAnimeMapA(): # each line is one byte # only chnage this if the api changes map = ['aid', 'unused', 'year', 'type', 'related_aid_list', 'related_aid_type', 'category_list', 'category_weight_list', 'romaji_name', 'kanji_name', 'english_name', 'other_name', 'short_name_list', 'synonym_list', 'retired', 'retired', 'episodes', 'highest_episode_number', 'special_ep_count', 'air_date', 'end_date', 'url', 'picname', 'category_id_list', 'rating', 'vote_count', 'temp_rating', 'temp_vote_count', 'average_review_rating', 'review_count', 'award_list', 'is_18_restricted', 'anime_planet_id', 'ANN_id', 'allcinema_id', 'AnimeNfo_id', 'unused', 'unused', 'unused', 'date_record_updated', 'character_id_list', 'creator_id_list', 'main_creator_id_list', 'main_creator_name_list', 'unused', 'unused', 'unused', 'unused', 'specials_count', 'credits_count', 'other_count', 'trailer_count', 'parody_count', 'unused', 'unused', 'unused'] return map @staticmethod def getFileMapF(): # each line is one byte # only chnage this if the api changes map = ['unused', 'aid', 'eid', 'gid', 'mylist_id', 'list_other_episodes', 'IsDeprecated', 'state', 'size', 'ed2k', 'md5', 'sha1', 'crc32', 'unused', 'unused', 'reserved', 'quality', 'source', 'audio_codec_list', 'audio_bitrate_list', 'video_codec', 'video_bitrate', 'video_resolution', 'file_type_extension', 'dub_language', 'sub_language', 'length_in_seconds', 'description', 'aired_date', 'unused', 'unused', 'anidb_file_name', 'mylist_state', 'mylist_filestate', 'mylist_viewed', 'mylist_viewdate', 'mylist_storage', 'mylist_source', 'mylist_other', 'unused'] return map @staticmethod def getFileMapA(): # each line is one byte # only chnage this if the api changes map = ['anime_total_episodes', 'highest_episode_number', 'year', 'type', 'related_aid_list', 'related_aid_type', 'category_list', 'reserved', 'romaji_name', 'kanji_name', 'english_name', 'other_name', 'short_name_list', 'synonym_list', 'retired', 'retired', 'epno', 'ep_name', 'ep_romaji_name', 'ep_kanji_name', 'episode_rating', 'episode_vote_count', 'unused', 'unused', 'group_name', 'group_short_name', 'unused', 'unused', 'unused', 'unused', 'unused', 'date_aid_record_updated'] return map def checkMapping(self, verbos=False): print("------") print("File F: " + str(self.checkMapFileF(verbos))) print("------") print("File A: " + str(self.checkMapFileA(verbos))) def checkMapFileF(self, verbos=False): get_general_map = self.getFileMapF get_bits = self.getFileBitsF get_codes = self.getFileCodesF return self._checkMapGeneral(get_general_map, get_bits, get_codes, verbos=verbos) def checkMapFileA(self, verbos=False): get_general_map = self.getFileMapA get_bits = self.getFileBitsA get_codes = self.getFileCodesA return self._checkMapGeneral(get_general_map, get_bits, get_codes, verbos=verbos) def _checkMapGeneral(self, getGeneralMap, getBits, getCodes, verbos=False): map = getGeneralMap() shuffle(map) mask = [elem for elem in map if elem not in self.blacklist][:5] bits = getBits(mask) mask_re = getCodes(bits) bits_re = getBits(mask_re) if verbos: print(mask) print(mask_re) print(bits) print(bits_re) print("bits are:" + str((bits_re == bits))) print("map is :" + str((sorted(mask_re) == sorted(mask)))) return (bits_re == bits) and sorted(mask_re) == sorted(mask)