SnowCat 雪猫底层全源码:NapCat 4.18.28 底座 + SnowLuma 能力移植 + V8 通道适配 9.9.37
26 包 monorepo(TS 全源码): - snowcat-core: NT 内核 API 封装 + listener(含 9.9.37 六回调适配)+ Packet 发包 - snowcat-onebot: OneBot v11 全动作 + MCP Streamable HTTP 适配器 + 稳定线 - snowcat-webui-frontend/backend: 雪猫控制台(React+HeroUI) - snowcat-shell: 单文件 bundle 出口(vite inlineDynamicImports) - snowcat-native: napi2native / MoeHoo / ffmpeg / pty 运行时 - 56 项 SnowLuma 独门动作移植(qzone 全家桶/群相册/装扮/闪照/收藏) - 工具件: 解包器/启动器/便携制作器/doctor GitHub 关联已全量指向 DandanLLab/SnowCatQQ
This commit is contained in:
commit
b9655a5ab1
1048 files changed
+130851
No files matched your search
@@ -0,0 +1,58 @@
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { MessageUnique } from 'snowcat-common/src/message-unique';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
message_id: Type.Optional(Type.Union([Type.Number(), Type.String()], { description: '消息ID' })),
|
||||
msg_seq: Type.Optional(Type.String({ description: '消息序号' })),
|
||||
msg_random: Type.Optional(Type.String({ description: '消息随机数' })),
|
||||
group_id: Type.Optional(Type.String({ description: '群号' })),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Any({ description: '操作结果' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export default class DelEssenceMsg extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.DelEssenceMsg;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '移出精华消息';
|
||||
override actionDescription = '将一条消息从群精华消息列表中移出';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.DelEssenceMsg.payload;
|
||||
override returnExample = GroupActionsExamples.DelEssenceMsg.response;
|
||||
|
||||
async _handle (payload: PayloadType): Promise<ReturnType> {
|
||||
// 如果直接提供了 msg_seq, msg_random, group_id,优先使用
|
||||
if (payload.msg_seq && payload.msg_random && payload.group_id) {
|
||||
return await this.core.apis.GroupApi.removeGroupEssenceBySeq(
|
||||
payload.group_id,
|
||||
payload.msg_random,
|
||||
payload.msg_seq
|
||||
);
|
||||
}
|
||||
|
||||
// 如果没有 message_id,则必须提供 msg_seq, msg_random, group_id
|
||||
if (!payload.message_id) {
|
||||
throw new Error('必须提供 message_id 或者同时提供 msg_seq, msg_random, group_id');
|
||||
}
|
||||
|
||||
const msg = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id);
|
||||
if (!msg) {
|
||||
const data = this.core.apis.GroupApi.essenceLRU.getValue(+payload.message_id);
|
||||
if (!data) throw new Error('消息不存在');
|
||||
const { msg_seq, msg_random, group_id } = JSON.parse(data) as { msg_seq: string, msg_random: string, group_id: string; };
|
||||
return await this.core.apis.GroupApi.removeGroupEssenceBySeq(group_id, msg_seq, msg_random);
|
||||
}
|
||||
return await this.core.apis.GroupApi.removeGroupEssence(
|
||||
msg.Peer.peerUid,
|
||||
msg.MsgId
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
notice_id: Type.String({ description: '公告ID' }),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Any({ description: '操作结果' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export class DelGroupNotice extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.DelGroupNotice;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '删除群公告';
|
||||
override actionDescription = '删除群聊中的公告';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.DelGroupNotice.payload;
|
||||
override returnExample = GroupActionsExamples.DelGroupNotice.response;
|
||||
|
||||
async _handle (payload: PayloadType) {
|
||||
const group = payload.group_id.toString();
|
||||
const noticeId = payload.notice_id;
|
||||
return await this.core.apis.GroupApi.deleteGroupBulletin(group, noticeId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { GetPacketStatusDepends } from '@/snowcat-onebot/action/packet/GetPacketStatus';
|
||||
import { AIVoiceChatType } from 'snowcat-core/packet/entities/aiChat';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
character: Type.String({ description: '角色ID' }),
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
text: Type.String({ description: '语音文本内容' }),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.String({ description: '语音URL' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export class GetAiRecord extends GetPacketStatusDepends<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.GetAiRecord;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '获取 AI 语音';
|
||||
override actionDescription = '通过 AI 语音引擎获取指定文本的语音 URL';
|
||||
override actionTags = ['AI 扩展'];
|
||||
override payloadExample = {
|
||||
character: 'ai_char_1',
|
||||
group_id: '123456',
|
||||
text: '你好',
|
||||
};
|
||||
|
||||
override returnExample = 'http://example.com/ai_voice.silk';
|
||||
|
||||
async _handle (payload: PayloadType) {
|
||||
const rawRsp = await this.core.apis.PacketApi.pkt.operation.GetAiVoice(+payload.group_id, payload.character, payload.text, AIVoiceChatType.Sound);
|
||||
if (!rawRsp.msgInfoBody[0]) {
|
||||
throw new Error('No voice data');
|
||||
}
|
||||
return await this.core.apis.PacketApi.pkt.operation.GetGroupPttUrl(+payload.group_id, rawRsp.msgInfoBody[0].index);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Object({
|
||||
group_id: Type.Number({ description: '群号' }),
|
||||
group_name: Type.String({ description: '群名称' }),
|
||||
member_count: Type.Number({ description: '成员数量' }),
|
||||
max_member_count: Type.Number({ description: '最大成员数量' }),
|
||||
group_all_shut: Type.Number({ description: '全员禁言状态' }),
|
||||
group_remark: Type.String({ description: '群备注' }),
|
||||
}, { description: '群详细信息' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export class GetGroupDetailInfo extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.GetGroupDetailInfo;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '获取群详细信息';
|
||||
override actionDescription = '获取群聊的详细信息,包括成员数、最大成员数等';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.GetGroupDetailInfo.payload;
|
||||
override returnExample = GroupActionsExamples.GetGroupDetailInfo.response;
|
||||
|
||||
async _handle (payload: PayloadType): Promise<ReturnType> {
|
||||
const data = await this.core.apis.GroupApi.fetchGroupDetail(payload.group_id.toString());
|
||||
return {
|
||||
...data,
|
||||
group_all_shut: data.shutUpAllTimestamp > 0 ? -1 : 0,
|
||||
group_remark: '',
|
||||
group_id: +payload.group_id,
|
||||
group_name: data.groupName,
|
||||
member_count: data.memberNum,
|
||||
max_member_count: data.maxMemberNum,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import type { MessageFormat } from '@/snowcat-onebot/config/config';
|
||||
import { ChatType, Peer } from 'snowcat-core';
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { MessageUnique } from 'snowcat-common/src/message-unique';
|
||||
import crypto from 'crypto';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { NetworkAdapterConfig } from '@/snowcat-onebot/config/config';
|
||||
import { OB11MessageData, OB11MessageDataType } from '@/snowcat-onebot/types';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Array(Type.Object({
|
||||
msg_seq: Type.Number({ description: '消息序号' }),
|
||||
msg_random: Type.Number({ description: '消息随机数' }),
|
||||
sender_id: Type.Number({ description: '发送者QQ' }),
|
||||
sender_nick: Type.String({ description: '发送者昵称' }),
|
||||
operator_id: Type.Number({ description: '操作者QQ' }),
|
||||
operator_nick: Type.String({ description: '操作者昵称' }),
|
||||
message_id: Type.Number({ description: '消息ID' }),
|
||||
operator_time: Type.Number({ description: '操作时间' }),
|
||||
content: Type.Array(Type.Any(), { description: '消息内容' }),
|
||||
}), { description: '精华消息列表' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export class GetGroupEssence extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.GoCQHTTP_GetEssenceMsg;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '获取群精华消息';
|
||||
override actionDescription = '获取指定群聊中的精华消息列表';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.GetGroupEssence.payload;
|
||||
override returnExample = GroupActionsExamples.GetGroupEssence.response;
|
||||
|
||||
private async msgSeqToMsgId (peer: Peer, msgSeq: string, msgRandom: string) {
|
||||
const replyMsgList = (await this.core.apis.MsgApi.getMsgsBySeqAndCount(peer, msgSeq, 1, true, true)).msgList.find((msg) => msg.msgSeq === msgSeq && msg.msgRandom === msgRandom);
|
||||
if (!replyMsgList) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
id: MessageUnique.createUniqueMsgId(peer, replyMsgList.msgId),
|
||||
msg: replyMsgList,
|
||||
};
|
||||
}
|
||||
|
||||
async _handle (payload: PayloadType, _adapter: string, config: NetworkAdapterConfig): Promise<ReturnType> {
|
||||
const msglist = (await this.core.apis.WebApi.getGroupEssenceMsgAll(payload.group_id.toString()))
|
||||
.flatMap((e) => e?.data?.msg_list)
|
||||
// 在群精华回空的时候会出现[null]的情况~ https://github.com/DandanLLab/SnowCatQQ/issues/1334
|
||||
.filter(Boolean);
|
||||
if (!msglist) {
|
||||
throw new Error('获取失败');
|
||||
}
|
||||
return await Promise.all(msglist.map(async (msg) => {
|
||||
const msgOriginData = await this.msgSeqToMsgId({
|
||||
chatType: ChatType.KCHATTYPEGROUP,
|
||||
peerUid: payload.group_id.toString(),
|
||||
}, msg.msg_seq.toString(), msg.msg_random.toString());
|
||||
if (msgOriginData) {
|
||||
const { id: message_id, msg: rawMessage } = msgOriginData;
|
||||
const parsed = await this.obContext.apis.MsgApi.parseMessage(rawMessage, config['messagePostFormat'] as MessageFormat | undefined ?? 'array');
|
||||
let content: OB11MessageData[] = [];
|
||||
if (parsed) {
|
||||
if (Array.isArray(parsed.message)) {
|
||||
content = parsed.message;
|
||||
} else {
|
||||
content = [{ type: OB11MessageDataType.text, data: { text: parsed.message } }];
|
||||
}
|
||||
}
|
||||
return {
|
||||
msg_seq: msg.msg_seq,
|
||||
msg_random: msg.msg_random,
|
||||
sender_id: +msg.sender_uin,
|
||||
sender_nick: msg.sender_nick,
|
||||
operator_id: +msg.add_digest_uin,
|
||||
operator_nick: msg.add_digest_nick,
|
||||
message_id,
|
||||
operator_time: msg.add_digest_time,
|
||||
content,
|
||||
};
|
||||
}
|
||||
const msgTempData = JSON.stringify({
|
||||
msg_seq: msg.msg_seq.toString(),
|
||||
msg_random: msg.msg_random.toString(),
|
||||
group_id: payload.group_id.toString(),
|
||||
});
|
||||
const hash = crypto.createHash('md5').update(msgTempData).digest();
|
||||
// 设置第一个bit为0 保证shortId为正数
|
||||
if (hash[0]) {
|
||||
hash[0] &= 0x7f;
|
||||
}
|
||||
const shortId = hash.readInt32BE(0);
|
||||
this.core.apis.GroupApi.essenceLRU.set(shortId, msgTempData);
|
||||
return {
|
||||
msg_seq: msg.msg_seq,
|
||||
msg_random: msg.msg_random,
|
||||
sender_id: +msg.sender_uin,
|
||||
sender_nick: msg.sender_nick,
|
||||
operator_id: +msg.add_digest_uin,
|
||||
operator_nick: msg.add_digest_nick,
|
||||
message_id: shortId,
|
||||
operator_time: msg.add_digest_time,
|
||||
content: msg.msg_content.map((msg): OB11MessageData | undefined => {
|
||||
if (msg.msg_type === 1) {
|
||||
return {
|
||||
type: OB11MessageDataType.text,
|
||||
data: {
|
||||
text: msg?.text ?? '',
|
||||
},
|
||||
};
|
||||
} else if (msg.msg_type === 3) {
|
||||
return {
|
||||
type: OB11MessageDataType.image,
|
||||
data: {
|
||||
file: '',
|
||||
url: msg?.image_url,
|
||||
},
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}).filter((e): e is OB11MessageData => e !== undefined),
|
||||
};
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { GroupNotifyMsgStatus } from 'snowcat-core';
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
const PayloadSchema = Type.Object({}, { description: '群忽略通知负载' });
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Object({
|
||||
invited_requests: Type.Array(Type.Any(), { description: '邀请请求列表' }),
|
||||
InvitedRequest: Type.Array(Type.Any(), { description: '邀请请求列表' }),
|
||||
join_requests: Type.Array(Type.Any(), { description: '加入请求列表' }),
|
||||
}, { description: '群忽略通知结果' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export class GetGroupIgnoredNotifies extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.GetGroupIgnoredNotifies;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '获取群忽略通知';
|
||||
override actionDescription = '获取被忽略的入群申请和邀请通知';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = {};
|
||||
override returnExample = {
|
||||
invited_requests: [],
|
||||
InvitedRequest: [],
|
||||
join_requests: [],
|
||||
};
|
||||
|
||||
async _handle (): Promise<ReturnType> {
|
||||
const SingleScreenNotifies = await this.core.apis.GroupApi.getSingleScreenNotifies(false, 50);
|
||||
const retData: ReturnType = { invited_requests: [], InvitedRequest: [], join_requests: [] };
|
||||
|
||||
const notifyPromises = SingleScreenNotifies.map(async (SSNotify) => {
|
||||
const invitorUin = SSNotify.user1?.uid ? +await this.core.apis.UserApi.getUinByUidV2(SSNotify.user1.uid) : 0;
|
||||
const actorUin = SSNotify.user2?.uid ? +await this.core.apis.UserApi.getUinByUidV2(SSNotify.user2.uid) : 0;
|
||||
const commonData = {
|
||||
request_id: +SSNotify.seq,
|
||||
invitor_uin: invitorUin,
|
||||
invitor_nick: SSNotify.user1?.nickName,
|
||||
group_id: +SSNotify.group?.groupCode,
|
||||
message: SSNotify?.postscript,
|
||||
group_name: SSNotify.group?.groupName,
|
||||
checked: SSNotify.status !== GroupNotifyMsgStatus.KUNHANDLE,
|
||||
actor: actorUin,
|
||||
requester_nick: SSNotify.user1?.nickName,
|
||||
};
|
||||
|
||||
if (SSNotify.type === 1) {
|
||||
retData.InvitedRequest.push(commonData);
|
||||
} else if (SSNotify.type === 7) {
|
||||
retData.join_requests.push(commonData);
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(notifyPromises);
|
||||
retData.invited_requests = retData.InvitedRequest;
|
||||
return retData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { OB11Construct } from '@/snowcat-onebot/helper/data';
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { OB11GroupSchema } from '../schemas';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = OB11GroupSchema;
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
class GetGroupInfo extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.GetGroupInfo;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '获取群信息';
|
||||
override actionDescription = '获取群聊的基本信息';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.GetGroupInfo.payload;
|
||||
override returnExample = GroupActionsExamples.GetGroupInfo.response;
|
||||
|
||||
async _handle (payload: PayloadType) {
|
||||
const group = (await this.core.apis.GroupApi.getGroups()).find(e => e.groupCode === payload.group_id.toString());
|
||||
if (!group) {
|
||||
const data = await this.core.apis.GroupApi.fetchGroupDetail(payload.group_id.toString());
|
||||
if (data.ownerUid && data.ownerUin === '0') {
|
||||
data.ownerUin = await this.core.apis.UserApi.getUinByUidV2(data.ownerUid);
|
||||
}
|
||||
return {
|
||||
...data,
|
||||
group_all_shut: data.shutUpAllTimestamp > 0 ? -1 : 0,
|
||||
group_remark: '',
|
||||
group_id: +payload.group_id,
|
||||
group_name: data.groupName,
|
||||
member_count: data.memberNum,
|
||||
max_member_count: data.maxMemberNum,
|
||||
};
|
||||
}
|
||||
return OB11Construct.group(group);
|
||||
}
|
||||
}
|
||||
|
||||
export default GetGroupInfo;
|
||||
@@ -0,0 +1,35 @@
|
||||
import { OB11Construct } from '@/snowcat-onebot/helper/data';
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { OB11GroupSchema } from '../schemas';
|
||||
import { GroupActionsExamples } from '@/snowcat-onebot/action/example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否不使用缓存' })),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Array(OB11GroupSchema, { description: '群列表' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
class GetGroupList extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.GetGroupList;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '获取群列表';
|
||||
override actionDescription = '获取当前帐号的群聊列表';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.GetGroupList.payload;
|
||||
override returnExample = GroupActionsExamples.GetGroupList.response;
|
||||
|
||||
async _handle (payload: PayloadType) {
|
||||
return OB11Construct.groups(
|
||||
await this.core.apis.GroupApi.getGroups(
|
||||
typeof payload.no_cache === 'string' ? payload.no_cache === 'true' : !!payload.no_cache));
|
||||
}
|
||||
}
|
||||
|
||||
export default GetGroupList;
|
||||
@@ -0,0 +1,68 @@
|
||||
import { OB11Construct } from '@/snowcat-onebot/helper/data';
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { OB11GroupMemberSchema } from '../schemas';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
user_id: Type.String({ description: 'QQ号' }),
|
||||
no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否不使用缓存' })),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = OB11GroupMemberSchema;
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
class GetGroupMemberInfo extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.GetGroupMemberInfo;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '获取群成员信息';
|
||||
override actionDescription = '获取群聊中指定成员的信息';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.GetGroupMemberInfo.payload;
|
||||
override returnExample = GroupActionsExamples.GetGroupMemberInfo.response;
|
||||
|
||||
private parseBoolean (value: boolean | string): boolean {
|
||||
return typeof value === 'string' ? value === 'true' : value;
|
||||
}
|
||||
|
||||
private async getUid (userId: string | number): Promise<string> {
|
||||
const uid = await this.core.apis.UserApi.getUidByUinV2(userId.toString());
|
||||
if (!uid) throw new Error(`Uin2Uid Error: 用户ID ${userId} 不存在`);
|
||||
return uid;
|
||||
}
|
||||
|
||||
private async getGroupMemberInfo (payload: PayloadType, uid: string, isNocache: boolean) {
|
||||
const groupMemberCache = this.core.apis.GroupApi.groupMemberCache.get(payload.group_id.toString());
|
||||
const groupMember = groupMemberCache?.get(uid);
|
||||
|
||||
const [member, info] = await Promise.all([
|
||||
this.core.apis.GroupApi.getGroupMemberEx(payload.group_id.toString(), uid, isNocache),
|
||||
this.core.apis.UserApi.getUserDetailInfo(uid, isNocache),
|
||||
]);
|
||||
|
||||
if (!member || !groupMember) throw new Error(`群(${payload.group_id})成员${payload.user_id}不存在`);
|
||||
|
||||
return info ? { ...groupMember, ...member, ...info } : member;
|
||||
}
|
||||
|
||||
async _handle (payload: PayloadType) {
|
||||
const isNocache = this.parseBoolean(payload.no_cache ?? true);
|
||||
const uid = await this.getUid(payload.user_id);
|
||||
const member = await this.getGroupMemberInfo(payload, uid, isNocache);
|
||||
|
||||
if (!member) {
|
||||
this.core.context.logger.logDebug('获取群成员详细信息失败, 只能返回基础信息');
|
||||
}
|
||||
|
||||
return OB11Construct.groupMember(payload.group_id.toString(), member);
|
||||
}
|
||||
}
|
||||
|
||||
export default GetGroupMemberInfo;
|
||||
@@ -0,0 +1,59 @@
|
||||
import { OB11Construct } from '@/snowcat-onebot/helper/data';
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { GroupMember } from 'snowcat-core';
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否不使用缓存' })),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Array(Type.Any(), { description: '群成员列表' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export class GetGroupMemberList extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.GetGroupMemberList;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '获取群成员列表';
|
||||
override actionDescription = '获取群聊中的所有成员列表';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.GetGroupMemberList.payload;
|
||||
override returnExample = GroupActionsExamples.GetGroupMemberList.response;
|
||||
|
||||
async _handle (payload: PayloadType) {
|
||||
const groupIdStr = payload.group_id.toString();
|
||||
const noCache = this.parseBoolean(payload.no_cache ?? false);
|
||||
const groupMembers = await this.getGroupMembers(groupIdStr, noCache);
|
||||
const _groupMembers = await Promise.all(
|
||||
Array.from(groupMembers.values()).map(item =>
|
||||
OB11Construct.groupMember(groupIdStr, item)
|
||||
)
|
||||
);
|
||||
return Array.from(new Map(_groupMembers.map(member => [member.user_id, member])).values());
|
||||
}
|
||||
|
||||
private parseBoolean (value: boolean | string): boolean {
|
||||
return typeof value === 'string' ? value === 'true' : value;
|
||||
}
|
||||
|
||||
private async getGroupMembers (groupIdStr: string, noCache: boolean): Promise<Map<string, GroupMember>> {
|
||||
const memberCache = this.core.apis.GroupApi.groupMemberCache;
|
||||
let groupMembers = memberCache.get(groupIdStr);
|
||||
|
||||
if (noCache || !groupMembers) {
|
||||
const data = this.core.apis.GroupApi.refreshGroupMemberCache(groupIdStr, true).then().catch();
|
||||
groupMembers = memberCache.get(groupIdStr) || (await data);
|
||||
if (!groupMembers) {
|
||||
throw new Error(`Failed to get group member list for group ${groupIdStr}`);
|
||||
}
|
||||
}
|
||||
|
||||
return groupMembers;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { WebApiGroupNoticeFeed } from 'snowcat-core';
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Array(Type.Object({
|
||||
sender_id: Type.Number({ description: '发送者QQ' }),
|
||||
publish_time: Type.Number({ description: '发布时间' }),
|
||||
notice_id: Type.String({ description: '公告ID' }),
|
||||
message: Type.Object({
|
||||
text: Type.String({ description: '文本内容' }),
|
||||
image: Type.Array(Type.Any(), { description: '图片列表' }),
|
||||
images: Type.Array(Type.Any(), { description: '图片列表' }),
|
||||
}, { description: '公告内容' }),
|
||||
settings: Type.Optional(Type.Any({ description: '设置项' })),
|
||||
read_num: Type.Optional(Type.Number({ description: '阅读数' })),
|
||||
}), { description: '群公告列表' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export type ApiGroupNotice = ReturnType[number] & WebApiGroupNoticeFeed;
|
||||
|
||||
export class GetGroupNotice extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.GoCQHTTP_GetGroupNotice;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '获取群公告';
|
||||
override actionDescription = '获取指定群聊中的公告列表';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.GetGroupNotice.payload;
|
||||
override returnExample = GroupActionsExamples.GetGroupNotice.response;
|
||||
|
||||
async _handle (payload: PayloadType) {
|
||||
const group = payload.group_id.toString();
|
||||
const ret = await this.core.apis.WebApi.getGroupNotice(group);
|
||||
if (!ret) {
|
||||
throw new Error('获取公告失败');
|
||||
}
|
||||
const retNotices: ReturnType = [];
|
||||
for (const key in ret.feeds) {
|
||||
if (!ret.feeds[key]) {
|
||||
continue;
|
||||
}
|
||||
const retApiNotice: WebApiGroupNoticeFeed = ret.feeds[key];
|
||||
const image = retApiNotice.msg.pics?.map((pic) => {
|
||||
return { id: pic.id, height: pic.h, width: pic.w };
|
||||
}) || [];
|
||||
|
||||
const retNotice: ReturnType[number] = {
|
||||
notice_id: retApiNotice.fid,
|
||||
sender_id: retApiNotice.u,
|
||||
publish_time: retApiNotice.pubt,
|
||||
message: {
|
||||
text: retApiNotice.msg.text,
|
||||
image,
|
||||
images: image,
|
||||
},
|
||||
settings: retApiNotice.settings,
|
||||
read_num: retApiNotice.read_num,
|
||||
};
|
||||
retNotices.push(retNotice);
|
||||
}
|
||||
|
||||
return retNotices;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Array(Type.Any(), { description: '禁言成员列表' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export class GetGroupShutList extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.GetGroupShutList;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '获取群禁言列表';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = {
|
||||
group_id: '123456789',
|
||||
};
|
||||
|
||||
override returnExample = [
|
||||
{
|
||||
user_id: 123456789,
|
||||
nickname: '禁言用户',
|
||||
shut_up_time: 1734567890,
|
||||
},
|
||||
];
|
||||
|
||||
async _handle (payload: PayloadType) {
|
||||
return await this.core.apis.GroupApi.getGroupShutUpMemberList(payload.group_id.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { GeneralCallResult } from 'snowcat-core';
|
||||
|
||||
export function assertGroupManagementResults (
|
||||
operation: string,
|
||||
results: Array<{ setting: string, result: GeneralCallResult; }>
|
||||
): void {
|
||||
const failure = results.find(item => item.result.result !== 0);
|
||||
if (!failure) return;
|
||||
throw new Error(
|
||||
`${operation}失败 Setting: ${failure.setting} ErrCode: ${failure.result.result} ` +
|
||||
`ErrMsg: ${failure.result.errMsg || '未知错误'}`
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { GetPacketStatusDepends } from '@/snowcat-onebot/action/packet/GetPacketStatus';
|
||||
import { AIVoiceChatType } from 'snowcat-core/packet/entities/aiChat';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
character: Type.String({ description: '角色ID' }),
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
text: Type.String({ description: '语音文本内容' }),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Object({
|
||||
message_id: Type.Number({ description: '消息ID' }),
|
||||
}, { description: '发送结果' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export class SendGroupAiRecord extends GetPacketStatusDepends<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.SendGroupAiRecord;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '发送群 AI 语音';
|
||||
override actionDescription = '发送 AI 生成的语音到指定群聊';
|
||||
override actionTags = ['AI 扩展'];
|
||||
override payloadExample = {
|
||||
character: 'ai_char_1',
|
||||
group_id: '123456',
|
||||
text: '你好',
|
||||
};
|
||||
|
||||
override returnExample = {};
|
||||
|
||||
async _handle (payload: PayloadType) {
|
||||
await this.core.apis.PacketApi.pkt.operation.GetAiVoice(+payload.group_id, payload.character, payload.text, AIVoiceChatType.Sound);
|
||||
return {
|
||||
message_id: 0, // can't get message_id from GetAiVoice
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { ContextMode, ReturnDataType, SendMsgBase, SendMsgPayload } from '@/snowcat-onebot/action/msg/SendMsg';
|
||||
import { ActionName, BaseCheckResult } from '@/snowcat-onebot/action/router';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
import { snowCatStable } from '@/snowcat-onebot/stable-line';
|
||||
|
||||
// 未检测参数
|
||||
class SendGroupMsg extends SendMsgBase {
|
||||
override actionName = ActionName.SendGroupMsg;
|
||||
override actionSummary = '发送群消息';
|
||||
override actionDescription = '发送群消息';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.SendGroupMsg.payload;
|
||||
override returnExample = GroupActionsExamples.SendGroupMsg.response;
|
||||
|
||||
protected override async check (payload: SendMsgPayload): Promise<BaseCheckResult> {
|
||||
delete payload.user_id;
|
||||
payload.message_type = 'group';
|
||||
return super.check(payload);
|
||||
}
|
||||
|
||||
override async _handle (payload: SendMsgPayload): Promise<ReturnDataType> {
|
||||
// SnowCat 稳定线:真人抖动+账号预算+熔断
|
||||
await snowCatStable.stableDelay();
|
||||
return this.base_handle(payload, ContextMode.Group);
|
||||
}
|
||||
}
|
||||
|
||||
export default SendGroupMsg;
|
||||
@@ -0,0 +1,38 @@
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { MessageUnique } from 'snowcat-common/src/message-unique';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
message_id: Type.Union([Type.Number(), Type.String()], { description: '消息ID' }),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Any({ description: '操作结果' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export default class SetEssenceMsg extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.SetEssenceMsg;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '设置精华消息';
|
||||
override actionDescription = '将一条消息设置为群精华消息';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.SetEssenceMsg.payload;
|
||||
override returnExample = GroupActionsExamples.SetEssenceMsg.response;
|
||||
|
||||
async _handle (payload: PayloadType) {
|
||||
const msg = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id);
|
||||
if (!msg) {
|
||||
throw new Error('msg not found');
|
||||
}
|
||||
return await this.core.apis.GroupApi.addGroupEssence(
|
||||
msg.Peer.peerUid,
|
||||
msg.MsgId
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { GroupNotify, NTGroupRequestOperateTypes } from 'snowcat-core/types';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
flag: Type.String({ description: '请求flag' }),
|
||||
approve: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否同意' })),
|
||||
reason: Type.Optional(Type.Union([Type.String({ default: ' ' }), Type.Null()], { description: '拒绝理由' })),
|
||||
count: Type.Optional(Type.Number({ default: 100, description: '搜索通知数量' })),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Null({ description: '操作结果' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export default class SetGroupAddRequest extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.SetGroupAddRequest;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '处理加群请求';
|
||||
override actionDescription = '同意或拒绝加群请求或邀请';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.SetGroupAddRequest.payload;
|
||||
override returnExample = GroupActionsExamples.SetGroupAddRequest.response;
|
||||
|
||||
async _handle (payload: PayloadType): Promise<null> {
|
||||
const flag = payload.flag.toString();
|
||||
const approve = payload.approve?.toString() !== 'false';
|
||||
const reason = payload.reason ?? ' ';
|
||||
const count = payload.count;
|
||||
const invite_notify = this.obContext.apis.MsgApi.notifyGroupInvite.get(flag);
|
||||
const { doubt, notify } = invite_notify
|
||||
? {
|
||||
doubt: false,
|
||||
notify: invite_notify,
|
||||
}
|
||||
: await this.findNotify(flag, count);
|
||||
if (!notify) {
|
||||
throw new Error('No such request');
|
||||
}
|
||||
await this.core.apis.GroupApi.handleGroupRequest(
|
||||
doubt,
|
||||
notify,
|
||||
approve ? NTGroupRequestOperateTypes.KAGREE : NTGroupRequestOperateTypes.KREFUSE,
|
||||
reason
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
private async findNotify (flag: string, count: number = 100): Promise<{
|
||||
doubt: boolean,
|
||||
notify: GroupNotify | undefined;
|
||||
}> {
|
||||
let notify = (await this.core.apis.GroupApi.getSingleScreenNotifies(false, count)).find(e => e.seq === flag);
|
||||
if (!notify) {
|
||||
notify = (await this.core.apis.GroupApi.getSingleScreenNotifies(true, count)).find(e => e.seq === flag);
|
||||
return { doubt: true, notify };
|
||||
}
|
||||
return { doubt: false, notify };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { NTGroupMemberRole } from 'snowcat-core/types';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
user_id: Type.String({ description: '用户QQ' }),
|
||||
enable: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否设置为管理员' })),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Null({ description: '操作结果' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export default class SetGroupAdmin extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.SetGroupAdmin;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '设置群管理员';
|
||||
override actionDescription = '设置或取消群聊中的管理员';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.SetGroupAdmin.payload;
|
||||
override returnExample = GroupActionsExamples.SetGroupAdmin.response;
|
||||
|
||||
async _handle (payload: PayloadType): Promise<null> {
|
||||
const enable = typeof payload.enable === 'string' ? payload.enable === 'true' : !!payload.enable;
|
||||
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||
if (!uid) throw new Error('get Uid Error');
|
||||
await this.core.apis.GroupApi.setMemberRole(payload.group_id.toString(), uid, enable ? NTGroupMemberRole.KADMIN : NTGroupMemberRole.KMEMBER);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
import { NTGroupMemberRole } from '@/snowcat-core';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
user_id: Type.String({ description: '用户QQ' }),
|
||||
duration: Type.Union([Type.Number(), Type.String()], { default: 0, description: '禁言时长(秒)' }),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Null({ description: '操作结果' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export default class SetGroupBan extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.SetGroupBan;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '群组禁言';
|
||||
override actionDescription = '禁言群聊中的指定成员';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.SetGroupBan.payload;
|
||||
override returnExample = GroupActionsExamples.SetGroupBan.response;
|
||||
|
||||
async _handle (payload: PayloadType): Promise<null> {
|
||||
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||
if (!uid) throw new Error('uid error');
|
||||
const member_role = (await this.core.apis.GroupApi.getGroupMemberEx(payload.group_id.toString(), uid, true))?.role;
|
||||
if (member_role === undefined) throw new Error('user not in group');
|
||||
if (member_role === NTGroupMemberRole.KOWNER) throw new Error('cannot ban owner');
|
||||
if (member_role === NTGroupMemberRole.KADMIN) {
|
||||
const self_role = (await this.core.apis.GroupApi.getGroupMemberEx(payload.group_id.toString(), this.core.selfInfo.uid, true))?.role;
|
||||
if (self_role === undefined) throw new Error('failed to fetch bot role');
|
||||
if (self_role !== NTGroupMemberRole.KOWNER) throw new Error('cannot ban admin');
|
||||
}
|
||||
// 例如无管理员权限时 result为 120101005 errMsg为 'ERR_NOT_GROUP_ADMIN'
|
||||
const ret = await this.core.apis.GroupApi.banMember(payload.group_id.toString(),
|
||||
[{ uid, timeStamp: +payload.duration }]);
|
||||
if (ret.result !== 0) throw new Error(ret.errMsg);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { sleep } from '@/snowcat-common/src/helper';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
user_id: Type.String({ description: '用户QQ' }),
|
||||
card: Type.Optional(Type.String({ description: '群名片' })),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Null({ description: '操作结果' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export default class SetGroupCard extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.SetGroupCard;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '设置群名片';
|
||||
override actionDescription = '设置群聊中指定成员的群名片';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.SetGroupCard.payload;
|
||||
override returnExample = GroupActionsExamples.SetGroupCard.response;
|
||||
|
||||
async _handle (payload: PayloadType): Promise<null> {
|
||||
const groupId = payload.group_id.toString();
|
||||
const userId = payload.user_id.toString();
|
||||
const card = payload.card || '';
|
||||
|
||||
const member = await this.core.apis.GroupApi.getGroupMember(groupId, userId);
|
||||
if (!member) {
|
||||
throw new Error(`群(${groupId})成员${userId}不存在`);
|
||||
}
|
||||
|
||||
await this.core.apis.GroupApi.setMemberCard(groupId, member.uid, card);
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
await sleep(1000);
|
||||
const updatedMember = await this.core.apis.GroupApi.refreshGroupMemberCachePartial(groupId, member.uid);
|
||||
if (updatedMember?.cardName === card) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
throw new Error('设置群名片未生效');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
user_id: Type.String({ description: '用户QQ' }),
|
||||
reject_add_request: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否拒绝加群请求' })),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Null({ description: '操作结果' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export default class SetGroupKick extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.SetGroupKick;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '群组踢人';
|
||||
override actionDescription = '将指定成员踢出群聊';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.SetGroupKick.payload;
|
||||
override returnExample = GroupActionsExamples.SetGroupKick.response;
|
||||
|
||||
async _handle (payload: PayloadType): Promise<null> {
|
||||
const rejectReq = payload.reject_add_request?.toString() === 'true';
|
||||
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||
if (!uid) throw new Error('get Uid Error');
|
||||
await this.core.apis.GroupApi.kickMember(payload.group_id.toString(), [uid], rejectReq);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
is_dismiss: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否解散' })),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Null({ description: '操作结果' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export default class SetGroupLeave extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.SetGroupLeave;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '退出群组';
|
||||
override actionDescription = '退出或解散指定群聊';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.SetGroupLeave.payload;
|
||||
override returnExample = GroupActionsExamples.SetGroupLeave.response;
|
||||
|
||||
async _handle (payload: PayloadType): Promise<null> {
|
||||
await this.core.apis.GroupApi.quitGroup(payload.group_id.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
import { assertGroupManagementResults } from './GroupOperationHelpers';
|
||||
|
||||
const MemberInvitePolicySchema = Type.Union([
|
||||
Type.Literal('disabled'),
|
||||
Type.Literal('require_approval'),
|
||||
Type.Literal('no_approval'),
|
||||
Type.Literal('no_approval_under_100'),
|
||||
], {
|
||||
description: '成员邀请策略:禁止、需要管理员审核、无需审核、群成员少于100人时无需审核',
|
||||
});
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
policy: MemberInvitePolicySchema,
|
||||
});
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Null({ description: '操作结果' });
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export default class SetGroupMemberInvitePolicy extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.SetGroupMemberInvitePolicy;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '设置群成员邀请策略';
|
||||
override actionDescription = '设置是否允许群成员邀请好友进群,以及邀请是否需要管理员审核';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.SetGroupMemberInvitePolicy.payload;
|
||||
override returnExample = GroupActionsExamples.SetGroupMemberInvitePolicy.response;
|
||||
|
||||
async _handle (payload: PayloadType): Promise<ReturnType> {
|
||||
const results = await this.core.apis.GroupApi.setGroupMemberInvitePolicy(payload.group_id, payload.policy);
|
||||
assertGroupManagementResults('设置群成员邀请策略', results);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
import { assertGroupManagementResults } from './GroupOperationHelpers';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
allow_member_upload_album: Type.Optional(Type.Boolean({ description: '允许成员上传群相册' })),
|
||||
allow_member_temporary_session: Type.Optional(Type.Boolean({ description: '允许成员发起临时会话' })),
|
||||
allow_member_create_group: Type.Optional(Type.Boolean({ description: '允许成员发起新的群聊' })),
|
||||
});
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Null({ description: '操作结果' });
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export default class SetGroupMemberPermissions extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.SetGroupMemberPermissions;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '设置群成员功能权限';
|
||||
override actionDescription = '设置群成员上传相册、发起临时会话和发起新群聊的权限;未传入的项目保持不变';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.SetGroupMemberPermissions.payload;
|
||||
override returnExample = GroupActionsExamples.SetGroupMemberPermissions.response;
|
||||
|
||||
async _handle (payload: PayloadType): Promise<ReturnType> {
|
||||
const permissions = {
|
||||
allowMemberUploadAlbum: payload.allow_member_upload_album,
|
||||
allowMemberTemporarySession: payload.allow_member_temporary_session,
|
||||
allowMemberCreateGroup: payload.allow_member_create_group,
|
||||
};
|
||||
if (Object.values(permissions).every(value => value === undefined)) {
|
||||
throw new Error('至少需要提供一个群成员功能权限');
|
||||
}
|
||||
|
||||
const results = await this.core.apis.GroupApi.setGroupMemberPermissions(payload.group_id, permissions);
|
||||
assertGroupManagementResults('设置群成员功能权限', results);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
group_name: Type.String({ description: '群名称' }),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Null({ description: '操作结果' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export default class SetGroupName extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.SetGroupName;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '设置群名称';
|
||||
override actionDescription = '修改指定群聊的名称';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.SetGroupName.payload;
|
||||
override returnExample = GroupActionsExamples.SetGroupName.response;
|
||||
|
||||
async _handle (payload: PayloadType): Promise<null> {
|
||||
let ret = await this.core.apis.GroupApi.setGroupName(payload.group_id.toString(), payload.group_name);
|
||||
if (ret.result.toString() === '1287') {
|
||||
ret = await this.core.apis.GroupApi.setGroupName(payload.group_id.toString(), payload.group_name, true);
|
||||
}
|
||||
if (ret.result !== 0) {
|
||||
throw new Error(`设置群名称失败 ErrCode: ${ret.result} ErrMsg: ${ret.errMsg}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
import { assertGroupManagementResults } from './GroupOperationHelpers';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
visible: Type.Boolean({ description: '新成员默认可见最近聊天记录' }),
|
||||
});
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Null({ description: '操作结果' });
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export default class SetGroupNewMemberHistoryVisibility extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.SetGroupNewMemberHistoryVisibility;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '设置新成员历史消息可见性';
|
||||
override actionDescription = '设置新入群成员默认是否可以查看最近聊天记录';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.SetGroupNewMemberHistoryVisibility.payload;
|
||||
override returnExample = GroupActionsExamples.SetGroupNewMemberHistoryVisibility.response;
|
||||
|
||||
async _handle (payload: PayloadType): Promise<ReturnType> {
|
||||
const results = await this.core.apis.GroupApi.setGroupNewMemberHistoryVisibility(
|
||||
payload.group_id,
|
||||
payload.visible
|
||||
);
|
||||
assertGroupManagementResults('设置新成员历史消息可见性', results);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { OneBotAction } from '@/snowcat-onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/snowcat-onebot/action/router';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
|
||||
import { GroupActionsExamples } from '../example/GroupActionsExamples';
|
||||
|
||||
const PayloadSchema = Type.Object({
|
||||
group_id: Type.String({ description: '群号' }),
|
||||
enable: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否开启全员禁言' })),
|
||||
});
|
||||
|
||||
type PayloadType = Static<typeof PayloadSchema>;
|
||||
|
||||
const ReturnSchema = Type.Null({ description: '操作结果' });
|
||||
|
||||
type ReturnType = Static<typeof ReturnSchema>;
|
||||
|
||||
export default class SetGroupWholeBan extends OneBotAction<PayloadType, ReturnType> {
|
||||
override actionName = ActionName.SetGroupWholeBan;
|
||||
override payloadSchema = PayloadSchema;
|
||||
override returnSchema = ReturnSchema;
|
||||
override actionSummary = '全员禁言';
|
||||
override actionDescription = '开启或关闭指定群聊的全员禁言';
|
||||
override actionTags = ['群组接口'];
|
||||
override payloadExample = GroupActionsExamples.SetGroupWholeBan.payload;
|
||||
override returnExample = GroupActionsExamples.SetGroupWholeBan.response;
|
||||
|
||||
async _handle (payload: PayloadType): Promise<null> {
|
||||
const enable = payload.enable?.toString() !== 'false';
|
||||
const res = await this.core.apis.GroupApi.banGroup(payload.group_id.toString(), enable);
|
||||
if (res.result !== 0) {
|
||||
throw new Error(`SetGroupWholeBan failed: ${res.errMsg} ${res.result}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user