Compare commits

...

14 Commits

Author SHA1 Message Date
cynic
0692b8ccb3 bugfix courtesy of the b1g man jucks toe 2024-07-12 04:59:10 -04:00
cynic
3bac1f0bec multichan support 2024-07-12 01:04:21 -04:00
cynic
4577c31e76 passthru nick 2024-07-12 00:40:55 -04:00
cynic
4caa4e9258 roomid check, send id w msg 2024-07-12 00:28:37 -04:00
cynic
c0075e2fbe swinging both ways 2023-10-29 16:32:28 -04:00
cynic
1261ec1fd4 <this> not this: 2023-10-29 16:28:27 -04:00
cynic
96223b0b03 member funcs need to be called explicitly as such because of the patriarchy 2023-10-29 02:16:42 -04:00
cynic
e4b5033ffe switch to a user agent befitting a nonhuman 2023-10-29 01:57:25 -04:00
cynic
dd2cf0b641 livin in the twenty first century 2023-10-29 01:52:37 -04:00
cynic
1589f67cbc fix file uploads 2022-08-07 16:27:59 -04:00
cynic
ecd45f1d04 oopsie (ENTERPRISE QUALITY) 2022-08-02 23:53:55 -04:00
cynic
d4384a0dcb add gitignore 2022-08-02 23:52:24 -04:00
cynic
f7c8ab88de fix files 2022-08-02 23:52:10 -04:00
cynic
3ab07b6967 r8limiter 2022-08-02 23:42:45 -04:00
4 changed files with 79 additions and 20 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
__pycache__

View File

@@ -1,8 +1,12 @@
{
"deek_user": "YOUR_USERNAME_HERE",
"deek_passwd": "YOUR_PASSWORD_HERE",
"deek_user": "ur usrnm",
"deek_passwd": "ur pswd",
"irc_serb": "irc.rizon.net",
"irc_port": 7000,
"irc_nick": "birdbridge",
"irc_chan": "#birdchat"
"irc_chan2deekroomid": {
"#birdchat": 1,
"#birdpunx": 107
},
"passthru_nick": "messages sent from this IRC nick are not prefixed by <nick>"
}

64
main.py
View File

