def update_day(file_name, cards):
    attempts = 0
    while attempts < 2:                     # Try to re-download corrupted data twice before giving up

        # Strip the file of tabs
        try:
            for line in fileinput.input('AH-Data/' + file_name, inplace=True):
                print(line.replace('\t', ''), end='')
        except FileExistsError:
            if config_handler.getter('verboseFlag'):
                print("File exists error: " + file_name + ". Most likely pops up because the file is bugged/empty.")
                attempts = 3

        with open("AH-Data/" + file_name) as f:

            csv_f = csv.reader(f)
            # row[0]=card name, row[1]=rarity, row[2]=currency, row[3]=price, row[4]=date
            # Rarity values: 0-->Equipment, 2-->Common, 3-->Uncommon, 4-->Rare, 5-->AA, 6-->Legendary
            try:
                for row in csv_f:
                    key = (row[0], row[1], row[2])
                    if key in cards:
                        cards[key].append((row[3], row[4]))
                    else:
                        cards[key] = [(row[3], row[4])]
                    attempts = 3                        # No errors - we can go out of the loop
            except (IndexError, _csv.Error):
                    # Erases and re-downloads corrupted files
                    if config_handler.getter('verboseFlag'):
                        print('Re-downloaded', file_name, 'due to an error')
                    download_data.replace_day(file_name)
                    attempts += 1
def update(force=False):
    try:
        last_check = datetime.datetime.strptime(config_handler.getter('cardInfoCheck'), '%Y-%m-%d')
    except ValueError:
        last_check = datetime.datetime.min              # If string is malformed or empty we want to perform the download

    try:
        if last_check < datetime.datetime.today() - datetime.timedelta(days=1) or force: # Don't spam cwik's API with requests
            r = requests.post('http://hexdbapi2.hexsales.net/v1/objects/search')
            if config_handler.getter('verboseFlag'):
                print("Updated card info from cwik' API")
            with open('Card Info/card_info.json', 'w') as fp:
                json.dump(r.json(), fp, indent=4, sort_keys=True)
            config_handler.setter('cardInfoCheck', datetime.datetime.today().strftime('%Y-%m-%d'))  # update date of last download

            store_colors()                  # Update files
            store_rarity()
            store_guid_to_names()
            store_set()
            with open('Card Info/guid_to_names.json') as fp:        # Update guid_to_names with new values
                simple_guid_to_names.guid_dict = json.load(fp)
            if config_handler.getter('verboseFlag'):
                print('Updated colors, rarity, guid and set information')
    except Exception:
        if config_handler.getter('verboseFlag'):
            print("Could not update card info from cwik's API")
def short_term_median():
    longTermMedians = long_term_median()        # In case we don't have enough short term sales
    cards = open_ah_data()                      # dict with (card, rarity, currency) tuples as keys and a list of (sale, date) as value
    cardValues = {}
    for key in cards:
        listOfSales = cards[key]                # It's still a pointer to the same list
        recentSales = []
        for i in range(1, len(listOfSales)):    # Start at 1, because list[-0] gives the first element and we want the last
            # if sale of the date is in the last 2 weeks
            if datetime.datetime.strptime(listOfSales[-i][1], '%Y-%m-%d') < datetime.datetime.today() - datetime.timedelta(days=15):
                break                           # Moves on to the next key
            else:
                try:
                    recentSales.append(literal_eval(listOfSales[-i][0]))
                except IndentationError:
                    if config_handler.getter('verboseFlag'):
                        print('Problem with short term median literal_eval of', listOfSales[i][0])
        numberOfSales = len(recentSales)
        if numberOfSales >= 5:
            median = statistics.median(recentSales)
        else:
            median = longTermMedians[key][0]
        cardValues[key] = (median, numberOfSales)

    return cardValues
def store_set():
    os.makedirs('Card Info', exist_ok=True)
    if not os.path.isfile('Card Info/card_info.json'):
        update(force=True)
    try:
        with card_info_lock:
            with open('Card Info/card_info.json', 'rt') as fp:
                cardInfo = json.load(fp)
    except:
        if config_handler.getter('verboseFlag'):
            print('Card_info.json error')

    cardSet = {}
    translation = {'001': 'Shards of Fate',
                   '002': 'Shattered Destiny',
                   '003': 'Armies of Myth',
                   '004': 'Primal Dawn',
                   'PVE001': 'Frost Ring Arena',
                   'PVE002': 'Chest Loot'
                   }

    for cardDict in cardInfo:
        if cardDict['set_number'] not in non_cards:                             #Ignoring non-cards
            if cardDict['rarity'] not in ('Non-Collectible', ''):       #Ignoring AAs, champions and non-collectible cards
                try:
                    traslatedSet = translation[cardDict['set_number']]
                except KeyError:
                    traslatedSet = cardDict['set_number']
                cardSet[cardDict['name']] = traslatedSet

    with open('Card Info/simple_set.json', 'wt') as fp:
        json.dump(cardSet, fp, indent=4, sort_keys=True)
