Ejemplo n.º 1
0
def get_standalone_info(game, name, document):
    # middle left column
    game_left_column = domparser.get_element(
        document, 'div', class_='leftcol game_description_column')

    purchase_block = domparser.get_element(game_left_column,
                                           'div',
                                           id='game_area_purchase')
    game.store.category = get_game_category(purchase_block, document)
    game.store.price = get_game_price(purchase_block, name)
    game.store.os = get_game_os(game_left_column)

    # top right header
    glance_ctn_block = domparser.get_element(document,
                                             'div',
                                             class_='glance_ctn')
    game.store.image = get_game_image(glance_ctn_block)
    game.store.avg_review,\
    game.store.cnt_review   = get_game_review(glance_ctn_block, name)
    game.store.release_date = get_game_release_date(glance_ctn_block, name)
    game.store.tags = get_game_tags(glance_ctn_block)

    if (game.store.category in [Category.Game, Category.Video]):
        game.store.description = get_game_description(glance_ctn_block)
    elif (game.store.category is Category.DLC):
        game.store.description = get_dlc_description(document)
    else:
        game.store.description = ''
        styledprint.print_info(
            'The category {0} is not implemented yet!'.format(
                game.store.category.name))

    game.store.interface,\
    game.store.audio,\
    game.store.subtitles    = get_game_languages(document)
Ejemplo n.º 2
0
def get_game_review(glance_ctn_block, name):
    overall_block = domparser.get_element(glance_ctn_block,
                                          'div',
                                          class_='subtitle column all',
                                          string='All Reviews:')

    if (overall_block == None):
        styledprint.print_info(
            'Cannot find the review block for game: {0}'.format(name))
        return '', '0'

    user_reviews_block = domparser.get_parent(overall_block)

    reviewCount = domparser.get_value(user_reviews_block,
                                      'content',
                                      'meta',
                                      itemprop='reviewCount')

    ratingValue = domparser.get_value(user_reviews_block,
                                      'content',
                                      'meta',
                                      itemprop='ratingValue')

    if (reviewCount):
        return int(ratingValue), int(reviewCount)
    return None, None
Ejemplo n.º 3
0
async def get_store_info(game, name, webSession):
    page, description, url = await get_page(game.store.link, name, webSession)
    if (not page):
        game.store.description = description
        return False

    document, description = get_document(page, name)

    if (document is None):
        game.store.description = description
        return False
    game.store.link = re.sub(
        r'(https://store.steampowered.com/[^/]*/[^/]*)/.*',
        r'\1',
        url,
        flags=re.IGNORECASE)

    if (('/sub/' in game.store.link) or ('/bundle/' in game.store.link)):
        await get_collection_info(game, name, document, webSession)
    elif ('/app/' in game.store.link):
        get_standalone_info(game, name, document)
    else:
        styledprint.print_info('Unknown type of link {0}'.format(
            game.store.link))

    # middle right column
    game.store.genres = get_game_genres(document)
    game.store.details = get_game_details(document)

    return True
Ejemplo n.º 4
0
 def add_to_mapping(self, left, middle, right=None):
     if (left not in self.mapping):
         if (right):
             self.mapping[left] = (middle.lower(), right)
         else:
             self.mapping[left] = (middle.lower(), )
     else:
         styledprint.print_info(
             'Impossible to add mapping, {0} is already in the mapper'.
             format(left))
