gluebot/main.py

547 lines
13 KiB
Python
Raw Normal View History

2024-02-23 02:22:16 +00:00
import requests
import websockets
import asyncio
import json
import re
import httpx
import traceback
import os
import aiohttp
import random
2024-02-22 16:34:55 +00:00
from bs4 import BeautifulSoup
2024-03-04 04:50:00 +00:00
from datetime import datetime, timedelta
2024-02-20 06:14:06 +00:00
from pathlib import Path
2024-02-22 17:29:33 +00:00
import aiofiles
2024-02-29 08:51:13 +00:00
import sys
2024-02-20 06:14:06 +00:00
2024-02-20 06:57:49 +00:00
HERE = Path(__file__).parent
2024-02-20 06:14:06 +00:00
username = os.environ.get("GLUEBOT_USERNAME")
password = os.environ.get("GLUEBOT_PASSWORD")
2024-02-28 09:26:30 +00:00
headers = {
"User-Agent": "gluebot",
"Origin": "https://deek.chat",
"DNT": "1",
}
url = "https://deek.chat"
ws_url = "wss://deek.chat/ws"
prefix = ","
token = None
session = None
delay = 3
2024-02-28 10:00:24 +00:00
gifmaker_common = [
"/usr/bin/gifmaker",
2024-02-28 09:26:30 +00:00
"--width", 350,
"--output", "/tmp/gifmaker",
"--nogrow",
]
2024-02-23 02:22:16 +00:00
2024-02-29 08:51:13 +00:00
def msg(message: str) -> None:
print(message, file=sys.stderr)
2024-02-20 06:14:06 +00:00
def get_time():
2024-02-23 02:22:16 +00:00
return datetime.now().timestamp()
2024-02-20 06:14:06 +00:00
2024-02-20 11:45:09 +00:00
def remove_file(path):
2024-02-23 02:22:16 +00:00
try:
path.unlink()
except Exception as e:
2024-02-29 08:51:13 +00:00
msg(f"(Remove) Error: {e}")
2024-02-23 02:22:16 +00:00
traceback.print_exc()
2024-02-20 11:45:09 +00:00
2024-02-20 06:14:06 +00:00
def get_extension(path):
2024-02-23 02:22:16 +00:00
return Path(path).suffix.lower().lstrip(".")
2024-02-20 06:14:06 +00:00
2024-02-22 16:34:55 +00:00
def clean_lines(s):
2024-02-23 02:22:16 +00:00
cleaned = s
cleaned = re.sub(r" *(\n+|\\n+) *", "\n", cleaned)
cleaned = re.sub(r" +", " ", cleaned)
return cleaned.strip()
2024-02-22 16:34:55 +00:00
def random_int(min_val, max_val):
2024-02-23 02:22:16 +00:00
return random.randint(min_val, max_val)
2024-02-22 16:34:55 +00:00
2024-03-04 04:50:00 +00:00
def random_date():
2024-03-07 01:17:12 +00:00
one_hundred = 36525
2024-03-04 04:50:00 +00:00
current_date = datetime.now()
2024-03-07 01:17:12 +00:00
end_date = current_date + timedelta(days=(one_hundred // 2))
2024-03-04 04:50:00 +00:00
random_days = random.randint(0, (end_date - current_date).days)
random_date = current_date + timedelta(days=random_days)
return random_date.strftime("%d %b %Y")
2024-02-22 17:29:33 +00:00
def get_path(name):
2024-02-23 02:22:16 +00:00
return str(Path(HERE, name))
2024-02-22 17:29:33 +00:00
2024-02-22 20:21:53 +00:00
def extract_range(string):
2024-02-23 02:22:16 +00:00
pattern = r"(?:(?P<number1>-?\d+)(?:\s*(.+?)\s*(?P<number2>-?\d+))?)?"
match = re.search(pattern, string)
num1 = None
num2 = None
if match["number1"]:
num1 = int(match["number1"])
2024-02-22 20:21:53 +00:00
2024-02-23 02:22:16 +00:00
if match["number2"]:
num2 = int(match["number2"])
2024-02-22 20:21:53 +00:00
2024-02-23 02:22:16 +00:00
return [num1, num2]
2024-02-22 20:21:53 +00:00
2024-02-22 20:45:50 +00:00
def clean_list(lst):
2024-02-23 02:22:16 +00:00
return list(filter(lambda x: x != "", lst))
2024-02-22 20:45:50 +00:00
2024-02-22 20:48:56 +00:00
def string_to_number(input_string):
2024-02-23 02:22:16 +00:00
hash_value = hash(input_string)
absolute_hash = abs(hash_value)
scaled_number = absolute_hash % 1000
return scaled_number
2024-02-22 20:48:56 +00:00
2024-02-28 10:27:00 +00:00
def clean_string(string):
return string.replace("&#34;", '"')
def escape_quotes(string):
return string.replace('"', '\\"')
def remove_char(string, char):
return string.replace(char, "")
def clean_gifmaker(arg):
arg = clean_string(arg)
arg = remove_char(arg, ";")
return arg
2024-02-28 10:00:24 +00:00
def join_command(command):
2024-02-28 10:27:00 +00:00
return " ".join(f'"{arg}"' for arg in command)
2024-02-28 10:00:24 +00:00
2024-02-28 09:26:30 +00:00
def gifmaker_command(args):
2024-02-28 10:00:24 +00:00
command = gifmaker_common.copy()
command.extend(args)
return join_command(command)
2024-02-20 06:14:06 +00:00
2024-02-20 11:45:09 +00:00
cmd_date = get_time()
2024-02-28 10:59:44 +00:00
userlist = []
2024-02-20 11:45:09 +00:00
2024-02-23 02:22:16 +00:00
2024-02-20 06:14:06 +00:00
def update_time():
2024-02-23 02:22:16 +00:00
global cmd_date
cmd_date = get_time()
2024-02-20 06:14:06 +00:00
def blocked():
2024-02-23 02:22:16 +00:00
return (get_time() - cmd_date) < delay
2024-02-20 06:14:06 +00:00
def auth():
2024-02-23 02:22:16 +00:00
global token, session, headers
if not username or not password:
2024-02-29 08:51:13 +00:00
msg("Missing environment variables")
2024-02-23 02:22:16 +00:00
exit(1)
2024-02-21 12:03:28 +00:00
2024-02-23 02:22:16 +00:00
data = {"name": username, "password": password, "submit": "log+in"}
2024-02-24 02:02:54 +00:00
res = requests.post(url + "/login/submit", headers=headers, data=data, allow_redirects=False)
token = re.search("(?:api_token)=[^;]+", res.headers.get("Set-Cookie")).group(0)
session = re.search("(?:session_id)=[^;]+", res.headers.get("Set-Cookie")).group(0)
2024-02-23 02:22:16 +00:00
headers["Cookie"] = token + "; " + session
2024-02-21 12:03:28 +00:00
2024-02-20 06:14:06 +00:00
2024-02-28 10:59:44 +00:00
def update_userlist(message):
global userlist
message = json.loads(message)
event = message.get("type")
if event == "loadUsers":
userlist = []
for key in message["data"]:
room_users = message["data"][key]
for user in room_users:
name = user.get("name")
if name:
userlist.append(name)
elif event == "enter":
name = message["data"].get("name")
if name and (name not in userlist):
userlist.append(name)
2024-02-29 08:49:23 +00:00
elif event == "exit":
name = message["data"].get("name")
if name and (name in userlist):
userlist.remove(name)
2024-02-28 10:59:44 +00:00
2024-02-20 06:14:06 +00:00
async def run():
2024-02-23 02:22:16 +00:00
async with websockets.connect(ws_url, extra_headers=headers) as ws:
try:
while True:
message = await ws.recv()
2024-02-28 10:59:44 +00:00
update_userlist(message)
2024-02-23 02:22:16 +00:00
await on_message(ws, message)
except KeyboardInterrupt:
exit(0)
except websockets.exceptions.ConnectionClosedOK:
2024-02-29 08:51:13 +00:00
msg("WebSocket connection closed")
2024-02-23 02:22:16 +00:00
except Exception as e:
2024-02-29 08:51:13 +00:00
msg("(WebSocket) Error:", e)
2024-02-23 02:22:16 +00:00
traceback.print_exc()
2024-02-20 06:14:06 +00:00
async def on_message(ws, message):
2024-02-23 02:22:16 +00:00
if blocked():
return
2024-02-20 06:14:06 +00:00
2024-02-23 02:22:16 +00:00
try:
data = json.loads(message)
2024-02-29 19:30:09 +00:00
except BaseException:
2024-02-23 02:22:16 +00:00
return
2024-02-20 06:14:06 +00:00
2024-02-23 02:22:16 +00:00
if data["type"] == "message":
if data["data"]["name"] == username:
return
2024-02-20 06:14:06 +00:00
2024-02-23 02:22:16 +00:00
text = data["data"]["text"].strip()
2024-02-20 06:14:06 +00:00
2024-02-23 02:22:16 +00:00
if not text.startswith(prefix):
return
2024-02-20 06:14:06 +00:00
2024-02-23 02:22:16 +00:00
room_id = data["roomId"]
words = text.lstrip(prefix).split(" ")
cmd = words[0]
args = words[1:]
2024-02-20 06:14:06 +00:00
2024-03-04 04:50:00 +00:00
if cmd in ["ping"]:
2024-02-23 02:22:16 +00:00
update_time()
await send_message(ws, "Pong!", room_id)
2024-02-20 06:14:06 +00:00
2024-03-04 04:50:00 +00:00
elif cmd in ["help"]:
2024-02-23 02:22:16 +00:00
update_time()
2024-03-04 04:51:02 +00:00
await send_message(ws, f"Commands: describe | wins | numbers | date | bird | shitpost | who | when", room_id)
2024-02-20 11:50:23 +00:00
2024-03-04 04:50:00 +00:00
elif cmd in ["describe"]:
2024-02-23 02:22:16 +00:00
if len(args) >= 1:
update_time()
2024-02-23 03:42:40 +00:00
arg = " ".join(clean_list(args))
2024-02-28 10:27:00 +00:00
arg = clean_gifmaker(arg)
2024-02-23 03:42:40 +00:00
await gif_describe(arg, room_id)
2024-02-20 06:14:06 +00:00
2024-03-04 04:50:00 +00:00
elif cmd in ["wins", "win"]:
2024-02-23 02:22:16 +00:00
if len(args) >= 1:
update_time()
2024-02-23 03:42:40 +00:00
arg = " ".join(clean_list(args))
2024-02-28 10:27:00 +00:00
arg = clean_gifmaker(arg)
2024-02-23 03:42:40 +00:00
await gif_wins(arg, room_id)
2024-03-03 19:27:48 +00:00
else:
update_time()
await gif_wins(None, room_id)
2024-02-20 06:14:06 +00:00
2024-03-04 04:50:00 +00:00
elif cmd in ["numbers", "number", "nums", "num"]:
2024-02-23 03:42:40 +00:00
update_time()
2024-02-23 02:22:16 +00:00
if len(args) > 0:
arg = " ".join(clean_list(args))
else:
arg = None
2024-02-22 20:28:07 +00:00
2024-02-28 10:27:00 +00:00
arg = clean_gifmaker(arg)
2024-02-23 02:22:16 +00:00
await gif_numbers(arg, room_id)
2024-02-20 06:14:06 +00:00
2024-03-04 04:50:00 +00:00
elif cmd in ["date", "data", "time", "datetime"]:
2024-02-23 02:22:16 +00:00
update_time()
2024-02-24 02:02:54 +00:00
await gif_date(room_id)
2024-02-20 06:14:06 +00:00
2024-03-04 04:50:00 +00:00
elif cmd in ["who", "pick", "any", "user", "username"]:
2024-02-23 02:22:16 +00:00
update_time()
2024-03-04 04:50:00 +00:00
if len(args) > 0:
arg = " ".join(clean_list(args))
else:
arg = None
2024-02-21 15:40:24 +00:00
2024-03-04 04:50:00 +00:00
await gif_user(arg, room_id)
elif cmd in ["when", "die", "death"]:
2024-02-28 10:59:44 +00:00
update_time()
2024-03-03 19:30:02 +00:00
if len(args) > 0:
arg = " ".join(clean_list(args))
else:
arg = None
2024-03-04 04:50:00 +00:00
await gif_when(arg, room_id)
elif cmd in ["bird", "birds", "birb", "birbs", "brb"]:
update_time()
await random_bird(ws, room_id)
elif cmd in ["post", "shitpost", "4chan", "anon", "shit"]:
update_time()
await random_post(ws, room_id)
2024-02-28 10:59:44 +00:00
2024-02-22 16:34:55 +00:00
2024-02-22 17:29:33 +00:00
async def random_bird(ws, room_id):
2024-02-23 02:22:16 +00:00
birdfile = get_path("data/aves.txt")
async with aiofiles.open(birdfile, mode="r", encoding="utf-8") as file:
birds = await file.readlines()
bird = random.choice(birds).strip()
await send_message(ws, f".i \"{bird}\" bird", room_id)
2024-02-22 17:29:33 +00:00
2024-02-20 06:57:49 +00:00
2024-02-20 06:14:06 +00:00
async def gif_describe(who, room_id):
2024-02-28 09:26:30 +00:00
command = gifmaker_command([
"--input", get_path("describe.jpg"),
"--words", f"{who} is\\n[Random] [x5]",
"--filter", "anyhue2",
"--opacity", 0.8,
"--fontsize", 66,
"--delay", 700,
"--padding", 50,
"--fontcolor", "light2",
"--bgcolor", "black",
])
2024-02-20 06:57:49 +00:00
2024-02-23 02:22:16 +00:00
await run_gifmaker(command, room_id)
2024-02-20 06:14:06 +00:00
async def gif_wins(who, room_id):
2024-03-03 19:27:48 +00:00
if not who:
who = random.choice(userlist)
2024-02-28 09:26:30 +00:00
command = gifmaker_command([
"--input", get_path("wins.gif"),
"--words", f"{who} wins a ; [repeat] ; [RANDOM] ; [repeat]",
"--bgcolor", "0,0,0",
"--bottom", 20,
"--filter", "anyhue2",
"--framelist", "11,11,33,33",
"--fontsize", 42,
])
2024-02-23 02:22:16 +00:00
await run_gifmaker(command, room_id)
2024-02-20 06:14:06 +00:00
2024-02-22 20:21:53 +00:00
async def gif_numbers(arg, room_id):
2024-02-23 02:22:16 +00:00
num = -1
if arg:
nums = extract_range(arg)
2024-02-22 20:21:53 +00:00
2024-02-23 02:22:16 +00:00
if nums[0] is not None:
if nums[1] is not None:
2024-02-23 02:26:27 +00:00
if nums[0] < nums[1]:
num = random_int(nums[0], nums[1])
else:
return
2024-02-23 02:22:16 +00:00
else:
num = random_int(0, nums[0])
2024-02-22 20:21:53 +00:00
2024-02-24 04:47:08 +00:00
if num == -1:
num = string_to_number(arg)
if num == -1:
num = random_int(0, 999)
2024-02-22 20:48:56 +00:00
2024-02-28 09:26:30 +00:00
command = gifmaker_command([
"--input", get_path("numbers.pnf"),
"--top", 20,
"--words", num,
"--fontcolor", "0,0,0",
"--fontsize", 66,
"--format", "jpg",
])
2024-02-22 20:28:07 +00:00
2024-02-23 02:22:16 +00:00
await run_gifmaker(command, room_id)
2024-02-20 06:14:06 +00:00
2024-02-24 02:02:54 +00:00
async def gif_date(room_id):
2024-02-28 09:26:30 +00:00
command = gifmaker_command([
"--input", get_path("time.jpg"),
"--words", "Date: [date %A %d] ; [repeat] ; Time: [date %I:%M %p] ; [repeat]",
"--filter", "anyhue2",
"--bottom", 20,
"--bgcolor", "0,0,0",
"--fontsize", 80,
])
2024-02-20 06:57:49 +00:00
2024-02-23 02:22:16 +00:00
await run_gifmaker(command, room_id)
2024-02-20 06:14:06 +00:00
2024-03-03 19:30:02 +00:00
async def gif_user(who, room_id):
if not who:
who = random.choice(userlist)
2024-02-28 10:59:44 +00:00
what = random.choice(["based", "cringe"])
command = gifmaker_command([
"--input", get_path("nerd.jpg"),
2024-03-03 19:30:02 +00:00
"--words", f"{who} is [x2] ; {what} [x2]",
2024-02-28 10:59:44 +00:00
"--filter", "anyhue2",
"--bottom", 20,
2024-02-28 11:33:28 +00:00
"--fontcolor", "light2",
"--bgcolor", "darkfont2",
2024-02-28 10:59:44 +00:00
"--outline", "font",
"--deepfry",
"--font", "nova",
"--fontsize", 45,
"--opacity", 0.8,
])
await run_gifmaker(command, room_id)
2024-03-04 04:50:00 +00:00
async def gif_when(who, room_id):
if not who:
who = random.choice(userlist)
date = random_date()
command = gifmaker_command([
"--input", get_path("sky.jpg"),
"--words", f"{who} will die [x2] ; {date} [x2]",
"--filter", "anyhue2",
2024-03-07 01:14:29 +00:00
"--bottom", 66,
2024-03-04 04:50:00 +00:00
"--fontcolor", "light2",
"--bgcolor", "darkfont2",
"--outline", "font",
"--font", "nova",
2024-03-07 01:14:29 +00:00
"--fontsize", 70,
2024-03-04 04:50:00 +00:00
"--opacity", 0.8,
"--wrap", 25,
])
await run_gifmaker(command, room_id)
2024-02-22 16:34:55 +00:00
async def random_post(ws, room_id):
2024-02-23 02:22:16 +00:00
boards = ["g", "an", "ck", "lit", "x", "tv", "v", "fit", "k", "o"]
board = random.choice(boards)
2024-02-22 16:34:55 +00:00
2024-02-23 02:22:16 +00:00
try:
threads_url = f"https://a.4cdn.org/{board}/threads.json"
async_client = httpx.AsyncClient()
threads_response = await async_client.get(threads_url)
threads_response.raise_for_status()
threads_json = threads_response.json()
threads = threads_json[0]["threads"]
2024-02-22 16:34:55 +00:00
2024-02-23 02:22:16 +00:00
# Select a random thread
id = threads[random_int(0, len(threads) - 1)]["no"]
thread_url = f"https://a.4cdn.org/{board}/thread/{id}.json"
2024-02-22 16:34:55 +00:00
2024-02-23 02:22:16 +00:00
# Fetch the selected thread
thread_response = await async_client.get(thread_url)
thread_response.raise_for_status()
thread_json = thread_response.json()
posts = thread_json["posts"]
2024-02-22 16:34:55 +00:00
2024-02-23 02:22:16 +00:00
# Select a random post
post = posts[random_int(0, len(posts) - 1)]
html = post.get("com", "")
2024-02-24 04:47:08 +00:00
if not html:
return
2024-02-22 16:34:55 +00:00
2024-02-23 02:22:16 +00:00
# Parse HTML using BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
2024-02-22 16:34:55 +00:00
2024-02-23 02:22:16 +00:00
# Remove elements with class "quotelink"
for elem in soup.select(".quotelink"):
elem.decompose()
2024-02-22 16:34:55 +00:00
2024-02-23 02:22:16 +00:00
# Replace <br> with newline
for br in soup.find_all("br"):
br.replace_with("\n")
2024-02-22 16:34:55 +00:00
2024-02-29 19:30:09 +00:00
# Get the text content
text = soup.get_text(separator="\n").strip()
2024-02-23 02:22:16 +00:00
text = clean_lines(text)
2024-02-24 04:47:08 +00:00
if not text:
return
2024-02-22 16:34:55 +00:00
2024-02-24 02:02:54 +00:00
await send_message(ws, text, room_id)
2024-02-23 02:22:16 +00:00
except Exception as err:
2024-02-29 08:51:13 +00:00
msg(f"Error: {err}")
2024-02-22 16:34:55 +00:00
2024-02-20 12:23:18 +00:00
async def run_gifmaker(command, room_id):
2024-02-23 02:22:16 +00:00
process = await asyncio.create_subprocess_shell(
2024-02-28 10:00:24 +00:00
command,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
2024-02-23 02:22:16 +00:00
shell=True,
)
stdout, stderr = await process.communicate()
2024-02-20 06:14:06 +00:00
2024-02-23 02:22:16 +00:00
if process.returncode != 0:
2024-02-29 08:51:13 +00:00
msg(f"(Process) Error: {stderr.decode()}")
2024-02-23 02:22:16 +00:00
return
2024-02-20 06:14:06 +00:00
2024-02-23 02:22:16 +00:00
await upload(Path(stdout.decode().strip()), room_id)
2024-02-20 06:14:06 +00:00
async def upload(path, room_id):
2024-02-23 02:22:16 +00:00
if (not path.exists()) or (not path.is_file()):
return
cookies = {
"session_id": session.split("=")[1],
"api_token": token.split("=")[1],
}
2024-02-20 06:14:06 +00:00
2024-02-23 02:22:16 +00:00
ext = get_extension(path)
2024-02-24 02:02:54 +00:00
ext = "jpeg" if ext == "jpg" else ext
2024-02-23 02:22:16 +00:00
url = "https://deek.chat/message/send/" + str(room_id)
2024-02-24 02:02:54 +00:00
2024-02-23 02:22:16 +00:00
data = aiohttp.FormData()
2024-02-24 02:02:54 +00:00
data.add_field(name="files[]", value=open(path, "rb"), filename=path.name, content_type=f"image/{ext}")
2024-02-22 20:21:53 +00:00
2024-02-23 02:22:16 +00:00
try:
async with aiohttp.ClientSession(cookies=cookies) as sess:
async with sess.post(url, data=data, headers={}) as response:
await response.text()
except Exception as e:
2024-02-29 08:51:13 +00:00
msg(f"(Upload) Error: {e}")
2024-02-23 02:22:16 +00:00
traceback.print_exc()
2024-02-20 06:14:06 +00:00
2024-02-23 02:22:16 +00:00
remove_file(path)
2024-02-20 06:14:06 +00:00
2024-02-20 11:45:09 +00:00
2024-02-20 06:14:06 +00:00
async def send_message(ws, text, room_id):
2024-02-23 02:22:16 +00:00
await ws.send(json.dumps({"type": "message", "data": text, "roomId": room_id}))
2024-02-20 06:14:06 +00:00
while True:
2024-02-23 02:22:16 +00:00
try:
auth()
2024-02-29 08:51:13 +00:00
msg("Authenticated")
2024-02-23 02:22:16 +00:00
asyncio.run(run())
except KeyboardInterrupt:
break
except Exception as e:
2024-02-29 08:51:13 +00:00
msg("(Main) Error:", e)
2024-02-23 02:22:16 +00:00
traceback.print_exc()