diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 35efece..f5e159a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -9,10 +9,10 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: setup node - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: 18 diff --git a/.gitignore b/.gitignore index 0dc9ec5..a3d980a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,15 @@ -node_modules/ +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + package-lock.json -dist/ -out/ +yarn.lock +node_modules +dist +out + .idea/ .DS_Store diff --git a/.yarnrc.yml b/.yarnrc.yml new file mode 100644 index 0000000..3186f3f --- /dev/null +++ b/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/README.md b/README.md index 333f2a6..ca1690e 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # LLOneBot -LiteLoaderQQNT插件,使你的NTQQ支持OneBot11协议进行QQ机器人开发 +LiteLoaderQQNT 插件,实现 OneBot 11 协议,用以 QQ 机器人开发 > [!CAUTION]\ -> **请不要在 QQ 官方群聊和任何影响力较大的简中互联网平台(包括但不限于:B站,微博,知乎,抖音等)发布和讨论*任何*与本插件存在相关性的信息** +> **请不要在 QQ 官方群聊和任何影响力较大的简中互联网平台(包括但不限于: B站,微博,知乎,抖音等)发布和讨论*任何*与本插件存在相关性的信息** TG群: @@ -13,13 +13,13 @@ TG群: ## 设置界面 -图片名称 +设置界面 ## HTTP 调用示例 -![](doc/image/example.jpg) +HTTP调用示例 -## 支持的 api 和功能详情 +## 支持的 API 见 @@ -35,13 +35,8 @@ TG群: - [x] 群禁言事件上报 - [x] 优化加群成功事件上报 - [x] 清理缓存api -- [ ] 无头模式 - [ ] 框架对接文档 -## onebot11文档 - - - ## Stargazers over time [![Stargazers over time](https://starchart.cc/LLOneBot/LLOneBot.svg?variant=adaptive)](https://starchart.cc/LLOneBot/LLOneBot) diff --git a/electron.vite.config.ts b/electron.vite.config.ts index a469511..1259f35 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -1,6 +1,6 @@ import cp from 'vite-plugin-cp' -import './scripts/gen-version' import path from 'node:path' +import './scripts/gen-manifest' const external = [ 'silk-wasm', @@ -32,6 +32,7 @@ let config = { external, input: 'src/main/main.ts', }, + minify: true, }, resolve: { alias: { @@ -44,8 +45,8 @@ let config = { targets: [ ...external.map(genCpModule), { src: './manifest.json', dest: 'dist' }, - { src: './icon.jpg', dest: 'dist' }, - { src: './src/ntqqapi/native/crychic/crychic-win32-x64.node', dest: 'dist/main/' }, + { src: './icon.webp', dest: 'dist' }, + // { src: './src/ntqqapi/native/crychic/crychic-win32-x64.node', dest: 'dist/main/' }, // { src: './src/ntqqapi/native/moehook/MoeHoo-win32-x64.node', dest: 'dist/main/' }, // { src: './src/ntqqapi/native/moehook/MoeHoo-linux-x64.node', dest: 'dist/main/' }, ], diff --git a/icon.jpg b/icon.jpg deleted file mode 100644 index 67ca0da..0000000 Binary files a/icon.jpg and /dev/null differ diff --git a/icon.webp b/icon.webp new file mode 100644 index 0000000..5f07709 Binary files /dev/null and b/icon.webp differ diff --git a/manifest.json b/manifest.json index dbd0073..f6e8266 100644 --- a/manifest.json +++ b/manifest.json @@ -1,11 +1,11 @@ { "manifest_version": 4, "type": "extension", - "name": "LLOneBot v3.27.4", + "name": "LLOneBot", "slug": "LLOneBot", - "description": "使你的NTQQ支持OneBot11协议进行QQ机器人开发", + "description": "实现 OneBot 11 协议,帮助进行 QQ 机器人开发", "version": "3.27.4", - "icon": "./icon.jpg", + "icon": "./icon.webp", "authors": [ { "name": "linyuchen", diff --git a/package.json b/package.json index 25882bf..d4f13ae 100644 --- a/package.json +++ b/package.json @@ -31,16 +31,11 @@ "@types/fluent-ffmpeg": "^2.1.24", "@types/node": "^20.11.24", "@types/ws": "^8.5.12", - "@typescript-eslint/eslint-plugin": "^6.4.0", "electron": "^29.0.1", - "electron-vite": "^2.0.0", - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0 || ^16.0.0", - "eslint-plugin-promise": "^6.0.0", - "ts-node": "^10.9.2", - "typescript": "*", - "vite": "^5.1.4", + "electron-vite": "^2.3.0", + "typescript": "^5.5.4", + "vite": "^5.3.5", "vite-plugin-cp": "^4.0.8" - } + }, + "packageManager": "yarn@4.4.0" } diff --git a/scripts/gen-manifest.ts b/scripts/gen-manifest.ts new file mode 100644 index 0000000..a4b41a6 --- /dev/null +++ b/scripts/gen-manifest.ts @@ -0,0 +1,38 @@ +import { version } from '../src/version' +import { writeFileSync } from 'node:fs' + +const manifest = { + manifest_version: 4, + type: 'extension', + name: 'LLOneBot', + slug: 'LLOneBot', + description: '实现 OneBot 11 协议,用以 QQ 机器人开发', + version, + icon: './icon.webp', + authors: [ + { + name: 'linyuchen', + link: 'https://github.com/linyuchen' + } + ], + repository: { + repo: 'linyuchen/LiteLoaderQQNT-OneBotApi', + branch: 'main', + release: { + tag: 'latest', + name: 'LLOneBot.zip' + } + }, + platform: [ + 'win32', + 'linux', + 'darwin' + ], + injects: { + renderer: './renderer/index.js', + main: './main/main.cjs', + preload: './preload/preload.cjs' + } +} + +writeFileSync('manifest.json', JSON.stringify(manifest, null, 2)) \ No newline at end of file diff --git a/scripts/gen-version.ts b/scripts/gen-version.ts deleted file mode 100644 index b702dee..0000000 --- a/scripts/gen-version.ts +++ /dev/null @@ -1,22 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { version } from '../src/version' - -const manifestPath = path.join(__dirname, '../manifest.json') - -function readManifest(): any { - if (fs.existsSync(manifestPath)) { - return JSON.parse(fs.readFileSync(manifestPath, 'utf-8')) - } -} - -function writeManifest(manifest: any) { - fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)) -} - -const manifest = readManifest() -if (version !== manifest.version) { - manifest.version = version - manifest.name = `LLOneBot v${version}` - writeManifest(manifest) -} diff --git a/src/common/config.ts b/src/common/config.ts index 3d039a7..d9a1eea 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -53,7 +53,6 @@ export class ConfigUtil { reportSelfMessage: false, autoDeleteFile: false, autoDeleteFileSecond: 60, - enablePoke: false, musicSignUrl: '', } diff --git a/src/common/types.ts b/src/common/types.ts index 80f15e0..b4d722d 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -28,7 +28,6 @@ export interface Config { autoDeleteFile?: boolean autoDeleteFileSecond?: number ffmpeg?: string // ffmpeg路径 - enablePoke?: boolean musicSignUrl?: string ignoreBeforeLoginMsg?: boolean } diff --git a/src/common/utils/file.ts b/src/common/utils/file.ts index c400e80..2b2aafa 100644 --- a/src/common/utils/file.ts +++ b/src/common/utils/file.ts @@ -1,11 +1,9 @@ -import fs from 'fs' -import fsPromise from 'fs/promises' -import util from 'util' +import fs from 'node:fs' +import fsPromise from 'node:fs/promises' import path from 'node:path' import { log, TEMP_DIR } from './index' import { dbUtil } from '../db' import * as fileType from 'file-type' -import { net } from 'electron' import { randomUUID, createHash } from 'node:crypto' export function isGIF(path: string) { @@ -36,7 +34,6 @@ export function checkFileReceived(path: string, timeout: number = 3000): Promise } export async function file2base64(path: string) { - const readFile = util.promisify(fs.readFile) let result = { err: '', data: '', @@ -52,7 +49,7 @@ export async function file2base64(path: string) { result.err = e.toString() return result } - const data = await readFile(path) + const data = await fsPromise.readFile(path) // 转换为Base64编码 result.data = data.toString('base64') } catch (err) { @@ -90,7 +87,6 @@ export interface HttpDownloadOptions { headers?: Record | string } export async function httpDownload(options: string | HttpDownloadOptions): Promise { - let chunks: Buffer[] = [] let url: string let headers: Record = { 'User-Agent': @@ -108,12 +104,10 @@ export async function httpDownload(options: string | HttpDownloadOptions): Promi } } } - const fetchRes = await net.fetch(url, { headers }) + const fetchRes = await fetch(url, { headers }) if (!fetchRes.ok) throw new Error(`下载文件失败: ${fetchRes.statusText}`) - const blob = await fetchRes.blob() - let buffer = await blob.arrayBuffer() - return Buffer.from(buffer) + return Buffer.from(await fetchRes.arrayBuffer()) } type Uri2LocalRes = { @@ -152,7 +146,7 @@ export async function uri2local(uri: string, fileName: string = null): Promise|]/g, '_') res.fileName = fileName filePath = path.join(TEMP_DIR, randomUUID() + fileName) - fs.writeFileSync(filePath, buffer) + await fsPromise.writeFile(filePath, buffer) } catch (e: any) { res.errMsg = `${url}下载失败,` + e.toString() return res @@ -217,7 +211,7 @@ export async function uri2local(uri: string, fileName: string = null): Promise } } diff --git a/src/main/main.ts b/src/main/main.ts index aadd755..69ac2fe 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -48,7 +48,6 @@ import { dbUtil } from '../common/db' import { setConfig } from './setConfig' import { NTQQUserApi } from '../ntqqapi/api/user' import { NTQQGroupApi } from '../ntqqapi/api/group' -import { crychic } from '../ntqqapi/native/crychic' import { OB11FriendPokeEvent, OB11GroupPokeEvent } from '../onebot11/event/notice/OB11PokeEvent' import { checkNewVersion, upgradeLLOneBot } from '../common/utils/upgrade' import { log } from '../common/utils/log' @@ -209,26 +208,7 @@ function onLoad() { } async function startReceiveHook() { - startHook().then() - if (getConfigUtil().getConfig().enablePoke) { - if (qqPkgInfo.buildVersion > '23873') { - log(`当前版本${qqPkgInfo.buildVersion}不支持发送戳一戳模块`) - } - else { - crychic.loadNode() - crychic.registerPokeHandler((id, isGroup) => { - log(`收到戳一戳消息了!是否群聊:${isGroup},id:${id}`) - let pokeEvent: OB11FriendPokeEvent | OB11GroupPokeEvent - if (isGroup) { - pokeEvent = new OB11GroupPokeEvent(parseInt(id)) - } - else { - pokeEvent = new OB11FriendPokeEvent(parseInt(selfInfo.uin), parseInt(id)) - } - postOb11Event(pokeEvent) - }) - } - } + startHook() registerReceiveHook<{ msgList: Array }>([ReceiveCmdS.NEW_MSG, ReceiveCmdS.NEW_ACTIVE_MSG], async (payload) => { diff --git a/src/ntqqapi/hook.ts b/src/ntqqapi/hook.ts index 2a33c8d..4f88a32 100644 --- a/src/ntqqapi/hook.ts +++ b/src/ntqqapi/hook.ts @@ -1,4 +1,4 @@ -import { BrowserWindow } from 'electron' +import type { BrowserWindow } from 'electron' import { NTQQApiClass, NTQQApiMethod } from './ntcall' import { NTQQMsgApi, sendMessagePool } from './api/msg' import { CategoryFriend, ChatType, Group, GroupMember, GroupMemberRole, RawMessage, User } from './types' diff --git a/src/onebot11/action/msg/SendMsg.ts b/src/onebot11/action/msg/SendMsg.ts index 2c92a51..b5eb8b2 100644 --- a/src/onebot11/action/msg/SendMsg.ts +++ b/src/onebot11/action/msg/SendMsg.ts @@ -23,7 +23,7 @@ import { OB11MessageVideo, OB11PostSendMsg, } from '../../types' -import { NTQQMsgApi, Peer } from '../../../ntqqapi/api/msg' +import { NTQQMsgApi } from '../../../ntqqapi/api/msg' import { SendMsgElementConstructor } from '../../../ntqqapi/constructor' import BaseAction from '../BaseAction' import { ActionName, BaseCheckResult } from '../types' @@ -37,6 +37,7 @@ 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 { diff --git a/src/renderer/index.ts b/src/renderer/index.ts index 8efc0a0..f176c0c 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -4,6 +4,7 @@ import { SettingButton, SettingItem, SettingList, SettingSwitch, SettingSelect } // @ts-ignore import StyleRaw from './style.css?raw' import { iconSvg } from './icon' +import { version } from '../version' // 打开设置界面时触发 @@ -53,8 +54,8 @@ async function onSettingWindowCreated(view: Element) { '
', ``, ` -
-
`, +
+ `, SettingList([ SettingItem( '正在检查 LLOneBot 更新', @@ -186,11 +187,6 @@ async function onSettingWindowCreated(view: Element) { SettingItem('', null, SettingButton('保存', 'config-ob11-save', 'primary')), ]), SettingList([ - SettingItem( - '戳一戳消息, 暂时只支持Windows版的LLOneBot', - `重启QQ后生效,如果导致QQ崩溃请勿开启此项, 群戳一戳只能收到群号`, - SettingSwitch('enablePoke', config.enablePoke), - ), SettingItem( '使用 Base64 编码获取文件', '调用 /get_image、/get_record、/get_file 时,没有 url 时添加 Base64 字段', @@ -404,7 +400,7 @@ async function onSettingWindowCreated(view: Element) { const buttonDom = view.querySelector('#llonebot-update-button')! if (ResultVersion.version === '') { - titleDom.innerHTML = '检查更新失败' + titleDom.innerHTML = `当前版本为 v${version},检查更新失败` buttonDom.innerHTML = '点击重试' buttonDom.addEventListener('click', async () => { @@ -414,10 +410,10 @@ async function onSettingWindowCreated(view: Element) { return } if (!ResultVersion.result) { - titleDom.innerHTML = '当前已是最新版本 v' + ResultVersion.version + titleDom.innerHTML = '当前已是最新版本 v' + version buttonDom.innerHTML = '无需更新' } else { - titleDom.innerHTML = '已检测到最新版本 v' + ResultVersion.version + titleDom.innerHTML = `当前版本为 v${version},最新版本为 v${ResultVersion.version}` buttonDom.innerHTML = '点击更新' buttonDom.dataset.type = 'primary'