Esempio n. 1
0
 def __init__(self) -> None:
     super().__init__()
     self.playability = card.playability()
     until_full_rotation = rotation.next_rotation() - dtutil.now()
     until_supplemental_rotation = rotation.next_supplemental(
     ) - dtutil.now()
     in_rotation = False
     if until_full_rotation < datetime.timedelta(7):
         in_rotation = True
         self.rotation_msg = 'Full rotation is in progress, ends ' + dtutil.display_date(
             rotation.next_rotation(), 2)
     elif until_supplemental_rotation < datetime.timedelta(7):
         in_rotation = True
         self.rotation_msg = 'Supplemental rotation is in progress, ends ' + dtutil.display_date(
             rotation.next_supplemental(), 2)
     elif until_full_rotation < until_supplemental_rotation:
         self.rotation_msg = 'Full rotation is ' + dtutil.display_date(
             rotation.next_rotation(), 2)
     else:
         self.rotation_msg = 'Supplemental rotation is ' + dtutil.display_date(
             rotation.next_supplemental(), 2)
     self.cards: List[Card] = []
     if in_rotation:
         self.read_rotation_files()
     self.show_interesting = True
Esempio n. 2
0
 def __init__(self, interestingness: Optional[str] = None, rotation_query: Optional[str] = None, only_these: Optional[List[str]] = None) -> None:
     super().__init__()
     self.playability = card.playability()
     until_full_rotation = rotation.next_rotation() - dtutil.now()
     until_supplemental_rotation = rotation.next_supplemental() - dtutil.now()
     in_rotation = configuration.get_bool('always_show_rotation')
     if until_full_rotation < datetime.timedelta(7):
         in_rotation = True
         self.rotation_msg = 'Full rotation is in progress, ends ' + dtutil.display_date(rotation.next_rotation(), 2)
     elif until_supplemental_rotation < datetime.timedelta(7):
         in_rotation = True
         self.rotation_msg = 'Supplemental rotation is in progress, ends ' + dtutil.display_date(rotation.next_supplemental(), 2)
     elif until_full_rotation < until_supplemental_rotation:
         self.rotation_msg = 'Full rotation is ' + dtutil.display_date(rotation.next_rotation(), 2)
     else:
         self.rotation_msg = 'Supplemental rotation is ' + dtutil.display_date(rotation.next_supplemental(), 2)
     self.cards: List[Card] = []
     if in_rotation:
         self.read_rotation_files()
     self.show_interesting = True
     if interestingness:
         self.cards = [c for c in self.cards if c.get('interestingness') == interestingness]
     if only_these:
         self.cards = [c for c in self.cards if c.name in only_these]
     self.num_cards = len(self.cards)
     self.rotation_query = rotation_query or ''
Esempio n. 3
0
def determine_end_of_league(start_date):
    if start_date.day < 15:
        month = start_date.month + 1
    else:
        month = start_date.month + 2
    if month > 12:
        year = start_date.year + 1
        month = month - 12
    else:
        year = start_date.year
    end_date_s = '{year}-{month}-01 00:00:00'.format(year=year, month=month)
    end_date = dtutil.parse(end_date_s, '%Y-%m-%d %H:%M:%S', dtutil.WOTC_TZ)
    if end_date > rotation.next_rotation():
        end_date = rotation.next_rotation()
    return end_date - datetime.timedelta(seconds=1)
Esempio n. 4
0
 async def background_task_rotation_hype(self) -> None:
     rotation_hype_channel_id = configuration.get_int(
         'rotation_hype_channel_id')
     if not rotation_hype_channel_id:
         logging.warning('rotation hype channel is not configured')
         return
     channel = self.get_channel(rotation_hype_channel_id)
     if not isinstance(channel, discord.abc.Messageable):
         logging.warning('rotation hype channel is not a text channel')
         return
     while self.is_ready():
         until_rotation = rotation.next_rotation() - dtutil.now()
         last_run_time = rotation.last_run_time()
         if until_rotation < datetime.timedelta(
                 7) and last_run_time is not None:
             if dtutil.now() - last_run_time < datetime.timedelta(
                     minutes=5):
                 hype = await rotation_hype_message()
                 if hype:
                     await channel.send(hype)
             timer = 5 * 60
         else:
             timer = int(
                 (until_rotation - datetime.timedelta(7)).total_seconds())
         await asyncio.sleep(timer)
