Ejemplo n.º 1
0
    def ping(self, message: core.BotMessage) -> None:
        """Ping: replies "Pong!"

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        message.respond("Pong!")
Ejemplo n.º 2
0
    def addPoints(self, message: core.BotMessage) -> None:
        """Adds points to the minigame leaderboard

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        if not message.room:
            return message.respond("You can only add points in a room.")
        if not message.sender.can("hostgame", message.room):
            return message.respond("Permission denied.")

        if len(message.arguments) < 2:
            return message.respond(
                f"Usage: ``{config.commandCharacter}addpoints [comma-separated list of users], [optional number of points]``."
            )
        usernames = message.arguments[1:]
        points = 1
        if len(usernames) > 1 and isInt(usernames[len(usernames) - 1].strip()):
            points = int(usernames.pop())

        if message.room.id not in self.minigamePoints.keys():
            self.minigamePoints[message.room.id] = {}
        for name in usernames:
            userid = psclient.toID((name))
            if userid not in self.minigamePoints[message.room.id].keys():
                self.minigamePoints[message.room.id][userid] = points
            else:
                self.minigamePoints[message.room.id][userid] += points

        return message.respond("Points added!")
Ejemplo n.º 3
0
    def removeRepeat(self, message: core.BotMessage) -> None:
        """removerepeat: removes a repeat

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        if len(message.arguments) < 2:
            return message.respond(
                f"Usage: ``{config.commandCharacter}removerepeat <message>``.")

        if not message.sender.can('searchlog', message.room):
            return message.respond("Permission denied.")

        msg = config.separator.join(message.arguments[1:])
        repeats = data.get("repeats")
        if not repeats or message.room.id not in repeats:
            return message.respond(
                f"There are no repeats for the room '{message.room.id}'.")

        repeatFound = False
        newRepeats = []
        for repeat in repeats[message.room.id]:
            if msg in repeat:
                repeatFound = True
                continue
            newRepeats.append(repeat)
        if not repeatFound: return message.respond("No repeat found.")

        repeats[message.room.id] = newRepeats
        data.store("repeats", repeats)
        return message.respond("Repeat removed!")
Ejemplo n.º 4
0
    def startGame(self, message: core.BotMessage) -> None:
        """Starts a tournament or game of UNO

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        if not message.room:
            return message.respond("You cannot start a game in PMs.")
        if not message.sender.can("hostgame", message.room):
            return message.respond("Permission denied.")
        isTournament = message.arguments[0].strip(
            config.commandCharacter) in ['tour', 'tournament']
        if isTournament and len(message.arguments) < 2:
            return message.respond(
                f"Usage: ``{config.commandCharacter}tournament [format], [comma-separated custom rules]``."
            )

        if isTournament:
            commands = TOUR_SETUP_COMMANDS
            tourFormat = message.arguments[1]
            message.room.say(f"/tour new {tourFormat},elim")
            if len(message.arguments) > 2:
                rules = ', '.join(message.arguments[2:])
                message.room.say(f"/tour rules {rules}")
        else:
            commands = UNO_COMMANDS
        for command in commands:
            message.room.say(command)
Ejemplo n.º 5
0
    def addReversioWord(self, message: core.BotMessage) -> None:
        """Adds a word to the reversio database.

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        if len(message.arguments) < 2:
            return message.respond(
                f"Usage: ``{config.commandCharacter}addreversioword {'[room], ' if not message.room else ''}<word>``."
            )
        word = ",".join(message.arguments[1:])
        room = message.room

        if not room and len(message.arguments) > 2:
            room = message.connection.getRoom(message.arguments[1])
            word = ",".join(message.arguments[2:])
        if not room:
            return message.respond("You must specify a valid room.")
        word = word.strip().lower()

        if message.sender.can("addfact", room):
            if room.id not in self.reversioWords.keys():
                self.reversioWords[room.id] = [word]
            else:
                self.reversioWords[room.id].append(word)
            data.store("reversioWords", self.reversioWords)
            return message.respond("Word added!")

        return message.respond("Permission denied.")
Ejemplo n.º 6
0
    def exportSnippets(self, message: core.BotMessage) -> None:
        """Exports the snippets to Pastebin

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        kind = 'fact'
        snippetList = self.factList
        if "topic" in message.arguments[0]:
            kind = 'topic'
            snippetList = self.topicList
        elif "quote" in message.arguments[0]:
            kind = 'quote'
            snippetList = self.quoteList

        if message.room:
            room = message.room
        elif len(message.arguments) > 1:
            room = message.connection.getRoom(message.arguments[1])
        else:
            return message.respond("You must specify a room.")
        if not message.sender.can("addfact", room):
            return message.respond("Permission denied.")
        if room.id not in snippetList.keys() or len(snippetList[room.id]) == 0:
            return message.respond(
                f"There are no {kind}s for the room {room.id}.")

        pasteData = "\n".join(snippetList[room.id])
        return message.respond(
            str(
                Pastebin(config.pastebinAPIKey).create_paste(
                    pasteData,  # the data
                    1,  # unlisted paste
                    f"{kind.title()}s for room {room.id}"  # title
                )))