Ejemplo n.º 5
0
async def refresh_applist(dryrun, skip, from_scratch=False, max_apps=None):
    local_applist = await steam.get_applist_from_local()
    if (skip):
        return local_applist

    async with web.Session(limit_per_host=20) as webSession:
        foreign_applist = await steam.get_applist_from_server(
            webSession, max_apps)
        styledprint.print_info('Apps in server:', len(foreign_applist))
        styledprint.print_info('Apps in cache at start:', len(local_applist))
        calname = 'refresh_applist'
        try:
            tasks = []
            for name in foreign_applist:
                for app in foreign_applist[name]:
                    if ((not from_scratch) and (name in local_applist)
                            and (app in local_applist[name])):
                        continue
                    appid, typ = app
                    link = steam.get_store_link(appid, typ)
                    f = asyncio.ensure_future(
                        steam.get_page(link, name, webSession))
                    f.add_done_callback(
                        functools.partial(poolsubmit, calname,
                                          get_newgame_info, name, appid, typ,
                                          tasks))
                    tasks.append(f)

            if (len(tasks)):
                styledprint.print_info('async tasks:')
                await asyncio.gather(progressbar.progress_bar(tasks))
        except Exception as e:
            styledprint.print_error(
                'Error happened while running the async loop:', e)
            styledprint.print_error(traceback.format_exc())
            pass
        fs = parallelism.wait_calname(calname)
        for f in fs:
            ext_applist = f.result()
            merge_applists(local_applist, ext_applist)
        styledprint.print_info(
            'Apps in cache at end (duplicate names not in the count):',
            len(local_applist))

        if (not dryrun):
            logging.debug('not dryrun so saving local_applist to disk')
            await steam.save_applist_to_local(local_applist)

    games = utils.DictCaseInsensitive()
    for game in local_applist:
        if (not game.lower().endswith('demo')):
            games[game] = local_applist[game]
    styledprint.print_info('Apps in cleaned cache:', len(games))
    return games
Ejemplo n.º 6
0
def get_game_release_date(glance_ctn_block, name):
    date = domparser.get_text(glance_ctn_block, 'div', class_='date')
    if (date):
        try:
            return parser.parse(date.strip(), fuzzy_with_tokens=True)
        except:
            styledprint.print_info('date: {0} for game: {1} is no good'.format(
                date, name))
            pass

    return None
Ejemplo n.º 7
0
def wait_calname(calname):
    if (calname not in future):
        return []

    logging.debug('futures.wait() started at: ' + str(datetime.now().time()))
    logging.debug('len(future[calname]: ' + str(len(future[calname])))
    styledprint.print_info('pool tasks:')
    for f in tqdm.tqdm(futures.as_completed(future[calname]),
                       total=len(future[calname])):
        pass
    logging.debug('futures.wait() done at: ' + str(datetime.now().time()))
    fs = future[calname]
    del future[calname]
    return fs
Ejemplo n.º 8
0
def main():

    CACHE_PATH = os.path.join('cache', 'games.p')
    cache = Cache(CACHE_PATH)
    cachedgames = cache.load_from_cache()
    i = 0
    for name in iter(cachedgames):
        game = cachedgames[name]
        if (not hasattr(game.store, 'interface')):
            game.store.interface = list()
            i = i + 1
        if (not hasattr(game.store, 'audio')):
            game.store.audio = list()
            i = i + 1
        if (not hasattr(game.store, 'subtitles')):
            game.store.subtitles = list()
            i = i + 1
    styledprint.print_info('{0} games cleaned'.format(i))
    cache.save_to_cache(cachedgames)
Ejemplo n.º 9
0
def get_appid_and_type_from_namematching(origname, name, games, appidstried,
                                         matches):
    while (True):
        if (matches is None):
            matches = get_clean_matches(name, games)

        if (len(matches) == 0):
            return None, None

        matchedname = matches[0]
        if (matchedname):
            score = namematching.get_match_score(name, matchedname)
            styledprint.print_info('Matched {0} with {1} at score {2}'.format(
                origname, matchedname, score))
            appid, typ = get_appid_and_type(matchedname, games, appidstried)
            if (appid):
                return appid, typ
            else:
                matches.pop(0)
        else:
            return None, None
Ejemplo n.º 10
0
    def __init__(self, mappingfile):
        if (os.path.exists(mappingfile)):
            self.LINK = '<->'
            self.mappingfile = mappingfile
            self.mapping = utils.DictCaseInsensitive()
            f = open(self.mappingfile, 'r', encoding='utf8')
            for line in iter(f):
                line = line.strip()
                # remove the quotes needed to protect spaces
                # at the end of names when steam messed up
                line = line[1:-1]
                if (self.LINK in line):
                    tup = line.split(self.LINK)
                    if (len(tup) <= 1):
                        styledprint.print_info(
                            'The line does not '
                            'contain enough members', line)
                        continue

                    key = tup[0]
                    value = tup[1].lower().strip('/')
                    if (key in self.mapping):
                        styledprint.print_info(
                            'The key {0} is already in the mapper!'.format(
                                key))
                        continue
                    if (len(tup) == 2):
                        self.mapping[key] = (value, )
                    elif (len(tup) == 3):
                        self.mapping[key] = (value, tup[2])
                    else:
                        styledprint.print_info(
                            'More members in the line than excepted!')