Esempio n. 5
0
 def __init__(self):
     until_full_rotation = rotation.next_rotation() - dtutil.now()
     until_supplemental_rotation = rotation.next_supplemental() - dtutil.now()
     in_rotation = False
     if until_full_rotation < datetime.timedelta(7):
         in_rotation = True
         self.rotation_msg = 'Full rotation is in progress, ends ' + dtutil.display_date(rotation.next_rotation(), 2)
     elif until_supplemental_rotation < datetime.timedelta(7):
         in_rotation = True
         self.rotation_msg = 'Supplemental rotation is in progress, ends ' + dtutil.display_date(rotation.next_supplemental(), 2)
     elif until_full_rotation < until_supplemental_rotation:
         self.rotation_msg = 'Full rotation is ' + dtutil.display_date(rotation.next_rotation(), 2)
     else:
         self.rotation_msg = 'Supplemental rotation is ' + dtutil.display_date(rotation.next_supplemental(), 2)
     if in_rotation:
         self.read_rotation_files()
     self.show_interesting = True
Esempio n. 6
0
 async def rotation(self, bot, channel):
     """`!rotation` Give the date of the next Penny Dreadful rotation."""
     next_rotation = rotation.next_rotation()
     now = dtutil.now()
     if next_rotation > now:
         diff = next_rotation - now
         msg = "The next rotation is in {diff}".format(diff=dtutil.display_time(diff.total_seconds()))
         await bot.client.send_message(channel, msg)
Esempio n. 7
0
 def setup_rotation(self) -> None:
     self.season_start_display = dtutil.display_date(
         rotation.last_rotation())
     self.season_end_display = dtutil.display_date(rotation.next_rotation())
     self.scryfall_url = 'https://scryfall.com/search?q=f%3Apd'
     self.legal_cards_url = 'http://pdmtgo.com/legal_cards.txt'
     self.in_rotation = rotation.in_rotation()
     self.rotation_msg = 'Rotation is in progress.'
     self.rotation_url = url_for('rotation')
Esempio n. 8
0
def admin_menu() -> List[Dict[str, str]]:
    m = []
    endpoints = sorted([rule.endpoint for rule in APP.url_map.iter_rules() if 'GET' in rule.methods and rule.rule.startswith('/admin')])
    for endpoint in endpoints:
        name = titlecase.titlecase(endpoint.replace('_', ' ')) if endpoint else 'Admin Home'
        m.append({'name': name, 'endpoint': endpoint, 'url': url_for(endpoint)})
    if (rotation.next_rotation() - dtutil.now()) < datetime.timedelta(7):
        m.append({'name': gettext('Rotation Tracking'), 'endpoint': 'rotation'})
    m.append({'name': gettext('Rotation Speculation'), 'endpoint': 'rotation_speculation'})
    return m
Esempio n. 9
0
def rotation_api():
    now = dtutil.now()
    diff = rotation.next_rotation() - now
    result = {
        "last": rotation.last_rotation_ex(),
        "next": rotation.next_rotation_ex(),
        "diff": diff.total_seconds(),
        "friendly_diff": dtutil.display_time(diff.total_seconds())
    }
    return return_json(result)
Esempio n. 10
0
def rotation_api() -> Response:
    now = dtutil.now()
    diff = rotation.next_rotation() - now
    result = {
        'last': rotation.last_rotation_ex(),
        'next': rotation.next_rotation_ex(),
        'diff': diff.total_seconds(),
        'friendly_diff': dtutil.display_time(diff.total_seconds())
    }
    return return_json(result)
