piss-bot/bot.py
2021-02-27 09:52:47 +01:00

116 lines
3.3 KiB
Python

import asyncio
import logging
import pickle
import re
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="...")
output = template.format(
title=event.name,
date=date,
location=location,
when=when,
url=url,
description=description
)
output = re.sub(r'(<br>)+', '<br>', output)
return output
async def send_message(text):
async with aiohttp.ClientSession() as session:
result = await session.post(config.WEBHOOK_URL, json={
"text": text,
"format": "html",
"displayName": "PUBLIC INFORMATION STREAMS & SERVICES",
"avatarUrl": config.AVATAR_URL
})
logging.debug(f"RECV: [{result.status}] {await result.text()}")
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():
logging.info(f"Sending description of {event.name}")
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():
logging.info(f"Notifying of {event.name}")
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())