initial commit

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
AeruandCopilot committed 2026-10-26 02:21:57 +01:00
commit c22dade3d5
21 files changed
+564

No files matched your search

View File
Whitespace-only changes.
+21
View File
@@ -0,0 +1,21 @@
import discord
from discord.ext import commands
from core.text import split
NOTE="-# slow down, this rep was rate limited, if you still spam the rate limite will increase"
class Ctx(commands.Context):
limited=False
async def send(s,content=None,**kw):
kw.setdefault("mention_author",False)
text=None if content is None else str(content)
if s.limited:
text=f"{text}\n{NOTE}" if text else NOTE
parts=split(text,1900) if len(text)>2000 else [text]
else:parts=split(text) if text is not None and len(text)>2000 else [text]
m=None
for i,p in enumerate(parts):
k=kw if i==len(parts)-1 else {"mention_author":False}
try:m=await s.message.reply(p,**k)
except discord.HTTPException:
k.pop("mention_author",None);m=await s.channel.send(p,**k)
return m
reply=send
+28
View File
@@ -0,0 +1,28 @@
import asyncio,time,aiohttp
from core.text import split
class Hook:
def __init__(s,url):
s.url=url;s.q=asyncio.Queue();s.task=None;s.http=None
async def start(s):
s.http=aiohttp.ClientSession();s.task=asyncio.create_task(s.run())
def put(s,text):
line=f"`{time.strftime('%d/%m %H:%M:%S')}` {text}"
print(line)
if s.url:
for c in split(line,1900):s.q.put_nowait(c)
async def run(s):
while True:
item=await s.q.get()
for i in range(6):
try:
async with s.http.post(s.url,json={"content":item,"allowed_mentions":{"parse":[]}}) as r:
if r.status==429:
await asyncio.sleep(float((await r.json()).get("retry_after",1))+.1);continue
if r.status<500:break
await asyncio.sleep(1+i)
except Exception:await asyncio.sleep(1+i)
s.q.task_done();await asyncio.sleep(.25)
async def close(s):
try:await asyncio.wait_for(s.q.join(),15)
except asyncio.TimeoutError:pass
s.task.cancel();await s.http.close()
+26
View File
@@ -0,0 +1,26 @@
import asyncio,time
BASE,MAX,STEP,CALM,CAP=0.5,2.0,0.25,5.0,20
class State:
__slots__=("slot","interval","last","tasks")
def __init__(s):s.slot=0.0;s.interval=BASE;s.last=0.0;s.tasks=set()
class Limiter:
def __init__(s):s.users={}
def admit(s,uid):
now=time.monotonic();st=s.users.get(uid)
if st is None:st=s.users[uid]=State()
if len(st.tasks)>=CAP:return st,None,True
if now-st.last>CALM:st.interval=BASE
wait=max(0.0,st.slot-now)
if wait>0:st.interval=min(MAX,st.interval+STEP)
st.slot=max(now,st.slot)+st.interval;st.last=now
return st,wait,False
def flush(s,st):
n=len(st.tasks)
for t in list(st.tasks):t.cancel()
st.tasks.clear();st.slot=0.0;st.interval=BASE;return n
def track(s,uid,st,task):
st.tasks.add(task)
def done(t):
st.tasks.discard(t)
if not st.tasks and time.monotonic()-st.last>CALM*2 and s.users.get(uid) is st:s.users.pop(uid,None)
task.add_done_callback(done)
+8
View File
@@ -0,0 +1,8 @@
from pathlib import Path
ROOT=Path(__file__).resolve().parent.parent
async def load_all(bot):
for d in ("cmds","events"):
for f in sorted((ROOT/d).glob("*.py")):
if f.name.startswith("_"):continue
try:await bot.load_extension(f"{d}.{f.stem}")
except Exception as e:bot.hook.put(f"module load failed: {d}.{f.stem}: {e!r}")
+10
View File
@@ -0,0 +1,10 @@
import asyncio,random,time
async def presence(bot,interval=45):
await bot.wait_until_ready()
since=int(time.time()*1000)
while True:
payload={"op":3,"d":{"status":"idle","since":since,"afk":True,"activities":[]}}
try:
if bot.ws:await bot.ws.send_as_json(payload)
except Exception as e:bot.hook.put(f"presence update failed: {e!r}")
await asyncio.sleep(interval+random.uniform(-5,5))
+10
View File
@@ -0,0 +1,10 @@
def split(t,n=1990):
out=[];op=False
while t:
pre="```\n" if op else "";room=n-len(pre)-4
if len(t)<=room:out.append(pre+t);break
cut=t.rfind("\n",0,room);cut=cut if cut>room//2 else room
chunk=t[:cut];t=t[cut:].lstrip("\n")
o=op^(chunk.count("```")%2==1)
out.append(pre+chunk+("\n```" if o else ""));op=o
return out or [""]
+22
View File
@@ -0,0 +1,22 @@
import asyncio
import functools
from concurrent.futures import ThreadPoolExecutor
_pool = ThreadPoolExecutor(max_workers=32, thread_name_prefix="dfu")
async def run_blocking(func, /, *args, **kwargs):
loop = asyncio.get_running_loop()
return await loop.run_in_executor(_pool, functools.partial(func, *args, **kwargs))
def threaded(func):
@functools.wraps(func)
async def wrapper(*args, **kwargs):
return await run_blocking(func, *args, **kwargs)
return wrapper
def spawn(coro, *, name=None):
task = asyncio.create_task(coro, name=name)
def _done(t):
if not t.cancelled() and t.exception():
print(f"task {name or ''} error: {t.exception()!r}")
task.add_done_callback(_done)
return task
def shutdown():
_pool.shutdown(wait=False, cancel_futures=True)
+35
View File
@@ -0,0 +1,35 @@
import asyncio,json,os
from pathlib import Path
from core.threads import run_blocking
def _read(p):
if not p.exists():p.write_text("[]")
return p.stat().st_mtime_ns,frozenset(int(x) for x in json.loads(p.read_text()))
def _write(p,ids):
t=p.with_suffix(".tmp");t.write_text(json.dumps(sorted(ids),indent=2));os.replace(t,p);return p.stat().st_mtime_ns
class Whitelist:
def __init__(s,path,hook):
s.path=Path(path);s.hook=hook;s.ids=frozenset();s.m=None;s.lock=asyncio.Lock();s.task=None
def __contains__(s,i):return i in s.ids
async def load(s):
try:m,ids=await run_blocking(_read,s.path)
except Exception as e:
s.hook.put(f"whitelist unreadable: {e!r}, keeping previous list")
try:s.m=(await run_blocking(s.path.stat)).st_mtime_ns
except OSError:pass
return
if s.m is not None and ids!=s.ids:s.hook.put(f"whitelist reloaded ({len(ids)} ids)")
s.ids=ids;s.m=m
async def watch(s):
while True:
await asyncio.sleep(1)
try:m=(await run_blocking(s.path.stat)).st_mtime_ns
except OSError:m=None
if m!=s.m:await s.load()
async def start(s):
await s.load();s.task=asyncio.create_task(s.watch())
async def mutate(s,i,add):
async with s.lock:
n=set(s.ids)
if add:n.add(i)
else:n.discard(i)
s.m=await run_blocking(_write,s.path,n);s.ids=frozenset(n)