132 lines
4.8 KiB
Python
132 lines
4.8 KiB
Python
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 <comic_id> -> To fetch a comic strip based on
|
|
`<comic_id>`, 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 <comic id>` to fetch a comic strip based on `<comic id>` "
|
|
"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
|