steam-review-scraper / steam_review_scraper / common.py
common.py
Raw
"""Common classes and functions.

Attributes:
    settings (Settings): Program settings.
"""

import os
import sys
import json
import time
import logging
import logging.handlers
import datetime


settings = None


class Settings(object):
    """ Class representing all program settings.

    Attributes:
        apps (lst(AppConfig)): Apps listed in settings.json.
        languages (lst(Language)): Languages listed in json.
        settings_data (dict): All settings data listed in json.
    """

    def __init__(self, apps, languages, settings_data):
        self.apps = apps
        self.languages = languages
        self.settings_data = settings_data

    def get_tracked_apps(self):
        return [self.apps[appid] for appid in self.apps if self.apps[appid].track]

    def get_tracked_languages(self):
        return [self.languages[lang_key] for lang_key in self.languages if self.languages[lang_key].track]

    def get(self, key, default=None):
        return self.settings_data.get(key, default)

    def __getitem__(self, key):
        return self.settings_data[key]


class AppConfig(object):
    """ Class representing steam app data.

    Attributes:
        appid (int): App/Game id.
        track (bool): App track.
        ignore_zero_players (bool): Ignore zero players.
        stopwords (lst(str)): App wordcloud stopwords.
    """
    def __init__(self, appid, track, ignore_zero_players, stopwords):
        self.appid = appid
        self.track = track
        self.ignore_zero_players = ignore_zero_players
        self.stopwords = stopwords

    def get_stopwords(self, lang_key):
        if lang_key in self.stopwords:
            return self.stopwords[lang_key]
        return []


class Language(object):
    """ Class representing language data.

    Attributes:
        lang_key (str): The key of the given language, ie 'english'.
        name (str): Nicely formatted name.
        steam_key (str): Language as represented on the steam servers.
        track (bool): Language track.
    """
    def __init__(self, lang_key, name, steam_key, track):
        self.lang_key = lang_key
        self.name = name
        self.steam_key = steam_key
        self.track = track


def pretty_time(seconds):
    """
    Pretty time formatting.

    Args:
        seconds (int): Time in seconds.

    Returns:
        str: Nicely formatted time string.
    """
    minutes, seconds = divmod(seconds, 60)
    hours, minutes = divmod(minutes, 60)
    if hours:
        return "%.0fh %.0fm %.0fs" % (hours, minutes, seconds)
    elif minutes:
        return "%.0fm %.0fs" % (minutes, seconds)
    return "%.0fs" % (seconds,)


def get_settings():
    """
    Parse and return settings json.

    Return:
         Settings: Object storing json settings.
    """
    global settings
    if settings:
        return settings

    k_settings_file_path = os.path.join(os.path.dirname(__file__), "settings/settings.json")
    if not os.path.isfile(k_settings_file_path):
        logging.error("Settings file doesn't exist! ({0})".format(k_settings_file_path))
        sys.exit(1)
    
    with open(k_settings_file_path, "r") as settings_file:
        try:
            settings_data = json.load(settings_file)
            apps = {}
            for appid in settings_data["apps"]:
                app_data = settings_data["apps"][appid]
                apps[appid] = AppConfig(
                    appid, app_data["track"],
                    app_data["ignore_zero_players"],
                    app_data.get("wordcloud_stopwords",
                    {}))
            languages = {}
            for lang_key in settings_data["languages"]:
                lang_data = settings_data["languages"][lang_key]
                languages[lang_key] = Language(
                    lang_key,
                    lang_data["name"],
                    lang_data["steam_key"],
                    lang_data["track"]
                )
        except (ValueError, KeyError):
            logging.error("Settings file ({0}) contains invalid json!".format(k_settings_file_path))
            sys.exit(1)
        settings = Settings(apps, languages, settings_data)
        return settings


def init_logging(log_name, log_level_name):
    """ Initialise app logging. """
    full_log_path = os.path.join(os.path.dirname(__file__), "logs", log_name)
    if not os.path.exists(os.path.dirname(full_log_path)):
        print("Creating log dir '{0}'".format(os.path.dirname(full_log_path)))
        os.makedirs(os.path.dirname(full_log_path))

    k_logging_format = "[%(asctime)s][%(name)s][%(module)s][%(levelname)s] %(message)s"
    if get_settings().get("log_to_console", True):
        console_handler = logging.StreamHandler(stream=sys.stdout)
        console_handler.setFormatter(logging.Formatter(k_logging_format))
        log_level_name = log_level_name or get_settings().get("log_level").upper()
        log_level = getattr(logging, log_level_name)
        if not log_level:
            raise Exception("Unknown log level specified '{0}'".format(log_level_name))
        console_handler.setLevel(log_level)
        logging.getLogger().addHandler(console_handler)
    file_handler = logging.handlers.TimedRotatingFileHandler(
        full_log_path,
        when=get_settings().get("log_when"),
        backupCount=get_settings().get("log_count"),
        utc=True
    )
    file_handler.suffix = "%Y-%m-%d"
    file_handler.setFormatter(logging.Formatter(k_logging_format))
    logging.getLogger().addHandler(file_handler)

    logging.getLogger().setLevel("INFO")