def store_rarity():
    os.makedirs('Card Info', exist_ok=True)
    if not os.path.isfile('Card Info/card_info.json'):
        update(force=True)
    try:
        with card_info_lock:
            with open('Card Info/card_info.json', 'rt') as fp:
                cardInfo = json.load(fp)
    except:
        if config_handler.getter('verboseFlag'):
            print('Card_info.json error')

    # if not response["error"] and response["status"] == 200:
    #     cardInfo = response["data"]
    # else:
    #     if config_handler.getter('verboseFlag'):
    #         print("Data not downloaded correctly")


    cardRarity = {}
    for cardDict in cardInfo:
        if cardDict['set_number'] not in non_cards:                             #Ignoring non-cards
            if cardDict['rarity'] not in ('Non-Collectible', ''):       #Ignoring AAs, champions and non-collectible cards
                cardRarity[cardDict['name']] = cardDict['rarity']

    with open('Card Info/simple_rarity.json', 'wt') as fp:
        json.dump(cardRarity, fp, indent=4, sort_keys=True)
def store_guid_to_names():
    os.makedirs('Card Info', exist_ok=True)
    if not os.path.isfile('Card Info/card_info.json'):
        update(force=True)
    try:
        with card_info_lock:
            with open('Card Info/card_info.json', 'rt') as fp:
                cardInfo = json.load(fp)
        card_names = {}

        for cardDict in cardInfo:
            if cardDict['set_number'] not in non_cards:  # Ignoring non-cards
                if cardDict['rarity'] not in ('Non-Collectible', '') or cardDict['name'] in (
                'Ruby Shard', 'Diamond Shard', 'Sapphire Shard', 'Wild Shard',
                'Blood Shard'):  # Ignoring champions and non-collectible cards
                    card_names[cardDict['uuid']] = cardDict['name']

    except Exception:
        if config_handler.getter('verboseFlag'):
            print('Card_info.json error')



    with open('Card Info/guid_to_names.json', 'wt') as fp:
        json.dump(card_names, fp, indent=4, sort_keys=True)
def collection_update(jsonDict):
    PATH = 'Collection/My_Collection.json'
    if jsonDict['Action'] == 'Overwrite':
        myCollection = {}
    if jsonDict['Action'] == 'Update':
        myCollection = collection_open(PATH)

    for card in jsonDict['Complete']:
        name = card_info_handler.simple_guid_to_names(card['Guid']['m_Guid'])
        number = card['Count']
        myCollection[name] = number
    for card in jsonDict['CardsAdded']:
        name = card_info_handler.simple_guid_to_names(card['Guid']['m_Guid'])
        number = card['Count']
        if name in myCollection:
            myCollection[name] += number
        else:
            myCollection[name] = number


    for card in jsonDict['CardsRemoved']:
        try:
            name = card_info_handler.simple_guid_to_names(card['Guid']['m_Guid'])
            if name in myCollection:
                myCollection[name] -= number
        except Exception:
            if config_handler.getter('verboseFlag'):
                print("Tried to remove a card that was not in the collection (most likely")
                raise
    with collectionLock:
        with open(PATH, 'wt') as fp:
            json.dump(myCollection, fp, indent=4, sort_keys=True)
 def run_with_except_hook(*args, **kw):
     try:
         run_old(*args, **kw)
     except (KeyboardInterrupt, SystemExit):
         raise
     except:
         sys.excepthook(*sys.exc_info())
         if config_handler.getter('verboseFlag'):
             raise
def collection_open(path):
    myCollection = {}
    try:
        with collectionLock:
            with open(path, 'rt') as fp:
                cards = json.load(fp)
        for card in cards:
            if card in myCollection:
                myCollection[card] += 1
            else:
                myCollection[card] = cards[card]
    except (FileNotFoundError, ValueError):
        if path != 'Collection/My_Drafted_Cards.json':
            if config_handler.getter('verboseFlag'):
                print("Please update your collection by relogging to Hex")
    return myCollection
def simple_guid_to_names(guid):
    if not os.path.isfile('Card Info/guid_to_names.json'):
        store_guid_to_names()
    # This avoids reloading the dictionary on every function call
    if not hasattr(simple_guid_to_names, "guid_dict"):
        with open('Card Info/guid_to_names.json') as fp:
            simple_guid_to_names.guid_dict = json.load(fp)
    name = 'Unknown card'
    try:
        name = simple_guid_to_names.guid_dict[guid]
    except KeyError:
        if config_handler.getter('verboseFlag'):
            print('Card with the following Guid could not be found: ' + guid)
        if guid != '00000000-0000-0000-0000-000000000000':  # Random guid that doesn't correspond to anything
            update()

    return name