Esempio n. 11
0
def build_menu() -> List[Dict[str, Union[str, Dict[str, str]]]]:
    archetypes_badge = None
    archetypes_badge = {'url': url_for('edit_archetypes'), 'text': '', 'badge_class': 'edit_archetypes'}
    resources_submenu: List[Dict[str, str]] = []
    if (rotation.next_rotation() - dtutil.now()) < datetime.timedelta(7) or (rotation.next_supplemental() - dtutil.now()) < datetime.timedelta(7):
        resources_submenu += [{'name': gettext('Rotation Tracking'), 'url': url_for('rotation')}]
    resources_submenu += [
        {'name': gettext('Rotation Changes'), 'url': url_for('rotation_changes')},
        {'name': gettext('Rotation Speculation'), 'url': url_for('rotation_speculation')},
        {'name': gettext('Deck Check'), 'url': url_for('deck_check')},
        {'name': gettext('Discord Chat'), 'url': 'https://discord.gg/H6EHdHu'},
        {'name': gettext('External Links'), 'url': url_for('resources')},
        {'name': gettext('Link Accounts'), 'url': url_for('link')},
        {'name': gettext('Bugs'), 'url': url_for('bugs')}
    ]
    menu = [
        {'name': gettext('Metagame'), 'url': url_for('home'), 'badge': archetypes_badge, 'submenu': [
            {'name': gettext('Latest Decks'), 'url': url_for('.decks')},
            {'name': gettext('Archetypes'), 'url': url_for('archetypes'), 'badge': archetypes_badge},
            {'name': gettext('People'), 'url': url_for('people')},
            {'name': gettext('Cards'), 'url': url_for('cards')},
            {'name': gettext('Past Seasons'), 'url': url_for('seasons')},
            {'name': gettext('Matchups'), 'url': url_for('matchups')},
        ]},
        {'name': gettext('League'), 'url': url_for('league'), 'submenu': [
            {'name': gettext('League Info'), 'url': url_for('league')},
            {'name': gettext('Sign Up'), 'url': url_for('signup')},
            {'name': gettext('Report'), 'url': url_for('report')},
            {'name': gettext('Records'), 'url': url_for('current_league')},
            {'name': gettext('Retire'), 'url': url_for('retire')},
        ]},
        {'name': gettext('Competitions'), 'url': url_for('competitions'), 'submenu': [
            {'name': gettext('Competition Results'), 'url': url_for('competitions')},
            {'name': gettext('Tournament Info'), 'url': url_for('tournaments')},
            {'name': gettext('Leaderboards'), 'url': url_for('tournament_leaderboards')},
            {'name': gettext('Gatherling'), 'url': 'https://gatherling.one/'},
            {'name': gettext('Achievements'), 'url': url_for('achievements')},
            {'name': gettext('Hosting'), 'url': url_for('hosting')}
        ]},
        {'name': gettext('Resources'), 'url': url_for('resources'), 'submenu': resources_submenu},
        {'name': gettext('About'), 'url': url_for('about'), 'submenu': [
            {'name': gettext('What is Penny Dreadful?'), 'url': url_for('about')},
            {'name': gettext('About pennydreadfulmagic.com'), 'url': url_for('about_pdm')},
            {'name': gettext('FAQs'), 'url': url_for('faqs')},
            {'name': gettext('Community Guidelines'), 'url': url_for('community_guidelines')}
        ]},
        {'name': gettext('Admin'), 'admin_only': True, 'url': url_for('admin_home'), 'submenu': admin.admin_menu()}
    ]
    for item in menu:
        item['has_submenu'] = item.get('submenu') is not None
        item['is_external'] = item.get('url', '').startswith('http') and '://pennydreadfulmagic.com/' not in item['url']
        for subitem in item.get('submenu', []):
            subitem['is_external'] = subitem.get('url', '').startswith('http') and '://pennydreadfulmagic.com/' not in subitem['url']
    return menu
Esempio n. 12
0
 def menu(self):
     archetypes_badge = None
     if session.get('admin') is True:
         n = len(deck.load_decks('NOT d.reviewed'))
         if n > 0:
             archetypes_badge = {
                 'url': url_for('edit_archetypes'),
                 'text': n
             }
     menu = [{
         'name': 'Decks',
         'url': url_for('home')
     }, {
         'name': 'Competitions',
         'url': url_for('competitions')
     }, {
         'name': 'People',
         'url': url_for('people')
     }, {
         'name': 'Cards',
         'url': url_for('cards')
     }, {
         'name': 'Archetypes',
         'url': url_for('archetypes'),
         'badge': archetypes_badge
     }, {
         'name': 'Resources',
         'url': url_for('resources')
     }]
     if (rotation.next_rotation() - dtutil.now()) < datetime.timedelta(7):
         menu += [{'name': 'Rotation', 'url': url_for('rotation')}]
     menu += [{
         'name': 'About',
         'url': url_for('about')
     }, {
         'name':
         'League',
         'url':
         url_for('league'),
         'has_submenu':
         True,
         'submenu': [{
             'name': 'Sign Up',
             'url': url_for('signup')
         }, {
             'name': 'Report',
             'url': url_for('report')
         }, {
             'name': 'Records',
             'url': url_for('current_league')
         }]
     }]
     return menu
