feat(plugins,models): 加了今日老婆插件还有群成员信息字段
Some checks are pending
Auto Deploy NeoBot (FRP + SSH 密码登录) / deploy-to-server (push) Waiting to run
Some checks are pending
Auto Deploy NeoBot (FRP + SSH 密码登录) / deploy-to-server (push) Waiting to run
1. 新增daily_wife插件,群里每天随机配对群友 2. 给GroupMemberInfo加了QQ等级和是否机器人的字段 3. 改了群成员API的缓存和字段过滤逻辑 4. 更新了反馈数据和更新日志页面
This commit is contained in:
2
main.py
2
main.py
@@ -15,7 +15,7 @@ ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|||||||
SRC_DIR = os.path.join(ROOT_DIR, "src")
|
SRC_DIR = os.path.join(ROOT_DIR, "src")
|
||||||
sys.path.insert(0, SRC_DIR)
|
sys.path.insert(0, SRC_DIR)
|
||||||
|
|
||||||
# 初始化日志系统,必须在其他 neobot 模块导入之前执行
|
# 初始化日志系统,必须在其他 neobot 模块导入之前执行,改了我就操死你
|
||||||
from neobot.core.utils.logger import logger
|
from neobot.core.utils.logger import logger
|
||||||
|
|
||||||
# 核心模块导入
|
# 核心模块导入
|
||||||
|
|||||||
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
@@ -217,17 +217,6 @@ class GroupAPI(BaseAPI):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
async def get_group_member_info(self, group_id: int, user_id: int, no_cache: bool = False) -> GroupMemberInfo:
|
async def get_group_member_info(self, group_id: int, user_id: int, no_cache: bool = False) -> GroupMemberInfo:
|
||||||
"""
|
|
||||||
获取指定群组成员的详细信息。
|
|
||||||
|
|
||||||
Args:
|
|
||||||
group_id (int): 目标群组的群号。
|
|
||||||
user_id (int): 目标成员的 QQ 号。
|
|
||||||
no_cache (bool, optional): 是否不使用缓存。Defaults to False.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
GroupMemberInfo: 包含群成员信息的 `GroupMemberInfo` 数据对象。
|
|
||||||
"""
|
|
||||||
cache_key = f"neobot:cache:get_group_member_info:{group_id}:{user_id}"
|
cache_key = f"neobot:cache:get_group_member_info:{group_id}:{user_id}"
|
||||||
if not no_cache:
|
if not no_cache:
|
||||||
cached_data = await redis_manager.redis.get(cache_key)
|
cached_data = await redis_manager.redis.get(cache_key)
|
||||||
@@ -235,21 +224,14 @@ class GroupAPI(BaseAPI):
|
|||||||
return GroupMemberInfo(**orjson.loads(cached_data))
|
return GroupMemberInfo(**orjson.loads(cached_data))
|
||||||
|
|
||||||
res = await self.call_api("get_group_member_info", {"group_id": group_id, "user_id": user_id})
|
res = await self.call_api("get_group_member_info", {"group_id": group_id, "user_id": user_id})
|
||||||
await redis_manager.redis.set(cache_key, orjson.dumps(res), ex=3600) # 缓存 1 小时
|
await redis_manager.redis.set(cache_key, orjson.dumps(res), ex=3600)
|
||||||
return GroupMemberInfo(**res)
|
valid_fields = GroupMemberInfo.__dataclass_fields__
|
||||||
|
return GroupMemberInfo(**{k: v for k, v in res.items() if k in valid_fields})
|
||||||
|
|
||||||
async def get_group_member_list(self, group_id: int) -> List[GroupMemberInfo]:
|
async def get_group_member_list(self, group_id: int) -> List[GroupMemberInfo]:
|
||||||
"""
|
|
||||||
获取一个群组的所有成员列表。
|
|
||||||
|
|
||||||
Args:
|
|
||||||
group_id (int): 目标群组的群号。
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
List[GroupMemberInfo]: 包含所有群成员信息的 `GroupMemberInfo` 对象列表。
|
|
||||||
"""
|
|
||||||
res = await self.call_api("get_group_member_list", {"group_id": group_id})
|
res = await self.call_api("get_group_member_list", {"group_id": group_id})
|
||||||
return [GroupMemberInfo(**item) for item in res]
|
valid_fields = GroupMemberInfo.__dataclass_fields__
|
||||||
|
return [GroupMemberInfo(**{k: v for k, v in item.items() if k in valid_fields}) for item in res]
|
||||||
|
|
||||||
async def get_group_honor_info(self, group_id: int, type: str) -> GroupHonorInfo:
|
async def get_group_honor_info(self, group_id: int, type: str) -> GroupHonorInfo:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -52,5 +52,23 @@
|
|||||||
"time": 1778727344,
|
"time": 1778727344,
|
||||||
"time_str": "2026-05-14 10:55:44",
|
"time_str": "2026-05-14 10:55:44",
|
||||||
"done": false
|
"done": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"user_id": 3678069648,
|
||||||
|
"nickname": "awedwd",
|
||||||
|
"content": "添加一个v我50自动打50块钱进我银行卡功能",
|
||||||
|
"time": 1778815461,
|
||||||
|
"time_str": "2026-05-15 11:24:21",
|
||||||
|
"done": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 8,
|
||||||
|
"user_id": 2771135787,
|
||||||
|
"nickname": "数无形时少直觉,形少数时",
|
||||||
|
"content": "<玩原神>",
|
||||||
|
"time": 1778816520,
|
||||||
|
"time_str": "2026-05-15 11:42:00",
|
||||||
|
"done": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -81,6 +81,12 @@ class GroupMemberInfo:
|
|||||||
card_changeable: bool = False
|
card_changeable: bool = False
|
||||||
"""是否允许修改群名片"""
|
"""是否允许修改群名片"""
|
||||||
|
|
||||||
|
qq_level: str = ""
|
||||||
|
"""QQ 等级"""
|
||||||
|
|
||||||
|
is_robot: bool = False
|
||||||
|
"""是否为机器人"""
|
||||||
|
|
||||||
|
|
||||||
@dataclass(slots=True)
|
@dataclass(slots=True)
|
||||||
class FriendInfo:
|
class FriendInfo:
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ VERIFIED_PLUGINS = (
|
|||||||
"bot_status",
|
"bot_status",
|
||||||
"broadcast",
|
"broadcast",
|
||||||
"code_py",
|
"code_py",
|
||||||
|
"daily_wife",
|
||||||
"echo",
|
"echo",
|
||||||
"feedback",
|
"feedback",
|
||||||
"furry",
|
"furry",
|
||||||
|
|||||||
89
src/neobot/plugins/daily_wife.py
Normal file
89
src/neobot/plugins/daily_wife.py
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import json
|
||||||
|
import random
|
||||||
|
from datetime import datetime, timezone, timedelta
|
||||||
|
from neobot.core.managers.command_manager import matcher
|
||||||
|
from neobot.models.events.message import GroupMessageEvent
|
||||||
|
from neobot.core.managers.redis_manager import redis_manager
|
||||||
|
from neobot.models.message import MessageSegment
|
||||||
|
|
||||||
|
CST = timezone(timedelta(hours=8))
|
||||||
|
|
||||||
|
__plugin_meta__ = {
|
||||||
|
"name": "今日老婆",
|
||||||
|
"description": "每天随机和群友凑成一对夫妻",
|
||||||
|
"usage": "/wife 或 /今日老婆 - 看看今天的老婆是谁",
|
||||||
|
}
|
||||||
|
|
||||||
|
_REDIS_KEY = "neobot:daily_wife:{}" # format with group_id
|
||||||
|
|
||||||
|
def _today_str() -> str:
|
||||||
|
return datetime.now(CST).strftime("%Y-%m-%d")
|
||||||
|
|
||||||
|
def _ttl_until_midnight() -> int:
|
||||||
|
now = datetime.now(CST)
|
||||||
|
midnight = (now + timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
return int((midnight - now).total_seconds())
|
||||||
|
|
||||||
|
@matcher.command("wife", "今日老婆")
|
||||||
|
async def handle_wife(event: GroupMessageEvent, args: list[str]):
|
||||||
|
if not isinstance(event, GroupMessageEvent):
|
||||||
|
await event.reply("这个指令只能在群聊里用嗷")
|
||||||
|
return
|
||||||
|
|
||||||
|
group_id = str(event.group_id)
|
||||||
|
user_id = str(event.user_id)
|
||||||
|
today = _today_str()
|
||||||
|
redis_key = _REDIS_KEY.format(group_id)
|
||||||
|
|
||||||
|
pairs = await redis_manager.redis.hgetall(redis_key)
|
||||||
|
stored_date = pairs.pop("_date", None)
|
||||||
|
|
||||||
|
if stored_date != today:
|
||||||
|
await redis_manager.redis.delete(redis_key)
|
||||||
|
pairs = {}
|
||||||
|
|
||||||
|
if user_id in pairs:
|
||||||
|
partner = json.loads(pairs[user_id])
|
||||||
|
partner_nick = partner.get("nickname", str(partner["user_id"]))
|
||||||
|
partner_id = partner["user_id"]
|
||||||
|
avatar_url = f"https://q1.qlogo.cn/g?b=qq&nk={partner_id}&s=640"
|
||||||
|
await event.reply([
|
||||||
|
MessageSegment.text(f"你今天的另一半已经有啦,是 {partner_nick}({partner_id})~\n"),
|
||||||
|
MessageSegment.image(avatar_url),
|
||||||
|
])
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
members = await event.bot.get_group_member_list(event.group_id)
|
||||||
|
except Exception as e:
|
||||||
|
await event.reply(f"获取群成员列表失败了: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
paired_ids = set(user_id)
|
||||||
|
for v in pairs.values():
|
||||||
|
paired_ids.add(str(json.loads(v)["user_id"]))
|
||||||
|
|
||||||
|
other_members = [m for m in members if str(m.user_id) not in paired_ids]
|
||||||
|
if not other_members:
|
||||||
|
await event.reply("群里没有其他可以配对的群友了……")
|
||||||
|
return
|
||||||
|
|
||||||
|
chosen = random.choice(other_members)
|
||||||
|
chosen_nick = chosen.card or chosen.nickname
|
||||||
|
my_nick = event.sender.nickname if event.sender else user_id
|
||||||
|
|
||||||
|
pairs[user_id] = json.dumps({"user_id": chosen.user_id, "nickname": chosen_nick})
|
||||||
|
pairs[str(chosen.user_id)] = json.dumps({"user_id": event.user_id, "nickname": my_nick})
|
||||||
|
pairs["_date"] = today
|
||||||
|
|
||||||
|
ttl = _ttl_until_midnight()
|
||||||
|
await redis_manager.redis.hset(redis_key, mapping=pairs)
|
||||||
|
await redis_manager.redis.expire(redis_key, ttl)
|
||||||
|
|
||||||
|
avatar_url = f"https://q1.qlogo.cn/g?b=qq&nk={chosen.user_id}&s=640"
|
||||||
|
|
||||||
|
await event.reply([
|
||||||
|
MessageSegment.text(f"今日老婆分配结果:\n你是 {my_nick}\n你今天的另一半是 {chosen_nick}({chosen.user_id})\n"),
|
||||||
|
MessageSegment.image(avatar_url),
|
||||||
|
MessageSegment.text(f"\n有效期至今天午夜,好好相处吧~"),
|
||||||
|
])
|
||||||
@@ -147,6 +147,11 @@
|
|||||||
<span class="text-base text-gray-300 leading-relaxed group-hover/item:text-white transition-colors"><span class="font-mono text-xs text-gray-500">plugins/feedback.py</span> 功能反馈插件,/feedback 提交建议,管理员能查看管理</span>
|
<span class="text-base text-gray-300 leading-relaxed group-hover/item:text-white transition-colors"><span class="font-mono text-xs text-gray-500">plugins/feedback.py</span> 功能反馈插件,/feedback 提交建议,管理员能查看管理</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li class="flex items-start gap-4 group/item">
|
||||||
|
<span class="flex-shrink-0 mt-1 px-2 py-1 rounded text-[10px] font-mono font-bold bg-green-500/10 text-green-400 border border-green-500/20 group-hover/item:bg-green-500/20 transition-colors">ADD</span>
|
||||||
|
<span class="text-base text-gray-300 leading-relaxed group-hover/item:text-white transition-colors"><span class="font-mono text-xs text-gray-500">plugins/daily_wife.py</span> /wife 今日老婆,每天和群友随机凑对</span>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="flex items-start gap-4 group/item">
|
<li class="flex items-start gap-4 group/item">
|
||||||
<span class="flex-shrink-0 mt-1 px-2 py-1 rounded text-[10px] font-mono font-bold bg-red-500/10 text-red-400 border border-red-500/20 group-hover/item:bg-red-500/20 transition-colors">FIX</span>
|
<span class="flex-shrink-0 mt-1 px-2 py-1 rounded text-[10px] font-mono font-bold bg-red-500/10 text-red-400 border border-red-500/20 group-hover/item:bg-red-500/20 transition-colors">FIX</span>
|
||||||
<span class="text-base text-gray-300 leading-relaxed group-hover/item:text-white transition-colors"><span class="font-mono text-xs text-gray-500">config_models.py</span> reverse_ws 没配 default_factory,用户不写 [reverse_ws] 直接启动就炸</span>
|
<span class="text-base text-gray-300 leading-relaxed group-hover/item:text-white transition-colors"><span class="font-mono text-xs text-gray-500">config_models.py</span> reverse_ws 没配 default_factory,用户不写 [reverse_ws] 直接启动就炸</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user