Ejemplo n.º 7
0
    def showSnippet(self, message: core.BotMessage) -> None:
        """Shows a fact, quote, or topic in chat

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        kind = 'facts'
        snippetList = self.factList
        if "topic" in message.arguments[0]:
            kind = 'topics'
            snippetList = self.topicList
        elif "quote" in message.arguments[0]:
            kind = 'quotes'
            snippetList = self.quoteList

        if message.room:
            roomid = message.room.id
            if roomid == 'trivia' and kind == 'quotes':
                return message.respond(
                    'This command is disabled in the Trivia room.')
        elif len(message.arguments) > 1:
            roomid = psclient.toID(message.arguments[1])
        else:
            return message.respond("You must specify a room.")

        if not snippetList or roomid not in snippetList.keys():
            return message.respond(f"There are no {kind} for this room.")

        return message.respond(random.choice(snippetList[roomid]))
Ejemplo n.º 8
0
    def countSnippets(self, message: core.BotMessage) -> None:
        """Counts the number of snippets

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        kind = 'fact'
        snippetList = self.factList
        if "topic" in message.arguments[0]:
            kind = 'topic'
            snippetList = self.topicList
        elif "quote" in message.arguments[0]:
            kind = 'quote'
            snippetList = self.quoteList

        if message.room:
            room = message.room
        elif len(message.arguments) > 1:
            room = message.connection.getRoom(message.arguments[1])
        else:
            return message.respond("You must specify a room.")

        num = 0
        if snippetList and room.id in snippetList.keys():
            num = len(snippetList[room.id])
        return message.respond(
            f"There {'is ' if num == 1 else 'are '} {str(num)} \
            {kind}{'' if num == 1 else 's'} for the room {room.id}.")
Ejemplo n.º 9
0
    def listRepeats(self, message: core.BotMessage) -> None:
        """listrepeats: lists repeats

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        room = message.room
        if not room:
            if len(message.arguments) != 2:
                return message.respond(
                    "You must specify a room when using this command in PMs.")
            room = message.connection.getRoom(message.arguments[1])
            if not room:
                return message.respond(
                    f"I'm not in the room '{message.arguments[1]}'.")

        if not message.sender.can('searchlog', room):
            return message.respond("Permission denied.")
        repeats = data.get("repeats")
        if not (repeats and room.id in repeats and repeats[room.id]):
            return message.respond(
                f"There are no repeats for the room '{room.id}'")
        htmlBuf = f"<details><summary>Repeats for the room <strong>{room.id}</strong></summary><ul>"
        for repeat in repeats[room.id]:
            htmlBuf += f"<li>Repeated every {list(repeat.values())[0]} minutes: \"{list(repeat.keys())[0]}\"</li>"
        htmlBuf += "</ul></details>"
        print(htmlBuf)
        return message.respondHTML(htmlBuf)
Ejemplo n.º 10
0
    def addJP(self, message: core.BotMessage) -> None:
        """Adds a joinphrase for a user

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        phrase = ""
        userid = ""
        if message.room:
            room = message.room
            if len(message.arguments) > 2:
                userid = psclient.toID(message.arguments[1])
                phrase = ",".join(message.arguments[2:]).strip()
        elif len(message.arguments) > 3:
            room = message.connection.getRoom(message.arguments[1])
            userid = psclient.toID(message.arguments[2])
            phrase = ",".join(message.arguments[3:])
        else:
            return message.respond("You must specify a room.")
        if not phrase or not userid:
            return message.respond(
                f"Usage: ``{config.commandCharacter}addjoinphrase {'[room], ' if not message.room else ''}[user], [phrase]``. "
            )
        if not message.sender.can("manage", room): return message.respond("Permission denied.")

        room.addJoinphrase(phrase, userid)
        return message.respond("Joinphrase successfully added!")
