forked from aewens/babili-bot
Compare commits
14 Commits
Author | SHA1 | Date |
---|---|---|
aewens | b7d668cedf | |
aewens | 579f7df5a5 | |
aewens | 64d0208837 | |
aewens | 286c144bdf | |
Ben Harris | a20a675e25 | |
aewens | 1296a65b39 | |
aewens | 7a58cd789d | |
Robert Miles | 2e870c3796 | |
aewens | 7acbceca8e | |
aewens | 675a8099b5 | |
aewens | 7d44bfad19 | |
aewens | 5246008861 | |
aewens | f32dce7faf | |
aewens | 957160b686 |
|
@ -1,6 +1,8 @@
|
|||
# App-specific
|
||||
settings.json
|
||||
settings.demo.json
|
||||
settings.test.json
|
||||
*.local
|
||||
data/*.json
|
||||
logs/*.log*
|
||||
logs/*.log.*
|
||||
|
|
|
@ -51,8 +51,8 @@ actions = [
|
|||
"callback": nomad
|
||||
},
|
||||
{
|
||||
"type": "response",
|
||||
"pattern": "/hm+/",
|
||||
"type": "passive",
|
||||
"pattern": "/^[^!]*hm+/",
|
||||
"callback": score_word("hmm", "hm+")
|
||||
},
|
||||
{
|
||||
|
@ -66,9 +66,9 @@ actions = [
|
|||
"callback": wordscoreboard("hmm")
|
||||
},
|
||||
{
|
||||
"type": "response",
|
||||
"pattern": "/o+f/",
|
||||
"callback": score_word("oof", "o+f")
|
||||
"type": "passive",
|
||||
"pattern": "/^[^!]*oo+f/",
|
||||
"callback": score_word("oof", "oo+f")
|
||||
},
|
||||
{
|
||||
"type": "response",
|
||||
|
@ -85,4 +85,4 @@ actions = [
|
|||
"pattern": "/!whois \S+/",
|
||||
"callback": whois
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -28,10 +28,12 @@ def pardon(self, name, source, response):
|
|||
|
||||
if name != author:
|
||||
return
|
||||
|
||||
del self.bot.memories["users"][user]["blacklist"]
|
||||
|
||||
user_memories = self.bot.memories["users"].get(user, dict())
|
||||
if user_memories.get("blacklist", None) is not None:
|
||||
del user_memories["blacklist"]
|
||||
|
||||
self.bot.thread(self.bot.save_memories)
|
||||
|
||||
confirmation = "{} has been pardoned".format(user)
|
||||
self.bot.send_message(source, confirmation)
|
||||
self.bot.send_message(source, confirmation)
|
||||
|
|
|
@ -9,7 +9,7 @@ def score_word(word, regex):
|
|||
check = response.lower().strip()
|
||||
|
||||
botnick = self.bot.botnick
|
||||
pattern = re.compile(regex)#"hm+")
|
||||
pattern = re.compile(regex)
|
||||
matches = re.findall(pattern, check)
|
||||
maximum = 10
|
||||
score = len(matches) if len(matches) <= maximum else maximum
|
||||
|
@ -78,4 +78,4 @@ def wordscoreboard(word):
|
|||
response = "{} Score Leaderboard: {}".format(capitalize(word), leaders)
|
||||
|
||||
self.bot.send_message(source, response)
|
||||
return scoreboard
|
||||
return scoreboard
|
||||
|
|
|
@ -75,9 +75,8 @@ def summon(self, name, source, response):
|
|||
self.bot.send_message(source, confirmation)
|
||||
|
||||
def how_dare_you(self, name, source, response):
|
||||
user = response.split("!summon ")[1]
|
||||
rude = "{}: You think you can just summon someone without a reason? Rude."
|
||||
self.bot.send_message(source, rude.format(user))
|
||||
self.bot.send_message(source, rude.format(name))
|
||||
|
||||
def whois(self, name, source, response):
|
||||
botnick = self.bot.botnick
|
||||
|
@ -104,4 +103,4 @@ def whois(self, name, source, response):
|
|||
elif not (registered or nameservers):
|
||||
self.bot.send_message(source, "{} is '{}'".format(domain, "available"))
|
||||
else:
|
||||
self.bot.send_message(source, "{} might be available".format(domain))
|
||||
self.bot.send_message(source, "{} might be available".format(domain))
|
||||
|
|
26
app.py
26
app.py
|
@ -17,16 +17,9 @@ parser.add_argument(
|
|||
)
|
||||
arguments = parser.parse_args()
|
||||
|
||||
bot = Bot("127.0.0.1", 6667)
|
||||
bot = Bot("localhost", 6667)
|
||||
responses = Responses(bot)
|
||||
tasks = Tasks(bot)
|
||||
|
||||
# for coro in coroutines:
|
||||
# worker = coro["worker"]
|
||||
# interval = coro["interval"]
|
||||
# state = coro.get("state", None)
|
||||
# coro_state = state if state is not None else (bot,)
|
||||
# tasks.add_coroutine(worker, interval, coro_state)
|
||||
tasks.coroutines = coroutines
|
||||
|
||||
for action in actions:
|
||||
|
@ -69,22 +62,28 @@ def handle_invite(channel, name):
|
|||
bot.memories["users"][name]["invites"].append(channel)
|
||||
changed = True
|
||||
|
||||
if changed:
|
||||
bot.thread(bot.save_memories)
|
||||
#if changed:
|
||||
# bot.thread(bot.save_memories)
|
||||
|
||||
def handle_kick(name):
|
||||
def handle_kick(name, source):
|
||||
if source in bot.settings.get("extras", dict()).get("rejoin", list()):
|
||||
bot.join(source)
|
||||
users = bot.memories["users"]
|
||||
if name not in users:
|
||||
bot.memories["users"][name] = dict()
|
||||
|
||||
bot.memories["users"][name]["kicker"] = True
|
||||
bot.thread(bot.save_memories)
|
||||
#bot.thread(bot.save_memories)
|
||||
|
||||
def handle_message(name, source, response):
|
||||
responses.parse(name, source, response)
|
||||
if response == "!debug":
|
||||
bot.logger.debug(":: {}".format(bot.memories))
|
||||
|
||||
def handle_raw(message):
|
||||
if "KICK #chaos {} :".format(bot.author) in message:
|
||||
bot.send("INVITE {} :#chaos".format(bot.author))
|
||||
|
||||
def handle_crashed():
|
||||
bot.logger.debug("Rebooting")
|
||||
bot.crashed = True
|
||||
|
@ -111,5 +110,6 @@ if __name__ == "__main__":
|
|||
"invite": handle_invite,
|
||||
"kick": handle_kick,
|
||||
"crashed": handle_crashed,
|
||||
"message": handle_message
|
||||
"message": handle_message,
|
||||
"raw": handle_raw
|
||||
})
|
||||
|
|
193
bot/core.py
193
bot/core.py
|
@ -1,4 +1,7 @@
|
|||
import re
|
||||
import sys
|
||||
import ssl
|
||||
import time
|
||||
import json
|
||||
import socket
|
||||
import os.path
|
||||
|
@ -13,11 +16,12 @@ logging.basicConfig(
|
|||
)
|
||||
|
||||
class Bot:
|
||||
def __init__(self, server, port):
|
||||
def __init__(self, server, port, secure=False):
|
||||
self.ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.logger = logging.getLogger("")
|
||||
self.server = server
|
||||
self.port = port
|
||||
self.secure = secure
|
||||
self.channels = []
|
||||
self.running = True
|
||||
self.crashed = False
|
||||
|
@ -31,6 +35,9 @@ class Bot:
|
|||
self.recv_size = 2048
|
||||
self.splitter = "\r\n"
|
||||
|
||||
if self.secure:
|
||||
self.ircsock = ssl.wrap_socket(self.ircsock)
|
||||
|
||||
def send(self, message, *args):
|
||||
response = message.format(*args) + "\n"
|
||||
password = self.settings.get("password", None)
|
||||
|
@ -54,7 +61,10 @@ class Bot:
|
|||
self.logger.info(response)
|
||||
|
||||
print("DEBUG: ", response)
|
||||
self.ircsock.send(response.encode())
|
||||
try:
|
||||
self.ircsock.send(response.encode())
|
||||
except BrokenPipeError:
|
||||
self.stop()
|
||||
|
||||
def send_action(self, target, message, *args):
|
||||
self.send_message(target, "\001ACTION {}\001".format(message), *args)
|
||||
|
@ -65,11 +75,21 @@ class Bot:
|
|||
|
||||
message = ""
|
||||
magic_string = "End of /NAMES list."
|
||||
banned = "Cannot join channel (You're banned)"
|
||||
start = time.time()
|
||||
while magic_string not in message:
|
||||
message = self.ircsock.recv(self.recv_size).decode()
|
||||
# message = message.strip(self.splitter)
|
||||
print(message)
|
||||
self.logger.debug(message)
|
||||
# Taking too long, escaping JOIN request
|
||||
if time.time() - start == 2000:
|
||||
return
|
||||
try:
|
||||
message = self.ircsock.recv(self.recv_size).decode()
|
||||
if banned in message:
|
||||
self.places.remove(chan)
|
||||
return
|
||||
# message = message.strip(self.splitter)
|
||||
#self.logger.debug(message)
|
||||
except UnicodeDecodeError:
|
||||
continue
|
||||
|
||||
list_pattern = re.compile("[@=] {} :".format(chan))
|
||||
user_listing = re.split(list_pattern, message)
|
||||
|
@ -90,7 +110,8 @@ class Bot:
|
|||
def leave(self, chan):
|
||||
message = "PART {} :Bye-bye!"
|
||||
self.send(message, chan)
|
||||
self.places.remove(chan)
|
||||
if chan in self.places:
|
||||
self.places.remove(chan)
|
||||
|
||||
def ping(self, message):
|
||||
response = message.split("PING :")[1]
|
||||
|
@ -100,7 +121,9 @@ class Bot:
|
|||
return text.split("!", 1)[0][1:]
|
||||
|
||||
def parse_name(self, name):
|
||||
if name[0] == "~" or name[0] == "@" or name[0] == "+":
|
||||
if len(name) == 0 or name is None:
|
||||
return name
|
||||
if name[0] in ["~", "@", "+", "%"]:
|
||||
return name[1:]
|
||||
else:
|
||||
return name
|
||||
|
@ -125,8 +148,8 @@ class Bot:
|
|||
name = self.parse_name(name)
|
||||
|
||||
user = self.memories["users"][name]
|
||||
del self.memories["users"][name]
|
||||
self.memories["users"][new_name] = user
|
||||
del self.memories["users"][name]
|
||||
return user, new_name
|
||||
|
||||
def handle_invite(self, message):
|
||||
|
@ -138,8 +161,9 @@ class Bot:
|
|||
|
||||
def handle_kick(self, message):
|
||||
before, after = message.split("KICK ", 1)
|
||||
source = after.split(" ", 1)[0]
|
||||
name = self.parse_name(self.get_name(before))
|
||||
return name
|
||||
return name, source
|
||||
|
||||
def handle_join(self, message):
|
||||
before, after = message.split("JOIN ", 1)
|
||||
|
@ -168,7 +192,6 @@ class Bot:
|
|||
self.memories = json.loads(f.read())
|
||||
|
||||
def thread(self, fn, *args):
|
||||
print((self, *args))
|
||||
t = Thread(target=fn, args=args)
|
||||
t.start()
|
||||
|
||||
|
@ -196,6 +219,7 @@ class Bot:
|
|||
|
||||
def stop(self):
|
||||
self.send("QUIT :Overheating, powering down")
|
||||
self.ircsock.close()
|
||||
self.running = False
|
||||
|
||||
def start(self, config, location, callback):
|
||||
|
@ -215,7 +239,10 @@ class Bot:
|
|||
logger.setFormatter(logging.Formatter(logfmt, datefmt))
|
||||
self.logger.addHandler(logger)
|
||||
|
||||
self.ircsock.connect((self.server, self.port))
|
||||
try:
|
||||
self.ircsock.connect((self.server, self.port))
|
||||
except ConnectionRefusedError:
|
||||
sys.exit(1)
|
||||
self.send("USER {0} {0} {0} {0}", self.botnick)
|
||||
self.send("NICK {0}", self.botnick)
|
||||
|
||||
|
@ -224,16 +251,23 @@ class Bot:
|
|||
email = self.settings["email"] or ""
|
||||
|
||||
magic_phrase = {
|
||||
"has_registered": "Password",
|
||||
"has_registered": "Password accepted",
|
||||
"needs_to_register": "choose a different nick",
|
||||
"needs_to_confirm": "Your account will expire"
|
||||
"needs_to_confirm": "Your account will expire",
|
||||
"not_registered": "Your nickname is not registered"
|
||||
#"ready_to_id": "is now your displayed host",
|
||||
#"nickserv_missing": "No such nick/channel"
|
||||
}
|
||||
|
||||
magic_string = "MODE {} +r".format(self.botnick)
|
||||
while magic_string not in message:
|
||||
message = self.ircsock.recv(self.recv_size).decode()
|
||||
authenticate = len(password) > 0 and len(confirm) > 0
|
||||
magic_string = "MODE {} :+r".format(self.botnick)
|
||||
while magic_string not in message and authenticate:
|
||||
try:
|
||||
message = self.ircsock.recv(self.recv_size).decode()
|
||||
except UnicodeDecodeError:
|
||||
continue
|
||||
|
||||
message = message.strip(self.splitter)
|
||||
self.logger.debug(message)
|
||||
#self.logger.debug(message)
|
||||
if not registered and magic_phrase["has_registered"] in message:
|
||||
registered = True
|
||||
if not registered and magic_phrase["needs_to_register"] in message:
|
||||
|
@ -241,7 +275,15 @@ class Bot:
|
|||
if not confirmed and magic_phrase["needs_to_confirm"] in message:
|
||||
self.send_message("NickServ", "CONFIRM {}", self.confirm)
|
||||
confirmed = True
|
||||
|
||||
if not registered and magic_phrase["not_registered"] in message:
|
||||
break
|
||||
#if not registered and magic_phrase["ready_to_id"] in message:
|
||||
# self.send_message("NickServ", "IDENTIFY {}", password)
|
||||
#if not registered and magic_phrase["nickserv_missing"] in message:
|
||||
# break
|
||||
if not authenticate:
|
||||
time.sleep(3)
|
||||
|
||||
self.send("MODE {} +B".format(self.botnick))
|
||||
|
||||
print("DEBUG: Joining")
|
||||
|
@ -256,56 +298,67 @@ class Bot:
|
|||
self.tasks.run()
|
||||
|
||||
while self.running:
|
||||
message = ""
|
||||
while self.splitter not in message:
|
||||
message = self.ircsock.recv(self.recv_size).decode()
|
||||
|
||||
message = message.strip(self.splitter)
|
||||
self.logger.debug("{}".format(message))
|
||||
_message = ""
|
||||
while self.splitter not in _message:
|
||||
try:
|
||||
_message = self.ircsock.recv(self.recv_size).decode()
|
||||
except UnicodeDecodeError:
|
||||
continue
|
||||
|
||||
if "raw" in callback:
|
||||
callback["raw"](message)
|
||||
callback["raw"](_message)
|
||||
|
||||
if "PRIVMSG " in message:
|
||||
name, source, response = self.parse(message)
|
||||
if source == self.botnick and "pm" in callback:
|
||||
callback["pm"](name, response)
|
||||
elif "message" in callback:
|
||||
callback["message"](name, source, response)
|
||||
elif "PING :" in message:
|
||||
self.ping(message)
|
||||
if "ping" in callback:
|
||||
callback["ping"]()
|
||||
elif "MODE " in message:
|
||||
channel, mode = self.handle_mode(message)
|
||||
if "mode" in callback:
|
||||
callback["mode"](channel, mode)
|
||||
elif "NICK " in message:
|
||||
old_name, new_name = self.handle_rename(message)
|
||||
if "nick" in callback:
|
||||
callback["nick"](old_name, new_name)
|
||||
elif "KICK " in message:
|
||||
kicker = self.handle_kick(message)
|
||||
if "kick" in callback:
|
||||
callback["kick"](kicker)
|
||||
elif "JOIN " in message:
|
||||
user = self.handle_join(message)
|
||||
if "join" in callback:
|
||||
callback["join"](user)
|
||||
elif "PART " in message:
|
||||
user = self.handle_part(message)
|
||||
if "part" in callback:
|
||||
callback["part"](user)
|
||||
elif "INVITE " in message:
|
||||
channel, name = self.handle_invite(message)
|
||||
if "invite" in callback:
|
||||
callback["invite"](channel, name)
|
||||
elif "unhandled" in callback:
|
||||
if "unhandled" in callback:
|
||||
callback["unhandled"](message)
|
||||
elif ":Closing link:" in message:
|
||||
self.logger.warning(message)
|
||||
self.stop()
|
||||
if "crashed" in callback:
|
||||
callback["crashed"]()
|
||||
break
|
||||
_message = _message.strip(self.splitter)
|
||||
messages = [msg for msg in _message.split(self.splitter) if msg]
|
||||
|
||||
for message in messages:
|
||||
if message[:4] == "PING":
|
||||
self.ping(message)
|
||||
if "ping" in callback:
|
||||
callback["ping"]()
|
||||
elif "PRIVMSG " in message:
|
||||
name, source, response = self.parse(message)
|
||||
self.logger.debug(message)
|
||||
if source == self.botnick and "pm" in callback:
|
||||
callback["pm"](name, response)
|
||||
elif "message" in callback:
|
||||
callback["message"](name, source, response)
|
||||
elif "MODE " in message:
|
||||
channel, mode = self.handle_mode(message)
|
||||
self.logger.debug(message)
|
||||
if "mode" in callback:
|
||||
callback["mode"](channel, mode)
|
||||
elif "NICK " in message:
|
||||
old_name, new_name = self.handle_rename(message)
|
||||
self.logger.debug(message)
|
||||
if "nick" in callback:
|
||||
callback["nick"](old_name, new_name)
|
||||
#elif "KICK " in message:
|
||||
# kicker, source = self.handle_kick(message)
|
||||
# self.logger.debug(message)
|
||||
# if "kick" in callback:
|
||||
# callback["kick"](kicker, source)
|
||||
elif "JOIN " in message:
|
||||
user = self.handle_join(message)
|
||||
self.logger.debug(message)
|
||||
if "join" in callback:
|
||||
callback["join"](user)
|
||||
elif "PART " in message:
|
||||
user = self.handle_part(message)
|
||||
self.logger.debug(message)
|
||||
if "part" in callback:
|
||||
callback["part"](user)
|
||||
elif "INVITE " in message:
|
||||
channel, name = self.handle_invite(message)
|
||||
self.logger.debug(message)
|
||||
if "invite" in callback:
|
||||
callback["invite"](channel, name)
|
||||
elif "unhandled" in callback:
|
||||
if "unhandled" in callback:
|
||||
callback["unhandled"](message)
|
||||
elif ":Closing link:" in message:
|
||||
self.logger.warning(message)
|
||||
self.logger.error("Activing crash mode")
|
||||
if "crashed" in callback:
|
||||
callback["crashed"]()
|
||||
break
|
||||
|
|
|
@ -7,7 +7,8 @@ class Responses:
|
|||
self.triggers = {
|
||||
"name": dict(),
|
||||
"source": dict(),
|
||||
"response": dict()
|
||||
"response": dict(),
|
||||
"passive": dict()
|
||||
}
|
||||
|
||||
def add_trigger(self, trigger_type, pattern, callback):
|
||||
|
@ -20,12 +21,6 @@ class Responses:
|
|||
if name not in users:
|
||||
return False
|
||||
|
||||
if name in users and "blacklist" in users[name]:
|
||||
reason = users[name]["blacklist"]["reason"]
|
||||
message = "is ignoring {} for reason '{}'".format(name, reason)
|
||||
self.bot.send_action(source, message)
|
||||
return False
|
||||
|
||||
last_response = 0
|
||||
if "last_response" in self.bot.memories["users"][name]:
|
||||
last_response = self.bot.memories["users"][name]["last_response"]
|
||||
|
@ -35,14 +30,23 @@ class Responses:
|
|||
wait = 1
|
||||
|
||||
if name != author and last_response > 0 and now - last_response < wait:
|
||||
reason = "Auto-banished"
|
||||
self.bot.memories["users"][name]["blacklist"] = {
|
||||
"reason": "Auto-banished",
|
||||
"reason": reason,
|
||||
"when": now
|
||||
}
|
||||
message = "is ignoring {} for reason '{}'".format(name, reason)
|
||||
self.bot.send_action(source, message)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def log(self, name, trigger):
|
||||
if trigger != "response":
|
||||
return
|
||||
now = datetime.now().timestamp()
|
||||
self.bot.memories["users"][name]["last_response"] = now
|
||||
|
||||
def parse(self, name, source, response):
|
||||
users = self.bot.memories["users"]
|
||||
if name not in users:
|
||||
|
@ -52,19 +56,37 @@ class Responses:
|
|||
trig = {
|
||||
"name": name,
|
||||
"source": source,
|
||||
"response": response.lower().strip()
|
||||
"response": response.lower().strip(),
|
||||
"passive": response.lower().strip()
|
||||
}
|
||||
|
||||
for trigger in list(self.triggers.keys()):
|
||||
for pattern, callback in self.triggers[trigger].items():
|
||||
if pattern[0] != "/" and pattern[-1] != "/":
|
||||
if pattern == check and self.allowed(name, source):
|
||||
callback(self, name, source, response)
|
||||
else:
|
||||
if pattern == check:
|
||||
if self.allowed(name, source):
|
||||
self.log(name, trigger)
|
||||
callback(self, name, source, response)
|
||||
elif "blacklist" in users[name]:
|
||||
reason = users[name]["blacklist"]["reason"]
|
||||
message = "You were banished for reason '{}'"
|
||||
message = message.format(reason)
|
||||
#self.bot.send_message(name, message)
|
||||
return False
|
||||
elif trigger != "passive":
|
||||
regex = re.compile(pattern[1:-1])
|
||||
if regex.match(trig[trigger]) is not None:
|
||||
if self.allowed(name, source):
|
||||
self.log(name, trigger)
|
||||
callback(self, name, source, response)
|
||||
elif "blacklist" in users[name]:
|
||||
reason = users[name]["blacklist"]["reason"]
|
||||
message = "You were banished for reason '{}'"
|
||||
message = message.format(reason)
|
||||
#self.bot.send_message(name, message)
|
||||
return False
|
||||
else:
|
||||
regex = re.compile(pattern[1:-1])
|
||||
if regex.match(trig[trigger]) is not None:
|
||||
callback(self, name, source, response)
|
||||
|
||||
now = datetime.now().timestamp()
|
||||
self.bot.memories["users"][name]["last_response"] = now
|
|
@ -9,9 +9,10 @@ class Tasks:
|
|||
self.thread = Thread(target=self.worker, args=(self,))
|
||||
self.coroutines = list()
|
||||
self.states = dict()
|
||||
self.halt = False
|
||||
|
||||
def periodic(self, scheduler, interval, action, index, state=dict()):
|
||||
if not self.states[index]:
|
||||
if self.halt:
|
||||
return
|
||||
|
||||
self.states[index] = action(state)
|
||||
|
@ -36,6 +37,7 @@ class Tasks:
|
|||
})
|
||||
|
||||
def stop(self):
|
||||
self.halt = True
|
||||
list(map(self.scheduler.cancel, self.scheduler.queue))
|
||||
for key, value in self.states.items():
|
||||
self.states[key] = False
|
||||
|
@ -43,4 +45,4 @@ class Tasks:
|
|||
|
||||
def run(self):
|
||||
self.thread.daemon = True
|
||||
self.thread.start()
|
||||
self.thread.start()
|
||||
|
|
|
@ -18,14 +18,14 @@ coroutines = [
|
|||
"state": {
|
||||
"alias": "bbj",
|
||||
"source": "http://localhost:7099/api",
|
||||
"channels": ["#team"]
|
||||
"channels": ["#team", "#tildeverse"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"worker": use(RSS),
|
||||
"interval": 6,
|
||||
"state": {
|
||||
"alias": "title",
|
||||
"alias": "links",
|
||||
"source": "https://tilde.news/newest.rss",
|
||||
"use": "title",
|
||||
"channels": ["#meta", "#tildeverse"]
|
||||
|
@ -41,4 +41,4 @@ coroutines = [
|
|||
"channels": ["#tildeverse"]
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -48,7 +48,7 @@ class BBJ:
|
|||
body = reply.get("body", "")
|
||||
body = sub(r">>\d\n\n", r"", body)
|
||||
body = sub(r"\n", r" ", body)
|
||||
php = "https://bbj.tilde.team/index.php"
|
||||
php = "https://bbj.tildeverse.org/"
|
||||
link = "{}?thread_id={}".format(php, thread_id)
|
||||
for channel in self.channels:
|
||||
response = "'{}' ({}) : {} <{}>".format(title, username, body, link)
|
||||
|
@ -86,4 +86,4 @@ class BBJ:
|
|||
for thread in threads:
|
||||
callback(thread)
|
||||
except HTTPError:
|
||||
return
|
||||
return
|
||||
|
|
|
@ -51,8 +51,14 @@ class RSS:
|
|||
|
||||
use = sub(r"(<\/?[^>]+>)|\n", "", item.findtext(self.use, ""))
|
||||
user = item.findtext("author", "").split("@")[0]
|
||||
post = "{} (posted by {}) <{}>".format(use, user, guid)
|
||||
response = "[{}] {}".format(self.alias, post)
|
||||
metadata = "(posted by {}) <{}>".format(user, guid)
|
||||
header = "[{}] {}".format(self.alias, use)
|
||||
splitter = " "
|
||||
max_size = 450 - len(splitter)
|
||||
if len(header) + len(metadata) >= max_size:
|
||||
header_size = max_size - len(metadata)
|
||||
header = header[:header_size]
|
||||
response = "{}{}{}".format(header, splitter, metadata)
|
||||
for channel in self.channels:
|
||||
self.bot.send_message(channel, response)
|
||||
|
||||
|
|
Loading…
Reference in New Issue