diff --git a/bot/api/onebot.ts b/bot/api/onebot.ts new file mode 100644 index 0000000..c8adba9 --- /dev/null +++ b/bot/api/onebot.ts @@ -0,0 +1,453 @@ +/** + * @author 锦恢 + * @email 1193466151@qq.com + * @description Lagrange.Core 前端接口 + * @comment 接口调用详细参考文档 + * - https://github.com/botuniverse/onebot-11/blob/master/communication/ws.md + */ + +import * as Lagrange from '../type'; + +/** + * @description 发送私聊消息 + * @param user_id 对方 QQ 号 + * @param message 要发送的内容 + * @param auto_escape 消息内容是否作为纯文本发送(即不解析 CQ 码),只在 message 字段是字符串时有效 + */ +export function sendPrivateMsg(user_id: number, message: Lagrange.Message, auto_escape: boolean = false) { + return { + action: 'send_private_msg', + params: { user_id, message, auto_escape } + }; +} + +/** + * @description 发送群消息 + * @param group_id 群号 + * @param message 要发送的内容 + * @param auto_escape 消息内容是否作为纯文本发送(即不解析 CQ 码),只在 message 字段是字符串时有效 + */ +export function sendGroupMsg(group_id: number, message: Lagrange.Message, auto_escape: boolean = false) { + return { + action: 'send_group_msg', + params: { group_id, message, auto_escape } + }; +} + +/** + * @description 发送消息 + * @param message_type 消息类型,支持 private、group,分别对应私聊、群组,如不传入,则根据传入的 *_id 参数判断 + * @param user_id 对方 QQ 号(消息类型为 private 时需要) + * @param group_id 群号(消息类型为 group 时需要) + * @param message 要发送的内容 + * @param auto_escape 消息内容是否作为纯文本发送(即不解析 CQ 码),只在 message 字段是字符串时有效 + */ +export function sendMsg(message_type: string, user_id: number, group_id: number, message: Lagrange.Message, auto_escape: boolean = false) { + return { + action: 'send_msg', + params: { message_type, user_id, group_id, message, auto_escape } + }; +} + +/** + * @description 撤回消息 + * @param message_id 消息 ID + */ +export function deleteMsg(message_id: number) { + return { + action: 'delete_msg', + params: { message_id } + }; +} + +/** + * @description 获取消息 + * @param message_id 消息 ID + */ +export function getMsg(message_id: number) { + return { + action: 'get_msg', + params: { message_id } + }; +} + +/** + * @description 获取合并转发消息 + * @param id 合并转发 ID + */ +export function getForwardMsg(id: string) { + return { + action: 'get_forward_msg', + params: { id } + }; +} + +/** + * @description 发送好友赞 + * @param user_id 对方 QQ 号 + * @param times 赞的次数,每个好友每天最多 10 次 + */ +export function sendLike(user_id: number, times: number = 1) { + return { + action: 'send_like', + params: { user_id, times } + }; +} + +/** + * @description 群组踢人 + * @param group_id 群号 + * @param user_id 要踢的 QQ 号 + * @param reject_add_request 拒绝此人的加群请求 + */ +export function setGroupKick(group_id: number, user_id: number, reject_add_request: boolean = false) { + return { + action: 'set_group_kick', + params: { group_id, user_id, reject_add_request } + }; +} + +/** + * @description 群组单人禁言 + * @param group_id 群号 + * @param user_id 要禁言的 QQ 号 + * @param duration 禁言时长,单位秒,0 表示取消禁言 + */ +export function setGroupBan(group_id: number, user_id: number, duration: number = 30 * 60) { + return { + action: 'set_group_ban', + params: { group_id, user_id, duration } + }; +} + +/** + * @description 群组匿名用户禁言 + * @param group_id 群号 + * @param anonymous 可选,要禁言的匿名用户对象(群消息上报的 anonymous 字段) + * @param anonymous_flag 可选,要禁言的匿名用户的 flag(需从群消息上报的数据中获得) + * @param duration 禁言时长,单位秒,无法取消匿名用户禁言 + */ +export function setGroupAnonymousBan(group_id: number, anonymous: object, anonymous_flag: string, duration: number = 30 * 60) { + return { + action: 'set_group_anonymous_ban', + params: { group_id, anonymous, anonymous_flag, duration } + }; +} + +/** + * @description 群组全员禁言 + * @param group_id 群号 + * @param enable 是否禁言 + */ +export function setGroupWholeBan(group_id: number, enable: boolean = true) { + return { + action: 'set_group_whole_ban', + params: { group_id, enable } + }; +} + +/** + * @description 群组设置管理员 + * @param group_id 群号 + * @param user_id 要设置管理员的 QQ 号 + * @param enable true 为设置,false 为取消 + */ +export function setGroupAdmin(group_id: number, user_id: number, enable: boolean = true) { + return { + action: 'set_group_admin', + params: { group_id, user_id, enable } + }; +} + +/** + * @description 群组匿名 + * @param group_id 群号 + * @param enable 是否允许匿名聊天 + */ +export function setGroupAnonymous(group_id: number, enable: boolean = true) { + return { + action: 'set_group_anonymous', + params: { group_id, enable } + }; +} + +/** + * @description 设置群名片(群备注) + * @param group_id 群号 + * @param user_id 要设置的 QQ 号 + * @param card 群名片内容,不填或空字符串表示删除群名片 + */ +export function setGroupCard(group_id: number, user_id: number, card: string = "") { + return { + action: 'set_group_card', + params: { group_id, user_id, card } + }; +} + +/** + * @description 设置群名 + * @param group_id 群号 + * @param group_name 新群名 + */ +export function setGroupName(group_id: number, group_name: string) { + return { + action: 'set_group_name', + params: { group_id, group_name } + }; +} + +/** + * @description 退出群组 + * @param group_id 群号 + * @param is_dismiss 是否解散,如果登录号是群主,则仅在此项为 true 时能够解散 + */ +export function setGroupLeave(group_id: number, is_dismiss: boolean = false) { + return { + action: 'set_group_leave', + params: { group_id, is_dismiss } + }; +} + +/** + * @description 设置群组专属头衔 + * @param group_id 群号 + * @param user_id 要设置的 QQ 号 + * @param special_title 专属头衔,不填或空字符串表示删除专属头衔 + * @param duration 专属头衔有效期,单位秒,-1 表示永久,不过此项似乎没有效果,可能是只有某些特殊的时间长度有效,有待测试 + */ +export function setGroupSpecialTitle(group_id: number, user_id: number, special_title: string = "", duration: number = -1) { + return { + action: 'set_group_special_title', + params: { group_id, user_id, special_title, duration } + }; +} + +/** + * @description 处理加好友请求 + * @param flag 加好友请求的 flag(需从上报的数据中获得) + * @param approve 是否同意请求 + * @param remark 添加后的好友备注(仅在同意时有效) + */ +export function setFriendAddRequest(flag: string, approve: boolean = true, remark: string = "") { + return { + action: 'set_friend_add_request', + params: { flag, approve, remark } + }; +} + +/** + * @description 处理加群请求/邀请 + * @param flag 加群请求的 flag(需从上报的数据中获得) + * @param sub_type add 或 invite,请求类型(需要和上报消息中的 sub_type 字段相符) + * @param approve 是否同意请求/邀请 + * @param reason 拒绝理由(仅在拒绝时有效) + */ +export function setGroupAddRequest(flag: string, sub_type: string, approve: boolean = true, reason: string = "") { + return { + action: 'set_group_add_request', + params: { flag, sub_type, approve, reason } + }; +} + +/** + * @description 获取登录号信息 + */ +export function getLoginInfo() { + return { + action: 'get_login_info', + params: { } + }; +} + +/** + * @description 获取陌生人信息 + * @param user_id QQ 号 + * @param no_cache 是否不使用缓存(使用缓存可能更新不及时,但响应更快) + */ +export function getStrangerInfo(user_id: number, no_cache: boolean = false) { + return { + action: 'get_stranger_info', + params: { user_id, no_cache } + }; +} + +/** + * @description 获取好友列表 + */ +export function getFriendList() { + return { + action: 'get_friend_list', + params: { } + }; +} + +/** + * @description 获取群信息 + * @param group_id 群号 + * @param no_cache 是否不使用缓存(使用缓存可能更新不及时,但响应更快) + */ +export function getGroupInfo(group_id: number, no_cache: boolean = false) { + return { + action: 'get_group_info', + params: { group_id, no_cache } + }; +} + +/** + * @description 获取群列表 + */ +export function getGroupList() { + return { + action: 'get_group_list', + params: { } + }; +} + +/** + * @description 获取群成员信息 + * @param group_id 群号 + * @param user_id QQ 号 + * @param no_cache 是否不使用缓存(使用缓存可能更新不及时,但响应更快) + */ +export function getGroupMemberInfo(group_id: number, user_id: number, no_cache: boolean = false) { + return { + action: 'get_group_member_info', + params: { group_id, user_id, no_cache } + }; +} + +/** + * @description 获取群成员列表 + * @param group_id 群号 + */ +export function getGroupMemberList(group_id: number) { + return { + action: 'get_group_member_list', + params: { group_id } + }; +} + +/** + * @description 获取群荣誉信息 + * @param group_id 群号 + * @param type 要获取的群荣誉类型,可传入 talkative performer legend strong_newbie emotion 以分别获取单个类型的群荣誉数据,或传入 all 获取所有数据 + */ +export function getGroupHonorInfo(group_id: number, type: string) { + return { + action: 'get_group_honor_info', + params: { group_id, type } + }; +} + +/** + * @description 获取 Cookies + * @param domain 需要获取 cookies 的域名 + */ +export function getCookies(domain: string = "") { + return { + action: 'get_cookies', + params: { domain } + }; +} + +/** + * @description 获取 CSRF Token + */ +export function getCsrfToken() { + return { + action: 'get_csrf_token', + params: { } + }; +} + +/** + * @description 获取 QQ 相关接口凭证 + */ +export function getCredentials() { + return { + action: 'get_credentials', + params: { } + }; +} + +/** + * @description 获取语音 + */ +export function getRecord() { + return { + action: 'get_record', + params: { } + }; +} + +/** + * @description 获取图片 + * @param file 收到的图片文件名(消息段的 file 参数),如 6B4DE3DFD1BD271E3297859D41C530F5.jpg + */ +export function getImage(file: string) { + return { + action: 'get_image', + params: { file } + }; +} + +/** + * @description 检查是否可以发送图片 + */ +export function canSendImage() { + return { + action: 'can_send_image', + params: { } + }; +} + +/** + * @description 检查是否可以发送语音 + */ +export function canSendRecord() { + return { + action: 'can_send_record', + params: { } + }; +} + +/** + * @description 获取运行状态 + */ +export function getStatus() { + return { + action: 'get_status', + params: { } + }; +} + +/** + * @description 获取版本信息 + */ +export function getVersionInfo() { + return { + action: 'get_version_info', + params: { } + }; +} + +/** + * @description 重启 OneBot 实现 + */ +export function setRestart() { + return { + action: 'set_restart', + params: { } + }; +} + +/** + * @description 清理缓存 + */ +export function cleanCache() { + return { + action: 'clean_cache', + params: { } + }; +} + diff --git a/bot/event.ts b/bot/event.ts new file mode 100644 index 0000000..e5cc4ff --- /dev/null +++ b/bot/event.ts @@ -0,0 +1,50 @@ +import type * as Lagrange from './type'; + +import lagrangeMapper from './lagrange-mapping'; + +function runPipe(message: Lagrange.Message) { + switch (message.post_type) { + case 'message': messagePipe(message); break; + case 'notice': noticePipe(message); break; + case 'request': requestPipe(message); break; + default: break; + } +} + +// 处理 message 类型的 post_type 的 +function messagePipe(message: Lagrange.MessagePostType) { + switch (message.message_type) { + case 'private': + + break; + case 'group': + + break; + default: + break; + } +} + +// 处理 notice 类型的 post_type 消息 +function noticePipe(message: Lagrange.NoticePostType) { + +} + +// 处理 request 类型的 post_type 消息 +function requestPipe(message: Lagrange.RequestPostType) { + +} + +export function onMessage(event: Buffer) { + const messageBuffer = event.toString('utf-8'); + const messageJson = JSON.parse(messageBuffer) as Lagrange.Message; + // 忽略系统 message + if (messageJson.post_type !== 'meta_event') { + runPipe(messageJson); + } +} + + +export function onClose() { + console.log('服务器连接关闭'); +} \ No newline at end of file diff --git a/bot/impl.ts b/bot/impl.ts new file mode 100644 index 0000000..7edd461 --- /dev/null +++ b/bot/impl.ts @@ -0,0 +1,13 @@ +import lagrangeMapper from './lagrange-mapping'; +import type * as Lagrange from './type'; + + +class Impl { + + @lagrangeMapper.onPrivateUser({ user_id: 1193466151 }) + async handleJinhui(message: Lagrange.PrivateMessage) { + + } + + +} \ No newline at end of file diff --git a/bot/plugins.ts b/bot/plugins.ts new file mode 100644 index 0000000..0c99393 --- /dev/null +++ b/bot/plugins.ts @@ -0,0 +1,31 @@ +import type * as Lagrange from './type'; + +class Plugins { + registeredPlugins: Map; + constructor() { + + } + + public register() { + return function(target: any, propertyKey: string, descriptor: PropertyDecorator) { + + } + } + + public use(name: string) { + return function(target: any, propertyKey: string, descriptor: PropertyDecorator) { + + } + } +} + +const plugins = new Plugins(); +export default plugins; + + +class Impl { + + echo(message: Lagrange.CommonMessage) { + + } +} \ No newline at end of file diff --git a/bot/type.ts b/bot/type.ts new file mode 100644 index 0000000..ed3b917 --- /dev/null +++ b/bot/type.ts @@ -0,0 +1,207 @@ +/** + * @author 锦恢 + * @email 1193466151@qq.com + * @description Lagrange.Core 前端接口 + * @comment 详细的接口信息来源 + * - https://github.com/botuniverse/onebot-11/blob/master/api/public.md + * - https://docs.go-cqhttp.org/reference/data_struct.html + */ + +export interface HeartBeatStatus { + app_initialized: boolean, + app_enabled: boolean, + app_good: boolean, + online: boolean, + good: boolean +} + +export type MetaEventType = 'heartbeat' | 'lifecycle'; + +export interface HeartBeatMessage { + interval: number, + status: HeartBeatStatus, + meta_event_type: 'heartbeat', + time: number, + self_id: number, + post_type: 'meta_event' +} + +export interface Sender { + user_id: number, + nickname: string, + sex: 'unknown' | 'male' | 'female', + card?: string, + age?: number, + area?: string, + level?: string, // 群聊等级,但是是 string + role?: string, + title?: string +} + +export interface MsgText { + type: 'text', + data: { + text: string + } +} + +export interface MsgImage { + type: 'image', + data: { + file: string, + url: string, + // 在简略窗口可以看到的信息,对于图片来说,这就是 [图片] + summary: string + } +} + +export interface MsgFace { + type: 'face', + data: { + id: string + } +} + +export interface MsgAt { + type: 'at', + data: { + qq: string + } +} + +export interface MsgFile { + // 一般是 '' + id: string, + // 文件名 + name: string, + // 文件大小,单位:字节 + size: number, + // id + busid: number, + // 链接 IPv4 + url: string +} + +export interface MetaMessage { + post_type: 'meta_event', + [msg: string]: any +} + +export interface CommonMessage { + // 事件类型 + post_type: 'message', + // 信息来自私聊还是群聊 + message_type?: 'private' | 'group', + // 发送信息的是朋友还是群友/陌生人 + sub_type?: 'friend' | 'normal', + // 消息的编号 + message_id?: number, + // 群号 + group_id?: number, + // 发消息的人的 QQ 号 + user_id: number, + // 是否为匿名发言,一般都是 null + anonymous?: null | boolean, + // 消息内容(结构化) + message?: MsgText | MsgImage | MsgFace | MsgAt, + // 消息内容(纯文本) + raw_message?: string, + // 发送的时间戳 + time: number, + // 自己的 id + self_id: number, + // 发送的文件 + // 默认字体大小,一般都是 0 + font?: number +} + +export interface PrivateMessage { + // 事件类型 + post_type: 'message', + // 信息来自私聊还是群聊 + message_type: 'private', + // 消息的编号 + message_id: number, + // 发消息的人的 QQ 号 + user_id: number, + // 消息内容(结构化) + message: MsgText | MsgImage | MsgFace | MsgAt, + // 消息内容(纯文本) + raw_message: string, + // 发送的时间戳 + time: number, + // 自己的 id + self_id: number, + // 默认字体大小,一般都是 0 + font?: number +} + +export interface GroupMessage { + // 事件类型 + post_type: 'message', + // 信息来自私聊还是群聊 + message_type: 'group', + // 发送信息的是朋友还是群友/陌生人 + sub_type: 'friend' | 'normal', + // 消息的编号 + message_id: number, + // 群号 + group_id: number, + // 发消息的人的 QQ 号 + user_id: number, + // 是否为匿名发言,一般都是 null + anonymous: null | boolean, + // 消息内容(结构化) + message: MsgText | MsgImage | MsgFace | MsgAt, + // 消息内容(纯文本) + raw_message: string, + // 发送的时间戳 + time: number, + // 自己的 id + self_id: number, + // 发送的文件 + // 默认字体大小,一般都是 0 + font?: number +} + +export interface FileMessage { + post_type: 'notice', + user_id: number, + file: MsgFile, + notice_type?: 'offline_file', + time: number, + self_id: number +} + +// 加群或者加好友 +export interface AddMessage { + post_type: 'request', + sub_type: 'add', + user_id: number, + group_id: number, + // 默认为 0 代表没有邀请者 + invitor_id: number, + request_type: 'private' | 'group', + // 群问题和申请者的回答 + comment: string, + flag: string, + time: number, + self_id: number, +} + +// 同意 +export interface ApproveMessage { + post_type: 'notice', + sub_type: 'approve', + group_id: number, + operator_id: number, + user_id: number, + notice_type: 'group_increase', + time: number, + self_id: number, +} + +export type Message = MetaMessage | PrivateMessage | GroupMessage | FileMessage | AddMessage | ApproveMessage; +export type MessagePostType = PrivateMessage | GroupMessage; +export type NoticePostType = FileMessage | ApproveMessage; +export type RequestPostType = AddMessage; \ No newline at end of file diff --git a/scripts/make_ts_api.py b/scripts/make_ts_api.py new file mode 100644 index 0000000..e9e4a13 --- /dev/null +++ b/scripts/make_ts_api.py @@ -0,0 +1,123 @@ +import markdown +import re +from bs4 import BeautifulSoup, Tag + +"""/** + * @description 发送私聊消息 + * @param user_id 对方 QQ 号 + * @param message 要发送的内容 + * @param auto_escape 消息内容是否作为纯文本发送(即不解析 CQ 码),只在 message 字段是字符串时有效 + */ +function send_private_msg(user_id: number, message: Lagrange.Message, auto_escape: boolean = false) { + return { + action: 'send_private_msg', + params: { user_id, message, auto_escape } + }; +}""" + +template = """/** + * @description %s%s */ +export function %s(%s) { + return { + action: '%s', + params: { %s } + }; +} + +""" + +onebot_document = open('./scripts/onebot.md', 'r', encoding='utf-8').read() +html = markdown.markdown(onebot_document) +soup = BeautifulSoup(html, 'html.parser') + +def snake_to_camel(s, capitalize_first_letter=False): + components = s.split('_') + camel = ''.join(x.capitalize() for x in components) + if not capitalize_first_letter: + camel = camel[0].lower() + camel[1:] + + return camel + +def next_node(el: Tag): + p = el.next_sibling + while len(p.text.strip()) == 0: + p = p.next_sibling + return p + +tss = """/** + * @author 锦恢 + * @email 1193466151@qq.com + * @description Lagrange.Core 前端接口 + * @comment 接口调用详细参考文档 + * - https://github.com/botuniverse/onebot-11/blob/master/communication/ws.md + */ + +import * as Lagrange from '../type'; + +""" + +for el in soup.find_all('h2'): + el: Tag + + function_name = None + function_desc = None + for child in el.children: + if child.name == 'code': + function_name = child.text + elif child.name is None: + function_desc = child.text + + if function_name and function_desc: + ts_func_name = snake_to_camel(function_name) + + title2 = next_node(el) + table = next_node(title2) + + count = 0 + params = [] + for line in table.text.strip().split('\n'): + count += 1 + if count >= 3: + splits = [l for l in line.split('|') if len(l.strip()) > 0] + print(splits) + if len(splits) == 4: + param = { + 'name': splits[0].strip(), + 'type': splits[1].strip().split()[0], + 'default': splits[2].strip(), + 'desc': splits[3].strip() + } + elif len(splits) == 3: + param = { + 'name': splits[0].strip(), + 'type': splits[1].strip().split()[0], + 'default': '-', + 'desc': splits[2].strip() + } + + if param['type'] == 'message': + param['type'] = 'Lagrange.Message' + + params.append(param) + + t1 = function_desc + t2 = '\n' + for param in params: + t2 += ' * @param {} {}\n'.format(param['name'], param['desc']) + t3 = ts_func_name + t4 = [] + for param in params: + if param['default'] == '-': + t4.append('{}: {}'.format(param['name'], param['type'])) + for param in params: + if param['default'] != '-': + t4.append('{}: {} = {}'.format(param['name'], param['type'], param['default'])) + t4 = ', '.join(t4) + t5 = function_name + t6 = [param['name'] for param in params] + t6 = ', '.join(t6) + ts_code = template % (t1, t2, t3, t4, t5, t6) + + tss += ts_code + +open('./bot/api/onebot.ts', 'w', encoding='utf-8').write(tss) \ No newline at end of file diff --git a/scripts/onebot.md b/scripts/onebot.md new file mode 100644 index 0000000..9b59765 --- /dev/null +++ b/scripts/onebot.md @@ -0,0 +1,634 @@ +# 公开 API + +- [`send_private_msg` 发送私聊消息](#send_private_msg-发送私聊消息) +- [`send_group_msg` 发送群消息](#send_group_msg-发送群消息) +- [`send_msg` 发送消息](#send_msg-发送消息) +- [`delete_msg` 撤回消息](#delete_msg-撤回消息) +- [`get_msg` 获取消息](#get_msg-获取消息) +- [`get_forward_msg` 获取合并转发消息](#get_forward_msg-获取合并转发消息) +- [`send_like` 发送好友赞](#send_like-发送好友赞) +- [`set_group_kick` 群组踢人](#set_group_kick-群组踢人) +- [`set_group_ban` 群组单人禁言](#set_group_ban-群组单人禁言) +- [`set_group_anonymous_ban` 群组匿名用户禁言](#set_group_anonymous_ban-群组匿名用户禁言) +- [`set_group_whole_ban` 群组全员禁言](#set_group_whole_ban-群组全员禁言) +- [`set_group_admin` 群组设置管理员](#set_group_admin-群组设置管理员) +- [`set_group_anonymous` 群组匿名](#set_group_anonymous-群组匿名) +- [`set_group_card` 设置群名片(群备注)](#set_group_card-设置群名片群备注) +- [`set_group_name` 设置群名](#set_group_name-设置群名) +- [`set_group_leave` 退出群组](#set_group_leave-退出群组) +- [`set_group_special_title` 设置群组专属头衔](#set_group_special_title-设置群组专属头衔) +- [`set_friend_add_request` 处理加好友请求](#set_friend_add_request-处理加好友请求) +- [`set_group_add_request` 处理加群请求/邀请](#set_group_add_request-处理加群请求邀请) +- [`get_login_info` 获取登录号信息](#get_login_info-获取登录号信息) +- [`get_stranger_info` 获取陌生人信息](#get_stranger_info-获取陌生人信息) +- [`get_friend_list` 获取好友列表](#get_friend_list-获取好友列表) +- [`get_group_info` 获取群信息](#get_group_info-获取群信息) +- [`get_group_list` 获取群列表](#get_group_list-获取群列表) +- [`get_group_member_info` 获取群成员信息](#get_group_member_info-获取群成员信息) +- [`get_group_member_list` 获取群成员列表](#get_group_member_list-获取群成员列表) +- [`get_group_honor_info` 获取群荣誉信息](#get_group_honor_info-获取群荣誉信息) +- [`get_cookies` 获取 Cookies](#get_cookies-获取-cookies) +- [`get_csrf_token` 获取 CSRF Token](#get_csrf_token-获取-csrf-token) +- [`get_credentials` 获取 QQ 相关接口凭证](#get_credentials-获取-qq-相关接口凭证) +- [`get_record` 获取语音](#get_record-获取语音) +- [`get_image` 获取图片](#get_image-获取图片) +- [`can_send_image` 检查是否可以发送图片](#can_send_image-检查是否可以发送图片) +- [`can_send_record` 检查是否可以发送语音](#can_send_record-检查是否可以发送语音) +- [`get_status` 获取运行状态](#get_status-获取运行状态) +- [`get_version_info` 获取版本信息](#get_version_info-获取版本信息) +- [`set_restart` 重启 OneBot 实现](#set_restart-重启-onebot-实现) +- [`clean_cache` 清理缓存](#clean_cache-清理缓存) + +## `send_private_msg` 发送私聊消息 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `user_id` | number | - | 对方 QQ 号 | +| `message` | message | - | 要发送的内容 | +| `auto_escape` | boolean | `false` | 消息内容是否作为纯文本发送(即不解析 CQ 码),只在 `message` 字段是字符串时有效 | + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `message_id` | number (int32) | 消息 ID | + +## `send_group_msg` 发送群消息 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `group_id` | number | - | 群号 | +| `message` | message | - | 要发送的内容 | +| `auto_escape` | boolean | `false` | 消息内容是否作为纯文本发送(即不解析 CQ 码),只在 `message` 字段是字符串时有效 | + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `message_id` | number (int32) | 消息 ID | + +## `send_msg` 发送消息 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `message_type` | string | - | 消息类型,支持 `private`、`group`,分别对应私聊、群组,如不传入,则根据传入的 `*_id` 参数判断 | +| `user_id` | number | - | 对方 QQ 号(消息类型为 `private` 时需要) | +| `group_id` | number | - | 群号(消息类型为 `group` 时需要) | +| `message` | message | - | 要发送的内容 | +| `auto_escape` | boolean | `false` | 消息内容是否作为纯文本发送(即不解析 CQ 码),只在 `message` 字段是字符串时有效 | + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `message_id` | number (int32) | 消息 ID | + +## `delete_msg` 撤回消息 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `message_id` | number (int32) | - | 消息 ID | + +### 响应数据 + +无 + +## `get_msg` 获取消息 + +### 参数 + +| 字段名 | 数据类型 | 说明 | +| ------------ | ----- | ------ | +| `message_id` | number (int32) | 消息 ID | + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ------------ | ------- | ---------- | +| `time` | number (int32) | 发送时间 | +| `message_type` | string | 消息类型,同 [消息事件](../event/message.md) | +| `message_id` | number (int32) | 消息 ID | +| `real_id` | number (int32) | 消息真实 ID | +| `sender` | object | 发送人信息,同 [消息事件](../event/message.md) | +| `message` | message | 消息内容 | + +## `get_forward_msg` 获取合并转发消息 + +### 参数 + +| 字段名 | 数据类型 | 说明 | +| ------------ | ------ | ------ | +| `id` | string | 合并转发 ID | + +### 响应数据 + +| 字段名 | 类型 | 说明 | +| --- | --- | --- | +| `message` | message | 消息内容,使用 [消息的数组格式](../message/array.md) 表示,数组中的消息段全部为 [`node` 消息段](../message/segment.md#合并转发自定义节点) | + +## `send_like` 发送好友赞 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `user_id` | number | - | 对方 QQ 号 | +| `times` | number | 1 | 赞的次数,每个好友每天最多 10 次 | + +### 响应数据 + +无 + +## `set_group_kick` 群组踢人 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `group_id` | number | - | 群号 | +| `user_id` | number | - | 要踢的 QQ 号 | +| `reject_add_request` | boolean | `false` | 拒绝此人的加群请求 | + +### 响应数据 + +无 + +## `set_group_ban` 群组单人禁言 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `group_id` | number | - | 群号 | +| `user_id` | number | - | 要禁言的 QQ 号 | +| `duration` | number | `30 * 60` | 禁言时长,单位秒,0 表示取消禁言 | + +### 响应数据 + +无 + +## `set_group_anonymous_ban` 群组匿名用户禁言 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `group_id` | number | - | 群号 | +| `anonymous` | object | - | 可选,要禁言的匿名用户对象(群消息上报的 `anonymous` 字段) | +| `anonymous_flag` | string | - | 可选,要禁言的匿名用户的 flag(需从群消息上报的数据中获得) | +| `duration` | number | `30 * 60` | 禁言时长,单位秒,无法取消匿名用户禁言 | + +上面的 `anonymous` 和 `anonymous_flag` 两者任选其一传入即可,若都传入,则使用 `anonymous`。 + +### 响应数据 + +无 + +## `set_group_whole_ban` 群组全员禁言 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `group_id` | number | - | 群号 | +| `enable` | boolean | `true` | 是否禁言 | + +### 响应数据 + +无 + +## `set_group_admin` 群组设置管理员 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `group_id` | number | - | 群号 | +| `user_id` | number | - | 要设置管理员的 QQ 号 | +| `enable` | boolean | `true` | true 为设置,false 为取消 | + +### 响应数据 + +无 + +## `set_group_anonymous` 群组匿名 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `group_id` | number | - | 群号 | +| `enable` | boolean | `true` | 是否允许匿名聊天 | + +### 响应数据 + +无 + +## `set_group_card` 设置群名片(群备注) + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `group_id` | number | - | 群号 | +| `user_id` | number | - | 要设置的 QQ 号 | +| `card` | string | "" | 群名片内容,不填或空字符串表示删除群名片 | + +### 响应数据 + +无 + +## `set_group_name` 设置群名 + +### 参数 + +| 字段名 | 数据类型 | 说明 | +| -------- | ------ | ---- | +| `group_id` | number (int64) | 群号 | +| `group_name` | string | 新群名 | + +### 响应数据 + +无 + +## `set_group_leave` 退出群组 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `group_id` | number | - | 群号 | +| `is_dismiss` | boolean | `false` | 是否解散,如果登录号是群主,则仅在此项为 true 时能够解散 | + +### 响应数据 + +无 + +## `set_group_special_title` 设置群组专属头衔 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `group_id` | number | - | 群号 | +| `user_id` | number | - | 要设置的 QQ 号 | +| `special_title` | string | "" | 专属头衔,不填或空字符串表示删除专属头衔 | +| `duration` | number | `-1` | 专属头衔有效期,单位秒,-1 表示永久,不过此项似乎没有效果,可能是只有某些特殊的时间长度有效,有待测试 | + +### 响应数据 + +无 + +## `set_friend_add_request` 处理加好友请求 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `flag` | string | - | 加好友请求的 flag(需从上报的数据中获得) | +| `approve` | boolean | `true` | 是否同意请求 | +| `remark` | string | "" | 添加后的好友备注(仅在同意时有效) | + +### 响应数据 + +无 + +## `set_group_add_request` 处理加群请求/邀请 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `flag` | string | - | 加群请求的 flag(需从上报的数据中获得) | +| `sub_type` | string | - | `add` 或 `invite`,请求类型(需要和上报消息中的 `sub_type` 字段相符) | +| `approve` | boolean | `true` | 是否同意请求/邀请 | +| `reason` | string | "" | 拒绝理由(仅在拒绝时有效) | + +### 响应数据 + +无 + +## `get_login_info` 获取登录号信息 + +### 参数 + +无 + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `user_id` | number (int64) | QQ 号 | +| `nickname` | string | QQ 昵称 | + +## `get_stranger_info` 获取陌生人信息 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `user_id` | number | - | QQ 号 | +| `no_cache` | boolean | `false` | 是否不使用缓存(使用缓存可能更新不及时,但响应更快) | + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `user_id` | number (int64) | QQ 号 | +| `nickname` | string | 昵称 | +| `sex` | string | 性别,`male` 或 `female` 或 `unknown` | +| `age` | number (int32) | 年龄 | + +## `get_friend_list` 获取好友列表 + +### 参数 + +无 + +### 响应数据 + +响应内容为 JSON 数组,每个元素如下: + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `user_id` | number (int64) | QQ 号 | +| `nickname` | string | 昵称 | +| `remark` | string | 备注名 | + +## `get_group_info` 获取群信息 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `group_id` | number | - | 群号 | +| `no_cache` | boolean | `false` | 是否不使用缓存(使用缓存可能更新不及时,但响应更快) | + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `group_id` | number (int64) | 群号 | +| `group_name` | string | 群名称 | +| `member_count` | number (int32) | 成员数 | +| `max_member_count` | number (int32) | 最大成员数(群容量) | + +## `get_group_list` 获取群列表 + +### 参数 + +无 + +### 响应数据 + +响应内容为 JSON 数组,每个元素和上面的 `get_group_info` 接口相同。 + +## `get_group_member_info` 获取群成员信息 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `group_id` | number | - | 群号 | +| `user_id` | number | - | QQ 号 | +| `no_cache` | boolean | `false` | 是否不使用缓存(使用缓存可能更新不及时,但响应更快) | + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `group_id` | number (int64) | 群号 | +| `user_id` | number (int64) | QQ 号 | +| `nickname` | string | 昵称 | +| `card` | string | 群名片/备注 | +| `sex` | string | 性别,`male` 或 `female` 或 `unknown` | +| `age` | number (int32) | 年龄 | +| `area` | string | 地区 | +| `join_time` | number (int32) | 加群时间戳 | +| `last_sent_time` | number (int32) | 最后发言时间戳 | +| `level` | string | 成员等级 | +| `role` | string | 角色,`owner` 或 `admin` 或 `member` | +| `unfriendly` | boolean | 是否不良记录成员 | +| `title` | string | 专属头衔 | +| `title_expire_time` | number (int32) | 专属头衔过期时间戳 | +| `card_changeable` | boolean | 是否允许修改群名片 | + +## `get_group_member_list` 获取群成员列表 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `group_id` | number (int64) | - | 群号 | + +### 响应数据 + +响应内容为 JSON 数组,每个元素的内容和上面的 `get_group_member_info` 接口相同,但对于同一个群组的同一个成员,获取列表时和获取单独的成员信息时,某些字段可能有所不同,例如 `area`、`title` 等字段在获取列表时无法获得,具体应以单独的成员信息为准。 + +## `get_group_honor_info` 获取群荣誉信息 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `group_id` | number (int64) | - | 群号 | +| `type` | string | - | 要获取的群荣誉类型,可传入 `talkative` `performer` `legend` `strong_newbie` `emotion` 以分别获取单个类型的群荣誉数据,或传入 `all` 获取所有数据 | + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `group_id` | number (int64) | 群号 | +| `current_talkative` | object | 当前龙王,仅 `type` 为 `talkative` 或 `all` 时有数据 | +| `talkative_list` | array | 历史龙王,仅 `type` 为 `talkative` 或 `all` 时有数据 | +| `performer_list` | array | 群聊之火,仅 `type` 为 `performer` 或 `all` 时有数据 | +| `legend_list` | array | 群聊炽焰,仅 `type` 为 `legend` 或 `all` 时有数据 | +| `strong_newbie_list` | array | 冒尖小春笋,仅 `type` 为 `strong_newbie` 或 `all` 时有数据 | +| `emotion_list` | array | 快乐之源,仅 `type` 为 `emotion` 或 `all` 时有数据 | + +其中 `current_talkative` 字段的内容如下: + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `user_id` | number (int64) | QQ 号 | +| `nickname` | string | 昵称 | +| `avatar` | string | 头像 URL | +| `day_count` | number (int32) | 持续天数 | + +其它各 `*_list` 的每个元素是一个 JSON 对象,内容如下: + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `user_id` | number (int64) | QQ 号 | +| `nickname` | string | 昵称 | +| `avatar` | string | 头像 URL | +| `description` | string | 荣誉描述 | + +## `get_cookies` 获取 Cookies + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `domain` | string | "" | 需要获取 cookies 的域名 | + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `cookies` | string | Cookies | + +## `get_csrf_token` 获取 CSRF Token + +### 参数 + +无 + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `token` | number (int32) | CSRF Token | + +## `get_credentials` 获取 QQ 相关接口凭证 + +即上面两个接口的合并。 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `domain` | string | "" | 需要获取 cookies 的域名 | + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `cookies` | string | Cookies | +| `csrf_token` | number (int32) | CSRF Token | + +## `get_record` 获取语音 + +> **提示**:要使用此接口,通常需要安装 ffmpeg,请参考 OneBot 实现的相关说明。 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `file` | string | - | 收到的语音文件名(消息段的 `file` 参数),如 `0B38145AA44505000B38145AA4450500.silk` | +| `out_format` | string | - | 要转换到的格式,目前支持 `mp3`、`amr`、`wma`、`m4a`、`spx`、`ogg`、`wav`、`flac` | + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `file` | string | 转换后的语音文件路径,如 `/home/somebody/cqhttp/data/record/0B38145AA44505000B38145AA4450500.mp3` | + +## `get_image` 获取图片 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `file` | string | - | 收到的图片文件名(消息段的 `file` 参数),如 `6B4DE3DFD1BD271E3297859D41C530F5.jpg` | + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `file` | string | 下载后的图片文件路径,如 `/home/somebody/cqhttp/data/image/6B4DE3DFD1BD271E3297859D41C530F5.jpg` | + +## `can_send_image` 检查是否可以发送图片 + +### 参数 + +无 + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `yes` | boolean | 是或否 | + +## `can_send_record` 检查是否可以发送语音 + +### 参数 + +无 + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `yes` | boolean | 是或否 | + +## `get_status` 获取运行状态 + +### 参数 + +无 + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `online` | boolean | 当前 QQ 在线,`null` 表示无法查询到在线状态 | +| `good` | boolean | 状态符合预期,意味着各模块正常运行、功能正常,且 QQ 在线 | +| …… | - | OneBot 实现自行添加的其它内容 | + +通常情况下建议只使用 `online` 和 `good` 这两个字段来判断运行状态,因为根据 OneBot 实现的不同,其它字段可能完全不同。 + +## `get_version_info` 获取版本信息 + +### 参数 + +无 + +### 响应数据 + +| 字段名 | 数据类型 | 说明 | +| ----- | ------- | --- | +| `app_name` | string | 应用标识,如 `mirai-native` | +| `app_version` | string | 应用版本,如 `1.2.3` | +| `protocol_version` | string | OneBot 标准版本,如 `v11` | +| …… | - | OneBot 实现自行添加的其它内容 | + +## `set_restart` 重启 OneBot 实现 + +由于重启 OneBot 实现同时需要重启 API 服务,这意味着当前的 API 请求会被中断,因此需要异步地重启,接口返回的 `status` 是 `async`。 + +### 参数 + +| 字段名 | 数据类型 | 默认值 | 说明 | +| ----- | ------- | ----- | --- | +| `delay` | number | `0` | 要延迟的毫秒数,如果默认情况下无法重启,可以尝试设置延迟为 2000 左右 | + +### 响应数据 + +无 + +## `clean_cache` 清理缓存 + +用于清理积攒了太多的缓存文件。 + +### 参数 + +无 + +### 响应数据 + +无 + +
+ +| 上一节 | 下一节 | +| --- | --- | +| [API 概述](README.md) | [隐藏 API](hidden.md) | \ No newline at end of file