mirror of
https://github.com/migatu/conjurer.git
synced 2026-07-14 13:34:40 +00:00
a64fb2da57
Make the stable 'working copy' bot the canonical code at the repository
root so the install/deploy scripts operate against it again.
- Move working_copy/* to root (bot entrypoint is bot.py)
- Restore root-level install/ops scripts from c4fa88e (deploy.sh,
install_main_bot.sh, status_report.*, conjurer.service, etc.)
- Fix deploy.sh: copy bot.py (was thin_client.py) and add the
conanjurer_* modules; bump command count
- Remove side-by-side variant dirs (backup_old_docker, prototype_one,
prototype_musician_one, musician_old, working_copy) and docker cruft
- Keep components as subdirs: conjurer_librarian, conjurer_musician,
spotify_dl, yt_dlp, fonts, utils, docs
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
264 lines
12 KiB
Python
264 lines
12 KiB
Python
import json
|
|
import logging
|
|
import os
|
|
import random
|
|
import re
|
|
import shutil
|
|
from datetime import datetime
|
|
|
|
import discord
|
|
import numpy as np
|
|
from discord.ext import commands, tasks
|
|
|
|
from ai_functions import get_random_cyclic_message
|
|
from constants import (
|
|
ENCODING,
|
|
LAST_SPONTANEOUS_CALL,
|
|
LOGFILE,
|
|
LOGSTORE,
|
|
MEMORY_FIVE_MUZYKA,
|
|
MEMORY_FIVE_SIARA,
|
|
TIME_BETWEEN_CALLS,
|
|
)
|
|
|
|
|
|
class AdministrationModule(commands.Cog):
|
|
def __init__(self, bot, logger_name):
|
|
self.bot = bot
|
|
self.logger = logging.getLogger(logger_name)
|
|
|
|
@commands.hybrid_command(
|
|
name="galeria_slaw",
|
|
description="Jeśli nie wiesz jak użyć tej komendy to nawet nie próbuj",
|
|
guild=discord.Object(id=664789470779932693),
|
|
)
|
|
@commands.has_any_role('Nocna Zmiana', 'Jarl', 'Thane' , 'Bartender')
|
|
async def galeria_slaw(self, ctx):
|
|
if isinstance(ctx.channel, discord.DMChannel):
|
|
for guild in self.bot.guilds:
|
|
async for entry in guild.bans(limit=1500):
|
|
fnord = discord.File(
|
|
"/home/pi/Conjurer/niech_spierdala.png",
|
|
spoiler=False,
|
|
description="Niech spierdala",
|
|
)
|
|
await ctx.reply(
|
|
f"User: {entry.user} wyjebany z serwera {guild.name} za {entry.reason} ",
|
|
file=fnord,
|
|
)
|
|
|
|
@commands.hybrid_command(
|
|
name="update_banlist",
|
|
description="Jeśli nie wiesz jak użyć tej komendy to nawet nie próbuj",
|
|
guild=discord.Object(id=664789470779932693),
|
|
)
|
|
@commands.has_any_role('Jarl', 'Thane')
|
|
|
|
async def update_banlist(self, ctx):
|
|
"""
|
|
Update a banlist in a Discord guild from preprovided list in channel.
|
|
|
|
:param ctx: ctx stands for "context" and is a parameter commonly used in Discord.py commands. It
|
|
contains information about the context in which the command was invoked, such as the message, the
|
|
channel, the server, and the user who invoked the command. This information can be used to perform
|
|
various actions, such
|
|
"""
|
|
async with ctx.channel.typing():
|
|
allowed = False
|
|
for role in ctx.author.roles:
|
|
if role.name == "Jarl":
|
|
allowed = True
|
|
|
|
if ctx.channel.id != 1102190666827702342:
|
|
# trunk-ignore(codespell/misspelled)
|
|
await ctx.send("Nie wydaje mnie sie")
|
|
elif not allowed:
|
|
await ctx.send("Idź bo Cię zdziele")
|
|
else:
|
|
tobancunter = 0
|
|
async with ctx.typing():
|
|
# 1. get list of users posted on channel for banning
|
|
channel = ctx.channel
|
|
messages = [
|
|
message async for message in channel.history(limit=None)
|
|
]
|
|
ids_to_ban = []
|
|
for message in messages:
|
|
lines = message.content.split("\n")
|
|
for line in lines:
|
|
match = re.search(
|
|
"\\d{18}",
|
|
line,
|
|
# trunk-ignore(codespell/misspelled)
|
|
) # poprawilem backslash na podwojny bo linter sie czepial
|
|
if match:
|
|
ids_to_ban.append(match.group())
|
|
tobancunter += 1
|
|
# 2. get list of already banned users for all servers Conjurer
|
|
# has rights to
|
|
for guild in self.bot.guilds:
|
|
bancunter = 0
|
|
# trunk-ignore(codespell/misspelled)
|
|
self.logger.info("Serwer: %s", guild)
|
|
current_banlist = []
|
|
permission = True
|
|
try:
|
|
async for entry in guild.bans(limit=None):
|
|
current_banlist.append(entry.user.id)
|
|
bancunter += 1
|
|
except BaseException: # pylint: disable=broad-exception-caught
|
|
permission = False
|
|
if permission:
|
|
# 3. compare lists ban only users on list 2 and not on
|
|
# list 1
|
|
cunter_counter = 0
|
|
bad_id_cunter_counter = 0
|
|
ban_list = np.setdiff1d(ids_to_ban, current_banlist)
|
|
for ident in ban_list:
|
|
try:
|
|
tmp_user = await self.bot.fetch_user(int(ident))
|
|
await guild.ban(
|
|
tmp_user,
|
|
reason="Automatyczna lista banów",
|
|
delete_message_seconds=0,
|
|
)
|
|
# TODO: Maybe use guild.bulk_ban ?
|
|
cunter_counter += 1
|
|
except discord.NotFound:
|
|
self.logger.info(
|
|
"Znaleziono uzyszkodnika ktory juz nie ma konta"
|
|
)
|
|
bad_id_cunter_counter += 1
|
|
# 4. return message success/failure - how many banned
|
|
await ctx.send(
|
|
"Obecnie na serwerze {guild} jest {bancunter} zbanowanych użytkowników. Znaleziono na tym kanale {tobancunter} id użytkowników do zbanowania. Zbanowano {cunter_counter} użytkowników. Na liście jest {bad_id_cunter_counter} użytkowników którzy skasowali już konto"
|
|
)
|
|
else:
|
|
await ctx.send(
|
|
f"Nie mam na serwerze {guild} uprawnień do banowania. :()"
|
|
)
|
|
await ctx.send("Zrobione tak czy inaczej")
|
|
@commands.hybrid_command(
|
|
name="archive_channel",
|
|
description="Jeśli nie wiesz jak użyć tej komendy to nawet nie próbuj",
|
|
guild=discord.Object(id=664789470779932693),
|
|
)
|
|
@commands.has_any_role('Jarl', 'Thane')
|
|
|
|
async def archive_channel(self, channel_no):
|
|
"""
|
|
The function `archive_channel` retrieves messages from a specified channel, processes them, and
|
|
saves the data in a JSON file with a timestamp in the filename.
|
|
|
|
:param channel_no: The `archive_channel` function you provided seems to be incomplete. It looks like
|
|
you are trying to archive messages from a Discord channel into a JSON file
|
|
"""
|
|
channel = self.bot.get_channel(channel_no)
|
|
messages = [message async for message in channel.history(limit=None)]
|
|
path_newfile = f"{LOGSTORE}channeldump_{channel_no}_{datetime.now()}.json"
|
|
new_data = []
|
|
for message in messages:
|
|
new_data.append(message)
|
|
with open(path_newfile, "x", encoding=ENCODING) as new_file:
|
|
new_file.seek(0)
|
|
json.dump(new_data, new_file, indent=4)
|
|
|
|
@tasks.loop(seconds=120)
|
|
async def check_self(self):
|
|
"""
|
|
The function `check_data` periodically checks for conditions to send messages and manage log files
|
|
in a Discord channel.
|
|
"""
|
|
# logger.info("Heartbeat of cleanup proc")
|
|
channel = self.bot.get_channel(1062047367337095268)
|
|
messages = [message async for message in channel.history(limit=1)]
|
|
for mess in messages:
|
|
channel = mess.channel
|
|
if os.path.getsize(LOGFILE) > 60000000:
|
|
await channel.send(
|
|
"*Conjurer porządkuje bar, wypala szklanki do czysta miotaczem płomieni ze swojej zbroi i ogólnie wygląda na zajętego....*"
|
|
)
|
|
async with channel.typing():
|
|
shutil.copyfile(LOGFILE, f"{LOGSTORE}discord{datetime.now()}")
|
|
self.logger.info("Log rollover")
|
|
handlers = self.logger.handlers
|
|
for handler in handlers:
|
|
if isinstance(handler, logging.handlers.RotatingFileHandler):
|
|
handler.doRollover()
|
|
await channel.send(
|
|
"*Przeciąga się za barem* No dobra - porobione to można dalej pi... *Zauważa spojrzenie Hammera* ...sać powieści o naszym wspaniałym barze SZEFIE!"
|
|
)
|
|
|
|
if os.path.getsize(MEMORY_FIVE_MUZYKA) > 3000000:
|
|
await channel.send(
|
|
"*Conjurer porządkuje bar, wypala szklanki do czysta miotaczem płomieni ze swojej zbroi i ogólnie wygląda na zajętego....*"
|
|
)
|
|
async with channel.typing():
|
|
path_newfile = f"{LOGSTORE}pamiec_muzyki{datetime.now()}.json"
|
|
self.logger.info(path_newfile)
|
|
with open(
|
|
MEMORY_FIVE_MUZYKA, "r+", encoding=ENCODING
|
|
) as file_music_memory:
|
|
with open(path_newfile, "x", encoding=ENCODING) as new_file:
|
|
# First we load existing data into a dict.
|
|
file_data = json.load(file_music_memory)
|
|
new_data = []
|
|
new_data.append(file_data[0])
|
|
new_data.extend(file_data[:-20])
|
|
file_music_memory.truncate(0)
|
|
file_music_memory.seek(0)
|
|
# convert back to json.
|
|
new_file.seek(0)
|
|
json.dump(new_data, file_music_memory, indent=4)
|
|
json.dump(file_data, new_file, indent=4)
|
|
await channel.send(
|
|
"*Przeciąga się za barem* No dobra - porobione to można dalej pi... *Zauważa spojrzenie Hammera* ...sać powieści o naszym wspaniałym barze SZEFIE!"
|
|
)
|
|
if os.path.getsize(MEMORY_FIVE_SIARA) > 3000000:
|
|
path_newfile = f"{LOGSTORE}pamiec_rozmow{datetime.now()}.json"
|
|
self.logger.info(path_newfile)
|
|
await channel.send(
|
|
"*Conjurer porządkuje bar, ścina lekkim laserem pulsacyjnym powierzchnie baru o grubości kilku mikronów i ogólnie wygląda na zajętego....*"
|
|
)
|
|
with open(MEMORY_FIVE_SIARA, "r+", encoding=ENCODING) as file:
|
|
with open(path_newfile, "x", encoding=ENCODING) as new_file:
|
|
# First we load existing data into a dict.
|
|
file_data = json.load(file)
|
|
new_data = []
|
|
new_data.append(file_data[0])
|
|
new_data.extend(file_data[-20])
|
|
file.truncate(0)
|
|
file.seek(0)
|
|
new_file.seek(0)
|
|
# convert back to json.
|
|
json.dump(new_data, file, indent=4)
|
|
json.dump(file_data, new_file, indent=4)
|
|
await channel.send(
|
|
"*Przeciąga się za barem* No dobra - porobione to można dalej pi... *Zauważa spojrzenie Hammera* eprzyć o głupotach z klientami... Szefie... *Bierze 'ukradkowy' łyk z piersiówki*"
|
|
)
|
|
global LAST_SPONTANEOUS_CALL
|
|
global TIME_BETWEEN_CALLS
|
|
tdelta = datetime.now() - LAST_SPONTANEOUS_CALL
|
|
tdelta = tdelta.total_seconds()
|
|
if tdelta > TIME_BETWEEN_CALLS:
|
|
self.logger.info("Spontaneous call")
|
|
# trunk-ignore(bandit/B311)
|
|
TIME_BETWEEN_CALLS = random.randint(
|
|
10200, 272800
|
|
) # temp random, set after each call
|
|
self.logger.debug(TIME_BETWEEN_CALLS)
|
|
LAST_SPONTANEOUS_CALL = datetime.now()
|
|
async with channel.typing():
|
|
message = await get_random_cyclic_message(self.bot)
|
|
self.logger.info("Odpowiedz")
|
|
self.logger.info(message)
|
|
await channel.send(message)
|
|
|
|
|
|
async def setup(bot):
|
|
logger = logging.getLogger("discord")
|
|
am = AdministrationModule(bot, "discord")
|
|
await bot.add_cog(am)
|
|
am.check_self.start()
|
|
logger.info("Loading administration commands module done")
|