Ejemplo n.º 11
0
def get_game_price(purchase_block, name):
    wrappers = domparser.get_elements(purchase_block,
                                      'div',
                                      class_='game_area_purchase_game_wrapper')

    if (wrappers is not None):
        names = list()
        prices = list()
        for wrapper in wrappers:
            names.append(domparser.get_text(wrapper, 'h1')[4:].lower())
            price = domparser.get_text(wrapper,
                                       'div',
                                       class_='game_purchase_price price')
            if (not price):
                price = domparser.get_text(wrapper,
                                           'div',
                                           class_='discount_final_price')
            prices.append(price)

        sortedprices = list()
        if (len(names)):
            matches = namematching.get_matches(name.lower(), names, len(names))
            for match in matches:
                index = names.index(match)
                sortedprices.append(prices[index])
        if (not len(sortedprices)):
            sortedprices = prices
    else:
        sortedprices = domparser.get_texts(purchase_block,
                                           'div',
                                           class_='game_purchase_price price')
        if (not sortedprices):
            sortedprices = domparser.get_texts(purchase_block,
                                               'div',
                                               class_='discount_final_price')

    for price in sortedprices:
        if (price):
            # we got the wrong div
            if ('demo' in price.lower()):
                continue

            price = price.replace('$', '').replace('€', '').strip()
            if (price.replace('.', '', 1).isdigit()):
                return float(price)
            elif (('free' in price.lower()) or ('play' in price.lower())):
                return 0
            else:
                styledprint.print_info('Unexpected price: {0} for {1}'.format(
                    price, name))
                return -1

    play_game_span = domparser.get_element(purchase_block,
                                           'span',
                                           string='Play Game')
    if (play_game_span is not None):
        return 0

    download_span = domparser.get_element(purchase_block,
                                          'span',
                                          string='Download')
    if (download_span is not None):
        return 0

    styledprint.print_info('No price found for {0}'.format(name))
    return -1
Ejemplo n.º 12
0
async def get_game_info(options, game, cachedgames, steamgames, winedb,
                        cleansteamgames, cleanwinedb, name, urlsmapping,
                        webSession):
    try:
        if ((not options.all) and (not game.hfr.is_available)):
            # Ignoring not available games for now
            # it may be better in the future to ignore them in output
            # or allow the user to do so in the html page.
            return

        cleanname = None
        #cache    = webSession.cache

        if (name in cachedgames):
            # Whether the cache is ignored or not,
            # if a game cached has a gift_date we keep it
            if (cachedgames[name].hfr.gift_date):
                game.hfr.gift_date = cachedgames[name].hfr.gift_date

            if (not options.ignorecache):
                game.store = cachedgames[name].store
                game.wine = cachedgames[name].wine

        # query the store if:
        # - not cacheonly
        # - not in cache
        # - in cache and to be refreshed
        if ((not options.cacheonly) and
            ((not game.store.link) or
             ((options.game) and (options.game.lower() in name.lower())))):

            # keep the old information if there is no new one
            if (game.store.link):
                storeBU = copy.deepcopy(game.store)
                worked = await steam.get_store_info(game, name, webSession)
                if (worked):
                    styledprint.print_info(
                        'Info for game {0} was retrieved, {1}'.format(
                            name, str(datetime.now().time())))
                else:
                    game.store = storeBU
            else:
                mapping = urlsmapping.get_mapping(name)

                if (mapping == None):
                    appidstried = []
                    matches = None
                    while (True):
                        appid, typ = get_appid_and_type(
                            name, steamgames, appidstried)
                        if (appid):
                            styledprint.print_debug(
                                'The game {0} got its appid simply'.format(
                                    name))
                        elif (options.fuzzymatching):
                            # it seems quicker to recompute it than use redis
                            #cleanname = await cache.function(namematching.nameclean, name)
                            cleanname = namematching.nameclean(name)
                            appid, typ = get_appid_and_type(
                                cleanname, cleansteamgames, appidstried)
                            if (appid):
                                styledprint.print_debug(
                                    'The game {0} got its appid '
                                    'by namecleaning'.format(name))
                            else:
                                appid, typ = get_appid_and_type_from_namematching(
                                    name, cleanname, cleansteamgames,
                                    appidstried, matches)

                        if ((appid in appidstried) or (not appid)):
                            game.store = StoreData()
                            game.store.description = 'The game was not found in the steam db'
                            styledprint.print_error('{0}: {1}'.format(
                                game.store.description, name))
                            cleanname = None
                            return
                        else:
                            appidstried.append(appid)

                            if (await steam.get_store_info_from_appid(
                                    game, name, appid, typ, webSession)):
                                break

                else:
                    url = mapping[0]

                    if (url == 'ignore'):
                        styledprint.print_debug(
                            '{0} cannot be found and is to be ignored'.format(
                                name))
                        return

                    styledprint.print_debug(
                        'URL mapping found for game {0}'.format(name))
                    await steam.get_store_info_from_url(
                        game, name, url, webSession)
                    # overwriting the steam provided category
                    if (len(mapping) == 2):
                        game.store.category = Category[mapping[1].upper()]
                        game.store.override = True

                styledprint.print_info(
                    'Info for game {0} was retrieved, {1}'.format(
                        name, str(datetime.now().time())))

        # TODO
        # compute cleanname once
        # cache heavy stuff
        if (name in winedb):
            game.wine = winedb[name]
        elif (options.fuzzymatching):
            if (cleanname is None):
                # it seems quicker to recompute it than use redis
                #cleanname = await cache.function(namematching.nameclean, name)
                cleanname = namematching.nameclean(name)
            if (cleanname in cleanwinedb):
                game.wine = cleanwinedb[cleanname]
            else:
                cleanmatches = get_clean_matches(cleanname, cleanwinedb)
                if (len(cleanmatches)):
                    game.wine = cleanwinedb[cleanmatches[0]]

    except Exception as e:
        styledprint.print_error('An exception was raised for', name)
        raise e
