import asyncio import configparser import logging import re import yaboli from yaboli.utils import * class Morse: SHORT_DESCRIPTION = "convert to and from morse code" DESCRIPTION = ( "'morse' converts to and from morse code.\n" "In morse code, letters should be separated by spaces and words" " separated by a slash '/'. Example: .... . .-.. .-.. --- / - .... . .-. .\n" "Any other characters indicate the end of a morse code message." " 'morse' will attempt to translate all morse code messages it finds.\n" ) COMMANDS = ( "!demorse - convert the parent message from morse code\n" "!demorse - convert the text from morse code\n" "!morse - convert the parent message into morse code\n" "!morse - convert some text into morse code\n" ) AUTHOR = "Created by @Garmy using github.com/Garmelon/yaboli\n" CREDITS = "Original bot by Leidenfrost.\n" MORSE_RE = r"[\.\-\/ ]+" TO_MORSE = { "a": ".-", "b": "-...", "c": "-.-.", "d": "-..", "e": ".", "f": "..-.", "g": "--.", "h": "....", "i": "..", "j": ".---", "k": "-.-", "l": ".-..", "m": "--", "n": "-.", "o": "---", "p": ".--.", "q": "--.-", "r": ".-.", "s": "...", "t": "-", "u": "..-", "v": "...-", "w": ".--", "x": "-..-", "y": "-.--", "z": "--..", "1": ".----", "2": "..---", "3": "...--", "4": "....-", "5": ".....", "6": "-....", "7": "--...", "8": "---..", "9": "----.", "0": "-----", ".": ".-.-.-", ",": "--..--", ":": "---...", "?": "..--..", "'": ".----.", "-": "-....-", "/": "-..-.", "(": "-.--.", ")": "-.--.-", '"': ".-..-.", "=": "-...-", "+": ".-.-.", "×": "-..-", "@": ".--.-.", } FROM_MORSE = {v: i for i, v in TO_MORSE.items()} @classmethod def from_morse(cls, text): words = [word.strip() for word in text.split("/")] words_trans = [] for word in words: letters = [letter for letter in word.split(" ") if letter] trans = [cls.FROM_MORSE.get(letter, "�") for letter in letters] words_trans.append("".join(trans)) return " ".join(words_trans) def to_morse(cls, text): words = [word for word in text.split(" ") if word] words_trans = [] for word in words: untranslated = "" result = [] # preserve untranslatable sequences of letters for letter in word: trans = cls.TO_MORSE.get(letter.lower()) if trans: if untranslated: result.append(untranslated) untranslated = "" result.append(trans) else: untranslated += letter if untranslated: result.append(untranslated) words_trans.append(" ".join(result)) return " / ".join(words_trans) @yaboli.command("demorse") async def command_demorse(self, room, message, argstr): text = argstr.strip() if not text and message.parent: msg = await room.get_message(message.parent) text = msg.content.strip() if not text: await room.send("Can't demorse nothing.", message.mid) return matches = re.findall(self.MORSE_RE, text) matches = [match.strip() for match in matches if match.strip()] if not matches: await room.send("No morse code found.", message.mid) return translated = [self.from_morse(match) for match in matches] translated = [word for word in translated if len(word) > 1] await room.send("\n".join(translated), message.mid) @yaboli.command("morse") async def command_morse(self, room, message, argstr): text = argstr.strip() if not text and message.parent: msg = await room.get_message(message.parent) text = msg.content.strip() if not text: await room.send("Can't morse nothing.", message.mid) return lines = text.split("\n") translated = [self.to_morse(line) for line in lines] await room.send("\n".join(translated), message.mid) class MorseBot(yaboli.Bot): SHORT_HELP = Morse.SHORT_DESCRIPTION LONG_HELP = Morse.DESCRIPTION + Morse.COMMANDS + Morse.AUTHOR + Morse.CREDITS PING_TEXT = ".--. --- -. --." def __init__(self, nick, cookiefile=None): super().__init__(nick, cookiefile=cookiefile) self.morse = Morse() async def on_command_specific(self, room, message, command, nick, argstr): if similar(nick, room.session.nick) and not argstr: await self.botrulez_ping(room, message, command, text=self.PING_TEXT) await self.botrulez_help(room, message, command, text=self.LONG_HELP) await self.botrulez_uptime(room, message, command) await self.botrulez_kill(room, message, command) await self.botrulez_restart(room, message, command) async def on_command_general(self, room, message, command, argstr): if not argstr: await self.botrulez_ping(room, message, command, text=self.PING_TEXT) await self.botrulez_help(room, message, command, text=self.SHORT_HELP) await self.morse.command_demorse(room, message, command, argstr) await self.morse.command_morse(room, message, command, argstr) def main(configfile): logging.basicConfig(level=logging.INFO) config = configparser.ConfigParser(allow_no_value=True) config.read(configfile) nick = config.get("general", "nick") cookiefile = config.get("general", "cookiefile", fallback=None) bot = MorseBot(nick, cookiefile=cookiefile) for room, password in config.items("rooms"): if not password: password = None bot.join_room(room, password=password) asyncio.get_event_loop().run_forever() if __name__ == "__main__": main("morse.conf")