from enum import Enum from typing import Union import re import datetime import logging re_trade = re.compile( r'Hi, I would like to buy your (?P.+) listed for (?P\d+) (?P\S+) in (?P\S+) ' r'\(stash tab "(?P.+)"; position: left (?P\d+), top (?P\d+)\)' ) re_log = re.compile( r'(?P\d\d\d\d/\d\d/\d\d \d\d:\d\d:\d\d) (\d+) (\S+) \[(?P\S+) (\S+) (\d+)\] ' r'(?P[#@%$&]?)(?PTo|From)?\s?(?P<\S+>)? ?(?P[^:]+): (?P.*)' ) re_clipboard = None re_clipboard_prefix = None log = logging.getLogger(__name__) logging.basicConfig(level=logging.DEBUG, format='%(levelname)-8s:: %(message)s') def compile_regex(conf: dict): global re_trade, re_log, re_clipboard, re_clipboard_prefix if 'General' in conf: if 're_log' in conf['Parser']: re_log = re.compile(conf['Parser']['re_log']) if 're_trade' in conf['Parser']: re_trade = re.compile(conf['Parser']['re_trade']) if 're_clipboard_prefix' in conf['Parser']: re_clipboard = re.compile(conf['Parser']['re_clipboard_prefix'] + conf['Parser']['re_trade']) re_clipboard_prefix = re.compile(conf['Parser']['re_clipboard_prefix'] + '.*') class Channel(Enum): WHISPER = 0 GLOBAL = 1 PARTY = 2 LOCAL = 3 TRADE = 4 GUILD = 5 channel_mapping = {'#': Channel.GLOBAL, '@': Channel.WHISPER, '%': Channel.PARTY, '': Channel.LOCAL, '$': Channel.TRADE, '&': Channel.GUILD} class Trade(): def __init__(self, nrItems: int, item: str, amount: float, currency: str, tab: str, row: str, col: str, league: str) -> None: self.nrItems = int(nrItems) if nrItems else None self.item = item self.amount = amount self.currency = currency self.tab = tab self.row = int(row) if row else None self.col = int(col) if col else None self.league = league @classmethod def by_regex_result(cls, res): return cls(nrItems=res['nrItems'], item=res['item'], amount=float(res['amount']), currency=res['currency'], tab=res['tab'], row=res['row'], col=res['col'], league=res['league']) def __str__(self) -> str: return f'Trade: {self.nrItems} {self.item} for {self.amount} {self.currency} in {self.tab} ({self.row}/{self.col}) in {self.league} league' def __hash__(self) -> int: return hash((self.nrItems, self.item, self.amount, self.currency, self.tab, self.row, self.col, self.league)) def __eq__(self, __o: object) -> bool: return (isinstance(__o, self.__class__) and self.nrItems == __o.nrItems and self.item == __o.item and self.amount == __o.amount and self.currency == __o.currency and self.tab == __o.tab and self.row == __o.row and self.col == __o.col and self.league == __o.league) class Message(): def __init__(self, message: str, date: datetime.datetime, user: str, channel: Channel, guild: Union[str, None] = None, to_from: Union[str, None] = None) -> None: self.message = message self.date = date self.channel = channel self.user = user self.guild = guild self.to_from = to_from self.trade: Union[Trade, None] = None if self.channel is Channel.WHISPER: self.parse_trade() @classmethod def from_text(cls, text: str): result = re_log.search(text) if not result: log.debug(f'Result is none for text "{text}"') return None date = datetime.datetime.strptime( result.group('date'), '%Y/%m/%d %H:%M:%S') guild = result.group('guild') if guild: guild = guild.strip('<>') return cls(result.group('message'), date, result.group('user'), channel_mapping[result.group('channel')], guild, result.group('ToFrom')) def __str__(self) -> str: text = f'Message: {self.date} - {self.channel.name}: ' if self.to_from: text = text + f'{self.to_from} ' if self.guild: text = text + f'<{self.guild}> ' text = text + f'{self.user}: {self.message}' return text def parse_trade(self) -> None: res = re_trade.search(self.message) if res: self.trade = Trade.by_regex_result(res) def unique_trade(self) -> int: assert self.trade return hash((self.user, self.trade.__hash__())) def unique_user_item(self) -> int: assert self.trade if self.to_from == 'From': # Item in my stash. return hash((self.trade.item, self.trade.tab, self.trade.row, self.trade.col, self.trade.league)) else: # Item in a stash from another char return hash((self.trade.item, self.trade.league))