mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
22dcbac16f | ||
![]() |
44faedd6c0 | ||
![]() |
fb3b673e63 | ||
![]() |
4e377f86d1 | ||
![]() |
e8bd98020b | ||
![]() |
c520034934 | ||
![]() |
5d5fd403b8 | ||
![]() |
1fc02229df | ||
![]() |
6c8d3db3a4 | ||
![]() |
c5b69561af | ||
![]() |
b5bffff941 | ||
![]() |
1a2cdc8c0e | ||
![]() |
50ab62f103 | ||
![]() |
5005d83ce0 | ||
![]() |
d7e40e488c | ||
![]() |
4958e22770 | ||
![]() |
a5e3f94228 | ||
![]() |
9e57b2c17e | ||
![]() |
e1ff366e10 |
1
.github/workflows/publish.yml
vendored
1
.github/workflows/publish.yml
vendored
@@ -27,7 +27,6 @@ jobs:
|
||||
- name: zip
|
||||
run: |
|
||||
sudo apt install zip -y
|
||||
cp manifest.json ./dist/manifest.json
|
||||
cd ./dist/
|
||||
zip -r ../LLOneBot.zip ./*
|
||||
|
||||
|
17
README.md
17
README.md
@@ -23,20 +23,6 @@ TG群:<https://t.me/+nLZEnpne-pQ1OWFl>
|
||||
|
||||
见 <https://llonebot.github.io/zh-CN/develop/api>
|
||||
|
||||
## TODO
|
||||
|
||||
- [x] 重构摆脱LLAPI,目前调用LLAPI只能在renderer进程调用,需重构成在main进程调用
|
||||
- [x] 支持正、反向websocket(感谢@disymayufei的PR)
|
||||
- [x] 转发消息记录
|
||||
- [x] 好友点赞api
|
||||
- [x] 群管理功能,禁言、踢人,改群名片等
|
||||
- [x] 视频消息
|
||||
- [x] 文件消息
|
||||
- [x] 群禁言事件上报
|
||||
- [x] 优化加群成功事件上报
|
||||
- [x] 清理缓存api
|
||||
- [ ] 框架对接文档
|
||||
|
||||
## Stargazers over time
|
||||
|
||||
[](https://starchart.cc/LLOneBot/LLOneBot)
|
||||
@@ -44,8 +30,7 @@ TG群:<https://t.me/+nLZEnpne-pQ1OWFl>
|
||||
## 鸣谢
|
||||
|
||||
- [LiteLoaderQQNT](https://liteloaderqqnt.github.io/guide/install.html)
|
||||
- [LLAPI](https://github.com/Night-stars-1/LiteLoaderQQNT-Plugin-LLAPI)
|
||||
- [chronocat](https://github.com/chrononeko/chronocat/)
|
||||
- [chronocat](https://github.com/chrononeko/chronocat)
|
||||
- [koishi-plugin-adapter-onebot](https://github.com/koishijs/koishi-plugin-adapter-onebot)
|
||||
- [silk-wasm](https://github.com/idranme/silk-wasm)
|
||||
|
||||
|
@@ -4,7 +4,7 @@
|
||||
"name": "LLOneBot",
|
||||
"slug": "LLOneBot",
|
||||
"description": "实现 OneBot 11 协议,用以 QQ 机器人开发",
|
||||
"version": "3.28.0",
|
||||
"version": "3.28.1",
|
||||
"icon": "./icon.webp",
|
||||
"authors": [
|
||||
{
|
||||
|
12
package.json
12
package.json
@@ -18,24 +18,24 @@
|
||||
"dependencies": {
|
||||
"compressing": "^1.10.1",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.18.2",
|
||||
"express": "^4.19.2",
|
||||
"fast-xml-parser": "^4.4.1",
|
||||
"file-type": "^19.0.0",
|
||||
"fluent-ffmpeg": "^2.1.2",
|
||||
"file-type": "^19.4.0",
|
||||
"fluent-ffmpeg": "^2.1.3",
|
||||
"level": "^8.0.1",
|
||||
"silk-wasm": "^3.6.1",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^4.17.20",
|
||||
"@types/fluent-ffmpeg": "^2.1.24",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/fluent-ffmpeg": "^2.1.25",
|
||||
"@types/node": "^20.11.24",
|
||||
"@types/ws": "^8.5.12",
|
||||
"electron": "^29.0.1",
|
||||
"electron-vite": "^2.3.0",
|
||||
"typescript": "^5.5.4",
|
||||
"vite": "^5.3.5",
|
||||
"vite": "^5.4.0",
|
||||
"vite-plugin-cp": "^4.0.8"
|
||||
},
|
||||
"packageManager": "yarn@4.4.0"
|
||||
|
@@ -33,6 +33,8 @@ export const llonebotError: LLOneBotError = {
|
||||
wsServerError: '',
|
||||
otherError: 'LLOnebot未能正常启动,请检查日志查看错误',
|
||||
}
|
||||
// 群号 -> 群成员map(uid=>GroupMember)
|
||||
export const groupMembers: Map<string, Map<string, GroupMember>> = new Map<string, Map<string, GroupMember>>()
|
||||
|
||||
export async function getFriend(uinOrUid: string): Promise<Friend | undefined> {
|
||||
let filterKey = isNumeric(uinOrUid.toString()) ? 'uin' : 'uid'
|
||||
@@ -79,34 +81,32 @@ export function deleteGroup(groupCode: string) {
|
||||
export async function getGroupMember(groupQQ: string | number, memberUinOrUid: string | number) {
|
||||
groupQQ = groupQQ.toString()
|
||||
memberUinOrUid = memberUinOrUid.toString()
|
||||
const group = await getGroup(groupQQ)
|
||||
if (group) {
|
||||
const filterKey = isNumeric(memberUinOrUid) ? 'uin' : 'uid'
|
||||
const filterValue = memberUinOrUid
|
||||
let filterFunc: (member: GroupMember) => boolean = (member) => member[filterKey] === filterValue
|
||||
let member = group.members?.find(filterFunc)
|
||||
if (!member) {
|
||||
try {
|
||||
const _members = await NTQQGroupApi.getGroupMembers(groupQQ)
|
||||
if (_members.length > 0) {
|
||||
group.members = _members
|
||||
}
|
||||
} catch (e) {
|
||||
// log("刷新群成员列表失败", e.stack.toString())
|
||||
}
|
||||
|
||||
member = group.members?.find(filterFunc)
|
||||
let members = groupMembers.get(groupQQ)
|
||||
if (!members) {
|
||||
try {
|
||||
members = await NTQQGroupApi.getGroupMembers(groupQQ)
|
||||
// 更新群成员列表
|
||||
groupMembers.set(groupQQ, members)
|
||||
}
|
||||
catch (e) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
const getMember = () => {
|
||||
let member: GroupMember | undefined = undefined
|
||||
if (isNumeric(memberUinOrUid)) {
|
||||
member = Array.from(members!.values()).find(member => member.uin === memberUinOrUid)
|
||||
} else {
|
||||
member = members!.get(memberUinOrUid)
|
||||
}
|
||||
return member
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export async function refreshGroupMembers(groupQQ: string) {
|
||||
const group = groups.find((group) => group.groupCode === groupQQ)
|
||||
if (group) {
|
||||
group.members = await NTQQGroupApi.getGroupMembers(groupQQ)
|
||||
let member = getMember()
|
||||
if (!member) {
|
||||
members = await NTQQGroupApi.getGroupMembers(groupQQ)
|
||||
member = getMember()
|
||||
}
|
||||
return member
|
||||
}
|
||||
|
||||
export const uidMaps: Record<string, string> = {} // 一串加密的字符串(uid) -> qq号
|
||||
|
@@ -58,7 +58,7 @@ export abstract class HttpServerBase {
|
||||
start(port: number) {
|
||||
try {
|
||||
this.expressAPP.get('/', (req: Request, res: Response) => {
|
||||
res.send(`${this.name}已启动`)
|
||||
res.send(`${this.name} 已启动`)
|
||||
})
|
||||
this.listen(port)
|
||||
llonebotError.httpServerError = ''
|
||||
|
@@ -33,17 +33,17 @@ if (typeof configVersionInfoPath !== 'string') {
|
||||
export { configVersionInfoPath }
|
||||
|
||||
type QQPkgInfo = {
|
||||
version: string;
|
||||
buildVersion: string;
|
||||
platform: string;
|
||||
eleArch: string;
|
||||
version: string
|
||||
buildVersion: string
|
||||
platform: string
|
||||
eleArch: string
|
||||
}
|
||||
type QQVersionConfigInfo = {
|
||||
baseVersion: string;
|
||||
curVersion: string;
|
||||
prevVersion: string;
|
||||
onErrorVersions: Array<any>;
|
||||
buildId: string;
|
||||
baseVersion: string
|
||||
curVersion: string
|
||||
prevVersion: string
|
||||
onErrorVersions: Array<any>
|
||||
buildId: string
|
||||
}
|
||||
|
||||
let _qqVersionConfigInfo: QQVersionConfigInfo = {
|
||||
@@ -80,4 +80,8 @@ if (systemPlatform === 'linux') {
|
||||
}
|
||||
// todo: mac 平台的 appid
|
||||
export const appid = _appid
|
||||
export const isQQ998: boolean = qqPkgInfo.buildVersion >= '22106'
|
||||
export const isQQ998: boolean = qqPkgInfo.buildVersion >= '22106'
|
||||
|
||||
export function getBuildVersion(): number {
|
||||
return +qqPkgInfo.buildVersion
|
||||
}
|
@@ -1,124 +1,93 @@
|
||||
import fs from 'fs'
|
||||
import fsPromise from 'fs/promises'
|
||||
import { decode, encode, getDuration, getWavFileInfo, isWav, isSilk } from 'silk-wasm'
|
||||
import { log } from './log'
|
||||
import path from 'node:path'
|
||||
import ffmpeg from 'fluent-ffmpeg'
|
||||
import fsPromise from 'node:fs/promises'
|
||||
import { decode, encode, getDuration, getWavFileInfo, isWav, isSilk, EncodeResult } from 'silk-wasm'
|
||||
import { log } from './log'
|
||||
import { TEMP_DIR } from './index'
|
||||
import { getConfigUtil } from '../config'
|
||||
import { spawn } from 'node:child_process'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { Readable } from 'node:stream'
|
||||
|
||||
interface FFmpegOptions {
|
||||
input?: string[]
|
||||
output?: string[]
|
||||
}
|
||||
|
||||
type Input = string | Readable
|
||||
|
||||
function convert(input: Input, options: FFmpegOptions): Promise<Buffer>
|
||||
function convert(input: Input, options: FFmpegOptions, outputPath: string): Promise<string>
|
||||
function convert(input: Input, options: FFmpegOptions, outputPath?: string): Promise<Buffer> | Promise<string> {
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
const chunks: Buffer[] = []
|
||||
let command = ffmpeg(input)
|
||||
.on('error', err => {
|
||||
log(`FFmpeg处理转换出错: `, err.message)
|
||||
reject(err)
|
||||
})
|
||||
.on('end', () => {
|
||||
if (!outputPath) {
|
||||
resolve(Buffer.concat(chunks))
|
||||
} else {
|
||||
resolve(outputPath)
|
||||
}
|
||||
})
|
||||
if (options.input) {
|
||||
command = command.inputOptions(options.input)
|
||||
}
|
||||
if (options.output) {
|
||||
command = command.outputOptions(options.output)
|
||||
}
|
||||
const ffmpegPath = getConfigUtil().getConfig().ffmpeg
|
||||
if (ffmpegPath) {
|
||||
command = command.setFfmpegPath(ffmpegPath)
|
||||
}
|
||||
if (!outputPath) {
|
||||
const stream = command.pipe()
|
||||
stream.on('data', chunk => {
|
||||
chunks.push(chunk)
|
||||
})
|
||||
} else {
|
||||
command.save(outputPath)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export async function encodeSilk(filePath: string) {
|
||||
function getFileHeader(filePath: string) {
|
||||
// 定义要读取的字节数
|
||||
const bytesToRead = 7
|
||||
try {
|
||||
const buffer = fs.readFileSync(filePath, {
|
||||
encoding: null,
|
||||
flag: 'r',
|
||||
})
|
||||
|
||||
const fileHeader = buffer.toString('hex', 0, bytesToRead)
|
||||
return fileHeader
|
||||
} catch (err) {
|
||||
console.error('读取文件错误:', err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
async function isWavFile(filePath: string) {
|
||||
return isWav(fs.readFileSync(filePath))
|
||||
}
|
||||
|
||||
async function guessDuration(pttPath: string) {
|
||||
const pttFileInfo = await fsPromise.stat(pttPath)
|
||||
let duration = pttFileInfo.size / 1024 / 3 // 3kb/s
|
||||
duration = Math.floor(duration)
|
||||
duration = Math.max(1, duration)
|
||||
log(`通过文件大小估算语音的时长:`, duration)
|
||||
return duration
|
||||
}
|
||||
|
||||
// function verifyDuration(oriDuration: number, guessDuration: number) {
|
||||
// // 单位都是秒
|
||||
// if (oriDuration - guessDuration > 10) {
|
||||
// return guessDuration
|
||||
// }
|
||||
// oriDuration = Math.max(1, oriDuration)
|
||||
// return oriDuration
|
||||
// }
|
||||
// async function getAudioSampleRate(filePath: string) {
|
||||
// try {
|
||||
// const mm = await import('music-metadata');
|
||||
// const metadata = await mm.parseFile(filePath);
|
||||
// log(`${filePath}采样率`, metadata.format.sampleRate);
|
||||
// return metadata.format.sampleRate;
|
||||
// } catch (error) {
|
||||
// log(`${filePath}采样率获取失败`, error.stack);
|
||||
// // console.error(error);
|
||||
// }
|
||||
// }
|
||||
|
||||
try {
|
||||
const file = await fsPromise.readFile(filePath)
|
||||
const pttPath = path.join(TEMP_DIR, randomUUID())
|
||||
if (!isSilk(file)) {
|
||||
log(`语音文件${filePath}需要转换成silk`)
|
||||
const _isWav = isWav(file)
|
||||
const pcmPath = pttPath + '.pcm'
|
||||
let sampleRate = 0
|
||||
const convert = () => {
|
||||
return new Promise<Buffer>((resolve, reject) => {
|
||||
const ffmpegPath = getConfigUtil().getConfig().ffmpeg || process.env.FFMPEG_PATH || 'ffmpeg'
|
||||
const cp = spawn(ffmpegPath, ['-y', '-i', filePath, '-ar', '24000', '-ac', '1', '-f', 's16le', pcmPath])
|
||||
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)) {
|
||||
sampleRate = 24000
|
||||
const data = fs.readFileSync(pcmPath)
|
||||
fs.unlink(pcmPath, (err) => {
|
||||
})
|
||||
return resolve(data)
|
||||
}
|
||||
log(`FFmpeg exit: code=${code ?? 'unknown'} sig=${signal ?? 'unknown'}`)
|
||||
reject(Error(`FFmpeg处理转换失败`))
|
||||
})
|
||||
})
|
||||
}
|
||||
let input: Buffer
|
||||
if (!_isWav) {
|
||||
input = await convert()
|
||||
let result: EncodeResult
|
||||
const allowSampleRate = [8000, 12000, 16000, 24000, 32000, 44100, 48000]
|
||||
if (isWav(file) && allowSampleRate.includes(getWavFileInfo(file).fmt.sampleRate)) {
|
||||
result = await encode(file, 0)
|
||||
} else {
|
||||
input = file
|
||||
const allowSampleRate = [8000, 12000, 16000, 24000, 32000, 44100, 48000]
|
||||
const { fmt } = getWavFileInfo(input)
|
||||
// log(`wav文件信息`, fmt)
|
||||
if (!allowSampleRate.includes(fmt.sampleRate)) {
|
||||
input = await convert()
|
||||
}
|
||||
const input = await convert(filePath, {
|
||||
output: [
|
||||
'-ar 24000',
|
||||
'-ac 1',
|
||||
'-f s16le'
|
||||
]
|
||||
})
|
||||
result = await encode(input, 24000)
|
||||
}
|
||||
const silk = await encode(input, sampleRate)
|
||||
fs.writeFileSync(pttPath, silk.data)
|
||||
log(`语音文件${filePath}转换成功!`, pttPath, `时长:`, silk.duration)
|
||||
const pttPath = path.join(TEMP_DIR, randomUUID())
|
||||
await fsPromise.writeFile(pttPath, result.data)
|
||||
log(`语音文件${filePath}转换成功!`, pttPath, `时长:`, result.duration)
|
||||
return {
|
||||
converted: true,
|
||||
path: pttPath,
|
||||
duration: silk.duration / 1000,
|
||||
duration: result.duration / 1000,
|
||||
}
|
||||
} else {
|
||||
const silk = file
|
||||
let duration = 0
|
||||
let duration = 1
|
||||
try {
|
||||
duration = getDuration(silk) / 1000
|
||||
} catch (e: any) {
|
||||
log('获取语音文件时长失败, 使用文件大小推测时长', filePath, e.stack)
|
||||
duration = await guessDuration(filePath)
|
||||
log('获取语音文件时长失败, 默认为1秒', filePath, e.stack)
|
||||
}
|
||||
|
||||
return {
|
||||
converted: false,
|
||||
path: filePath,
|
||||
@@ -131,40 +100,20 @@ export async function encodeSilk(filePath: string) {
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
type OutFormat = 'mp3' | 'amr' | 'wma' | 'm4a' | 'spx' | 'ogg' | 'wav' | 'flac'
|
||||
|
||||
export async function decodeSilk(inputFilePath: string, outFormat: OutFormat = 'mp3') {
|
||||
const silk = await fsPromise.readFile(inputFilePath)
|
||||
const { data } = await decode(silk, 24000)
|
||||
const tmpPath = path.join(TEMP_DIR, path.basename(inputFilePath))
|
||||
const outFilePath = tmpPath + `.${outFormat}`
|
||||
const pcmFilePath = tmpPath + '.pcm'
|
||||
await fsPromise.writeFile(pcmFilePath, data)
|
||||
return convert(pcmFilePath, {
|
||||
input: [
|
||||
'-f s16le',
|
||||
'-ar 24000',
|
||||
'-ac 1'
|
||||
]
|
||||
}, outFilePath)
|
||||
}
|
@@ -41,7 +41,7 @@ export function mergeNewProperties(newObj: any, oldObj: any) {
|
||||
})
|
||||
}
|
||||
|
||||
export function isNull(value: any): value is null | undefined | void {
|
||||
export function isNull(value: unknown) {
|
||||
return value === undefined || value === null
|
||||
}
|
||||
|
||||
@@ -74,24 +74,50 @@ export function wrapText(str: string, maxLength: number): string {
|
||||
* @returns 处理后缓存或调用原方法的结果
|
||||
*/
|
||||
export function cacheFunc(ttl: number, customKey: string = '') {
|
||||
const cache = new Map<string, { expiry: number; value: any }>();
|
||||
const cache = new Map<string, { expiry: number; value: any }>()
|
||||
|
||||
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor {
|
||||
const originalMethod = descriptor.value;
|
||||
const className = target.constructor.name; // 获取类名
|
||||
const methodName = propertyKey; // 获取方法名
|
||||
const originalMethod = descriptor.value
|
||||
const className = target.constructor.name // 获取类名
|
||||
const methodName = propertyKey // 获取方法名
|
||||
descriptor.value = async function (...args: any[]) {
|
||||
const cacheKey = `${customKey}${className}.${methodName}:${JSON.stringify(args)}`;
|
||||
const cached = cache.get(cacheKey);
|
||||
const cacheKey = `${customKey}${className}.${methodName}:${JSON.stringify(args)}`
|
||||
const cached = cache.get(cacheKey)
|
||||
if (cached && cached.expiry > Date.now()) {
|
||||
return cached.value;
|
||||
return cached.value
|
||||
} else {
|
||||
const result = await originalMethod.apply(this, args);
|
||||
cache.set(cacheKey, { value: result, expiry: Date.now() + ttl });
|
||||
return result;
|
||||
const result = await originalMethod.apply(this, args)
|
||||
cache.set(cacheKey, { value: result, expiry: Date.now() + ttl })
|
||||
return result
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return descriptor;
|
||||
};
|
||||
return descriptor
|
||||
}
|
||||
}
|
||||
|
||||
export function CacheClassFuncAsyncExtend(ttl: number = 3600 * 1000, customKey: string = '', checker: any = (...data: any[]) => { return true }) {
|
||||
function logExecutionTime(target: any, methodName: string, descriptor: PropertyDescriptor) {
|
||||
const cache = new Map<string, { expiry: number; value: any }>()
|
||||
const originalMethod = descriptor.value
|
||||
descriptor.value = async function (...args: any[]) {
|
||||
const key = `${customKey}${String(methodName)}.(${args.map(arg => JSON.stringify(arg)).join(', ')})`
|
||||
cache.forEach((value, key) => {
|
||||
if (value.expiry < Date.now()) {
|
||||
cache.delete(key)
|
||||
}
|
||||
})
|
||||
const cachedValue = cache.get(key)
|
||||
if (cachedValue && cachedValue.expiry > Date.now()) {
|
||||
return cachedValue.value
|
||||
}
|
||||
const result = await originalMethod.apply(this, args)
|
||||
if (!checker(...args, result)) {
|
||||
return result //丢弃缓存
|
||||
}
|
||||
cache.set(key, { expiry: Date.now() + ttl, value: result })
|
||||
return result
|
||||
}
|
||||
}
|
||||
return logExecutionTime
|
||||
}
|
71
src/common/utils/table.ts
Normal file
71
src/common/utils/table.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
export class LimitedHashTable<K, V> {
|
||||
private keyToValue: Map<K, V> = new Map()
|
||||
private valueToKey: Map<V, K> = new Map()
|
||||
private maxSize: number
|
||||
|
||||
constructor(maxSize: number) {
|
||||
this.maxSize = maxSize
|
||||
}
|
||||
|
||||
resize(count: number) {
|
||||
this.maxSize = count
|
||||
}
|
||||
|
||||
set(key: K, value: V): void {
|
||||
this.keyToValue.set(key, value)
|
||||
this.valueToKey.set(value, key)
|
||||
while (this.keyToValue.size !== this.valueToKey.size) {
|
||||
console.log('keyToValue.size !== valueToKey.size Error Atom')
|
||||
this.keyToValue.clear()
|
||||
this.valueToKey.clear()
|
||||
}
|
||||
while (this.keyToValue.size > this.maxSize || this.valueToKey.size > this.maxSize) {
|
||||
const oldestKey = this.keyToValue.keys().next().value
|
||||
this.valueToKey.delete(this.keyToValue.get(oldestKey)!)
|
||||
this.keyToValue.delete(oldestKey)
|
||||
}
|
||||
}
|
||||
|
||||
getValue(key: K): V | undefined {
|
||||
return this.keyToValue.get(key)
|
||||
}
|
||||
|
||||
getKey(value: V): K | undefined {
|
||||
return this.valueToKey.get(value)
|
||||
}
|
||||
|
||||
deleteByValue(value: V): void {
|
||||
const key = this.valueToKey.get(value)
|
||||
if (key !== undefined) {
|
||||
this.keyToValue.delete(key)
|
||||
this.valueToKey.delete(value)
|
||||
}
|
||||
}
|
||||
|
||||
deleteByKey(key: K): void {
|
||||
const value = this.keyToValue.get(key)
|
||||
if (value !== undefined) {
|
||||
this.keyToValue.delete(key)
|
||||
this.valueToKey.delete(value)
|
||||
}
|
||||
}
|
||||
|
||||
getKeyList(): K[] {
|
||||
return Array.from(this.keyToValue.keys())
|
||||
}
|
||||
|
||||
//获取最近刚写入的几个值
|
||||
getHeads(size: number): { key: K; value: V }[] | undefined {
|
||||
const keyList = this.getKeyList()
|
||||
if (keyList.length === 0) {
|
||||
return undefined
|
||||
}
|
||||
const result: { key: K; value: V }[] = []
|
||||
const listSize = Math.min(size, keyList.length)
|
||||
for (let i = 0; i < listSize; i++) {
|
||||
const key = keyList[listSize - i]
|
||||
result.push({ key, value: this.keyToValue.get(key)! })
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
@@ -21,7 +21,6 @@ import {
|
||||
getGroupMember,
|
||||
groups,
|
||||
llonebotError,
|
||||
refreshGroupMembers,
|
||||
selfInfo,
|
||||
uidMaps,
|
||||
} from '../common/data'
|
||||
@@ -53,7 +52,7 @@ import { GroupDecreaseSubType, OB11GroupDecreaseEvent } from '../onebot11/event/
|
||||
import '../ntqqapi/wrapper'
|
||||
import { sentMessages } from '@/ntqqapi/api'
|
||||
import { NTEventDispatch } from '../common/utils/EventTask'
|
||||
import { wrapperApi, wrapperConstructor } from '../ntqqapi/wrapper'
|
||||
import { wrapperConstructor, getSession } from '../ntqqapi/wrapper'
|
||||
|
||||
let mainWindow: BrowserWindow | null = null
|
||||
|
||||
@@ -442,33 +441,11 @@ function onLoad() {
|
||||
uidMaps[value] = key
|
||||
}
|
||||
})
|
||||
NTEventDispatch.init({ ListenerMap: wrapperConstructor, WrapperSession: wrapperApi.NodeIQQNTWrapperSession! })
|
||||
try {
|
||||
log('start get groups')
|
||||
const _groups = await NTQQGroupApi.getGroups()
|
||||
log('_groups', _groups)
|
||||
await Promise.all(
|
||||
_groups.map(async (group) => {
|
||||
try {
|
||||
const members = await NTQQGroupApi.getGroupMembers(group.groupCode)
|
||||
group.members = members
|
||||
groups.push(group)
|
||||
} catch (e) {
|
||||
log('获取群成员失败', e)
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
catch (e) {
|
||||
log('获取群列表失败', e)
|
||||
}
|
||||
finally {
|
||||
log('start activate group member info')
|
||||
NTQQGroupApi.activateMemberInfoChange().then().catch(log)
|
||||
NTQQGroupApi.activateMemberListChange().then().catch(log)
|
||||
startReceiveHook().then()
|
||||
}
|
||||
|
||||
NTEventDispatch.init({ ListenerMap: wrapperConstructor, WrapperSession: getSession()! })
|
||||
log('start activate group member info')
|
||||
NTQQGroupApi.activateMemberInfoChange().then().catch(log)
|
||||
NTQQGroupApi.activateMemberListChange().then().catch(log)
|
||||
startReceiveHook().then()
|
||||
|
||||
if (config.ob11.enableHttp) {
|
||||
ob11HTTPServer.start(config.ob11.httpPort)
|
||||
|
@@ -16,12 +16,12 @@ import fs from 'node:fs'
|
||||
import { ReceiveCmdS } from '../hook'
|
||||
import { log } from '@/common/utils'
|
||||
import { rkeyManager } from '@/ntqqapi/api/rkey'
|
||||
import { wrapperApi } from '@/ntqqapi/wrapper'
|
||||
import { getSession } from '@/ntqqapi/wrapper'
|
||||
import { Peer } from '@/ntqqapi/types/msg'
|
||||
|
||||
export class NTQQFileApi {
|
||||
static async getVideoUrl(peer: Peer, msgId: string, elementId: string): Promise<string> {
|
||||
const session = wrapperApi.NodeIQQNTWrapperSession
|
||||
const session = getSession()
|
||||
return (await session?.getRichMediaService().getVideoPlayUrlV2(peer,
|
||||
msgId,
|
||||
elementId,
|
||||
|
@@ -1,10 +1,12 @@
|
||||
import { Friend, FriendRequest, FriendV2 } from '../types'
|
||||
import { ReceiveCmdS } from '../hook'
|
||||
import { callNTQQApi, GeneralCallResult, NTQQApiMethod } from '../ntcall'
|
||||
import { friendRequests } from '../../common/data'
|
||||
import { wrapperApi } from '@/ntqqapi/wrapper'
|
||||
import { friendRequests } from '@/common/data'
|
||||
import { getSession } from '@/ntqqapi/wrapper'
|
||||
import { BuddyListReqType, NodeIKernelProfileService } from '../services'
|
||||
import { NTEventDispatch } from '../../common/utils/EventTask'
|
||||
import { NTEventDispatch } from '@/common/utils/EventTask'
|
||||
import { CacheClassFuncAsyncExtend } from '@/common/utils/helper'
|
||||
import { LimitedHashTable } from '@/common/utils/table'
|
||||
|
||||
export class NTQQFriendApi {
|
||||
static async getFriends(forced = false) {
|
||||
@@ -69,7 +71,7 @@ export class NTQQFriendApi {
|
||||
|
||||
static async getBuddyV2(refresh = false): Promise<FriendV2[]> {
|
||||
const uids: string[] = []
|
||||
const session = wrapperApi.NodeIQQNTWrapperSession
|
||||
const session = getSession()
|
||||
const buddyService = session?.getBuddyService()
|
||||
const buddyListV2 = refresh ? await buddyService?.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService?.getBuddyListV2('0', BuddyListReqType.KNOMAL)
|
||||
uids.push(...buddyListV2?.data.flatMap(item => item.buddyUids)!)
|
||||
@@ -78,4 +80,31 @@ export class NTQQFriendApi {
|
||||
)
|
||||
return Array.from(data.values())
|
||||
}
|
||||
|
||||
@CacheClassFuncAsyncExtend(3600 * 1000, 'getBuddyIdMap', () => true)
|
||||
static async getBuddyIdMapCache(refresh = false): Promise<LimitedHashTable<string, string>> {
|
||||
return await NTQQFriendApi.getBuddyIdMap(refresh)
|
||||
}
|
||||
|
||||
static async getBuddyIdMap(refresh = false): Promise<LimitedHashTable<string, string>> {
|
||||
const uids: string[] = []
|
||||
const retMap: LimitedHashTable<string, string> = new LimitedHashTable<string, string>(5000)
|
||||
const session = getSession()
|
||||
const buddyService = session?.getBuddyService()
|
||||
const buddyListV2 = refresh ? await buddyService?.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService?.getBuddyListV2('0', BuddyListReqType.KNOMAL)
|
||||
uids.push(...buddyListV2?.data.flatMap(item => item.buddyUids)!)
|
||||
const data = await NTEventDispatch.CallNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>(
|
||||
'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids
|
||||
);
|
||||
data.forEach((value, key) => {
|
||||
retMap.set(value.uin!, value.uid!)
|
||||
})
|
||||
//console.log('getBuddyIdMap', retMap.getValue)
|
||||
return retMap
|
||||
}
|
||||
|
||||
static async isBuddy(uid: string): Promise<boolean> {
|
||||
const session = getSession()
|
||||
return session?.getBuddyService().isBuddy(uid)!
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ import { deleteGroup, uidMaps } from '../../common/data'
|
||||
import { dbUtil } from '../../common/db'
|
||||
import { log } from '../../common/utils/log'
|
||||
import { NTQQWindowApi, NTQQWindows } from './window'
|
||||
import { wrapperApi } from '../wrapper'
|
||||
import { getSession } from '../wrapper'
|
||||
|
||||
export class NTQQGroupApi {
|
||||
static async activateMemberListChange() {
|
||||
@@ -55,45 +55,15 @@ export class NTQQGroupApi {
|
||||
return result.groupList
|
||||
}
|
||||
|
||||
static async getGroupMembers(groupQQ: string, num = 3000): Promise<GroupMember[]> {
|
||||
const sceneId = await callNTQQApi({
|
||||
methodName: NTQQApiMethod.GROUP_MEMBER_SCENE,
|
||||
args: [
|
||||
{
|
||||
groupCode: groupQQ,
|
||||
scene: 'groupMemberList_MainWindow',
|
||||
},
|
||||
],
|
||||
})
|
||||
// log("get group member sceneId", sceneId)
|
||||
try {
|
||||
const result = await callNTQQApi<{
|
||||
result: { infos: any }
|
||||
}>({
|
||||
methodName: NTQQApiMethod.GROUP_MEMBERS,
|
||||
args: [
|
||||
{
|
||||
sceneId: sceneId,
|
||||
num: num,
|
||||
},
|
||||
null,
|
||||
],
|
||||
})
|
||||
// log("members info", typeof result.result.infos, Object.keys(result.result.infos))
|
||||
const values = result.result.infos.values()
|
||||
|
||||
const members: GroupMember[] = Array.from(values)
|
||||
for (const member of members) {
|
||||
uidMaps[member.uid] = member.uin
|
||||
}
|
||||
// log(uidMaps)
|
||||
// log("members info", values)
|
||||
log(`get group ${groupQQ} members success`)
|
||||
return members
|
||||
} catch (e) {
|
||||
log(`get group ${groupQQ} members failed`, e)
|
||||
return []
|
||||
static async getGroupMembers(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> {
|
||||
const session = getSession()
|
||||
const groupService = session?.getGroupService()
|
||||
const sceneId = groupService?.createMemberListScene(groupQQ, 'groupMemberList_MainWindow')
|
||||
const result = await groupService?.getNextMemberList(sceneId!, undefined, num)
|
||||
if (result?.errCode !== 0) {
|
||||
throw ('获取群成员列表出错,' + result?.errMsg)
|
||||
}
|
||||
return result.result.infos
|
||||
}
|
||||
|
||||
static async getGroupMembersInfo(groupCode: string, uids: string[], forceUpdate: boolean = false) {
|
||||
@@ -300,28 +270,28 @@ export class NTQQGroupApi {
|
||||
static publishGroupBulletin(groupQQ: string, title: string, content: string) { }
|
||||
|
||||
static async removeGroupEssence(GroupCode: string, msgId: string) {
|
||||
const session = wrapperApi.NodeIQQNTWrapperSession
|
||||
const session = getSession()
|
||||
// 代码没测过
|
||||
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
|
||||
let MsgData = await session?.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: GroupCode }, msgId, 1, false)
|
||||
let param = {
|
||||
groupCode: GroupCode,
|
||||
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
|
||||
msgSeq: parseInt(MsgData.msgList[0].msgSeq)
|
||||
msgRandom: parseInt(MsgData?.msgList[0].msgRandom!),
|
||||
msgSeq: parseInt(MsgData?.msgList[0].msgSeq!)
|
||||
}
|
||||
// GetMsgByShoretID(ShoretID) -> MsgService.getMsgs(Peer,MsgId,1,false) -> 组出参数
|
||||
return session?.getGroupService().removeGroupEssence(param)
|
||||
}
|
||||
|
||||
static async addGroupEssence(GroupCode: string, msgId: string) {
|
||||
const session = wrapperApi.NodeIQQNTWrapperSession
|
||||
const session = getSession()
|
||||
// 代码没测过
|
||||
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
|
||||
let MsgData = await session?.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: GroupCode }, msgId, 1, false)
|
||||
let param = {
|
||||
groupCode: GroupCode,
|
||||
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
|
||||
msgSeq: parseInt(MsgData.msgList[0].msgSeq)
|
||||
msgRandom: parseInt(MsgData?.msgList[0].msgRandom!),
|
||||
msgSeq: parseInt(MsgData?.msgList[0].msgSeq!)
|
||||
}
|
||||
// GetMsgByShoretID(ShoretID) -> MsgService.getMsgs(Peer,MsgId,1,false) -> 组出参数
|
||||
return session?.getGroupService().addGroupEssence(param)
|
||||
|
@@ -5,8 +5,9 @@ import { selfInfo } from '../../common/data'
|
||||
import { ReceiveCmdS, registerReceiveHook } from '../hook'
|
||||
import { log } from '../../common/utils/log'
|
||||
import { sleep } from '../../common/utils/helper'
|
||||
import { isQQ998 } from '../../common/utils'
|
||||
import { wrapperApi } from '@/ntqqapi/wrapper'
|
||||
import { isQQ998, getBuildVersion } from '../../common/utils'
|
||||
import { getSession } from '@/ntqqapi/wrapper'
|
||||
import { NTEventDispatch } from '@/common/utils/EventTask'
|
||||
|
||||
export let sendMessagePool: Record<string, ((sendSuccessMsg: RawMessage) => void) | null> = {} // peerUid: callbackFunc
|
||||
|
||||
@@ -202,6 +203,9 @@ export class NTQQMsgApi {
|
||||
}
|
||||
|
||||
static async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
||||
if (getBuildVersion() >= 26702) {
|
||||
return NTQQMsgApi.sendMsgV2(peer, msgElements, waitComplete, timeout)
|
||||
}
|
||||
const waiter = sendWaiter(peer, waitComplete, timeout)
|
||||
callNTQQApi({
|
||||
methodName: NTQQApiMethod.SEND_MSG,
|
||||
@@ -218,6 +222,72 @@ export class NTQQMsgApi {
|
||||
return await waiter
|
||||
}
|
||||
|
||||
static async sendMsgV2(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
||||
if (peer.chatType === ChatType.temp) {
|
||||
//await NTQQMsgApi.PrepareTempChat().then().catch()
|
||||
}
|
||||
function generateMsgId() {
|
||||
const timestamp = Math.floor(Date.now() / 1000)
|
||||
const random = Math.floor(Math.random() * Math.pow(2, 32))
|
||||
const buffer = Buffer.alloc(8)
|
||||
buffer.writeUInt32BE(timestamp, 0)
|
||||
buffer.writeUInt32BE(random, 4)
|
||||
const msgId = BigInt('0x' + buffer.toString('hex')).toString()
|
||||
return msgId
|
||||
}
|
||||
// 此处有采用Hack方法 利用数据返回正确得到对应消息
|
||||
// 与之前 Peer队列 MsgSeq队列 真正的MsgId并发不同
|
||||
// 谨慎采用 目前测试暂无问题 Developer.Mlikiowa
|
||||
let msgId: string
|
||||
try {
|
||||
msgId = await NTQQMsgApi.getMsgUnique(peer.chatType, await NTQQMsgApi.getServerTime())
|
||||
} catch (error) {
|
||||
//if (!napCatCore.session.getMsgService()['generateMsgUniqueId'])
|
||||
//兜底识别策略V2
|
||||
msgId = generateMsgId().toString()
|
||||
}
|
||||
let data = await NTEventDispatch.CallNormalEvent<
|
||||
(msgId: string, peer: Peer, msgElements: SendMessageElement[], map: Map<any, any>) => Promise<unknown>,
|
||||
(msgList: RawMessage[]) => void
|
||||
>(
|
||||
'NodeIKernelMsgService/sendMsg',
|
||||
'NodeIKernelMsgListener/onMsgInfoListUpdate',
|
||||
1,
|
||||
timeout,
|
||||
(msgRecords: RawMessage[]) => {
|
||||
for (let msgRecord of msgRecords) {
|
||||
if (msgRecord.msgId === msgId && msgRecord.sendStatus === 2) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
msgId,
|
||||
peer,
|
||||
msgElements,
|
||||
new Map()
|
||||
)
|
||||
const retMsg = data[1].find(msgRecord => {
|
||||
if (msgRecord.msgId === msgId) {
|
||||
return true
|
||||
}
|
||||
})
|
||||
return retMsg!
|
||||
}
|
||||
|
||||
static async getMsgUnique(chatType: number, time: string) {
|
||||
const session = getSession()
|
||||
if (getBuildVersion() >= 26702) {
|
||||
return session?.getMsgService().generateMsgUniqueId(chatType, time)!
|
||||
}
|
||||
return session?.getMsgService().getMsgUniqueId(time)!
|
||||
}
|
||||
|
||||
static async getServerTime() {
|
||||
const session = getSession()
|
||||
return session?.getMSFService().getServerTime()!
|
||||
}
|
||||
|
||||
static async forwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
|
||||
const waiter = sendWaiter(destPeer, true, 10000)
|
||||
callNTQQApi<GeneralCallResult>({
|
||||
@@ -289,7 +359,7 @@ export class NTQQMsgApi {
|
||||
})
|
||||
}
|
||||
static async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) {
|
||||
const session = wrapperApi.NodeIQQNTWrapperSession
|
||||
const session = getSession()
|
||||
return await session?.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z);
|
||||
}
|
||||
}
|
||||
|
@@ -1,14 +1,14 @@
|
||||
import { callNTQQApi, GeneralCallResult, NTQQApiClass, NTQQApiMethod } from '../ntcall'
|
||||
import { Group, SelfInfo, User } from '../types'
|
||||
import { SelfInfo, User, UserDetailInfoByUin, UserDetailInfoByUinV2 } from '../types'
|
||||
import { ReceiveCmdS } from '../hook'
|
||||
import { selfInfo, uidMaps } from '../../common/data'
|
||||
import { cacheFunc, isQQ998, log, sleep } from '../../common/utils'
|
||||
import { wrapperApi } from '@/ntqqapi/wrapper'
|
||||
import { selfInfo, uidMaps, friends, groupMembers } from '@/common/data'
|
||||
import { cacheFunc, isQQ998, log, sleep, getBuildVersion } from '@/common/utils'
|
||||
import { getSession } from '@/ntqqapi/wrapper'
|
||||
import { RequestUtil } from '@/common/utils/request'
|
||||
import { NodeIKernelProfileService, UserDetailSource, ProfileBizType } from '../services'
|
||||
import { NodeIKernelProfileListener } from '../listeners'
|
||||
import { NTEventDispatch } from '@/common/utils/EventTask'
|
||||
import { qqPkgInfo } from '@/common/utils/QQBasicInfo'
|
||||
import { NTQQFriendApi } from './friend'
|
||||
|
||||
const userInfoCache: Record<string, User> = {} // uid: User
|
||||
|
||||
@@ -50,7 +50,7 @@ export class NTQQUserApi {
|
||||
return result.profiles.get(uid)
|
||||
}
|
||||
|
||||
// 26702
|
||||
/** 26702 */
|
||||
static async fetchUserDetailInfo(uid: string) {
|
||||
type EventService = NodeIKernelProfileService['fetchUserDetailInfo']
|
||||
type EventListener = NodeIKernelProfileListener['onUserDetailInfoChanged']
|
||||
@@ -63,9 +63,9 @@ export class NTQQUserApi {
|
||||
5000,
|
||||
(profile) => {
|
||||
if (profile.uid === uid) {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
},
|
||||
'BuddyProfileStore',
|
||||
[
|
||||
@@ -89,7 +89,7 @@ export class NTQQUserApi {
|
||||
}
|
||||
|
||||
static async getUserDetailInfo(uid: string, getLevel = false, withBizInfo = true) {
|
||||
if (+qqPkgInfo.buildVersion >= 26702) {
|
||||
if (getBuildVersion() >= 26702) {
|
||||
return this.fetchUserDetailInfo(uid)
|
||||
}
|
||||
// this.getUserInfo(uid)
|
||||
@@ -195,7 +195,7 @@ export class NTQQUserApi {
|
||||
}
|
||||
|
||||
static async getPSkey(domains: string[]): Promise<Map<string, string>> {
|
||||
const session = wrapperApi.NodeIQQNTWrapperSession
|
||||
const session = getSession()
|
||||
const res = await session?.getTipOffService().getPskey(domains, true)
|
||||
if (res.result !== 0) {
|
||||
throw new Error(`获取Pskey失败: ${res.errMsg}`)
|
||||
@@ -204,7 +204,91 @@ export class NTQQUserApi {
|
||||
}
|
||||
|
||||
static async getClientKey(): Promise<ClientKeyData> {
|
||||
const session = wrapperApi.NodeIQQNTWrapperSession
|
||||
const session = getSession()
|
||||
return await session?.getTicketService().forceFetchClientKey('')
|
||||
}
|
||||
|
||||
static async like(uid: string, count = 1): Promise<{ result: number, errMsg: string, succCounts: number }> {
|
||||
const session = getSession()
|
||||
return session?.getProfileLikeService().setBuddyProfileLike({
|
||||
friendUid: uid,
|
||||
sourceId: 71,
|
||||
doLikeCount: count,
|
||||
doLikeTollCount: 0
|
||||
})!
|
||||
}
|
||||
|
||||
static async getUidByUinV1(Uin: string) {
|
||||
const session = getSession()
|
||||
// 通用转换开始尝试
|
||||
let uid = (await session?.getUixConvertService().getUid([Uin])!).uidInfo.get(Uin);
|
||||
// Uid 好友转
|
||||
if (!uid) {
|
||||
friends.forEach((t) => {
|
||||
if (t.uin == Uin) {
|
||||
uid = t.uid
|
||||
}
|
||||
})
|
||||
}
|
||||
//Uid 群友列表转
|
||||
if (!uid) {
|
||||
for (let groupMembersList of groupMembers.values()) {
|
||||
for (let GroupMember of groupMembersList.values()) {
|
||||
if (GroupMember.uin == Uin) {
|
||||
uid = GroupMember.uid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!uid) {
|
||||
let unveifyUid = (await NTQQUserApi.getUserDetailInfoByUin(Uin)).info.uid;//从QQ Native 特殊转换 方法三
|
||||
if (unveifyUid.indexOf('*') == -1) {
|
||||
uid = unveifyUid
|
||||
}
|
||||
}
|
||||
return uid
|
||||
}
|
||||
|
||||
static async getUidByUinV2(Uin: string) {
|
||||
const session = getSession()
|
||||
let uid = (await session?.getProfileService().getUidByUin('FriendsServiceImpl', [Uin])!).get(Uin)
|
||||
if (uid) return uid
|
||||
uid = (await session?.getGroupService().getUidByUins([Uin])!).uids.get(Uin)
|
||||
if (uid) return uid
|
||||
uid = (await session?.getUixConvertService().getUid([Uin])!).uidInfo.get(Uin)
|
||||
if (uid) return uid
|
||||
console.log((await NTQQFriendApi.getBuddyIdMapCache(true)))
|
||||
uid = (await NTQQFriendApi.getBuddyIdMapCache(true)).getValue(Uin)//从Buddy缓存获取Uid
|
||||
if (uid) return uid
|
||||
uid = (await NTQQFriendApi.getBuddyIdMap(true)).getValue(Uin)
|
||||
if (uid) return uid
|
||||
let unveifyUid = (await NTQQUserApi.getUserDetailInfoByUinV2(Uin)).detail.uid//从QQ Native 特殊转换
|
||||
if (unveifyUid.indexOf("*") == -1) uid = unveifyUid
|
||||
//if (uid) return uid
|
||||
return uid
|
||||
}
|
||||
|
||||
static async getUidByUin(Uin: string) {
|
||||
if (getBuildVersion() >= 26702) {
|
||||
return await NTQQUserApi.getUidByUinV2(Uin)
|
||||
}
|
||||
return await NTQQUserApi.getUidByUinV1(Uin)
|
||||
}
|
||||
|
||||
static async getUserDetailInfoByUinV2(Uin: string) {
|
||||
return await NTEventDispatch.CallNoListenerEvent
|
||||
<(Uin: string) => Promise<UserDetailInfoByUinV2>>(
|
||||
'NodeIKernelProfileService/getUserDetailInfoByUin',
|
||||
5000,
|
||||
Uin
|
||||
)
|
||||
}
|
||||
static async getUserDetailInfoByUin(Uin: string) {
|
||||
return NTEventDispatch.CallNoListenerEvent
|
||||
<(Uin: string) => Promise<UserDetailInfoByUin>>(
|
||||
'NodeIKernelProfileService/getUserDetailInfoByUin',
|
||||
5000,
|
||||
Uin
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ import { log } from '../common/utils/log'
|
||||
import { defaultVideoThumb, getVideoInfo } from '../common/utils/video'
|
||||
import { encodeSilk } from '../common/utils/audio'
|
||||
import { isNull } from '../common/utils'
|
||||
import faceConfig from './face_config.json';
|
||||
import faceConfig from './face_config.json'
|
||||
|
||||
export const mFaceCache = new Map<string, string>() // emojiId -> faceName
|
||||
|
||||
|
@@ -268,7 +268,7 @@ async function updateGroups(_groups: Group[], needUpdate: boolean = true) {
|
||||
const members = await NTQQGroupApi.getGroupMembers(group.groupCode)
|
||||
|
||||
if (members) {
|
||||
existGroup.members = members
|
||||
existGroup.members = Array.from(members.values())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,11 +287,11 @@ async function processGroupEvent(payload: { groupList: Group[] }) {
|
||||
await sleep(200) // 如果请求QQ API的速度过快,通常无法正确拉取到最新的群信息,因此这里人为引入一个延时
|
||||
const newMembers = await NTQQGroupApi.getGroupMembers(group.groupCode)
|
||||
|
||||
group.members = newMembers
|
||||
group.members = Array.from(newMembers.values())
|
||||
const newMembersSet = new Set<string>() // 建立索引降低时间复杂度
|
||||
|
||||
for (const member of newMembers) {
|
||||
newMembersSet.add(member.uin)
|
||||
newMembersSet.add(member[1].uin)
|
||||
}
|
||||
|
||||
// 判断bot是否是管理员,如果是管理员不需要从这里得知有人退群,这里的退群无法得知是主动退群还是被踢
|
||||
|
240
src/ntqqapi/listeners/NodeIKernelGroupListener.ts
Normal file
240
src/ntqqapi/listeners/NodeIKernelGroupListener.ts
Normal file
@@ -0,0 +1,240 @@
|
||||
import { Group, GroupListUpdateType, GroupMember, GroupNotify } from '@/ntqqapi/types'
|
||||
|
||||
interface IGroupListener {
|
||||
onGroupListUpdate(updateType: GroupListUpdateType, groupList: Group[]): void
|
||||
|
||||
onGroupExtListUpdate(...args: unknown[]): void
|
||||
|
||||
onGroupSingleScreenNotifies(doubt: boolean, seq: string, notifies: GroupNotify[]): void
|
||||
|
||||
onGroupNotifiesUpdated(dboubt: boolean, notifies: GroupNotify[]): void
|
||||
|
||||
onGroupNotifiesUnreadCountUpdated(...args: unknown[]): void
|
||||
|
||||
onGroupDetailInfoChange(...args: unknown[]): void
|
||||
|
||||
onGroupAllInfoChange(...args: unknown[]): void
|
||||
|
||||
onGroupsMsgMaskResult(...args: unknown[]): void
|
||||
|
||||
onGroupConfMemberChange(...args: unknown[]): void
|
||||
|
||||
onGroupBulletinChange(...args: unknown[]): void
|
||||
|
||||
onGetGroupBulletinListResult(...args: unknown[]): void
|
||||
|
||||
onMemberListChange(arg: {
|
||||
sceneId: string,
|
||||
ids: string[],
|
||||
infos: Map<string, GroupMember>,
|
||||
finish: boolean,
|
||||
hasRobot: boolean
|
||||
}): void
|
||||
|
||||
onMemberInfoChange(groupCode: string, changeType: number, members: Map<string, GroupMember>): void
|
||||
|
||||
onSearchMemberChange(...args: unknown[]): void
|
||||
|
||||
onGroupBulletinRichMediaDownloadComplete(...args: unknown[]): void
|
||||
|
||||
onGroupBulletinRichMediaProgressUpdate(...args: unknown[]): void
|
||||
|
||||
onGroupStatisticInfoChange(...args: unknown[]): void
|
||||
|
||||
onJoinGroupNotify(...args: unknown[]): void
|
||||
|
||||
onShutUpMemberListChanged(...args: unknown[]): void
|
||||
|
||||
onGroupBulletinRemindNotify(...args: unknown[]): void
|
||||
|
||||
onGroupFirstBulletinNotify(...args: unknown[]): void
|
||||
|
||||
onJoinGroupNoVerifyFlag(...args: unknown[]): void
|
||||
|
||||
onGroupArkInviteStateResult(...args: unknown[]): void
|
||||
// 发现于Win 9.9.9 23159
|
||||
onGroupMemberLevelInfoChange(...args: unknown[]): void
|
||||
}
|
||||
|
||||
export interface NodeIKernelGroupListener extends IGroupListener {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(listener: IGroupListener): NodeIKernelGroupListener
|
||||
}
|
||||
|
||||
export class GroupListener implements IGroupListener {
|
||||
// 发现于Win 9.9.9 23159
|
||||
onGroupMemberLevelInfoChange(...args: unknown[]): void {
|
||||
|
||||
}
|
||||
onGetGroupBulletinListResult(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupAllInfoChange(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupBulletinChange(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupBulletinRemindNotify(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupArkInviteStateResult(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupBulletinRichMediaDownloadComplete(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupConfMemberChange(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupDetailInfoChange(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupExtListUpdate(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupFirstBulletinNotify(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupListUpdate(updateType: GroupListUpdateType, groupList: Group[]) {
|
||||
}
|
||||
|
||||
onGroupNotifiesUpdated(dboubt: boolean, notifies: GroupNotify[]) {
|
||||
}
|
||||
|
||||
onGroupBulletinRichMediaProgressUpdate(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupNotifiesUnreadCountUpdated(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupSingleScreenNotifies(doubt: boolean, seq: string, notifies: GroupNotify[]) {
|
||||
}
|
||||
|
||||
onGroupsMsgMaskResult(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onGroupStatisticInfoChange(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onJoinGroupNotify(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onJoinGroupNoVerifyFlag(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onMemberInfoChange(groupCode: string, changeType: number, members: Map<string, GroupMember>) {
|
||||
}
|
||||
|
||||
onMemberListChange(arg: {
|
||||
sceneId: string,
|
||||
ids: string[],
|
||||
infos: Map<string, GroupMember>, // uid -> GroupMember
|
||||
finish: boolean,
|
||||
hasRobot: boolean
|
||||
}) {
|
||||
}
|
||||
|
||||
onSearchMemberChange(...args: unknown[]) {
|
||||
}
|
||||
|
||||
onShutUpMemberListChanged(...args: unknown[]) {
|
||||
}
|
||||
}
|
||||
|
||||
export class DebugGroupListener implements IGroupListener {
|
||||
onGroupMemberLevelInfoChange(...args: unknown[]): void {
|
||||
console.log('onGroupMemberLevelInfoChange:', ...args)
|
||||
}
|
||||
onGetGroupBulletinListResult(...args: unknown[]) {
|
||||
console.log('onGetGroupBulletinListResult:', ...args)
|
||||
}
|
||||
|
||||
onGroupAllInfoChange(...args: unknown[]) {
|
||||
console.log('onGroupAllInfoChange:', ...args)
|
||||
}
|
||||
|
||||
onGroupBulletinChange(...args: unknown[]) {
|
||||
console.log('onGroupBulletinChange:', ...args)
|
||||
}
|
||||
|
||||
onGroupBulletinRemindNotify(...args: unknown[]) {
|
||||
console.log('onGroupBulletinRemindNotify:', ...args)
|
||||
}
|
||||
|
||||
onGroupArkInviteStateResult(...args: unknown[]) {
|
||||
console.log('onGroupArkInviteStateResult:', ...args)
|
||||
}
|
||||
|
||||
onGroupBulletinRichMediaDownloadComplete(...args: unknown[]) {
|
||||
console.log('onGroupBulletinRichMediaDownloadComplete:', ...args)
|
||||
}
|
||||
|
||||
onGroupConfMemberChange(...args: unknown[]) {
|
||||
console.log('onGroupConfMemberChange:', ...args)
|
||||
}
|
||||
|
||||
onGroupDetailInfoChange(...args: unknown[]) {
|
||||
console.log('onGroupDetailInfoChange:', ...args)
|
||||
}
|
||||
|
||||
onGroupExtListUpdate(...args: unknown[]) {
|
||||
console.log('onGroupExtListUpdate:', ...args)
|
||||
}
|
||||
|
||||
onGroupFirstBulletinNotify(...args: unknown[]) {
|
||||
console.log('onGroupFirstBulletinNotify:', ...args)
|
||||
}
|
||||
|
||||
onGroupListUpdate(...args: unknown[]) {
|
||||
console.log('onGroupListUpdate:', ...args)
|
||||
}
|
||||
|
||||
onGroupNotifiesUpdated(...args: unknown[]) {
|
||||
console.log('onGroupNotifiesUpdated:', ...args)
|
||||
}
|
||||
|
||||
onGroupBulletinRichMediaProgressUpdate(...args: unknown[]) {
|
||||
console.log('onGroupBulletinRichMediaProgressUpdate:', ...args)
|
||||
}
|
||||
|
||||
onGroupNotifiesUnreadCountUpdated(...args: unknown[]) {
|
||||
console.log('onGroupNotifiesUnreadCountUpdated:', ...args)
|
||||
}
|
||||
|
||||
onGroupSingleScreenNotifies(doubt: boolean, seq: string, notifies: GroupNotify[]) {
|
||||
console.log('onGroupSingleScreenNotifies:')
|
||||
}
|
||||
|
||||
onGroupsMsgMaskResult(...args: unknown[]) {
|
||||
console.log('onGroupsMsgMaskResult:', ...args)
|
||||
}
|
||||
|
||||
onGroupStatisticInfoChange(...args: unknown[]) {
|
||||
console.log('onGroupStatisticInfoChange:', ...args)
|
||||
}
|
||||
|
||||
onJoinGroupNotify(...args: unknown[]) {
|
||||
console.log('onJoinGroupNotify:', ...args)
|
||||
}
|
||||
|
||||
onJoinGroupNoVerifyFlag(...args: unknown[]) {
|
||||
console.log('onJoinGroupNoVerifyFlag:', ...args)
|
||||
}
|
||||
|
||||
onMemberInfoChange(groupCode: string, changeType: number, members: Map<string, GroupMember>) {
|
||||
console.log('onMemberInfoChange:', groupCode, changeType, members)
|
||||
}
|
||||
|
||||
onMemberListChange(...args: unknown[]) {
|
||||
console.log('onMemberListChange:', ...args)
|
||||
}
|
||||
|
||||
onSearchMemberChange(...args: unknown[]) {
|
||||
console.log('onSearchMemberChange:', ...args)
|
||||
}
|
||||
|
||||
onShutUpMemberListChanged(...args: unknown[]) {
|
||||
console.log('onShutUpMemberListChanged:', ...args)
|
||||
}
|
||||
}
|
514
src/ntqqapi/listeners/NodeIKernelMsgListener.ts
Normal file
514
src/ntqqapi/listeners/NodeIKernelMsgListener.ts
Normal file
@@ -0,0 +1,514 @@
|
||||
import { ChatType, RawMessage } from '@/ntqqapi/types'
|
||||
|
||||
export interface OnRichMediaDownloadCompleteParams {
|
||||
fileModelId: string,
|
||||
msgElementId: string,
|
||||
msgId: string,
|
||||
fileId: string,
|
||||
fileProgress: string, // '0'
|
||||
fileSpeed: string, // '0'
|
||||
fileErrCode: string, // '0'
|
||||
fileErrMsg: string,
|
||||
fileDownType: number, // 暂时未知
|
||||
thumbSize: number,
|
||||
filePath: string,
|
||||
totalSize: string,
|
||||
trasferStatus: number,
|
||||
step: number,
|
||||
commonFileInfo: unknown | null,
|
||||
fileSrvErrCode: string,
|
||||
clientMsg: string,
|
||||
businessId: number,
|
||||
userTotalSpacePerDay: unknown | null,
|
||||
userUsedSpacePerDay: unknown | null
|
||||
}
|
||||
|
||||
export interface onGroupFileInfoUpdateParamType {
|
||||
retCode: number
|
||||
retMsg: string
|
||||
clientWording: string
|
||||
isEnd: boolean
|
||||
item: Array<any>
|
||||
allFileCount: string
|
||||
nextIndex: string
|
||||
reqId: string
|
||||
}
|
||||
|
||||
// {
|
||||
// sessionType: 1,
|
||||
// chatType: 100,
|
||||
// peerUid: 'u_PVQ3tl6K78xxxx',
|
||||
// groupCode: '809079648',
|
||||
// fromNick: '拾xxxx,
|
||||
// sig: '0x'
|
||||
// }
|
||||
export interface TempOnRecvParams {
|
||||
sessionType: number,//1
|
||||
chatType: ChatType,//100
|
||||
peerUid: string,//uid
|
||||
groupCode: string,//gc
|
||||
fromNick: string,//gc name
|
||||
sig: string,
|
||||
}
|
||||
|
||||
export interface IKernelMsgListener {
|
||||
onAddSendMsg(msgRecord: RawMessage): void
|
||||
|
||||
onBroadcastHelperDownloadComplete(broadcastHelperTransNotifyInfo: unknown): void
|
||||
|
||||
onBroadcastHelperProgressUpdate(broadcastHelperTransNotifyInfo: unknown): void
|
||||
|
||||
onChannelFreqLimitInfoUpdate(contact: unknown, z: unknown, freqLimitInfo: unknown): void
|
||||
|
||||
onContactUnreadCntUpdate(hashMap: unknown): void
|
||||
|
||||
onCustomWithdrawConfigUpdate(customWithdrawConfig: unknown): void
|
||||
|
||||
onDraftUpdate(contact: unknown, arrayList: unknown, j2: unknown): void
|
||||
|
||||
onEmojiDownloadComplete(emojiNotifyInfo: unknown): void
|
||||
|
||||
onEmojiResourceUpdate(emojiResourceInfo: unknown): void
|
||||
|
||||
onFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): void
|
||||
|
||||
onFileMsgCome(arrayList: unknown): void
|
||||
|
||||
onFirstViewDirectMsgUpdate(firstViewDirectMsgNotifyInfo: unknown): void
|
||||
|
||||
onFirstViewGroupGuildMapping(arrayList: unknown): void
|
||||
|
||||
onGrabPasswordRedBag(i2: unknown, str: unknown, i3: unknown, recvdOrder: unknown, msgRecord: unknown): void
|
||||
|
||||
onGroupFileInfoAdd(groupItem: unknown): void
|
||||
|
||||
onGroupFileInfoUpdate(groupFileListResult: onGroupFileInfoUpdateParamType): void
|
||||
|
||||
onGroupGuildUpdate(groupGuildNotifyInfo: unknown): void
|
||||
|
||||
onGroupTransferInfoAdd(groupItem: unknown): void
|
||||
|
||||
onGroupTransferInfoUpdate(groupFileListResult: unknown): void
|
||||
|
||||
onGuildInteractiveUpdate(guildInteractiveNotificationItem: unknown): void
|
||||
|
||||
onGuildMsgAbFlagChanged(guildMsgAbFlag: unknown): void
|
||||
|
||||
onGuildNotificationAbstractUpdate(guildNotificationAbstractInfo: unknown): void
|
||||
|
||||
onHitCsRelatedEmojiResult(downloadRelateEmojiResultInfo: unknown): void
|
||||
|
||||
onHitEmojiKeywordResult(hitRelatedEmojiWordsResult: unknown): void
|
||||
|
||||
onHitRelatedEmojiResult(relatedWordEmojiInfo: unknown): void
|
||||
|
||||
onImportOldDbProgressUpdate(importOldDbMsgNotifyInfo: unknown): void
|
||||
|
||||
onInputStatusPush(inputStatusInfo: unknown): void
|
||||
|
||||
onKickedOffLine(kickedInfo: unknown): void
|
||||
|
||||
onLineDev(arrayList: unknown): void
|
||||
|
||||
onLogLevelChanged(j2: unknown): void
|
||||
|
||||
onMsgAbstractUpdate(arrayList: unknown): void
|
||||
|
||||
onMsgBoxChanged(arrayList: unknown): void
|
||||
|
||||
onMsgDelete(contact: unknown, arrayList: unknown): void
|
||||
|
||||
onMsgEventListUpdate(hashMap: unknown): void
|
||||
|
||||
onMsgInfoListAdd(arrayList: unknown): void
|
||||
|
||||
onMsgInfoListUpdate(msgList: RawMessage[]): void
|
||||
|
||||
onMsgQRCodeStatusChanged(i2: unknown): void
|
||||
|
||||
onMsgRecall(i2: unknown, str: unknown, j2: unknown): void
|
||||
|
||||
onMsgSecurityNotify(msgRecord: unknown): void
|
||||
|
||||
onMsgSettingUpdate(msgSetting: unknown): void
|
||||
|
||||
onNtFirstViewMsgSyncEnd(): void
|
||||
|
||||
onNtMsgSyncEnd(): void
|
||||
|
||||
onNtMsgSyncStart(): void
|
||||
|
||||
onReadFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): void
|
||||
|
||||
onRecvGroupGuildFlag(i2: unknown): void
|
||||
|
||||
onRecvMsg(...arrayList: unknown[]): void
|
||||
|
||||
onRecvMsgSvrRspTransInfo(j2: unknown, contact: unknown, i2: unknown, i3: unknown, str: unknown, bArr: unknown): void
|
||||
|
||||
onRecvOnlineFileMsg(arrayList: unknown): void
|
||||
|
||||
onRecvS2CMsg(arrayList: unknown): void
|
||||
|
||||
onRecvSysMsg(arrayList: unknown): void
|
||||
|
||||
onRecvUDCFlag(i2: unknown): void
|
||||
|
||||
onRichMediaDownloadComplete(fileTransNotifyInfo: OnRichMediaDownloadCompleteParams): void
|
||||
|
||||
onRichMediaProgerssUpdate(fileTransNotifyInfo: unknown): void
|
||||
|
||||
onRichMediaUploadComplete(fileTransNotifyInfo: unknown): void
|
||||
|
||||
onSearchGroupFileInfoUpdate(searchGroupFileResult:
|
||||
{
|
||||
result: {
|
||||
retCode: number,
|
||||
retMsg: string,
|
||||
clientWording: string
|
||||
},
|
||||
syncCookie: string,
|
||||
totalMatchCount: number,
|
||||
ownerMatchCount: number,
|
||||
isEnd: boolean,
|
||||
reqId: number,
|
||||
item: Array<{
|
||||
groupCode: string,
|
||||
groupName: string,
|
||||
uploaderUin: string,
|
||||
uploaderName: string,
|
||||
matchUin: string,
|
||||
matchWords: Array<unknown>,
|
||||
fileNameHits: Array<{
|
||||
start: number,
|
||||
end: number
|
||||
}>,
|
||||
fileModelId: string,
|
||||
fileId: string,
|
||||
fileName: string,
|
||||
fileSize: string,
|
||||
busId: number,
|
||||
uploadTime: number,
|
||||
modifyTime: number,
|
||||
deadTime: number,
|
||||
downloadTimes: number,
|
||||
localPath: string
|
||||
}>
|
||||
}): void
|
||||
|
||||
onSendMsgError(j2: unknown, contact: unknown, i2: unknown, str: unknown): void
|
||||
|
||||
onSysMsgNotification(i2: unknown, j2: unknown, j3: unknown, arrayList: unknown): void
|
||||
|
||||
onTempChatInfoUpdate(tempChatInfo: TempOnRecvParams): void
|
||||
|
||||
onUnreadCntAfterFirstView(hashMap: unknown): void
|
||||
|
||||
onUnreadCntUpdate(hashMap: unknown): void
|
||||
|
||||
onUserChannelTabStatusChanged(z: unknown): void
|
||||
|
||||
onUserOnlineStatusChanged(z: unknown): void
|
||||
|
||||
onUserTabStatusChanged(arrayList: unknown): void
|
||||
|
||||
onlineStatusBigIconDownloadPush(i2: unknown, j2: unknown, str: unknown): void
|
||||
|
||||
onlineStatusSmallIconDownloadPush(i2: unknown, j2: unknown, str: unknown): void
|
||||
|
||||
// 第一次发现于Linux
|
||||
onUserSecQualityChanged(...args: unknown[]): void
|
||||
|
||||
onMsgWithRichLinkInfoUpdate(...args: unknown[]): void
|
||||
|
||||
onRedTouchChanged(...args: unknown[]): void
|
||||
|
||||
// 第一次发现于Win 9.9.9 23159
|
||||
onBroadcastHelperProgerssUpdate(...args: unknown[]): void
|
||||
|
||||
}
|
||||
|
||||
export interface NodeIKernelMsgListener extends IKernelMsgListener {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(listener: IKernelMsgListener): NodeIKernelMsgListener
|
||||
}
|
||||
|
||||
|
||||
export class MsgListener implements IKernelMsgListener {
|
||||
onAddSendMsg(msgRecord: RawMessage) {
|
||||
|
||||
}
|
||||
|
||||
onBroadcastHelperDownloadComplete(broadcastHelperTransNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onBroadcastHelperProgressUpdate(broadcastHelperTransNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onChannelFreqLimitInfoUpdate(contact: unknown, z: unknown, freqLimitInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onContactUnreadCntUpdate(hashMap: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onCustomWithdrawConfigUpdate(customWithdrawConfig: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onDraftUpdate(contact: unknown, arrayList: unknown, j2: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onEmojiDownloadComplete(emojiNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onEmojiResourceUpdate(emojiResourceInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onFileMsgCome(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onFirstViewDirectMsgUpdate(firstViewDirectMsgNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onFirstViewGroupGuildMapping(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onGrabPasswordRedBag(i2: unknown, str: unknown, i3: unknown, recvdOrder: unknown, msgRecord: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onGroupFileInfoAdd(groupItem: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onGroupFileInfoUpdate(groupFileListResult: onGroupFileInfoUpdateParamType) {
|
||||
|
||||
}
|
||||
|
||||
onGroupGuildUpdate(groupGuildNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
onGroupTransferInfoAdd(groupItem: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onGroupTransferInfoUpdate(groupFileListResult: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onGuildInteractiveUpdate(guildInteractiveNotificationItem: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onGuildMsgAbFlagChanged(guildMsgAbFlag: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onGuildNotificationAbstractUpdate(guildNotificationAbstractInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onHitCsRelatedEmojiResult(downloadRelateEmojiResultInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onHitEmojiKeywordResult(hitRelatedEmojiWordsResult: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onHitRelatedEmojiResult(relatedWordEmojiInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onImportOldDbProgressUpdate(importOldDbMsgNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onInputStatusPush(inputStatusInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onKickedOffLine(kickedInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onLineDev(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onLogLevelChanged(j2: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgAbstractUpdate(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgBoxChanged(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgDelete(contact: unknown, arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgEventListUpdate(hashMap: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgInfoListAdd(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgInfoListUpdate(msgList: RawMessage[]) {
|
||||
|
||||
}
|
||||
|
||||
onMsgQRCodeStatusChanged(i2: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgRecall(i2: unknown, str: unknown, j2: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgSecurityNotify(msgRecord: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onMsgSettingUpdate(msgSetting: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onNtFirstViewMsgSyncEnd() {
|
||||
|
||||
}
|
||||
|
||||
onNtMsgSyncEnd() {
|
||||
|
||||
}
|
||||
|
||||
onNtMsgSyncStart() {
|
||||
|
||||
}
|
||||
|
||||
onReadFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onRecvGroupGuildFlag(i2: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onRecvMsg(arrayList: RawMessage[]) {
|
||||
|
||||
}
|
||||
|
||||
onRecvMsgSvrRspTransInfo(j2: unknown, contact: unknown, i2: unknown, i3: unknown, str: unknown, bArr: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onRecvOnlineFileMsg(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onRecvS2CMsg(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onRecvSysMsg(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onRecvUDCFlag(i2: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onRichMediaDownloadComplete(fileTransNotifyInfo: OnRichMediaDownloadCompleteParams) {
|
||||
}
|
||||
|
||||
onRichMediaProgerssUpdate(fileTransNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onRichMediaUploadComplete(fileTransNotifyInfo: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onSearchGroupFileInfoUpdate(searchGroupFileResult: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onSendMsgError(j2: unknown, contact: unknown, i2: unknown, str: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onSysMsgNotification(i2: unknown, j2: unknown, j3: unknown, arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onTempChatInfoUpdate(tempChatInfo: TempOnRecvParams) {
|
||||
|
||||
}
|
||||
|
||||
onUnreadCntAfterFirstView(hashMap: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onUnreadCntUpdate(hashMap: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onUserChannelTabStatusChanged(z: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onUserOnlineStatusChanged(z: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onUserTabStatusChanged(arrayList: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onlineStatusBigIconDownloadPush(i2: unknown, j2: unknown, str: unknown) {
|
||||
|
||||
}
|
||||
|
||||
onlineStatusSmallIconDownloadPush(i2: unknown, j2: unknown, str: unknown) {
|
||||
|
||||
}
|
||||
|
||||
// 第一次发现于Linux
|
||||
onUserSecQualityChanged(...args: unknown[]) {
|
||||
|
||||
}
|
||||
|
||||
onMsgWithRichLinkInfoUpdate(...args: unknown[]) {
|
||||
|
||||
}
|
||||
|
||||
onRedTouchChanged(...args: unknown[]) {
|
||||
|
||||
}
|
||||
// 第一次发现于Win 9.9.9-23159
|
||||
onBroadcastHelperProgerssUpdate(...args: unknown[]) {
|
||||
|
||||
}
|
||||
}
|
@@ -1 +1,3 @@
|
||||
export * from './NodeIKernelProfileListener'
|
||||
export * from './NodeIKernelProfileListener'
|
||||
export * from './NodeIKernelGroupListener'
|
||||
export * from './NodeIKernelMsgListener'
|
249
src/ntqqapi/services/NodeIKernelGroupService.ts
Normal file
249
src/ntqqapi/services/NodeIKernelGroupService.ts
Normal file
@@ -0,0 +1,249 @@
|
||||
import { NodeIKernelGroupListener } from '@/ntqqapi/listeners'
|
||||
import {
|
||||
GroupExtParam,
|
||||
GroupMember,
|
||||
GroupMemberRole,
|
||||
GroupNotifyTypes,
|
||||
GroupRequestOperateTypes,
|
||||
} from '@/ntqqapi/types'
|
||||
import { GeneralCallResult } from './common'
|
||||
|
||||
//高版本的接口不应该随意使用 使用应该严格进行pr审核 同时部分ipc中未出现的接口不要过于依赖 应该做好数据兜底
|
||||
|
||||
export interface NodeIKernelGroupService {
|
||||
getMemberCommonInfo(Req: {
|
||||
groupCode: string,
|
||||
startUin: string,
|
||||
identifyFlag: string,
|
||||
uinList: string[],
|
||||
memberCommonFilter: {
|
||||
memberUin: number,
|
||||
uinFlag: number,
|
||||
uinFlagExt: number,
|
||||
uinMobileFlag: number,
|
||||
shutUpTime: number,
|
||||
privilege: number,
|
||||
},
|
||||
memberNum: number,
|
||||
filterMethod: string,
|
||||
onlineFlag: string,
|
||||
realSpecialTitleFlag: number
|
||||
}): Promise<unknown>
|
||||
//26702
|
||||
getGroupMemberLevelInfo(groupCode: string): Promise<unknown>
|
||||
//26702
|
||||
getGroupHonorList(groupCodes: Array<string>): unknown
|
||||
|
||||
getUinByUids(uins: string[]): Promise<{
|
||||
errCode: number,
|
||||
errMsg: string,
|
||||
uins: Map<string, string>
|
||||
}>
|
||||
|
||||
getUidByUins(uins: string[]): Promise<{
|
||||
errCode: number,
|
||||
errMsg: string,
|
||||
uids: Map<string, string>
|
||||
}>
|
||||
//26702(其实更早 但是我不知道)
|
||||
checkGroupMemberCache(arrayList: Array<string>): Promise<unknown>
|
||||
|
||||
//26702(其实更早 但是我不知道)
|
||||
getGroupLatestEssenceList(groupCode: string): Promise<unknown>
|
||||
|
||||
//26702(其实更早 但是我不知道)
|
||||
shareDigest(Req: {
|
||||
appId: string,
|
||||
appType: number,
|
||||
msgStyle: number,
|
||||
recvUin: string,
|
||||
sendType: number,
|
||||
clientInfo: {
|
||||
platform: number
|
||||
},
|
||||
richMsg: {
|
||||
usingArk: boolean,
|
||||
title: string,
|
||||
summary: string,
|
||||
url: string,
|
||||
pictureUrl: string,
|
||||
brief: string
|
||||
}
|
||||
}): Promise<unknown>
|
||||
//26702(其实更早 但是我不知道)
|
||||
isEssenceMsg(Req: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<unknown>
|
||||
//26702(其实更早 但是我不知道)
|
||||
queryCachedEssenceMsg(Req: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<unknown>
|
||||
//26702(其实更早 但是我不知道)
|
||||
fetchGroupEssenceList(Req: { groupCode: string, pageStart: number, pageLimit: number }, Arg: unknown): Promise<unknown>
|
||||
//26702
|
||||
getAllMemberList(groupCode: string, forceFetch: boolean): Promise<{
|
||||
errCode: number,
|
||||
errMsg: string,
|
||||
result: {
|
||||
ids: Array<{
|
||||
uid: string,
|
||||
index: number//0
|
||||
}>,
|
||||
infos: {},
|
||||
finish: true,
|
||||
hasRobot: false
|
||||
}
|
||||
}>
|
||||
|
||||
setHeader(uid: string, path: string): unknown
|
||||
|
||||
addKernelGroupListener(listener: NodeIKernelGroupListener): number
|
||||
|
||||
removeKernelGroupListener(listenerId: unknown): void
|
||||
|
||||
createMemberListScene(groupCode: string, scene: string): string
|
||||
|
||||
destroyMemberListScene(SceneId: string): void
|
||||
//About Arg (a) name: lastId 根据手Q来看为object {index:?(number),uid:string}
|
||||
getNextMemberList(sceneId: string, a: undefined, num: number): Promise<{
|
||||
errCode: number, errMsg: string,
|
||||
result: { ids: string[], infos: Map<string, GroupMember>, finish: boolean, hasRobot: boolean }
|
||||
}>
|
||||
|
||||
getPrevMemberList(): unknown
|
||||
|
||||
monitorMemberList(): unknown
|
||||
|
||||
searchMember(sceneId: string, keywords: string[]): unknown
|
||||
|
||||
getMemberInfo(group_id: string, uids: string[], forceFetch: boolean): Promise<GeneralCallResult>
|
||||
//getMemberInfo [ '56729xxxx', [ 'u_4Nj08cwW5Hxxxxx' ], true ]
|
||||
|
||||
kickMember(groupCode: string, memberUids: string[], refuseForever: boolean, kickReason: string): Promise<void>
|
||||
|
||||
modifyMemberRole(groupCode: string, uid: string, role: GroupMemberRole): void
|
||||
|
||||
modifyMemberCardName(groupCode: string, uid: string, cardName: string): void
|
||||
|
||||
getTransferableMemberInfo(groupCode: string): unknown//获取整个群的
|
||||
|
||||
transferGroup(uid: string): void
|
||||
|
||||
getGroupList(force: boolean): Promise<GeneralCallResult>
|
||||
|
||||
getGroupExtList(force: boolean): Promise<GeneralCallResult>
|
||||
|
||||
getGroupDetailInfo(groupCode: string): unknown
|
||||
|
||||
getMemberExtInfo(param: GroupExtParam): Promise<unknown>//req
|
||||
|
||||
getGroupAllInfo(): unknown
|
||||
|
||||
getDiscussExistInfo(): unknown
|
||||
|
||||
getGroupConfMember(): unknown
|
||||
|
||||
getGroupMsgMask(): unknown
|
||||
|
||||
getGroupPortrait(): void
|
||||
|
||||
modifyGroupName(groupCode: string, groupName: string, arg: false): void
|
||||
|
||||
modifyGroupRemark(groupCode: string, remark: string): void
|
||||
|
||||
modifyGroupDetailInfo(groupCode: string, arg: unknown): void
|
||||
|
||||
setGroupMsgMask(groupCode: string, arg: unknown): void
|
||||
|
||||
changeGroupShieldSettingTemp(groupCode: string, arg: unknown): void
|
||||
|
||||
inviteToGroup(arg: unknown): void
|
||||
|
||||
inviteMembersToGroup(args: unknown[]): void
|
||||
|
||||
inviteMembersToGroupWithMsg(args: unknown): void
|
||||
|
||||
createGroup(arg: unknown): void
|
||||
|
||||
createGroupWithMembers(arg: unknown): void
|
||||
|
||||
quitGroup(groupCode: string): void
|
||||
|
||||
destroyGroup(groupCode: string): void
|
||||
//获取单屏群通知列表
|
||||
getSingleScreenNotifies(force: boolean, start_seq: string, num: number): Promise<GeneralCallResult>
|
||||
|
||||
clearGroupNotifies(groupCode: string): void
|
||||
|
||||
getGroupNotifiesUnreadCount(unknown: Boolean): Promise<GeneralCallResult>
|
||||
|
||||
clearGroupNotifiesUnreadCount(groupCode: string): void
|
||||
|
||||
operateSysNotify(
|
||||
doubt: boolean,
|
||||
operateMsg: {
|
||||
operateType: GroupRequestOperateTypes, // 2 拒绝
|
||||
targetMsg: {
|
||||
seq: string, // 通知序列号
|
||||
type: GroupNotifyTypes,
|
||||
groupCode: string,
|
||||
postscript: string
|
||||
}
|
||||
}): Promise<void>
|
||||
|
||||
setTop(groupCode: string, isTop: boolean): void
|
||||
|
||||
getGroupBulletin(groupCode: string): unknown
|
||||
|
||||
deleteGroupBulletin(groupCode: string, seq: string): void
|
||||
|
||||
publishGroupBulletin(groupCode: string, pskey: string, data: any): Promise<GeneralCallResult>
|
||||
|
||||
publishInstructionForNewcomers(groupCode: string, arg: unknown): void
|
||||
|
||||
uploadGroupBulletinPic(groupCode: string, pskey: string, imagePath: string): Promise<GeneralCallResult & {
|
||||
errCode: number
|
||||
picInfo?: {
|
||||
id: string,
|
||||
width: number,
|
||||
height: number
|
||||
}
|
||||
}>
|
||||
|
||||
downloadGroupBulletinRichMedia(groupCode: string): unknown
|
||||
|
||||
getGroupBulletinList(groupCode: string): unknown
|
||||
|
||||
getGroupStatisticInfo(groupCode: string): unknown
|
||||
|
||||
getGroupRemainAtTimes(groupCode: string): number
|
||||
|
||||
getJoinGroupNoVerifyFlag(groupCode: string): unknown
|
||||
|
||||
getGroupArkInviteState(groupCode: string): unknown
|
||||
|
||||
reqToJoinGroup(groupCode: string, arg: unknown): void
|
||||
|
||||
setGroupShutUp(groupCode: string, shutUp: boolean): void
|
||||
|
||||
getGroupShutUpMemberList(groupCode: string): unknown[]
|
||||
|
||||
setMemberShutUp(groupCode: string, memberTimes: { uid: string, timeStamp: number }[]): Promise<void>
|
||||
|
||||
getGroupRecommendContactArkJson(groupCode: string): unknown
|
||||
|
||||
getJoinGroupLink(groupCode: string): unknown
|
||||
|
||||
modifyGroupExtInfo(groupCode: string, arg: unknown): void
|
||||
|
||||
//需要提前判断是否存在 高版本新增
|
||||
addGroupEssence(param: {
|
||||
groupCode: string
|
||||
msgRandom: number,
|
||||
msgSeq: number
|
||||
}): Promise<unknown>
|
||||
//需要提前判断是否存在 高版本新增
|
||||
removeGroupEssence(param: {
|
||||
groupCode: string
|
||||
msgRandom: number,
|
||||
msgSeq: number
|
||||
}): Promise<unknown>
|
||||
|
||||
isNull(): boolean
|
||||
}
|
3
src/ntqqapi/services/NodeIKernelMSFService.ts
Normal file
3
src/ntqqapi/services/NodeIKernelMSFService.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface NodeIKernelMSFService {
|
||||
getServerTime(): string
|
||||
}
|
744
src/ntqqapi/services/NodeIKernelMsgService.ts
Normal file
744
src/ntqqapi/services/NodeIKernelMsgService.ts
Normal file
@@ -0,0 +1,744 @@
|
||||
import { ElementType, MessageElement, Peer, RawMessage, SendMessageElement } from '@/ntqqapi/types'
|
||||
import { NodeIKernelMsgListener } from '@/ntqqapi/listeners/NodeIKernelMsgListener'
|
||||
import { GeneralCallResult } from './common'
|
||||
|
||||
export interface QueryMsgsParams {
|
||||
chatInfo: Peer,
|
||||
filterMsgType: [],
|
||||
filterSendersUid: string[],
|
||||
filterMsgFromTime: string,
|
||||
filterMsgToTime: string,
|
||||
pageLimit: number,
|
||||
isReverseOrder: boolean,
|
||||
isIncludeCurrent: boolean
|
||||
}
|
||||
|
||||
export interface TmpChatInfoApi {
|
||||
errMsg: string
|
||||
result: number
|
||||
tmpChatInfo?: TmpChatInfo
|
||||
}
|
||||
|
||||
export interface TmpChatInfo {
|
||||
chatType: number
|
||||
fromNick: string
|
||||
groupCode: string
|
||||
peerUid: string
|
||||
sessionType: number
|
||||
sig: string
|
||||
}
|
||||
|
||||
export interface NodeIKernelMsgService {
|
||||
|
||||
generateMsgUniqueId(chatType: number, time: string): string
|
||||
|
||||
addKernelMsgListener(nodeIKernelMsgListener: NodeIKernelMsgListener): number
|
||||
|
||||
sendMsg(msgId: string, peer: Peer, msgElements: SendMessageElement[], map: Map<any, any>): Promise<GeneralCallResult>
|
||||
|
||||
recallMsg(peer: Peer, msgIds: string[]): Promise<GeneralCallResult>
|
||||
|
||||
addKernelMsgImportToolListener(arg: Object): unknown
|
||||
|
||||
removeKernelMsgListener(args: unknown): unknown
|
||||
|
||||
addKernelTempChatSigListener(...args: unknown[]): unknown
|
||||
|
||||
removeKernelTempChatSigListener(...args: unknown[]): unknown
|
||||
|
||||
setAutoReplyTextList(AutoReplyText: Array<unknown>, i2: number): unknown
|
||||
|
||||
getAutoReplyTextList(...args: unknown[]): unknown
|
||||
|
||||
getOnLineDev(): void
|
||||
|
||||
kickOffLine(DevInfo: Object): unknown
|
||||
|
||||
setStatus(args: { status: number, extStatus: number, batteryStatus: number }): Promise<GeneralCallResult>
|
||||
|
||||
fetchStatusMgrInfo(): unknown
|
||||
|
||||
fetchStatusUnitedConfigInfo(): unknown
|
||||
|
||||
getOnlineStatusSmallIconBasePath(): unknown
|
||||
|
||||
getOnlineStatusSmallIconFileNameByUrl(Url: string): unknown
|
||||
|
||||
downloadOnlineStatusSmallIconByUrl(arg0: number, arg1: string): unknown
|
||||
|
||||
getOnlineStatusBigIconBasePath(): unknown
|
||||
|
||||
downloadOnlineStatusBigIconByUrl(arg0: number, arg1: string): unknown
|
||||
|
||||
getOnlineStatusCommonPath(arg: string): unknown
|
||||
|
||||
getOnlineStatusCommonFileNameByUrl(Url: string): unknown
|
||||
|
||||
downloadOnlineStatusCommonByUrl(arg0: string, arg1: string): unknown
|
||||
|
||||
// this.tokenType = i2
|
||||
// this.apnsToken = bArr
|
||||
// this.voipToken = bArr2
|
||||
// this.profileId = str
|
||||
|
||||
setToken(arg: Object): unknown
|
||||
|
||||
switchForeGround(): unknown
|
||||
|
||||
switchBackGround(arg: Object): unknown
|
||||
|
||||
//hex
|
||||
setTokenForMqq(token: string): unknown
|
||||
|
||||
switchForeGroundForMqq(...args: unknown[]): unknown
|
||||
|
||||
switchBackGroundForMqq(...args: unknown[]): unknown
|
||||
|
||||
getMsgSetting(...args: unknown[]): unknown
|
||||
|
||||
setMsgSetting(...args: unknown[]): unknown
|
||||
|
||||
addSendMsg(...args: unknown[]): unknown
|
||||
|
||||
cancelSendMsg(...args: unknown[]): unknown
|
||||
|
||||
switchToOfflineSendMsg(peer: Peer, MsgId: string): unknown
|
||||
|
||||
reqToOfflineSendMsg(...args: unknown[]): unknown
|
||||
|
||||
refuseReceiveOnlineFileMsg(peer: Peer, MsgId: string): unknown
|
||||
|
||||
resendMsg(...args: unknown[]): unknown
|
||||
|
||||
recallMsg(...args: unknown[]): unknown
|
||||
|
||||
reeditRecallMsg(...args: unknown[]): unknown
|
||||
//调用请检查除开commentElements其余参数不能为null
|
||||
forwardMsg(msgIds: string[], srcContact: Peer, dstContacts: Peer[], commentElements: MessageElement[]): Promise<GeneralCallResult>
|
||||
|
||||
forwardMsgWithComment(...args: unknown[]): unknown
|
||||
|
||||
forwardSubMsgWithComment(...args: unknown[]): unknown
|
||||
|
||||
forwardRichMsgInVist(...args: unknown[]): unknown
|
||||
|
||||
forwardFile(...args: unknown[]): unknown
|
||||
//Array<Msg>, Peer from, Peer to
|
||||
multiForwardMsg(...args: unknown[]): unknown
|
||||
|
||||
multiForwardMsgWithComment(...args: unknown[]): unknown
|
||||
|
||||
deleteRecallMsg(...args: unknown[]): unknown
|
||||
|
||||
deleteRecallMsgForLocal(...args: unknown[]): unknown
|
||||
|
||||
addLocalGrayTipMsg(...args: unknown[]): unknown
|
||||
|
||||
addLocalJsonGrayTipMsg(...args: unknown[]): unknown
|
||||
|
||||
addLocalJsonGrayTipMsgExt(...args: unknown[]): unknown
|
||||
|
||||
IsLocalJsonTipValid(...args: unknown[]): unknown
|
||||
|
||||
addLocalAVRecordMsg(...args: unknown[]): unknown
|
||||
|
||||
addLocalTofuRecordMsg(...args: unknown[]): unknown
|
||||
|
||||
addLocalRecordMsg(Peer: Peer, msgId: string, ele: MessageElement, attr: Array<any> | number, front: boolean): Promise<unknown>
|
||||
|
||||
deleteMsg(Peer: Peer, msgIds: Array<string>): Promise<any>
|
||||
|
||||
updateElementExtBufForUI(...args: unknown[]): unknown
|
||||
|
||||
updateMsgRecordExtPbBufForUI(...args: unknown[]): unknown
|
||||
|
||||
startMsgSync(...args: unknown[]): unknown
|
||||
|
||||
startGuildMsgSync(...args: unknown[]): unknown
|
||||
|
||||
isGuildChannelSync(...args: unknown[]): unknown
|
||||
|
||||
getMsgUniqueId(UniqueId: string): string
|
||||
|
||||
isMsgMatched(...args: unknown[]): unknown
|
||||
|
||||
getOnlineFileMsgs(...args: unknown[]): unknown
|
||||
|
||||
getAllOnlineFileMsgs(...args: unknown[]): unknown
|
||||
|
||||
getLatestDbMsgs(peer: Peer, cnt: number): Promise<unknown>
|
||||
|
||||
getLastMessageList(peer: Peer[]): Promise<unknown>
|
||||
|
||||
getAioFirstViewLatestMsgs(peer: Peer, num: number): unknown
|
||||
|
||||
//deprecated 从9.9.15-26702版本开始,该接口已经废弃,请使用getMsgsEx
|
||||
getMsgs(peer: Peer, msgId: string, count: unknown, queryOrder: boolean): Promise<unknown>
|
||||
|
||||
getMsgsIncludeSelf(peer: Peer, msgId: string, count: number, queryOrder: boolean): Promise<GeneralCallResult & {
|
||||
msgList: RawMessage[]
|
||||
}>
|
||||
|
||||
// this.$peer = contact
|
||||
// this.$msgTime = j2
|
||||
// this.$clientSeq = j3
|
||||
// this.$cnt = i2
|
||||
|
||||
getMsgsWithMsgTimeAndClientSeqForC2C(...args: unknown[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>
|
||||
|
||||
getMsgsWithStatus(params: {
|
||||
peer: Peer
|
||||
msgId: string
|
||||
msgTime: unknown
|
||||
cnt: unknown
|
||||
queryOrder: boolean
|
||||
isIncludeSelf: boolean
|
||||
appid: unknown
|
||||
}): Promise<GeneralCallResult & { msgList: RawMessage[] }>
|
||||
|
||||
getMsgsBySeqRange(peer: Peer, startSeq: string, endSeq: string): Promise<GeneralCallResult & { msgList: RawMessage[] }>
|
||||
|
||||
getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, unknownArg: boolean): Promise<GeneralCallResult & { msgList: RawMessage[] }>
|
||||
|
||||
getMsgsByMsgId(peer: Peer, ids: string[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>
|
||||
|
||||
getRecallMsgsByMsgId(peer: Peer, MsgId: string[]): Promise<unknown>
|
||||
|
||||
getMsgsBySeqList(peer: Peer, seqList: string[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>
|
||||
|
||||
getSingleMsg(Peer: Peer, msgSeq: string): Promise<GeneralCallResult & { msgList: RawMessage[] }>
|
||||
|
||||
getSourceOfReplyMsg(peer: Peer, MsgId: string, SourceSeq: string): unknown
|
||||
|
||||
getSourceOfReplyMsgV2(peer: Peer, RootMsgId: string, ReplyMsgId: string): unknown
|
||||
|
||||
getMsgByClientSeqAndTime(peer: Peer, clientSeq: string, time: string): unknown
|
||||
|
||||
getSourceOfReplyMsgByClientSeqAndTime(peer: Peer, clientSeq: string, time: string): unknown
|
||||
//cnt clientSeq?并不是吧
|
||||
getMsgsByTypeFilter(peer: Peer, msgId: string, cnt: unknown, queryOrder: boolean, typeFilter: { type: number, subtype: Array<number> }): unknown
|
||||
|
||||
getMsgsByTypeFilters(peer: Peer, msgId: string, cnt: unknown, queryOrder: boolean, typeFilters: Array<{ type: number, subtype: Array<number> }>): unknown
|
||||
|
||||
getMsgWithAbstractByFilterParam(...args: unknown[]): unknown
|
||||
|
||||
queryMsgsWithFilter(...args: unknown[]): unknown
|
||||
|
||||
/**
|
||||
* @deprecated 该函数已被标记为废弃,请使用新的替代方法。
|
||||
* 使用过滤条件查询消息列表的版本2接口。
|
||||
*
|
||||
* 该函数通过一系列过滤条件来查询特定聊天中的消息列表。这些条件包括消息类型、发送者、时间范围等。
|
||||
* 函数返回一个Promise,解析为查询结果的未知类型对象。
|
||||
*
|
||||
* @param MsgId 消息ID,用于特定消息的查询。
|
||||
* @param MsgTime 消息时间,用于指定消息的时间范围。
|
||||
* @param param 查询参数对象,包含详细的过滤条件和分页信息。
|
||||
* @param param.chatInfo 聊天信息,包括聊天类型和对方用户ID。
|
||||
* @param param.filterMsgType 需要过滤的消息类型数组,留空表示不过滤。
|
||||
* @param param.filterSendersUid 需要过滤的发送者用户ID数组。
|
||||
* @param param.filterMsgFromTime 查询消息的起始时间。
|
||||
* @param param.filterMsgToTime 查询消息的结束时间。
|
||||
* @param param.pageLimit 每页的消息数量限制。
|
||||
* @param param.isReverseOrder 是否按时间顺序倒序返回消息。
|
||||
* @param param.isIncludeCurrent 是否包含当前页码。
|
||||
* @returns 返回一个Promise,解析为查询结果的未知类型对象。
|
||||
*/
|
||||
queryMsgsWithFilterVer2(MsgId: string, MsgTime: string, param: QueryMsgsParams): Promise<unknown>
|
||||
|
||||
// this.chatType = i2
|
||||
// this.peerUid = str
|
||||
|
||||
// this.chatInfo = new ChatInfo()
|
||||
// this.filterMsgType = new ArrayList<>()
|
||||
// this.filterSendersUid = new ArrayList<>()
|
||||
// this.chatInfo = chatInfo
|
||||
// this.filterMsgType = arrayList
|
||||
// this.filterSendersUid = arrayList2
|
||||
// this.filterMsgFromTime = j2
|
||||
// this.filterMsgToTime = j3
|
||||
// this.pageLimit = i2
|
||||
// this.isReverseOrder = z
|
||||
// this.isIncludeCurrent = z2
|
||||
//queryMsgsWithFilterEx(0L, 0L, 0L, new QueryMsgsParams(new ChatInfo(2, str), new ArrayList(), new ArrayList(), 0L, 0L, 250, false, true))
|
||||
queryMsgsWithFilterEx(msgId: string, msgTime: string, megSeq: string, param: QueryMsgsParams): Promise<GeneralCallResult & {
|
||||
msgList: RawMessage[]
|
||||
}>
|
||||
//queryMsgsWithFilterEx(this.$msgId, this.$msgTime, this.$msgSeq, this.$param)
|
||||
queryFileMsgsDesktop(...args: unknown[]): unknown
|
||||
|
||||
setMsgRichInfoFlag(...args: unknown[]): unknown
|
||||
|
||||
queryPicOrVideoMsgs(msgId: string, msgTime: string, megSeq: string, param: QueryMsgsParams): Promise<unknown>
|
||||
|
||||
queryPicOrVideoMsgsDesktop(...args: unknown[]): unknown
|
||||
|
||||
queryEmoticonMsgs(msgId: string, msgTime: string, msgSeq: string, Params: QueryMsgsParams): Promise<unknown>
|
||||
|
||||
queryTroopEmoticonMsgs(msgId: string, msgTime: string, msgSeq: string, Params: QueryMsgsParams): Promise<unknown>
|
||||
|
||||
queryMsgsAndAbstractsWithFilter(msgId: string, msgTime: string, megSeq: string, param: QueryMsgsParams): unknown
|
||||
|
||||
setFocusOnGuild(...args: unknown[]): unknown
|
||||
|
||||
setFocusSession(...args: unknown[]): unknown
|
||||
|
||||
enableFilterUnreadInfoNotify(...args: unknown[]): unknown
|
||||
|
||||
enableFilterMsgAbstractNotify(...args: unknown[]): unknown
|
||||
|
||||
onScenesChangeForSilenceMode(...args: unknown[]): unknown
|
||||
|
||||
getContactUnreadCnt(...args: unknown[]): unknown
|
||||
|
||||
getUnreadCntInfo(...args: unknown[]): unknown
|
||||
|
||||
getGuildUnreadCntInfo(...args: unknown[]): unknown
|
||||
|
||||
getGuildUnreadCntTabInfo(...args: unknown[]): unknown
|
||||
|
||||
getAllGuildUnreadCntInfo(...args: unknown[]): unknown
|
||||
|
||||
getAllJoinGuildCnt(...args: unknown[]): unknown
|
||||
|
||||
getAllDirectSessionUnreadCntInfo(...args: unknown[]): unknown
|
||||
|
||||
getCategoryUnreadCntInfo(...args: unknown[]): unknown
|
||||
|
||||
getGuildFeedsUnreadCntInfo(...args: unknown[]): unknown
|
||||
|
||||
setUnVisibleChannelCntInfo(...args: unknown[]): unknown
|
||||
|
||||
setUnVisibleChannelTypeCntInfo(...args: unknown[]): unknown
|
||||
|
||||
setVisibleGuildCntInfo(...args: unknown[]): unknown
|
||||
|
||||
setMsgRead(peer: Peer): Promise<GeneralCallResult>
|
||||
|
||||
setAllC2CAndGroupMsgRead(): Promise<unknown>
|
||||
|
||||
setGuildMsgRead(...args: unknown[]): unknown
|
||||
|
||||
setAllGuildMsgRead(...args: unknown[]): unknown
|
||||
|
||||
setMsgReadAndReport(...args: unknown[]): unknown
|
||||
|
||||
setSpecificMsgReadAndReport(...args: unknown[]): unknown
|
||||
|
||||
setLocalMsgRead(...args: unknown[]): unknown
|
||||
|
||||
setGroupGuildMsgRead(...args: unknown[]): unknown
|
||||
|
||||
getGuildGroupTransData(...args: unknown[]): unknown
|
||||
|
||||
setGroupGuildBubbleRead(...args: unknown[]): unknown
|
||||
|
||||
getGuildGroupBubble(...args: unknown[]): unknown
|
||||
|
||||
fetchGroupGuildUnread(...args: unknown[]): unknown
|
||||
|
||||
setGroupGuildFlag(...args: unknown[]): unknown
|
||||
|
||||
setGuildUDCFlag(...args: unknown[]): unknown
|
||||
|
||||
setGuildTabUserFlag(...args: unknown[]): unknown
|
||||
|
||||
setBuildMode(flag: number/*0 1 3*/): unknown
|
||||
|
||||
setConfigurationServiceData(...args: unknown[]): unknown
|
||||
|
||||
setMarkUnreadFlag(...args: unknown[]): unknown
|
||||
|
||||
getChannelEventFlow(...args: unknown[]): unknown
|
||||
|
||||
getMsgEventFlow(...args: unknown[]): unknown
|
||||
|
||||
getRichMediaFilePathForMobileQQSend(...args: unknown[]): unknown
|
||||
|
||||
getRichMediaFilePathForGuild(arg: {
|
||||
md5HexStr: string,
|
||||
fileName: string,
|
||||
elementType: ElementType,
|
||||
elementSubType: number,
|
||||
thumbSize: 0,
|
||||
needCreate: true,
|
||||
downloadType: 1,
|
||||
file_uuid: ''
|
||||
}): string
|
||||
|
||||
assembleMobileQQRichMediaFilePath(...args: unknown[]): unknown
|
||||
|
||||
getFileThumbSavePathForSend(...args: unknown[]): unknown
|
||||
|
||||
getFileThumbSavePath(...args: unknown[]): unknown
|
||||
//猜测居多
|
||||
translatePtt2Text(MsgId: string, Peer: {}, MsgElement: {}): unknown
|
||||
|
||||
setPttPlayedState(...args: unknown[]): unknown
|
||||
// NodeIQQNTWrapperSession fetchFavEmojiList [
|
||||
// "",
|
||||
// 48,
|
||||
// true,
|
||||
// true
|
||||
// ]
|
||||
fetchFavEmojiList(str: string, num: number, uk1: boolean, uk2: boolean): Promise<GeneralCallResult & {
|
||||
emojiInfoList: Array<{
|
||||
uin: string,
|
||||
emoId: number,
|
||||
emoPath: string,
|
||||
isExist: boolean,
|
||||
resId: string,
|
||||
url: string,
|
||||
md5: string,
|
||||
emoOriginalPath: string,
|
||||
thumbPath: string,
|
||||
RomaingType: string,
|
||||
isAPNG: false,
|
||||
isMarkFace: false,
|
||||
eId: string,
|
||||
epId: string,
|
||||
ocrWord: string,
|
||||
modifyWord: string,
|
||||
exposeNum: number,
|
||||
clickNum: number,
|
||||
desc: string
|
||||
}>
|
||||
}>
|
||||
|
||||
addFavEmoji(...args: unknown[]): unknown
|
||||
|
||||
fetchMarketEmoticonList(...args: unknown[]): unknown
|
||||
|
||||
fetchMarketEmoticonShowImage(...args: unknown[]): unknown
|
||||
|
||||
fetchMarketEmoticonAioImage(...args: unknown[]): unknown
|
||||
|
||||
fetchMarketEmotionJsonFile(...args: unknown[]): unknown
|
||||
|
||||
getMarketEmoticonPath(...args: unknown[]): unknown
|
||||
|
||||
getMarketEmoticonPathBySync(...args: unknown[]): unknown
|
||||
|
||||
fetchMarketEmoticonFaceImages(...args: unknown[]): unknown
|
||||
|
||||
fetchMarketEmoticonAuthDetail(...args: unknown[]): unknown
|
||||
|
||||
getFavMarketEmoticonInfo(...args: unknown[]): unknown
|
||||
|
||||
addRecentUsedFace(...args: unknown[]): unknown
|
||||
|
||||
getRecentUsedFaceList(...args: unknown[]): unknown
|
||||
|
||||
getMarketEmoticonEncryptKeys(...args: unknown[]): unknown
|
||||
|
||||
downloadEmojiPic(...args: unknown[]): unknown
|
||||
|
||||
deleteFavEmoji(...args: unknown[]): unknown
|
||||
|
||||
modifyFavEmojiDesc(...args: unknown[]): unknown
|
||||
|
||||
queryFavEmojiByDesc(...args: unknown[]): unknown
|
||||
|
||||
getHotPicInfoListSearchString(...args: unknown[]): unknown
|
||||
|
||||
getHotPicSearchResult(...args: unknown[]): unknown
|
||||
|
||||
getHotPicHotWords(...args: unknown[]): unknown
|
||||
|
||||
getHotPicJumpInfo(...args: unknown[]): unknown
|
||||
|
||||
getEmojiResourcePath(...args: unknown[]): unknown
|
||||
|
||||
JoinDragonGroupEmoji(JoinDragonGroupEmojiReq: any/*joinDragonGroupEmojiReq*/): unknown
|
||||
|
||||
getMsgAbstracts(...args: unknown[]): unknown
|
||||
|
||||
getMsgAbstract(...args: unknown[]): unknown
|
||||
|
||||
getMsgAbstractList(...args: unknown[]): unknown
|
||||
|
||||
getMsgAbstractListBySeqRange(...args: unknown[]): unknown
|
||||
|
||||
refreshMsgAbstracts(...args: unknown[]): unknown
|
||||
|
||||
refreshMsgAbstractsByGuildIds(...args: unknown[]): unknown
|
||||
|
||||
getRichMediaElement(...args: unknown[]): unknown
|
||||
|
||||
cancelGetRichMediaElement(...args: unknown[]): unknown
|
||||
|
||||
refuseGetRichMediaElement(...args: unknown[]): unknown
|
||||
|
||||
switchToOfflineGetRichMediaElement(...args: unknown[]): unknown
|
||||
|
||||
downloadRichMedia(...args: unknown[]): unknown
|
||||
|
||||
getFirstUnreadMsgSeq(args: {
|
||||
peerUid: string
|
||||
guildId: string
|
||||
}): unknown
|
||||
|
||||
getFirstUnreadCommonMsg(...args: unknown[]): unknown
|
||||
|
||||
getFirstUnreadAtmeMsg(...args: unknown[]): unknown
|
||||
|
||||
getFirstUnreadAtallMsg(...args: unknown[]): unknown
|
||||
|
||||
getNavigateInfo(...args: unknown[]): unknown
|
||||
|
||||
getChannelFreqLimitInfo(...args: unknown[]): unknown
|
||||
|
||||
getRecentUseEmojiList(...args: unknown[]): unknown
|
||||
|
||||
getRecentEmojiList(...args: unknown[]): unknown
|
||||
|
||||
setMsgEmojiLikes(...args: unknown[]): unknown
|
||||
|
||||
getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, cookie: string, bForward: boolean, number: number): Promise<{
|
||||
result: number,
|
||||
errMsg: string,
|
||||
emojiLikesList:
|
||||
Array<{
|
||||
tinyId: string,
|
||||
nickName: string,
|
||||
headUrl: string
|
||||
}>,
|
||||
cookie: string,
|
||||
isLastPage: boolean,
|
||||
isFirstPage: boolean
|
||||
}>
|
||||
|
||||
setMsgEmojiLikesForRole(...args: unknown[]): unknown
|
||||
|
||||
clickInlineKeyboardButton(...args: unknown[]): unknown
|
||||
|
||||
setCurOnScreenMsg(...args: unknown[]): unknown
|
||||
|
||||
setCurOnScreenMsgForMsgEvent(...args: unknown[]): unknown
|
||||
|
||||
getMiscData(key: string): unknown
|
||||
|
||||
setMiscData(key: string, value: string): unknown
|
||||
|
||||
getBookmarkData(...args: unknown[]): unknown
|
||||
|
||||
setBookmarkData(...args: unknown[]): unknown
|
||||
|
||||
sendShowInputStatusReq(ChatType: number, EventType: number, toUid: string): Promise<unknown>
|
||||
|
||||
queryCalendar(...args: unknown[]): unknown
|
||||
|
||||
queryFirstMsgSeq(peer: Peer, ...args: unknown[]): unknown
|
||||
|
||||
queryRoamCalendar(...args: unknown[]): unknown
|
||||
|
||||
queryFirstRoamMsg(...args: unknown[]): unknown
|
||||
|
||||
fetchLongMsg(peer: Peer, msgId: string): unknown
|
||||
|
||||
fetchLongMsgWithCb(...args: unknown[]): unknown
|
||||
|
||||
setIsStopKernelFetchLongMsg(...args: unknown[]): unknown
|
||||
|
||||
insertGameResultAsMsgToDb(...args: unknown[]): unknown
|
||||
|
||||
getMultiMsg(...args: unknown[]): Promise<GeneralCallResult & {
|
||||
msgList: RawMessage[]
|
||||
}>
|
||||
|
||||
setDraft(...args: unknown[]): unknown
|
||||
|
||||
getDraft(...args: unknown[]): unknown
|
||||
|
||||
deleteDraft(...args: unknown[]): unknown
|
||||
|
||||
getRecentHiddenSesionList(...args: unknown[]): unknown
|
||||
|
||||
setRecentHiddenSession(...args: unknown[]): unknown
|
||||
|
||||
delRecentHiddenSession(...args: unknown[]): unknown
|
||||
|
||||
getCurHiddenSession(...args: unknown[]): unknown
|
||||
|
||||
setCurHiddenSession(...args: unknown[]): unknown
|
||||
|
||||
setReplyDraft(...args: unknown[]): unknown
|
||||
|
||||
getReplyDraft(...args: unknown[]): unknown
|
||||
|
||||
deleteReplyDraft(...args: unknown[]): unknown
|
||||
|
||||
getFirstUnreadAtMsg(peer: Peer): unknown
|
||||
|
||||
clearMsgRecords(...args: unknown[]): unknown//设置已读后调用我觉得比较好 清理记录 现在别了
|
||||
|
||||
IsExistOldDb(...args: unknown[]): unknown
|
||||
|
||||
canImportOldDbMsg(...args: unknown[]): unknown
|
||||
|
||||
setPowerStatus(z: boolean): unknown
|
||||
|
||||
canProcessDataMigration(...args: unknown[]): unknown
|
||||
|
||||
importOldDbMsg(...args: unknown[]): unknown
|
||||
|
||||
stopImportOldDbMsgAndroid(...args: unknown[]): unknown
|
||||
|
||||
isMqqDataImportFinished(...args: unknown[]): unknown
|
||||
|
||||
getMqqDataImportTableNames(...args: unknown[]): unknown
|
||||
|
||||
getCurChatImportStatusByUin(...args: unknown[]): unknown
|
||||
|
||||
getDataImportUserLevel(): unknown
|
||||
|
||||
getMsgQRCode(...args: unknown[]): unknown
|
||||
|
||||
getGuestMsgAbstracts(...args: unknown[]): unknown
|
||||
|
||||
getGuestMsgByRange(...args: unknown[]): unknown
|
||||
|
||||
getGuestMsgAbstractByRange(...args: unknown[]): unknown
|
||||
|
||||
registerSysMsgNotification(...args: unknown[]): unknown
|
||||
|
||||
unregisterSysMsgNotification(...args: unknown[]): unknown
|
||||
|
||||
enterOrExitAio(...args: unknown[]): unknown
|
||||
|
||||
// this.peerUid = ""
|
||||
// this.peerNickname = ""
|
||||
// this.fromGroupCode = ""
|
||||
// this.sig = new byte[0]
|
||||
// this.selfUid = ""
|
||||
// this.selfPhone = ""
|
||||
// this.chatType = i2
|
||||
// this.peerUid = str
|
||||
// this.peerNickname = str2
|
||||
// this.fromGroupCode = str3
|
||||
// this.sig = bArr
|
||||
// this.selfUid = str4
|
||||
// this.selfPhone = str5
|
||||
// this.gameSession = tempChatGameSession
|
||||
prepareTempChat(args: unknown): unknown//主动临时消息 不做
|
||||
|
||||
sendSsoCmdReqByContend(cmd: string, param: string): Promise<unknown>
|
||||
|
||||
//chattype,uid->Promise<any>
|
||||
getTempChatInfo(ChatType: number, Uid: string): Promise<TmpChatInfoApi>
|
||||
|
||||
setContactLocalTop(...args: unknown[]): unknown
|
||||
|
||||
switchAnonymousChat(...args: unknown[]): unknown
|
||||
|
||||
renameAnonyChatNick(...args: unknown[]): unknown
|
||||
|
||||
getAnonymousInfo(...args: unknown[]): unknown
|
||||
|
||||
updateAnonymousInfo(...args: unknown[]): unknown
|
||||
|
||||
sendSummonMsg(peer: Peer, MsgElement: unknown, MsgAttributeInfo: unknown): Promise<unknown>//频道的东西
|
||||
|
||||
outputGuildUnreadInfo(...args: unknown[]): unknown
|
||||
|
||||
checkMsgWithUrl(...args: unknown[]): unknown
|
||||
|
||||
checkTabListStatus(...args: unknown[]): unknown
|
||||
|
||||
getABatchOfContactMsgBoxInfo(...args: unknown[]): unknown
|
||||
|
||||
insertMsgToMsgBox(peer: Peer, msgId: string, arg: 2006): unknown
|
||||
|
||||
isHitEmojiKeyword(...args: unknown[]): unknown
|
||||
|
||||
getKeyWordRelatedEmoji(...args: unknown[]): unknown
|
||||
|
||||
recordEmoji(...args: unknown[]): unknown
|
||||
|
||||
fetchGetHitEmotionsByWord(args: Object): Promise<unknown>//表情推荐?
|
||||
|
||||
deleteAllRoamMsgs(...args: unknown[]): unknown//漫游消息?
|
||||
|
||||
packRedBag(...args: unknown[]): unknown
|
||||
|
||||
grabRedBag(...args: unknown[]): unknown
|
||||
|
||||
pullDetail(...args: unknown[]): unknown
|
||||
|
||||
selectPasswordRedBag(...args: unknown[]): unknown
|
||||
|
||||
pullRedBagPasswordList(...args: unknown[]): unknown
|
||||
|
||||
requestTianshuAdv(...args: unknown[]): unknown
|
||||
|
||||
tianshuReport(...args: unknown[]): unknown
|
||||
|
||||
tianshuMultiReport(...args: unknown[]): unknown
|
||||
|
||||
GetMsgSubType(a0: number, a1: number): unknown
|
||||
|
||||
setIKernelPublicAccountAdapter(...args: unknown[]): unknown
|
||||
//tempChatGameSession有关
|
||||
createUidFromTinyId(fromTinyId: string, toTinyId: string): unknown
|
||||
|
||||
dataMigrationGetDataAvaiableContactList(...args: unknown[]): unknown
|
||||
|
||||
dataMigrationGetMsgList(...args: unknown[]): unknown
|
||||
|
||||
dataMigrationStopOperation(...args: unknown[]): unknown
|
||||
|
||||
//新的希望
|
||||
dataMigrationImportMsgPbRecord(DataMigrationMsgInfo: Array<{
|
||||
extensionData: string//"Hex"
|
||||
extraData: string //""
|
||||
chatType: number
|
||||
chatUin: string
|
||||
msgType: number
|
||||
msgTime: string
|
||||
msgSeq: string
|
||||
msgRandom: string
|
||||
}>, DataMigrationResourceInfo: {
|
||||
extraData: string
|
||||
filePath: string
|
||||
fileSize: string
|
||||
msgRandom: string
|
||||
msgSeq: string
|
||||
msgSubType: number
|
||||
msgType: number
|
||||
}): unknown
|
||||
|
||||
dataMigrationGetResourceLocalDestinyPath(...args: unknown[]): unknown
|
||||
|
||||
dataMigrationSetIOSPathPrefix(...args: unknown[]): unknown
|
||||
|
||||
getServiceAssistantSwitch(...args: unknown[]): unknown
|
||||
|
||||
setServiceAssistantSwitch(...args: unknown[]): unknown
|
||||
|
||||
setSubscribeFolderUsingSmallRedPoint(...args: unknown[]): unknown
|
||||
|
||||
clearGuildNoticeRedPoint(...args: unknown[]): unknown
|
||||
|
||||
clearFeedNoticeRedPoint(...args: unknown[]): unknown
|
||||
|
||||
clearFeedSquareRead(...args: unknown[]): unknown
|
||||
|
||||
IsC2CStyleChatType(...args: unknown[]): unknown
|
||||
|
||||
IsTempChatType(uin: number): unknown//猜的
|
||||
|
||||
getGuildInteractiveNotification(...args: unknown[]): unknown
|
||||
|
||||
getGuildNotificationAbstract(...args: unknown[]): unknown
|
||||
|
||||
setFocusOnBase(...args: unknown[]): unknown
|
||||
|
||||
queryArkInfo(...args: unknown[]): unknown
|
||||
|
||||
queryUserSecQuality(...args: unknown[]): unknown
|
||||
|
||||
getGuildMsgAbFlag(...args: unknown[]): unknown
|
||||
|
||||
getGroupMsgStorageTime(): unknown//这是嘛啊
|
||||
|
||||
}
|
22
src/ntqqapi/services/NodeIKernelProfileLikeService.ts
Normal file
22
src/ntqqapi/services/NodeIKernelProfileLikeService.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { BuddyProfileLikeReq } from '../types'
|
||||
import { GeneralCallResult } from './common'
|
||||
|
||||
export interface NodeIKernelProfileLikeService {
|
||||
addKernelProfileLikeListener(listener: NodeIKernelProfileLikeService): void
|
||||
|
||||
removeKernelProfileLikeListener(listener: unknown): void
|
||||
|
||||
setBuddyProfileLike(...args: unknown[]): { result: number, errMsg: string, succCounts: number }
|
||||
|
||||
getBuddyProfileLike(req: BuddyProfileLikeReq): Promise<GeneralCallResult & {
|
||||
'info': {
|
||||
'userLikeInfos': Array<any>,
|
||||
'friendMaxVotes': number,
|
||||
'start': number
|
||||
}
|
||||
}>
|
||||
|
||||
getProfileLikeScidResourceInfo(...args: unknown[]): void
|
||||
|
||||
isNull(): boolean
|
||||
}
|
5
src/ntqqapi/services/NodeIKernelUixConvertService.ts
Normal file
5
src/ntqqapi/services/NodeIKernelUixConvertService.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface NodeIKernelUixConvertService {
|
||||
getUin(uid: string[]): Promise<{ uinInfo: Map<string, string> }>
|
||||
|
||||
getUid(uin: string[]): Promise<{ uidInfo: Map<string, string> }>
|
||||
}
|
@@ -1,2 +1,7 @@
|
||||
export * from './NodeIKernelBuddyService'
|
||||
export * from './NodeIKernelProfileService'
|
||||
export * from './NodeIKernelProfileService'
|
||||
export * from './NodeIKernelGroupService'
|
||||
export * from './NodeIKernelProfileLikeService'
|
||||
export * from './NodeIKernelMsgService'
|
||||
export * from './NodeIKernelMSFService'
|
||||
export * from './NodeIKernelUixConvertService'
|
@@ -1,5 +1,12 @@
|
||||
import { QQLevel, Sex } from './user'
|
||||
|
||||
export enum GroupListUpdateType {
|
||||
REFRESHALL,
|
||||
GETALL,
|
||||
MODIFIED,
|
||||
REMOVE
|
||||
}
|
||||
|
||||
export interface Group {
|
||||
groupCode: string
|
||||
maxMember: number
|
||||
|
@@ -15,13 +15,7 @@ export enum ElementType {
|
||||
export interface SendTextElement {
|
||||
elementType: ElementType.TEXT
|
||||
elementId: ''
|
||||
textElement: {
|
||||
content: string
|
||||
atType: number
|
||||
atUid: string
|
||||
atTinyId: string
|
||||
atNtUid: string
|
||||
}
|
||||
textElement: TextElement
|
||||
}
|
||||
|
||||
export interface SendPttElement {
|
||||
@@ -77,12 +71,7 @@ export interface SendPicElement {
|
||||
export interface SendReplyElement {
|
||||
elementType: ElementType.REPLY
|
||||
elementId: ''
|
||||
replyElement: {
|
||||
replayMsgSeq: string
|
||||
replayMsgId: string
|
||||
senderUin: string
|
||||
senderUinStr: string
|
||||
}
|
||||
replyElement: ReplyElement
|
||||
}
|
||||
|
||||
export interface SendFaceElement {
|
||||
@@ -96,6 +85,21 @@ export interface SendMarketFaceElement {
|
||||
marketFaceElement: MarketFaceElement
|
||||
}
|
||||
|
||||
export interface TextElement {
|
||||
content: string
|
||||
atType: number
|
||||
atUid: string
|
||||
atTinyId: string
|
||||
atNtUid: string
|
||||
}
|
||||
|
||||
export interface ReplyElement {
|
||||
replayMsgSeq: string
|
||||
replayMsgId: string
|
||||
senderUin: string
|
||||
senderUinStr: string
|
||||
}
|
||||
|
||||
export interface FileElement {
|
||||
fileMd5?: ''
|
||||
fileName: string
|
||||
@@ -377,6 +381,7 @@ export interface RawMessage {
|
||||
msgShortId?: number // 自己维护的消息id
|
||||
msgTime: string // 时间戳,秒
|
||||
msgSeq: string
|
||||
msgRandom: string
|
||||
senderUid: string
|
||||
senderUin?: string // 发送者QQ号
|
||||
peerUid: string // 群号 或者 QQ uid
|
||||
@@ -419,4 +424,38 @@ export interface Peer {
|
||||
chatType: ChatType
|
||||
peerUid: string // 如果是群聊uid为群号,私聊uid就是加密的字符串
|
||||
guildId?: string
|
||||
}
|
||||
|
||||
export interface MessageElement {
|
||||
elementType: ElementType
|
||||
elementId: string
|
||||
extBufForUI: string //"0x"
|
||||
textElement?: TextElement
|
||||
faceElement?: FaceElement
|
||||
marketFaceElement?: MarkdownElement
|
||||
replyElement?: ReplyElement
|
||||
picElement?: PicElement
|
||||
pttElement?: PttElement
|
||||
videoElement?: VideoElement
|
||||
grayTipElement?: GrayTipElement
|
||||
arkElement?: ArkElement
|
||||
fileElement?: FileElement
|
||||
liveGiftElement?: null
|
||||
markdownElement?: MarkdownElement
|
||||
structLongMsgElement?: any
|
||||
multiForwardMsgElement?: MultiForwardMsgElement
|
||||
giphyElement?: any
|
||||
walletElement?: null
|
||||
inlineKeyboardElement?: InlineKeyboardElement
|
||||
textGiftElement?: null //????
|
||||
calendarElement?: any
|
||||
yoloGameResultElement?: any
|
||||
avRecordElement?: any
|
||||
structMsgElement?: null
|
||||
faceBubbleElement?: any
|
||||
shareLocationElement?: any
|
||||
tofuRecordElement?: any
|
||||
taskTopMsgElement?: any
|
||||
recommendedMsgElement?: any
|
||||
actionBarElement?: any
|
||||
}
|
@@ -64,3 +64,41 @@ export interface FriendRequestNotify {
|
||||
buddyReqs: FriendRequest[]
|
||||
}
|
||||
}
|
||||
|
||||
export enum MemberExtSourceType {
|
||||
DEFAULTTYPE = 0,
|
||||
TITLETYPE = 1,
|
||||
NEWGROUPTYPE = 2,
|
||||
}
|
||||
|
||||
export interface GroupExtParam {
|
||||
groupCode: string
|
||||
seq: string
|
||||
beginUin: string
|
||||
dataTime: string
|
||||
uinList: Array<string>
|
||||
uinNum: string
|
||||
groupType: string
|
||||
richCardNameVer: string
|
||||
sourceType: MemberExtSourceType
|
||||
memberExtFilter: {
|
||||
memberLevelInfoUin: number
|
||||
memberLevelInfoPoint: number
|
||||
memberLevelInfoActiveDay: number
|
||||
memberLevelInfoLevel: number
|
||||
memberLevelInfoName: number
|
||||
levelName: number
|
||||
dataTime: number
|
||||
userShowFlag: number
|
||||
sysShowFlag: number
|
||||
timeToUpdate: number
|
||||
nickName: number
|
||||
specialTitle: number
|
||||
levelNameNew: number
|
||||
userShowFlagNew: number
|
||||
msgNeedField: number
|
||||
cmdUinFlagExt3Grocery: number
|
||||
memberIcon: number
|
||||
memberInfoSeq: number
|
||||
}
|
||||
}
|
@@ -258,4 +258,86 @@ export interface UserDetailInfoListenerArg {
|
||||
simpleInfo: SimpleInfo
|
||||
commonExt: CommonExt
|
||||
photoWall: PhotoWall
|
||||
}
|
||||
|
||||
export interface BuddyProfileLikeReq {
|
||||
friendUids: string[]
|
||||
basic: number
|
||||
vote: number
|
||||
favorite: number
|
||||
userProfile: number
|
||||
type: number
|
||||
start: number
|
||||
limit: number
|
||||
}
|
||||
|
||||
export interface UserDetailInfoByUinV2 {
|
||||
result: number
|
||||
errMsg: string
|
||||
detail: {
|
||||
uid: string
|
||||
uin: string
|
||||
simpleInfo: SimpleInfo
|
||||
commonExt: CommonExt
|
||||
photoWall: null
|
||||
}
|
||||
}
|
||||
|
||||
export interface UserDetailInfoByUin {
|
||||
result: number
|
||||
errMsg: string
|
||||
info: {
|
||||
uid: string //这个没办法用
|
||||
qid: string
|
||||
uin: string
|
||||
nick: string
|
||||
remark: string
|
||||
longNick: string
|
||||
avatarUrl: string
|
||||
birthday_year: number
|
||||
birthday_month: number
|
||||
birthday_day: number
|
||||
sex: number //0
|
||||
topTime: string
|
||||
constellation: number
|
||||
shengXiao: number
|
||||
kBloodType: number
|
||||
homeTown: string
|
||||
makeFriendCareer: number
|
||||
pos: string
|
||||
eMail: string
|
||||
phoneNum: string
|
||||
college: string
|
||||
country: string
|
||||
province: string
|
||||
city: string
|
||||
postCode: string
|
||||
address: string
|
||||
isBlock: boolean
|
||||
isSpecialCareOpen: boolean
|
||||
isSpecialCareZone: boolean
|
||||
ringId: string
|
||||
regTime: number
|
||||
interest: string
|
||||
termType: number
|
||||
labels: any[]
|
||||
qqLevel: { crownNum: number, sunNum: number, moonNum: number, starNum: number }
|
||||
isHideQQLevel: number
|
||||
privilegeIcon: { jumpUrl: string, openIconList: any[], closeIconList: any[] }
|
||||
isHidePrivilegeIcon: number
|
||||
photoWall: { picList: any[] }
|
||||
vipFlag: boolean
|
||||
yearVipFlag: boolean
|
||||
svipFlag: boolean
|
||||
vipLevel: number
|
||||
status: number
|
||||
qidianMasterFlag: number
|
||||
qidianCrewFlag: number
|
||||
qidianCrewFlag2: number
|
||||
extStatus: number
|
||||
recommendImgFlag: number
|
||||
disableEmojiShortCuts: number
|
||||
pendantId: string
|
||||
vipNameColorId: string
|
||||
}
|
||||
}
|
@@ -1,10 +1,24 @@
|
||||
import { NodeIKernelBuddyService } from './services/NodeIKernelBuddyService'
|
||||
import {
|
||||
NodeIKernelBuddyService,
|
||||
NodeIKernelGroupService,
|
||||
NodeIKernelProfileService,
|
||||
NodeIKernelProfileLikeService,
|
||||
NodeIKernelMSFService,
|
||||
NodeIKernelMsgService,
|
||||
NodeIKernelUixConvertService
|
||||
} from './services'
|
||||
import os from 'node:os'
|
||||
const Process = require('node:process')
|
||||
|
||||
export interface NodeIQQNTWrapperSession {
|
||||
[key: string]: any
|
||||
getBuddyService(): NodeIKernelBuddyService
|
||||
getGroupService(): NodeIKernelGroupService
|
||||
getProfileService(): NodeIKernelProfileService
|
||||
getProfileLikeService(): NodeIKernelProfileLikeService
|
||||
getMsgService(): NodeIKernelMsgService
|
||||
getMSFService(): NodeIKernelMSFService
|
||||
getUixConvertService(): NodeIKernelUixConvertService
|
||||
}
|
||||
|
||||
export interface WrapperApi {
|
||||
@@ -28,7 +42,7 @@ export interface WrapperConstructor {
|
||||
NodeIKernelProfileListener?: any
|
||||
}
|
||||
|
||||
export const wrapperApi: WrapperApi = {}
|
||||
const wrapperApi: WrapperApi = {}
|
||||
|
||||
export const wrapperConstructor: WrapperConstructor = {}
|
||||
|
||||
@@ -65,4 +79,8 @@ Process.dlopen = function (module, filename, flags = os.constants.dlopen.RTLD_LA
|
||||
}
|
||||
}
|
||||
return dlopenRet
|
||||
}
|
||||
|
||||
export function getSession() {
|
||||
return wrapperApi['NodeIQQNTWrapperSession']
|
||||
}
|
@@ -18,7 +18,8 @@ class GetGroupMemberList extends BaseAction<PayloadType, OB11GroupMember[]> {
|
||||
const group = await getGroup(payload.group_id.toString())
|
||||
if (group) {
|
||||
if (!group.members?.length || payload.no_cache === true || payload.no_cache === 'true') {
|
||||
group.members = await NTQQGroupApi.getGroupMembers(payload.group_id.toString())
|
||||
const members = await NTQQGroupApi.getGroupMembers(payload.group_id.toString())
|
||||
group.members = Array.from(members.values())
|
||||
log('强制刷新群成员列表, 数量: ', group.members.length)
|
||||
}
|
||||
return OB11Constructor.groupMembers(group)
|
||||
|
@@ -7,10 +7,9 @@ import {
|
||||
GroupMemberRole,
|
||||
PicSubType,
|
||||
RawMessage,
|
||||
SendArkElement,
|
||||
SendMessageElement,
|
||||
} from '../../../ntqqapi/types'
|
||||
import { friends, getFriend, getGroup, getGroupMember, getUidByUin, selfInfo } from '../../../common/data'
|
||||
import { friends, getGroup, getGroupMember, getUidByUin, selfInfo } from '../../../common/data'
|
||||
import {
|
||||
OB11MessageCustomMusic,
|
||||
OB11MessageData,
|
||||
@@ -20,69 +19,32 @@ import {
|
||||
OB11MessageMixType,
|
||||
OB11MessageMusic,
|
||||
OB11MessageNode,
|
||||
OB11MessageVideo,
|
||||
OB11PostSendMsg,
|
||||
} from '../../types'
|
||||
import { NTQQMsgApi } from '../../../ntqqapi/api/msg'
|
||||
import { SendMsgElementConstructor } from '../../../ntqqapi/constructor'
|
||||
import BaseAction from '../BaseAction'
|
||||
import { ActionName, BaseCheckResult } from '../types'
|
||||
import * as fs from 'node:fs'
|
||||
import fs from 'node:fs'
|
||||
import { decodeCQCode } from '../../cqcode'
|
||||
import { dbUtil } from '../../../common/db'
|
||||
import { ALLOW_SEND_TEMP_MSG, getConfigUtil } from '../../../common/config'
|
||||
import { log } from '../../../common/utils/log'
|
||||
import { sleep } from '../../../common/utils/helper'
|
||||
import { uri2local } from '../../../common/utils'
|
||||
import { crychic } from '../../../ntqqapi/native/crychic'
|
||||
import { NTQQGroupApi } from '../../../ntqqapi/api'
|
||||
import { CustomMusicSignPostData, IdMusicSignPostData, MusicSign, MusicSignPostData } from '../../../common/utils/sign'
|
||||
import { Peer } from '../../../ntqqapi/types/msg'
|
||||
|
||||
function checkSendMessage(sendMsgList: OB11MessageData[]) {
|
||||
function checkUri(uri: string): boolean {
|
||||
const pattern = /^(file:\/\/|http:\/\/|https:\/\/|base64:\/\/)/
|
||||
return pattern.test(uri)
|
||||
}
|
||||
|
||||
for (let msg of sendMsgList) {
|
||||
if (msg['type'] && msg['data']) {
|
||||
let type = msg['type']
|
||||
let data = msg['data']
|
||||
if (type === 'text' && !data['text']) {
|
||||
return 400
|
||||
}
|
||||
else if (['image', 'voice', 'record'].includes(type)) {
|
||||
if (!data['file']) {
|
||||
return 400
|
||||
}
|
||||
else {
|
||||
if (checkUri(data['file'])) {
|
||||
return 200
|
||||
}
|
||||
else {
|
||||
return 400
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type === 'at' && !data['qq']) {
|
||||
return 400
|
||||
}
|
||||
else if (type === 'reply' && !data['id']) {
|
||||
return 400
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 400
|
||||
}
|
||||
}
|
||||
return 200
|
||||
}
|
||||
import { NTQQGroupApi, NTQQMsgApi, NTQQUserApi, NTQQFriendApi } from '@/ntqqapi/api'
|
||||
import { CustomMusicSignPostData, IdMusicSignPostData, MusicSign, MusicSignPostData } from '@/common/utils/sign'
|
||||
import { Peer } from '@/ntqqapi/types/msg'
|
||||
|
||||
export interface ReturnDataType {
|
||||
message_id: number
|
||||
}
|
||||
|
||||
export enum ContextMode {
|
||||
Normal = 0,
|
||||
Private = 1,
|
||||
Group = 2
|
||||
}
|
||||
|
||||
export function convertMessage2List(message: OB11MessageMixType, autoEscape = false) {
|
||||
if (typeof message === 'string') {
|
||||
if (autoEscape === true) {
|
||||
@@ -107,7 +69,7 @@ export function convertMessage2List(message: OB11MessageMixType, autoEscape = fa
|
||||
|
||||
export async function createSendElements(
|
||||
messageData: OB11MessageData[],
|
||||
target: Group | Friend | undefined,
|
||||
peer: Peer,
|
||||
ignoreTypes: OB11MessageDataType[] = [],
|
||||
) {
|
||||
let sendElements: SendMessageElement[] = []
|
||||
@@ -125,7 +87,7 @@ export async function createSendElements(
|
||||
}
|
||||
break
|
||||
case OB11MessageDataType.at: {
|
||||
if (!target) {
|
||||
if (!peer) {
|
||||
continue
|
||||
}
|
||||
let atQQ = sendMsg.data?.qq
|
||||
@@ -133,7 +95,7 @@ export async function createSendElements(
|
||||
atQQ = atQQ.toString()
|
||||
if (atQQ === 'all') {
|
||||
// todo:查询剩余的at全体次数
|
||||
const groupCode = (target as Group)?.groupCode
|
||||
const groupCode = peer.peerUid
|
||||
let remainAtAllCount = 1
|
||||
let isAdmin: boolean = true
|
||||
if (groupCode) {
|
||||
@@ -141,7 +103,7 @@ export async function createSendElements(
|
||||
remainAtAllCount = (await NTQQGroupApi.getGroupAtAllRemainCount(groupCode)).atInfo
|
||||
.RemainAtAllCountForUin
|
||||
log(`群${groupCode}剩余at全体次数`, remainAtAllCount)
|
||||
const self = await getGroupMember((target as Group)?.groupCode, selfInfo.uin)
|
||||
const self = await getGroupMember(groupCode, selfInfo.uin)
|
||||
isAdmin = self?.role === GroupMemberRole.admin || self?.role === GroupMemberRole.owner
|
||||
} catch (e) {
|
||||
}
|
||||
@@ -150,9 +112,9 @@ export async function createSendElements(
|
||||
sendElements.push(SendMsgElementConstructor.at(atQQ, atQQ, AtType.atAll, '全体成员'))
|
||||
}
|
||||
}
|
||||
else {
|
||||
else if (peer.chatType === ChatType.group) {
|
||||
// const atMember = group?.members.find(m => m.uin == atQQ)
|
||||
const atMember = await getGroupMember((target as Group)?.groupCode, atQQ)
|
||||
const atMember = await getGroupMember(peer.peerUid, atQQ)
|
||||
if (atMember) {
|
||||
sendElements.push(
|
||||
SendMsgElementConstructor.at(atQQ, atMember.uid, AtType.atUser, atMember.cardName || atMember.nick),
|
||||
@@ -265,18 +227,6 @@ export async function createSendElements(
|
||||
break
|
||||
case OB11MessageDataType.poke: {
|
||||
let qq = sendMsg.data?.qq || sendMsg.data?.id
|
||||
if (qq) {
|
||||
if ('groupCode' in target!) {
|
||||
crychic.sendGroupPoke(target.groupCode, qq.toString())
|
||||
}
|
||||
else {
|
||||
if (!qq) {
|
||||
qq = parseInt(target?.uin!)
|
||||
}
|
||||
crychic.sendFriendPoke(qq.toString())
|
||||
}
|
||||
sendElements.push(SendMsgElementConstructor.poke('', '')!)
|
||||
}
|
||||
}
|
||||
break
|
||||
case OB11MessageDataType.dice: {
|
||||
@@ -338,6 +288,31 @@ export async function sendMsg(
|
||||
return returnMsg
|
||||
}
|
||||
|
||||
async function createContext(payload: OB11PostSendMsg, contextMode: ContextMode): Promise<Peer> {
|
||||
// This function determines the type of message by the existence of user_id / group_id,
|
||||
// not message_type.
|
||||
// This redundant design of Ob11 here should be blamed.
|
||||
|
||||
if ((contextMode === ContextMode.Group || contextMode === ContextMode.Normal) && payload.group_id) {
|
||||
const group = (await getGroup(payload.group_id))! // checked before
|
||||
return {
|
||||
chatType: ChatType.group,
|
||||
peerUid: group.groupCode
|
||||
}
|
||||
}
|
||||
if ((contextMode === ContextMode.Private || contextMode === ContextMode.Normal) && payload.user_id) {
|
||||
const Uid = await NTQQUserApi.getUidByUin(payload.user_id.toString())
|
||||
const isBuddy = await NTQQFriendApi.isBuddy(Uid!)
|
||||
//console.log("[调试代码] UIN:", payload.user_id, " UID:", Uid, " IsBuddy:", isBuddy)
|
||||
return {
|
||||
chatType: isBuddy ? ChatType.friend : ChatType.temp,
|
||||
peerUid: Uid!,
|
||||
guildId: payload.group_id || ''//临时主动发起时需要传入群号
|
||||
}
|
||||
}
|
||||
throw '请指定 group_id 或 user_id'
|
||||
}
|
||||
|
||||
export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
||||
actionName = ActionName.SendMsg
|
||||
|
||||
@@ -364,13 +339,11 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
||||
}
|
||||
}
|
||||
if (payload.user_id && payload.message_type !== 'group') {
|
||||
if (!(await getFriend(payload.user_id))) {
|
||||
if (!ALLOW_SEND_TEMP_MSG && !(await dbUtil.getReceivedTempUinMap())[payload.user_id.toString()]) {
|
||||
return {
|
||||
valid: false,
|
||||
message: `不能发送临时消息`,
|
||||
}
|
||||
}
|
||||
const uid = await NTQQUserApi.getUidByUin(payload.user_id.toString())
|
||||
const isBuddy = await NTQQFriendApi.isBuddy(uid!)
|
||||
// 此处有问题
|
||||
if (!isBuddy) {
|
||||
//return { valid: false, message: '异常消息' }
|
||||
}
|
||||
}
|
||||
return {
|
||||
@@ -379,56 +352,14 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
||||
}
|
||||
|
||||
protected async _handle(payload: OB11PostSendMsg) {
|
||||
const peer: Peer = {
|
||||
chatType: ChatType.friend,
|
||||
peerUid: '',
|
||||
}
|
||||
let isTempMsg = false
|
||||
let group: Group | undefined = undefined
|
||||
let friend: Friend | undefined = undefined
|
||||
const genGroupPeer = async () => {
|
||||
group = await getGroup(payload.group_id?.toString()!)
|
||||
peer.chatType = ChatType.group
|
||||
// peer.name = group.name
|
||||
peer.peerUid = group?.groupCode!
|
||||
}
|
||||
|
||||
const genFriendPeer = () => {
|
||||
friend = friends.find((f) => f.uin == payload.user_id.toString())
|
||||
if (friend) {
|
||||
// peer.name = friend.nickName
|
||||
peer.peerUid = friend.uid
|
||||
}
|
||||
else {
|
||||
peer.chatType = ChatType.temp
|
||||
const tempUserUid = getUidByUin(payload.user_id.toString())
|
||||
if (!tempUserUid) {
|
||||
throw `找不到私聊对象${payload.user_id}`
|
||||
}
|
||||
// peer.name = tempUser.nickName
|
||||
isTempMsg = true
|
||||
peer.peerUid = tempUserUid
|
||||
}
|
||||
}
|
||||
if (payload?.group_id && payload.message_type === 'group') {
|
||||
await genGroupPeer()
|
||||
}
|
||||
else if (payload?.user_id) {
|
||||
genFriendPeer()
|
||||
}
|
||||
else if (payload.group_id) {
|
||||
await genGroupPeer()
|
||||
}
|
||||
else {
|
||||
throw '发送消息参数错误, 请指定group_id或user_id'
|
||||
}
|
||||
const peer = await createContext(payload, ContextMode.Normal)
|
||||
const messages = convertMessage2List(
|
||||
payload.message,
|
||||
payload.auto_escape === true || payload.auto_escape === 'true',
|
||||
)
|
||||
if (this.getSpecialMsgNum(messages, OB11MessageDataType.node)) {
|
||||
try {
|
||||
const returnMsg = await this.handleForwardNode(peer, messages as OB11MessageNode[], group)
|
||||
const returnMsg = await this.handleForwardNode(peer, messages as OB11MessageNode[])
|
||||
return { message_id: returnMsg?.msgShortId! }
|
||||
} catch (e: any) {
|
||||
throw '发送转发消息失败 ' + e.toString()
|
||||
@@ -485,7 +416,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
||||
}
|
||||
}
|
||||
// log("send msg:", peer, sendElements)
|
||||
const { sendElements, deleteAfterSentFiles } = await createSendElements(messages, group || friend)
|
||||
const { sendElements, deleteAfterSentFiles } = await createSendElements(messages, peer)
|
||||
if (sendElements.length === 1) {
|
||||
if (sendElements[0] === null) {
|
||||
return { message_id: 0 }
|
||||
@@ -534,7 +465,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
||||
}
|
||||
|
||||
// 返回一个合并转发的消息id
|
||||
private async handleForwardNode(destPeer: Peer, messageNodes: OB11MessageNode[], group: Group | undefined) {
|
||||
private async handleForwardNode(destPeer: Peer, messageNodes: OB11MessageNode[]) {
|
||||
const selfPeer = {
|
||||
chatType: ChatType.friend,
|
||||
peerUid: selfInfo.uid,
|
||||
@@ -567,7 +498,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
||||
try {
|
||||
const { sendElements, deleteAfterSentFiles } = await createSendElements(
|
||||
convertMessage2List(messageNode.data.content),
|
||||
group,
|
||||
destPeer
|
||||
)
|
||||
log('开始生成转发节点', sendElements)
|
||||
let sendElementsSplit: SendMessageElement[][] = []
|
||||
@@ -655,42 +586,6 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// private genMusicElement(url: string, audio: string, title: string, content: string, image: string): SendArkElement {
|
||||
// const musicJson = {
|
||||
// app: 'com.tencent.structmsg',
|
||||
// config: {
|
||||
// ctime: 1709689928,
|
||||
// forward: 1,
|
||||
// token: '5c1e4905f926dd3a64a4bd3841460351',
|
||||
// type: 'normal',
|
||||
// },
|
||||
// extra: { app_type: 1, appid: 100497308, uin: selfInfo.uin },
|
||||
// meta: {
|
||||
// news: {
|
||||
// action: '',
|
||||
// android_pkg_name: '',
|
||||
// app_type: 1,
|
||||
// appid: 100497308,
|
||||
// ctime: 1709689928,
|
||||
// desc: content || title,
|
||||
// jumpUrl: url,
|
||||
// musicUrl: audio,
|
||||
// preview: image,
|
||||
// source_icon: 'https://p.qpic.cn/qqconnect/0/app_100497308_1626060999/100?max-age=2592000&t=0',
|
||||
// source_url: '',
|
||||
// tag: 'QQ音乐',
|
||||
// title: title,
|
||||
// uin: selfInfo.uin,
|
||||
// },
|
||||
// },
|
||||
// prompt: content || title,
|
||||
// ver: '0.0.0.1',
|
||||
// view: 'news',
|
||||
// }
|
||||
|
||||
// return SendMsgElementConstructor.ark(musicJson)
|
||||
// }
|
||||
}
|
||||
|
||||
export default SendMsg
|
||||
|
@@ -1,8 +1,6 @@
|
||||
import BaseAction from '../BaseAction'
|
||||
import { getFriend, getUidByUin, uidMaps } from '../../../common/data'
|
||||
import { ActionName } from '../types'
|
||||
import { NTQQFriendApi } from '../../../ntqqapi/api/friend'
|
||||
import { log } from '../../../common/utils/log'
|
||||
import { NTQQUserApi } from '@/ntqqapi/api'
|
||||
|
||||
interface Payload {
|
||||
user_id: number
|
||||
@@ -13,19 +11,12 @@ export default class SendLike extends BaseAction<Payload, null> {
|
||||
actionName = ActionName.SendLike
|
||||
|
||||
protected async _handle(payload: Payload): Promise<null> {
|
||||
log('点赞参数', payload)
|
||||
try {
|
||||
const qq = payload.user_id.toString()
|
||||
const friend = await getFriend(qq)
|
||||
let uid: string
|
||||
if (!friend) {
|
||||
uid = getUidByUin(qq)!
|
||||
} else {
|
||||
uid = friend.uid
|
||||
}
|
||||
let result = await NTQQFriendApi.likeFriend(uid, parseInt(payload.times?.toString()) || 1)
|
||||
const uid: string = await NTQQUserApi.getUidByUin(qq) || ''
|
||||
const result = await NTQQUserApi.like(uid, parseInt(payload.times?.toString()) || 1)
|
||||
if (result.result !== 0) {
|
||||
throw result.errMsg
|
||||
throw Error(result.errMsg)
|
||||
}
|
||||
} catch (e) {
|
||||
throw `点赞失败 ${e}`
|
||||
|
@@ -26,7 +26,7 @@ import {
|
||||
VideoElement,
|
||||
FriendV2
|
||||
} from '../ntqqapi/types'
|
||||
import { deleteGroup, getFriend, getGroupMember, selfInfo, tempGroupCodeMap, uidMaps } from '../common/data'
|
||||
import { deleteGroup, getGroupMember, selfInfo, tempGroupCodeMap, uidMaps } from '../common/data'
|
||||
import { EventType } from './event/OB11BaseEvent'
|
||||
import { encodeCQCode } from './cqcode'
|
||||
import { dbUtil } from '../common/db'
|
||||
@@ -34,9 +34,6 @@ import { OB11GroupIncreaseEvent } from './event/notice/OB11GroupIncreaseEvent'
|
||||
import { OB11GroupBanEvent } from './event/notice/OB11GroupBanEvent'
|
||||
import { OB11GroupUploadNoticeEvent } from './event/notice/OB11GroupUploadNoticeEvent'
|
||||
import { OB11GroupNoticeEvent } from './event/notice/OB11GroupNoticeEvent'
|
||||
import { NTQQUserApi } from '../ntqqapi/api/user'
|
||||
import { NTQQFileApi } from '../ntqqapi/api/file'
|
||||
import { NTQQMsgApi } from '../ntqqapi/api/msg'
|
||||
import { calcQQLevel } from '../common/utils/qqlevel'
|
||||
import { log } from '../common/utils/log'
|
||||
import { isNull, sleep } from '../common/utils/helper'
|
||||
@@ -44,7 +41,7 @@ import { getConfigUtil } from '../common/config'
|
||||
import { OB11GroupTitleEvent } from './event/notice/OB11GroupTitleEvent'
|
||||
import { OB11GroupCardEvent } from './event/notice/OB11GroupCardEvent'
|
||||
import { OB11GroupDecreaseEvent } from './event/notice/OB11GroupDecreaseEvent'
|
||||
import { NTQQGroupApi } from '../ntqqapi/api'
|
||||
import { NTQQGroupApi, NTQQUserApi, NTQQFileApi, NTQQMsgApi } from '../ntqqapi/api'
|
||||
import { OB11GroupMsgEmojiLikeEvent } from './event/notice/OB11MsgEmojiLikeEvent'
|
||||
import { mFaceCache } from '../ntqqapi/constructor'
|
||||
import { OB11FriendAddNoticeEvent } from './event/notice/OB11FriendAddNoticeEvent'
|
||||
@@ -54,8 +51,6 @@ import { OB11FriendPokeEvent, OB11GroupPokeEvent } from './event/notice/OB11Poke
|
||||
import { OB11BaseNoticeEvent } from './event/notice/OB11BaseNoticeEvent'
|
||||
import { OB11GroupEssenceEvent } from './event/notice/OB11GroupEssenceEvent'
|
||||
|
||||
let lastRKeyUpdateTime = 0
|
||||
|
||||
export class OB11Constructor {
|
||||
static async message(msg: RawMessage): Promise<OB11Message> {
|
||||
let config = getConfigUtil().getConfig()
|
||||
@@ -99,10 +94,7 @@ export class OB11Constructor {
|
||||
}
|
||||
else if (msg.chatType == ChatType.friend) {
|
||||
resMsg.sub_type = 'friend'
|
||||
const friend = await getFriend(msg.senderUin!)
|
||||
if (friend) {
|
||||
resMsg.sender.nickname = friend.nick
|
||||
}
|
||||
resMsg.sender.nickname = (await NTQQUserApi.getUserDetailInfo(msg.senderUid)).nick
|
||||
}
|
||||
else if (msg.chatType == ChatType.temp) {
|
||||
resMsg.sub_type = 'group'
|
||||
|
@@ -1,4 +1,3 @@
|
||||
/// <reference path="../global.d.ts" />
|
||||
import { CheckVersion } from '../common/types'
|
||||
import { SettingButton, SettingItem, SettingList, SettingSwitch, SettingSelect } from './components'
|
||||
// @ts-ignore
|
||||
@@ -26,22 +25,24 @@ function initSideBar() {
|
||||
})
|
||||
}
|
||||
|
||||
function isEmpty(value: unknown) {
|
||||
return value === undefined || value === null || value === ''
|
||||
}
|
||||
|
||||
async function onSettingWindowCreated(view: Element) {
|
||||
window.llonebot.log('setting window created')
|
||||
initSideBar()
|
||||
const isEmpty = (value: any) => value === undefined || value === null || value === ''
|
||||
let config = await window.llonebot.getConfig()
|
||||
let ob11Config = { ...config.ob11 }
|
||||
|
||||
const setConfig = (key: string, value: any) => {
|
||||
const configKey = key.split('.')
|
||||
|
||||
if (key.indexOf('ob11') === 0) {
|
||||
if (configKey.length === 2) ob11Config[configKey[1]] = value
|
||||
else ob11Config[key] = value
|
||||
} else {
|
||||
if (configKey.length === 2) config[configKey[0]][configKey[1]] = value
|
||||
else config[key] = value
|
||||
|
||||
if (!['heartInterval', 'token', 'ffmpeg'].includes(key)) {
|
||||
window.llonebot.setConfig(false, config)
|
||||
}
|
||||
@@ -65,7 +66,7 @@ async function onSettingWindowCreated(view: Element) {
|
||||
]),
|
||||
SettingList([
|
||||
SettingItem(
|
||||
'是否启用 LLOneBot, 重启QQ后生效',
|
||||
'是否启用 LLOneBot, 重启 QQ 后生效',
|
||||
null,
|
||||
SettingSwitch('enableLLOB', config.enableLLOB, { 'control-display-id': 'config-enableLLOB' }),
|
||||
)]
|
||||
@@ -160,21 +161,21 @@ async function onSettingWindowCreated(view: Element) {
|
||||
SettingSelect(
|
||||
[
|
||||
{ text: '消息段', value: 'array' },
|
||||
{ text: 'CQ码', value: 'string' },
|
||||
{ text: 'CQ 码', value: 'string' },
|
||||
],
|
||||
'ob11.messagePostFormat',
|
||||
config.ob11.messagePostFormat,
|
||||
),
|
||||
),
|
||||
SettingItem(
|
||||
'ffmpeg 路径,发送语音、视频需要,同时保证ffprobe和ffmpeg在一起',
|
||||
` <a href="javascript:LiteLoader.api.openExternal(\'https://llonebot.github.io/zh-CN/guide/ffmpeg\');">下载地址</a> <span id="config-ffmpeg-path-text">, 路径:${
|
||||
'FFmpeg 路径,发送语音、视频需要',
|
||||
`<a href="javascript:LiteLoader.api.openExternal(\'https://llonebot.github.io/zh-CN/guide/ffmpeg\');">可点此下载</a>, 路径: <span id="config-ffmpeg-path-text">${
|
||||
!isEmpty(config.ffmpeg) ? config.ffmpeg : '未指定'
|
||||
}</span>`,
|
||||
SettingButton('选择ffmpeg', 'config-ffmpeg-select'),
|
||||
}</span>, 需保证 FFprobe 和 FFmpeg 在一起`,
|
||||
SettingButton('选择 FFmpeg', 'config-ffmpeg-select'),
|
||||
),
|
||||
SettingItem(
|
||||
'音乐卡片签名地址',
|
||||
'音乐卡片签名 URL 地址',
|
||||
null,
|
||||
`<div class="q-input" style="width:210px;"><input class="q-input__inner" data-config-key="musicSignUrl" type="text" value="${config.musicSignUrl}" placeholder="未设置" /></div>`,
|
||||
'config-musicSignUrl',
|
||||
|
@@ -1 +1 @@
|
||||
export const version = '3.28.0'
|
||||
export const version = '3.28.1'
|
||||
|
Reference in New Issue
Block a user