Ejemplo n.º 13
0
def get_rows(games):
    reviewMapping     = dict()
    reviewMapping[10] = 'Overwhelmingly Positive'
    reviewMapping[9]  = 'Very Positive'
    reviewMapping[8]  = 'Positive'
    reviewMapping[7]  = 'Mostly Positive'
    reviewMapping[6]  = 'Mixed'
    reviewMapping[5]  = 'Mostly Negative'
    reviewMapping[4]  = 'Negative'
    reviewMapping[3]  = 'Very Negative'
    reviewMapping[2]  = 'Overwhelmingly Negative'
    justifyFormat     = '<div class=\\"text\\">{0}</div>'

    data = writeline('function getRows(){')
    increase_indent_count()
    data += writeline('rows=[];', True)


    for gameName in sorted(games, key=str.lower):
        game = games[gameName]
        if (not game.hfr.is_available):
            continue

        data += writeline('var row = {')
        increase_indent_count()
        data += writeline('name: "{0}",'.format(gameName.replace('"', '\\"')))
        #TODO make smallImage an input parameter?
        smallImage = True
        if (game.store.link):
            if(game.store.image):
                if (smallImage):
                    imageLink = re.sub(r'header\.jpg.*', 'capsule_sm_120.jpg', game.store.image)
                else:
                    imageLink = game.store.image
                data += writeline('nameFormat: "<a href=\\"{0}\\"><b>{1}</b><img src=\\"{2}\\" width=\\"100%\\"/></a>",'
                                  .format(game.store.link, justifyFormat, imageLink))
            else:
                data += writeline('nameFormat: "<a href=\\"{0}\\"><b>{1}</b></a>",'
                                  .format(game.store.link, justifyFormat))
        else:
            data += writeline('nameFormat: "<b>{0}</b>",'.format(justifyFormat))
        if(game.store.description):
            data += writeline('description: "{0}",'.format(
                game.store.description.replace(os.linesep, '<br/>').replace('"', '\\"')))
        if (game.store.category):
            data += writeline('category: "{0}",'.format(game.store.category.name))
        if (len(game.store.os) > 0):
            data += writeline('os: "{0}",'.format(', '.join(game.store.os).replace('OS X', 'OS')))
        if (game.store.price != None):
            data += writeline('price: {0},'.format(str(game.store.price)))
            if (game.store.price == 0):
                data += writeline('priceFormat: "{0}",'
                                  .format(justifyFormat.replace('{0}', 'Free')))
            elif (game.store.price < 0):
                data += writeline('priceFormat: "{0}",'
                                  .format(justifyFormat.replace('{0}', 'N/A')))
            else:
                data += writeline('priceFormat: "{0}",'.
                                  format(justifyFormat.replace('{0}', '${0}')))

        if (len(game.store.genres) > 0):
            data += writeline('genres: "{0}",'.format(', '.join(game.store.genres)))
        if (game.store.release_date):
            date, errors = game.store.release_date
            # if errors has more than whitespace or empty strings
            errors = tuple(filter(lambda x: x.strip(), errors))
            if (len(errors)):
                fmt = '%Y'
            else:
                fmt = '%Y-%m-%d'
            data += writeline('date: "{0}",'.format(date.strftime(fmt).replace('-', '&#8209;')))
        if (game.store.avg_review) and (game.store.avg_review in reviewMapping):
            avg_review_text = reviewMapping[game.store.avg_review]
            MIN_POW         = 6
            avg_review_p    = math.pow(10, MIN_POW) * game.store.avg_review
            # if we have average negative reviews, we reduce the average review's power per review
            if (game.store.avg_review < 6):
                avg_review = str(avg_review_p - game.store.cnt_review)
            # if we have average positive reviews, we increment the average review's power per review
            else:
                avg_review = str(avg_review_p + game.store.cnt_review)
            if (game.store.avg_review < 10):
                avg_review = '0{0}'.format(avg_review)
            data += writeline('review: "{0} {1}",'.
                              format(avg_review, avg_review_text))
            data += writeline('reviewFormat: "{0}",'.
                              format(justifyFormat.replace('{0}',
                                                           '{0} ({1})'.
                                                           format(avg_review_text,
                                                                  game.store.cnt_review))))
        else:
            if (game.store.avg_review):
                styledprint.print_info('The average review {0} for game {1} is not in the mapping!'.
                      format(game.store.avg_review, gameName))

        if (game.hfr.requirements):
            if (game.hfr.requirements.lower() == 'standard'):
                stars = '*'
            else:
                stars = '**'

            if (game.hfr.is_new):
                requirements = '{0}: Nouveauté'.format(game.hfr.requirements)
            else:
                requirements = game.hfr.requirements
            data += writeline('requirements: "{0}<sup><b>{1}</b></sup>",'.format(requirements, stars))

        if (len(game.store.tags) > 0):
            data += writeline('tags: "{0}",'.format(', '.join(game.store.tags)))

        if (len(game.store.details) > 0):
            data += writeline('details: "{0}",'.format(', '.join(game.store.details)))

        if (game.hfr.gift_date):
            data += writeline('giftdate: "{0}",'.format(game.hfr.gift_date.strftime("%Y-%m-%d")))

        if (len(game.store.interface) > 0):
            data += writeline('interface: "{0}",'.format(', '.join(game.store.interface)))
        if (len(game.store.audio) > 0):
            data += writeline('audio: "{0}",'.format(', '.join(game.store.audio)))
        if (len(game.store.subtitles) > 0):
            data += writeline('subtitles: "{0}",'.format(', '.join(game.store.subtitles)))

        if (game.wine):
            data += writeline('wine: "{0}",'.format(', '
                .join([app.rating for app in game.wine])))
            data += writeline('wineFormat: "{0}",'
                              .format(justifyFormat
                                  .format(', '.join(
                                      ['<a href=\\"{0}\\"><b>{1}</b></a>'
                                           .format(app.link, app.rating) for app in game.wine]))))
        else:
            data += writeline('wineFormat: "{0}",'
                              .format(justifyFormat
                                      .format('<a href=\\"https://appdb.winehq.org/objectManager.php?sClass=application&sTitle=Browse+Applications&iappFamily-appNameOp=2&sappFamily-appNameData={0}\\"><i>?</i></a>'
                                              .format(gameName.replace('"', '\\"')))))

        decrease_indent_count()
        data += writeline('};')
        try:
            if (game.store.override):
                data += writeline('row[\'row-cls\'] = \'override\'')
        except:
            pass
        data += writeline('rows.push(row);', True)

    data += writeline('return rows;')
    decrease_indent_count()
    data += writeline('};')
    return data