forked from tan/xkcdtextbot
Compare commits
5 Commits
Author | SHA1 | Date |
---|---|---|
Lonami Exo | dbf8609842 | |
Lonami Exo | 472d1f09d9 | |
Lonami Exo | d263f315be | |
Lonami | 5d5ddb7db2 | |
Lonami | c022d559a4 |
58
bot.py
58
bot.py
|
@ -1,14 +1,15 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import asyncio
|
||||
import html
|
||||
from os import environ
|
||||
from collections import namedtuple
|
||||
from json import loads
|
||||
|
||||
import logging
|
||||
|
||||
import requests
|
||||
import aiohttp
|
||||
from telethon import TelegramClient, events
|
||||
from telethon.tl.custom import Button
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
# Enable logging
|
||||
|
@ -20,21 +21,25 @@ logger = logging.getLogger(__name__)
|
|||
Xkcd = namedtuple('Xkcd', ['title', 'link', 'transcript', 'alt', 'number'])
|
||||
|
||||
URL_FMT_STR = "http://www.ohnorobot.com/index.php?Search=Search&comic=56&s={}"
|
||||
# FIXME HTML parsemode + escaping
|
||||
MSG_FMT_STR = "[{number}]({link}): **{title}**\n\n__{alt}__"
|
||||
MSG_FMT_STR = '<a href="{link}">{number}</a>: <b>{title}</b>\n\n<i>{alt}</i>'
|
||||
XKCD_JSON_FMT_STR = "https://xkcd.com/{}/info.0.json"
|
||||
MAX_SEARCH_RESULTS = 10
|
||||
|
||||
bot = TelegramClient('xkcd', 6, 'eb06d4abfb49dc3eeb1aeb98ae0f581e')
|
||||
bot.parse_mode = 'html'
|
||||
|
||||
session = None # set later
|
||||
me = None # set later
|
||||
|
||||
# blockquote element -> Xkcd
|
||||
def parse_blockquote(elem):
|
||||
async def parse_blockquote(elem):
|
||||
children = list(elem.children)
|
||||
title = children[0].text
|
||||
link = 'https' + children[-1].text[4:]
|
||||
|
||||
number = link.rsplit('/', 2)[1]
|
||||
info = loads(requests.get(XKCD_JSON_FMT_STR.format(number)).text)
|
||||
async with session.get(XKCD_JSON_FMT_STR.format(number)) as resp:
|
||||
info = await resp.json()
|
||||
alt = info['alt']
|
||||
|
||||
# TODO markdown bold the <span> matches
|
||||
|
@ -47,16 +52,17 @@ def parse_blockquote(elem):
|
|||
return Xkcd(title, link, text, alt, number)
|
||||
|
||||
# string -> [Xkcd]
|
||||
def get_xkcds(text):
|
||||
async def get_xkcds(text):
|
||||
logger.info("getting %s", text)
|
||||
if text == '':
|
||||
return []
|
||||
# TODO return newest when empty
|
||||
soup = BeautifulSoup(requests.get(URL_FMT_STR.format(text)).text, "html.parser")
|
||||
async with session.get(URL_FMT_STR.format(text)) as resp:
|
||||
soup = BeautifulSoup(await resp.text(), "html.parser")
|
||||
|
||||
bqs = soup.find_all("blockquote")[:MAX_SEARCH_RESULTS]
|
||||
logger.info(bqs)
|
||||
return (parse_blockquote(e) for e in bqs)
|
||||
return await asyncio.gather(*(parse_blockquote(e) for e in bqs))
|
||||
|
||||
|
||||
# Define a few command handlers. These usually take the two arguments bot and
|
||||
|
@ -64,15 +70,19 @@ def get_xkcds(text):
|
|||
@bot.on(events.NewMessage(pattern='/start$'))
|
||||
async def start(event):
|
||||
"""Send a message when the command /start is issued."""
|
||||
# TODO
|
||||
await event.respond('Hi!')
|
||||
await event.respond(
|
||||
f"Hello! I'm {me.username} and I search for XKCD when used inline.",
|
||||
buttons=Button.switch_inline('Try it!', 'cheaply')
|
||||
)
|
||||
|
||||
|
||||
@bot.on(events.NewMessage(pattern='/help$'))
|
||||
async def help(event):
|
||||
"""Send a message when the command /help is issued."""
|
||||
# TODO
|
||||
await event.respond('Help!')
|
||||
await event.respond(
|
||||
f"I only work inline, and it is my job to search for XKCD comics!",
|
||||
buttons=Button.switch_inline('Try it!', 'cheaply')
|
||||
)
|
||||
|
||||
|
||||
@bot.on(events.InlineQuery)
|
||||
|
@ -83,8 +93,13 @@ async def inlinequery(event):
|
|||
result = await asyncio.gather(*(builder.article(
|
||||
title=xkcd.title,
|
||||
url=xkcd.link,
|
||||
text=MSG_FMT_STR.format(number=xkcd.number, link=xkcd.link, title=xkcd.title, alt=xkcd.alt)
|
||||
) for xkcd in get_xkcds(event.text)))
|
||||
text=MSG_FMT_STR.format(
|
||||
number=xkcd.number,
|
||||
link=xkcd.link,
|
||||
title=html.escape(xkcd.title),
|
||||
alt=html.escape(xkcd.alt)
|
||||
)
|
||||
) for xkcd in await get_xkcds(event.text)))
|
||||
|
||||
# FIXME get_xkcds returns duplicates, which lead to the same result ID
|
||||
# Build a dict by their ID to remove the duplicates
|
||||
|
@ -92,11 +107,14 @@ async def inlinequery(event):
|
|||
await event.answer(result)
|
||||
|
||||
|
||||
def main():
|
||||
bot.start(bot_token=environ['TOKEN'])
|
||||
with bot:
|
||||
bot.run_until_disconnected()
|
||||
async def main():
|
||||
global session, me
|
||||
async with aiohttp.ClientSession() as session:
|
||||
await bot.start(bot_token=environ['TOKEN'])
|
||||
async with bot:
|
||||
me = await bot.get_me()
|
||||
await bot.run_until_disconnected()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
asyncio.get_event_loop().run_until_complete(main())
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
aiohttp~=3.5
|
||||
beautifulsoup4~=4.7
|
||||
telethon~=1.7
|
Loading…
Reference in New Issue