112 lines
4.0 KiB
Python
Executable File
112 lines
4.0 KiB
Python
Executable File
#!/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):
|
|
super().__init__()
|
|
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()
|