예제 #1
0
def site_resources(args: str) -> Dict[str, str]:
    results = {}
    match = re.match('^s? ?([0-9]*|all) +', args)
    if match:
        season_prefix = 'seasons/' + match.group(1)
        args = args.replace(match.group(0), '', 1).strip()
    else:
        season_prefix = ''
    if ' ' in args:
        area, detail = args.split(' ', 1)
    else:
        area, detail = args, ''
    if area == 'archetype':
        area = 'archetypes'
    if area == 'card':
        area = 'cards'
    if area == 'person':
        area = 'people'
    sitemap = fetcher.sitemap()
    matches = [
        endpoint for endpoint in sitemap
        if endpoint.startswith('/{area}/'.format(area=area))
    ]
    if len(matches) > 0:
        detail = '{detail}/'.format(
            detail=fetch_tools.escape(detail, True)) if detail else ''
        url = fetcher.decksite_url('{season_prefix}/{area}/{detail}'.format(
            season_prefix=season_prefix,
            area=fetch_tools.escape(area),
            detail=detail))
        results[url] = args
    return results
예제 #2
0
def times_from_location(q: str, twentyfour: bool) -> Dict[str, List[str]]:
    api_key = configuration.get('google_maps_api_key')
    if not api_key:
        raise NotConfiguredException('No value found for google_maps_api_key')
    url = 'https://maps.googleapis.com/maps/api/geocode/json?address={q}&key={api_key}&sensor=false'.format(
        q=fetch_tools.escape(q), api_key=api_key)
    info = fetch_tools.fetch_json(url)
    if 'error_message' in info:
        return info['error_message']
    try:
        location = info['results'][0]['geometry']['location']
    except IndexError as e:
        raise TooFewItemsException(e) from e
    url = 'https://maps.googleapis.com/maps/api/timezone/json?location={lat},{lng}&timestamp={timestamp}&key={api_key}&sensor=false'.format(
        lat=fetch_tools.escape(str(location['lat'])),
        lng=fetch_tools.escape(str(location['lng'])),
        timestamp=fetch_tools.escape(str(dtutil.dt2ts(dtutil.now()))),
        api_key=api_key)
    timezone_info = fetch_tools.fetch_json(url)
    if 'error_message' in timezone_info:
        return timezone_info['error_message']
    if timezone_info['status'] == 'ZERO_RESULTS':
        raise TooFewItemsException(timezone_info['status'])
    try:
        timezone = dtutil.timezone(timezone_info['timeZoneId'])
    except KeyError as e:
        raise TooFewItemsException(
            f'Unable to find a timezone in {timezone_info}') from e
    return {
        current_time(timezone, twentyfour):
        [info['results'][0]['formatted_address']]
    }
def scryfall_image(c: Card, version: str = '', face: str = None) -> str:
    if face == 'meld':
        name = c.names[1]
    elif ' // ' in c.name:
        name = c.name.replace(' // ', '/')
    else:
        name = c.name
    u = 'https://api.scryfall.com/cards/named?exact={c}&format=image'.format(
        c=escape(name))
    if version:
        u += '&version={v}'.format(v=escape(version))
    if face and face != 'meld':
        u += '&face={f}'.format(f=escape(face))
    return u
예제 #4
0
def search_scryfall(query: str) -> Tuple[int, List[str], List[str]]:
    """Returns a tuple. First member is an integer indicating how many cards match the query total,
       second member is a list of card names up to the maximum that could be fetched in a timely fashion."""
    if query == '':
        return 0, [], []
    print(f'Searching scryfall for `{query}`')
    result_json = fetch_tools.fetch_json(
        'https://api.scryfall.com/cards/search?q=' + fetch_tools.escape(query),
        character_encoding='utf-8')
    if 'code' in result_json.keys():  # The API returned an error
        if result_json['status'] == 404:  # No cards found
            return 0, [], []
        print('Error fetching scryfall data:\n', result_json)
        return 0, [], []
    for warning in result_json.get(
            'warnings', []):  # scryfall-provided human-readable warnings
        print(warning)
    result_data = result_json['data']
    result_data.sort(key=lambda x: x['legalities']['penny'])

    def get_frontside(scr_card: Dict) -> str:
        """If card is transform, returns first name. Otherwise, returns name.
        This is to make sure cards are later found in the database"""
        # not sure how to handle meld cards
        if scr_card['layout'] in ['transform', 'flip', 'modal_dfc']:
            return scr_card['card_faces'][0]['name']
        return scr_card['name']

    result_cardnames = [get_frontside(obj) for obj in result_data]
    return result_json['total_cards'], result_cardnames, result_json.get(
        'warnings', [])
예제 #5
0
def scryfall_image(c: Card, version: str = '', face: str = None) -> str:
    if face == 'meld':
        name = c.names[1]
    elif ' // ' in c.name:
        name = c.name.replace(' // ', '/')
    else:
        name = c.name
    p = oracle.get_printing(c, c.get('preferred_printing'))
    if p is not None:
        u = f'https://api.scryfall.com/cards/{p.set_code}/{p.number}?format=image'
    else:
        u = 'https://api.scryfall.com/cards/named?exact={c}&format=image'.format(c=escape(name))
    if version:
        u += '&version={v}'.format(v=escape(version))
    if face and face != 'meld':
        u += '&face={f}'.format(f=escape(face))
    return u
