piss-bot/bot.py

108 lines
3.1 KiB
Python

import asyncio
import logging
import pickle
import textwrap
from asyncio import sleep
import aiohttp
import arrow
from ics import Calendar
from config import Config
config = Config()
class State:
notified = []
notified_soon = []
def process_event(event, template):
if event.begin.hour == event.begin.minute == 0:
date_fmt = 'dddd, D. MMMM YYYY'
else:
date_fmt = 'HH:mm / dddd, D. MMMM YYYY'
date = event.begin.format(date_fmt, locale='cs_CZ')
when = event.begin.humanize()
location = f"@ {event.location}" if event.location else ""
description = event.description or ""
description = description.strip()
if description:
lines = description.splitlines()
if "http" in lines[0]:
url = lines[0].strip()
description = "\n".join(lines[1:])
else:
url = ""
else:
url = ""
description = description or "???"
description = textwrap.shorten(description, width=512, placeholder="...")
return template.format(
title=event.name,
date=date,
location=location,
when=when,
url=url,
description=description
)
async def send_message(text):
async with aiohttp.ClientSession() as session:
await session.post(config.WEBHOOK_URL, json={
"text": text,
"format": "html",
"displayName": "PUBLIC INFORMATION STREAMS & SERVICES",
"avatarUrl": "http://i.imgur.com/IDOBtEJ.png"
})
async def main():
try:
with open('state.pickle', 'rb') as state_fp:
state = pickle.load(state_fp)
except FileNotFoundError:
state = State()
while True:
calendars = []
async with aiohttp.ClientSession() as session:
for url in config.URLS:
logging.debug(f"Requesting {url}...")
async with session.get(url) as resp:
calendars.append(Calendar(await resp.text()))
future_events = [event for calendar in calendars for event in calendar.events if event.begin > arrow.now()]
logging.debug(f"Got {len(future_events)} future events...")
for event in future_events:
if event.name not in state.notified and event.begin.shift(days=-2) < arrow.now():
await send_message(process_event(event, config.EVENT_TEMPLATE))
state.notified.append(event.name)
if event.name not in state.notified_soon and event.begin.shift(hours=-2) < arrow.now():
await send_message(process_event(event, config.SOON_TEMPLATE))
state.notified_soon.append(event.name)
with open('state.pickle', 'wb') as state_fp:
pickle.dump(state, state_fp)
logging.debug("Sleeping for 60s...")
await sleep(60)
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - [%(levelname)s] %(message)s')
if config.WEBHOOK_URL is None:
raise RuntimeError("WEBHOOK_URL is not defined.")
loop = asyncio.get_event_loop()
loop.run_until_complete(main())