def build_menu() -> List[Dict[str, Union[str, Dict[str, str]]]]:
    current_template = (request.endpoint or '').replace('seasons.', '')
    archetypes_badge = {'endpoint': 'edit_archetypes', 'text': '', 'badge_class': 'edit_archetypes'}
    resources_submenu: List[Dict[str, str]] = []
    if (rotation.next_rotation() - dtutil.now()) < datetime.timedelta(7) or (rotation.next_supplemental() - dtutil.now()) < datetime.timedelta(7):
        resources_submenu += [{'name': gettext('Rotation Tracking'), 'endpoint': 'rotation'}]
    resources_submenu += [
        {'name': gettext('Rotation Changes'), 'endpoint': 'rotation_changes'},
        {'name': gettext('Rotation Speculation'), 'endpoint': 'rotation_speculation'},
        {'name': gettext('Deck Check'), 'endpoint': 'deck_check'},
        {'name': gettext('Discord Chat'), 'url': 'https://discord.gg/H6EHdHu'},
        {'name': gettext('External Links'), 'endpoint': 'resources'},
        {'name': gettext('Link Accounts'), 'endpoint': 'link'},
        {'name': gettext('Bugs'), 'endpoint': 'bugs'}
    ]
    menu = [
        {'name': gettext('Metagame'), 'endpoint': 'home', 'badge': archetypes_badge, 'submenu': [
            {'name': gettext('Decks'), 'endpoint': '.decks'},
            {'name': gettext('Archetypes'), 'endpoint': 'archetypes', 'badge': archetypes_badge},
            {'name': gettext('People'), 'endpoint': 'people'},
            {'name': gettext('Cards'), 'endpoint': 'cards'},
            {'name': gettext('Past Seasons'), 'endpoint': 'seasons'},
            {'name': gettext('Matchups'), 'endpoint': 'matchups'},
        ]},
        {'name': gettext('League'), 'endpoint': 'league', 'submenu': [
            {'name': gettext('League Info'), 'endpoint': 'league'},
            {'name': gettext('Sign Up'), 'endpoint': 'signup'},
            {'name': gettext('Report'), 'endpoint': 'report'},
            {'name': gettext('Records'), 'endpoint': 'current_league'},
            {'name': gettext('Retire'), 'endpoint': 'retire'},
        ]},
        {'name': gettext('Competitions'), 'endpoint': 'competitions', 'submenu': [
            {'name': gettext('Competition Results'), 'endpoint': 'competitions'},
            {'name': gettext('Tournament Info'), 'endpoint': 'tournaments'},
            {'name': gettext('Leaderboards'), 'endpoint': 'tournament_leaderboards'},
            {'name': gettext('Gatherling'), 'url': 'https://gatherling.com/'},
            {'name': gettext('Achievements'), 'endpoint': 'achievements'},
            {'name': gettext('Hosting'), 'endpoint': 'hosting'}
        ]},
        {'name': gettext('Resources'), 'endpoint': 'resources', 'submenu': resources_submenu},
        {'name': gettext('About'), 'endpoint': 'about', 'submenu': [
            {'name': gettext('What is Penny Dreadful?'), 'endpoint': 'about'},
            {'name': gettext('About pennydreadfulmagic.com'), 'endpoint': 'about_pdm'},
            {'name': gettext('FAQs'), 'endpoint': 'faqs'},
            {'name': gettext('Community Guidelines'), 'endpoint': 'community_guidelines'}
        ]},
        {'name': gettext('Admin'), 'admin_only': True, 'endpoint': 'admin_home', 'submenu': admin.admin_menu()}
    ]
    setup_links(menu)
    for item in menu:
        item['current'] = item.get('endpoint', '').replace('seasons', '').replace('.', '') == current_template or current_template in [entry.get('endpoint', '') for entry in item.get('submenu', [])]
        item['has_submenu'] = item.get('submenu') is not None
    return menu