@@ -3,6 +3,7 @@ from ircked.bot import irc_bot
from ircked.message import *
import traceback
import html
import ratelimiter
class bird_inst():
def __init__(self, endpoint, httpendpoint, config):
@@ -15,25 +16,30 @@ class bird_inst():
self.irc.connect_register(self.config["irc_serb"], self.config["irc_port"])
self.send_queue = []
self.limiter = ratelimiter.ratelimit(.5)
def irc_handler(msg, ctx):
#print("<><><><>", str(msg))
if msg.command == "PING":
message.manual("", "PONG", msg.parameters).send(ctx.socket)
elif msg.command == "001":
message.manual("", "JOIN", [self.config["irc_chan"]]).send(ctx.socket)
for chan in self.config["irc_chan2deekroomid"].keys():
message.manual("", "JOIN", [chan]).send(ctx.socket)
elif msg.command == "PRIVMSG" and "\x01VERSION\x01" in msg.parameters:
message.manual(":"+msg.parameters[0], "PRIVMSG", [msg.prefix[1:].split("!")[0], ":\x01dorfl bot\x01"]).send(ctx.socket)
if msg.command == "PRIVMSG" and ("py-ctcp" not in msg.prefix):
pm = privmsg.parse(msg)
self.send_post(pm.fr.split("!")[0]+": "+pm.bod)
post = pm.bod
if pm.fr.split("!")[0] != self.config["passthru_nick"]: post = "<"+pm.fr.split("!")[0]+"> " + post
self.send_post(post, self.config["irc_chan2deekroomid"][pm.to])
threading.Thread(target=self.irc.run, kwargs={"event_handler": irc_handler}, daemon=True).start()
def auth(self, name, passwd):
h = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0",
"Origin": "https://deekchat.ml",
"User-Agent": "renabot",
"Origin": "https://deek.chat",
"DNT": "1",
}
res = requests.post(self.httpendpoint+"/login/submit", headers=h, data={"name": name, "password": passwd, "submit": "log+in"}, allow_redirects=False)
print(res.headers)
token = re.search("(?:api_token)=[^;]+", res.headers.get("Set-Cookie")).group(0)
sessid = re.search("(?:session_id)=[^;]+", res.headers.get("Set-Cookie")).group(0)
h["Cookie"] = token+"; "+sessid
@@ -43,41 +49,65 @@ class bird_inst():
async with websockets.connect(self.endpoint, extra_headers=self.headers) as self.ws:
print(self.ws)
asyncio.get_event_loop().create_task(self._send_post())
asyncio.get_event_loop().create_task(self.ship_queued_messages())
while True:
data = json.loads(await self.ws.recv())
print(">>>", data)
#getattr(self, "handle_"+data["type"], None)(data)
try: getattr(self, "handle_"+data["type"], None)(data)
except Exception as e: print("hey buddy your shits fucked thought you might want to know", e)
def handle_message(self, ctx):
print("btw i just got this", ctx["data"]["message"]["text"])
ctx["data"]["message"]["text"] = html.unescape(ctx["data"]["message"]["text"])
if ctx["data"]["message"]["name"] == self.config["deek_user"]: return
mesg = ctx["data"]["message"]["text"].replace("\n", " ")
room = int(ctx["roomId"])
if not room in self.config["irc_chan2deekroomid"].values(): return
print("btw i just got this", ctx["data"]["text"])
ctx["data"]["text"] = html.unescape(ctx["data"]["text"])
if ctx["data"]["name"] == self.config["deek_user"]: return
mesg = ctx["data"]["text"].replace("\n", " ")
chunks = list(mesg[0+i:400+i] for i in range(0, len(mesg), 400))
chunks = ["<"+ctx["data"]["name"]+"> "+m for m in chunks]
chunks[0] = f"(#{ctx['data']['id']}) " + chunks[0]
irc_chan = ""
for k in self.config["irc_chan2deekroomid"].keys():
if self.config["irc_chan2deekroomid"][k] == room:
irc_chan = k
for m in chunks:
self.irc.sendraw(privmsg.build(self.config["irc_nick"], self.config["irc_chan"], ctx["data"]["message"]["name"]+": "+m).msg)
self.limiter.action(True, self.irc.sendraw, (privmsg.build(self.config["irc_nick"], irc_chan, m).msg,))
def handle_messageStart(self, ctx): pass
def handle_messageChange(self, ctx): pass
def handle_messageEnd(self, ctx): self.handle_message(ctx)
def handle_avatar(self, ctx): pass
def handle_loadUsers(self, ctx): pass
def handle_files(self, ctx):
ctx["data"]["message"]["text"] = html.unescape(ctx["data"]["message"]["text"])
self.irc.sendraw(privmsg.build(self.config["irc_nick"], self.config["irc_chan"], ctx["data"]["message"]["name"]+": "+ctx["data"]["message"]["text"]).msg)
room = int(ctx["roomId"])
if not room in self.config["irc_chan2deekroomid"].values(): return
ctx["data"]["text"] = html.unescape(ctx["data"]["text"])
irc_chan = ""
for k in self.config["irc_chan2deekroomid"].keys():
if self.config["irc_chan2deekroomid"][k] == room:
irc_chan = k
self.irc.sendraw(privmsg.build(self.config["irc_nick"], irc_chan, "<"+ctx["data"]["name"]+"> "+ctx["data"]["text"]).msg)
for f in ctx["data"]["files"]:
self.irc.sendraw(privmsg.build(self.config["irc_nick"], self.config["irc_chan"], f"({ctx['name']} uploaded file: {self.httpendpoint}/storage/files/{f['name']})").msg)
self.limiter.action(True, self.irc.sendraw, (privmsg.build(self.config["irc_nick"], irc_chan, f"({ctx['data']['name']} uploaded file: {self.httpendpoint}/storage/files/{f['name']} )").msg,))
def handle_exit(self, ctx): pass
def handle_enter(self, ctx): pass
def handle_userLoaded(self, ctx): pass
def send_post(self, msg):
def send_post(self, msg, room):
if self.ws is None: return
print(msg)
self.send_queue.append(msg)
self.send_queue.append((msg, room))
async def _send_post(self):
while True:
for msg in self.send_queue:
await self.ws.send(json.dumps({"type": "message", "data": {"message": msg}}))
await self.ws.send(json.dumps({"type": "message", "data": msg[0], "roomId": msg[1]}))
self.send_queue.remove(msg)
print("shipped", msg)
await asyncio.sleep(.1)
async def ship_queued_messages(self):
while True:
self.limiter.lazyrun()
await asyncio.sleep(.1)
cfg = json.loads(open("config.json", "r").read())
bi = bird_inst("wss://deekchat.ml/ws", "https://deekchat.ml", cfg)
bi = bird_inst("wss://deek.chat/ws", "https://deek.chat", cfg)
print("yes hello birdchat here")
bi.auth(cfg["deek_user"], cfg["deek_passwd"])
while True:

24
ratelimiter.py Normal file
View File

@@ -0,0 +1,24 @@
#naive ratelimiter
from time import time
class ratelimit():
def __init__(self, min_delay):
self.delay = min_delay
self.last_action = 0
self.action_queue = []
def action(self, manual, target, args):
print("action~", target, args)
if time() - self.last_action > self.delay:
self.last_action = time()
target(*args)
try: self.action_queue.remove((target, args))
except: print("did not remove", target, args)
else:
print("deferred")
if manual:
self.action_queue.append((target, args))
def lazyrun(self):
if len(self.action_queue) <= 0: return
f = self.action_queue[0][0]
args = self.action_queue[0][1]
self.action(False, f, args)