136 lines
5.6 KiB
Python
136 lines
5.6 KiB
Python
import json
|
||
import requests as r
|
||
import logging
|
||
import time
|
||
import datetime
|
||
from functools import wraps
|
||
from threading import Thread
|
||
from irc import IRC
|
||
|
||
from sasl import nick, password
|
||
from users import USERS
|
||
|
||
|
||
class Shoutbox(object):
|
||
def __init__(self, cookies):
|
||
self.channels = {'annonces': 0, 'projets': 0, 'hs': 0}
|
||
self.cookies = cookies
|
||
self._callbacks = []
|
||
self.irc_clients = {} # pseudo: [IRC(), date]
|
||
self.running = False
|
||
self._handler = Thread(target=self._handle)
|
||
|
||
for channel, last_id in self.channels.items():
|
||
messages = json.loads(r.get(f"https://www.planet-casio.com/Fr/shoutbox/api/read?since={last_id}&channel={channel}&format=text").text)['messages']
|
||
for m in messages:
|
||
self.channels[channel] = m['id']
|
||
|
||
def run(self):
|
||
self.running = True
|
||
logging.debug("Thread start")
|
||
self._handler.start()
|
||
|
||
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()
|
||
self.irc_clients.pop(client)
|
||
self._handler.join()
|
||
logging.debug("STOP: Shoutbox thread closed")
|
||
|
||
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):
|
||
if msg.startswith("ACTION"):
|
||
msg = msg.replace("ACTION", "/me")
|
||
# 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)
|
||
|
||
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]
|
||
return pseudo.replace(' ', '_')
|
||
|
||
def _handle(self):
|
||
while self.running:
|
||
try:
|
||
for channel, last_id in self.channels.items():
|
||
# Do not spam with logs
|
||
logging.getLogger().setLevel(logging.INFO)
|
||
messages = json.loads(r.get(f"https://www.planet-casio.com/Fr/shoutbox/api/read?since={last_id}&channel={channel}&format=text").text)['messages']
|
||
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
|
||
# Get channel id, parse SBMessage
|
||
self.channels[channel] = m['id']
|
||
message = SBMessage(m, channel)
|
||
# If handler needs to be killed
|
||
if not self.running:
|
||
logging.debug("going to stop")
|
||
break
|
||
# 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()
|
||
]
|
||
# Start a thread for new client
|
||
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
|
||
for k, c in self.irc_clients.items():
|
||
if datetime.datetime.now() - c[1] > datetime.timedelta(hours=1):
|
||
logging.info(f"killing {c[0].nick}")
|
||
c[0].stop()
|
||
self.irc_clients.pop(k)
|
||
except Exception as e:
|
||
logging.error(f"Faillure in Shoutbox thread {e}")
|
||
finally:
|
||
time.sleep(3)
|
||
|
||
|
||
class SBMessage(object):
|
||
def __init__(self, raw, channel):
|
||
self.author = raw['author']
|
||
self.channel = channel
|
||
self.text = raw['content']
|