mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1dd468e2ff | ||
![]() |
2a1aa8c649 | ||
![]() |
1633734e08 | ||
![]() |
dff92e6f27 | ||
![]() |
dba5e30d5d | ||
![]() |
2d04ab2e72 | ||
![]() |
1a015ac8d3 | ||
![]() |
6390620ddd | ||
![]() |
0d19005dc3 | ||
![]() |
c6479dd2c4 | ||
![]() |
8871331b7c | ||
![]() |
e01148b86a | ||
![]() |
2f87e3818e | ||
![]() |
2c8a594c38 | ||
![]() |
1508dab7fe | ||
![]() |
958b21e47e | ||
![]() |
781c3311ae | ||
![]() |
52850d172e |
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 4,
|
"manifest_version": 4,
|
||||||
"type": "extension",
|
"type": "extension",
|
||||||
"name": "LLOneBot v3.26.6",
|
"name": "LLOneBot v3.27.1",
|
||||||
"slug": "LLOneBot",
|
"slug": "LLOneBot",
|
||||||
"description": "使你的NTQQ支持OneBot11协议进行QQ机器人开发, 不支持商店在线更新",
|
"description": "使你的NTQQ支持OneBot11协议进行QQ机器人开发",
|
||||||
"version": "3.26.6",
|
"version": "3.27.1",
|
||||||
"icon": "./icon.jpg",
|
"icon": "./icon.jpg",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
"file-type": "^19.0.0",
|
"file-type": "^19.0.0",
|
||||||
"fluent-ffmpeg": "^2.1.2",
|
"fluent-ffmpeg": "^2.1.2",
|
||||||
"level": "^8.0.1",
|
"level": "^8.0.1",
|
||||||
"silk-wasm": "^3.3.4",
|
"silk-wasm": "^3.6.0",
|
||||||
"utf-8-validate": "^6.0.3",
|
"utf-8-validate": "^6.0.3",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"ws": "^8.16.0"
|
"ws": "^8.16.0"
|
||||||
|
@@ -43,6 +43,7 @@ export class ConfigUtil {
|
|||||||
enableQOAutoQuote: false
|
enableQOAutoQuote: false
|
||||||
}
|
}
|
||||||
let defaultConfig: Config = {
|
let defaultConfig: Config = {
|
||||||
|
enableLLOB: true,
|
||||||
ob11: ob11Default,
|
ob11: ob11Default,
|
||||||
heartInterval: 60000,
|
heartInterval: 60000,
|
||||||
token: '',
|
token: '',
|
||||||
|
@@ -17,6 +17,7 @@ export interface CheckVersion {
|
|||||||
version: string
|
version: string
|
||||||
}
|
}
|
||||||
export interface Config {
|
export interface Config {
|
||||||
|
enableLLOB: boolean
|
||||||
ob11: OB11Config
|
ob11: OB11Config
|
||||||
token?: string
|
token?: string
|
||||||
heartInterval?: number // ms
|
heartInterval?: number // ms
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import { encode, getDuration, getWavFileInfo, isWav } from 'silk-wasm'
|
|
||||||
import fsPromise from 'fs/promises'
|
import fsPromise from 'fs/promises'
|
||||||
|
import { decode, encode, getDuration, getWavFileInfo, isWav, isSilk } from 'silk-wasm'
|
||||||
import { log } from './log'
|
import { log } from './log'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import { DATA_DIR, TEMP_DIR } from './index'
|
import { TEMP_DIR } from './index'
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
import { getConfigUtil } from '../config'
|
import { getConfigUtil } from '../config'
|
||||||
import { spawn } from 'node:child_process'
|
import { spawn } from 'node:child_process'
|
||||||
@@ -60,10 +60,11 @@ export async function encodeSilk(filePath: string) {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const file = await fsPromise.readFile(filePath)
|
||||||
const pttPath = path.join(TEMP_DIR, uuidv4())
|
const pttPath = path.join(TEMP_DIR, uuidv4())
|
||||||
if (getFileHeader(filePath) !== '02232153494c4b') {
|
if (!isSilk(file)) {
|
||||||
log(`语音文件${filePath}需要转换成silk`)
|
log(`语音文件${filePath}需要转换成silk`)
|
||||||
const _isWav = await isWavFile(filePath)
|
const _isWav = isWav(file)
|
||||||
const pcmPath = pttPath + '.pcm'
|
const pcmPath = pttPath + '.pcm'
|
||||||
let sampleRate = 0
|
let sampleRate = 0
|
||||||
const convert = () => {
|
const convert = () => {
|
||||||
@@ -79,7 +80,8 @@ export async function encodeSilk(filePath: string) {
|
|||||||
if (code == null || EXIT_CODES.includes(code)) {
|
if (code == null || EXIT_CODES.includes(code)) {
|
||||||
sampleRate = 24000
|
sampleRate = 24000
|
||||||
const data = fs.readFileSync(pcmPath)
|
const data = fs.readFileSync(pcmPath)
|
||||||
fs.unlink(pcmPath, (err) => {})
|
fs.unlink(pcmPath, (err) => {
|
||||||
|
})
|
||||||
return resolve(data)
|
return resolve(data)
|
||||||
}
|
}
|
||||||
log(`FFmpeg exit: code=${code ?? 'unknown'} sig=${signal ?? 'unknown'}`)
|
log(`FFmpeg exit: code=${code ?? 'unknown'} sig=${signal ?? 'unknown'}`)
|
||||||
@@ -91,7 +93,7 @@ export async function encodeSilk(filePath: string) {
|
|||||||
if (!_isWav) {
|
if (!_isWav) {
|
||||||
input = await convert()
|
input = await convert()
|
||||||
} else {
|
} else {
|
||||||
input = fs.readFileSync(filePath)
|
input = file
|
||||||
const allowSampleRate = [8000, 12000, 16000, 24000, 32000, 44100, 48000]
|
const allowSampleRate = [8000, 12000, 16000, 24000, 32000, 44100, 48000]
|
||||||
const { fmt } = getWavFileInfo(input)
|
const { fmt } = getWavFileInfo(input)
|
||||||
// log(`wav文件信息`, fmt)
|
// log(`wav文件信息`, fmt)
|
||||||
@@ -108,7 +110,7 @@ export async function encodeSilk(filePath: string) {
|
|||||||
duration: silk.duration / 1000,
|
duration: silk.duration / 1000,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const silk = fs.readFileSync(filePath)
|
const silk = file
|
||||||
let duration = 0
|
let duration = 0
|
||||||
try {
|
try {
|
||||||
duration = getDuration(silk) / 1000
|
duration = getDuration(silk) / 1000
|
||||||
@@ -128,3 +130,41 @@ export async function encodeSilk(filePath: string) {
|
|||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function decodeSilk(inputFilePath: string, outFormat: 'mp3' | 'amr' | 'wma' | 'm4a' | 'spx' | 'ogg' | 'wav' | 'flac' = 'mp3') {
|
||||||
|
const silkArrayBuffer = await fsPromise.readFile(inputFilePath)
|
||||||
|
const data = (await decode(silkArrayBuffer, 24000)).data
|
||||||
|
const fileName = path.join(TEMP_DIR, path.basename(inputFilePath))
|
||||||
|
const outPCMPath = fileName + '.pcm'
|
||||||
|
const outFilePath = fileName + '.' + outFormat
|
||||||
|
await fsPromise.writeFile(outPCMPath, data)
|
||||||
|
const convert = () => {
|
||||||
|
return new Promise<string>((resolve, reject) => {
|
||||||
|
const ffmpegPath = getConfigUtil().getConfig().ffmpeg || process.env.FFMPEG_PATH || 'ffmpeg'
|
||||||
|
const cp = spawn(ffmpegPath, [
|
||||||
|
'-y',
|
||||||
|
'-f', 's16le', // PCM format
|
||||||
|
'-ar', '24000', // Sample rate
|
||||||
|
'-ac', '1', // Number of audio channels
|
||||||
|
'-i', outPCMPath,
|
||||||
|
outFilePath,
|
||||||
|
])
|
||||||
|
cp.on('error', (err) => {
|
||||||
|
log(`FFmpeg处理转换出错: `, err.message)
|
||||||
|
return reject(err)
|
||||||
|
})
|
||||||
|
cp.on('exit', (code, signal) => {
|
||||||
|
const EXIT_CODES = [0, 255]
|
||||||
|
if (code == null || EXIT_CODES.includes(code)) {
|
||||||
|
fs.unlink(outPCMPath, (err) => {
|
||||||
|
})
|
||||||
|
return resolve(outFilePath)
|
||||||
|
}
|
||||||
|
const exitErr = `FFmpeg exit: code=${code ?? 'unknown'} sig=${signal ?? 'unknown'}`
|
||||||
|
log(exitErr)
|
||||||
|
reject(Error(`FFmpeg处理转换失败,${exitErr}`))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return convert()
|
||||||
|
}
|
@@ -13,7 +13,7 @@ import {
|
|||||||
CHANNEL_UPDATE,
|
CHANNEL_UPDATE,
|
||||||
} from '../common/channels'
|
} from '../common/channels'
|
||||||
import { ob11WebsocketServer } from '../onebot11/server/ws/WebsocketServer'
|
import { ob11WebsocketServer } from '../onebot11/server/ws/WebsocketServer'
|
||||||
import { DATA_DIR } from '../common/utils'
|
import { DATA_DIR, qqPkgInfo } from '../common/utils'
|
||||||
import {
|
import {
|
||||||
friendRequests,
|
friendRequests,
|
||||||
getFriend,
|
getFriend,
|
||||||
@@ -203,18 +203,23 @@ function onLoad() {
|
|||||||
async function startReceiveHook() {
|
async function startReceiveHook() {
|
||||||
startHook().then()
|
startHook().then()
|
||||||
if (getConfigUtil().getConfig().enablePoke) {
|
if (getConfigUtil().getConfig().enablePoke) {
|
||||||
crychic.loadNode()
|
if ( qqPkgInfo.buildVersion > '23873'){
|
||||||
crychic.registerPokeHandler((id, isGroup) => {
|
log(`当前版本${qqPkgInfo.buildVersion}不支持发送戳一戳模块`)
|
||||||
log(`收到戳一戳消息了!是否群聊:${isGroup},id:${id}`)
|
}
|
||||||
let pokeEvent: OB11FriendPokeEvent | OB11GroupPokeEvent
|
else {
|
||||||
if (isGroup) {
|
crychic.loadNode()
|
||||||
pokeEvent = new OB11GroupPokeEvent(parseInt(id))
|
crychic.registerPokeHandler((id, isGroup) => {
|
||||||
}
|
log(`收到戳一戳消息了!是否群聊:${isGroup},id:${id}`)
|
||||||
else {
|
let pokeEvent: OB11FriendPokeEvent | OB11GroupPokeEvent
|
||||||
pokeEvent = new OB11FriendPokeEvent(parseInt(id))
|
if (isGroup) {
|
||||||
}
|
pokeEvent = new OB11GroupPokeEvent(parseInt(id))
|
||||||
postOb11Event(pokeEvent)
|
}
|
||||||
})
|
else {
|
||||||
|
pokeEvent = new OB11FriendPokeEvent(parseInt(id))
|
||||||
|
}
|
||||||
|
postOb11Event(pokeEvent)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
registerReceiveHook<{
|
registerReceiveHook<{
|
||||||
msgList: Array<RawMessage>
|
msgList: Array<RawMessage>
|
||||||
@@ -435,6 +440,11 @@ function onLoad() {
|
|||||||
|
|
||||||
async function start() {
|
async function start() {
|
||||||
log('llonebot pid', process.pid)
|
log('llonebot pid', process.pid)
|
||||||
|
const config = getConfigUtil().getConfig()
|
||||||
|
if (!config.enableLLOB){
|
||||||
|
log('LLOneBot 开关设置为关闭,不启动LLOneBot')
|
||||||
|
return
|
||||||
|
}
|
||||||
llonebotError.otherError = ''
|
llonebotError.otherError = ''
|
||||||
startTime = Date.now()
|
startTime = Date.now()
|
||||||
dbUtil.getReceivedTempUinMap().then((m) => {
|
dbUtil.getReceivedTempUinMap().then((m) => {
|
||||||
@@ -469,7 +479,6 @@ function onLoad() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const config = getConfigUtil().getConfig()
|
|
||||||
if (config.ob11.enableHttp) {
|
if (config.ob11.enableHttp) {
|
||||||
ob11HTTPServer.start(config.ob11.httpPort)
|
ob11HTTPServer.start(config.ob11.httpPort)
|
||||||
}
|
}
|
||||||
|
@@ -188,6 +188,7 @@ export const IMAGE_HTTP_HOST = 'https://gchat.qpic.cn'
|
|||||||
export const IMAGE_HTTP_HOST_NT = 'https://multimedia.nt.qq.com.cn'
|
export const IMAGE_HTTP_HOST_NT = 'https://multimedia.nt.qq.com.cn'
|
||||||
|
|
||||||
export interface PicElement {
|
export interface PicElement {
|
||||||
|
picSubType: PicSubType
|
||||||
picType: PicType // 有这玩意儿吗
|
picType: PicType // 有这玩意儿吗
|
||||||
originImageUrl: string // http url, 没有host,host是https://gchat.qpic.cn/, 带download参数的是https://multimedia.nt.qq.com.cn
|
originImageUrl: string // http url, 没有host,host是https://gchat.qpic.cn/, 带download参数的是https://multimedia.nt.qq.com.cn
|
||||||
originImageMd5?: string
|
originImageMd5?: string
|
||||||
@@ -226,6 +227,7 @@ export interface GrayTipElement {
|
|||||||
content: string
|
content: string
|
||||||
}
|
}
|
||||||
jsonGrayTipElement: {
|
jsonGrayTipElement: {
|
||||||
|
busiId: number
|
||||||
jsonStr: string
|
jsonStr: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@ import BaseAction from '../BaseAction'
|
|||||||
import fs from 'fs/promises'
|
import fs from 'fs/promises'
|
||||||
import { dbUtil } from '@/common/db'
|
import { dbUtil } from '@/common/db'
|
||||||
import { getConfigUtil } from '@/common/config'
|
import { getConfigUtil } from '@/common/config'
|
||||||
import { log, sleep, uri2local } from '@/common/utils'
|
import { checkFileReceived, log, sleep, uri2local } from '@/common/utils'
|
||||||
import { NTQQFileApi } from '@/ntqqapi/api'
|
import { NTQQFileApi } from '@/ntqqapi/api'
|
||||||
import { ActionName } from '../types'
|
import { ActionName } from '../types'
|
||||||
import { FileElement, RawMessage, VideoElement } from '@/ntqqapi/types'
|
import { FileElement, RawMessage, VideoElement } from '@/ntqqapi/types'
|
||||||
@@ -38,20 +38,21 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
|
|||||||
log('找到了文件 element', element)
|
log('找到了文件 element', element)
|
||||||
// 构建下载函数
|
// 构建下载函数
|
||||||
await NTQQFileApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, cache.elementId, '', '', true)
|
await NTQQFileApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, cache.elementId, '', '', true)
|
||||||
await sleep(1000) // 这里延时是为何?
|
// 等待文件下载完成
|
||||||
msg = await dbUtil.getMsgByLongId(cache.msgId)
|
msg = await dbUtil.getMsgByLongId(cache.msgId)
|
||||||
log('下载完成后的msg', msg)
|
log('下载完成后的msg', msg)
|
||||||
cache.filePath = this.getElement(msg, cache.elementId).filePath
|
cache.filePath = this.getElement(msg, cache.elementId).filePath
|
||||||
|
await checkFileReceived(cache.filePath, 10 * 1000)
|
||||||
dbUtil.addFileCache(file, cache).then()
|
dbUtil.addFileCache(file, cache).then()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
protected async _handle(payload: GetFilePayload): Promise<GetFileResponse> {
|
protected async _handle(payload: GetFilePayload): Promise<GetFileResponse> {
|
||||||
const cache = await dbUtil.getFileCache(payload.file)
|
let cache = await dbUtil.getFileCache(payload.file)
|
||||||
const { autoDeleteFile, enableLocalFile2Url, autoDeleteFileSecond } = getConfigUtil().getConfig()
|
|
||||||
if (!cache) {
|
if (!cache) {
|
||||||
throw new Error('file not found')
|
throw new Error('file not found')
|
||||||
}
|
}
|
||||||
|
const { autoDeleteFile, enableLocalFile2Url, autoDeleteFileSecond } = getConfigUtil().getConfig()
|
||||||
if (cache.downloadFunc) {
|
if (cache.downloadFunc) {
|
||||||
await cache.downloadFunc()
|
await cache.downloadFunc()
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,9 @@
|
|||||||
import { GetFileBase, GetFilePayload, GetFileResponse } from './GetFile'
|
import { GetFileBase, GetFilePayload, GetFileResponse } from './GetFile'
|
||||||
import { ActionName } from '../types'
|
import { ActionName } from '../types'
|
||||||
|
import {decodeSilk} from "@/common/utils/audio";
|
||||||
|
import { getConfigUtil } from '@/common/config'
|
||||||
|
import path from 'node:path'
|
||||||
|
import fs from 'node:fs'
|
||||||
|
|
||||||
interface Payload extends GetFilePayload {
|
interface Payload extends GetFilePayload {
|
||||||
out_format: 'mp3' | 'amr' | 'wma' | 'm4a' | 'spx' | 'ogg' | 'wav' | 'flac'
|
out_format: 'mp3' | 'amr' | 'wma' | 'm4a' | 'spx' | 'ogg' | 'wav' | 'flac'
|
||||||
@@ -9,7 +13,13 @@ export default class GetRecord extends GetFileBase {
|
|||||||
actionName = ActionName.GetRecord
|
actionName = ActionName.GetRecord
|
||||||
|
|
||||||
protected async _handle(payload: Payload): Promise<GetFileResponse> {
|
protected async _handle(payload: Payload): Promise<GetFileResponse> {
|
||||||
let res = super._handle(payload)
|
let res = await super._handle(payload)
|
||||||
|
res.file = await decodeSilk(res.file, payload.out_format)
|
||||||
|
res.file_name = path.basename(res.file)
|
||||||
|
res.file_size = fs.statSync(res.file).size.toString()
|
||||||
|
if (getConfigUtil().getConfig().enableLocalFile2Url){
|
||||||
|
res.base64 = fs.readFileSync(res.file, 'base64')
|
||||||
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,7 +24,7 @@ import {
|
|||||||
User,
|
User,
|
||||||
VideoElement,
|
VideoElement,
|
||||||
} from '../ntqqapi/types'
|
} from '../ntqqapi/types'
|
||||||
import { deleteGroup, getFriend, getGroupMember, selfInfo, tempGroupCodeMap } from '../common/data'
|
import { deleteGroup, getFriend, getGroupMember, selfInfo, tempGroupCodeMap, uidMaps } from '../common/data'
|
||||||
import { EventType } from './event/OB11BaseEvent'
|
import { EventType } from './event/OB11BaseEvent'
|
||||||
import { encodeCQCode } from './cqcode'
|
import { encodeCQCode } from './cqcode'
|
||||||
import { dbUtil } from '../common/db'
|
import { dbUtil } from '../common/db'
|
||||||
@@ -47,6 +47,7 @@ import { mFaceCache } from '../ntqqapi/constructor'
|
|||||||
import { OB11FriendAddNoticeEvent } from './event/notice/OB11FriendAddNoticeEvent'
|
import { OB11FriendAddNoticeEvent } from './event/notice/OB11FriendAddNoticeEvent'
|
||||||
import { OB11FriendRecallNoticeEvent } from './event/notice/OB11FriendRecallNoticeEvent'
|
import { OB11FriendRecallNoticeEvent } from './event/notice/OB11FriendRecallNoticeEvent'
|
||||||
import { OB11GroupRecallNoticeEvent } from './event/notice/OB11GroupRecallNoticeEvent'
|
import { OB11GroupRecallNoticeEvent } from './event/notice/OB11GroupRecallNoticeEvent'
|
||||||
|
import { OB11GroupPokeEvent } from './event/notice/OB11PokeEvent'
|
||||||
|
|
||||||
let lastRKeyUpdateTime = 0
|
let lastRKeyUpdateTime = 0
|
||||||
|
|
||||||
@@ -161,10 +162,12 @@ export class OB11Constructor {
|
|||||||
// message_data["data"]["file"] = element.picElement.sourcePath
|
// message_data["data"]["file"] = element.picElement.sourcePath
|
||||||
let fileName = element.picElement.fileName
|
let fileName = element.picElement.fileName
|
||||||
const sourcePath = element.picElement.sourcePath
|
const sourcePath = element.picElement.sourcePath
|
||||||
if (element.picElement.picType === PicType.gif && !fileName.endsWith('.gif')) {
|
const isGif = element.picElement.picType === PicType.gif
|
||||||
|
if (isGif && !fileName.endsWith('.gif')) {
|
||||||
fileName += '.gif'
|
fileName += '.gif'
|
||||||
}
|
}
|
||||||
message_data['data']['file'] = fileName
|
message_data['data']['file'] = fileName
|
||||||
|
message_data['data']['subType'] = element.picElement.picSubType
|
||||||
// message_data["data"]["path"] = element.picElement.sourcePath
|
// message_data["data"]["path"] = element.picElement.sourcePath
|
||||||
// let currentRKey = "CAQSKAB6JWENi5LMk0kc62l8Pm3Jn1dsLZHyRLAnNmHGoZ3y_gDZPqZt-64"
|
// let currentRKey = "CAQSKAB6JWENi5LMk0kc62l8Pm3Jn1dsLZHyRLAnNmHGoZ3y_gDZPqZt-64"
|
||||||
|
|
||||||
@@ -188,9 +191,7 @@ export class OB11Constructor {
|
|||||||
element.picElement.sourcePath,
|
element.picElement.sourcePath,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
})
|
}).then()
|
||||||
.then()
|
|
||||||
// 不在自动下载图片
|
|
||||||
}
|
}
|
||||||
else if (element.videoElement || element.fileElement) {
|
else if (element.videoElement || element.fileElement) {
|
||||||
const videoOrFileElement = element.videoElement || element.fileElement
|
const videoOrFileElement = element.videoElement || element.fileElement
|
||||||
@@ -297,7 +298,7 @@ export class OB11Constructor {
|
|||||||
if (message_data.type !== 'unknown' && message_data.data) {
|
if (message_data.type !== 'unknown' && message_data.data) {
|
||||||
const cqCode = encodeCQCode(message_data)
|
const cqCode = encodeCQCode(message_data)
|
||||||
if (messagePostFormat === 'string') {
|
if (messagePostFormat === 'string') {
|
||||||
;(resMsg.message as string) += cqCode
|
(resMsg.message as string) += cqCode
|
||||||
}
|
}
|
||||||
else (resMsg.message as OB11MessageData[]).push(message_data)
|
else (resMsg.message as OB11MessageData[]).push(message_data)
|
||||||
|
|
||||||
@@ -492,6 +493,16 @@ export class OB11Constructor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
* */
|
* */
|
||||||
|
if (grayTipElement.jsonGrayTipElement.busiId == 1061) {
|
||||||
|
//判断业务类型
|
||||||
|
//Poke事件
|
||||||
|
let pokedetail: any[] = json.items;
|
||||||
|
//筛选item带有uid的元素
|
||||||
|
pokedetail = pokedetail.filter(item => item.uid);
|
||||||
|
if (pokedetail.length == 2) {
|
||||||
|
return new OB11GroupPokeEvent(parseInt(msg.peerUid), parseInt((uidMaps[pokedetail[0].uid])!), parseInt((uidMaps[pokedetail[1].uid])));
|
||||||
|
}
|
||||||
|
}
|
||||||
const memberUin = json.items[1].param[0]
|
const memberUin = json.items[1].param[0]
|
||||||
const title = json.items[3].txt
|
const title = json.items[3].txt
|
||||||
log('收到群成员新头衔消息', json)
|
log('收到群成员新头衔消息', json)
|
||||||
|
@@ -50,6 +50,7 @@ export function encodeCQCode(data: OB11MessageData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const CQCodeEscape = (text: string) => {
|
const CQCodeEscape = (text: string) => {
|
||||||
|
text = text.toString()
|
||||||
return text.replace(/\&/g, '&').replace(/\[/g, '[').replace(/\]/g, ']').replace(/,/g, ',')
|
return text.replace(/\&/g, '&').replace(/\[/g, '[').replace(/\]/g, ']').replace(/,/g, ',')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,10 +21,10 @@ export class OB11FriendPokeEvent extends OB11PokeEvent {
|
|||||||
export class OB11GroupPokeEvent extends OB11PokeEvent {
|
export class OB11GroupPokeEvent extends OB11PokeEvent {
|
||||||
group_id: number
|
group_id: number
|
||||||
|
|
||||||
constructor(group_id: number, user_id: number = 0) {
|
constructor(group_id: number, user_id: number = 0, target_id: number = 0) {
|
||||||
super()
|
super()
|
||||||
this.group_id = group_id
|
this.group_id = group_id
|
||||||
this.target_id = user_id
|
this.target_id = target_id
|
||||||
this.user_id = user_id
|
this.user_id = user_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,6 +27,7 @@ class OB11WebsocketServer extends WebsocketServerBase {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let handleResult = await action.websocketHandle(params, echo)
|
let handleResult = await action.websocketHandle(params, echo)
|
||||||
|
handleResult.echo = echo
|
||||||
wsReply(wsClient, handleResult)
|
wsReply(wsClient, handleResult)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
wsReply(wsClient, OB11Response.error(`api处理出错:${e.stack}`, 1200, echo))
|
wsReply(wsClient, OB11Response.error(`api处理出错:${e.stack}`, 1200, echo))
|
||||||
|
@@ -62,6 +62,13 @@ async function onSettingWindowCreated(view: Element) {
|
|||||||
SettingButton('请稍候', 'llonebot-update-button', 'secondary'),
|
SettingButton('请稍候', 'llonebot-update-button', 'secondary'),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
|
SettingList([
|
||||||
|
SettingItem(
|
||||||
|
'是否启用 LLOneBot, 重启QQ后生效',
|
||||||
|
null,
|
||||||
|
SettingSwitch('enableLLOB', config.enableLLOB, { 'control-display-id': 'config-enableLLOB' }),
|
||||||
|
)]
|
||||||
|
),
|
||||||
SettingList([
|
SettingList([
|
||||||
SettingItem(
|
SettingItem(
|
||||||
'启用 HTTP 服务',
|
'启用 HTTP 服务',
|
||||||
|
@@ -1 +1 @@
|
|||||||
export const version = '3.26.6'
|
export const version = '3.27.1'
|
||||||
|
Reference in New Issue
Block a user