Merge branch 'dev'

This commit is contained in:
linyuchen 2024-03-20 18:53:08 +08:00
commit e276d0e4f8
24 changed files with 429 additions and 158 deletions

View File

@ -3,5 +3,5 @@ export const CHANNEL_SET_CONFIG = 'llonebot_set_config'
export const CHANNEL_LOG = 'llonebot_log'
export const CHANNEL_ERROR = 'llonebot_error'
export const CHANNEL_UPDATE = 'llonebot_update'
export const CHANNEL_CHECKVERSION = 'llonebot_checkversion'
export const CHANNEL_CHECK_VERSION = 'llonebot_check_version'
export const CHANNEL_SELECT_FILE = 'llonebot_select_ffmpeg'

View File

@ -6,7 +6,7 @@ import path from "node:path";
import {selfInfo} from "./data";
import {DATA_DIR} from "./utils";
export const HOOK_LOG = true;
export const HOOK_LOG = false;
export const ALLOW_SEND_TEMP_MSG = false;

View File

@ -6,11 +6,12 @@ import util from "util";
import {encode, getDuration, isWav} from "silk-wasm";
import path from "node:path";
import {v4 as uuidv4} from "uuid";
import {DATA_DIR, log, TEMP_DIR} from "./index";
import {checkFfmpeg, DATA_DIR, log, TEMP_DIR} from "./index";
import {getConfigUtil} from "../config";
import {dbUtil} from "../db";
import * as fileType from "file-type";
import {net} from "electron";
import config from "../../../electron.vite.config";
export function isGIF(path: string) {
@ -66,28 +67,6 @@ export async function file2base64(path: string) {
return result;
}
export function checkFfmpeg(newPath: string = null): Promise<boolean> {
return new Promise((resolve, reject) => {
log("开始检查ffmpeg", newPath);
if (newPath) {
ffmpeg.setFfmpegPath(newPath);
}
try {
ffmpeg.getAvailableFormats((err, formats) => {
if (err) {
log('ffmpeg is not installed or not found in PATH:', err);
resolve(false)
} else {
log('ffmpeg is installed.');
resolve(true);
}
})
} catch (e) {
resolve(false);
}
});
}
export async function encodeSilk(filePath: string) {
const fsp = require("fs").promises

View File

@ -13,4 +13,5 @@ export const PLUGIN_DIR = global.LiteLoader.plugins["LLOneBot"].path.plugin;
if (!fs.existsSync(TEMP_DIR)) {
fs.mkdirSync(TEMP_DIR);
}
export {getVideoInfo} from "./video";
export {getVideoInfo} from "./video";
export {checkFfmpeg} from "./video";

View File

@ -1,24 +1,29 @@
import {version} from "../../version";
import { version } from "../../version";
import * as path from "node:path";
import * as fs from "node:fs";
import {copyFolder, httpDownload, log, PLUGIN_DIR, TEMP_DIR} from ".";
import { copyFolder, httpDownload, log, PLUGIN_DIR, TEMP_DIR } from ".";
import compressing from "compressing";
const downloadMirrorHosts = ["https://mirror.ghproxy.com/"];
const checkVersionMirrorHosts = ["https://521github.com"];
export async function checkVersion() {
export async function checkNewVersion() {
const latestVersionText = await getRemoteVersion();
const latestVersion = latestVersionText.split(".");
log("llonebot last version", latestVersion);
const currentVersion = version.split(".");
for (let k in [0, 1, 2]) {
if (latestVersion[k] > currentVersion[k]) {
return {result: false, version: latestVersionText};
const currentVersion: string[] = version.split(".");
log("llonebot current version", currentVersion);
for (let k of [0, 1, 2]) {
if (parseInt(latestVersion[k]) > parseInt(currentVersion[k])) {
log("")
return { result: true, version: latestVersionText };
}
else if (parseInt(latestVersion[k]) < parseInt(currentVersion[k])) {
break;
}
}
return {result: true, version: version};
return { result: false, version: version };
}
export async function upgradeLLOneBot() {
@ -28,17 +33,17 @@ export async function upgradeLLOneBot() {
const filePath = path.join(TEMP_DIR, "./update-" + latestVersion + ".zip");
let downloadSuccess = false;
// 多镜像下载
for(const mirrorGithub of downloadMirrorHosts){
try{
for (const mirrorGithub of downloadMirrorHosts) {
try {
const buffer = await httpDownload(mirrorGithub + downloadUrl);
fs.writeFileSync(filePath, buffer)
downloadSuccess = true;
break;
}catch (e) {
} catch (e) {
log("llonebot upgrade error", e);
}
}
if (!downloadSuccess){
if (!downloadSuccess) {
log("llonebot upgrade error", "download failed");
return false;
}

File diff suppressed because one or more lines are too long

View File

@ -7,7 +7,7 @@ import {
CHANNEL_ERROR,
CHANNEL_GET_CONFIG,
CHANNEL_LOG,
CHANNEL_CHECKVERSION,
CHANNEL_CHECK_VERSION,
CHANNEL_SELECT_FILE,
CHANNEL_SET_CONFIG,
CHANNEL_UPDATE,
@ -41,10 +41,10 @@ import {NTQQUserApi} from "../ntqqapi/api/user";
import {NTQQGroupApi} from "../ntqqapi/api/group";
import {registerPokeHandler} from "../ntqqapi/external/ccpoke";
import {OB11FriendPokeEvent, OB11GroupPokeEvent} from "../onebot11/event/notice/OB11PokeEvent";
import {checkVersion, upgradeLLOneBot} from "../common/utils/upgrade";
import {checkFfmpeg} from "../common/utils/file";
import {checkNewVersion, upgradeLLOneBot} from "../common/utils/upgrade";
import {log} from "../common/utils/log";
import {getConfigUtil} from "../common/config";
import {checkFfmpeg} from "../common/utils/video";
let running = false;
@ -53,8 +53,8 @@ let running = false;
// 加载插件时触发
function onLoad() {
log("llonebot main onLoad");
ipcMain.handle(CHANNEL_CHECKVERSION, async (event, arg) => {
return checkVersion();
ipcMain.handle(CHANNEL_CHECK_VERSION, async (event, arg) => {
return checkNewVersion();
});
ipcMain.handle(CHANNEL_UPDATE, async (event, arg) => {
return upgradeLLOneBot();

View File

@ -4,6 +4,7 @@ import {ob11WebsocketServer} from "../onebot11/server/ws/WebsocketServer";
import {ob11ReverseWebsockets} from "../onebot11/server/ws/ReverseWebsocket";
import {llonebotError} from "../common/data";
import {getConfigUtil} from "../common/config";
import {checkFfmpeg} from "../common/utils";
export async function setConfig(config: Config) {
let oldConfig = getConfigUtil().getConfig();
@ -51,4 +52,5 @@ export async function setConfig(config: Config) {
}
}
}
checkFfmpeg(config.ffmpeg).then()
}

View File

@ -5,6 +5,7 @@ import {uidMaps} from "../../common/data";
import {BrowserWindow} from "electron";
import {dbUtil} from "../../common/db";
import {log} from "../../common/utils/log";
import {NTQQWindowApi, NTQQWindows} from "./window";
export class NTQQGroupApi{
static async getGroups(forced = false) {
@ -74,25 +75,7 @@ export class NTQQGroupApi{
}
static async getGroupIgnoreNotifies() {
await NTQQGroupApi.getGroupNotifies();
const result = callNTQQApi<GroupNotifies>({
className: NTQQApiClass.WINDOW_API,
methodName: NTQQApiMethod.OPEN_EXTRA_WINDOW,
cbCmd: ReceiveCmdS.GROUP_NOTIFY,
afterFirstCmd: false,
args: [
"GroupNotifyFilterWindow"
]
})
// 关闭窗口
setTimeout(() => {
for (const w of BrowserWindow.getAllWindows()) {
// log("close window", w.webContents.getURL())
if (w.webContents.getURL().indexOf("#/notify-filter/") != -1) {
w.close();
}
}
}, 2000);
return result;
return await NTQQWindowApi.openWindow(NTQQWindows.GroupNotifyFilterWindow,[], ReceiveCmdS.GROUP_NOTIFY);
}
static async handleGroupRequest(seq: string, operateType: GroupRequestOperateTypes, reason?: string) {
const notify: GroupNotify = await dbUtil.getGroupNotify(seq)

7
src/ntqqapi/api/index.ts Normal file
View File

@ -0,0 +1,7 @@
export * from "./file";
export * from "./friend";
export * from "./group";
export * from "./msg";
export * from "./user";
export * from "./webapi";
export * from "./window";

View File

@ -53,5 +53,4 @@ export class NTQQUserApi{
return info
}
}

87
src/ntqqapi/api/webapi.ts Normal file
View File

@ -0,0 +1,87 @@
import {net, session} from "electron";
import {NTQQApi} from "../ntcall";
import {groups} from "../../common/data";
import {log} from "../../common/utils";
export class WebApi{
private static bkn: string;
private static skey: string;
private static pskey: string;
private static cookie: string
private defaultHeaders: Record<string,string> = {
"User-Agent": "QQ/8.9.28.635 CFNetwork/1312 Darwin/21.0.0"
}
constructor() {
}
public async addGroupDigest(groupCode: string, msgSeq: string){
const url = `https://qun.qq.com/cgi-bin/group_digest/cancel_digest?random=665&X-CROSS-ORIGIN=fetch&group_code=${groupCode}&msg_seq=${msgSeq}&msg_random=444021292`
const res = await this.request(url)
return await res.json()
}
public async getGroupDigest(groupCode: string){
const url = `https://qun.qq.com/cgi-bin/group_digest/digest_list?random=665&X-CROSS-ORIGIN=fetch&group_code=${groupCode}&page_start=0&page_limit=20`
const res = await this.request(url)
log(res.headers)
return await res.json()
}
private genBkn(sKey: string){
sKey = sKey || "";
let hash = 5381;
for (let i = 0; i < sKey.length; i++) {
const code = sKey.charCodeAt(i);
hash = hash + (hash << 5) + code;
}
return (hash & 0x7FFFFFFF).toString();
}
private async init(){
if (!WebApi.bkn) {
const group = groups[0];
WebApi.skey = (await NTQQApi.getSkey(group.groupName, group.groupCode)).data;
WebApi.bkn = this.genBkn(WebApi.skey);
let cookie = await NTQQApi.getPSkey();
const pskeyRegex = /p_skey=([^;]+)/;
const match = cookie.match(pskeyRegex);
const pskeyValue = match ? match[1] : null;
WebApi.pskey = pskeyValue;
if (cookie.indexOf("skey=;") !== -1) {
cookie = cookie.replace("skey=;", `skey=${WebApi.skey};`);
}
WebApi.cookie = cookie;
// for(const kv of WebApi.cookie.split(";")){
// const [key, value] = kv.split("=");
// }
// log("set cookie", key, value)
// await session.defaultSession.cookies.set({
// url: 'https://qun.qq.com', // 你要请求的域名
// name: key.trim(),
// value: value.trim(),
// expirationDate: Date.now() / 1000 + 300000, // Cookie 过期时间例如设置为当前时间之后的300秒
// });
// }
}
}
private async request(url: string, method: "GET" | "POST" = "GET", headers: Record<string, string> = {}){
await this.init();
url += "&bkn=" + WebApi.bkn;
let _headers: Record<string, string> = {
...this.defaultHeaders, ...headers,
"Cookie": WebApi.cookie,
credentials: 'include'
}
log("request", url, _headers)
const options = {
method: method,
headers: _headers
}
return fetch(url, options)
}
}

49
src/ntqqapi/api/window.ts Normal file
View File

@ -0,0 +1,49 @@
import {callNTQQApi, GeneralCallResult, NTQQApiClass, NTQQApiMethod} from "../ntcall";
import {ReceiveCmd} from "../hook";
import {BrowserWindow} from "electron";
export interface NTQQWindow{
windowName: string,
windowUrlHash: string,
}
export class NTQQWindows{
static GroupHomeWorkWindow: NTQQWindow = {
windowName: "GroupHomeWorkWindow",
windowUrlHash: "#/group-home-work"
}
static GroupNotifyFilterWindow: NTQQWindow = {
windowName: "GroupNotifyFilterWindow",
windowUrlHash: "#/group-notify-filter"
}
static GroupEssenceWindow: NTQQWindow = {
windowName: "GroupEssenceWindow",
windowUrlHash: "#/group-essence"
}
}
export class NTQQWindowApi{
// 打开窗口并获取对应的下发事件
static async openWindow<R=GeneralCallResult>(ntQQWindow: NTQQWindow, args: any[], cbCmd: ReceiveCmd=null, autoCloseSeconds: number=2){
const result = await callNTQQApi<R>({
className: NTQQApiClass.WINDOW_API,
methodName: NTQQApiMethod.OPEN_EXTRA_WINDOW,
cbCmd,
afterFirstCmd: false,
args: [
ntQQWindow.windowName,
...args
]
})
setTimeout(() => {
for (const w of BrowserWindow.getAllWindows()) {
// log("close window", w.webContents.getURL())
if (w.webContents.getURL().indexOf(ntQQWindow.windowUrlHash) != -1) {
w.close();
}
}
}, autoCloseSeconds * 1000);
return result;
}
}

View File

@ -33,6 +33,7 @@ export let ReceiveCmdS = {
SELF_STATUS: 'nodeIKernelProfileListener/onSelfStatusChanged',
CACHE_SCAN_FINISH: "nodeIKernelStorageCleanListener/onFinishScan",
MEDIA_UPLOAD_COMPLETE: "nodeIKernelMsgListener/onRichMediaUploadComplete",
SKEY_UPDATE: "onSkeyUpdate"
}
export type ReceiveCmd = typeof ReceiveCmdS[keyof typeof ReceiveCmdS]
@ -60,45 +61,56 @@ let receiveHooks: Array<{
export function hookNTQQApiReceive(window: BrowserWindow) {
const originalSend = window.webContents.send;
const patchSend = (channel: string, ...args: NTQQApiReturnData) => {
// console.log("hookNTQQApiReceive", channel, args)
let isLogger = false
try {
if (!args[0]?.eventName?.startsWith("ns-LoggerApi")) {
HOOK_LOG && log(`received ntqq api message: ${channel}`, JSON.stringify(args))
}
isLogger = args[0]?.eventName?.startsWith("ns-LoggerApi")
} catch (e) {
}
if (args?.[1] instanceof Array) {
for (let receiveData of args?.[1]) {
const ntQQApiMethodName = receiveData.cmdName;
// log(`received ntqq api message: ${channel} ${ntQQApiMethodName}`, JSON.stringify(receiveData))
for (let hook of receiveHooks) {
if (hook.method.includes(ntQQApiMethodName)) {
new Promise((resolve, reject) => {
try {
let _ = hook.hookFunc(receiveData.payload)
if (hook.hookFunc.constructor.name === "AsyncFunction") {
(_ as Promise<void>).then()
if (!isLogger) {
try {
HOOK_LOG && log(`received ntqq api message: ${channel}`, args)
}catch (e) {
log("hook log error", e, args)
}
}
try {
if (args?.[1] instanceof Array) {
for (let receiveData of args?.[1]) {
const ntQQApiMethodName = receiveData.cmdName;
// log(`received ntqq api message: ${channel} ${ntQQApiMethodName}`, JSON.stringify(receiveData))
for (let hook of receiveHooks) {
if (hook.method.includes(ntQQApiMethodName)) {
new Promise((resolve, reject) => {
try {
let _ = hook.hookFunc(receiveData.payload)
if (hook.hookFunc.constructor.name === "AsyncFunction") {
(_ as Promise<void>).then()
}
} catch (e) {
log("hook error", e, receiveData.payload)
}
} catch (e) {
log("hook error", e, receiveData.payload)
}
}).then()
}).then()
}
}
}
}
}
if (args[0]?.callbackId) {
// log("hookApiCallback", hookApiCallbacks, args)
const callbackId = args[0].callbackId;
if (hookApiCallbacks[callbackId]) {
// log("callback found")
new Promise((resolve, reject) => {
hookApiCallbacks[callbackId](args[1]);
}).then()
delete hookApiCallbacks[callbackId];
if (args[0]?.callbackId) {
// log("hookApiCallback", hookApiCallbacks, args)
const callbackId = args[0].callbackId;
if (hookApiCallbacks[callbackId]) {
// log("callback found")
new Promise((resolve, reject) => {
hookApiCallbacks[callbackId](args[1]);
}).then()
delete hookApiCallbacks[callbackId];
}
}
}catch (e) {
log("hookNTQQApiReceive error", e.stack.toString(), args)
}
return originalSend.call(window.webContents, channel, ...args);
originalSend.call(window.webContents, channel, ...args);
}
window.webContents.send = patchSend;
}
@ -110,12 +122,19 @@ export function hookNTQQApiCall(window: BrowserWindow) {
const proxyIpcMsg = new Proxy(ipc_message_proxy, {
apply(target, thisArg, args) {
// console.log(thisArg, args);
let isLogger = false
try {
if (args[3][1][0] !== "info") {
HOOK_LOG && log("call NTQQ api", thisArg, args);
}
isLogger = args[3][0].eventName.startsWith("ns-LoggerApi")
} catch (e) {
}
if (!isLogger) {
try{
HOOK_LOG && log("call NTQQ api", thisArg, args);
}catch (e) {
}
}
return target.apply(thisArg, args);
},
@ -137,7 +156,11 @@ export function hookNTQQApiCall(window: BrowserWindow) {
}
});
let ret = target.apply(thisArg, args);
HOOK_LOG && log("call NTQQ invoke api return", ret)
try {
HOOK_LOG && log("call NTQQ invoke api return", ret)
}catch (e) {
}
return ret;
}
});

View File

@ -1,8 +1,11 @@
import {ipcMain} from "electron";
import {hookApiCallbacks, ReceiveCmd, registerReceiveHook, removeReceiveHook} from "./hook";
import {hookApiCallbacks, ReceiveCmd, ReceiveCmdS, registerReceiveHook, removeReceiveHook} from "./hook";
import {v4 as uuidv4} from "uuid"
import {log} from "../common/utils/log";
import {NTQQWindow, NTQQWindowApi, NTQQWindows} from "./api/window";
import {WebApi} from "./api/webapi";
import {HOOK_LOG} from "../common/config";
export enum NTQQApiClass {
NT_API = "ns-ntApi",
@ -11,7 +14,10 @@ export enum NTQQApiClass {
WINDOW_API = "ns-WindowApi",
HOTUPDATE_API = "ns-HotUpdateApi",
BUSINESS_API = "ns-BusinessApi",
GLOBAL_DATA = "ns-GlobalDataApi"
GLOBAL_DATA = "ns-GlobalDataApi",
SKEY_API = "ns-SkeyApi",
GROUP_HOME_WORK = "ns-GroupHomeWork",
GROUP_ESSENCE = "ns-GroupEssence",
}
export enum NTQQApiMethod {
@ -65,7 +71,9 @@ export enum NTQQApiMethod {
OPEN_EXTRA_WINDOW = 'openExternalWindow',
SET_QQ_AVATAR = 'nodeIKernelProfileService/setHeader'
SET_QQ_AVATAR = 'nodeIKernelProfileService/setHeader',
GET_SKEY = "nodeIKernelTipOffService/getPskey",
UPDATE_SKEY = "updatePskey"
}
enum NTQQApiChannel {
@ -98,7 +106,7 @@ export function callNTQQApi<ReturnType>(params: NTQQApiParams) {
timeout = timeout ?? 5;
afterFirstCmd = afterFirstCmd ?? true;
const uuid = uuidv4();
// log("callNTQQApi", channel, className, methodName, args, uuid)
HOOK_LOG && log("callNTQQApi", channel, className, methodName, args, uuid)
return new Promise((resolve: (data: ReturnType) => void, reject) => {
// log("callNTQQApiPromise", channel, className, methodName, args, uuid)
const _timeout = timeout * 1000
@ -178,4 +186,58 @@ export class NTQQApi {
})
}
static async getSkey(groupName: string, groupCode: string): Promise<{data: string}> {
return await NTQQWindowApi.openWindow<{data: string}>(NTQQWindows.GroupHomeWorkWindow, [{
groupName,
groupCode,
"source": "funcbar"
}], ReceiveCmdS.SKEY_UPDATE, 1);
// return await callNTQQApi<string>({
// className: NTQQApiClass.GROUP_HOME_WORK,
// methodName: NTQQApiMethod.UPDATE_SKEY,
// args: [
// {
// domain: "qun.qq.com"
// }
// ]
// })
// return await callNTQQApi<GeneralCallResult>({
// methodName: NTQQApiMethod.GET_SKEY,
// args: [
// {
// "domains": [
// "qzone.qq.com",
// "qlive.qq.com",
// "qun.qq.com",
// "gamecenter.qq.com",
// "vip.qq.com",
// "qianbao.qq.com",
// "qidian.qq.com"
// ],
// "isForNewPCQQ": false
// },
// null
// ]
// })
}
static async getPSkey() {
return await callNTQQApi<string>({
className: NTQQApiClass.GROUP_HOME_WORK,
methodName: NTQQApiMethod.UPDATE_SKEY,
args: [
{
domain: "qun.qq.com"
}
]
})
}
static async addGroupDigest(groupCode: string, msgSeq: string) {
return await new WebApi().addGroupDigest(groupCode, msgSeq);
}
static async getGroupDigest(groupCode: string) {
return await new WebApi().getGroupDigest(groupCode);
}
}

View File

@ -18,7 +18,54 @@ export interface User {
longNick?: string; // 签名
remark?: string;
sex?: Sex;
"qqLevel"?: QQLevel
qqLevel?: QQLevel,
qid?: string
"birthday_year"?: number,
"birthday_month"?: number,
"birthday_day"?: number,
"topTime"?: string,
"constellation"?: number,
"shengXiao"?: number,
"kBloodType"?: number,
"homeTown"?: string, //"0-0-0",
"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,
"labels"?: string[],
"isHideQQLevel"?: number,
"privilegeIcon"?: {
"jumpUrl": string,
"openIconList": unknown[],
"closeIconList": unknown[]
},
"photoWall"?: {
"picList": unknown[]
},
"vipFlag"?: boolean,
"yearVipFlag"?: boolean,
"svipFlag"?: boolean,
"vipLevel"?: number,
"status"?: number,
"qidianMasterFlag"?: number,
"qidianCrewFlag"?: number,
"qidianCrewFlag2"?: number,
"extStatus"?: number,
"recommendImgFlag"?: number,
"disableEmojiShortCuts"?: number,
"pendantId"?: string,
}
export interface SelfInfo extends User {

View File

@ -1,29 +0,0 @@
import BaseAction from "./BaseAction";
import {NTQQApi} from "../../ntqqapi/ntcall";
import {ActionName} from "./types";
import {log} from "../../common/utils/log";
interface Payload {
method: string,
args: any[],
}
export default class Debug extends BaseAction<Payload, any> {
actionName = ActionName.Debug
protected async _handle(payload: Payload): Promise<any> {
log("debug call ntqq api", payload);
const method = NTQQApi[payload.method]
if (!method) {
throw `${method} 不存在`
}
const result = method(...payload.args);
if (method.constructor.name === "AsyncFunction") {
return await result
}
return result
// const info = await NTQQApi.getUserDetailInfo(friends[0].uid);
// return info
}
}

View File

@ -1,36 +1,20 @@
import BaseAction from "../BaseAction";
import {OB11User} from "../../types";
import {getFriend, getGroupMember, groups} from "../../../common/data";
import {getUidByUin, uidMaps} from "../../../common/data";
import {OB11Constructor} from "../../constructor";
import {ActionName} from "../types";
import {isNull, log} from "../../../common/utils";
import {NTQQUserApi} from "../../../ntqqapi/api/user";
import {Friend, GroupMember} from "../../../ntqqapi/types";
export default class GoCQHTTPGetStrangerInfo extends BaseAction<{ user_id: number }, OB11User> {
actionName = ActionName.GoCQHTTP_GetStrangerInfo
private async refreshInfo(user: Friend | GroupMember){
if (isNull(user.sex)){
let info = (await NTQQUserApi.getUserDetailInfo(user.uid))
Object.assign(user, info);
}
}
protected async _handle(payload: { user_id: number }): Promise<OB11User> {
const user_id = payload.user_id.toString()
const friend = await getFriend(user_id)
if (friend) {
await this.refreshInfo(friend);
return OB11Constructor.friend(friend);
const uid = getUidByUin(user_id)
if (!uid) {
throw new Error("查无此人")
}
for (const group of groups) {
const member = await getGroupMember(group.groupCode, user_id)
if (member) {
await this.refreshInfo(member);
return OB11Constructor.groupMember(group.groupCode, member) as OB11User
}
}
throw new Error("查无此人")
return OB11Constructor.stranger(await NTQQUserApi.getUserDetailInfo(uid))
}
}

View File

@ -20,7 +20,7 @@ import SendLike from "./SendLike";
import SetGroupAddRequest from "./SetGroupAddRequest";
import SetGroupLeave from "./SetGroupLeave";
import GetGuildList from "./GetGuildList";
import Debug from "./Debug";
import Debug from "./llonebot/Debug";
import SetFriendAddRequest from "./SetFriendAddRequest";
import SetGroupWholeBan from "./SetGroupWholeBan";
import SetGroupName from "./SetGroupName";

View File

@ -0,0 +1,31 @@
import BaseAction from "../BaseAction";
import * as ntqqApi from "../../../ntqqapi/api";
import {ActionName} from "../types";
import {log} from "../../../common/utils/log";
interface Payload {
method: string,
args: any[],
}
export default class Debug extends BaseAction<Payload, any> {
actionName = ActionName.Debug
protected async _handle(payload: Payload): Promise<any> {
log("debug call ntqq api", payload);
for (const ntqqApiClass in ntqqApi) {
const method = ntqqApi[ntqqApiClass][payload.method]
if (method) {
const result = method(...payload.args);
if (method.constructor.name === "AsyncFunction") {
return await result
}
return result
}
}
throw `${payload.method}方法 不存在`
// const info = await NTQQApi.getUserDetailInfo(friends[0].uid);
// return info
}
}

View File

@ -311,14 +311,14 @@ export class OB11Constructor {
nickname: friend.nick,
remark: friend.remark,
sex: OB11Constructor.sex(friend.sex),
qq_level: friend.qqLevel && calcQQLevel(friend.qqLevel) || 0
level: friend.qqLevel && calcQQLevel(friend.qqLevel) || 0
}
}
static selfInfo(selfInfo: SelfInfo): OB11User {
return {
user_id: parseInt(selfInfo.uin),
nickname: selfInfo.nick
nickname: selfInfo.nick,
}
}
@ -365,6 +365,19 @@ export class OB11Constructor {
}
}
static stranger(user: User): OB11User {
return {
...user,
user_id: parseInt(user.uin),
nickname: user.nick,
sex: OB11Constructor.sex(user.sex),
age: 0,
qid: user.qid,
login_days: 0,
level: user.qqLevel && calcQQLevel(user.qqLevel) || 0,
}
}
static groupMembers(group: Group): OB11GroupMember[] {
log("construct ob11 group members", group)
return group.members.map(m => OB11Constructor.groupMember(group.groupCode, m))

View File

@ -6,7 +6,10 @@ export interface OB11User {
nickname: string;
remark?: string;
sex?: OB11UserSex;
qq_level?: number;
level?: number;
age?: number;
qid?: string;
login_days?: number;
}
export enum OB11UserSex {

View File

@ -5,7 +5,7 @@ import {
CHANNEL_ERROR,
CHANNEL_GET_CONFIG,
CHANNEL_LOG,
CHANNEL_CHECKVERSION,
CHANNEL_CHECK_VERSION,
CHANNEL_SELECT_FILE,
CHANNEL_SET_CONFIG,
CHANNEL_UPDATE,
@ -19,7 +19,7 @@ const llonebot = {
ipcRenderer.send(CHANNEL_LOG, data);
},
checkVersion:async (): Promise<CheckVersion> => {
return ipcRenderer.invoke(CHANNEL_CHECKVERSION);
return ipcRenderer.invoke(CHANNEL_CHECK_VERSION);
},
updateLLOneBot:async (): Promise<boolean> => {
return ipcRenderer.invoke(CHANNEL_UPDATE);

View File

@ -336,7 +336,7 @@ async function onSettingWindowCreated(view: Element) {
});
return;
}
if (ResultVersion.result) {
if (!ResultVersion.result) {
view.querySelector(".llonebot-update-title").innerHTML = "当前已是最新版本 V" + ResultVersion.version;
view.querySelector(".llonebot-update-button").innerHTML = "无需更新";
} else {