mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
commit
e988908784
@ -4,7 +4,7 @@
|
|||||||
"name": "LLOneBot",
|
"name": "LLOneBot",
|
||||||
"slug": "LLOneBot",
|
"slug": "LLOneBot",
|
||||||
"description": "实现 OneBot 11 和 Satori 协议,用于 QQ 机器人开发",
|
"description": "实现 OneBot 11 和 Satori 协议,用于 QQ 机器人开发",
|
||||||
"version": "4.0.3",
|
"version": "4.0.4",
|
||||||
"icon": "./icon.webp",
|
"icon": "./icon.webp",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
"cordis": "^3.18.1",
|
"cordis": "^3.18.1",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"cosmokit": "^1.6.3",
|
"cosmokit": "^1.6.3",
|
||||||
"express": "^5.0.0",
|
"express": "^5.0.1",
|
||||||
"fast-xml-parser": "^4.5.0",
|
"fast-xml-parser": "^4.5.0",
|
||||||
"fluent-ffmpeg": "^2.1.3",
|
"fluent-ffmpeg": "^2.1.3",
|
||||||
"minato": "^3.6.0",
|
"minato": "^3.6.0",
|
||||||
@ -42,7 +42,7 @@
|
|||||||
"electron": "^31.4.0",
|
"electron": "^31.4.0",
|
||||||
"electron-vite": "^2.3.0",
|
"electron-vite": "^2.3.0",
|
||||||
"protobufjs-cli": "^1.1.3",
|
"protobufjs-cli": "^1.1.3",
|
||||||
"typescript": "^5.6.2",
|
"typescript": "^5.6.3",
|
||||||
"vite": "^5.4.8",
|
"vite": "^5.4.8",
|
||||||
"vite-plugin-cp": "^4.0.8"
|
"vite-plugin-cp": "^4.0.8"
|
||||||
},
|
},
|
||||||
|
@ -34,7 +34,8 @@ export class ConfigUtil {
|
|||||||
enableWsReverse: false,
|
enableWsReverse: false,
|
||||||
messagePostFormat: 'array',
|
messagePostFormat: 'array',
|
||||||
enableHttpHeart: false,
|
enableHttpHeart: false,
|
||||||
listenLocalhost: false
|
listenLocalhost: false,
|
||||||
|
reportSelfMessage: false
|
||||||
}
|
}
|
||||||
const satoriDefault: SatoriConfig = {
|
const satoriDefault: SatoriConfig = {
|
||||||
enable: true,
|
enable: true,
|
||||||
@ -50,7 +51,6 @@ export class ConfigUtil {
|
|||||||
enableLocalFile2Url: false,
|
enableLocalFile2Url: false,
|
||||||
debug: false,
|
debug: false,
|
||||||
log: false,
|
log: false,
|
||||||
reportSelfMessage: false,
|
|
||||||
autoDeleteFile: false,
|
autoDeleteFile: false,
|
||||||
autoDeleteFileSecond: 60,
|
autoDeleteFileSecond: 60,
|
||||||
musicSignUrl: '',
|
musicSignUrl: '',
|
||||||
@ -73,6 +73,7 @@ export class ConfigUtil {
|
|||||||
this.checkOldConfig(jsonData.ob11, jsonData, 'httpPort', 'http')
|
this.checkOldConfig(jsonData.ob11, jsonData, 'httpPort', 'http')
|
||||||
this.checkOldConfig(jsonData.ob11, jsonData, 'httpHosts', 'hosts')
|
this.checkOldConfig(jsonData.ob11, jsonData, 'httpHosts', 'hosts')
|
||||||
this.checkOldConfig(jsonData.ob11, jsonData, 'wsPort', 'wsPort')
|
this.checkOldConfig(jsonData.ob11, jsonData, 'wsPort', 'wsPort')
|
||||||
|
this.checkOldConfig(jsonData.ob11, jsonData, 'reportSelfMessage', 'reportSelfMessage')
|
||||||
this.config = jsonData
|
this.config = jsonData
|
||||||
return this.config
|
return this.config
|
||||||
}
|
}
|
||||||
@ -86,8 +87,8 @@ export class ConfigUtil {
|
|||||||
private checkOldConfig(
|
private checkOldConfig(
|
||||||
currentConfig: OB11Config,
|
currentConfig: OB11Config,
|
||||||
oldConfig: Config,
|
oldConfig: Config,
|
||||||
currentKey: 'httpPort' | 'httpHosts' | 'wsPort',
|
currentKey: 'httpPort' | 'httpHosts' | 'wsPort' | 'reportSelfMessage',
|
||||||
oldKey: 'http' | 'hosts' | 'wsPort',
|
oldKey: 'http' | 'hosts' | 'wsPort' | 'reportSelfMessage',
|
||||||
) {
|
) {
|
||||||
// 迁移旧的配置到新配置,避免用户重新填写配置
|
// 迁移旧的配置到新配置,避免用户重新填写配置
|
||||||
const oldValue = oldConfig[oldKey]
|
const oldValue = oldConfig[oldKey]
|
||||||
|
@ -17,6 +17,7 @@ export interface OB11Config {
|
|||||||
*/
|
*/
|
||||||
enableQOAutoQuote?: boolean
|
enableQOAutoQuote?: boolean
|
||||||
listenLocalhost: boolean
|
listenLocalhost: boolean
|
||||||
|
reportSelfMessage: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SatoriConfig {
|
export interface SatoriConfig {
|
||||||
@ -33,7 +34,6 @@ export interface Config {
|
|||||||
heartInterval: number // ms
|
heartInterval: number // ms
|
||||||
enableLocalFile2Url?: boolean // 开启后,本地文件路径图片会转成http链接, 语音会转成base64
|
enableLocalFile2Url?: boolean // 开启后,本地文件路径图片会转成http链接, 语音会转成base64
|
||||||
debug?: boolean
|
debug?: boolean
|
||||||
reportSelfMessage?: boolean
|
|
||||||
log?: boolean
|
log?: boolean
|
||||||
autoDeleteFile?: boolean
|
autoDeleteFile?: boolean
|
||||||
autoDeleteFileSecond?: number
|
autoDeleteFileSecond?: number
|
||||||
@ -50,6 +50,8 @@ export interface Config {
|
|||||||
wsPort?: string
|
wsPort?: string
|
||||||
/** @deprecated */
|
/** @deprecated */
|
||||||
enableLLOB?: boolean
|
enableLLOB?: boolean
|
||||||
|
/** @deprecated */
|
||||||
|
reportSelfMessage?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CheckVersion {
|
export interface CheckVersion {
|
||||||
|
@ -53,7 +53,6 @@ function convert(ctx: Context, input: Input, options: FFmpegOptions, outputPath?
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function encodeSilk(ctx: Context, filePath: string) {
|
export async function encodeSilk(ctx: Context, filePath: string) {
|
||||||
try {
|
|
||||||
const file = await fsPromise.readFile(filePath)
|
const file = await fsPromise.readFile(filePath)
|
||||||
if (!isSilk(file)) {
|
if (!isSilk(file)) {
|
||||||
ctx.logger.info(`语音文件${filePath}需要转换成silk`)
|
ctx.logger.info(`语音文件${filePath}需要转换成silk`)
|
||||||
@ -93,10 +92,6 @@ export async function encodeSilk(ctx: Context, filePath: string) {
|
|||||||
duration,
|
duration,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
ctx.logger.error('convert silk failed', (err as Error).stack)
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type OutFormat = 'mp3' | 'amr' | 'wma' | 'm4a' | 'spx' | 'ogg' | 'wav' | 'flac'
|
type OutFormat = 'mp3' | 'amr' | 'wma' | 'm4a' | 'spx' | 'ogg' | 'wav' | 'flac'
|
||||||
|
@ -183,7 +183,6 @@ function onLoad() {
|
|||||||
heartInterval: config.heartInterval,
|
heartInterval: config.heartInterval,
|
||||||
token: config.token!,
|
token: config.token!,
|
||||||
debug: config.debug!,
|
debug: config.debug!,
|
||||||
reportSelfMessage: config.reportSelfMessage!,
|
|
||||||
musicSignUrl: config.musicSignUrl,
|
musicSignUrl: config.musicSignUrl,
|
||||||
enableLocalFile2Url: config.enableLocalFile2Url!,
|
enableLocalFile2Url: config.enableLocalFile2Url!,
|
||||||
ffmpeg: config.ffmpeg,
|
ffmpeg: config.ffmpeg,
|
||||||
|
@ -201,6 +201,16 @@ export class NTQQFileApi extends Service {
|
|||||||
)
|
)
|
||||||
return data.notifyInfo.filePath
|
return data.notifyInfo.filePath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async ocrImage(path: string) {
|
||||||
|
return await invoke(
|
||||||
|
'nodeIKernelNodeMiscService/wantWinScreenOCR',
|
||||||
|
[
|
||||||
|
{ url: path },
|
||||||
|
{ timeout: 5000 }
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NTQQFileCacheApi extends Service {
|
export class NTQQFileCacheApi extends Service {
|
||||||
|
@ -16,7 +16,7 @@ export class NTQQFriendApi extends Service {
|
|||||||
|
|
||||||
/** 大于或等于 26702 应使用 getBuddyV2 */
|
/** 大于或等于 26702 应使用 getBuddyV2 */
|
||||||
async getFriends() {
|
async getFriends() {
|
||||||
const data = await invoke<{
|
const res = await invoke<{
|
||||||
data: {
|
data: {
|
||||||
categoryId: number
|
categoryId: number
|
||||||
categroyName: string
|
categroyName: string
|
||||||
@ -28,11 +28,7 @@ export class NTQQFriendApi extends Service {
|
|||||||
cbCmd: ReceiveCmdS.FRIENDS,
|
cbCmd: ReceiveCmdS.FRIENDS,
|
||||||
afterFirstCmd: false
|
afterFirstCmd: false
|
||||||
})
|
})
|
||||||
const _friends: Friend[] = []
|
return res.data.flatMap(e => e.buddyList)
|
||||||
for (const item of data.data) {
|
|
||||||
_friends.push(...item.buddyList)
|
|
||||||
}
|
|
||||||
return _friends
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleFriendRequest(friendUid: string, reqTime: string, accept: boolean) {
|
async handleFriendRequest(friendUid: string, reqTime: string, accept: boolean) {
|
||||||
|
@ -296,4 +296,30 @@ export class NTQQGroupApi extends Service {
|
|||||||
async setGroupAvatar(groupCode: string, path: string) {
|
async setGroupAvatar(groupCode: string, path: string) {
|
||||||
return await invoke('nodeIKernelGroupService/setHeader', [{ path, groupCode }])
|
return await invoke('nodeIKernelGroupService/setHeader', [{ path, groupCode }])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async searchMember(groupCode: string, keyword: string) {
|
||||||
|
await invoke('nodeIKernelGroupListener/onSearchMemberChange', [], {
|
||||||
|
registerEvent: true
|
||||||
|
})
|
||||||
|
const sceneId = await invoke(NTMethod.GROUP_MEMBER_SCENE, [{
|
||||||
|
groupCode,
|
||||||
|
scene: 'groupMemberList_MainWindow'
|
||||||
|
}])
|
||||||
|
const data = await invoke<{
|
||||||
|
sceneId: string
|
||||||
|
keyword: string
|
||||||
|
infos: Map<string, GroupMember>
|
||||||
|
}>(
|
||||||
|
'nodeIKernelGroupService/searchMember',
|
||||||
|
[{ sceneId, keyword }],
|
||||||
|
{
|
||||||
|
cbCmd: 'nodeIKernelGroupListener/onSearchMemberChange',
|
||||||
|
cmdCB: payload => {
|
||||||
|
return payload.sceneId === sceneId && payload.keyword === keyword
|
||||||
|
},
|
||||||
|
afterFirstCmd: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return data.infos
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,18 +108,23 @@ export class NTQQUserApi extends Service {
|
|||||||
async getUidByUinV1(uin: string, groupCode?: string) {
|
async getUidByUinV1(uin: string, groupCode?: string) {
|
||||||
let uid = (await invoke('nodeIKernelUixConvertService/getUid', [{ uins: [uin] }])).uidInfo.get(uin)
|
let uid = (await invoke('nodeIKernelUixConvertService/getUid', [{ uins: [uin] }])).uidInfo.get(uin)
|
||||||
if (!uid) {
|
if (!uid) {
|
||||||
const unveifyUid = (await this.getUserDetailInfoByUin(uin)).info.uid //特殊转换
|
const friends = await this.ctx.ntFriendApi.getFriends()
|
||||||
if (unveifyUid.indexOf('*') === -1) {
|
|
||||||
uid = unveifyUid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!uid) {
|
|
||||||
const friends = await this.ctx.ntFriendApi.getFriends() //从好友列表转
|
|
||||||
uid = friends.find(item => item.uin === uin)?.uid
|
uid = friends.find(item => item.uin === uin)?.uid
|
||||||
}
|
}
|
||||||
if (!uid && groupCode) {
|
if (!uid && groupCode) {
|
||||||
const members = await this.ctx.ntGroupApi.getGroupMembers(groupCode)
|
let member = await this.ctx.ntGroupApi.searchMember(groupCode, uin)
|
||||||
uid = Array.from(members.values()).find(e => e.uin === uin)?.uid
|
if (member.size === 0) {
|
||||||
|
await this.ctx.ntGroupApi.getGroupMembers(groupCode, 1)
|
||||||
|
await this.ctx.sleep(30)
|
||||||
|
member = await this.ctx.ntGroupApi.searchMember(groupCode, uin)
|
||||||
|
}
|
||||||
|
uid = member.values().find(e => e.uin === uin)?.uid
|
||||||
|
}
|
||||||
|
if (!uid) {
|
||||||
|
const unveifyUid = (await this.getUserDetailInfoByUin(uin)).info.uid
|
||||||
|
if (!unveifyUid.includes('*')) {
|
||||||
|
uid = unveifyUid
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return uid
|
return uid
|
||||||
}
|
}
|
||||||
|
@ -205,9 +205,6 @@ class Core extends Service {
|
|||||||
})
|
})
|
||||||
|
|
||||||
registerReceiveHook<{ msgRecord: RawMessage }>(ReceiveCmdS.SELF_SEND_MSG, payload => {
|
registerReceiveHook<{ msgRecord: RawMessage }>(ReceiveCmdS.SELF_SEND_MSG, payload => {
|
||||||
if (!this.config.reportSelfMessage) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sentMsgIds.set(payload.msgRecord.msgId, true)
|
sentMsgIds.set(payload.msgRecord.msgId, true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -210,13 +210,9 @@ export namespace SendElement {
|
|||||||
|
|
||||||
export async function ptt(ctx: Context, pttPath: string): Promise<SendPttElement> {
|
export async function ptt(ctx: Context, pttPath: string): Promise<SendPttElement> {
|
||||||
const { converted, path: silkPath, duration } = await encodeSilk(ctx, pttPath)
|
const { converted, path: silkPath, duration } = await encodeSilk(ctx, pttPath)
|
||||||
if (!silkPath) {
|
|
||||||
throw '语音转换失败, 请检查语音文件是否正常'
|
|
||||||
}
|
|
||||||
// log("生成语音", silkPath, duration);
|
|
||||||
const { md5, fileName, path, fileSize } = await ctx.ntFileApi.uploadFile(silkPath, ElementType.Ptt)
|
const { md5, fileName, path, fileSize } = await ctx.ntFileApi.uploadFile(silkPath, ElementType.Ptt)
|
||||||
if (fileSize === 0) {
|
if (fileSize === 0) {
|
||||||
throw '文件异常,大小为0'
|
throw new Error('文件异常,大小为 0')
|
||||||
}
|
}
|
||||||
if (converted) {
|
if (converted) {
|
||||||
unlink(silkPath)
|
unlink(silkPath)
|
||||||
|
@ -14,7 +14,8 @@ import {
|
|||||||
NodeIKernelRichMediaService,
|
NodeIKernelRichMediaService,
|
||||||
NodeIKernelTicketService,
|
NodeIKernelTicketService,
|
||||||
NodeIKernelTipOffService,
|
NodeIKernelTipOffService,
|
||||||
NodeIKernelRobotService
|
NodeIKernelRobotService,
|
||||||
|
NodeIKernelNodeMiscService
|
||||||
} from './services'
|
} from './services'
|
||||||
|
|
||||||
export enum NTClass {
|
export enum NTClass {
|
||||||
@ -94,6 +95,7 @@ interface NTService {
|
|||||||
nodeIKernelTicketService: NodeIKernelTicketService
|
nodeIKernelTicketService: NodeIKernelTicketService
|
||||||
nodeIKernelTipOffService: NodeIKernelTipOffService
|
nodeIKernelTipOffService: NodeIKernelTipOffService
|
||||||
nodeIKernelRobotService: NodeIKernelRobotService
|
nodeIKernelRobotService: NodeIKernelRobotService
|
||||||
|
nodeIKernelNodeMiscService: NodeIKernelNodeMiscService
|
||||||
}
|
}
|
||||||
|
|
||||||
interface InvokeOptions<ReturnType> {
|
interface InvokeOptions<ReturnType> {
|
||||||
|
@ -125,4 +125,6 @@ export interface NodeIKernelGroupService {
|
|||||||
removeGroupEssence(param: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<unknown>
|
removeGroupEssence(param: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<unknown>
|
||||||
|
|
||||||
setHeader(args: unknown[]): Promise<GeneralCallResult>
|
setHeader(args: unknown[]): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
searchMember(sceneId: string, keyword: string): Promise<void>
|
||||||
}
|
}
|
||||||
|
15
src/ntqqapi/services/NodeIKernelNodeMiscService.ts
Normal file
15
src/ntqqapi/services/NodeIKernelNodeMiscService.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export interface NodeIKernelNodeMiscService {
|
||||||
|
wantWinScreenOCR(...args: unknown[]): Promise<{
|
||||||
|
code: number
|
||||||
|
errMsg: string
|
||||||
|
result: {
|
||||||
|
text: string
|
||||||
|
[key: `pt${number}`]: {
|
||||||
|
x: string
|
||||||
|
y: string
|
||||||
|
}
|
||||||
|
charBox: unknown[]
|
||||||
|
score: ''
|
||||||
|
}[]
|
||||||
|
}>
|
||||||
|
}
|
@ -10,3 +10,4 @@ export * from './NodeIKernelRichMediaService'
|
|||||||
export * from './NodeIKernelTicketService'
|
export * from './NodeIKernelTicketService'
|
||||||
export * from './NodeIKernelTipOffService'
|
export * from './NodeIKernelTipOffService'
|
||||||
export * from './NodeIKernelRobotService'
|
export * from './NodeIKernelRobotService'
|
||||||
|
export * from './NodeIKernelNodeMiscService'
|
||||||
|
63
src/onebot11/action/go-cqhttp/OCRImage.ts
Normal file
63
src/onebot11/action/go-cqhttp/OCRImage.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { BaseAction, Schema } from '../BaseAction'
|
||||||
|
import { ActionName } from '../types'
|
||||||
|
import { uri2local } from '@/common/utils/file'
|
||||||
|
import { access, unlink } from 'node:fs/promises'
|
||||||
|
|
||||||
|
interface Payload {
|
||||||
|
image: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TextDetection {
|
||||||
|
text: string
|
||||||
|
confidence: number
|
||||||
|
coordinates: {
|
||||||
|
x: number //int32
|
||||||
|
y: number
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Response {
|
||||||
|
texts: TextDetection[]
|
||||||
|
language: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class OCRImage extends BaseAction<Payload, Response> {
|
||||||
|
actionName = ActionName.GoCQHTTP_OCRImage
|
||||||
|
payloadSchema = Schema.object({
|
||||||
|
image: Schema.string().required()
|
||||||
|
})
|
||||||
|
|
||||||
|
protected async _handle(payload: Payload) {
|
||||||
|
const { errMsg, isLocal, path, success } = await uri2local(this.ctx, payload.image, true)
|
||||||
|
if (!success) {
|
||||||
|
throw new Error(errMsg)
|
||||||
|
}
|
||||||
|
await access(path)
|
||||||
|
|
||||||
|
const data = await this.ctx.ntFileApi.ocrImage(path)
|
||||||
|
if (!isLocal) {
|
||||||
|
unlink(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
const texts = data.result.map(item => {
|
||||||
|
const ret: TextDetection = {
|
||||||
|
text: item.text,
|
||||||
|
confidence: 1,
|
||||||
|
coordinates: []
|
||||||
|
}
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
const pt = item[`pt${i + 1}`]
|
||||||
|
ret.coordinates.push({
|
||||||
|
x: parseInt(pt.x),
|
||||||
|
y: parseInt(pt.y)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
texts,
|
||||||
|
language: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -73,6 +73,7 @@ import { GetGroupFileUrl } from './go-cqhttp/GetGroupFileUrl'
|
|||||||
import { GetGroupNotice } from './go-cqhttp/GetGroupNotice'
|
import { GetGroupNotice } from './go-cqhttp/GetGroupNotice'
|
||||||
import { GetRobotUinRange } from './llonebot/GetRobotUinRange'
|
import { GetRobotUinRange } from './llonebot/GetRobotUinRange'
|
||||||
import { DeleteFriend } from './go-cqhttp/DeleteFriend'
|
import { DeleteFriend } from './go-cqhttp/DeleteFriend'
|
||||||
|
import { OCRImage } from './go-cqhttp/OCRImage'
|
||||||
|
|
||||||
export function initActionMap(adapter: Adapter) {
|
export function initActionMap(adapter: Adapter) {
|
||||||
const actionHandlers = [
|
const actionHandlers = [
|
||||||
@ -151,6 +152,7 @@ export function initActionMap(adapter: Adapter) {
|
|||||||
new GetGroupFileUrl(adapter),
|
new GetGroupFileUrl(adapter),
|
||||||
new GetGroupNotice(adapter),
|
new GetGroupNotice(adapter),
|
||||||
new DeleteFriend(adapter),
|
new DeleteFriend(adapter),
|
||||||
|
new OCRImage(adapter),
|
||||||
]
|
]
|
||||||
const actionMap = new Map<string, BaseAction<any, unknown>>()
|
const actionMap = new Map<string, BaseAction<any, unknown>>()
|
||||||
for (const action of actionHandlers) {
|
for (const action of actionHandlers) {
|
||||||
|
@ -86,4 +86,5 @@ export enum ActionName {
|
|||||||
GoCQHTTP_GetGroupFileUrl = 'get_group_file_url',
|
GoCQHTTP_GetGroupFileUrl = 'get_group_file_url',
|
||||||
GoCQHTTP_GetGroupNotice = '_get_group_notice',
|
GoCQHTTP_GetGroupNotice = '_get_group_notice',
|
||||||
GoCQHTTP_DeleteFriend = 'delete_friend',
|
GoCQHTTP_DeleteFriend = 'delete_friend',
|
||||||
|
GoCQHTTP_OCRImage = 'ocr_image',
|
||||||
}
|
}
|
||||||
|
@ -173,26 +173,23 @@ class OneBot11Adapter extends Service {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
const isSelfMsg = msg.user_id.toString() === selfInfo.uin
|
const isSelfMsg = msg.user_id.toString() === selfInfo.uin
|
||||||
if (isSelfMsg && !this.config.reportSelfMessage) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (isSelfMsg) {
|
if (isSelfMsg) {
|
||||||
msg.target_id = parseInt(message.peerUin)
|
msg.target_id = parseInt(message.peerUin)
|
||||||
}
|
}
|
||||||
this.dispatch(msg)
|
this.dispatch(msg)
|
||||||
}).catch(e => this.ctx.logger.error('constructMessage error: ', e.stack.toString()))
|
}).catch(e => this.ctx.logger.error('handling incoming messages', e))
|
||||||
|
|
||||||
OB11Entities.groupEvent(this.ctx, message).then(groupEvent => {
|
OB11Entities.groupEvent(this.ctx, message).then(groupEvent => {
|
||||||
if (groupEvent) {
|
if (groupEvent) {
|
||||||
this.dispatch(groupEvent)
|
this.dispatch(groupEvent)
|
||||||
}
|
}
|
||||||
})
|
}).catch(e => this.ctx.logger.error('handling incoming group events', e))
|
||||||
|
|
||||||
OB11Entities.privateEvent(this.ctx, message).then(privateEvent => {
|
OB11Entities.privateEvent(this.ctx, message).then(privateEvent => {
|
||||||
if (privateEvent) {
|
if (privateEvent) {
|
||||||
this.dispatch(privateEvent)
|
this.dispatch(privateEvent)
|
||||||
}
|
}
|
||||||
})
|
}).catch(e => this.ctx.logger.error('handling incoming buddy events', e))
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleRecallMsg(message: RawMessage) {
|
private handleRecallMsg(message: RawMessage) {
|
||||||
@ -310,7 +307,6 @@ class OneBot11Adapter extends Service {
|
|||||||
heartInterval: config.heartInterval,
|
heartInterval: config.heartInterval,
|
||||||
token: config.token,
|
token: config.token,
|
||||||
debug: config.debug,
|
debug: config.debug,
|
||||||
reportSelfMessage: config.reportSelfMessage,
|
|
||||||
msgCacheExpire: config.msgCacheExpire,
|
msgCacheExpire: config.msgCacheExpire,
|
||||||
musicSignUrl: config.musicSignUrl,
|
musicSignUrl: config.musicSignUrl,
|
||||||
enableLocalFile2Url: config.enableLocalFile2Url,
|
enableLocalFile2Url: config.enableLocalFile2Url,
|
||||||
@ -341,6 +337,9 @@ class OneBot11Adapter extends Service {
|
|||||||
this.handleRecallMsg(input)
|
this.handleRecallMsg(input)
|
||||||
})
|
})
|
||||||
this.ctx.on('nt/message-sent', input => {
|
this.ctx.on('nt/message-sent', input => {
|
||||||
|
if (!this.config.reportSelfMessage) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.handleMsg(input)
|
this.handleMsg(input)
|
||||||
})
|
})
|
||||||
this.ctx.on('nt/group-notify', input => {
|
this.ctx.on('nt/group-notify', input => {
|
||||||
@ -370,7 +369,6 @@ namespace OneBot11Adapter {
|
|||||||
heartInterval: number
|
heartInterval: number
|
||||||
token: string
|
token: string
|
||||||
debug: boolean
|
debug: boolean
|
||||||
reportSelfMessage: boolean
|
|
||||||
musicSignUrl?: string
|
musicSignUrl?: string
|
||||||
enableLocalFile2Url: boolean
|
enableLocalFile2Url: boolean
|
||||||
ffmpeg?: string
|
ffmpeg?: string
|
||||||
|
@ -66,15 +66,10 @@ export async function createSendElements(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (peer.chatType === ChatType.Group) {
|
else if (peer.chatType === ChatType.Group) {
|
||||||
const uid = await ctx.ntUserApi.getUidByUin(atQQ) ?? ''
|
const uid = await ctx.ntUserApi.getUidByUin(atQQ, peer.peerUid) ?? ''
|
||||||
let display = ''
|
let display = ''
|
||||||
if (sendMsg.data.name) {
|
if (sendMsg.data.name) {
|
||||||
display = `@${sendMsg.data.name}`
|
display = `@${sendMsg.data.name}`
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
const member = await ctx.ntGroupApi.getGroupMember(peer.peerUid, uid)
|
|
||||||
display = `@${member.cardName || member.nick}`
|
|
||||||
} catch { }
|
|
||||||
}
|
}
|
||||||
sendElements.push(SendElement.at(atQQ, uid, AtType.One, display))
|
sendElements.push(SendElement.at(atQQ, uid, AtType.One, display))
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ async function onSettingWindowCreated(view: Element) {
|
|||||||
SettingItem(
|
SettingItem(
|
||||||
'上报 Bot 自身发送的消息',
|
'上报 Bot 自身发送的消息',
|
||||||
'上报 event 为 message_sent',
|
'上报 event 为 message_sent',
|
||||||
SettingSwitch('reportSelfMessage', config.reportSelfMessage),
|
SettingSwitch('ob11.reportSelfMessage', config.ob11.reportSelfMessage),
|
||||||
),
|
),
|
||||||
SettingItem(
|
SettingItem(
|
||||||
'使用 Base64 编码获取文件',
|
'使用 Base64 编码获取文件',
|
||||||
|
@ -175,10 +175,14 @@ export class MessageEncoder {
|
|||||||
if (type === 'text') {
|
if (type === 'text') {
|
||||||
this.elements.push(SendElement.text(attrs.content))
|
this.elements.push(SendElement.text(attrs.content))
|
||||||
} else if (type === 'at') {
|
} else if (type === 'at') {
|
||||||
|
this.peer ??= await getPeer(this.ctx, this.channelId)
|
||||||
|
if (this.peer.chatType !== NT.ChatType.Group) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (attrs.type === 'all') {
|
if (attrs.type === 'all') {
|
||||||
this.elements.push(SendElement.at('', '', NT.AtType.All, '@全体成员'))
|
this.elements.push(SendElement.at('', '', NT.AtType.All, '@全体成员'))
|
||||||
} else {
|
} else {
|
||||||
const uid = await this.ctx.ntUserApi.getUidByUin(attrs.id) ?? ''
|
const uid = await this.ctx.ntUserApi.getUidByUin(attrs.id, this.peer.peerUid) ?? ''
|
||||||
const display = attrs.name ? '@' + attrs.name : ''
|
const display = attrs.name ? '@' + attrs.name : ''
|
||||||
this.elements.push(SendElement.at(attrs.id, uid, NT.AtType.One, display))
|
this.elements.push(SendElement.at(attrs.id, uid, NT.AtType.One, display))
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
export const version = '4.0.3'
|
export const version = '4.0.4'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user