def requestFromChat(): global runBot print("Starting thread") while True: response = twitchSocket.recv(1024).decode("utf-8") print(str(response)) if response == "PING :tmi.twitch.tv\r\n": twitchSocket.send("PONG :tmi.twitch.tv\r\n".encode("utf-8")) else: username = re.search(r"\w+", response).group(0) message = CHAT_MSG.sub("", response) print(message) lowerCase = message.lower() splitMessage = lowerCase.split() if len(splitMessage) == 1: with runBotLock: command = splitMessage[0] if command == 'startbot' and username in cfg.allowedOperators: runBot = True chat(twitchSocket, 'Chat drums enabled MAKE SOME NOISE!') elif command == 'stopbot' and username in cfg.allowedOperators: runBot = False chat( twitchSocket, '"Chat drums have been put away, they will be back soon' ) elif runBot: if command in cfg.commands: requestQueue.put(command)
def showArmor(s, username, character, items, chan): print items utils.chat( s, "Armor Info:coat::\n - Name: " + items[character.armor].name + "\n - Description: " + items[character.armor].desc + "\n - Armor Rating: " + str(items[character.armor].armor), character.whisperMode, username, chan)
def showShield(s, username, character, items, chan): print items utils.chat( s, "Shield Info:shield::\n - Name: " + items[character.shield].name + "\n - Description: " + items[character.shield].desc + "\n - Armor Rating: " + str(items[character.shield].armor), character.whisperMode, username, chan)
def getPoints(username, twitchSocket): """ Reports the number of pebbles a user currently has username -- The user to get pebbles for twitchSocket -- The socket connection to twitch """ chat(sock=twitchSocket, msg="@" + username + ", you have " + str(getUserPebbles(username)) + " pebbles")
def showWeapon(s, username, character, items, chan): print items utils.chat( s, "Weapon Info:dagger_knife::\n - Name: " + items[character.weapon].name + " \n - Description: " + items[character.weapon].desc + " \n - Damage: " + str(items[character.weapon].damage), character.whisperMode, username, chan)
def toggleWhisper(s, username, character, chan): if character.whisperMode == 0: character.whisperMode = 1 utils.chat(s, "<@" + username + "> whisper mode has been enabled.", character.whisperMode, username, chan) else: character.whisperMode = 0 utils.chat(s, "<@" + username + "> whisper mode has been disabled.", character.whisperMode, username, chan)
def unequipShield(s, username, character, chan): if character.shield == 0: utils.chat( s, "<@" + username + "> you already don't have a shield equipped!", character.whisperMode, username, chan) else: character.shield = 0 utils.chat( s, "<@" + username + "> you take your shield and shove it in your bottomless bag.", character.whisperMode, username, chan)
def unequipArmor(s, username, character, chan): if character.armor == 0: utils.chat( s, "<@" + username + "> you already don't have any armor equipped!", character.whisperMode, username, chan) else: character.armor = 0 utils.chat( s, "<@" + username + "> you take your armor and you somehow manage to fit the whole bulk of it in your bottomless bad, you're basically naked now you dirty dog you!", character.whisperMode, username, chan)
def unequipWeapon(s, username, character, chan): if character.weapon == 0: utils.chat( s, "<@" + username + "> you already don't have a weapon equipped!", character.whisperMode, username, chan) else: character.weapon = 0 utils.chat( s, "<@" + username + "> you take your weapon and you stash it in your magical semi-bottomless bag.", character.whisperMode, username, chan)
def storages_info(): if not nextbox_sub_ensure(2): return False items_mounted = '//*[@id="app-content-vue"]/div/div[1]/*/button' items_unmounted = '//*[@id="app-content-vue"]/div/div[2]/*/button' top = get_xpath(items_mounted, as_list=True) bottom = get_xpath(items_unmounted, as_list=True) chat(f"storages: top: #{top} - bottom: #{bottom}") return {"top": top or [], "bottom": bottom or []}
def ensure_host(host, proto=None): url_toks = br.current_url.split("/") my_host = url_toks[2] my_proto = url_toks[0][:-1] if host != my_host or (proto is not None and my_proto != proto): proto = proto or my_proto url = f"{proto}://{host}" open_page(url) chatty_sleep( f"tried to ensure: {host}, but found {my_host} -> getting: {url}") else: chat(f"ensuring url points to: {proto or my_proto}://{host}")
def setup_and_test_tls(): if not nextbox_sub_ensure(7): return False button_xp = '//*[@id="app-content-vue"]/div/div/div/div/button' if not input_into_text_field( '//*[@id="app-content-vue"]/div/div/div/div/input', conf["email"]): chat("mmmh, TLS already enabled, uha: this might be painful...") if not test_and_click_button(button_xp): return False chat( "now waiting (~15secs) for apache restart => jump back to non-https (i.e., recurse!)" ) br.delete_all_cookies() sleep(5) return setup_and_test_tls() sleep(1) if not test_and_click_button(button_xp): chat("cannot click button to activate, giving up...") return False chat( "ok, certificate is on the way, let's wait some secs then check, if it works" ) sleep(10) return test_for_valid_login_page(conf["static_domain"], "https")
def setup_and_test_proxy(): if not nextbox_sub_ensure(5): return False input_xp = '//*[@id="app-content-vue"]/div/div[2]/input' button_xp = '//*[@id="app-content-vue"]/div/div[2]/button' but = get_xpath(button_xp) inp = get_xpath(input_xp) # no input? means proxy is active! if not inp: chat("proxy is enabled, disabling first") but.click() ret = input_into_text_field(input_xp, conf["proxy_domain"]) if not ret: chat("failed input of proxy_domain") return False if not test_and_click_button(button_xp): chat("failed button click") return False chat("checking 'new' login page now") return test_for_valid_login_page(conf["proxy_domain"], "https")
def main(): # Networking functions s = socket.socket() s.connect((cfg.HOST, cfg.PORT)) s.send("PASS {}\r\n".format(cfg.PASS).encode("utf-8")) s.send("NICK {}\r\n".format(cfg.NICK).encode("utf-8")) s.send("JOIN #{}\r\n".format(cfg.CHAN).encode("utf-8")) CHAT_MSG = re.compile(r"^:\w+!\w+@\w+\.tmi\.twitch\.tv PRIVMSG #\w+ :") utils.chat(s, "Hi everyone!") thread.start_new_thread(utils.threadFillOpList, ()) while True: response = s.recv(1024).decode("utf-8") if response == "PINT :time.twitch.tv\r\n": s.send("PONG :tmi.twitch.tv\r\n".encode("utf-8")) else: username = re.search(r"\w+", response).group(0) message = CHAT_MSG.sub("", response) print(response) # Custom commands if message.strip() == "!time": utils.chat(s, "It is currently " + time.strftime("%I:%M %p %Z on %A, %B %d, %Y.")) if message.strip() == "!messages" and utils.isOp(username): utils.chat(s, "Welcome to KBman99's Live Stream! Please follow below to see when I go live next!") if message.strip() == "!twitter": utils.chat(s, "My twitter is https://twitter.com/_the_kB") sleep(1)
def songRequest(username, url, twitchSocket, requestType=None): """ Adds a song to the queue, user must have enough pebbles as determined in cfg username -- the user requesting a song twithcSocket -- The socket connection to twitch """ numPebbles = getUserPebbles(username) if numPebbles < REQUEST_COST: chat(sock=twitchSocket, msg="@" + username + ", you need: " + str(REQUEST_COST) + ", but only have: " + str(numPebbles) + " pebbles.") else: if userHasRequest(username=username): chat(sock=twitchSocket, msg="Sorry, @" + username + ", you already have a song in the queue. Limit is 1") else: addSongRequest(username, url, requestType) subtractPebbles(numPebbles=REQUEST_COST, username=username)
def main(): # Networking functions s = socket.socket() s.connect((cfg.HOST, cfg.PORT)) s.send("PASS {}\r\n".format(cfg.PASS).encode("utf-8")) s.send("NICK {}\r\n".format(cfg.NICK).encode("utf-8")) s.send("JOIN #{}\r\n".format(cfg.CHAN).encode("utf-8")) CHAT_MSG = re.compile(r"^:\w+!\w+@\w+\.tmi\.twitch\.tv PRIVMSG #\w+ :") utils.chat(s, "Hi everyone!") # threading.start_new_thread(utils.threadFillOpList, ()) x = threading.Thread(target=utils.threadFillOpList) x.start() ## Demarrage du module de paris nvbet = Bet() ## commands = sql.getCommands() ## cmd = [] ## for c in commands: ## cmd.append(Command(c["Command"], c["Response"], c["Description"], c["Op"])) ## while True: response = s.recv(1024).decode("utf-8") if response == "PING :tmi.twitch.tv\r\n": s.send("PONG :tmi.twitch.tv\r\n".encode("utf-8")) else: username = re.search(r"\w+", response).group(0) message = CHAT_MSG.sub("", response) print(response) if isCommand(message): command_name = message.split()[0] arguments = message.split()[1:] if command_name in scratch.cmd2.keys(): number_arguments = scratch.cmd2[command_name].arg scratch.cmd2[command_name].myFunction() else: print("Commande non répertoriée") if message.strip() == "test": print(cfg.oplist) sleep(1)
def random_nextcloud_walk(): chat("visiting some random nextcloud stuff") res = True for _ in ["files", "photos", "calendar", "mail"]: br.get(gen_url("/apps/files")) br.get(gen_url("/apps/files")) res &= wait_for_path("/apps/files") br.get(gen_url("/apps/photos")) res &= wait_for_path("/apps/photos") br.get(gen_url("/apps/calendar")) res &= wait_for_path("/apps/calendar") return res
def playAudio(sound): try: wf = wave.open( os.environ['HOMEPATH'] + '\\Desktop\ChatDrums\\' + sound + '.wav', 'rb') stream = p.open(format=p.get_format_from_width(wf.getsampwidth()), channels=wf.getnchannels(), rate=wf.getframerate(), output=True) data = wf.readframes(cfg.CHUNK) while len(data) > 0: stream.write(data) data = wf.readframes(cfg.CHUNK) stream.stop_stream() stream.close() except FileNotFoundError: chat(twitchSocket, 'Error: File not found')
def showInventory(s, username, character, items, chan): print items inventoryText = "" tempInv = str(character.inventory).split(',') print tempInv for i in tempInv: if items[int(i)].id == character.weapon or items[int( i)].id == character.armor or items[int( i)].id == character.shield: inventoryText += "\n - (" + str(i) + ")(E)" + items[int( i)].name + " " else: inventoryText += "\n - (" + str(i) + ")" + items[int(i)].name + " " utils.chat(s, "<@" + username + ">'s Inventory: " + inventoryText, character.whisperMode, username, chan)
def backup_test(): if not nextbox_sub_ensure(3): return False cont_button_xp = '//*[@id="app-content-vue"]/div/div/button' # if this button exists, then we've a not cleaned up backup wait_for_xpath(cont_button_xp, 5) continue_button = get_xpath(cont_button_xp) if continue_button.is_enabled(): chat("someone left his stuff here, cleaning up...") click_xpath(cont_button_xp) xp_dropdown = '//*[@id="app-content-vue"]/div/div[1]/div[1]/div[2]/input' if not wait_for_xpath(xp_dropdown, 5): return False # storage dropdown input field click_xpath(xp_dropdown) chat("chooosing target storage - 1st click the dropdown") # now select first storage click_xpath( '//*[@id="app-content-vue"]/div/div[1]/div[1]/div[3]/ul/li[1]/span/div/span[1]' ) chat("now click to choose") # now click into input field input_into_text_field('//*[@id="app-content-vue"]/div/div[1]/input', "xxxtest_backup_name") chat("enter our designated backup name") if not test_and_click_button( '//*[@id="app-content-vue"]/div/div[1]/button'): return False wait_for_xpath(cont_button_xp, 5) continue_button = get_xpath(cont_button_xp) log(f"waiting for backup...", " B ", end=" ", no_pad=False, flush=True) while not continue_button.is_enabled(): log(".", "", end="", no_pad=True, flush=True) sleep(0.5) print() banner_msg = get_xpath('//*[@id="app-content-vue"]/div/div/span').text # don't leave the backup un-cleaned-up click_xpath(cont_button_xp) if banner_msg == "Completed Backup successfully": return True return False
def main(): #Networking functions s = socket.socket() s.connect((cfg.HOST, cfg.PORT)) s.send("PASS {}\r\n".format(cfg.PASS).encode("utf-8")) s.send("NICK {}\r\n".format(cfg.NICK).encode("utf-8")) s.send("JOIN {}\r\n".format(cfg.CHAN).encode("utf-8")) #_thread.start_new_thread(utils.threadFillOpList, ()) #CHAT_MSG = re.compile(r"^:\w+!\w+@\w+\.tmi\.twitch\.tv PRIVMSG #\w+ :") CHAT_MSG = re.compile(r"^:\w+!\w+@\w+\.tmi\.twitch\.tv PRIVMSG #\w+ :") utils.chat(s, "hi mizzy wizzy!") start = time.time() while True: response = s.recv(2048).decode("utf-8") print(response) utils.mirror_msg(s, response)
def posReminder(isLive): # function to post a reminder to Twitch channel specified in cfg.py only if a stream is live # will post every 1 hour as long as channel is still live # Networking functions s = socket.socket() s.connect((cfg.HOST, cfg.PORT)) s.send("PASS {}\r\n".format(cfg.PASS).encode("utf-8")) s.send("NICK {}\r\n".format(cfg.NICK).encode("utf-8")) s.send("JOIN #{}\r\n".format(cfg.CHAN).encode("utf-8")) CHAT_MSG = re.compile(r"^:\w+!\w@\w+\.tmi\.twitch\.tv PRIVMSG #\w+ :") # message that will post to Twitch channel utils.chat(s, "Sit up straight and consider your posture.") sleep(3600) is_stream_live()
def sellItem(s, username, character, items, itemToSell, chan): inventory = character.inventory.split(',') print inventory # check if the item is equipped if str(itemToSell) in inventory: if itemToSell == character.weapon or itemToSell == character.shield or itemToSell == character.armor: utils.chat( s, "<@" + username + "> you have this item equipped, please unequip it if you want to sell it.", character.whisperMode, username, chan) else: print inventory list.remove(inventory, str(itemToSell)) character.money += items[itemToSell].trade_value print inventory character.inventory = ','.join(inventory) utils.chat( s, "<@" + username + "> you sold " + items[itemToSell].name + " for " + str(items[itemToSell].trade_value) + "copper.", character.whisperMode, username, chan) # character.inventory = ','.join(inventory) else: utils.chat(s, "<@" + username + "> you don't have that item.", character.whisperMode, username, chan)
def showEquipment(s, user, character, items, chan): print items if character.weapon == 0: weapon = "Nothing." else: weapon = items[character.weapon].name if character.armor == 0: armor = "Nothing." else: armor = items[character.armor].name if character.shield == 0: shield = "Nothing." else: shield = items[character.shield].name utils.chat( s, "<@" + user + "> your equipment you're using is: \n - Weapon:dagger_knife:: " + weapon + "\n - Armor:coat:: " + armor + "\n - Shield:shield:: " + shield + ".", character.whisperMode, user, chan)
def main(): # Networking functions s = socket.socket() s.connect((cfg_auth.HOST, cfg_auth.PORT)) s.send("PASS {}\r\n".format(cfg_auth.PASS).encode("utf-8")) s.send("NICK {}\r\n".format(cfg_auth.NICK).encode("utf-8")) s.send("JOIN {}\r\n".format(cfg_auth.CHAN).encode("utf-8")) # Media Player Setup player = playSong.MediaPlayer() thread.start_new_thread(player.play_video, ()) # Bot Setup CHAT_MSG = re.compile(r"^:\w+!\w+@\w+\.tmi\.twitch\.tv PRIVMSG #\w+ :") utils.chat(s, "Hi everyone!") thread.start_new_thread(utils.threadFillOpList, ()) while True: try: response = s.recv(1024).decode("utf-8") except socket.error, e: print e if response == "PING :tmi.twitch.tv\r\n": s.send("PONG :tmi.twitch.tv\r\n".encode("utf-8")) else: username = re.search(r"\w+", response).group(0) # return the entire match message = CHAT_MSG.sub("", response) print(username + ": " + message) # Custom Commands if message.strip() == "!vote energy": player.mood = "energy" if message.strip() == "!vote chill": player.mood = "chill" sleep(1.5)
def main(): # Networking functions s = socket.socket() s.connect((config.HOST, config.PORT)) s.send(f"PASS {config.PASS}\r\n".encode("utf-8")) s.send(f"NICK {config.USER}\r\n".encode("utf-8")) s.send(f"JOIN #{config.CHAN}\r\n".encode("utf-8")) chat_msg = re.compile(r"^:\w+!\w+@\w+\.tmi\.twitch\.tv PRIVMSG #\w+ :") utils.chat(s, config.CONNECT_MSG) _thread.start_new_thread(utils.threadFillOplist, ()) while True: response = s.recv(1024).decode("utf-8") if response == "PING :tmi.twitch.tv\r\n": # Handle twitch ping to maintain connection s.send("PONG :tmi.twitch.tv\r\n".encode("utf-8")) else: username = re.search(r"\w+", response).group(0) message = chat_msg.sub("", response) # Open and load all chat commands.json chat_commands = json.load(open("./commands.json", "r")) if message[0] == "!": message = message.split(' ', 1) command = message[0] bot_response = message[1] # First generic commands.json pre FILE IO # if message.strip() == '!time': # utils.chat(s, "It is currently " + time.strftime("%I:%M %p %Z on %A, %B %d, %Y. ")) # if message.strip() == "!messages" and utils.isAllowed(username): # utils.chat(s, "Please give me a follow on ") # utils.chat(s, "Support at ") print('test') time.sleep(1)
def parse(c, s): if c.response.find("~") > -1: list = c.response.split("~") for item in list: if item.find("{") > -1: code = item.split("{")[1].split("}")[0] utils.chat(s, item.split("{")[0] + eval(code)) else: utils.chat(s, item) else: if c.response.find("{") > -1: code = c.response.split("{")[1].split("}")[0] utils.chat(s, c.response.split("{")[0] + eval(code)) else: utils.chat(s, c.response)
def main(): # Networking functions s = socket.socket() s.connect((cfg.HOST, cfg.PORT)) s.send("PASS {}\r\n".format(cfg.PASS).encode("utf-8")) s.send("NICK {}\r\n".format(cfg.NICK).encode("utf-8")) s.send("JOIN #{}\r\n".format(cfg.CHAN).encode("utf-8")) CHAT_MSG = re.compile(r"^:\w+!\w+@\w+\.tmi\.twitch\.tv PRIVMSG #\w+ :") utils.chat(s, "Hi everyone!") thread.start_new_thread(utils.threadFillOpList, ()) commands = sql.getCommands() cmd = [] for c in commands: cmd.append(Command(c["Command"], c["Response"], c["Description"], c["Op"])) while True: response = s.recv(1024).decode("utf-8") if response == "PING :tmi.twitch.tv\r\n": s.send("PONG :tmi.twitch.tv\r\n".encode("utf-8")) else: username = re.search(r"\w+", response).group(0) message = CHAT_MSG.sub("", response) print(response) for c in cmd: if message.strip() == c.cmd: if c.op == 0: parse(c, s) else: if utils.isOp(username): parse(c, s) sleep(1) utils.chat(s, "Bye everyone :)");
def main(): # Networking functions engine = pyttsx.init() voices = engine.getProperty('voices') for voice in voices: print(voice) engine.setProperty(voice, voice.id) # changes the voice engine.say('Ready') engine.say("I am regy") engine.runAndWait() s = socket.socket() s.connect((keys.HOST, keys.PORT)) s.send("PASS {}\r\n".format(keys.PASS).encode("utf-8")) s.send("NICK {}\r\n".format(keys.NICK).encode("utf-8")) s.send("JOIN #{}\r\n".format(keys.chan).encode("utf-8")) CHAT_MSG = re.compile(r"^:\w+!\w+@\w+\.tmi\.twitch\.tv PRIVMSG #\w+ :") utils.chat(s, "All set up") thread.start_new_thread(utils.threadFillOplist, ()) while True: response = s.recv(1024).decode("utf-8") if response == "PING :tmi.twitch.tv\r\n": s.send("PONG :tmi.twitch.tv\r\n".encode("utf-8")) else: username = re.search(r"\w+", response).group(0) message = CHAT_MSG.sub("", response) print response if message.strip() == "!time" and utils.isOp(username): utils.chat( s, "It's currently " + time.strftime("%I:%M %p %Z on %A, %B %d, %Y.")) if "!say" in message.strip(): engine.say(re.sub('!say ', '', message.strip())) engine.runAndWait() if message.strip() == "!help": utils.chat(s, "!say, !time") if message.strip() == "!help" and utils.isOp(username): utils.chat(s, "!say, !time, !ban, !timeout") sleep(1)
def setup_and_test_static_dns(): if not nextbox_sub_ensure(6): return False button_xp = '//*[@id="app-content-vue"]/div/div[2]/button' input_xp = '//*[@id="app-content-vue"]/div/div[2]/input' ret = input_into_text_field(input_xp, conf["static_domain"]) if not ret: click_xpath(button_xp) chat("looks like it's already active, ok let's disable it and retry!") if not input_into_text_field(input_xp, conf["static_domain"]): chat("failed again, failing overall...") return False chat("cool, worked out") if not test_and_click_button(button_xp): return False chat("looks good so far, let's see if we can connect") return test_for_valid_login_page(conf["static_domain"], "http")
def givePoints(numPebbles, givingUser, toUser, twitchSocket): """ Transfers a number of pebbles from one user to another numPebbles -- The number of pebbles to transfer givingUser -- The user who is giving pebbles toUser -- The user receiving pebbles twitchSocket -- The socket connection to twitch """ try: numPebbles = int(numPebbles) except ValueError: chat(sock=twitchSocket, msg="Sorry, @" + givingUser + ", but I don't think that was a number.") return if getUserPebbles(givingUser) < numPebbles: chat(sock=twitchSocket, msg="Sorry, @" + givingUser + ", but you don't have enough pebbles to give.") elif not userExists(toUser): chat(sock=twitchSocket, msg="Sorry, @" + givingUser + ", but I can't find that user.") else: addPebbles(numPebbles, toUser) subtractPebbles(numPebbles, givingUser) chat(sock=twitchSocket, msg="@" + givingUser + " gave @" + toUser + " " + str(numPebbles) + " pebbles!")
def logout(): chat("logging out now, just because I can!") click_xpath('//*[@id="expand"]') chat("expanding, just for the show...") get_xpath('//*[@id="expanddiv"]') res = get_xpath('//li[@data-id="logout"]').find_element(By.TAG_NAME, "a") if not res: chat("failed logging out...") return False return res.click()
def first_login(): # fill in new admin credentials input_into_text_field('//*[@id="adminlogin"]', conf["user_login"]) input_into_text_field('//*[@id="adminpass"]', conf["user_pass"]) # submit form conf["dom"].find_elements_by_tag_name("form")[0].submit() chat("we submitted the form, 'things' should happen!") wait_for_path("/index.php/core/apps/recommended", max_iters=100) chat("recommended apps are being installed, good!") wait_for_path("/apps/dashboard/", max_iters=6000) chat("found dashboard, trying to 'esc' the welcome dialog away") conf["dom"].find_element_by_tag_name("body").send_keys(Keys.ESCAPE) return True
def main(): # Networking functions s = socket.socket() s.connect((cfg.HOST, cfg.PORT)) s.send("PASS {}\r\n".format(cfg.PASS).encode("utf-8")) s.send("NICK {}\r\n".format(cfg.NICK).encode("utf-8")) s.send("JOIN #{}\r\n".format(cfg.CHAN).encode("utf-8")) CHAT_MSG = re.compile(r"^:\w+!\w+@\w+.tmi\.twitch\.tv PRIVMSG #\w+ :") utils.chat(s, "Hi everyone!") _thread.start_new_thread(utils.threadFillOpList, ()) while True: response = s.recv(1024).decode("utf-8") if response == "PING :tmi.twitch.tv\r\n": s.send("PONG :tmi.twitch.tv\r\n".encode("utf-8")) else: username = re.search(r"\w+", response).group(0) message = CHAT_MSG.sub("", response) print(response) # Custom commands if message.strip() == "!time": utils.chat(s, "It is currently " + time.strftime("%I:%M %p %Z on %A, %B %d, %Y.")) if message.strip() == "Hello FantastiBot!": utils.chat(s, "Hello " + username + "!") if message.strip() == "!mods": modlist = [] for i in cfg.oplist: if cfg.oplist[i] == "mod": modlist.append(i) if len(modlist) == 0: utils.chat(s, "There are no moderators currently online.") elif len(modlist) == 1: utils.chat(s, "Currently, " + modlist[0] + " is the only moderator online.") elif len(modlist) >= 2: modString = "" for i in range(len(modlist)): if i == len(modlist)-1: modString += modlist[i] elif i == len(modlist)-2: modString += modlist[i] + " and " elif i < len(modlist)-2: modString += modlist[i] + ", " utils.chat(s, modString + " are currently moderating.") # Custom OP commands if utils.isOp(username): if message.strip() == "!messages": utils.chat(s, "Please follow me, I don't bite.") utils.chat(s, "I'm so lonely.") if message.strip().find("!timeout") != -1: utils.timeout(s, message[9:]) sleep(1)