diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ba5054..009fe0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ All notable changes to this project will be documented in this file. If there is a `Changed` section please read carefully, as this often means that you will need to adapt your `config.yml`, otherwise the bot might fail to start. +## [1.2.1] - unreleased + +### Changed + + * Reworked internal code structure + +### Fixed + + * Publish vote info in chat when reloading config was not working when TTS was disabled + * Casting votes was allowed for broadcaster and mods only + ## [1.2.0] - 2022-08-13 ### Added diff --git a/dist/tts.exe b/dist/tts.exe index 9b07641..dfb3b27 100644 Binary files a/dist/tts.exe and b/dist/tts.exe differ diff --git a/tts.py b/tts.py index 21edd07..441be3a 100644 --- a/tts.py +++ b/tts.py @@ -49,7 +49,7 @@ class IRC: self.tts_denied = [] self.tts_allowed = [] self.tts_status = conf['TTS_STARTENABLED'] - self.quickvote = False + self.quickvote_status = False self.votemsg = False self.poll = {} self.pollcount = 0 @@ -177,167 +177,45 @@ class IRC: logging.debug('Deny List:') logging.debug(self.tts_denied) + if msg.startswith('#') and self.quickvote_status is True: + logging.info('Quickvote: Cast detected') + self.pollcount += 1 + self.poll[user] = msg.lower() + logging.debug(self.poll) + return True + if 'broadcaster' in badges or 'moderator' in badges: - if msg.startswith('!dtts'): - logging.debug("!dtts command detected") - user = msg.replace('!dtts', '').strip().lower() - - if user.startswith('@'): - logging.debug('Removing "@" from username') - user = user.replace('@', '') - if user not in self.tts_denied: - logging.info("Adding %s to deny list", user) - self.tts_denied.append(user) - if user in self.tts_allowed: - logging.info("Removing %s from allowed list", user) - self.tts_allowed.remove(user) - - return True - if msg.startswith('!ping'): logging.debug("Ping check received.") self.sendmsg(conf['IRC_CHANNEL'], "@"+str(user), "Pong!") + return True + if msg.startswith('!dtts'): + logging.debug("!dtts command detected") + self.Commands.dtts(self, msg) return True if msg.startswith('!random'): logging.info('!random command detected') - - randomfile = msg.replace('!random', '').strip().lower() - if randomfile: - randomfile = "random_"+str(os.path.basename(randomfile))+".txt" - else: - randomfile = "random.txt" - - try: - with open(randomfile,"r", encoding="utf-8") as file: - lines = file.read().splitlines() - random_msg = random.choice(lines) - except FileNotFoundError: - logging.error('%s not found', randomfile) - return False - - raw_msg = { - "TTS": True, - "msg": random_msg, - "badges": True, - "subscriber": True, - "msgid": True, - "user": conf['IRC_USERNAME'], - "length": conf['IRC_TTS_LEN'], - "queuetime": datetime.datetime.now(), - "timestamp": str(time.time_ns()) - } - msg_queue[raw_msg['timestamp']] = [raw_msg['user'], raw_msg['msg']] - + self.Commands.random(self, msg) return True if msg.startswith('!quickvote'): logging.info("!quickvote command detected") - if self.quickvote: - logging.debug('Quickvote stopped') - - if self.pollcount == 0: - logging.info("Nobody voted") - self.sendmsg(conf['IRC_CHANNEL'], "@chat", conf['MESSAGE']['VOTEEND']) - self.sendmsg(conf['IRC_CHANNEL'], "*", conf['MESSAGE']['VOTENOBODY']) - - raw_msg = { - "TTS": True, - "msg": conf['MESSAGE']['VOTENOBODY'], - "badges": True, - "subscriber": True, - "msgid": True, - "user": conf['IRC_USERNAME'], - "length": conf['IRC_TTS_LEN'], - "queuetime": datetime.datetime.now(), - "timestamp": str(time.time_ns()) - } - msg_queue[raw_msg['timestamp']] = [raw_msg['user'], raw_msg['msg']] - - logging.info('The result is: %s', conf['MESSAGE']['VOTENOBODY']) - logging.debug('Votemsg: %s', msg) - - self.quickvote = False - self.poll = {} - return False - - logging.info("Counting votes") - count = 0 - count = Counter(self.poll.values()).most_common(5) - self.sendmsg(conf['IRC_CHANNEL'], "@chat", conf['MESSAGE']['VOTEEND']) - - logging.debug(count) - - raw_msg = { - "TTS": True, - "msg": conf['MESSAGE']['VOTERESULT'] +" "+ str(count[0][0].replace('#','')), - "badges": True, - "subscriber": True, - "msgid": True, - "user": conf['IRC_USERNAME'], - "length": conf['IRC_TTS_LEN'], - "queuetime": datetime.datetime.now(), - "timestamp": str(time.time_ns()) - } - msg_queue[raw_msg['timestamp']] = [raw_msg['user'], raw_msg['msg']] - - logging.info('The result is: %s', conf['MESSAGE']['VOTERESULT'] +" "+ str(count[0])) - logging.debug('Votemsg: %s', msg) - - for key, value in count: - self.sendmsg( - conf['IRC_CHANNEL'], "*", - str(key)+" ("+str(value)+ " "+ conf['MESSAGE']['VOTES'] + ")" - ) - - self.quickvote = False - self.poll = {} - self.pollcount = 0 - return True - else: - logging.debug('Quickvote started') - self.quickvote = True - self.votemsg = resp.split('!quickvote', 1)[1].strip() - if self.votemsg: - self.sendmsg( - conf['IRC_CHANNEL'], "@chat", - conf['MESSAGE']['VOTESTART'] + " (" + str(self.votemsg) + ")" - ) - else: - self.sendmsg(conf['IRC_CHANNEL'], "@chat", conf['MESSAGE']['VOTESTART']) + self.Commands.quickvote(self, msg) return True if msg.startswith('!ptts'): logging.debug("!ptts command detected") - user = msg.replace('!ptts', '').strip().lower() - - if user.startswith('@'): - logging.debug('Removing "@" from username') - user = user.replace('@', '') - - logging.info("Adding %s to whitelist", user) - self.tts_allowed.append(user) - - if user in self.tts_denied: - logging.info("Removing %s from deny list", user) - self.tts_denied.remove(user) - + self.Commands.ptts(self, msg) return True - if msg.startswith('#') and self.quickvote is True: - logging.info('Quickvote: Cast detected') - self.pollcount += 1 - self.poll[user] = msg.lower() - logging.debug(self.poll) - if msg.startswith('!toff'): logging.info('TTS is now turned off') msg_queue.clear() msg_queue_raw.clear() self.tts_status = False self.sendmsg(conf['IRC_CHANNEL'], "@"+str(user), conf['MESSAGE']['TOFF']) - return True if msg.startswith('!ton'): @@ -346,28 +224,20 @@ class IRC: msg_queue_raw.clear() self.tts_status = True self.sendmsg(conf['IRC_CHANNEL'], "@"+str(user), conf['MESSAGE']['TON']) - return True if msg.startswith('!tts'): logging.debug('!tts command detected') - - if msglen > conf['IRC_TTS_LEN']: - logging.info('TTS message is to long') - self.sendmsg(conf['IRC_CHANNEL'], "@"+str(user), conf['MESSAGE']['TOO_LONG']) - return False - logging.debug("tts status: %s", self.tts_status) - logging.debug(conf['TTS_STARTENABLED']) if not self.tts_status: logging.info('TTS is disabled') self.sendmsg(conf['IRC_CHANNEL'], "@"+str(user), conf['MESSAGE']['DISABLED']) return False - if user in self.tts_denied: - logging.info("%s is not allowed to use TTS", user) - self.sendmsg(conf['IRC_CHANNEL'], "@"+str(user), conf['MESSAGE']['DENIED']) + if msglen > conf['IRC_TTS_LEN']: + logging.info('TTS message is to long') + self.sendmsg(conf['IRC_CHANNEL'], "@"+str(user), conf['MESSAGE']['TOO_LONG']) return False if conf['IRC_SUBONLY']: @@ -386,6 +256,11 @@ class IRC: self.sendmsg(conf['IRC_CHANNEL'], "@"+str(user), conf['MESSAGE']['MODONLY']) return False + if user in self.tts_denied: + logging.info("%s is not allowed to use TTS", user) + self.sendmsg(conf['IRC_CHANNEL'], "@"+str(user), conf['MESSAGE']['DENIED']) + return False + if conf['WHITELIST']: if user not in self.tts_allowed: logging.info('User is not on whitelist') @@ -395,13 +270,13 @@ class IRC: "@"+str(user), conf['MESSAGE']['WHITELISTONLY'] ) return False - else: - logging.info('Nobody is on the whitelist.') - self.sendmsg( - conf['IRC_CHANNEL'], - "@"+str(user), conf['MESSAGE']['WHITELISTONLY'] - ) - return False + + logging.warning('Nobody is on the whitelist.') + self.sendmsg( + conf['IRC_CHANNEL'], + "@"+str(user), conf['MESSAGE']['WHITELISTONLY'] + ) + return False logging.info('Valid TTS message, adding to raw queue') tts = True @@ -424,6 +299,191 @@ class IRC: return False + class Commands(): + """ Bot commands """ + + def __init__(self): + self.tts_denied = [] + self.tts_allowed = [] + self.quickvote_status = self.quickvote_status + self.votemsg = self.votemsg + self.poll = self.poll + self.pollcount = self.pollcount + + def quickvote(self, msg): + """ !quickvote command + + Starts or stops the !quickvote function. On stop calculates the 5 most casted + votes and send them to chat. The highest vote is send to msg_queue. + + :param str msg: The IRC message triggering the command + """ + + if self.quickvote_status: + logging.debug('Quickvote stopped') + + if self.pollcount == 0: + logging.info("Nobody voted") + IRC.sendmsg(self, conf['IRC_CHANNEL'], "@chat", conf['MESSAGE']['VOTEEND']) + IRC.sendmsg(self, conf['IRC_CHANNEL'], "*", conf['MESSAGE']['VOTENOBODY']) + + raw_msg = { + "TTS": True, + "msg": conf['MESSAGE']['VOTENOBODY'], + "badges": True, + "subscriber": True, + "msgid": True, + "user": conf['IRC_USERNAME'], + "length": conf['IRC_TTS_LEN'], + "queuetime": datetime.datetime.now(), + "timestamp": str(time.time_ns()) + } + msg_queue[raw_msg['timestamp']] = [raw_msg['user'], raw_msg['msg']] + + logging.info('The result is: %s', conf['MESSAGE']['VOTENOBODY']) + logging.debug('Votemsg: %s', msg) + + self.quickvote_status = False + self.poll = {} + return False + + logging.info("Counting votes") + count = 0 + count = Counter(self.poll.values()).most_common(5) + IRC.sendmsg(self, conf['IRC_CHANNEL'], "@chat", conf['MESSAGE']['VOTEEND']) + + logging.debug(count) + + raw_msg = { + "TTS": True, + "msg": conf['MESSAGE']['VOTERESULT'] +" "+ str(count[0][0].replace('#','')), + "badges": True, + "subscriber": True, + "msgid": True, + "user": conf['IRC_USERNAME'], + "length": conf['IRC_TTS_LEN'], + "queuetime": datetime.datetime.now(), + "timestamp": str(time.time_ns()) + } + msg_queue[raw_msg['timestamp']] = [raw_msg['user'], raw_msg['msg']] + + logging.info('The result is: %s', conf['MESSAGE']['VOTERESULT'] +" "+ str(count[0])) + logging.debug('Votemsg: %s', msg) + + for key, value in count: + IRC.sendmsg( + self, + conf['IRC_CHANNEL'], "*", + str(key)+" ("+str(value)+ " "+ conf['MESSAGE']['VOTES'] + ")" + ) + + self.quickvote_status = False + self.poll = {} + self.pollcount = 0 + return + + logging.debug('Quickvote started') + self.quickvote_status = True + self.votemsg = msg.split('!quickvote', 1)[1].strip() + if self.votemsg: + IRC.sendmsg(self, + conf['IRC_CHANNEL'], "@chat", + conf['MESSAGE']['VOTESTART'] + " (" + str(self.votemsg) + ")" + ) + else: + IRC.sendmsg(self, conf['IRC_CHANNEL'], "@chat", conf['MESSAGE']['VOTESTART']) + + return + + def random(self, msg): + """ !random command + + Read a random line from randomfile and put it into msg_queue + If no file is given in msg a standard file will be used + + :param str msg: The IRC message triggering the command + :raise: FileNotFoundError if randomfile does not exists + :return: True if line was successfully read and added to msg_queue + :rtype: bool + """ + + randomfile = msg.replace('!random', '').strip().lower() + + if randomfile: + randomfile = "random_"+str(os.path.basename(randomfile))+".txt" + else: + randomfile = "random.txt" + + try: + with open(randomfile,"r", encoding="utf-8") as file: + lines = file.read().splitlines() + random_msg = random.choice(lines) + except FileNotFoundError: + logging.error('%s not found', randomfile) + return False + + raw_msg = { + "TTS": True, + "msg": random_msg, + "badges": True, + "subscriber": True, + "msgid": True, + "user": conf['IRC_USERNAME'], + "length": conf['IRC_TTS_LEN'], + "queuetime": datetime.datetime.now(), + "timestamp": str(time.time_ns()) + } + msg_queue[raw_msg['timestamp']] = [raw_msg['user'], raw_msg['msg']] + + return True + + def ptts(self, msg): + """ !ptts command + + Add user to tts_allowed list and remove user from tts_denied list + + :param str msg: The IRC message triggering the command + """ + + user = msg.replace('!ptts', '').strip().lower() + + if user.startswith('@'): + logging.debug('Removing "@" from username') + user = user.replace('@', '') + + logging.info("Adding %s to whitelist", user) + self.tts_allowed.append(user) + + if user in self.tts_denied: + logging.info("Removing %s from deny list", user) + self.tts_denied.remove(user) + + return + + def dtts(self, msg): + """ !dtts command + + Add user to tts_denied list and remove user from tts_allowed list + + :param str msg: The IRC message triggering the command + """ + + user = msg.replace('!dtts', '').strip().lower() + + if user.startswith('@'): + logging.debug('Removing "@" from username') + user = user.replace('@', '') + + if user not in self.tts_denied: + logging.info("Adding %s to deny list", user) + self.tts_denied.append(user) + + if user in self.tts_allowed: + logging.info("Removing %s from allowed list", user) + self.tts_allowed.remove(user) + + return + class HTTPserv(BaseHTTPRequestHandler): """Simple HTTP Server""" @@ -644,7 +704,7 @@ sys.tracebacklimit = 0 if sys.argv[1:]: if sys.argv[1] == "--version": print('Simple TTS Bot') - print('Version 1.2.0') + print('Version 1.2.1') sys.exit(1) def main(): @@ -692,21 +752,21 @@ def main(): try: irc.get_response() - if not irc.tts_status: - logging.debug("TTS is disabled") - if conf['LOG_LEVEL'] == "DEBUG": - time.sleep(1) - continue - confreload = datetime.datetime.now() if confreload - lastreload > datetime.timedelta(seconds=60): conf = load_config() lastreload = datetime.datetime.now() - if irc.quickvote and irc.votemsg: + if irc.quickvote_status and irc.votemsg: logging.info('Quickvote is active') irc.sendmsg(conf['IRC_CHANNEL'], "@chat", conf['MESSAGE']['VOTESTART'] + " (" + str(irc.votemsg) + ")") + if not irc.tts_status: + logging.debug("TTS is disabled") + if conf['LOG_LEVEL'] == "DEBUG": + time.sleep(1) + continue + logging.debug('Raw message queue:') logging.debug(msg_queue_raw)