#!/usr/bin/env python3.9 import json import requests import sys from datetime import datetime, timedelta from datafiles import JSONFile from irc import Client from schedule import Scheduler from time import sleep from tools import human_readable_time_from_delta IRC_SERVER = "irc.eu.libera.chat" IRC_PORT = 6667 IRC_CHANNEL = "#aocrr" IRC_NICK = "aocrr-bot" IRC_USER = "aocrr-bot" IRC_REALNAME = "#aocrr Leaderboard Announcer" def fetch_leaderboard(session_id: str, year: int = datetime.now().year) -> dict: return json.loads( requests.get( "https://adventofcode.com/%d/leaderboard/private/view/711147.json" % year, cookies={'session': session_id} ).content ) class IrcBot: def __init__(self): self.cache = JSONFile("aocrr_bot.cache", create=True) self.__session_id = open(".session", "r").readlines()[0].strip() self.irc_client = Client(IRC_SERVER, IRC_PORT, IRC_NICK, IRC_USER, IRC_REALNAME) self.irc_client.join(IRC_CHANNEL) self.irc_client.register('PRIVMSG', self.on_privmsg) self.update_leaderboard() self.scheduler = Scheduler() self.scheduler.schedule('irc-receive', timedelta(seconds=10), self.irc_client.receive) self.scheduler.schedule('leaderboard', timedelta(minutes=15), self.update_leaderboard) def on_privmsg(self, msg_from: str, msg_to: str, message: str): if msg_to != IRC_CHANNEL: return if message.startswith("!today"): pass elif message.startswith("!test"): self.irc_client.privmsg(IRC_CHANNEL, "What I've read: " + " ".join(message.split()[1:])) elif message.startswith("!quit") and msg_from.startswith("stha!"): self.irc_client.privmsg(IRC_CHANNEL, "Oh, ok ... bye :'(") self.irc_client.quit() sys.exit(0) def update_leaderboard(self): try: new_leaderboard = fetch_leaderboard(self.__session_id) except: return # didn't work this time? Well, we'll just try again in 15min ... now = datetime.now() new_stars = {} for member, member_data in new_leaderboard['members'].items(): if member not in self.cache: self.cache[member] = { 'name': member_data['name'], 'days': {}, } for day in member_data['completion_day_level']: day_start = datetime(now.year, 12, int(day), 6, 0, 0) if day not in self.cache[member]['days']: self.cache[member]['days'][day] = {} for part in member_data['completion_day_level'][day]: if part not in self.cache[member]['days'][day]: completion_time = datetime.fromtimestamp( member_data['completion_day_level'][day][part]['get_star_ts'] ) if member_data['name'] not in new_stars: new_stars[member_data['name']] = {} finishing_time = human_readable_time_from_delta(completion_time - day_start) new_stars[member_data['name']]['d' + day + 'p' + part] = finishing_time self.cache[member]['days'][day][part] = finishing_time if len(new_stars) > 0: self.irc_client.privmsg(IRC_CHANNEL, "New Stars found:") for member, parts in new_stars.items(): line = member + ": " line += ", ".join( "%s (%s)" % (part, new_stars[member][part]) for part in sorted(new_stars[member].keys()) ) self.irc_client.privmsg(IRC_CHANNEL, line) self.cache['__last_update__'] = datetime.now().isoformat() self.cache.save() def run(self): while 1: self.scheduler.run_pending() sleep(1) if __name__ == '__main__': ircbot = IrcBot() ircbot.run()