def part_to_relic_mapping(relic_info): """ DEPRECIATED Converts the relic_info dictionary into a part-first dictionary. return: { 'part': [ '$relic_name $rarity' ] } """ parts = {} for relic in relic_info: drops = relic_info[relic]['drops'] for i in range(len(drops)): part = utils.to_itemid(drops[i]) drop_rarity = '%s %s' % (relic, utils.idx_to_rarity(i)) if part in parts: parts[part].append(drop_rarity) else: parts[part] = [drop_rarity] return parts
async def add_wanted_part(client, message): raw_args = shlex.split(message.content)[1:] parser = utils.DiscordParser("!want") parser.add_argument('part', type=str, help="The wanted part name.") parser.add_argument('--unsafe', action='store_true', help="Do not check for item validity.") args = await parser.parse_args(client, message.channel, raw_args) item = args.part item_id = utils.to_itemid(item) user = message.author logger.info("item_id: %s, user: %s" % (item_id, user.name)) market_url = utils.warframe_market_url(item_id) if not args.unsafe: res = await utils.async_request(market_url) if args.unsafe or res.ok: parts_info = utils.get_json('part_info') drop_relic_list = parts_info.get(item_id) new_item = { 'item_id': item_id, 'user': user.name, 'userID': user.id, 'drop_list': drop_relic_list } wanted_list = utils.get_json('wanted_list') wanted_list.append(new_item) utils.save_json('wanted_list', wanted_list) logger.info("Adding part.") out_message = 'Adding ' + item_id + ' to wanted list for ' +\ user.name + '.' await client.send_message(message.channel, out_message) else: logger.warning("Bad item name or uncached item %s" % item_id) await client.send_message(message.channel, "Bad item id or uncached item.")
async def check_alerts(client, channel): logger.info("Checking for alerts.") wanted_list = utils.get_json('wanted_list') url = 'http://deathsnacks.com/wf/' req = await utils.async_request(url) if req.ok: ts = int(time.time()) soup = BeautifulSoup(req.text, 'html.parser') parts = soup.find( 'ul', {'class': ['list-group', 'alerts-container']})\ .find_all('span', {'class': 'badge'}) for soup_item in parts: item = soup_item.text if item.endswith(' Blueprint'): item = item[:-10] item_id = utils.to_itemid(item) users = [] usernames = [] for i in range(len(wanted_list)): want = wanted_list[i] if want['item_id'] == item_id: if (('last_updated' not in want) or # If within the same hour, probably the same alert. (ts - want['last_updated'] >= 60 * 60)): users.append(want['userID']) usernames.append(want['user']) wanted_list[i]['last_updated'] = ts if len(users) > 0: logger.info('Alert for %s, notifying %s' % (item_id, ', '.join(usernames))) for userID in users: user = await client.get_user_info(userID) await client.send_message( user, 'Alert for ' + item_id + '\nhttp://deathsnacks.com/wf/') utils.save_json('wanted_list', wanted_list) else: logger.error("Request for %s returned error code %s." % (url, req.status_code))
async def get_relic_info(relic_name): """ Gets relic information and caches it, if not already cached. Also helps mantain a parts list. """ logger.info("Fetching relic info for %s." % relic_name) relic_infos = utils.get_json('relic_info') if relic_name in relic_infos: return relic_infos[relic_name] logger.info("Relic not in database. Searching Wikia.") relic_url = "https://warframe.fandom.com/wiki/%s" \ % relic_name.replace(' ', '_') req = await utils.async_request(relic_url) if req.ok: soup = BeautifulSoup(req.text, 'html.parser') else: logger.error("Request to %s has response code %s." % (relic_url, req.status_code)) raise ValueError("Bad relic url.") relic_info = extract_relic_info(soup) # Cache. relic_infos[relic_name] = relic_info utils.save_json('relic_info', relic_infos) # Update parts mapping. part_info = utils.get_json('part_info') drops = relic_info['drops'] for i in range(len(drops)): part = utils.to_itemid(drops[i]) drop_rarity = '%s %s' % (relic, utils.idx_to_rarity(i)) if part in part_info: part_info[part].append(drop_rarity) else: part_info[part] = [drop_rarity]
async def remove_part(client, message): raw_args = shlex.split(message.content)[1:] parser = utils.DiscordParser("!remove") parser.add_argument('part', type=str, help='The part to remove.') args = await parser.parse_args(client, message.channel, raw_args) item = args.part item_id = utils.to_itemid(item) user = message.author logger.info("item_id: %s, user: %s" % (item_id, user.name)) wanted_list = utils.get_json('wanted_list') for i in range(len(wanted_list)): want = wanted_list[i] if want['userID'] == user.id and want['item_id'] == item_id: del wanted_list[i] utils.save_json('wanted_list', wanted_list) out_message = "Removed entry for part " + item_id +\ " for user " + user.name + "." logger.info("Part removed.") await client.send_message(message.channel, out_message) return # If nothing got deleted, then will end up here. logger.info("Could not find matching part for user.") out_message = "Could not find entry for part " + item_id +\ " for user " + user.name + "." await client.send_message(message.channel, out_message)
async def mod_info(client, message): raw_args = shlex.split(message.content)[1:] parser = utils.DiscordParser("!mod") parser.add_argument("mod", type=str, help="The requested mod.") args = await parser.parse_args(client, message.channel, raw_args) item_id = utils.to_itemid(args.mod) wikia_id = utils.to_wikiaid(item_id) url = 'http://warframe.wikia.com/wiki/' + wikia_id req = await utils.async_request(url) if req.ok: soup = BeautifulSoup(req.text, 'html.parser') image_url = soup.find('img', {'class': 'pi-image-thumbnail'})\ .attrs['src'] await client.send_message(message.channel, image_url) else: await client.send_message(message.channel, "Could not find mod %s." % item_id)
async def parts_info(client, message): raw_args = shlex.split(message.content)[1:] parser = utils.DiscordParser("!part") parser.add_argument("part", type=str, help="The requsted part.") args = await parser.parse_args(client, message.channel, raw_args) item = args.part item_id = utils.to_itemid(item) part_info = utils.get_json('part_info') if item_id in part_info: logging.info("Found relic info for %s." % item_id) await client.send_message( message.channel, 'Item ' + item_id + ' is dropped by ' + ', '.join(part_info[item_id]) + '.') url = utils.warframe_market_url(item_id) req = await utils.async_request(url) if req.ok: data = json.loads(req.text) prices = list(map(lambda x: x['platinum'], data['payload']['orders'])) median = sorted(prices)[len(prices) // 2] logging.info("Median price for %s is %s plat." % (item_id, median)) await client.send_message( message.channel, "Market price for " + item_id + ": " + str(median) + ' plat.') else: logging.info("Could not find item in warframe.market.") await client.send_message(message.channel, 'Bad item name "' + item + '".')
async def prime_info(client, message): raw_args = shlex.split(message.content)[1:] parser = utils.DiscordParser( "!info", description="Info and drop locations for prime items.") parser.add_argument("item", type=str, help="The requested weapon/warframe.") args = await parser.parse_args(client, message.channel, raw_args) item_id = utils.to_itemid(args.item) if not item_id.endswith('_prime'): item_id += '_prime' wikia_id = utils.to_wikiaid(item_id) url = 'http://warframe.wikia.com/wiki/' + wikia_id req = await utils.async_request(url) if req.ok: # try: soup = BeautifulSoup(req.text, 'html.parser') # Disambiguation between warframes and weapons. # Table rows. drop_table = soup.find('b', string='Drop Locations')\ .next.next.next warframe_table = drop_table.find('div', { 'class': 'tabbertab', 'title': 'PC' }) if warframe_table: table = warframe_table else: table = drop_table if not warframe_table: man_table = soup.find('table', {'class': 'foundrytable'}) mats_row = man_table.find_all('tr', recursive=False)[1] mats_soup = mats_row.find_all('td')[:5] mats_str = '\nRequired materials:\n' for mat_soup in mats_soup: if mat_soup.text.strip() == '': break mat = mat_soup.find('a').attrs['title'] mat_count = mat_soup.text.strip() mats_str += '\t%s: %s\n' % (mat, mat_count) trs = table.find_all('tr') message_str = 'Drop locations for %s:\n```\n' % item_id for tr in trs: td = tr.find_all('td') part = td[0].text.strip() drop_locations = \ BeautifulSoup( str(td[1]).replace('<br/>', '\n'), 'html.parser') \ .text.strip().split('\n') message_str += part + '\n' for drop_loc in drop_locations: message_str += '\t' + drop_loc + '\n' if not warframe_table: message_str += mats_str message_str += '```' await client.send_message(message.channel, message_str) else: await client.send_message(message.channel, "Could not find prime item %s." % item_id)