Ejemplo n.º 11
0
    def memoryStats(self, message: core.BotMessage) -> None:
        """Gets info on memory usage

        Args:
            message (message: core.BotMessage) -> None: the Message object that invoked the command
        """
        if not message.sender.id in config.sysops:
            return message.respond("Permission denied.")
        buf = []

        meminfoPath = pathlib.Path("/proc/meminfo")
        if meminfoPath.is_file():
            for line in open('/proc/meminfo', 'r',
                             encoding='utf-8').readlines():
                if 'MemAvailable' in line:
                    buf.append(
                        f"{round(int(line.split(':')[1].split('kB')[0]) / 1024, 2)} MB available"
                    )
                if 'MemFree' in line:
                    buf.append(
                        f"{round(int(line.split(':')[1].split('kB')[0]) / 1024, 2)} MB free"
                    )
                if 'MemTotal' in line:
                    buf.append(
                        f"{round(int(line.split(':')[1].split('kB')[0]) / 1024, 2)} MB total"
                    )

        buf.append(
            f"{round(psutil.Process().memory_info().rss / 1024 ** 2, 2)} MB used by the bot process"
        )
        return message.respond(f"Memory stats: {', '.join(buf)}")
Ejemplo n.º 12
0
    def timer(self, message: core.BotMessage) -> None:
        """timer: evaluates the given Python expression

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        if len(message.arguments) not in range(1, 4):
            message.respond(
                f"Usage: ``{config.commandCharacter}timer <duration>, <optional message>``"
            )
            return
        response = "/wall " if message.type == 'pm' or message.connection.this.can(
            'wall', message.room) else ""
        response += message.arguments[2] if len(
            message.arguments
        ) > 2 else f"Timer set by {message.sender.name} is up"

        try:
            duration = float(message.arguments[1])
        except ValueError:
            message.respond(f"{message.arguments[1]} isn't a valid duration")
            return
        t = threading.Timer(duration, message.respond, args=[response])
        t.daemon = True
        t.start()
Ejemplo n.º 13
0
    def checkHouse(self, message: core.BotMessage) -> None:
        """Checks what house a user is in

        Arguments:
            message (core.Botmessage: core.BotMessage) -> None: the Message object that invoked the command
        """
        user: str = ','.join(message.arguments[1:]) if len(message.arguments) > 1 else message.senderName
        houses: List[str] = getUserHouses(psclient.toID(user))
        if houses: return message.respond(f"{user} is in {houses[0].title()} house!")
        return message.respond(f"{user} is not in any house.")
Ejemplo n.º 14
0
    def owo(self, message: core.BotMessage) -> None:
        """owo: replaces vowels with owo faces

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        text = config.separator.join(message.arguments[1:])
        for vowel in list("AaEeIiOoUuYy"):
            text = text.replace(vowel, f"{vowel}w{vowel}")
        message.respond(text)
Ejemplo n.º 15
0
    def uwu(self, message: core.BotMessage) -> None:
        """uwu: turns English into weird anime language

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        text = config.separator.join(message.arguments[1:])
        uwuRules = {'r': 'w', 'l': 'w', 'R': 'W', 'L': 'W'}
        for (letter, replacement) in uwuRules.items():
            text = text.replace(letter, replacement)
        message.respond(sanitize(text))
Ejemplo n.º 16
0
    def showSampleTeams(self, message: core.BotMessage) -> None:
        """Displays sample teams

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        formatid = psclient.toID(','.join(message.arguments[1:]) if len(message.arguments) > 1 else '')
        if not formatid or formatid not in htmlboxes:
            return message.respond(f"You must specify a format that I have sample teams for: {', '.join(list(htmlboxes.keys()))}")

        return message.respondHTML(generateHTML(htmlboxes[formatid]))
Ejemplo n.º 17
0
    def kill(self, message: core.BotMessage) -> None:
        """Kills the bot process

        Args:
            message (message: core.BotMessage) -> None: the Message object that invoked the command
        """
        if message.sender.id in config.sysops:
            message.respond("Killing the bot process....")
            core.log(f"E: admin.kill(): killed by {message.senderName}")
            sys.exit()
        return message.respond("Permission denied.")
