Compare commits

...

13 Commits

Author SHA1 Message Date
9265c250b3 补充一些权限系统有关的注释
All checks were successful
continuous-integration/drone/push Build is passing
2026-05-20 19:34:12 +08:00
4dd9320678 取消罗文的反应机制
All checks were successful
continuous-integration/drone/push Build is passing
2026-05-20 19:11:46 +08:00
db96202d5d 添加小睦想
All checks were successful
continuous-integration/drone/push Build is passing
2026-05-19 00:11:32 +08:00
881b08c41f 此方晚安文档更新
All checks were successful
continuous-integration/drone/push Build is passing
2026-05-13 15:33:40 +08:00
c11d29e136 Merge branch 'master' of ssh://gitea.service.jazzwhom.top:2221/mttu-developers/konabot
Some checks failed
continuous-integration/drone/push Build is failing
2026-05-13 15:25:25 +08:00
1fa74b61d6 更新各种依赖 2026-05-13 15:25:11 +08:00
f0601acbe9 oyasumi
All checks were successful
continuous-integration/drone/push Build is passing
2026-05-13 15:06:49 +08:00
39c7c043ca Merge branch 'master' of ssh://gitea.service.jazzwhom.top:2221/mttu-developers/konabot
All checks were successful
continuous-integration/drone/push Build is passing
2026-04-29 18:52:01 +08:00
39accb16e0 桂花说 2026-04-29 18:51:37 +08:00
ec1f9627f3 Merge pull request 'chores: manual fix and pbr pipeline' (#73) from bkbkzzzz/konabot:marchtoy_gl into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #73
2026-04-28 14:11:47 +08:00
c0590dacbc Merge branch 'master' into marchtoy_gl 2026-04-28 14:11:08 +08:00
d748e242db manual fix 2026-04-28 14:09:45 +08:00
e2fd0809a5 PBR 2026-04-28 01:09:17 +08:00
13 changed files with 1086 additions and 798 deletions

BIN
assets/img/meme/xiaomu.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

View File

@ -29,10 +29,21 @@ async def _to_entity_chain(el: _EntityLike):
class PermManager: class PermManager:
"""
权限管理模块
"""
def __init__(self, db: DatabaseManager) -> None: def __init__(self, db: DatabaseManager) -> None:
self.db = db self.db = db
async def get_permission_info(self, entities: _EntityLike, key: str): async def get_permission_info(
self, entities: _EntityLike, key: str
) -> tuple[PermEntity, str, bool] | None:
"""
获得一个权限实体或权限实体串对一个 key 的权限信息。若未入库(默认值)则
代表没有该权限相关的记录
"""
entities = await _to_entity_chain(entities) entities = await _to_entity_chain(entities)
key = key.removesuffix("*").removesuffix(".") key = key.removesuffix("*").removesuffix(".")
key_split = key.split(".") key_split = key.split(".")
@ -52,17 +63,29 @@ class PermManager:
return None return None
async def check_has_permission(self, entities: _EntityLike, key: str) -> bool: async def check_has_permission(self, entities: _EntityLike, key: str) -> bool:
"""
检查一个权限实体或者权限实体串是否有权限
"""
res = await self.get_permission_info(entities, key) res = await self.get_permission_info(entities, key)
if res is None: if res is None:
return False return False
return res[2] return res[2]
async def update_permission(self, entity: PermEntity, key: str, perm: bool | None): async def update_permission(self, entity: PermEntity, key: str, perm: bool | None):
"""
更新一个具体的权限实体的一则权限
"""
async with self.db.get_conn() as conn: async with self.db.get_conn() as conn:
repo = PermRepo(conn) repo = PermRepo(conn)
await repo.update_perm_info(entity, key, perm) await repo.update_perm_info(entity, key, perm)
async def list_permission(self, entities: _EntityLike, query: PagerQuery): async def list_permission(self, entities: _EntityLike, query: PagerQuery):
"""
列出一个权限实体或权限实体串拥有的所有权限记录
"""
entities = await _to_entity_chain(entities) entities = await _to_entity_chain(entities)
async with self.db.get_conn() as conn: async with self.db.get_conn() as conn:
repo = PermRepo(conn) repo = PermRepo(conn)
@ -113,6 +136,22 @@ def register_default_allow_permission(key: str):
def require_permission(perm: str) -> Rule: # pragma: no cover def require_permission(perm: str) -> Rule: # pragma: no cover
"""
`require_permission` 是一个 Nonebot 规则,可以用来要求一个 Nonebot 的指令需
要拥有一定的权限。
```python
from konabot.common.permsys import require_permission
from nonebot import on_command
cmd = on_command("kz", rule=require_permission("kagami.kz"))
@cmd.handle()
async def _():
await cmd.finish("你抓到了普通pt")
```
"""
async def check_permission(event: Event, pm: DepPermManager) -> bool: async def check_permission(event: Event, pm: DepPermManager) -> bool:
return await pm.check_has_permission(event, perm) return await pm.check_has_permission(event, perm)

View File

@ -22,6 +22,11 @@ class PermEntity:
def get_entity_chain_of_entity(entity: PermEntity) -> list[PermEntity]: def get_entity_chain_of_entity(entity: PermEntity) -> list[PermEntity]:
"""
获得一个权限实体的权限串。实际上返回三个权限,从小到大分别是用户、平台全体和
系统全局的权限实体。
"""
return [ return [
PermEntity("sys", "global", "global"), PermEntity("sys", "global", "global"),
PermEntity(entity.platform, "global", "global"), PermEntity(entity.platform, "global", "global"),
@ -30,6 +35,10 @@ def get_entity_chain_of_entity(entity: PermEntity) -> list[PermEntity]:
async def get_entity_chain(event: Event) -> list[PermEntity]: # pragma: no cover async def get_entity_chain(event: Event) -> list[PermEntity]: # pragma: no cover
"""
获得一个 Nonebot Event 的权限实体串。
"""
entities = [PermEntity("sys", "global", "global")] entities = [PermEntity("sys", "global", "global")]
if isinstance(event, OB11Event): if isinstance(event, OB11Event):

View File

@ -1,3 +0,0 @@
# 关于罗文和洛温
AdoreLowen 希望和洛温阿特金森区分,所以最好就不要叫他洛温了!此方 BOT 会在一些群提醒叫错了的人。

View File

@ -1,16 +1,16 @@
# 指令介绍 # 指令介绍
简易 Raymarch 小玩具 简易 Raymarch 小玩具
用法march `<scene>` 用法march `[scene]`
march torus(1.0, 0.2).color(1.0, 0.2, 0.2) torus(1.0, 0.2).rot(90, 0, 0).color(0.2, 0.2, 1.0) camera(4.0).pos(4, 0, 0).lookat(0) march torus(1.0, 0.2).color(1.0, 0.2, 0.2) torus(1.0, 0.2).rot(90, 0, 0).color(0.2, 0.2, 1.0) camera(4.0).pos(4, 0, 0).lookat(0)
# 主要语法 # 主要语法
`<scene>` ::= `<scene>` "." `<op>` |`<obj>` `[scene]` ::= `[scene]` "." `[op]` |`[obj]`
`<obj>` ::= `<obj_ty>` | `<obj_ty>` "(" <args> ")" `[obj]` ::= `[obj_ty]` | `[obj_ty]` "(" [args] ")"
`<op>` ::= `<op_ty>` | `<op_ty>` "(" `<args>` ")" `[op]` ::= `[op_ty]` | `[op_ty]` "(" `[args]` ")"
`<args>` ::= `<args>` "," `<arg>` | `<arg>` `[args]` ::= `[args]` "," `[arg]` | `[arg]`
其中 `obj_ty`、`op_ty` 分别为物体类型(如 `cube`、`sphere`、`torus` 等)与变换类型(如 `pos`、`rot`)。 其中 `obj_ty`、`op_ty` 分别为物体类型(如 `cube`、`sphere`、`torus` 等)与变换类型(如 `pos`、`rot`)。
@ -37,4 +37,4 @@
`rounded`:圆角 `rounded`:圆角
# 特殊说明 # 特殊说明
`<op_ty>` 不包含 scale。非正交的变换会破坏 SDF 的性质。 `[op_ty]` 不包含 scale。非正交的变换会破坏 SDF 的性质。

View File

@ -0,0 +1,8 @@
# 指令介绍
**此方晚安** - 让此方 BOT 禁言你一段时间
## 指令格式
- `@此方BOT 此方晚安`: 禁言几个小时
- `@此方BOT 此方午安`: 禁言几十分钟

View File

@ -0,0 +1,44 @@
import re
from typing import Any
from nonebot import on_message
from nonebot.adapters import Event
from nonebot_plugin_alconna import UniMessage, UniMsg
from playwright.async_api import Page
from konabot.common.nb import match_keyword
from konabot.common.web_render import WebRenderer, konaweb
async def render_image(message: str) -> UniMessage[Any]:
"""
渲染文本为图片
"""
async def page_function(page: Page):
await page.wait_for_function("typeof setContent === 'function'")
await page.evaluate(
"([ message ]) => { return setContent(message); }",
[ message ],
)
img_data = await WebRenderer.render(
url=konaweb("guihuasay"),
target="#main",
other_function=page_function,
)
return UniMessage.image(raw=img_data)
cmd = on_message(
rule=match_keyword.match_keyword(
re.compile(r"^(桂花[说想])\s.+", re.I),
),
)
@cmd.handle()
async def _(event: Event, msg: UniMsg):
text = msg.extract_plain_text().lstrip()
_, content = text.split(maxsplit=1)
msg = await render_image(content)
await msg.send(event)

View File

@ -2,6 +2,7 @@
const float EPS = 0.001; const float EPS = 0.001;
const int MAX_ITER = 128; const int MAX_ITER = 128;
const float INF = 1e10; const float INF = 1e10;
const float PI = 3.14159;
uniform vec2 u_resolution; uniform vec2 u_resolution;
out vec4 fragColor; out vec4 fragColor;
@ -68,17 +69,76 @@ vec3 nrm(vec3 p) {
)); ));
} }
float saturate(float x) {
return clamp(x, 0.0, 1.0);
}
float ggx_distribution(vec3 n, vec3 h, float roughness) {
float alpha = roughness * roughness;
float alpha2 = alpha * alpha;
float NdotH = saturate(dot(n, h));
float denom = NdotH * NdotH * (alpha2 - 1.0) + 1.0;
return alpha2 / max(PI * denom * denom, EPS);
}
float geometry_schlick_ggx(float NdotX, float roughness) {
float r = roughness + 1.0;
float k = r * r / 8.0;
return NdotX / max(NdotX * (1.0 - k) + k, EPS);
}
float geometry_smith(vec3 n, vec3 v, vec3 l, float roughness) {
float NdotV = saturate(dot(n, v));
float NdotL = saturate(dot(n, l));
return geometry_schlick_ggx(NdotV, roughness) * geometry_schlick_ggx(NdotL, roughness);
}
vec3 fresnel_schlick(vec3 f0, float cos_theta) {
return f0 + (1.0 - f0) * pow(1.0 - saturate(cos_theta), 5.0);
}
vec3 tonemap_aces(vec3 c) {
const float a = 2.51;
const float b = 0.03;
const float c1 = 2.43;
const float d = 0.59;
const float e = 0.14;
return clamp((c * (a * c + b)) / (c * (c1 * c + d) + e), 0.0, 1.0);
}
vec4 materialColor(int obj_id) { vec4 materialColor(int obj_id) {
<COLOR_BLOCK> <COLOR_BLOCK>
return vec4(1.0); return vec4(1.0);
} }
vec4 color(vec3 p, int obj_id) { vec4 color(vec3 p, vec3 r, int obj_id) {
vec3 normal = nrm(p); vec3 light_col = vec3(1.0);
vec3 light_dir = normalize(vec3(0.5, 0.8, -0.6)); vec4 albedo = materialColor(obj_id);
float light = 0.2 + 0.8 * max(dot(normal, light_dir), 0.0); vec3 N = nrm(p);
vec4 base = materialColor(obj_id); vec3 V = normalize(-r);
return vec4(base.rgb * light, base.a); vec3 L = normalize(vec3(0.5, 0.8, -0.6));
vec3 H = normalize(V + L);
float roughness = 0.45;
float metallic = 0.02;
float NdotL = saturate(dot(N, L));
float NdotV = saturate(dot(N, V));
float D = ggx_distribution(N, H, roughness);
float G = geometry_smith(N, V, L, roughness);
vec3 F0 = mix(vec3(0.04), albedo.rgb, metallic);
vec3 F = fresnel_schlick(F0, dot(V, H));
vec3 kD = (1.0 - F) * (1.0 - metallic);
vec3 diffuse = kD * albedo.rgb / PI;
vec3 specular = D * G * F / max(4.0 * NdotL * NdotV, EPS);
float hemi = N.y * 0.5 + 0.5;
vec3 sky_ambient = vec3(0.60, 0.72, 0.92);
vec3 ground_ambient = vec3(0.18, 0.16, 0.14);
vec3 ambient = mix(ground_ambient, sky_ambient, hemi) * (diffuse + 0.25 * F0) * 0.35;
vec3 col = ambient + (diffuse + specular) * light_col * NdotL;
col = tonemap_aces(col);
col = pow(col, vec3(1.0 / 2.2));
return vec4(col, 1.0);
} }
vec4 march(vec3 p, vec3 r) { vec4 march(vec3 p, vec3 r) {
@ -87,7 +147,7 @@ vec4 march(vec3 p, vec3 r) {
for(int i = 0; i < MAX_ITER; ++i) { for(int i = 0; i < MAX_ITER; ++i) {
qry = sd(p); qry = sd(p);
if(qry.value < EPS){ if(qry.value < EPS){
col = color(p, qry.obj_id); col = color(p, r, qry.obj_id);
break; break;
} }
p += qry.value * r; p += qry.value * r;

View File

@ -1,6 +1,8 @@
from io import BytesIO from io import BytesIO
from typing import Iterable, cast from typing import Iterable, cast
import PIL.Image
from loguru import logger from loguru import logger
from nonebot import on_message from nonebot import on_message
from nonebot_plugin_alconna import ( from nonebot_plugin_alconna import (
@ -18,7 +20,7 @@ from nonebot_plugin_alconna import (
from playwright.async_api import ConsoleMessage, Page from playwright.async_api import ConsoleMessage, Page
from konabot.common.nb.match_keyword import match_keyword from konabot.common.nb.match_keyword import match_keyword
from konabot.common.nb.extract_image import DepPILImage from konabot.common.nb.extract_image import DepImageBytesOrNone, DepPILImage
from konabot.common.web_render import konaweb from konabot.common.web_render import konaweb
from konabot.common.web_render.core import WebRenderer from konabot.common.web_render.core import WebRenderer
from konabot.common.web_render.host_images import host_tempdir from konabot.common.web_render.host_images import host_tempdir
@ -35,6 +37,7 @@ from konabot.plugins.memepack.drawing.saying import (
draw_pt, draw_pt,
draw_suan, draw_suan,
draw_vr, draw_vr,
draw_xm
) )
from konabot.plugins.memepack.drawing.watermark import draw_doubao_watermark from konabot.plugins.memepack.drawing.watermark import draw_doubao_watermark
@ -361,3 +364,33 @@ async def _(saying: list[str]):
await vrsay.send(await UniMessage().image(raw=img_bytes).export()) await vrsay.send(await UniMessage().image(raw=img_bytes).export())
xmsay = on_alconna(
Alconna(
"小睦说",
Args[
"saying",
MultiVar(str, "*"),
Field(missing_tips=lambda: "你没有写小睦说了什么"),
],
Args["image?", Image | None],
),
use_cmd_start=True,
use_cmd_sep=False,
skip_for_unmatch=False,
aliases={"小睦想"},
)
@xmsay.handle()
async def _(saying: list[str], image: DepImageBytesOrNone):
if image is not None:
img = PIL.Image.open(BytesIO(image))
else:
img = None
img = await draw_xm("\n".join(saying), img)
img_bytes = BytesIO()
img.save(img_bytes, format="PNG")
await xmsay.send(await UniMessage().image(raw=img_bytes).export())

View File

@ -7,23 +7,41 @@ import PIL.Image
from konabot.common.path import ASSETS_PATH from konabot.common.path import ASSETS_PATH
from konabot.common.utils.to_async import make_async from konabot.common.utils.to_async import make_async
from .base.fonts import HARMONYOS_SANS_SC_BLACK, HARMONYOS_SANS_SC_REGULAR, LXGWWENKAI_REGULAR from .base.fonts import (
HARMONYOS_SANS_SC_BLACK,
HARMONYOS_SANS_SC_REGULAR,
LXGWWENKAI_REGULAR,
)
geimao_image = PIL.Image.open(ASSETS_PATH / "img" / "meme" / "geimao.jpg").convert("RGBA") geimao_image = PIL.Image.open(ASSETS_PATH / "img" / "meme" / "geimao.jpg").convert(
"RGBA"
)
pt_image = PIL.Image.open(ASSETS_PATH / "img" / "meme" / "ptsay.png").convert("RGBA") pt_image = PIL.Image.open(ASSETS_PATH / "img" / "meme" / "ptsay.png").convert("RGBA")
mnk_image = PIL.Image.open(ASSETS_PATH / "img" / "meme" / "mnksay.jpg").convert("RGBA") mnk_image = PIL.Image.open(ASSETS_PATH / "img" / "meme" / "mnksay.jpg").convert("RGBA")
dasuan_image = PIL.Image.open(ASSETS_PATH / "img" / "meme" / "dss.png").convert("RGBA") dasuan_image = PIL.Image.open(ASSETS_PATH / "img" / "meme" / "dss.png").convert("RGBA")
suan_image = PIL.Image.open(ASSETS_PATH / "img" / "meme" / "suanleba.png").convert("RGBA") suan_image = PIL.Image.open(ASSETS_PATH / "img" / "meme" / "suanleba.png").convert(
cute_ten_image = PIL.Image.open(ASSETS_PATH / "img" / "meme" / "tententen.png").convert("RGBA") "RGBA"
)
cute_ten_image = PIL.Image.open(ASSETS_PATH / "img" / "meme" / "tententen.png").convert(
"RGBA"
)
kio_image = PIL.Image.open(ASSETS_PATH / "img" / "meme" / "kiosay.jpg").convert("RGBA") kio_image = PIL.Image.open(ASSETS_PATH / "img" / "meme" / "kiosay.jpg").convert("RGBA")
vr_image = PIL.Image.open(ASSETS_PATH / 'img' / 'meme' / 'vr.jpg').convert("RGBA") vr_image = PIL.Image.open(ASSETS_PATH / "img" / "meme" / "vr.jpg").convert("RGBA")
xm_image = PIL.Image.open(ASSETS_PATH / "img" / "meme" / "xiaomu.png").convert("RGBA")
def _draw_geimao(saying: str): def _draw_geimao(saying: str):
img = geimao_image.copy() img = geimao_image.copy()
with imagetext_py.Writer(img) as iw: with imagetext_py.Writer(img) as iw:
iw.draw_text_wrapped( iw.draw_text_wrapped(
saying, 960, 50, 0.5, 0, 1920, 240, HARMONYOS_SANS_SC_BLACK, saying,
960,
50,
0.5,
0,
1920,
240,
HARMONYOS_SANS_SC_BLACK,
imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")), imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")),
0.8, 0.8,
imagetext_py.TextAlign.Center, imagetext_py.TextAlign.Center,
@ -42,7 +60,14 @@ def _draw_pt(saying: str):
img = pt_image.copy() img = pt_image.copy()
with imagetext_py.Writer(img) as iw: with imagetext_py.Writer(img) as iw:
iw.draw_text_wrapped( iw.draw_text_wrapped(
saying, 259, 278, 0.5, 0.5, 360, 48, HARMONYOS_SANS_SC_REGULAR, saying,
259,
278,
0.5,
0.5,
360,
48,
HARMONYOS_SANS_SC_REGULAR,
imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")), imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")),
1.0, 1.0,
imagetext_py.TextAlign.Center, imagetext_py.TextAlign.Center,
@ -59,7 +84,14 @@ def _draw_mnk(saying: str):
img = mnk_image.copy() img = mnk_image.copy()
with imagetext_py.Writer(img) as iw: with imagetext_py.Writer(img) as iw:
iw.draw_text_wrapped( iw.draw_text_wrapped(
saying, 540, 25, 0.5, 0, 1080, 120, HARMONYOS_SANS_SC_BLACK, saying,
540,
25,
0.5,
0,
1080,
120,
HARMONYOS_SANS_SC_BLACK,
imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")), imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")),
0.8, 0.8,
imagetext_py.TextAlign.Center, imagetext_py.TextAlign.Center,
@ -81,7 +113,14 @@ def _draw_suan(saying: str, dasuan: bool = False):
img = suan_image.copy() img = suan_image.copy()
with imagetext_py.Writer(img) as iw: with imagetext_py.Writer(img) as iw:
iw.draw_text_wrapped( iw.draw_text_wrapped(
saying, 1020, 290, 0.5, 0.5, 400, 48, LXGWWENKAI_REGULAR, saying,
1020,
290,
0.5,
0.5,
400,
48,
LXGWWENKAI_REGULAR,
imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")), imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")),
1.0, 1.0,
imagetext_py.TextAlign.Center, imagetext_py.TextAlign.Center,
@ -98,7 +137,14 @@ def _draw_cute_ten(saying: str):
img = cute_ten_image.copy() img = cute_ten_image.copy()
with imagetext_py.Writer(img) as iw: with imagetext_py.Writer(img) as iw:
iw.draw_text_wrapped( iw.draw_text_wrapped(
saying, 390, 479, 0.5, 0.5, 760, 96, LXGWWENKAI_REGULAR, saying,
390,
479,
0.5,
0.5,
760,
96,
LXGWWENKAI_REGULAR,
imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")), imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")),
1.0, 1.0,
imagetext_py.TextAlign.Center, imagetext_py.TextAlign.Center,
@ -116,7 +162,14 @@ def draw_kiosay(saying: str):
img = kio_image.copy() img = kio_image.copy()
with imagetext_py.Writer(img) as iw: with imagetext_py.Writer(img) as iw:
iw.draw_text_wrapped( iw.draw_text_wrapped(
saying, 450, 540, 0.5, 0.5, 900, 96, LXGWWENKAI_REGULAR, saying,
450,
540,
0.5,
0.5,
900,
96,
LXGWWENKAI_REGULAR,
imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")), imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")),
1.0, 1.0,
imagetext_py.TextAlign.Center, imagetext_py.TextAlign.Center,
@ -131,12 +184,19 @@ def draw_vr(saying: str):
w, h = img.size w, h = img.size
hw = 300 hw = 300
img2 = PIL.Image.new("RGBA", (w, h + hw), 'white') img2 = PIL.Image.new("RGBA", (w, h + hw), "white")
img2.paste(img, (0, hw)) img2.paste(img, (0, hw))
with imagetext_py.Writer(img2) as iw: with imagetext_py.Writer(img2) as iw:
iw.draw_text_wrapped( iw.draw_text_wrapped(
saying, w // 2, hw // 2 + 15, 0.5, 0.5, w, 64, LXGWWENKAI_REGULAR, saying,
w // 2,
hw // 2 + 15,
0.5,
0.5,
w,
64,
LXGWWENKAI_REGULAR,
imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")), imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")),
1.0, 1.0,
imagetext_py.TextAlign.Center, imagetext_py.TextAlign.Center,
@ -145,3 +205,36 @@ def draw_vr(saying: str):
return img2 return img2
@make_async
def draw_xm(saying: str, image: PIL.Image.Image | None = None):
img_base = PIL.Image.new("RGBA", xm_image.size, (255, 255, 255, 255))
with imagetext_py.Writer(img_base) as iw:
iw.draw_text_wrapped(
saying,
442,
200,
0.5,
0.5,
884,
64,
LXGWWENKAI_REGULAR,
imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")),
1.0,
imagetext_py.TextAlign.Center,
draw_emojis=True,
)
if image is not None:
image_r = image.copy().convert("RGBA")
width, height = image_r.size
base_width = img_base.size[0]
height = int(height / width * base_width)
image_r = image_r.resize((base_width, height))
# try to align center
y = 215 - image_r.height // 2
img_base.paste(image_r, (0, y), mask=image_r)
img_base.paste(xm_image, (0, 0), mask=xm_image)
return img_base

View File

@ -1,44 +0,0 @@
import nonebot
from nonebot.adapters.onebot.v11.bot import Bot
from nonebot.adapters.onebot.v11.event import GroupMessageEvent
from nonebot_plugin_alconna import UniMsg, UniMessage
from pydantic import BaseModel
class NoLuowenConfig(BaseModel):
plugin_noluowen_qqid: int = -1
plugin_noluowen_enable_group: list[int] = []
config = nonebot.get_plugin_config(NoLuowenConfig)
async def is_luowen_mentioned(evt: GroupMessageEvent, msg: UniMsg) -> bool:
if config.plugin_noluowen_qqid <= 0:
return False
if evt.user_id == config.plugin_noluowen_qqid:
return False
if evt.group_id not in config.plugin_noluowen_enable_group:
return False
txt = msg.extract_plain_text()
if "洛温" not in txt:
return False
if "罗文" in txt:
return False
if "阿特金森" in txt:
return False
return True
evt_luowen_mentioned = nonebot.on_message(rule=is_luowen_mentioned)
@evt_luowen_mentioned.handle()
async def _(evt: GroupMessageEvent, bot: Bot):
msg = (
UniMessage()
.reply(str(evt.message_id))
.at(str(config.plugin_noluowen_qqid))
.text(" 好像有人念错了你的 ID")
)
await evt_luowen_mentioned.send(await msg.export(bot=bot))

View File

@ -0,0 +1,64 @@
import random
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent
from nonebot.rule import to_me
from nonebot_plugin_alconna import UniMessage
from konabot.common.permsys import require_permission
async def make_sleep(event: GroupMessageEvent, bot: Bot, duration: int):
"""
让人睡着
"""
await bot.set_group_ban(
group_id=event.group_id,
user_id=event.user_id,
duration=duration,
)
seconds = duration % 60
minutes = (duration // 60) % 60
hours = duration // 3600
t1 = f"{hours} 小时 {minutes} 分钟 {seconds}"
message = f" 好好睡吧!奖励你 {t1}的睡眠💤"
message = UniMessage.at(str(event.user_id)).text(message)
await message.send(target=event, bot=bot)
cmd_sleep_night = on_command(
"此方晚安",
rule=require_permission("oyasumi") & to_me(),
aliases={"晚安"},
)
@cmd_sleep_night.handle()
async def oyasumi(event: GroupMessageEvent, bot: Bot):
"""
限定只能用 GroupMessageEvent因为它只能在 QQ 群中使用
"""
# 考虑到有人是熬夜很久,所以这里就给一个 3 到 5 小时睡眠的随机数。这个时间内
# 要睡不着我觉得是个小概率事件了!
duration = random.randint(3 * 3600, 5 * 3600)
await make_sleep(event, bot, duration)
await cmd_sleep_night.finish()
cmd_sleep_noon = on_command(
"此方午安",
rule=require_permission("oyasumi") & to_me(),
aliases={"午安"},
)
@cmd_sleep_noon.handle()
async def sleep_noon(event: GroupMessageEvent, bot: Bot):
duration = random.randint(60 * 15, 60 * 30)
await make_sleep(event, bot, duration)
await cmd_sleep_night.finish()

1431
poetry.lock generated

File diff suppressed because it is too large Load Diff