Esempio n. 14
0
def active_league() -> competition.Competition:
    where = 'c.id = ({id_query})'.format(id_query=active_competition_id_query())
    leagues = competition.load_competitions(where)
    if len(leagues) == 0:
        start_date = dtutil.now(tz=dtutil.WOTC_TZ)
        end_date = determine_end_of_league(start_date, rotation.next_rotation())
        name = determine_league_name(start_date, end_date)
        comp_id = competition.get_or_insert_competition(start_date, end_date, name, 'League', None, competition.Top.EIGHT)
        if not comp_id:
            raise InvalidDataException(f'No competition id with {start_date}, {end_date}, {name}')
        leagues = [competition.load_competition(comp_id)]
    return guarantee.exactly_one(leagues)
Esempio n. 15
0
 def __init__(self, interestingness: Optional[str] = None, query: Optional[str] = '') -> None:
     super().__init__()
     until_full_rotation = rotation.next_rotation() - dtutil.now()
     until_supplemental_rotation = rotation.next_supplemental() - dtutil.now()
     in_rotation = configuration.get_bool('always_show_rotation')
     if until_full_rotation < datetime.timedelta(7):
         in_rotation = True
         self.rotation_msg = 'Full rotation is in progress, ends ' + dtutil.display_date(rotation.next_rotation(), 2)
     elif until_supplemental_rotation < datetime.timedelta(7):
         in_rotation = True
         self.rotation_msg = 'Supplemental rotation is in progress, ends ' + dtutil.display_date(rotation.next_supplemental(), 2)
     elif until_full_rotation < until_supplemental_rotation:
         self.rotation_msg = 'Full rotation is ' + dtutil.display_date(rotation.next_rotation(), 2)
     else:
         self.rotation_msg = 'Supplemental rotation is ' + dtutil.display_date(rotation.next_supplemental(), 2)
     if in_rotation:
         self.in_rotation = in_rotation
         self.show_interestingness_filter = True
         self.runs, self.runs_percent, self.cards = rotation.read_rotation_files()
         # Now add interestingness to the cards, which only decksite knows not magic.rotation.
         playability = card.playability()
         c: Card
         for c in self.cards:
             c.interestingness = rotation.interesting(playability, c)
     else:
         self.cards = []
     self.show_interesting = True
     if interestingness:
         self.cards = [c for c in self.cards if c.get('interestingness') == interestingness]
     self.num_cards = len(self.cards)
     self.query = query
     for c in self.cards:
         if c.status != 'Undecided':
             continue
         c.hits = redact(c.hits)
         c.hits_needed = redact(c.hits_needed)
         c.percent = redact(c.percent)
         c.percent_needed = redact(c.percent_needed)
     self.show_filters_toggle = True
Esempio n. 16
0
def next_pd500_date() -> datetime.datetime:
    end_of_season = rotation.next_rotation()
    return end_of_season - datetime.timedelta(
        days=11, hours=13, minutes=30
    )  # This effectively hardcodes a 10:30 PD Sat start time AND a Thu/Fri midnight rotation time.
