shoutbridge/shoutbox.py

137 lines
5.7 KiB
Python
Raw Permalink Normal View History

2022-03-11 19:18:26 +01:00
import json
import requests as r
import logging
import time
2022-03-11 21:30:54 +01:00
import datetime
2022-12-16 11:56:34 +01:00
import re
2022-03-11 19:18:26 +01:00
from functools import wraps
from threading import Thread
2022-03-11 21:30:54 +01:00
from irc import IRC
from sasl import nick, password
from users import USERS
2022-03-11 19:18:26 +01:00
class Shoutbox(object):
def __init__(self, cookies):
self.channels = {'annonces': 0, 'projets': 0, 'hs': 0}
self.cookies = cookies
self._callbacks = []
2022-03-11 22:34:18 +01:00
self.irc_clients = {} # pseudo: [IRC(), date]
self.running = False
self._handler = Thread(target=self._handle)
2022-03-11 19:18:26 +01:00
for channel, last_id in self.channels.items():
2023-08-08 21:14:10 +02:00
messages = json.loads(r.get(f"https://www.planet-casio.com/Fr/shoutbox/api/read?since={last_id}&channel={channel}&format=irc").text)['messages']
2022-03-11 19:18:26 +01:00
for m in messages:
self.channels[channel] = m['id']
def run(self):
self.running = True
2022-04-12 23:34:32 +02:00
logging.debug("Thread start")
self._handler.start()
2022-03-11 21:30:54 +01:00
def stop(self):
logging.debug("STOP: Stop requests to planet-casio.com")
self.running = False
logging.debug("STOP: Halt all irc user threads")
for client in self.irc_clients:
self.irc_clients[client][0].stop()
2022-12-14 17:54:24 +01:00
self.irc_clients.pop(client)
self._handler.join()
logging.debug("STOP: Shoutbox thread closed")
2022-03-11 19:18:26 +01:00
def on(self, event):
""" Adds a callback to the IRC handler
Event is a function taking in parameter a SBMessage and returning
True if the callback should be executed on the message """
def callback(func):
@wraps(func)
def wrapper(message):
func(message)
self._callbacks.append((event, wrapper))
logging.info(f"added callback {func.__name__}")
return wrapper
return callback
def post(self, user, msg, channel, users):
2022-03-11 22:34:18 +01:00
if msg.startswith("ACTION"):
msg = msg.replace("ACTION", "/me")
2022-04-13 14:20:04 +02:00
# Look for pseudo v43-v5 translation
for v43_name, v5_name in users:
if v5_name.lower() == user.lower():
r.post("https://www.planet-casio.com/Fr/shoutbox/api/post-as",
data={"user": v43_name, "message": msg, "channel": channel},
cookies=self.cookies)
return
# No translation found
r.post("https://www.planet-casio.com/Fr/shoutbox/api/post-as",
data={"user": "IRC", "message": f"{user} : {msg}", "channel": channel},
cookies=self.cookies)
2022-03-11 19:18:26 +01:00
2022-03-11 21:30:54 +01:00
def normalize(pseudo):
if pseudo.lower() in [u[0].lower() for u in USERS]:
return [u[1] for u in USERS if u[0].lower() == pseudo.lower()][0]
2022-12-16 11:56:34 +01:00
return re.sub(r'[^.A-Za-z0-9_]', '_', pseudo)
2022-03-11 19:18:26 +01:00
def _handle(self):
while self.running:
try:
for channel, last_id in self.channels.items():
2022-04-13 20:51:05 +02:00
# Do not spam with logs
logging.getLogger().setLevel(logging.INFO)
2023-08-08 21:14:10 +02:00
messages = json.loads(r.get(f"https://www.planet-casio.com/Fr/shoutbox/api/read?since={last_id}&channel={channel}&format=irc").text)['messages']
2022-04-13 20:51:05 +02:00
logging.getLogger().setLevel(logging.DEBUG)
for m in messages:
logging.debug(m)
# If message comes from IRC, drop it (no loops allowed)
if m['source'] == "IRC":
continue
2022-04-13 20:51:05 +02:00
# Get channel id, parse SBMessage
self.channels[channel] = m['id']
message = SBMessage(m, channel)
2022-04-13 20:51:05 +02:00
# If handler needs to be killed
if not self.running:
2022-04-13 20:51:05 +02:00
logging.debug("going to stop")
break
2022-04-13 20:51:05 +02:00
# For each callback defined with @decorator
for event, callback in self._callbacks:
author = Shoutbox.normalize(message.author)
# client is not known or is disconnected
if author not in self.irc_clients.keys() \
or self.irc_clients[author][0].running == False:
self.irc_clients[author] = [
IRC('irc.planet-casio.com', 6697),
datetime.datetime.now()
]
2022-04-13 20:51:05 +02:00
# Start a thread for new client
2022-12-14 23:17:55 +01:00
if self.irc_clients[author][0].start(f"{author}[s]", password, nick):
logging.debug(f"{author} has joined IRC")
# client is known but AFK
else:
self.irc_clients[author][1] = datetime.datetime.now()
logging.debug(f"{author} has updated IRC")
if event(message):
logging.info(f"matched {event.__name__}")
callback(message)
# kill afk clients
2022-12-14 22:48:12 +01:00
for k, c in self.irc_clients.items():
if datetime.datetime.now() - c[1] > datetime.timedelta(hours=1):
2022-04-13 20:51:05 +02:00
logging.info(f"killing {c[0].nick}")
c[0].stop()
2022-12-14 22:48:12 +01:00
self.irc_clients.pop(k)
except Exception as e:
logging.error(f"Faillure in Shoutbox thread {e}")
finally:
time.sleep(3)
2022-03-11 22:34:18 +01:00
2022-03-11 19:18:26 +01:00
class SBMessage(object):
def __init__(self, raw, channel):
self.author = raw['author']
self.channel = channel
self.text = raw['content']