Ejemplo n.º 18
0
    def uwu(self, message: core.BotMessage) -> None:
        """uwu: turns English into weird anime language

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        text = config.separator.join(message.arguments[1:])
        uwuRules = {'r': 'w', 'l': 'w', 'R': 'W', 'L': 'W'}
        for key in uwuRules:
            text = text.replace(key, uwuRules[key])
        message.respond(text)
Ejemplo n.º 19
0
    def audio(self, message: core.BotMessage) -> None:
        """audio: displays audio in the room

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        if len(message.arguments) < 2:
            return message.respond(f"Usage: ``{ config.commandCharacter}audio <URL to audio file>``.")

        url = ','.join(message.arguments[1:]).strip()
        if not isAudioURL(url):
            return message.respond(
                "You must specify a valid URL beginning with ``http://`` or ``https://``; the URL must refer to an audio file."
            )

        return message.respondHTMLPatched(f'<audio controls src="{url}"></audio>')
Ejemplo n.º 20
0
    def audio(self, message: core.BotMessage) -> None:
        """audio: displays audio in the room

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        if len(message.arguments) < 2:
            return message.respond(f"Usage: ``{ config.commandCharacter}audio <URL to audio file>``.")

        url = message.arguments[1].strip().lower()
        if not re.match(r'^https?:\/\/(.*?)\.[a-z]{2,}/(.*?)\.(mp[34]|wav|ogg)$', url):
            return message.respond(
                "You must specify a valid URL beginning with ``http://`` or ``https://``; the URL must refer to an audio file."
            )

        return message.respondHTML(f'<audio controls src="{url}"></audio>')
Ejemplo n.º 21
0
    def runCommand(self, message: core.BotMessage) -> None:
        """runCommand: sends the given command to the given room

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        if not message.arguments or len(message.arguments) < 3:
            return message.respond(
                f"Usage: ``{config.commandCharacter}do <room>, <message>``.")
        room = message.connection.getRoom(message.arguments[1])
        if room:
            if not message.sender.can("manage", room):
                return message.respond("Permission denied.")
            command = ",".join(message.arguments[2:]).strip()
            return room.say(command)
        return message.respond(f"{message.arguments[1]} isn't a room I'm in.")
Ejemplo n.º 22
0
    def createHouse(self, message: core.BotMessage) -> None:
        """Creates a new house

        Args:
            message (core.Botmessage: core.BotMessage) -> None: the message that invoked the command
        """
        if message.sender.id not in config.sysops:
            return message.respond(
                f"Only bot operators (sysops) can create houses. The bot operators are: {', '.join(config.sysops)}"
            )
        if len(message.arguments) < 2: return message.respond(f"Usage: ``{config.commandCharacter}createhouse <house>``")
        house: str = psclient.toID(','.join(message.arguments[1:]))
        houseData: Dict[str, list] = data.get("houses") or {}
        if house in houseData: return message.respond(f"The house {house} already exists. Houses can only be deleted manually.")
        houseData[house] = []
        data.store("houses", houseData)
        return message.respond(f"Successfully created the house {house.title()}!")
Ejemplo n.º 23
0
    def handleModule(self, message: core.BotMessage) -> None:
        """Handles loading, reloading, and hotpatching modules

        Args:
            message (message: core.BotMessage) -> None: the message that triggered the command
        """
        if not message.sender.id in config.sysops:
            return message.respond("Permission denied.")
        if not message.arguments or len(message.arguments) < 2:
            return message.respond(
                f"Usage: ``{message.arguments[0]} <module>``.")
        module = psclient.toID(message.arguments[1])
        action = ''
        if 'load' in message.arguments[0]: action = 'load'
        if 'unload' in message.arguments[0]: action = 'unload'
        if 'hotpatch' in message.arguments[0]: action = 'hotpatch'

        if module == __name__ and action == 'unload':
            return message.respond(
                f"Don't unload the module that provides ``{message.arguments[0]}``."
            )

        if action == 'unload':
            return message.respond(self.unload(message.connection, module))
        if action == 'load':
            return message.respond(self.load(message.connection, module))
        if action == 'hotpatch':
            mod = importlib.import_module(module)
            importlib.reload(mod)
            message.connection.commands.update(
                mod.Module().commands)  # type: ignore
            return message.respond(
                f"Successfully hotpatched the {module} module.")
        return message.respond("Something went wrong -- no action detected!")
