Files
chat_rebot-connect-with-one…/scripts/qq_friend_action.py
Claw 4068869217 feat(plugin): 集成 OpenClaw Bridge + QQ 操作技能套件
新增 openclaw_bridge 插件,实现 QQ ↔ OpenClaw Gateway 桥接:

src/process.py:
  - QQ 消息自动转发 OpenClaw Gateway
  - 内置安全检测(高危词、管理员白名单、MC指令过滤)
  - 高危词库外部化到 config.toml [security] section
  - 群昵称自动解析
  - Session 隔离(按群×用户)

config/openclawbridge/config.toml:
  - 插件配置模板(已脱敏:占位符替代个人信息)

scripts/qq_*.py (×15):
  - 消息发送/文件传输/群管理/好友管理
  - 信息查询/历史回溯/OCR/点赞
  - 全部脱敏(QQ号→YOUR_ADMIN_QQ, IP→YOUR_NAPCAT_HOST等)

skills/*/SKILL.md (×8):
  - AgentSkills 使用指导
  - qq-messenger / qq-management / qq-resolver / qq-napcat-extras
  - browser / file-process / mc-query / nix-helper

SKILL.md:
  - AgentSkill 入口,完整架构说明和部署步骤
2026-05-04 16:28:12 +08:00

207 lines
7.3 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
QQ 好友管理动作 — 通过 NapCat (OneBot) HTTP API
支持操作:
- 删除好友(delete friend)
- 拉黑用户(delete friend + 从所有群踢出+禁止加群)
- 同意好友请求(approve friend request)
- 拒绝好友请求(reject friend request)
- 列出好友列表
权限规则:
- 删除好友、拉黑:只有 boss(YOUR_ADMIN_QQ)批准后才能执行
- 例外:检测到攻击性信息时,**自动删除+拉黑一条龙**,无需等待批准
- 同意/拒绝好友请求:必须问 boss
用法:
python3 qq_friend_action.py --delete 12345678 # 删除好友
python3 qq_friend_action.py --block 12345678 # 拉黑用户(删好友+从所有群踢出)
python3 qq_friend_action.py --block 12345678 --gid YOUR_GROUP_ID # 从指定群踢出+拒绝加群
python3 qq_friend_action.py --approve-friend <flag> # 同意好友请求
python3 qq_friend_action.py --reject-friend <flag> # 拒绝好友请求
python3 qq_friend_action.py --list-friends # 列出好友
"""
import json
import sys
import argparse
import requests
CQHTTP_URL = "http://YOUR_NAP CAT_HOST:25570"
def delete_friend(user_id: int) -> dict:
"""删除好友"""
resp = requests.post(f"{CQHTTP_URL}/delete_friend",
json={"user_id": user_id}, timeout=10)
return resp.json()
def get_group_list():
"""获取群列表(用于踢出)"""
resp = requests.post(f"{CQHTTP_URL}/get_group_list", json={}, timeout=10)
data = resp.json()
if data.get("status") == "ok":
return data.get("data", [])
return []
def set_group_kick(group_id: int, user_id: int) -> dict:
"""从群踢出用户并拒绝加群"""
# 注意:NapCat 可能需要 uid 格式,try-except 兜底
resp = requests.post(f"{CQHTTP_URL}/set_group_kick", json={
"group_id": group_id,
"user_id": user_id,
"reject_add_request": True
}, timeout=10)
return resp.json()
def set_group_ban(group_id: int, user_id: int, duration: int = 2592000) -> dict:
"""禁言用户(30天)"""
resp = requests.post(f"{CQHTTP_URL}/set_group_ban", json={
"group_id": group_id,
"user_id": user_id,
"duration": duration
}, timeout=10)
return resp.json()
def handle_friend_request(flag: str, approve: bool, remark: str = "") -> dict:
"""处理好友请求"""
params = {
"flag": flag,
"approve": approve,
}
if approve and remark:
params["remark"] = remark
resp = requests.post(f"{CQHTTP_URL}/set_friend_add_request",
json=params, timeout=10)
return resp.json()
def get_friend_list():
"""获取好友列表"""
resp = requests.post(f"{CQHTTP_URL}/get_friend_list", json={}, timeout=10)
data = resp.json()
if data.get("status") == "ok":
return data.get("data", [])
return []
def format_friends(friends: list) -> str:
if not friends:
return "暂无好友数据"
lines = [f"共 {len(friends)} 个好友\n"]
for f in friends:
uid = f.get("user_id", "?")
nickname = f.get("nickname", "?")
remark = f.get("remark", "")
remark_str = f"(备注:{remark})" if remark else ""
lines.append(f"• {nickname} ({uid}){remark_str}")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="QQ 好友管理操作")
parser.add_argument("--delete", type=int, metavar="QQ号", help="删除好友")
parser.add_argument("--block", type=int, metavar="QQ号", help="拉黑用户(删好友+踢出所有群)")
parser.add_argument("--gid", type=int, help="仅从指定群踢出(配合 --block)")
parser.add_argument("--approve-friend", type=str, help="同意好友请求(输入 flag)")
parser.add_argument("--reject-friend", type=str, help="拒绝好友请求(输入 flag)")
parser.add_argument("--remark", type=str, default="", help="好友备注(可选,仅同意时生效)")
parser.add_argument("--list-friends", action="store_true", help="列出好友列表")
parser.add_argument("--json", action="store_true", help="JSON 格式输出")
args = parser.parse_args()
try:
if args.list_friends:
friends = get_friend_list()
if args.json:
print(json.dumps(friends, ensure_ascii=False, indent=2))
else:
print(format_friends(friends))
return
if args.delete:
user_id = args.delete
result = delete_friend(user_id)
if result.get("status") == "ok":
print(f"✅ 已删除好友 {user_id}")
else:
print(f"❌ 删除好友失败: {result.get('message', '未知错误')}")
sys.exit(1)
return
if args.block:
user_id = args.block
results = []
# 1. 删除好友
r1 = delete_friend(user_id)
deleted = r1.get("status") == "ok"
if deleted:
results.append(f"✅ 已删除好友 {user_id}")
else:
results.append(f"❌ 删除好友失败: {r1.get('message', '未知错误')}")
# 2. 从群踢出
if args.gid:
groups = [{"group_id": args.gid, "group_name": ""}]
else:
groups = get_group_list()
kicked_groups = []
for g in groups:
gid = g.get("group_id")
if not gid:
continue
try:
r_kick = set_group_kick(gid, user_id)
if r_kick.get("status") == "ok":
gname = g.get("group_name", str(gid))
kicked_groups.append(gname)
except Exception:
pass
if kicked_groups:
results.append(f"✅ 已从 {len(kicked_groups)} 个群踢出:{', '.join(kicked_groups[:3])}")
else:
results.append("ℹ️ 未执行踢出操作(可能已不是好友/不在群中)")
print("\n".join(results))
return
if args.approve_friend:
result = handle_friend_request(args.approve_friend, approve=True,
remark=args.remark)
if result.get("status") == "ok":
print(f"✅ 已同意好友请求 {args.approve_friend}")
else:
print(f"❌ 同意失败: {result.get('message', '未知错误')}")
sys.exit(1)
return
if args.reject_friend:
result = handle_friend_request(args.reject_friend, approve=False)
if result.get("status") == "ok":
print(f"✅ 已拒绝好友请求 {args.reject_friend}")
else:
print(f"❌ 拒绝失败: {result.get('message', '未知错误')}")
sys.exit(1)
return
parser.print_help()
except requests.exceptions.ConnectionError:
print(f"❌ 连接失败: 无法连接到 NapCat ({CQHTTP_URL})")
sys.exit(1)
except Exception as e:
print(f"❌ 操作失败: {e}")
sys.exit(1)
if __name__ == "__main__":
main()