diff --git a/contrib_bots/lib/xkcd.py b/contrib_bots/lib/xkcd.py new file mode 100644 index 0000000..c3286a0 --- /dev/null +++ b/contrib_bots/lib/xkcd.py @@ -0,0 +1,131 @@ +from random import randint + +import logging +import requests + +XKCD_TEMPLATE_URL = 'https://xkcd.com/%s/info.0.json' +LATEST_XKCD_URL = 'https://xkcd.com/info.0.json' + +class XkcdHandler(object): + ''' + This plugin provides several commands that can be used for fetch a comic + strip from https://xkcd.com. The bot looks for messages starting with + "@xkcd" and responds with a message with the comic based on provided + commands. + ''' + + def usage(self): + return ''' + This plugin allows users to fetch a comic strip provided by + https://xkcd.com. Users should preface the command with "@xkcd". + + There are several commands to use this bot: + - @xkcd help -> To show all commands the bot supports. + - @xkcd latest -> To fetch the latest comic strip from xkcd. + - @xkcd random -> To fetch a random comic strip from xkcd. + - @xkcd -> To fetch a comic strip based on + ``, e.g `@xkcd 1234`. + ''' + + def triage_message(self, message, client): + # Return True if we want to (possibly) response to this message + original_content = message['content'] + is_xkcd_called = original_content.startswith('@xkcd ') + is_xkcd_called_without_command = original_content == '@xkcd' + + return is_xkcd_called or is_xkcd_called_without_command + + def handle_message(self, message, client, state_handler): + xkcd_bot_response = get_xkcd_bot_response(message) + + client.send_message(dict( + type='stream', + to=message['display_recipient'], + subject=message['subject'], + content=xkcd_bot_response, + )) + +class XkcdBotCommand(object): + LATEST = 0 + RANDOM = 1 + COMIC_ID = 2 + +class XkcdNotFoundError(Exception): + pass + +class XkcdServerError(Exception): + pass + +def get_xkcd_bot_response(message): + original_content = message['content'].strip() + cropped = original_content[len('@xkcd '):] + command = cropped.strip() + + xkcd_called_without_command = original_content == '@xkcd' + + commands_help = ("%s" + "\n* `@xkcd help` to show this help message." + "\n* `@xkcd latest` to fetch the latest comic strip from xkcd." + "\n* `@xkcd random` to fetch a random comic strip from xkcd." + "\n* `@xkcd ` to fetch a comic strip based on `` " + "e.g `@xkcd 1234`.") + + try: + if command == 'help' or xkcd_called_without_command: + return commands_help % ('xkcd bot supports these commands:') + elif command == 'latest': + fetched = fetch_xkcd_query(XkcdBotCommand.LATEST) + elif command == 'random': + fetched = fetch_xkcd_query(XkcdBotCommand.RANDOM) + elif command.isdigit(): + fetched = fetch_xkcd_query(XkcdBotCommand.COMIC_ID, cropped.strip()) + else: + return commands_help % ('xkcd bot only supports these commands:') + except (requests.exceptions.ConnectionError, XkcdServerError): + logging.exception('Connection error occurred when trying to connect to xkcd server') + return 'Sorry, I cannot process your request right now, please try again later!' + except XkcdNotFoundError: + logging.exception('XKCD server responded 404 when trying to fetch comic with id %s' + % (command)) + return 'Sorry, there is likely no xkcd comic strip with id: #%s' % (command) + else: + return ("#%s: **%s**\n[%s](%s)" % (fetched['num'], + fetched['title'], + fetched['alt'], + fetched['img'])) + +def fetch_xkcd_query(mode, comic_id=None): + try: + if mode == XkcdBotCommand.LATEST: # Fetch the latest comic strip. + url = LATEST_XKCD_URL + + elif mode == XkcdBotCommand.RANDOM: # Fetch a random comic strip. + latest = requests.get(LATEST_XKCD_URL) + + if latest.status_code != 200: + raise XkcdServerError() + + latest_id = latest.json()['num'] + random_id = randint(1, latest_id) + url = XKCD_TEMPLATE_URL % (str(random_id)) + + elif mode == XkcdBotCommand.COMIC_ID: # Fetch specific comic strip by id number. + if comic_id is None: + raise Exception('Missing comic_id argument') + url = XKCD_TEMPLATE_URL % (comic_id) + + fetched = requests.get(url) + + if fetched.status_code == 404: + raise XkcdNotFoundError() + elif fetched.status_code != 200: + raise XkcdServerError() + + xkcd_json = fetched.json() + except requests.exceptions.ConnectionError as e: + logging.warning(e) + raise + + return xkcd_json + +handler_class = XkcdHandler diff --git a/contrib_bots/lib/xkcd/docs.md b/contrib_bots/lib/xkcd/docs.md new file mode 100644 index 0000000..3201404 --- /dev/null +++ b/contrib_bots/lib/xkcd/docs.md @@ -0,0 +1,40 @@ +# xkcd bot + +xkcd bot is a Zulip bot that can fetch a comic strip from xkcd. To use xkcd +bot you can simply call it with `@xkcd` followed by a command. Like this: + +``` +@xkcd +``` + +xkcd bot has four commands: + +1. `help` +This command is used to list all commands that can be used with this bot. +You can use this command by typing `@xkcd help` in a stream. +![](xkcd-help.png) + +2. `latest` +This command is used to fetch the latest comic strip from xkcd. You can use +this command by typing `@xkcd latest` in a stream. +![](xkcd-latest.png) + +3. `random` +This command is used to fetch a random comic strip from xkcd. You can use +this command by typing `@xkcd random` in a stream, xkcd bot will post a +random xkcd comic strip. +![](xkcd-random.png) + +4. `` +To fetch a comic strip based on id, you can directly use `@xkcd `, +for example if you want to fetch a comic strip with id 1234, you can type +`@xkcd 1234`, xkcd bot will post a comic strip with id 1234. +![](xkcd-specific-id.png) + +If you type a wrong command to xkcd bot, xkcd bot will post information +you'd get from `@xkcd help`. +![](xkcd-wrong-command.png) + +And if you type a wrong id, xkcd bot will post a message that an xkcd comic +strip with that id is not available. +![](xkcd-wrong-id.png) diff --git a/contrib_bots/lib/xkcd/xkcd-help.png b/contrib_bots/lib/xkcd/xkcd-help.png new file mode 100644 index 0000000..08c72ae Binary files /dev/null and b/contrib_bots/lib/xkcd/xkcd-help.png differ diff --git a/contrib_bots/lib/xkcd/xkcd-latest.png b/contrib_bots/lib/xkcd/xkcd-latest.png new file mode 100644 index 0000000..e8d1b61 Binary files /dev/null and b/contrib_bots/lib/xkcd/xkcd-latest.png differ diff --git a/contrib_bots/lib/xkcd/xkcd-random.png b/contrib_bots/lib/xkcd/xkcd-random.png new file mode 100644 index 0000000..8aa7c20 Binary files /dev/null and b/contrib_bots/lib/xkcd/xkcd-random.png differ diff --git a/contrib_bots/lib/xkcd/xkcd-specific-id.png b/contrib_bots/lib/xkcd/xkcd-specific-id.png new file mode 100644 index 0000000..c9fb972 Binary files /dev/null and b/contrib_bots/lib/xkcd/xkcd-specific-id.png differ diff --git a/contrib_bots/lib/xkcd/xkcd-wrong-command.png b/contrib_bots/lib/xkcd/xkcd-wrong-command.png new file mode 100644 index 0000000..ed51f3b Binary files /dev/null and b/contrib_bots/lib/xkcd/xkcd-wrong-command.png differ diff --git a/contrib_bots/lib/xkcd/xkcd-wrong-id.png b/contrib_bots/lib/xkcd/xkcd-wrong-id.png new file mode 100644 index 0000000..2ef1288 Binary files /dev/null and b/contrib_bots/lib/xkcd/xkcd-wrong-id.png differ