Esempio n. 17
0
 def menu(self):
     archetypes_badge = None
     n = len(deck.load_decks('NOT d.reviewed'))
     if n > 0:
         archetypes_badge = {'url': url_for('edit_archetypes'), 'text': n}
     resources_submenu = []
     if (rotation.next_rotation() - dtutil.now()) < datetime.timedelta(
             7) or (rotation.next_supplemental() -
                    dtutil.now()) < datetime.timedelta(7):
         resources_submenu += [{
             'name': gettext('Rotation Tracking'),
             'url': url_for('rotation')
         }]
     resources_submenu += [{
         'name': gettext('Rotation Changes'),
         'url': url_for('rotation_changes')
     }, {
         'name': gettext('Rotation Speculation'),
         'url': url_for('rotation_speculation')
     }, {
         'name': gettext('Discord Chat'),
         'url': 'https://discord.gg/H6EHdHu'
     }, {
         'name': gettext('External Links'),
         'url': url_for('resources')
     }, {
         'name':
         gettext('Log In'),
         'url':
         url_for('authenticate', target=request.url)
     }, {
         'name': gettext('Log Out'),
         'url': url_for('logout')
     }]
     menu = [{
         'name':
         gettext('Metagame'),
         'url':
         url_for('home'),
         'badge':
         archetypes_badge,
         'submenu': [{
             'name': gettext('Latest Decks'),
             'url': url_for('decks')
         }, {
             'name': gettext('Archetypes'),
             'url': url_for('archetypes'),
             'badge': archetypes_badge
         }, {
             'name': gettext('People'),
             'url': url_for('people')
         }, {
             'name': gettext('Cards'),
             'url': url_for('cards')
         }, {
             'name': gettext('Past Seasons'),
             'url': url_for('seasons')
         }]
     }, {
         'name':
         gettext('League'),
         'url':
         url_for('league'),
         'submenu': [
             {
                 'name': gettext('League Info'),
                 'url': url_for('league')
             },
             {
                 'name': gettext('Sign Up'),
                 'url': url_for('signup')
             },
             {
                 'name': gettext('Report'),
                 'url': url_for('report')
             },
             {
                 'name': gettext('Records'),
                 'url': url_for('current_league')
             },
             {
                 'name': gettext('Retire'),
                 'url': url_for('retire')
             },
         ]
     }, {
         'name':
         gettext('Competitions'),
         'url':
         url_for('competitions'),
         'submenu': [{
             'name': gettext('Competition Results'),
             'url': url_for('competitions')
         }, {
             'name': gettext('Tournament Info'),
             'url': url_for('tournaments')
         }, {
             'name': gettext('Leaderboards'),
             'url': url_for('tournament_leaderboards')
         }, {
             'name': gettext('Gatherling'),
             'url': 'https://gatherling.com/'
         }, {
             'name': gettext('Hosting'),
             'url': url_for('hosting')
         }]
     }, {
         'name': gettext('Resources'),
         'url': url_for('resources'),
         'submenu': resources_submenu
     }, {
         'name':
         gettext('About'),
         'url':
         url_for('about'),
         'submenu': [{
             'name': gettext('What is Penny Dreadful?'),
             'url': url_for('about')
         }, {
             'name': gettext('About pennydreadfulmagic.com'),
             'url': url_for('about_pdm')
         }, {
             'name': gettext('FAQs'),
             'url': url_for('faqs')
         }, {
             'name': gettext('Community Guidelines'),
             'url': url_for('community_guidelines')
         }]
     }, {
         'name': gettext('Admin'),
         'admin_only': True,
         'url': url_for('admin'),
         'submenu': admin.menu()
     }]
     for item in menu:
         item['has_submenu'] = item.get('submenu') is not None
         item['is_external'] = item.get('url', '').startswith(
             'http') and '://pennydreadfulmagic.com/' not in item['url']
         for subitem in item.get('submenu', []):
             subitem['is_external'] = subitem.get('url', '').startswith(
                 'http'
             ) and '://pennydreadfulmagic.com/' not in subitem['url']
     return menu
Esempio n. 18
0
import datetime
import fileinput
import os
import pathlib
import shutil
import subprocess
from collections import Counter
from typing import Dict, List, Set

import ftfy

from magic import card_price, fetcher, rotation
from price_grabber.parser import PriceListType, parse_cardhoarder_prices, parse_mtgotraders_prices
from shared import configuration, dtutil, fetch_tools, redis, repo, text

TIME_UNTIL_ROTATION = rotation.next_rotation() - dtutil.now()


def run() -> None:
    files = rotation.files()
    n = len(files)
    time_until = TIME_UNTIL_ROTATION - datetime.timedelta(weeks=1)
    if n >= rotation.TOTAL_RUNS:
        print(
            'It is the moment of discovery, the triumph of the mind, and the end of this rotation.'
        )
        return

    if n == 0 and TIME_UNTIL_ROTATION > datetime.timedelta(7):
        print(
            'The monks of the North Tree rarely saw their kodama until the rotation, when it woke like a slumbering, angry bear.'