Ejemplo n.º 24
0
    def topusers(self, message: core.BotMessage) -> None:
        """Gets the top users of a room

        Args:
            message (message: core.BotMessage) -> None: the Message object that invoked the command
        """
        if len(message.arguments) < 2:
            return message.respond(
                f"Usage: ``{config.commandCharacter}topusers <room>, [optional number of days]``."
            )

        roomID = psclient.toID(message.arguments[1])
        try:
            days = int(message.arguments[2])
        except (IndexError, ValueError):
            days = 30

        room = message.connection.getRoom(roomID)
        if not message.connection.rustChatlogger:
            return message.respond("There is currently no chatlogger loaded.")
        if not room: return message.respond(f"Invalid room: {roomID}")
        if not message.sender.can("searchlog", room):
            return message.respond("Permission denied.")
        message.respond("Please wait; fetching userstats...")

        return message.respondHTMLPatched(
            message.connection.rustChatlogger.topusers_html(roomID, days, 30))
Ejemplo n.º 25
0
    def resetLB(self, message: core.BotMessage) -> None:
        """Resets the minigame leaderboard

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        room = message.room
        if not room:
            if len(message.arguments) < 2: return message.respond("You must specify a room.")
            room = message.connection.getRoom(message.arguments[1])
        if not room: return message.respond("You must specify a room.")

        if not message.sender.can("hostgame", message.room): return message.respond("Permission denied.")
        if room.id not in self.minigamePoints.keys():
            return message.respond(f"There are no scores in the leaderboard for the room '{room.id}'.")

        del self.minigamePoints[room.id]
        return message.respond("Cleared the minigame leaderboard!")
Ejemplo n.º 26
0
    def reverse(self, message: core.BotMessage) -> None:
        """Sends a reversed phrase for the Reversio game.

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        if message.room:
            roomID = message.room.id
        elif message.arguments and len(message.arguments) > 1:
            roomID = psclient.toID(message.arguments[1])
        else:
            return message.respond("You must specify a room.")

        if roomID not in self.reversioWords.keys() or len(self.reversioWords[roomID]) < 1:
            return message.respond(f"There are no reversio words for the room {roomID}.")
        response = "/wall " if (not message.room) or message.sender.can("wall", message.room) else ""
        response += random.choice(self.reversioWords[roomID]).lower()[::-1].strip()
        return message.respond(response)
Ejemplo n.º 27
0
    def viewModules(self, message: core.BotMessage) -> None:
        """Lists the currently loaded modules

        Args:
            message (message: core.BotMessage) -> None: the Message object that invoked the command
        """
        return message.respond(
            f"Modules currently known to be loaded: {', '.join([f'``{module}``' for module in message.connection.modules])}"
        )
Ejemplo n.º 28
0
    def showLB(self, message: core.BotMessage) -> None:
        """Displays the minigame leaderboard

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        roomid = message.room.id if message.room else None
        if not roomid:
            if len(message.arguments) < 2: return message.respond("You must specify a room.")
            roomid = psclient.toID(message.arguments[1])
        if not roomid: return message.respond("You must specify a room.")
        if roomid not in self.minigamePoints.keys(): return message.respond("There are no scores.")

        points = self.minigamePoints[roomid]
        # TODO: investigate mypy errors
        sortedUsers = sorted(points, key=points.get, reverse=True) # type: ignore
        formattedPoints = ", ".join([f"{key} (**{points[key]}**)" for key in sortedUsers])
        return message.respond(f"**Scores**: {formattedPoints}" if formattedPoints else "There are no scores.")
Ejemplo n.º 29
0
    def help(self, message: core.BotMessage) -> None:
        """Help

        Arguments:
            message {Message} -- the Message object that invoked the command
        """
        return message.respond(
            "Expecto Botronum guide: https://github.com/AnnikaCodes/expecto-botronum/blob/master/README.md#commands"
        )
Ejemplo n.º 30
0
    def viewModerationSettings(self, message: core.BotMessage) -> None:
        """Displays information about a room's moderation settings

        Args:
            message (core.BotMessage): the Message object that invoked the command
        """
        room = message.connection.getRoom(message.arguments[1]) if len(message.arguments) > 1 else message.room
        if not room:
            return message.respond("You must specify a valid room when using this command in PMs.")

        if not message.sender.can("searchlog", room): return message.respond("Permission denied.")

        moderation = room.moderation or {}
        buf = f"Moderation settings for room **``{room.id}``**: "
        buf += ', '.join(
            [f"**{thing}**: {'enabled' if moderation.get(thing) else 'disabled'}" for thing in core.VALID_AUTOMOD_TYPES]
        )
        buf += '.'
        message.respond(buf)