async def react(self, msg: IRCMessage) -> None: if msg.command == 'PRIVMSG': assert msg.sender is not None if msg.sender.identity in self.config.get('ignored_users', []): return channel = msg.args[0] nick = msg.sender.nick async with httpx.AsyncClient() as client: for url in self.extractor.gen_urls(msg.body): try: title = await self.generate_preview(client, url) except asyncio.TimeoutError: self.client.send( IRCMessage( 'PRIVMSG', channel, body=f"{nick}: Preview timed out.", )) self.logger.exception("Error during processing %s", url) except Exception: self.logger.exception("Error during processing %s", url) else: if title: self.client.send( IRCMessage( 'PRIVMSG', channel, body=f"{nick}: {title}", ))
def start(self) -> None: super().start() channels: Set[str] = set(self.config['channels']) join = channels.difference(self.shared_data) part = self.shared_data.difference(channels) self.shared_data = channels for channel in join: self.logger.info("Joining %s…", channel) self.client.send(IRCMessage('JOIN', channel)) for channel in part: self.logger.info("Parting %s…", channel) self.client.send(IRCMessage('PART', channel))
async def dump(self, recipient, channel): c = self.db.cursor() c.execute( 'SELECT COUNT(*) FROM offline_msg WHERE channel=? AND recipient=?', (channel, recipient)) count = c.fetchone()[0] if count == 0: self.logger.info("No messages for %s.", recipient) return self.logger.info("Dumping %d messages for %s.", count, recipient) c.execute( ''' SELECT time, sender, body FROM offline_msg WHERE channel=? AND recipient=? ORDER BY rowid ''', (channel, recipient)) for timestamp, sender, body in c: self.client.send( IRCMessage('PRIVMSG', channel, body="{time} <{sender}> {body}".format( time=timestamp.strftime("%H:%M"), sender=sender, body=body, ))) c.execute('DELETE FROM offline_msg WHERE channel=? AND recipient=?', (channel, recipient)) self.db.commit()
async def __show_score(self, sender, channel, match, msg): scorable = match[1] score = self.score(scorable, channel) if score is None: body = f"{scorable} has no score." else: body = f"{scorable}'s score is {score}." self.client.send(IRCMessage('PRIVMSG', channel, body=body))
async def __del(self, sender, channel, match, msg): self.shared_data[channel].discard(match[1]) self.client.send( IRCMessage( 'PRIVMSG', channel, body=f"Understood, I'll stop keeping messages for {match[1]}.") ) return True
def respond_score(self, sender, nick, channel, operator): if sender == nick: self.client.send( IRCMessage('PRIVMSG', channel, body=f"{sender}: No self-scoring!")) return value_map = { '++': +1, '--': -1, } change = value_map[operator] self.change_score(nick, channel, change) score = self.score(nick, channel) or 0 self.client.send( IRCMessage('PRIVMSG', channel, body=f"{nick}'s score is now {score}."))
async def __add(self, sender, channel, match, msg): self.shared_data[channel].add(match[1]) self.client.send( IRCMessage( 'PRIVMSG', channel, body=f"Understood, I'll keep the messages for {match[1]}.")) self.logger.debug("Currently saving messages for: %s", dict(self.shared_data)) return True
async def __erase_scores(self, sender, channel, match, msg): nick = match[1] c = self.db.cursor() c.execute( ''' DELETE FROM score WHERE nick=? AND channel=? ''', (nick, channel)) self.db.commit() self.client.send( IRCMessage('PRIVMSG', channel, body=f"{nick}'s score erased."))
async def query_names(self, channel: str) -> Set[str]: self.logger.info("No cached names for %s, querying…", channel) self.client.send(IRCMessage('NAMES', channel)) names: Set[str] = set() while True: response = await self.queue.get() if response.command == "366": # RPL_ENDOFNAMES break if response.command == "353": # RPL_NAMREPLY if response.args[-1] == channel: names.update( nick.lstrip("@+") for nick in response.body.split()) self.logger.info("Nicks on %s: %s", channel, names) return names
async def __list_scores(self, sender, channel, match, msg): count = int(match[1] or 5) if count < 0: count = -count order = 'ASC' else: order = 'DESC' max_request = self.config['max_scoreboard_request'] or 10 try: self.auth(sender, channel) except NotAuthorizedError: auth = False else: auth = True if count > max_request and not auth: self.client.send( IRCMessage('PRIVMSG', channel, body=f"{sender.nick}: Too many scores requested.")) return c = self.db.cursor() c.execute( f''' SELECT nick, score FROM score WHERE channel=? ORDER BY score {order} LIMIT ? ''', (channel, count)) for nick, score in c: self.client.send( IRCMessage('PRIVMSG', channel, body=f"{nick}'s score is {score}.")) self.client.send(IRCMessage('PRIVMSG', channel, body="End of scores."))
async def react(self, msg: IRCMessage) -> None: if msg.command == 'PING': self.client.send(IRCMessage('PONG', body=msg.body))
async def __part(self, sender, channel, match, msg) -> None: self.client.send(IRCMessage('PART', match[1]))
async def __join(self, sender, channel, match, msg) -> None: self.client.send(IRCMessage('JOIN', match[1]))