From 290a09be5d423ecc6c72d7f8b7dd1d2f42ea3486 Mon Sep 17 00:00:00 2001 From: gpkvt Date: Sun, 28 Aug 2022 12:33:46 +0200 Subject: [PATCH] Removed subclass --- tts.py | 1062 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 532 insertions(+), 530 deletions(-) diff --git a/tts.py b/tts.py index 702432b..ce2c2a3 100644 --- a/tts.py +++ b/tts.py @@ -58,9 +58,7 @@ class IRC: } self.quickvote = { "status": False, - "message": False - } - self.poll = { + "message": False, "count": 0, "data": {} } @@ -241,30 +239,30 @@ class IRC: if msg.startswith('#') and self.quickvote['status'] is True: logging.info('Quickvote: Cast detected') - self.poll['count'] += 1 - self.poll['data'][user] = msg.lower() - logging.debug("poll: %s", self.poll) + self.quickvote['count'] += 1 + self.quickvote['data'][user] = msg.lower() + logging.debug("quickvote: %s", self.quickvote) return if msg.startswith('!tts'): logging.info('!tts command detected') - self.Commands.tts(self, message, tags) + self.ttscmd(message, tags) return if msg.startswith('!wiki') and CONF['FEATURE']['WIKI']: logging.debug("!wiki command detected") - self.Commands.wiki(self, tags, msg) + self.wiki(tags, msg) return if CONF['FEATURE']['QUOTE']: if msg.startswith('!addquote'): logging.debug("!addquote command detected") - self.Commands.addquote(self, tags, msg) + self.addquote(tags, msg) return if msg.startswith('!smartquote') or msg.startswith('!sq'): logging.debug("!smartquote command detected") - self.Commands.quote(self, tags, msg) + self.quote(tags, msg) return def priviledged_commands(self, message, tags): @@ -319,31 +317,31 @@ class IRC: elif msg.startswith('!pick') and CONF['FEATURE']['PICK']: logging.debug("!pick command detected") - self.Commands.pick(self, msg) + self.pickcmd(msg) elif msg.startswith('!random') and CONF['FEATURE']['RANDOM']: logging.info('!random command detected') - self.Commands.random(self, msg) + self.random(msg) elif msg.startswith('!quickvote') and CONF['FEATURE']['QUOTE']: logging.info("!quickvote command detected") - self.Commands.quickvote(self, msg) + self.quickvotecmd(msg) elif msg.startswith('!ptts'): logging.debug("!ptts command detected") - self.Commands.ptts(self, msg) + self.ptts(msg) elif msg.startswith('!dtts'): logging.debug("!dtts command detected") - self.Commands.dtts(self, msg) + self.dtts(msg) elif msg.startswith('!usermap'): logging.info('!usermap command detected') - self.Commands.usermap(self, msg) + self.usermap(msg) elif msg.startswith('!delay'): logging.info('!delay command detected') - self.Commands.delay(self, msg) + self.delay(msg) def check_subonly(self, tags): """ Check if subonly mode is enabled and sender is sub @@ -538,511 +536,237 @@ class IRC: if resp.find('PRIVMSG') != -1: self.resp_privmsg(resp) - class Commands(): - """ Bot commands """ + def ttscmd(self, msg, tags): + """ !tts command - def __init__(self): - self.tts_denied = [] - self.tts_allowed = [] - self.quickvote_status = self.quickvote_status - self.pick_status = self.pick_status - self.votemsg = self.votemsg - self.poll = self.poll - self.pollcount = self.pollcount - self.pickme = self.pickme - self.picknumber = self.picknumber - self.pickcount = self.pickcount + Check if message is valid and send it to queue - def tts(self, msg, tags): - """ !tts command + :param str msg: The IRC message triggering the command + :param dict tags: The message metadata + """ - Check if message is valid and send it to queue + user = tags['user'] - :param str msg: The IRC message triggering the command - :param dict tags: The message metadata - """ + if IRC.check_tts_disabled(self, user): + logging.info('TTS is disabled') + elif IRC.check_msg_too_long(self, msg, user): + logging.info('TTS message is too long') + elif IRC.check_user_denied(self, user): + logging.info('User is not allowed to use TTS') + elif IRC.check_subonly(self, tags): + logging.info('TTS is sub-only') + elif IRC.check_modonly(self, tags): + logging.info('TTS is mod-only') + elif IRC.check_whitelist(self, user): + logging.info('User is not on whitelist') + else: + logging.info('Sending TTS message to raw_queue') + IRC.send_tts_msg(self, msg, tags) - user = tags['user'] + def addquote(self, tags, msg): + """ !addquote command - if IRC.check_tts_disabled(self, user): - logging.info('TTS is disabled') - elif IRC.check_msg_too_long(self, msg, user): - logging.info('TTS message is too long') - elif IRC.check_user_denied(self, user): - logging.info('User is not allowed to use TTS') - elif IRC.check_subonly(self, tags): - logging.info('TTS is sub-only') - elif IRC.check_modonly(self, tags): - logging.info('TTS is mod-only') - elif IRC.check_whitelist(self, user): - logging.info('User is not on whitelist') - else: - logging.info('Sending TTS message to raw_queue') - IRC.send_tts_msg(self, msg, tags) + Adds a newline to quotes.txt - def addquote(self, tags, msg): - """ !addquote command + :param dict tags: Message metadata (tags) + :param str msg: IRC message triggering the command + """ - Adds a newline to quotes.txt - - :param dict tags: Message metadata (tags) - :param str msg: IRC message triggering the command - """ - - user = tags['user'] - - if IRC.check_user_denied(self, user): - logging.info('User is not allowed to use TTS') - elif IRC.check_subonly(self, tags): - logging.info('TTS is sub-only') - else: - try: - with open("quotes.txt", "rb") as file: - nol = len(file.readlines()) - file.close() - except FileNotFoundError: - logging.warning("quotes.txt does not exists, will create") - nol = 0 - - nol = nol + 1 - quote = msg.replace("!addquote ", "").strip() - quote = quote.split(" ",1) - username = quote[0] - - date = time.strftime("%d.%m.%Y") - - try: - token = CONF['IRC_OAUTH_TOKEN'].replace('oauth:','') - login = CONF['IRC_CHANNEL'].replace('#','') - api_endpoint = f"https://api.twitch.tv/helix/users?login={login}" - headers = { - 'Content-type': 'application/x-form-urlencoded', - 'Authorization': 'Bearer '+token, - 'Client-Id': 'ebo548vs6tq54c9zlrgin2yfzzlrrs' - } - req = requests.get(url=api_endpoint, headers=headers) - data = req.json() - user_id = data['data'][0]['id'] - - api_endpoint = f"https://api.twitch.tv/helix/channels?broadcaster_id={user_id}" - headers = { - 'Content-type': 'application/x-form-urlencoded', - 'Authorization': 'Bearer '+token, - 'Client-Id': 'ebo548vs6tq54c9zlrgin2yfzzlrrs' - } - req = requests.get(url=api_endpoint, headers=headers) - data = req.json() - - game = data['data'][0]['game_name'] - quote = f"#{nol}: \"{quote[1]}\" -{username}/{game} ({date})\n" - except Exception: - logging.warning('Could not get metadata for quote') - quote = f"#{nol}: \"{quote[1]}\" -{username} ({date})\n" - - logging.info('Adding quote %s', quote) - with open("quotes.txt", "ab") as file: - file.write(quote.encode('utf-8')) - - message = f"{CONF['MESSAGE']['QUOTE_ADDED_PREFIX']} \ - #{nol} {CONF['MESSAGE']['QUOTE_ADDED_SUFFIX']}" - raw_msg = { - "TTS": True, - "msg": message, - "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']] - IRC.sendmsg(self, CONF['IRC_CHANNEL'], "@"+str(user), message) - - def wiki(self, tags, msg): - """ !wiki command - - Search for wikipedia articles and return the first 3 sentences - - :param dict tags: Message metadata (tags) - :param str msg: IRC message triggering the command - """ + user = tags['user'] + if IRC.check_user_denied(self, user): + logging.info('User is not allowed to use TTS') + elif IRC.check_subonly(self, tags): + logging.info('TTS is sub-only') + else: try: - user = tags['user'] - wikipedia.set_lang(CONF['WIKI_LANG']) - msg = msg.replace('!wiki', '').strip() - wikiresult = wikipedia.summary(msg, sentences=3) - - IRC.sendmsg(self, CONF['IRC_CHANNEL'], "@"+str(user), wikiresult) - IRC.sendmsg(self, CONF['IRC_CHANNEL'], "@"+str(user), wikipedia.page(msg).url) - - message = wikiresult.replace('==', '') - raw_msg = { - "TTS": True, - "msg": message, - "badges": True, - "subscriber": True, - "msgid": True, - "user": 'wikipedia', - "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']] - - except wikipedia.exceptions.DisambiguationError: - user = f"@{user}" - IRC.sendmsg(self, CONF['IRC_CHANNEL'], user, CONF['MESSAGE']['WIKI_TOO_MANY']) - except Exception: - user = f"@{user}" - IRC.sendmsg(self, CONF['IRC_CHANNEL'], user, CONF['MESSAGE']['WIKI_NO_RESULT']) - - def quote(self, tags, msg = False): - """ !smartquote command - - Gets a line from quotes.txt. If a number if given as msg - it fetches the given line number. If a string is given - it fetches the best matching line. If nothing is given - it fetches a random line. - - :param dict tags: Message metadata (tags) - :param str msg: IRC message triggering the command - """ - - try: - user = tags['user'] - query = msg.replace('!smartquote', '').strip() - query = msg.replace('!sq', '').strip() - - if query.isdigit(): - logging.info('Fetching quote #%s', query) - - file = open("quotes.txt", "rb") - quotes = file.readlines() - - for line in quotes: - if line.decode('utf-8').startswith("#"+str(query)+":"): - quote = line - break - file.close() - - elif query != "": - logging.info('Fetching match for %s', query) - - file = open("quotes.txt", "rb") - quotes = file.readlines() - matches = process.extract(query, quotes, limit=10) - quotes = [] - - for match, score in matches: - if score >= 60: - quotes.append(match) - - logging.debug('Quotes: %s', quotes) - if len(quotes) >= 5: - quote = random.choice(quotes) - else: - quote = quotes[0] - - else: - logging.info('Fetching random quote') - - with open("quotes.txt", "rb") as file: - lines = file.read().splitlines() - quote = random.choice(lines) + with open("quotes.txt", "rb") as file: + nol = len(file.readlines()) + file.close() except FileNotFoundError: - logging.error('"quotes.txt does not exists.') - except IndexError: - logging.error('Error fetching quote.') + logging.warning("quotes.txt does not exists, will create") + nol = 0 - if not 'quote' in vars(): - logging.info('No quote found.') - quote = CONF['MESSAGE']['QUOTE_NOT_FOUND'] - IRC.sendmsg(self, CONF['IRC_CHANNEL'], "", quote) - return False + nol = nol + 1 + quote = msg.replace("!addquote ", "").strip() + quote = quote.split(" ",1) + username = quote[0] - if not isinstance(quote, str): - quote = quote.decode('utf-8') + date = time.strftime("%d.%m.%Y") - if IRC.check_tts_disabled(self, user): - logging.info('TTS is disabled') - elif IRC.check_user_denied(self, user): - logging.info('User is not allowed to use TTS') - elif IRC.check_subonly(self, tags): - logging.info('TTS is sub-only') - elif IRC.check_modonly(self, tags): - logging.info('TTS is mod-only') - elif IRC.check_whitelist(self, user): - logging.info('User is not on whitelist') - else: - logging.info('Sending quote to TTS') - logging.debug("Quote: %s", quote) - IRC.sendmsg(self, CONF['IRC_CHANNEL'], "", quote) - - message = quote.rsplit('(', 1)[0] - raw_msg = { - "TTS": True, - "msg": message, - "badges": True, - "subscriber": True, - "msgid": True, - "user": CONF['IRC_USERNAME'], - "length": CONF['IRC_TTS_LEN'], - "queuetime": datetime.datetime.now(), - "timestamp": str(time.time_ns()) + try: + token = CONF['IRC_OAUTH_TOKEN'].replace('oauth:','') + login = CONF['IRC_CHANNEL'].replace('#','') + api_endpoint = f"https://api.twitch.tv/helix/users?login={login}" + headers = { + 'Content-type': 'application/x-form-urlencoded', + 'Authorization': 'Bearer '+token, + 'Client-Id': 'ebo548vs6tq54c9zlrgin2yfzzlrrs' } - msg_queue[raw_msg['timestamp']] = [raw_msg['user'], raw_msg['msg']] + req = requests.get(url=api_endpoint, headers=headers) + data = req.json() + user_id = data['data'][0]['id'] - return True - - def delay(self, msg): - """ !delay command - - Adjust the delay setting in config.yml - - :param str msg: The IRC message triggering the command - """ - - try: - delay = msg.split(' ')[1] - except Exception: - delay = False - - if delay: - with open('config.yml','r', encoding='utf-8') as yamlfile: - cur_yaml = yaml.safe_load(yamlfile) - cur_yaml['irc']['clearmsg_timeout'] = int(delay) - - if cur_yaml: - with open('config.yml','w', encoding='utf-8') as yamlfile: - yaml.safe_dump(cur_yaml, yamlfile) - load_config() - - - def usermap(self, msg): - """ !usermap command - - Adds a new entry to usermapping in config.yml - - :param str msg: The IRC message triggering the command - """ - - try: - msg = msg.replace('!usermap ', '') - splitmsg = msg.split(" ") - username, *mappingname = splitmsg - mappingname = ' '.join(mappingname) - except Exception: - username = False - mappingname = False - - if username and mappingname: - with open('config.yml','r', encoding='utf-8') as yamlfile: - cur_yaml = yaml.safe_load(yamlfile) - cur_yaml['usermapping'].update({username: mappingname}) - - if cur_yaml: - with open('config.yml','w', encoding='utf-8') as yamlfile: - yaml.safe_dump(cur_yaml, yamlfile) - load_config() - - def pick(self, msg): - """ !pick command - - Pick a number of users who typed #pickme in the chat - after the pick command was started. - - :param str msg: Number of users to pick - """ - - if self.pick_status: - logging.info('Pick stopped') - logging.debug("Got %s participats, wanted %s", self.pickcount, self.picknumber) - - try: - if int(self.pickcount) > int(self.picknumber): - picks = random.sample(self.pickme, self.picknumber) - logging.info('Got more than the requested number of participants') - else: - picks = self.pickme - logging.info('Got less than or exactly the \ - requested number of participants') - - converted_picks = [str(element) for element in picks] - joined_picks = " ".join(converted_picks) - except Exception: - logging.error("There was an error during picking.") - joined_picks = False - - message = f"{CONF['MESSAGE']['PICKRESULT']} {joined_picks}" - if joined_picks: - raw_msg = { - "TTS": True, - "msg": message, - "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']] - - IRC.sendmsg(self, - CONF['IRC_CHANNEL'], "", - CONF['MESSAGE']['PICKRESULT'] - ) - IRC.sendmsg(self, - CONF['IRC_CHANNEL'], "*", - joined_picks - ) - else: - IRC.sendmsg(self, - CONF['IRC_CHANNEL'], "*", - CONF['MESSAGE']['PICKNONE'] - ) - - self.pick_status = False - self.pickme = [] - self.pickcount = 0 - - return - - logging.debug('Pick started') - self.pick_status = True - try: - msg = msg.split(' ')[1].strip() - self.picknumber = msg - except IndexError: - self.picknumber = self.picknumber - - logging.info("Will pick %s participants", self.picknumber) - - IRC.sendmsg(self, - CONF['IRC_CHANNEL'], "@chat", - CONF['MESSAGE']['PICKSTART'] - ) - return - - 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 - - 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) - - count = str(count[0][0].replace('#','')) - message = f"{CONF['MESSAGE']['VOTERESULT']} {count}" - raw_msg = { - "TTS": True, - "msg": message , - "badges": True, - "subscriber": True, - "msgid": True, - "user": CONF['IRC_USERNAME'], - "length": CONF['IRC_TTS_LEN'], - "queuetime": datetime.datetime.now(), - "timestamp": str(time.time_ns()) + api_endpoint = f"https://api.twitch.tv/helix/channels?broadcaster_id={user_id}" + headers = { + 'Content-type': 'application/x-form-urlencoded', + 'Authorization': 'Bearer '+token, + 'Client-Id': 'ebo548vs6tq54c9zlrgin2yfzzlrrs' } - msg_queue[raw_msg['timestamp']] = [raw_msg['user'], raw_msg['msg']] + req = requests.get(url=api_endpoint, headers=headers) + data = req.json() - logging.info('The result is: %s', CONF['MESSAGE']['VOTERESULT'] +" "+ str(count[0])) - logging.debug('Votemsg: %s', msg) + game = data['data'][0]['game_name'] + quote = f"#{nol}: \"{quote[1]}\" -{username}/{game} ({date})\n" + except Exception: + logging.warning('Could not get metadata for quote') + quote = f"#{nol}: \"{quote[1]}\" -{username} ({date})\n" - for key, value in count: - message = f"{key} ({value}) {CONF['MESSAGE']['VOTES']})" - IRC.sendmsg( - self, - CONF['IRC_CHANNEL'], "*", - message - ) - - 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 - - :return bool: - """ - - randomfile = msg.replace('!random', '').strip().lower() - - if randomfile: - randomfile = f"random_{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 + logging.info('Adding quote %s', quote) + with open("quotes.txt", "ab") as file: + file.write(quote.encode('utf-8')) + message = f"{CONF['MESSAGE']['QUOTE_ADDED_PREFIX']} \ + #{nol} {CONF['MESSAGE']['QUOTE_ADDED_SUFFIX']}" raw_msg = { "TTS": True, - "msg": random_msg, + "msg": message, + "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']] + IRC.sendmsg(self, CONF['IRC_CHANNEL'], "@"+str(user), message) + + def wiki(self, tags, msg): + """ !wiki command + + Search for wikipedia articles and return the first 3 sentences + + :param dict tags: Message metadata (tags) + :param str msg: IRC message triggering the command + """ + + try: + user = tags['user'] + wikipedia.set_lang(CONF['WIKI_LANG']) + msg = msg.replace('!wiki', '').strip() + wikiresult = wikipedia.summary(msg, sentences=3) + + IRC.sendmsg(self, CONF['IRC_CHANNEL'], "@"+str(user), wikiresult) + IRC.sendmsg(self, CONF['IRC_CHANNEL'], "@"+str(user), wikipedia.page(msg).url) + + message = wikiresult.replace('==', '') + raw_msg = { + "TTS": True, + "msg": message, + "badges": True, + "subscriber": True, + "msgid": True, + "user": 'wikipedia', + "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']] + + except wikipedia.exceptions.DisambiguationError: + user = f"@{user}" + IRC.sendmsg(self, CONF['IRC_CHANNEL'], user, CONF['MESSAGE']['WIKI_TOO_MANY']) + except Exception: + user = f"@{user}" + IRC.sendmsg(self, CONF['IRC_CHANNEL'], user, CONF['MESSAGE']['WIKI_NO_RESULT']) + + def quote(self, tags, msg = False): + """ !smartquote command + + Gets a line from quotes.txt. If a number if given as msg + it fetches the given line number. If a string is given + it fetches the best matching line. If nothing is given + it fetches a random line. + + :param dict tags: Message metadata (tags) + :param str msg: IRC message triggering the command + """ + + try: + user = tags['user'] + query = msg.replace('!smartquote', '').strip() + query = msg.replace('!sq', '').strip() + + if query.isdigit(): + logging.info('Fetching quote #%s', query) + + file = open("quotes.txt", "rb") + quotes = file.readlines() + + for line in quotes: + if line.decode('utf-8').startswith("#"+str(query)+":"): + quote = line + break + file.close() + + elif query != "": + logging.info('Fetching match for %s', query) + + file = open("quotes.txt", "rb") + quotes = file.readlines() + matches = process.extract(query, quotes, limit=10) + quotes = [] + + for match, score in matches: + if score >= 60: + quotes.append(match) + + logging.debug('Quotes: %s', quotes) + if len(quotes) >= 5: + quote = random.choice(quotes) + else: + quote = quotes[0] + + else: + logging.info('Fetching random quote') + + with open("quotes.txt", "rb") as file: + lines = file.read().splitlines() + quote = random.choice(lines) + except FileNotFoundError: + logging.error('"quotes.txt does not exists.') + except IndexError: + logging.error('Error fetching quote.') + + if not 'quote' in vars(): + logging.info('No quote found.') + quote = CONF['MESSAGE']['QUOTE_NOT_FOUND'] + IRC.sendmsg(self, CONF['IRC_CHANNEL'], "", quote) + return False + + if not isinstance(quote, str): + quote = quote.decode('utf-8') + + if IRC.check_tts_disabled(self, user): + logging.info('TTS is disabled') + elif IRC.check_user_denied(self, user): + logging.info('User is not allowed to use TTS') + elif IRC.check_subonly(self, tags): + logging.info('TTS is sub-only') + elif IRC.check_modonly(self, tags): + logging.info('TTS is mod-only') + elif IRC.check_whitelist(self, user): + logging.info('User is not on whitelist') + else: + logging.info('Sending quote to TTS') + logging.debug("Quote: %s", quote) + IRC.sendmsg(self, CONF['IRC_CHANNEL'], "", quote) + + message = quote.rsplit('(', 1)[0] + raw_msg = { + "TTS": True, + "msg": message, "badges": True, "subscriber": True, "msgid": True, @@ -1053,50 +777,328 @@ class IRC: } msg_queue[raw_msg['timestamp']] = [raw_msg['user'], raw_msg['msg']] - return True + return True - def ptts(self, msg): - """ !ptts command + def delay(self, msg): + """ !delay command - Add user to tts_allowed list and remove user from tts_denied list + Adjust the delay setting in config.yml - :param str msg: The IRC message triggering the command - """ + :param str msg: The IRC message triggering the command + """ - user = msg.replace('!ptts', '').strip().lower() + try: + delay = msg.split(' ')[1] + except Exception: + delay = False - if user.startswith('@'): - logging.debug('Removing "@" from username') - user = user.replace('@', '') + if delay: + with open('config.yml','r', encoding='utf-8') as yamlfile: + cur_yaml = yaml.safe_load(yamlfile) + cur_yaml['irc']['clearmsg_timeout'] = int(delay) - logging.info("Adding %s to whitelist", user) - self.tts_allowed.append(user) + if cur_yaml: + with open('config.yml','w', encoding='utf-8') as yamlfile: + yaml.safe_dump(cur_yaml, yamlfile) + load_config() - if user in self.tts_denied: - logging.info("Removing %s from deny list", user) - self.tts_denied.remove(user) - def dtts(self, msg): - """ !dtts command + def usermap(self, msg): + """ !usermap command - Add user to tts_denied list and remove user from tts_allowed list + Adds a new entry to usermapping in config.yml - :param str msg: The IRC message triggering the command - """ + :param str msg: The IRC message triggering the command + """ - user = msg.replace('!dtts', '').strip().lower() + try: + msg = msg.replace('!usermap ', '') + splitmsg = msg.split(" ") + username, *mappingname = splitmsg + mappingname = ' '.join(mappingname) + except Exception: + username = False + mappingname = False - if user.startswith('@'): - logging.debug('Removing "@" from username') - user = user.replace('@', '') + if username and mappingname: + with open('config.yml','r', encoding='utf-8') as yamlfile: + cur_yaml = yaml.safe_load(yamlfile) + cur_yaml['usermapping'].update({username: mappingname}) - if user not in self.tts_denied: - logging.info("Adding %s to deny list", user) - self.tts_denied.append(user) + if cur_yaml: + with open('config.yml','w', encoding='utf-8') as yamlfile: + yaml.safe_dump(cur_yaml, yamlfile) + load_config() - if user in self.tts_allowed: - logging.info("Removing %s from allowed list", user) - self.tts_allowed.remove(user) + def pickcmd(self, msg): + """ !pick command + + Pick a number of users who typed #pickme in the chat + after the pick command was started. + + :param str msg: Number of users to pick + """ + + if self.pick['status']: + logging.info('Pick stopped') + logging.debug("Got %s participats, wanted %s", + self.pick['count'], + self.pick['number'] + ) + + try: + if int(self.pick['count']) > int(self.pick['number']): + picks = random.sample(self.pick['pickme'], self.pick['number']) + logging.info('Got more than the requested number of participants') + else: + picks = self.pick['pickme'] + logging.info('Got less than or exactly the \ + requested number of participants') + + converted_picks = [str(element) for element in picks] + joined_picks = " ".join(converted_picks) + except Exception: + logging.error("There was an error during picking.") + joined_picks = False + + message = f"{CONF['MESSAGE']['PICKRESULT']} {joined_picks}" + if joined_picks: + raw_msg = { + "TTS": True, + "msg": message, + "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']] + + IRC.sendmsg(self, + CONF['IRC_CHANNEL'], "", + CONF['MESSAGE']['PICKRESULT'] + ) + IRC.sendmsg(self, + CONF['IRC_CHANNEL'], "*", + joined_picks + ) + else: + IRC.sendmsg(self, + CONF['IRC_CHANNEL'], "*", + CONF['MESSAGE']['PICKNONE'] + ) + + self.pick['status'] = False + self.pick['pickme'] = [] + self.pick['count'] = 0 + + return + + logging.debug('Pick started') + self.pick['status'] = True + try: + msg = msg.split(' ')[1].strip() + self.pick['number'] = msg + except IndexError: + self.pick['number'] = self.pick['number'] + + logging.info("Will pick %s participants", self.pick['number']) + + IRC.sendmsg(self, + CONF['IRC_CHANNEL'], "@chat", + CONF['MESSAGE']['PICKSTART'] + ) + return + + def quickvotecmd(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.quickvote['count'] == 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.quickvote['data'] = {} + return + + logging.info("Counting votes") + count = 0 + count = Counter(self.quickvote['data'].values()).most_common(5) + IRC.sendmsg(self, CONF['IRC_CHANNEL'], "@chat", CONF['MESSAGE']['VOTEEND']) + + logging.debug(count) + + count = str(count[0][0].replace('#','')) + message = f"{CONF['MESSAGE']['VOTERESULT']} {count}" + raw_msg = { + "TTS": True, + "msg": message , + "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: + message = f"{key} ({value}) {CONF['MESSAGE']['VOTES']})" + IRC.sendmsg( + self, + CONF['IRC_CHANNEL'], "*", + message + ) + + self.quickvote['status'] = False + self.quickvote['data'] = {} + self.quickvote['count'] = 0 + return + + logging.debug('Quickvote started') + self.quickvote['status'] = True + self.quickvote['message'] = msg.split('!quickvote', 1)[1].strip() + if self.quickvote['message']: + IRC.sendmsg( + self, + CONF['IRC_CHANNEL'], "@chat", + CONF['MESSAGE']['VOTESTART'] + " (" + str(self.quickvote['message']) + ")" + ) + 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 + + :return bool: + """ + + randomfile = msg.replace('!random', '').strip().lower() + + if randomfile: + randomfile = f"random_{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['whitelist'].append(user) + + if user in self.tts['blacklist']: + logging.info("Removing %s from deny list", user) + self.tts['blacklist'].remove(user) + + 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['blacklist']: + logging.info("Adding %s to deny list", user) + self.tts['blacklist'].append(user) + + if user in self.tts['whitelist']: + logging.info("Removing %s from allowed list", user) + self.tts['whitelist'].remove(user) class ThreadingSimpleServer(ThreadingMixIn, HTTPServer): """ Threaded HTTP Server """