예제 #6
0
def card_rulings(c: Card) -> str:
    raw_rulings = fetcher.rulings(c.name)
    comments = [r['comment'] for r in raw_rulings]
    if len(comments) > 3:
        n = len(comments) - 2
        comments = comments[:2]
        comments.append(
            'And {n} others.  See <https://scryfall.com/search?q=%21%22{cardname}%22#rulings>'
            .format(n=n, cardname=fetch_tools.escape(c.name)))
    return '\n'.join(comments) or 'No rulings available.'
예제 #7
0
def search_scryfall(query: str,
                    exhaustive: bool = False) -> Tuple[int, List[str]]:
    """Returns a tuple. First member is an integer indicating how many cards match the query total,
       second member is a list of card names up to the maximum that could be fetched in a timely fashion.
       Supply exhaustive=True to instead retrieve the full list (potentially very slow)."""
    if query == '':
        return False, []
    redis_key = f'scryfall:query:{query}:' + ('exhaustive' if exhaustive else
                                              'nonexhaustive')
    cached = redis.get_list(redis_key)
    result_data: List[Dict]
    if cached:
        total_cards, result_data = int(cached[0]), cached[1]
    else:
        url = 'https://api.scryfall.com/cards/search?q=' + fetch_tools.escape(
            query)
        result_data = []
        while True:
            for _ in range(3):
                try:
                    result_json = fetch_tools.fetch_json(url)
                    break
                except FetchException as c:
                    print(c)
            if 'code' in result_json.keys():  # The API returned an error
                if result_json['status'] == 404:  # No cards found
                    return False, []
                print('Error fetching scryfall data:\n', result_json)
                return False, []
            for warning in result_json.get(
                    'warnings',
                []):  # scryfall-provided human-readable warnings
                print(warning)  # Why aren't we displaying these to the user?
            result_data += result_json['data']
            total_cards = int(result_json['total_cards'])
            if not exhaustive or len(result_data) >= total_cards:
                break
            sleep(0.1)
            url = result_json['next_page']
        redis.store(redis_key, [total_cards, result_data], ex=3600)
    result_data.sort(key=lambda x: x['legalities']['penny'])

    def get_frontside(scr_card: Dict) -> str:
        """If card is transform, returns first name. Otherwise, returns name.
        This is to make sure cards are later found in the database"""
        # not sure how to handle meld cards
        if scr_card['layout'] in [
                'transform', 'flip', 'adventure', 'modal_dfc'
        ]:
            return scr_card['card_faces'][0]['name']
        return scr_card['name']

    result_cardnames = [get_frontside(obj) for obj in result_data]
    return total_cards, result_cardnames
예제 #8
0
 def cardhoarder_url(
     self
 ) -> str:  # This should be a Deck, but we can't import it from here.
     d = self.deck
     cs: Dict[str, int] = {}
     for entry in d.maindeck + d.sideboard:
         name = entry.name
         cs[name] = cs.get(name, 0) + entry['n']
     deck_s = '||'.join([
         str(v) + ' ' + card.to_mtgo_format(k).replace('"', '')
         for k, v in cs.items()
     ])
     return 'https://www.cardhoarder.com/decks/upload?deck={deck}'.format(
         deck=fetch_tools.escape(deck_s))
예제 #9
0
def card_history(c: Card) -> str:
    data: Dict[int, bool] = {}
    for format_name, status in c.legalities.items():
        if 'Penny Dreadful ' in format_name and status == 'Legal':
            season_id = seasons.SEASONS.index(
                format_name.replace('Penny Dreadful ', '')) + 1
            data[season_id] = True
    data[seasons.current_season_num()] = c.legalities.get('Penny Dreadful', None) == 'Legal'
    s = '   '
    for i in range(1, seasons.current_season_num() + 1):
        s += f'{i} '
        s += ':white_check_mark:' if data.get(i, False) else ':no_entry_sign:'
        s += '   '
    s = s.strip()
    s += '\n<' + fetcher.decksite_url('/seasons/all/cards/{name}/'.format(
        name=fetch_tools.escape(c.name, skip_double_slash=True))) + '>'
    return s
예제 #10
0
def bluebones_image(cards: List[Card]) -> str:
    c = '|'.join(c.name for c in cards)
    return 'http://magic.bluebones.net/proxies/index2.php?c={c}'.format(
        c=escape(c))
예제 #11
0
async def buglink(ctx: MtgContext, *, c: Card) -> None:
    """Link to the modo-bugs page for a card."""
    base_url = 'https://github.com/PennyDreadfulMTG/modo-bugs/issues'
    if c is None:
        await ctx.send(base_url)
        return
    msg = '<{base_url}?utf8=%E2%9C%93&q=is%3Aissue+%22{name}%22>'.format(base_url=base_url, name=fetch_tools.escape(c.name))
    if not c.bugs or len(c.bugs) == 0:
        msg = "I don't know of a bug for {name} but here's the link: {link}".format(name=c.name, link=msg)
    await ctx.send(msg)