Compare commits

..

No commits in common. "master" and "master" have entirely different histories.

2 changed files with 20 additions and 41 deletions

58
bot.py
View File

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

View File

@ -1,3 +0,0 @@
aiohttp~=3.5
beautifulsoup4~=4.7
telethon~=1.7