async def cardviewer_announce(session): if not flask.request.is_json: return flask.jsonify(message="Request not JSON"), 400 req = flask.request.get_json() cards = server.db.metadata.tables['cards'] card_multiverse = server.db.metadata.tables['card_multiverse'] query = sqlalchemy.select([cards.c.id, cards.c.name, cards.c.text]) if 'multiverseid' in req: query = query.select_from(cards.join(card_multiverse)).where( card_multiverse.c.id == req['multiverseid']) elif 'name' in req: name = cardname.to_query(req['name']) exact = cardname.clean_text(req['name']) hidden = False if 'variant' in req: name += escape_like("_" + req['variant']) exact += "_" + req['variant'] hidden = True exact_query = sqlalchemy.exists().where(cards.c.filteredname == exact) if not hidden: exact_query = exact_query.where(~cards.c.hidden) query = query.where((exact_query & (cards.c.filteredname == exact)) | (~exact_query & cards.c.filteredname.ilike(name))) if not hidden: query = query.where(~cards.c.hidden) elif 'host' in req or 'augment' in req: name = "" if 'augment' in req: name += cardname.to_query(req['augment']) + escape_like("_aug") if 'host' in req: name += ("_" if name != "" else "") + cardname.to_query( req['host']) + escape_like("_host") query = query.where(cards.c.filteredname.ilike(name)) else: return flask.jsonify(message=""), 400 with server.db.engine.begin() as conn: cards = conn.execute(query).fetchall() if len(cards) == 0: return flask.jsonify(message="No such card"), 400 elif len(cards) > 1: return flask.jsonify(message="Matched multiple cards"), 400 card_id, name, text = cards[0] await common.rpc.bot.cardviewer.announce(card_id) return flask.jsonify( name=name, text=text, )
async def cardviewer_announce(session): if not flask.request.is_json: return flask.jsonify(message="Request not JSON"), 400 req = flask.request.get_json() log.debug("Received cardviewer: %r", req) cards = server.db.metadata.tables['cards'] card_multiverse = server.db.metadata.tables['card_multiverse'] query = sqlalchemy.select([cards.c.id, cards.c.name, cards.c.text]) if 'multiverseid' in req: query = query.select_from(cards.join(card_multiverse)).where(card_multiverse.c.id == req['multiverseid']) elif 'name' in req: name = cardname.to_query(req['name']) exact = cardname.clean_text(req['name']) hidden = False if 'variant' in req: name += escape_like("_" + req['variant']) exact += "_" + req['variant'] hidden = True exact_query = sqlalchemy.exists().where(cards.c.filteredname == exact) if not hidden: exact_query = exact_query.where(~cards.c.hidden) query = query.where( (exact_query & (cards.c.filteredname == exact)) | (~exact_query & cards.c.filteredname.ilike(name))) if not hidden: query = query.where(~cards.c.hidden) elif 'host' in req or 'augment' in req: name = "" if 'augment' in req: name += cardname.to_query(req['augment']) + escape_like("_aug") if 'host' in req: name += ("_" if name != "" else "") + cardname.to_query(req['host']) + escape_like("_host") query = query.where(cards.c.filteredname.ilike(name)) else: return flask.jsonify(message=""), 400 with server.db.engine.begin() as conn: cards = conn.execute(query).fetchall() if len(cards) == 0: return flask.jsonify(message="No such card"), 400 elif len(cards) > 1: return flask.jsonify(message="Matched multiple cards"), 400 card_id, name, text = cards[0] await common.rpc.bot.cardviewer.announce(card_id) return flask.jsonify( name=name, text=text, )
def find_card(lrrbot, search, includehidden=False): cards = lrrbot.metadata.tables["cards"] card_multiverse = lrrbot.metadata.tables["card_multiverse"] card_collector = lrrbot.metadata.tables["card_collector"] if isinstance(search, int): query = (sqlalchemy.select([cards.c.name, cards.c.text]) .select_from(card_multiverse.join(cards, cards.c.id == card_multiverse.c.cardid)) .where(card_multiverse.c.id == search)) if not includehidden: query = query.where(cards.c.hidden == False) with lrrbot.engine.begin() as conn: return conn.execute(query).fetchall() if isinstance(search, tuple): query = (sqlalchemy.select([cards.c.name, cards.c.text]) .select_from(card_collector.join(cards, cards.c.id == card_collector.c.cardid)) .where((card_collector.c.setid == search[0].lower()) & (card_collector.c.collector == search[1]))) if not includehidden: query = query.where(cards.c.hidden == False) with lrrbot.engine.begin() as conn: return conn.execute(query).fetchall() cleansearch = clean_text(search) with lrrbot.engine.begin() as conn: query = sqlalchemy.select([cards.c.name, cards.c.text]).where(cards.c.filteredname == cleansearch) if not includehidden: query = query.where(cards.c.hidden == False) rows = conn.execute(query).fetchall() if rows: return rows searchwords = search.split() searchwords = [clean_text(i) for i in searchwords] searchlike = "%" + "%".join(common.postgres.escape_like(i) for i in searchwords) + "%" query = sqlalchemy.select([cards.c.name, cards.c.text]).where(cards.c.filteredname.like(searchlike)) if not includehidden: query = query.where(cards.c.hidden == False) return conn.execute(query).fetchall()
def process_card(card, expansion): if card.get('layout') == 'split': # Return split cards as a single card... for all the other pieces, return nothing if card['name'] != card['names'][0]: return None, None, None, None splits = [] for splitname in card['names']: candidates = [ i for i in expansion['cards'] if i['name'] == splitname ] if not candidates: print("Can't find split card piece: %s" % splitname) sys.exit(1) splits.append(candidates[0]) card = {} card['name'] = ' // '.join(s['name'] for s in splits) card['manaCost'] = ' // '.join(s['manaCost'] for s in splits) card['type'] = splits[0]['type'] # should be the same for all splits card['text'] = ' // '.join(s['text'] for s in splits) multiverseids = [ s['multiverseid'] for s in splits if s.get('multiverseid') ] elif card.get('layout') == 'flip': if card['name'] == card['names'][0] and card.get('multiverseid'): multiverseids = [card['multiverseid']] else: multiverseids = [] else: if card.get('multiverseid'): multiverseids = [card['multiverseid']] else: multiverseids = [] # sanitise card name name = clean_text(card["name"]) if not re_check.match(name): print("Still some junk left in name %s (%s)" % (card['name'], json.dumps(name))) sys.exit(1) def build_description(): yield card['name'] if 'manaCost' in card: yield ' [' yield re_mana.sub(r"\1", card['manaCost']) yield ']' if card.get('layout') == 'flip': if card['name'] == card['names'][0]: yield ' (flip: ' yield card['names'][1] yield ')' else: yield ' (unflip: ' yield card['names'][0] yield ')' elif card.get('layout') == 'double-faced': if card['name'] == card['names'][0]: yield ' (back: ' yield card['names'][1] yield ')' else: yield ' (front: ' yield card['names'][0] yield ')' elif card.get('layout') == 'meld': # Only the melded card in MTGJSON has all three cards in the 'names' field # The front-face cards only have [me, back] melded_card = [ i for i in expansion['cards'] if i['name'] == card['names'][-1] ] if not melded_card: print("Can't find melded card: %s" % card['names'][-1]) sys.exit(1) melded_card = melded_card[0] # MTGJSON doesn't have this field in a consistent order... # some cards have [top, bottom, back] some have [bottom, top, back] part_cards = [ i for i in expansion['cards'] if i['name'] in melded_card['names'][:-1] ] if len(part_cards) != 2: print("Can't find part-cards for melded card: %s" % melded_card['name']) sys.exit(1) if melded_card['number'][-1] != 'b': print("Melded card's number doesn't end in 'b': %s" % melded_card['name']) sys.exit(1) if part_cards[0]['number'] == melded_card['number'][:-1] + 'a': bottom_card, top_card = part_cards elif part_cards[1]['number'] == melded_card['number'][:-1] + 'a': top_card, bottom_card = part_cards else: print( "Couldn't figure out which card was top and bottom for: %s" % melded_card['name']) sys.exit(1) if card['name'] == top_card['name']: # The names of what this melds with and into are in the card text pass elif card['name'] == bottom_card['name']: yield ' (melds with: ' yield top_card['name'] yield '; into: ' yield melded_card['name'] yield ')' elif card['name'] == melded_card['name']: yield ' (melds from: ' yield top_card['name'] yield '; ' yield bottom_card['name'] yield ')' yield ' | ' yield card.get('type', '?Type missing?') if 'power' in card or 'toughness' in card: yield ' [' yield card.get('power', '?') yield '/' yield card.get('toughness', '?') yield ']' if 'loyalty' in card: yield ' [' yield str(card['loyalty']) yield ']' if 'hand' in card or 'life' in card: yield ' [hand:' yield str(card.get('hand', '?')) yield '/life:' yield str(card.get('life', '?')) yield ']' if 'text' in card: yield ' | ' yield re_newlines.sub( ' / ', re_remindertext.sub( lambda match: ' ' if match.group(1) and match.group(2) else '', card['text']).strip()) desc = ''.join(build_description()) desc = re_multiplespaces.sub(' ', desc).strip() if len(desc) > MAXLEN: desc = desc[:MAXLEN - 1] + "\u2026" return name, desc, multiverseids, card.get('number')
def process_single_card(card, expansion, include_reminder=False): # sanitise card name filtered = clean_text(card.get('internalname', card["name"])) if not re_check.match(filtered): print("Still some junk left in name %s (%s)" % (card.get('internalname', card["name"]), json.dumps(filtered))) print(json.dumps(card)) sys.exit(1) def build_description(): yield card['name'] if 'manaCost' in card: yield ' [' yield re_mana.sub(r"\1", card['manaCost']) yield ']' if card.get('layout') == 'flip': if card['name'] == card['names'][0]: yield ' (flip: ' yield card['names'][1] yield ')' else: yield ' (unflip: ' yield card['names'][0] yield ')' elif card.get('layout') == 'transform': if card['name'] == card['names'][0]: yield ' (back: ' yield card['names'][1] yield ')' else: yield ' (front: ' yield card['names'][0] yield ')' elif card.get('layout') == 'meld': card_a, melded_card, card_b = card['names'] if card['name'] in (card_a, card_b): # mtgjson is inconsistent as to which of these is which # check if "melds with cardname" is in the card text if card['name'] == card_a: other_card = card_b else: other_card = card_a if '(Melds with %s.)' % other_card in card['text']: yield ' (melds with: ' yield other_card yield '; into: ' yield melded_card yield ')' else: # The names of what this melds with and into are in the rules text pass elif card['name'] == melded_card: yield ' (melds from: ' yield card_a yield '; ' yield card_b yield ')' yield ' | ' yield card.get('type', '?Type missing?') if 'power' in card or 'toughness' in card: yield ' [' yield card.get('power', '?') yield '/' yield card.get('toughness', '?') yield ']' if 'loyalty' in card: yield ' [' yield str(card['loyalty']) yield ']' if 'hand' in card or 'life' in card: yield ' [hand: ' if 'hand' in card: yield card['hand'] else: yield "?" yield ', life: ' if 'life' in card: yield card['life'] else: yield "?" yield ']' if 'text' in card: yield ' | ' yield process_text(card['text'], include_reminder) desc = ''.join(build_description()) desc = re_multiplespaces.sub(' ', desc).strip() desc = utils.trim_length(desc) if card.get('layout') == 'flip' and card['name'] != card['names'][0]: multiverseids = numbers = [] else: if card.get('layout') == 'transform': if card['name'] == card['names'][0]: if card.get('number') and 'a' not in card['number'] and 'b' not in card['number']: card['number'] = [card['number'], card['number'] + 'a'] else: if card.get('number') and 'a' not in card['number'] and 'b' not in card['number']: card['number'] = card['number'] + 'b' card['foreignData'] = [] # mtgjson doesn't seem to have accurate foreign multiverse ids for back faces multiverseids = [card['multiverseId']] if card.get('multiverseId') else [] # disabling adding foreign multiverse ids unless we decide we want them for some reason # they add a lot of time to the running of this script #for lang in card.get('foreignData', []): # if lang.get('multiverseId'): # multiverseids.append(lang['multiverseId']) numbers = card['number'] if card.get('number') else [] if not isinstance(numbers, list): numbers = [numbers] hidden = 'internalname' in card # if a card has multiple variants, make "number" entries for the variants # to match what sort of thing we'd be seeing on scryfall if len(multiverseids) > 1 and len(numbers) == 1: orig_number = numbers[0] for i in range(len(multiverseids)): numbers.append(orig_number + chr(ord('a') + i)) numbers = [(expansion['code'].lower(), i) for i in numbers] return filtered, card['name'], desc, multiverseids, numbers, hidden
def process_single_card(card, expansion, include_reminder=False): # sanitise card name filtered = clean_text(card.get('internalname', card["name"])) if not re_check.match(filtered): print("Still some junk left in name %s (%s)" % (card.get('internalname', card["name"]), json.dumps(filtered))) print(json.dumps(card)) sys.exit(1) def build_description(): yield card['name'] if 'manaCost' in card: yield ' [' yield re_mana.sub(r"\1", card['manaCost']) yield ']' if card.get('layout') == 'flip': if card['name'] == card['names'][0]: yield ' (flip: ' yield card['names'][1] yield ')' else: yield ' (unflip: ' yield card['names'][0] yield ')' elif card.get('layout') == 'double-faced': if card['name'] == card['names'][0]: yield ' (back: ' yield card['names'][1] yield ')' else: yield ' (front: ' yield card['names'][0] yield ')' elif card.get('layout') == 'meld': top_card, bottom_card, melded_card = card['names'] if card['name'] == top_card: # The names of what this melds with and into are in the card text pass elif card['name'] == bottom_card: yield ' (melds with: ' yield top_card yield '; into: ' yield melded_card yield ')' elif card['name'] == melded_card: yield ' (melds from: ' yield top_card yield '; ' yield bottom_card yield ')' yield ' | ' yield card.get('type', '?Type missing?') if 'power' in card or 'toughness' in card: yield ' [' yield card.get('power', '?') yield '/' yield card.get('toughness', '?') yield ']' if 'loyalty' in card: yield ' [' yield str(card['loyalty']) yield ']' if 'hand' in card or 'life' in card: yield ' [hand: ' if 'hand' in card: yield "%+d" % card['hand'] else: yield "?" yield ', life: ' if 'life' in card: yield "%+d" % card['life'] else: yield "?" yield ']' if 'text' in card: yield ' | ' text = card['text'] # Let Un-set cards keep their reminder text, since there's joeks in there if not include_reminder: text = re_remindertext.sub( lambda match: ' ' if match.group(1) and match.group(2) else '', text) yield re_newlines.sub(' / ', text.strip()) desc = ''.join(build_description()) desc = re_multiplespaces.sub(' ', desc).strip() desc = utils.trim_length(desc) if card.get('layout') == 'flip' and card['name'] != card['names'][0]: multiverseids = numbers = [] else: multiverseids = [card['multiverseid'] ] if card.get('multiverseid') else [] if card.get('variations'): multiverseids.extend(card['variations']) numbers = card['number'] if card.get('number') else [] if not isinstance(numbers, list): numbers = [numbers] hidden = 'internalname' in card # if a card has multiple variants, make "number" entries for the variants # to match what sort of thing we'd be seeing on scryfall if len(multiverseids) > 1 and len(numbers) == 1: orig_number = numbers[0] for i in range(len(multiverseids)): numbers.append(orig_number + chr(ord('a') + i)) numbers = [(expansion['code'].lower(), i) for i in numbers] return filtered, card['name'], desc, multiverseids, numbers, hidden
def process_card(card, expansion): if card.get('layout') == 'split': # Return split cards as a single card... for all the other pieces, return nothing if card['name'] != card['names'][0]: return None, None, None, None splits = [] for splitname in card['names']: candidates = [i for i in expansion['cards'] if i['name'] == splitname] if not candidates: print("Can't find split card piece: %s" % splitname) sys.exit(1) splits.append(candidates[0]) card = {} card['name'] = ' // '.join(s['name'] for s in splits) card['manaCost'] = ' // '.join(s['manaCost'] for s in splits) card['type'] = splits[0]['type'] # should be the same for all splits card['text'] = ' // '.join(s['text'] for s in splits) multiverseids = [s['multiverseid'] for s in splits if s.get('multiverseid')] elif card.get('layout') == 'flip': if card['name'] == card['names'][0] and card.get('multiverseid'): multiverseids = [card['multiverseid']] else: multiverseids = [] else: if card.get('multiverseid'): multiverseids = [card['multiverseid']] else: multiverseids = [] # sanitise card name name = clean_text(card["name"]) if not re_check.match(name): print("Still some junk left in name %s (%s)" % (card['name'], json.dumps(name))) sys.exit(1) def build_description(): yield card['name'] if 'manaCost' in card: yield ' [' yield re_mana.sub(r"\1", card['manaCost']) yield ']' if card.get('layout') == 'flip': if card['name'] == card['names'][0]: yield ' (flip: ' yield card['names'][1] yield ')' else: yield ' (unflip: ' yield card['names'][0] yield ')' elif card.get('layout') == 'double-faced': if card['name'] == card['names'][0]: yield ' (back: ' yield card['names'][1] yield ')' else: yield ' (front: ' yield card['names'][0] yield ')' elif card.get('layout') == 'meld': if card['name'] == card['names'][0]: # The names of what this melds with and into are in the card text pass elif card['name'] == card['names'][1]: yield ' (melds with: ' yield card['names'][0] yield '; into: ' yield card['names'][2] yield ')' elif card['name'] == card['names'][2]: yield ' (melds from: ' yield card['names'][0] yield '; ' yield card['names'][1] yield ')' yield ' | ' yield card.get('type', '?Type missing?') if 'power' in card or 'toughness' in card: yield ' [' yield card.get('power', '?') yield '/' yield card.get('toughness', '?') yield ']' if 'loyalty' in card: yield ' [' yield str(card['loyalty']) yield ']' if 'hand' in card or 'life' in card: yield ' [hand:' yield str(card.get('hand', '?')) yield '/life:' yield str(card.get('life', '?')) yield ']' if 'text' in card: yield ' | ' yield re_newlines.sub(' / ', re_remindertext.sub('', card['text']).strip()) desc = ''.join(build_description()) desc = re_multiplespaces.sub(' ', desc).strip() if len(desc) > MAXLEN: desc = desc[:MAXLEN-1] + "\u2026" return name, desc, multiverseids, card.get('number')