initial commit
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
commit
c22dade3d5
21 files changed
+564
No files matched your search
+11
@@ -0,0 +1,11 @@
|
||||
import io,time
|
||||
import aiohttp,discord
|
||||
from discord.ext import commands
|
||||
class cat(commands.Cog):
|
||||
def __init__(s,bot):s.bot=bot
|
||||
@commands.command()
|
||||
async def cat(s,ctx):
|
||||
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=15)) as http,http.get("https://cataas.com/cat") as r:
|
||||
r.raise_for_status();data=await r.read();ext=r.content_type.split('/')[-1].replace('jpeg','jpg')
|
||||
await ctx.send(file=discord.File(io.BytesIO(data),filename=f"cat-{int(time.time())}.{ext}"))
|
||||
async def setup(bot):await bot.add_cog(cat(bot))
|
||||
@@ -0,0 +1,8 @@
|
||||
from discord.ext import commands
|
||||
class help(commands.Cog):
|
||||
def __init__(s,bot):s.bot=bot
|
||||
@commands.command(name="help")
|
||||
async def help(s,ctx):
|
||||
names=sorted(c.qualified_name for c in s.bot.walk_commands() if not c.hidden)
|
||||
await ctx.send("```\n"+"\n".join(";"+n for n in names)+"\n```")
|
||||
async def setup(bot):await bot.add_cog(help(bot))
|
||||
@@ -0,0 +1,41 @@
|
||||
import asyncio,re
|
||||
from discord.ext import commands
|
||||
def uid(s):
|
||||
m=re.fullmatch(r"<@!?(\d+)>|(\d+)",s.strip())
|
||||
return int(m[1] or m[2]) if m else None
|
||||
class perm(commands.Cog):
|
||||
def __init__(s,bot):
|
||||
s.bot=bot;s.names={};s.sem=asyncio.Semaphore(2)
|
||||
async def cog_check(s,ctx):return ctx.author.id==s.bot.user.id
|
||||
async def name(s,i):
|
||||
if i in s.names:return s.names[i]
|
||||
u=s.bot.get_user(i)
|
||||
if u is None:
|
||||
async with s.sem:
|
||||
try:u=await s.bot.fetch_user(i)
|
||||
except Exception:u=None
|
||||
await asyncio.sleep(.6)
|
||||
n=(u.global_name or u.name) if u else "unknown"
|
||||
if u:s.names[i]=n
|
||||
return n
|
||||
@commands.group(invoke_without_command=True)
|
||||
async def perm(s,ctx):await ctx.send("`;perm list|add <id|mention>|remove <id|mention>`")
|
||||
@perm.command(name="list")
|
||||
async def _list(s,ctx):
|
||||
ids=sorted(s.bot.wl.ids)
|
||||
if not ids:return await ctx.send("whitelist empty")
|
||||
n=await asyncio.gather(*(s.name(i) for i in ids))
|
||||
await ctx.send("\n".join(f"{i} - {x}" for i,x in zip(ids,n)))
|
||||
@perm.command(name="add")
|
||||
async def _add(s,ctx,target:str):
|
||||
i=uid(target)
|
||||
if i is None:return await ctx.send("invalid id")
|
||||
await s.bot.wl.mutate(i,True);s.bot.hook.put(f"whitelist: {i} added by {ctx.author.id}")
|
||||
await ctx.send(f"{i} added ({await s.name(i)})")
|
||||
@perm.command(name="remove")
|
||||
async def _remove(s,ctx,target:str):
|
||||
i=uid(target)
|
||||
if i is None:return await ctx.send("invalid id")
|
||||
await s.bot.wl.mutate(i,False);s.bot.hook.put(f"whitelist: {i} removed by {ctx.author.id}")
|
||||
await ctx.send(f"{i} removed")
|
||||
async def setup(bot):await bot.add_cog(perm(bot))
|
||||
@@ -0,0 +1,26 @@
|
||||
import asyncio,re
|
||||
import aiohttp
|
||||
from discord.ext import commands
|
||||
URL="https://discordstatus.com/metrics-display/5k2rt9f7pmny/day.json"
|
||||
async def local():
|
||||
try:
|
||||
p=await asyncio.create_subprocess_exec("ping","-c","1","-W","5","discord.com",stdout=asyncio.subprocess.PIPE,stderr=asyncio.subprocess.STDOUT)
|
||||
out,_=await asyncio.wait_for(p.communicate(),8)
|
||||
m=re.search(r"time[=<]\s*([\d.]+)\s*ms",out.decode(),re.I)
|
||||
return round(float(m[1])) if m else None
|
||||
except Exception:return None
|
||||
async def glob():
|
||||
try:
|
||||
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10)) as h,h.get(URL) as r:
|
||||
return int((await r.json(content_type=None))["summary"]["last"])
|
||||
except Exception:return None
|
||||
class ping(commands.Cog):
|
||||
def __init__(s,bot):s.bot=bot
|
||||
@commands.command()
|
||||
async def ping(s,ctx):
|
||||
l,g=await asyncio.gather(local(),glob())
|
||||
f=lambda v:f"{v}ms" if v is not None else "n/a"
|
||||
w=s.bot.latency
|
||||
w=round(w*1000) if w==w and w!=float("inf") else None
|
||||
await ctx.send(f"websocket ping: {f(w)}\nlocal discord ping: {f(l)}\nglobal discord ping: {f(g)}")
|
||||
async def setup(bot):await bot.add_cog(ping(bot))
|
||||
@@ -0,0 +1,119 @@
|
||||
import io,unicodedata,urllib.request
|
||||
from pathlib import Path
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from PIL import Image,ImageDraw,ImageFilter,ImageFont,ImageOps
|
||||
from pilmoji import Pilmoji
|
||||
from core.threads import run_blocking
|
||||
W,H,AV,PAD,MAXC=1200,480,268,42,420
|
||||
BG0,BG1,CARD,STROKE,ACC,TXT,SUB,MARK=(7,9,17),(15,20,36),(18,24,44),(46,64,108),(82,116,214),(236,242,255),(128,150,192),(52,80,160)
|
||||
FONT=Path(__file__).resolve().parents[1]/"font"/"NotoSans-Regular.ttf"
|
||||
def norm(t):return unicodedata.normalize("NFKC",t)
|
||||
def font(n):
|
||||
try:return ImageFont.truetype(str(FONT),n)
|
||||
except Exception:return ImageFont.load_default()
|
||||
def fetch(url):
|
||||
with urllib.request.urlopen(urllib.request.Request(url,headers={"User-Agent":"Mozilla/5.0"}),timeout=20) as r:return r.read()
|
||||
def names(t,users):
|
||||
for u in {u.id:u for u in users}.values():
|
||||
n="@"+(getattr(u,"display_name",None) or u.name);t=t.replace(f"<@{u.id}>",n).replace(f"<@!{u.id}>",n)
|
||||
return t
|
||||
def gradient():
|
||||
im=Image.new("RGB",(W,H));d=ImageDraw.Draw(im)
|
||||
for y in range(H):
|
||||
t=y/(H-1);d.line((0,y,W,y),fill=tuple(int(a+(b-a)*t) for a,b in zip(BG0,BG1)))
|
||||
return im.convert("RGBA")
|
||||
def glow(im):
|
||||
o=Image.new("RGBA",im.size,(0,0,0,0));d=ImageDraw.Draw(o);cx,cy,m=int(W*.74),int(H*.2),int(H*.7)
|
||||
for i in range(18):
|
||||
r=int(m*(1-i/18));d.ellipse((cx-r,cy-r,cx+r,cy+r),fill=(100,130,215,int(52*(1-i/18))))
|
||||
o=o.filter(ImageFilter.GaussianBlur(12));im.paste(o,(0,0),o)
|
||||
def tw(d,t,f):
|
||||
l,_,r,_=d.textbbox((0,0),t,font=f);return r-l
|
||||
def chop(d,w,f,mw):
|
||||
out=[];cur=""
|
||||
for c in w:
|
||||
if cur and tw(d,cur+c,f)>mw:out.append(cur);cur=c
|
||||
else:cur+=c
|
||||
return out+([cur] if cur else [])
|
||||
def wrap(d,t,f,mw):
|
||||
lines=[]
|
||||
for p in t.splitlines() or [t]:
|
||||
ws=p.split()
|
||||
if not ws:
|
||||
if lines:lines.append("")
|
||||
continue
|
||||
cur=""
|
||||
for w in ws:
|
||||
for part in (chop(d,w,f,mw) if tw(d,w,f)>mw else [w]):
|
||||
x=part if not cur else cur+" "+part
|
||||
if tw(d,x,f)<=mw:cur=x
|
||||
else:
|
||||
if cur:lines.append(cur)
|
||||
cur=part
|
||||
if cur:lines.append(cur)
|
||||
return lines
|
||||
def lh(d,f):
|
||||
_,t,_,b=d.textbbox((0,0),"Ag",font=f);h=b-t;return max(h+6,int(h*1.26))
|
||||
def fit(d,t,mw,mh):
|
||||
last=(["..."],font(15),lh(d,font(15)))
|
||||
for s in range(110,14,-2):
|
||||
f=font(s);l=wrap(d,t,f,mw);h=lh(d,f)
|
||||
if len(l)*h<=mh:return l or ["..."],f,h
|
||||
last=(l,f,h)
|
||||
l,f,h=last;return (l or ["..."])[:max(1,mh//max(1,h))],f,h
|
||||
def avatar(b):
|
||||
a=ImageOps.fit(Image.open(io.BytesIO(b)).convert("RGB"),(AV,AV));m=Image.new("L",(AV,AV),0)
|
||||
ImageDraw.Draw(m).ellipse((0,0,AV,AV),fill=255);r=Image.new("RGBA",(AV,AV),(0,0,0,0));r.paste(a,(0,0),m);return r
|
||||
def build(ab,text,sig):
|
||||
im=gradient();glow(im);d=ImageDraw.Draw(im)
|
||||
ax,ay=PAD,(H-AV)//2;cl,ct,cr,cb=ax+AV+18,24,W-24,H-24
|
||||
sh=Image.new("RGBA",im.size,(0,0,0,0));ImageDraw.Draw(sh).rounded_rectangle((cl+7,ct+10,cr+7,cb+10),radius=28,fill=(0,0,0,105))
|
||||
sh=sh.filter(ImageFilter.GaussianBlur(10));im.paste(sh,(0,0),sh)
|
||||
d.rounded_rectangle((cl,ct,cr,cb),radius=28,fill=CARD,outline=STROKE,width=2)
|
||||
gd=AV+28;g=Image.new("RGBA",(gd,gd),(0,0,0,0));gg=ImageDraw.Draw(g);c=gd//2
|
||||
for i in range(10):
|
||||
r=c-i*4
|
||||
if r<=0:break
|
||||
gg.ellipse((c-r,c-r,c+r,c+r),fill=(*ACC,int(55*(1-i/10))))
|
||||
g=g.filter(ImageFilter.GaussianBlur(4));im.paste(g,(ax-14,ay-14),g)
|
||||
rd=AV+8;ring=Image.new("RGBA",(rd,rd),(0,0,0,0));ImageDraw.Draw(ring).ellipse((0,0,rd-1,rd-1),outline=(*ACC,175),width=3);im.paste(ring,(ax-4,ay-4),ring)
|
||||
a=avatar(ab);im.paste(a,(ax,ay),a)
|
||||
qx,zt,tr=cl+52,ct+44,cr-32;sf=font(27);sig=f"\u2014 {sig}";_,_,_,sh_=d.textbbox((0,0),sig,font=sf)
|
||||
sy=cb-sh_-30;dy=sy-15;zh=max(48,dy-zt-16)
|
||||
lines,qf,h=fit(d,text,tr-qx,zh)
|
||||
d.text((cl+10,ct+6),"\u201c",font=font(max(54,min(100,int(h*1.55)))),fill=MARK)
|
||||
cx=(qx+tr)//2;y=zt+max(0,(zh-len(lines)*h)//2)
|
||||
with Pilmoji(im) as p:
|
||||
for l in lines:
|
||||
p.text((cx-tw(d,l,qf)//2,y),l,font=qf,fill=TXT,emoji_scale_factor=1.08,emoji_position_offset=(0,-2));y+=h
|
||||
d.rectangle((qx,dy,tr,dy+1),fill=STROKE)
|
||||
p.text((qx,sy),sig,font=sf,fill=SUB,emoji_scale_factor=1.0,emoji_position_offset=(0,-1))
|
||||
out=io.BytesIO();im.convert("RGB").save(out,format="PNG");out.seek(0);return out
|
||||
class q(commands.Cog):
|
||||
def __init__(s,bot):s.bot=bot
|
||||
@commands.command(name="q")
|
||||
async def q(s,ctx,*args):
|
||||
m=ctx.message;target=m.author;text=""
|
||||
ref=m.reference
|
||||
if not args and ref and ref.message_id:
|
||||
r=ref.resolved if isinstance(ref.resolved,discord.Message) else None
|
||||
if r is None:
|
||||
try:r=await m.channel.fetch_message(ref.message_id)
|
||||
except Exception:r=None
|
||||
if r:
|
||||
text=names((r.content or "").strip(),r.mentions)
|
||||
if text:target=r.author
|
||||
if not text:
|
||||
rest=list(args)
|
||||
if rest and rest[0].startswith("<@") and m.mentions:
|
||||
target=m.mentions[0];rest=[x for x in rest if x not in(f"<@{target.id}>",f"<@!{target.id}>")]
|
||||
text=names(" ".join(rest).strip(),m.mentions)
|
||||
if not text:return await ctx.send("usage: ;q text | ;q @user text | reply with ;q")
|
||||
text=norm(text[:MAXC])
|
||||
url=str(target.display_avatar.replace(size=512,format="png").url)
|
||||
ab=await run_blocking(fetch,url)
|
||||
sig=norm(f"{getattr(target,'global_name',None) or target.display_name} (@{target.name})")
|
||||
img=await run_blocking(build,ab,text,sig)
|
||||
await ctx.send(file=discord.File(img,filename="quote.png"))
|
||||
async def setup(bot):await bot.add_cog(q(bot))
|
||||
@@ -0,0 +1,93 @@
|
||||
import datetime as dt,os,platform,time
|
||||
import psutil
|
||||
from discord.ext import commands
|
||||
from core.threads import run_blocking
|
||||
def h(n):
|
||||
n=float(n)
|
||||
for u in("b","kib","mib","gib","tib"):
|
||||
if abs(n)<1024:return f"{n:.2f} {u}"
|
||||
n/=1024
|
||||
return f"{n:.2f} pib"
|
||||
def kv(d):return "\n".join(f"{k}: {v}" for k,v in d.items())
|
||||
def rd(p):
|
||||
try:
|
||||
with open(p) as f:return f.read().strip()
|
||||
except OSError:return ""
|
||||
def system():
|
||||
u=platform.uname();r={}
|
||||
try:r=platform.freedesktop_os_release()
|
||||
except Exception:pass
|
||||
b=psutil.boot_time()
|
||||
return kv({"system":u.system,"kernel":u.release,"version":u.version,"machine":u.machine,"platform":platform.platform(),"distro":r.get("PRETTY_NAME"),"distro id":r.get("ID"),"distro version":r.get("VERSION_ID"),"libc":" ".join(platform.libc_ver()),"python":f"{platform.python_implementation()} {platform.python_version()}","compiler":platform.python_compiler(),"build":" ".join(platform.python_build()),"boot":dt.datetime.fromtimestamp(b).isoformat(),"uptime":str(dt.timedelta(seconds=int(time.time()-b))),"entropy":rd("/proc/sys/kernel/random/entropy_avail"),"max pid":rd("/proc/sys/kernel/pid_max"),"max threads":rd("/proc/sys/kernel/threads-max"),"file max":rd("/proc/sys/fs/file-max"),"file nr":rd("/proc/sys/fs/file-nr"),"swappiness":rd("/proc/sys/vm/swappiness"),"overcommit":rd("/proc/sys/vm/overcommit_memory"),"tainted":rd("/proc/sys/kernel/tainted"),"cpu vulns":len(os.listdir("/sys/devices/system/cpu/vulnerabilities")) if os.path.isdir("/sys/devices/system/cpu/vulnerabilities") else 0})
|
||||
def clock():
|
||||
n=dt.datetime.now().astimezone()
|
||||
return kv({"local":n.isoformat(),"utc":dt.datetime.now(dt.timezone.utc).isoformat(),"tz":n.tzname(),"offset":n.utcoffset(),"time.tzname":time.tzname,"timezone":time.timezone,"altzone":time.altzone,"daylight":time.daylight,"iso week":n.isocalendar()[:2],"day of year":n.timetuple().tm_yday,"epoch":time.time(),"monotonic":time.monotonic(),"perf_counter":time.perf_counter(),"process time":time.process_time(),"clock res":time.get_clock_info("monotonic").resolution})
|
||||
def cpu():
|
||||
pc=psutil.cpu_percent(interval=1,percpu=True);fr=psutil.cpu_freq(percpu=True) or []
|
||||
info={}
|
||||
for l in rd("/proc/cpuinfo").splitlines():
|
||||
if ":" in l:
|
||||
k,v=l.split(":",1);info.setdefault(k.strip(),v.strip())
|
||||
cores="\n".join(f" core {i:>2}: {p:5.1f}%"+(f" @ {fr[i].current:.0f} mhz ({fr[i].min:.0f}-{fr[i].max:.0f})" if i<len(fr) else "") for i,p in enumerate(pc))
|
||||
return kv({"model":info.get("model name","unknown"),"vendor":info.get("vendor_id"),"family":info.get("cpu family"),"model id":info.get("model"),"stepping":info.get("stepping"),"microcode":info.get("microcode"),"cache":info.get("cache size"),"bogomips":info.get("bogomips"),"physical":psutil.cpu_count(False),"logical":psutil.cpu_count(),"total %":round(sum(pc)/len(pc),1),"loadavg":os.getloadavg(),"times":psutil.cpu_times()._asdict(),"times %":psutil.cpu_times_percent()._asdict(),"stats":psutil.cpu_stats()._asdict(),"flags":info.get("flags"),"per core":"\n"+cores})
|
||||
def mem():
|
||||
v=psutil.virtual_memory()._asdict();s=psutil.swap_memory()._asdict()
|
||||
f=lambda d:{k:(x if k in("percent","sin","sout") else h(x)) for k,x in d.items()}
|
||||
mi={}
|
||||
for l in rd("/proc/meminfo").splitlines():
|
||||
k,_,x=l.partition(":");mi[k]=x.strip()
|
||||
ex={k:mi[k] for k in("Dirty","Writeback","Mapped","AnonPages","PageTables","KernelStack","Hugepagesize","HugePages_Total","CommitLimit","Committed_AS","VmallocUsed") if k in mi}
|
||||
return "ram\n"+kv(f(v))+"\nswap\n"+kv(f(s))+"\nextra\n"+kv(ex)
|
||||
def disks():
|
||||
o=[]
|
||||
for n,p in enumerate(psutil.disk_partitions()):
|
||||
try:u=psutil.disk_usage(p.mountpoint);o.append(f"part{n} {p.fstype} [{p.opts}] {h(u.used)}/{h(u.total)} ({u.percent}%) free {h(u.free)}")
|
||||
except Exception:pass
|
||||
for k,v in psutil.disk_io_counters(perdisk=True).items():
|
||||
o.append(f"io {k}: read {h(v.read_bytes)} ({v.read_count}) write {h(v.write_bytes)} ({v.write_count}) read time {v.read_time}ms write time {v.write_time}ms busy {getattr(v,'busy_time','-')}ms")
|
||||
return "\n".join(o)
|
||||
def net():
|
||||
st=psutil.net_if_stats();io=psutil.net_io_counters(pernic=True);o=[]
|
||||
for k,a in psutil.net_if_addrs().items():
|
||||
s=st.get(k);i=io.get(k)
|
||||
o.append(f"{k}: up={s.isup if s else '?'} speed={s.speed if s else '?'} mb duplex={s.duplex.name if s else '?'} mtu={s.mtu if s else '?'}"+(f" rx={h(i.bytes_recv)} ({i.packets_recv} pkts) tx={h(i.bytes_sent)} ({i.packets_sent} pkts) err={i.errin}/{i.errout} drop={i.dropin}/{i.dropout}" if i else ""))
|
||||
o.append(" families: "+", ".join(sorted({x.family.name for x in a})))
|
||||
t=io.get
|
||||
tot=psutil.net_io_counters()
|
||||
o.append(f"total: rx={h(tot.bytes_recv)} tx={h(tot.bytes_sent)} err={tot.errin}/{tot.errout} drop={tot.dropin}/{tot.dropout}")
|
||||
try:
|
||||
c=psutil.net_connections();z={};k={}
|
||||
for x in c:
|
||||
z[x.status]=z.get(x.status,0)+1;k[x.type.name]=k.get(x.type.name,0)+1
|
||||
o.append(f"connections: {len(c)} {z} {k}")
|
||||
except Exception:pass
|
||||
return "\n".join(o)
|
||||
def sensors():
|
||||
o=[]
|
||||
for k,v in (getattr(psutil,"sensors_temperatures",lambda:{})() or {}).items():o+=[f"temp {k}/{x.label or '-'}: {x.current} c (high {x.high} crit {x.critical})" for x in v]
|
||||
for k,v in (getattr(psutil,"sensors_fans",lambda:{})() or {}).items():o+=[f"fan {k}/{x.label or '-'}: {x.current} rpm" for x in v]
|
||||
b=getattr(psutil,"sensors_battery",lambda:None)()
|
||||
if b:o.append(f"battery: {b.percent:.0f}% plugged={b.power_plugged} left={b.secsleft}")
|
||||
return "\n".join(o) or "no sensors"
|
||||
def procs():
|
||||
z={};t=0;n=0;top=[]
|
||||
for p in psutil.process_iter(["status","num_threads","memory_percent","cpu_percent"]):
|
||||
i=p.info;z[i["status"]]=z.get(i["status"],0)+1;t+=i["num_threads"] or 0;n+=1;top.append((i["memory_percent"] or 0,i["cpu_percent"] or 0))
|
||||
top.sort(reverse=True)
|
||||
return kv({"processes":n,"threads":t,"by status":z,"top mem %":[round(a,2) for a,_ in top[:5]],"mem % sum":round(sum(a for a,_ in top),1)})
|
||||
def me():
|
||||
p=psutil.Process();m=p.memory_info()
|
||||
return kv({"pid":p.pid,"ppid":p.ppid(),"threads":p.num_threads(),"rss":h(m.rss),"vms":h(m.vms),"shared":h(m.shared),"fds":p.num_fds(),"ctx switches":p.num_ctx_switches()._asdict(),"cpu times":p.cpu_times()._asdict(),"io":p.io_counters()._asdict() if hasattr(p,"io_counters") else "-","started":dt.datetime.fromtimestamp(p.create_time()).isoformat(),"nice":p.nice(),"status":p.status()})
|
||||
def build():
|
||||
o=[]
|
||||
for t,f in(("system",system),("time",clock),("cpu",cpu),("memory",mem),("disks",disks),("network",net),("sensors",sensors),("processes",procs),("bot process",me)):
|
||||
try:b=f()
|
||||
except Exception as e:b=f"n/a: {e!r}"
|
||||
o.append(f"===== {t} =====\n{b}")
|
||||
return "\n\n".join(o)
|
||||
class status(commands.Cog):
|
||||
def __init__(s,bot):s.bot=bot
|
||||
@commands.command()
|
||||
async def status(s,ctx):
|
||||
d=await run_blocking(build);await ctx.send(f"```\n{d}\n```")
|
||||
async def setup(bot):await bot.add_cog(status(bot))
|
||||
Reference in new issue
Block a user