From f149594e2361b3e876f29acdff973791e9109e5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Sun, 17 Mar 2024 13:34:39 +0800 Subject: [PATCH 1/7] feat: update --- src/common/channels.ts | 2 ++ src/common/utils.ts | 55 +++++++++++++++++++++++++++++++++++++----- src/main/main.ts | 51 ++++++++++++++++++++++----------------- src/preload.ts | 8 ++++++ 4 files changed, 88 insertions(+), 28 deletions(-) diff --git a/src/common/channels.ts b/src/common/channels.ts index ef928d9..5bb8ee6 100644 --- a/src/common/channels.ts +++ b/src/common/channels.ts @@ -2,4 +2,6 @@ export const CHANNEL_GET_CONFIG = 'llonebot_get_config' 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_REMOTEVERSION = 'llonebot_remoteversion' export const CHANNEL_SELECT_FILE = 'llonebot_select_ffmpeg' diff --git a/src/common/utils.ts b/src/common/utils.ts index c6904ab..c6c37e9 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -1,12 +1,13 @@ import * as path from "node:path"; -import {selfInfo} from "./data"; -import {ConfigUtil} from "./config"; +import { selfInfo } from "./data"; +import { ConfigUtil } from "./config"; import util from "util"; -import {encode, getDuration, isWav} from "silk-wasm"; +import { encode, getDuration, isWav } from "silk-wasm"; import fs from 'fs'; import * as crypto from 'crypto'; -import {v4 as uuidv4} from "uuid"; +import { v4 as uuidv4 } from "uuid"; import ffmpeg from "fluent-ffmpeg" +import * as https from "node:https"; export const DATA_DIR = global.LiteLoader.plugins["LLOneBot"].path.data; @@ -35,8 +36,50 @@ function truncateString(obj: any, maxLength = 500) { export function isNumeric(str: string) { return /^\d+$/.test(str); } +export async function updateLLOneBot() { + let mirrorGithubList = ["https://mirror.ghproxy.com"]; + return true; +} +export async function getRemoteVersion() { + let mirrorGithubList = ["https://521github.com"]; + let Version = ""; + for (let i = 0; i < mirrorGithubList.length; i++) { + let mirrorGithub = mirrorGithubList[i]; + let tVersion = await getRemoteVersionByMirror(mirrorGithub); + console.log("tVersion", tVersion); + if (tVersion && tVersion != "") { + Version = tVersion; + break; + } + } + return Version; +} +export async function getRemoteVersionByMirror(mirrorGithub: string) { + let releasePage = "error"; + let reqPromise = async function (): Promise { + return new Promise((resolve, reject) => { + https.get(mirrorGithub + "/LLOneBot/LLOneBot/releases", res => { + let list = []; + res.on('data', chunk => { + list.push(chunk); + }); + res.on('end', () => { + resolve(Buffer.concat(list).toString()); + }); + }).on('error', err => { + reject(); + }); + }); + } + try { + releasePage = await reqPromise(); + if (releasePage === "error") return ""; + return releasePage.match(new RegExp('(?<=(tag/v)).*?(?=("))'))[0]; + } + catch { } + return ""; - +} export function log(...msg: any[]) { if (!getConfigUtil().getConfig().log) { return //console.log(...msg); @@ -265,7 +308,7 @@ export async function encodeSilk(filePath: string) { export async function getVideoInfo(filePath: string) { const size = fs.statSync(filePath).size; return new Promise<{ width: number, height: number, time: number, format: string, size: number, filePath: string }>((resolve, reject) => { - ffmpeg(filePath).ffprobe( (err, metadata) => { + ffmpeg(filePath).ffprobe((err, metadata) => { if (err) { reject(err); } else { diff --git a/src/main/main.ts b/src/main/main.ts index fc769da..4f9aef5 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -1,17 +1,19 @@ // 运行在 Electron 主进程 下的插件入口 -import {BrowserWindow, dialog, ipcMain} from 'electron'; +import { BrowserWindow, dialog, ipcMain } from 'electron'; import * as fs from 'node:fs'; -import {Config} from "../common/types"; +import { Config } from "../common/types"; import { CHANNEL_ERROR, CHANNEL_GET_CONFIG, CHANNEL_LOG, + CHANNEL_REMOTEVERSION, CHANNEL_SELECT_FILE, CHANNEL_SET_CONFIG, + CHANNEL_UPDATE, } from "../common/channels"; -import {ob11WebsocketServer} from "../onebot11/server/ws/WebsocketServer"; -import {checkFfmpeg, DATA_DIR, getConfigUtil, log} from "../common/utils"; +import { ob11WebsocketServer } from "../onebot11/server/ws/WebsocketServer"; +import { checkFfmpeg, DATA_DIR, getConfigUtil, getRemoteVersion, log, updateLLOneBot } from "../common/utils"; import { friendRequests, getFriend, @@ -21,21 +23,21 @@ import { refreshGroupMembers, selfInfo } from "../common/data"; -import {hookNTQQApiCall, hookNTQQApiReceive, ReceiveCmd, registerReceiveHook} from "../ntqqapi/hook"; -import {OB11Constructor} from "../onebot11/constructor"; -import {NTQQApi} from "../ntqqapi/ntcall"; -import {ChatType, FriendRequestNotify, GroupNotifies, GroupNotifyTypes, RawMessage} from "../ntqqapi/types"; -import {ob11HTTPServer} from "../onebot11/server/http"; -import {OB11FriendRecallNoticeEvent} from "../onebot11/event/notice/OB11FriendRecallNoticeEvent"; -import {OB11GroupRecallNoticeEvent} from "../onebot11/event/notice/OB11GroupRecallNoticeEvent"; -import {postOB11Event} from "../onebot11/server/postOB11Event"; -import {ob11ReverseWebsockets} from "../onebot11/server/ws/ReverseWebsocket"; -import {OB11GroupAdminNoticeEvent} from "../onebot11/event/notice/OB11GroupAdminNoticeEvent"; -import {OB11GroupRequestEvent} from "../onebot11/event/request/OB11GroupRequest"; -import {OB11FriendRequestEvent} from "../onebot11/event/request/OB11FriendRequest"; +import { hookNTQQApiCall, hookNTQQApiReceive, ReceiveCmd, registerReceiveHook } from "../ntqqapi/hook"; +import { OB11Constructor } from "../onebot11/constructor"; +import { NTQQApi } from "../ntqqapi/ntcall"; +import { ChatType, FriendRequestNotify, GroupNotifies, GroupNotifyTypes, RawMessage } from "../ntqqapi/types"; +import { ob11HTTPServer } from "../onebot11/server/http"; +import { OB11FriendRecallNoticeEvent } from "../onebot11/event/notice/OB11FriendRecallNoticeEvent"; +import { OB11GroupRecallNoticeEvent } from "../onebot11/event/notice/OB11GroupRecallNoticeEvent"; +import { postOB11Event } from "../onebot11/server/postOB11Event"; +import { ob11ReverseWebsockets } from "../onebot11/server/ws/ReverseWebsocket"; +import { OB11GroupAdminNoticeEvent } from "../onebot11/event/notice/OB11GroupAdminNoticeEvent"; +import { OB11GroupRequestEvent } from "../onebot11/event/request/OB11GroupRequest"; +import { OB11FriendRequestEvent } from "../onebot11/event/request/OB11FriendRequest"; import * as path from "node:path"; -import {dbUtil} from "../common/db"; -import {setConfig} from "./setConfig"; +import { dbUtil } from "../common/db"; +import { setConfig } from "./setConfig"; let running = false; @@ -44,7 +46,12 @@ let running = false; // 加载插件时触发 function onLoad() { log("llonebot main onLoad"); - + ipcMain.handle(CHANNEL_REMOTEVERSION, async (event, arg) => { + return getRemoteVersion(); + }); + ipcMain.handle(CHANNEL_UPDATE, async (event, arg) => { + return updateLLOneBot(); + }); ipcMain.handle(CHANNEL_SELECT_FILE, async (event, arg) => { const selectPath = new Promise((resolve, reject) => { dialog @@ -76,7 +83,7 @@ function onLoad() { } }) if (!fs.existsSync(DATA_DIR)) { - fs.mkdirSync(DATA_DIR, {recursive: true}); + fs.mkdirSync(DATA_DIR, { recursive: true }); } ipcMain.handle(CHANNEL_ERROR, (event, arg) => { return llonebotError; @@ -94,7 +101,7 @@ function onLoad() { }) async function postReceiveMsg(msgList: RawMessage[]) { - const {debug, reportSelfMessage} = getConfigUtil().getConfig(); + const { debug, reportSelfMessage } = getConfigUtil().getConfig(); for (let message of msgList) { // log("收到新消息", message.msgId, message.msgSeq) @@ -167,7 +174,7 @@ function onLoad() { } }) registerReceiveHook<{ msgRecord: RawMessage }>(ReceiveCmd.SELF_SEND_MSG, async (payload) => { - const {reportSelfMessage} = getConfigUtil().getConfig(); + const { reportSelfMessage } = getConfigUtil().getConfig(); if (!reportSelfMessage) { return } diff --git a/src/preload.ts b/src/preload.ts index 983d62a..f20f404 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -5,8 +5,10 @@ import { CHANNEL_ERROR, CHANNEL_GET_CONFIG, CHANNEL_LOG, + CHANNEL_REMOTEVERSION, CHANNEL_SELECT_FILE, CHANNEL_SET_CONFIG, + CHANNEL_UPDATE, } from "./common/channels"; const {contextBridge} = require("electron"); @@ -16,6 +18,12 @@ const llonebot = { log: (data: any) => { ipcRenderer.send(CHANNEL_LOG, data); }, + getRemoteVersion:async (): Promise => { + return ipcRenderer.invoke(CHANNEL_REMOTEVERSION); + }, + updateLLOneBot:async (): Promise => { + return ipcRenderer.invoke(CHANNEL_UPDATE); + }, setConfig: (config: Config) => { ipcRenderer.send(CHANNEL_SET_CONFIG, config); }, From 90820cf74d264f97a68de6a0a8a7e6b65a1314c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Sun, 17 Mar 2024 14:22:02 +0800 Subject: [PATCH 2/7] fix: doc url --- src/common/utils.ts | 7 ++++++- src/renderer/index.ts | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/common/utils.ts b/src/common/utils.ts index c6c37e9..d1fa501 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -38,7 +38,12 @@ export function isNumeric(str: string) { } export async function updateLLOneBot() { let mirrorGithubList = ["https://mirror.ghproxy.com"]; - return true; + const latestVersion = await getRemoteVersion(); + if (latestVersion && latestVersion != "") { + const downloadUrl = "https://github.com/LLOneBot/LLOneBot/releases/download/v" + latestVersion + "/LLOneBot.zip"; + const realUrl = mirrorGithubList[0] + downloadUrl; + } + return false; } export async function getRemoteVersion() { let mirrorGithubList = ["https://521github.com"]; diff --git a/src/renderer/index.ts b/src/renderer/index.ts index af26786..8bbe09c 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -90,7 +90,7 @@ async function onSettingWindowCreated(view: Element) { ], 'ob11.messagePostFormat', config.ob11.messagePostFormat), ), SettingItem( - 'ffmpeg 路径,发送语音、视频需要,同时保证ffprobe和ffmpeg在一起', `配置可参考 官方文档 路径:${!isEmpty(config.ffmpeg) ? config.ffmpeg : '未指定'}`, + 'ffmpeg 路径,发送语音、视频需要,同时保证ffprobe和ffmpeg在一起', `配置可参考 官方文档 路径:${!isEmpty(config.ffmpeg) ? config.ffmpeg : '未指定'}`, SettingButton('选择', 'config-ffmpeg-select'), ), SettingItem( From 75c92a68bd2f0c568ce582b3586e583f2b46d508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Sun, 17 Mar 2024 14:48:19 +0800 Subject: [PATCH 3/7] feat:checkVersion --- package-lock.json | 13 +++++++++++++ package.json | 1 + src/common/channels.ts | 2 +- src/common/types.ts | 5 ++++- src/common/utils.ts | 13 +++++++++++++ src/main/main.ts | 8 ++++---- src/preload.ts | 8 ++++---- 7 files changed, 40 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index e2030ae..cda8ff2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "file-type": "^19.0.0", "fluent-ffmpeg": "^2.1.2", "level": "^8.0.1", + "node-stream-zip": "^1.15.0", "silk-wasm": "^3.2.3", "utf-8-validate": "^6.0.3", "uuid": "^9.0.1", @@ -4930,6 +4931,18 @@ "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, + "node_modules/node-stream-zip": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz", + "integrity": "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==", + "engines": { + "node": ">=0.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/antelle" + } + }, "node_modules/normalize-url": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", diff --git a/package.json b/package.json index 6628ec2..a3392fc 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "file-type": "^19.0.0", "fluent-ffmpeg": "^2.1.2", "level": "^8.0.1", + "node-stream-zip": "^1.15.0", "silk-wasm": "^3.2.3", "utf-8-validate": "^6.0.3", "uuid": "^9.0.1", diff --git a/src/common/channels.ts b/src/common/channels.ts index 5bb8ee6..c4d76b6 100644 --- a/src/common/channels.ts +++ b/src/common/channels.ts @@ -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_REMOTEVERSION = 'llonebot_remoteversion' +export const CHANNEL_CHECKVERSION = 'llonebot_checkversion' export const CHANNEL_SELECT_FILE = 'llonebot_select_ffmpeg' diff --git a/src/common/types.ts b/src/common/types.ts index f7a7a71..98e495c 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -9,7 +9,10 @@ export interface OB11Config { enableWsReverse?: boolean messagePostFormat?: 'array' | 'string' } - +export interface CheckVersion { + result: boolean, + version: string +} export interface Config { ob11: OB11Config token?: string diff --git a/src/common/utils.ts b/src/common/utils.ts index d1fa501..616f666 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -8,6 +8,7 @@ import * as crypto from 'crypto'; import { v4 as uuidv4 } from "uuid"; import ffmpeg from "fluent-ffmpeg" import * as https from "node:https"; +import { version } from "../version"; export const DATA_DIR = global.LiteLoader.plugins["LLOneBot"].path.data; @@ -36,6 +37,18 @@ function truncateString(obj: any, maxLength = 500) { export function isNumeric(str: string) { return /^\d+$/.test(str); } +// 判断是否为最新版本 +export async function checkVersion() { + const latestVersionText = await getRemoteVersion(); + const latestVersion = latestVersionText.split("."); + const currentVersion = version.split("."); + for (let k in [0, 1, 2]) { + if (latestVersion[k] > currentVersion[k]) { + return { result: true, version: latestVersion }; + } + } + return { result: true, version: version }; +} export async function updateLLOneBot() { let mirrorGithubList = ["https://mirror.ghproxy.com"]; const latestVersion = await getRemoteVersion(); diff --git a/src/main/main.ts b/src/main/main.ts index 4f9aef5..2142073 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -7,13 +7,13 @@ import { CHANNEL_ERROR, CHANNEL_GET_CONFIG, CHANNEL_LOG, - CHANNEL_REMOTEVERSION, + CHANNEL_CHECKVERSION, CHANNEL_SELECT_FILE, CHANNEL_SET_CONFIG, CHANNEL_UPDATE, } from "../common/channels"; import { ob11WebsocketServer } from "../onebot11/server/ws/WebsocketServer"; -import { checkFfmpeg, DATA_DIR, getConfigUtil, getRemoteVersion, log, updateLLOneBot } from "../common/utils"; +import { checkFfmpeg, checkVersion, DATA_DIR, getConfigUtil, getRemoteVersion, log, updateLLOneBot } from "../common/utils"; import { friendRequests, getFriend, @@ -46,8 +46,8 @@ let running = false; // 加载插件时触发 function onLoad() { log("llonebot main onLoad"); - ipcMain.handle(CHANNEL_REMOTEVERSION, async (event, arg) => { - return getRemoteVersion(); + ipcMain.handle(CHANNEL_CHECKVERSION, async (event, arg) => { + return checkVersion(); }); ipcMain.handle(CHANNEL_UPDATE, async (event, arg) => { return updateLLOneBot(); diff --git a/src/preload.ts b/src/preload.ts index f20f404..ed83aa0 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -1,11 +1,11 @@ // Electron 主进程 与 渲染进程 交互的桥梁 -import {Config, LLOneBotError} from "./common/types"; +import {CheckVersion, Config, LLOneBotError} from "./common/types"; import { CHANNEL_ERROR, CHANNEL_GET_CONFIG, CHANNEL_LOG, - CHANNEL_REMOTEVERSION, + CHANNEL_CHECKVERSION, CHANNEL_SELECT_FILE, CHANNEL_SET_CONFIG, CHANNEL_UPDATE, @@ -18,8 +18,8 @@ const llonebot = { log: (data: any) => { ipcRenderer.send(CHANNEL_LOG, data); }, - getRemoteVersion:async (): Promise => { - return ipcRenderer.invoke(CHANNEL_REMOTEVERSION); + checkVersion:async (): Promise => { + return ipcRenderer.invoke(CHANNEL_CHECKVERSION); }, updateLLOneBot:async (): Promise => { return ipcRenderer.invoke(CHANNEL_UPDATE); From 133719f96a0fe7941c450c133380de29c0389d74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Sun, 17 Mar 2024 14:50:36 +0800 Subject: [PATCH 4/7] fix: VersionCheck --- src/common/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/utils.ts b/src/common/utils.ts index 616f666..bb18582 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -44,7 +44,7 @@ export async function checkVersion() { const currentVersion = version.split("."); for (let k in [0, 1, 2]) { if (latestVersion[k] > currentVersion[k]) { - return { result: true, version: latestVersion }; + return { result: true, version: latestVersionText }; } } return { result: true, version: version }; From 8a440864196151c34d9d446da2b1c6b7d77fa600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Sun, 17 Mar 2024 15:22:10 +0800 Subject: [PATCH 5/7] fix: checkVersion --- src/common/utils.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/common/utils.ts b/src/common/utils.ts index bb18582..acc3f88 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -44,7 +44,7 @@ export async function checkVersion() { const currentVersion = version.split("."); for (let k in [0, 1, 2]) { if (latestVersion[k] > currentVersion[k]) { - return { result: true, version: latestVersionText }; + return { result: false, version: latestVersionText }; } } return { result: true, version: version }; @@ -64,7 +64,6 @@ export async function getRemoteVersion() { for (let i = 0; i < mirrorGithubList.length; i++) { let mirrorGithub = mirrorGithubList[i]; let tVersion = await getRemoteVersionByMirror(mirrorGithub); - console.log("tVersion", tVersion); if (tVersion && tVersion != "") { Version = tVersion; break; From d93193c7fd35ac4a88d5df6f209d6fe4955aa6e9 Mon Sep 17 00:00:00 2001 From: linyuchen Date: Sun, 17 Mar 2024 15:46:04 +0800 Subject: [PATCH 6/7] fix merge conflict --- src/main/main.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/main.ts b/src/main/main.ts index e6c8b25..406df68 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -13,7 +13,7 @@ import { CHANNEL_UPDATE, } from "../common/channels"; import {ob11WebsocketServer} from "../onebot11/server/ws/WebsocketServer"; -import {checkFfmpeg, DATA_DIR, getConfigUtil, log} from "../common/utils"; +import {checkFfmpeg, checkVersion, DATA_DIR, getConfigUtil, log, updateLLOneBot} from "../common/utils"; import { friendRequests, getFriend, @@ -202,12 +202,12 @@ function onLoad() { "doubt": boolean, "oldestUnreadSeq": string, "unreadCount": number - }>(ReceiveCmd.UNREAD_GROUP_NOTIFY, async (payload) => { + }>(ReceiveCmdS.UNREAD_GROUP_NOTIFY, async (payload) => { if (payload.unreadCount) { // log("开始获取群通知详情") let notify: GroupNotifies; try { - notify = await NTQQApi.getGroupNotifies(); + notify = await NTQQGroupApi.getGroupNotifies(); } catch (e) { // log("获取群通知详情失败", e); return @@ -260,7 +260,7 @@ function onLoad() { groupRequestEvent.group_id = parseInt(notify.group.groupCode); let requestQQ = "" try { - requestQQ = (await NTQQApi.getUserDetailInfo(notify.user1.uid)).uin; + requestQQ = (await NTQQUserApi.getUserDetailInfo(notify.user1.uid)).uin; } catch (e) { log("获取加群人QQ号失败", e) } @@ -275,7 +275,7 @@ function onLoad() { groupInviteEvent.group_id = parseInt(notify.group.groupCode); let user_id = (await getFriend(notify.user2.uid))?.uin if (!user_id) { - user_id = (await NTQQApi.getUserDetailInfo(notify.user2.uid))?.uin + user_id = (await NTQQUserApi.getUserDetailInfo(notify.user2.uid))?.uin } groupInviteEvent.user_id = parseInt(user_id); groupInviteEvent.sub_type = "invite"; @@ -292,14 +292,14 @@ function onLoad() { } }) - registerReceiveHook(ReceiveCmd.FRIEND_REQUEST, async (payload) => { + registerReceiveHook(ReceiveCmdS.FRIEND_REQUEST, async (payload) => { for (const req of payload.data.buddyReqs) { if (req.isUnread && !friendRequests[req.sourceId] && (parseInt(req.reqTime) > startTime / 1000)) { friendRequests[req.sourceId] = req; log("有新的好友请求", req); let friendRequestEvent = new OB11FriendRequestEvent(); try { - let requester = await NTQQApi.getUserDetailInfo(req.friendUid) + let requester = await NTQQUserApi.getUserDetailInfo(req.friendUid) friendRequestEvent.user_id = parseInt(requester.uin); } catch (e) { log("获取加好友者QQ号失败", e); @@ -318,7 +318,7 @@ function onLoad() { log("llonebot pid", process.pid) startTime = Date.now(); startReceiveHook().then(); - NTQQApi.getGroups(true).then() + NTQQGroupApi.getGroups(true).then() const config = getConfigUtil().getConfig() // 检查ffmpeg checkFfmpeg(config.ffmpeg).then(exist => { @@ -347,7 +347,7 @@ function onLoad() { const init = async () => { try { log("start get self info") - const _ = await NTQQApi.getSelfInfo(); + const _ = await NTQQUserApi.getSelfInfo(); log("get self info api result:", _); Object.assign(selfInfo, _); selfInfo.nick = selfInfo.uin; @@ -357,7 +357,7 @@ function onLoad() { log("self info", selfInfo); if (selfInfo.uin) { try { - const userInfo = (await NTQQApi.getUserDetailInfo(selfInfo.uid)); + const userInfo = (await NTQQUserApi.getUserDetailInfo(selfInfo.uid)); log("self info", userInfo); if (userInfo) { selfInfo.nick = userInfo.nick; From 5aecf45959598a008d974397e526806f3cb076df Mon Sep 17 00:00:00 2001 From: spring Date: Mon, 18 Mar 2024 11:32:56 +0800 Subject: [PATCH 7/7] add: support for file download --- src/onebot11/action/go-cqhttp/DownloadFile.ts | 103 ++++++++++++++++++ src/onebot11/action/index.ts | 2 + src/onebot11/action/types.ts | 1 + 3 files changed, 106 insertions(+) create mode 100644 src/onebot11/action/go-cqhttp/DownloadFile.ts diff --git a/src/onebot11/action/go-cqhttp/DownloadFile.ts b/src/onebot11/action/go-cqhttp/DownloadFile.ts new file mode 100644 index 0000000..6c457e1 --- /dev/null +++ b/src/onebot11/action/go-cqhttp/DownloadFile.ts @@ -0,0 +1,103 @@ +import BaseAction from "../BaseAction"; +import {ActionName} from "../types"; +import fs from "fs"; +import {join as joinPath} from "node:path"; +import {calculateFileMD5, DATA_DIR} from "../../../common/utils"; + +interface Payload { + thread_count?: number + url?: string + base64?: string + name?: string + headers?: string | string[] +} + +interface FileResponse { + file: string +} + +const localPath = joinPath(DATA_DIR, "file_cache") +export default class GoCQHTTPDownloadFile extends BaseAction { + actionName = ActionName.GoCQHTTP_DownloadFile + + constructor() { + super(); + if (!fs.existsSync(localPath)) { + fs.mkdirSync(localPath) + } + } + + protected async _handle(payload: Payload): Promise { + let name = payload.name || ""; + const isRandomName = !payload.name + + if (isRandomName) { + do { + name = this.generateRandomString(10); + // 使用循环防止极低概率的情况下随机出已有的文件, 导致覆盖 + } while (fs.existsSync(joinPath(localPath, name))); + } + + const filePath = joinPath(localPath, name); + + if (payload.base64) { + fs.writeFileSync(filePath, payload.base64, 'base64') + } else if (payload.url) { + const headers = this.getHeaders(payload.headers); + + const result = await fetch(payload.url, {headers}) + if (! result.ok) throw new Error(`下载文件失败: ${result.statusText}`) + + const blob = await result.blob(); + let buffer = await blob.arrayBuffer(); + fs.writeFileSync(filePath, Buffer.from(buffer), 'binary'); + } else { + throw new Error("不存在任何文件, 无法下载") + } + if (fs.existsSync(filePath)) { + + if (isRandomName) { + // 默认实现要名称未填写时文件名为文件 md5 + const md5 = await calculateFileMD5(filePath); + const newPath = joinPath(localPath, md5); + fs.renameSync(filePath, newPath); + return { file: newPath } + } + return { file: filePath } + } else { + throw new Error("文件写入失败, 检查权限") + } + } + + generateRandomString(length: number): string { + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + let randomString = ''; + for (let i = 0; i < length; i++) { + const randomIndex = Math.floor(Math.random() * characters.length); + randomString += characters.charAt(randomIndex); + } + return randomString; + } + + getHeaders(headersIn?: string | string[]): any { + const headers = {}; + if (typeof headersIn == 'string') { + headersIn = headersIn.split('[\\r\\n]'); + } + if (Array.isArray(headersIn)) { + for (const headerItem of headersIn) { + const spilt = headerItem.indexOf('='); + if (spilt < 0) { + headers[headerItem] = ""; + } else { + const key = headerItem.substring(0, spilt); + headers[key] = headerItem.substring(0, spilt + 1); + } + } + } + if (!headers['Content-Type']) { + headers['Content-Type'] = 'application/octet-stream'; + } + return headers; + } +} \ No newline at end of file diff --git a/src/onebot11/action/index.ts b/src/onebot11/action/index.ts index af557be..def74d6 100644 --- a/src/onebot11/action/index.ts +++ b/src/onebot11/action/index.ts @@ -36,6 +36,7 @@ import GoCQHTTPUploadGroupFile from "./go-cqhttp/UploadGroupFile"; import {GetConfigAction, SetConfigAction} from "./llonebot/Config"; import GetGroupAddRequest from "./llonebot/GetGroupAddRequest"; import SetQQAvatar from './llonebot/SetQQAvatar' +import GoCQHTTPDownloadFile from "./go-cqhttp/DownloadFile"; export const actionHandlers = [ new Debug(), @@ -72,6 +73,7 @@ export const actionHandlers = [ new GoCQHTTPSendGroupForwardMsg(), new GoCQHTTPSendPrivateForwardMsg(), new GoCQHTTPGetStrangerInfo(), + new GoCQHTTPDownloadFile(), new GetGuildList(), new GoCQHTTPMarkMsgAsRead(), new GoCQHTTPUploadGroupFile(), diff --git a/src/onebot11/action/types.ts b/src/onebot11/action/types.ts index 48db8fd..a00bf13 100644 --- a/src/onebot11/action/types.ts +++ b/src/onebot11/action/types.ts @@ -54,4 +54,5 @@ export enum ActionName { GetGuildList = "get_guild_list", GoCQHTTP_MarkMsgAsRead = "mark_msg_as_read", GoCQHTTP_UploadGroupFile = "upload_group_file", + GoCQHTTP_DownloadFile = "download_file", } \ No newline at end of file