def open_ah_data():
    if not os.path.isfile('Card Info/database.json'):
        update()
    try:
        with open('Card Info/database.json', 'rt') as fp:
            cards = json.load(fp)
    except:
        if config_handler.getter('verboseFlag'):
            print('Problem while loading database.json')

    # Converting keys to tuples
    # Without creating a temporary dict, "for key in cards" would run for the new keys too
    newCards = {}
    for key in cards:
        newCards[literal_eval(key)] = cards[key]
    cards = newCards

    return cards
def update():
    download_data.main()   # Downloads the latest AH-Data

    days = date_generator()
    cards = {}

    for formatted_date in days:
        try:
            update_day(formatted_date, cards)  # Only works because all instances modify the same card dictionary
        except FileNotFoundError:
            if config_handler.getter('verboseFlag'):
                print('Could not find ' + formatted_date)

    # Convert keys to strings, so that json can recognize them
    # Could also use 'w' instead of 'wt' since opening in text mode is the default
    os.makedirs('Card Info', exist_ok=True)
    with open('Card Info/database.json', 'wt') as fp:
        json.dump({str(key): value for key, value in cards.items()}, fp, indent=4, sort_keys=True)
def long_term_median():
    cards = open_ah_data()                      # dict with (card, rarity, currency) tuples as keys and a list of (price, date) as value
    cardValues = {}
    for key in cards:
        try:
            listOfSales = cards[key]                # It's still a pointer to the same list
            sales = []
            for sale in listOfSales:
                sales.append(literal_eval(sale[0]))
            numberOfSales = len(sales)
        except IndentationError:
            if config_handler.getter('verboseFlag'):
                print('Problem with long term median of', key)
        try:
            median = statistics.median(sales)
        except statistics.StatisticsError:
            median = 0
        cardValues[key] = (median, numberOfSales)

    return cardValues
def export_collection():
    collection = collection_open('Collection/My_Collection.json')
    colors = card_info_handler.simple_colors()
    sets = card_info_handler.simple_set()
    rarities = card_info_handler.simple_rarity()
    prices = AH_data_handler.open_simple_median()
    with open("Collection/My_Collection.csv", 'wt')as fp:
        writer = csv.writer(fp, delimiter=';')
        writer.writerow(['Card', 'Price', 'Shard', 'Set', 'Rarity', 'Number Owned'])
        for key in collection:
            if key not in ('Blood Shard', 'Diamond Shard', 'Sapphire Shard', 'Ruby Shard', 'Wild Shard'):
                try:
                    price = prices[key.replace(',', '')]                                     # AH Data has no commas
                except:
                    price = 0
                try:
                    writer.writerow([key, price, colors[key], sets[key], rarities[key], collection[key]])
                except KeyError:
                    if config_handler.getter('verboseFlag'):
                        print(key, " not found")
Exemple #15
0
    def my_data_parsing(self, jsonDict):

        # Write data to log
        #if jsonDict['Message'] not in ('PlayerUpdated', 'CardUpdated') or self.verboseFlag:
        if config_handler.getter('API_logging'):
            with open(APIHandler.store_path, 'a') as fp:
                fp.write(datetime.datetime.now().strftime('%H:%M:%S') + '\t' + str(jsonDict) + '\n')

        myMessage = ('', '')
        # First DraftPack for the last 20 minutes
        if jsonDict['Message'] == 'DraftPack' and len(jsonDict['Cards']) == 17 and (time.time() - APIHandler.startTime) >= 1500:
            threading.Thread(target=self.play_sound, args=('Sounds/short_ringtone.wav',)).start()
            APIHandler.startTime = time.time()
            gui_queue.put(('Reset', 'Reset draft value'))

        if jsonDict['Message'] == 'GameStarted':
            threading.Thread(target=self.play_sound, args=('Sounds/game_start.wav',)).start()

        if jsonDict['Message'] == 'DraftPack':
            # jsonDict['Cards'] is a list of card-dictionaries.
            # Each card-dictionary has the Guid, Flags and Gems keys
            draftPack = [card_info_handler.simple_guid_to_names(x['Guid']['m_Guid']) for x in jsonDict['Cards']]
            myMessage = ('DraftPack', draftPack)
            gui_queue.put(myMessage)

        elif jsonDict['Message'] == 'DraftCardPicked':
            card_picked = card_info_handler.simple_guid_to_names(jsonDict['Card']['Guid']['m_Guid'])
            myMessage = ('CardPicked', card_picked )
            gui_queue.put(myMessage)

            #threading.Thread(target=collection_handler.update_draft_value, args =(ahData[jsonDict[2][0]],)).start()
            # Needs updating to new format
            # collection_handler.draft_card_picked('Collection/My_Drafted_Cards.json', jsonDict['Card'])

        elif jsonDict['Message'] == 'Collection':
            if not os.path.isfile('Collection/My_Collection.json') and jsonDict['Action'] == 'Overwrite':
                gui_queue.put(('Update', 'Collection updated'))
            with APIHandler.collectionLock:
                collection_handler.collection_update(jsonDict)