├── .gitignore ├── .gitlab-ci.yml ├── LICENSE ├── README.md ├── echo.py └── maubot.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | *.mbp 2 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | include: 2 | - project: 'maubot/maubot' 3 | file: '/.gitlab-ci-plugin.yml' 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Tulir Asokan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # echo 2 | A simple [maubot](https://github.com/maubot/maubot) that echoes pings and other stuff. 3 | 4 | ## Usage 5 | * `!ping` - Reply with "Pong!" and the time it took for the message to reach the bot. 6 | * `!echo ` - Reply with the given message 7 | -------------------------------------------------------------------------------- /echo.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from time import time 3 | from html import escape 4 | 5 | from mautrix.types import TextMessageEventContent, MessageType, Format, RelatesTo, RelationType 6 | 7 | from maubot import Plugin, MessageEvent 8 | from maubot.handlers import command 9 | 10 | 11 | class EchoBot(Plugin): 12 | @staticmethod 13 | def plural(num: float, unit: str, decimals: Optional[int] = None) -> str: 14 | num = round(num, decimals) 15 | if num == 1: 16 | return f"{num} {unit}" 17 | else: 18 | return f"{num} {unit}s" 19 | 20 | @classmethod 21 | def prettify_diff(cls, diff: int) -> str: 22 | if abs(diff) < 10 * 1_000: 23 | return f"{diff} ms" 24 | elif abs(diff) < 60 * 1_000: 25 | return cls.plural(diff / 1_000, 'second', decimals=1) 26 | minutes, seconds = divmod(diff / 1_000, 60) 27 | if abs(minutes) < 60: 28 | return f"{cls.plural(minutes, 'minute')} and {cls.plural(seconds, 'second')}" 29 | hours, minutes = divmod(minutes, 60) 30 | if abs(hours) < 24: 31 | return (f"{cls.plural(hours, 'hour')}, {cls.plural(minutes, 'minute')}" 32 | f" and {cls.plural(seconds, 'second')}") 33 | days, hours = divmod(hours, 24) 34 | return (f"{cls.plural(days, 'day')}, {cls.plural(hours, 'hour')}, " 35 | f"{cls.plural(minutes, 'minute')} and {cls.plural(seconds, 'second')}") 36 | 37 | @command.new("ping", help="Ping") 38 | @command.argument("message", pass_raw=True, required=False) 39 | async def ping_handler(self, evt: MessageEvent, message: str = "") -> None: 40 | diff = int(time() * 1000) - evt.timestamp 41 | pretty_diff = self.prettify_diff(diff) 42 | text_message = f'"{message[:20]}" took' if message else "took" 43 | html_message = f'"{escape(message[:20])}" took' if message else "took" 44 | content = TextMessageEventContent( 45 | msgtype=MessageType.NOTICE, format=Format.HTML, 46 | body=f"{evt.sender}: Pong! (ping {text_message} {pretty_diff} to arrive)", 47 | formatted_body=f"{evt.sender}: Pong! " 48 | f"(ping {html_message} " 49 | f"{pretty_diff} to arrive)", 50 | relates_to=RelatesTo( 51 | rel_type=RelationType("xyz.maubot.pong"), 52 | event_id=evt.event_id, 53 | )) 54 | pong_from = evt.sender.split(":", 1)[1] 55 | content.relates_to["from"] = pong_from 56 | content.relates_to["ms"] = diff 57 | content["pong"] = { 58 | "ms": diff, 59 | "from": pong_from, 60 | "ping": evt.event_id, 61 | } 62 | await evt.respond(content) 63 | 64 | @command.new("echo", help="Repeat a message") 65 | @command.argument("message", pass_raw=True) 66 | async def echo_handler(self, evt: MessageEvent, message: str) -> None: 67 | await evt.respond(message) 68 | -------------------------------------------------------------------------------- /maubot.yaml: -------------------------------------------------------------------------------- 1 | maubot: 0.1.0 2 | id: xyz.maubot.echo 3 | version: 1.4.0 4 | license: MIT 5 | modules: 6 | - echo 7 | main_class: EchoBot 8 | --------------------------------------------------------------------------------