def __init__(self, **data): self._id = build_game_id(data['_id'], data['system']) self.system = data['system'] self.nsuids = data.get('nsuids', {region: None for region in REGIONS}) self.titles = data.get('titles', {region: None for region in REGIONS}) self.release_dates = data.get('release_dates', {region: None for region in REGIONS}) self.wishlisted = data.get('wishlisted', 0) self.wishlisted_history = data.get('wishlisted_history', {}) self.hidden_gem = data.get('hidden_gem', False) self.number_of_players = data.get('number_of_players', 0) self.published_by_nintendo = data.get('published_by_nintendo', False) self.categories = sorted(list(set(data.get('categories', [])))) self.websites = data.get( 'websites', { country: None for country, dets in COUNTRIES.items() if WEBSITE in dets }) self.scores = Score(**data.get('scores', {})) self.free_to_play = data.get('free_to_play', False) self._title = None
def index(): if MAINTENANCE: return render_template('maintenance.html') return render_template('index.html', systems=sorted( [system[ID] for system in SYSTEMS.values()]), countries=COUNTRIES.values(), delete_url=DELETE_URL, show_url=SHOW_URL, emoji_star=STAR, emoji_warning=WARNING)
def make_table(games, prices, system): games = sorted(games.values(), key=lambda x: x.wishlisted, reverse=True) content = [ f'Title | Countries/Regions | % | MS | US | {STAR} ', '--- | --- | :---: | :---: | :---: | :---:' ] for game in games[:30]: if game.system != system: continue if not game.wishlisted: continue countries = {} discounts = set() for country, details in COUNTRIES.items(): nsuid = game.nsuids.get(details[REGION]) if not nsuid: continue price = prices.get(nsuid) if not price: continue country_price = price.prices[country] if not country_price: continue latest_sale = country_price.active if not latest_sale: continue countries[country] = details[FLAG] discounts.add(latest_sale.discount) if len(countries): row = make_row(game, countries, sum(discounts) / len(discounts)) content.append(row) if len(content) < 3: return None return '\n'.join(content)
def extract_game_data(system, data): title = data.get('title') fs_id = data.get('fs_id') if fs_id in FSID_FIXER: data['product_code_txt'], data['nsuid_txt'] = FSID_FIXER.get(fs_id) try: # Getting nsuids for switch (7) or 3ds (5) nsuid = [ nsuid_txt for nsuid_txt in data.get('nsuid_txt', []) if nsuid_txt[0] in ['5', '7'] ][0] product_id = [ product_code_txt for product_code_txt in data.get('product_code_txt', []) if product_code_txt[:3] in ['HAC', 'CTR', 'KTR'] ][0] except: return None game_code = get_game_id(nsuid=nsuid, game_id=product_id) if len(nsuid) < 10 or len(game_code) < 7: return None game = Game(_id=game_code, system=system) game.titles[EU] = title game.nsuids[EU] = nsuid game.categories = get_categories(data.get('game_categories_txt', [])) game.free_to_play = data.get('price_sorting_f', 1) == 0 game.published_by_nintendo = data.get('publisher', '') == 'Nintendo' game.number_of_players = data.get('players_to', 0) for country, details in COUNTRIES.items(): if details[REGION] == EU and WEBSITE in details: game.websites[country] = details[WEBSITE].format(nsuid=nsuid) try: game.release_dates[EU] = datetime.strptime( data.get('dates_released_dts')[0][:10], '%Y-%m-%d') except: return None return game
def validate(system, country=None): system = SYSTEMS.get(system.title(), SYSTEMS.get(system.upper())) if not system: raise Exception(f'Invalid system {system}') if not country: return system, None country = COUNTRIES.get(country.upper()) if not country: raise Exception(f'Invalid country {country}') return system, country
def extract_game_data(system, slug): url = AMERICA[DATA].format(slug=slug) response = requests.get(url) soup = BeautifulSoup(response.text, 'html.parser') scripts = [tag.text for tag in soup.find_all('script') if 'window.game' in tag.text] if not len(scripts): return None data = {x[0]: x[1] for x in [line.strip().replace('",', '').split(': "') for line in scripts[0].split('\n') if ':' in line]} nsuid = data.get('nsuid') game_code = data.get('productCode') if len(nsuid) < 10 or len(game_code) < 7: return None title = data.get('title') game_id = get_game_id(nsuid=nsuid, game_id=game_code) game = Game(_id=game_id, system=system) game.titles[NA] = FIXES.get(title, title) game.nsuids[NA] = FIXES.get(nsuid, nsuid) game.categories = get_categories(data.get('genre', '').split(',')) game.free_to_play = data.get('msrp') == '0.00' game.published_by_nintendo = data.get('publisher') == 'Nintendo' for country, details in COUNTRIES.items(): if details[REGION] == NA and WEBSITE in details: game.websites[country] = details[WEBSITE].format(nsuid=nsuid) try: game.release_dates[NA] = datetime.strptime(data.get('releaseDate'), '%b %d, %Y') except: return None try: number_of_players = soup.find('dd', {'class': 'num-of-players'}).text.strip() game.number_of_players = int(re.sub('[^0-9]*', '', number_of_players)) except: game.number_of_players = 0 return game
def generate(games, prices, submissions, system): title = f'Current Nintendo {system} eShop deals' table = make_table(games, prices, system) content = [] content.extend(header()) content.append( '> 💸 👉 PRICES AND SCORES IN THE LINKS AT THE BOTTOM 👈 💸') content.append('') if table: content.append('###Most wanted games on sale') content.append('') content.append(table) content.append(SEPARATOR) content.append('###For prices and more check your country/region post') content.append( f'> *{WARNING} There\'s a known bug on reddit mobile where links won\'t open correctly*' ) content.append('') content.append('-|new sales this week|total sales') content.append('---|:---:|:---:') for country, details in COUNTRIES.items(): key = f'{system}/{country}' submission = submissions.get(key) if not submission: continue content.append( f'[{details[FLAG]} {details[NAME]}]({submission.url})|{submission.new_sales}|{submission.total_sales}' ) content.extend(footer()) return title, '\n'.join(content)
def wishlist(system, country): if MAINTENANCE: return render_template('maintenance.html') try: system, country = validate(system, country) except: return None region = country[REGION] games = list(GamesDatabase().load_all(filter={ SYSTEM: system[ID], f'nsuids.{region}': { '$ne': None }, 'free_to_play': False }, sort=[(f'release_dates.{region}', -1) ])) for game in games: game.countries = [] for c, d in COUNTRIES.items(): if d[REGION] in game.nsuids: game.countries.append(c) game.countries = ' '.join(game.countries) return render_template('wishlist.html', system=system[NAME], country=country[ID], flag=country[FLAG], region=region, games=games, add_url=ADD_URL, delete_url=DELETE_URL, show_url=SHOW_URL, now=datetime.utcnow(), emoji_nintendo=NINTENDO, emoji_plus=PLUS, emoji_star=STAR, emoji_warning=WARNING)
def generate(games, prices, submissions, system): title = f'Current Nintendo {system} eShop deals' table = make_table(games, prices, system) content = [] content.extend(header()) content.append('') content.append('⬇ Regional posts with prices, dates, scores, and more.') content.append('') content.append('-|new sales this week|total sales') content.append('---|:---:|:---:') for country, details in COUNTRIES.items(): key = f'{system}/{country}' submission = submissions.get(key) if not submission: continue full_url = f'https://www.reddit.com/r/{USER_SUBREDDIT}/comments/{submission.submission_id}' content.append( f'[{details[FLAG]} {details[NAME]}]({full_url})|{submission.new_sales}|{submission.total_sales}' ) content.append('') if table: content.append(f'###Most [wishlisted]({WEBSITE_URL}) games on sale') content.append('') content.append(table) content.append(SEPARATOR) content.extend(footer()) return title, '\n'.join(content)
def update_games(system, wishlist_counts): now = datetime.utcnow() games_db = GamesDatabase() prices_db = PricesDatabase() games = { game.id: game for game in games_db.load_all(filter={SYSTEM: system}) } new_games_found = {} for region in REGIONS: saved_games = [ game.nsuids[region] for game in games.values() if game.nsuids.get(region) ] for nsuid, new_game in new_game_finders[region](system, saved_games): new_games_found[region] = new_games_found.get(region, 0) + 1 game = games.get(new_game.id, Game(_id=new_game.id, system=system)) game.nsuids[region] = new_game.nsuids.get(region) title = new_game.titles.get(region) for lookup, replacement in TITLE_FIXES.items(): if lookup in title: title = title.replace(lookup, replacement) game.titles[region] = title game.release_dates[region] = new_game.release_dates.get(region) game.categories += new_game.categories game.categories = list(set(game.categories)) game.number_of_players = max( [game.number_of_players, new_game.number_of_players]) game.published_by_nintendo = any( [game.published_by_nintendo, new_game.published_by_nintendo]) game.free_to_play = any([game.free_to_play, new_game.free_to_play]) for country, website in new_game.websites.items(): if website: game.websites[country] = website games[game.id] = game prices = {price.id: price for price in prices_db.load_all()} for game_id, game in games.items(): week = str(int(now.strftime("%V"))) game.wishlisted_history[week] = wishlist_counts.get(game_id, 0) game.wishlisted = game.wishlisted_average if game.scores.next_update < now: game.scores = metacritic.get_scores(system, game.titles.values()) try: GamesDatabase().save(game) except Exception as e: LOG.error(f'Error saving {game}: {str(e)}') continue for region, nsuid in game.nsuids.items(): if not nsuid: continue save = False price = prices.get(nsuid) if not price: save = True price = Price(_id=nsuid, game_id=game.id, system=system, region=region) for country, details in COUNTRIES.items(): if details[REGION] == region and country not in price.prices: price.prices[country] = None save = True if save: LOG.info(f'Saving {game.title} ({nsuid}) into prices') prices_db.save(price) return f'{system} games found: {new_games_found}'