mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a01e4ca89f | ||
![]() |
c20362e9b6 | ||
![]() |
c90cfb99bd | ||
![]() |
7bcea14799 | ||
![]() |
b415c1a6d1 | ||
![]() |
452c72d280 | ||
![]() |
48350be625 | ||
![]() |
ab824fb219 | ||
![]() |
043d8a1861 | ||
![]() |
074ac15d0f | ||
![]() |
d36a28fa81 | ||
![]() |
ba12bc6c91 | ||
![]() |
87332778e5 | ||
![]() |
453feb8473 | ||
![]() |
8ff469974c |
@@ -17,5 +17,8 @@ charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.bat]
|
||||
charset = latin1
|
||||
|
||||
# Unfortunately, EditorConfig doesn't support space configuration inside import braces directly.
|
||||
# You'll need to rely on your linter/formatter like ESLint or Prettier for that.
|
||||
|
@@ -9,7 +9,7 @@ NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现
|
||||
## 猫猫技能
|
||||
- [x] **高性能**:1K+ 群聊数目、20 线程并行发送消息毫无压力
|
||||
- [x] **多种启动方式**:支持以无头、LiteLoader 插件、仅 QQ GUI 三种方式启动
|
||||
- [x] **多平台支持**: 支持Windows/Linux(可选Docker)/Android Termux覆盖全面
|
||||
- [x] **多平台支持**: 支持Windows/Linux(可选Docker)/Android Termux/MacOs覆盖全平台
|
||||
- [x] **安装简单**: 支持一键脚本/程序自动部署/镜像部署等多种覆盖范围
|
||||
- [x] **低占用**:无头模式占用资源极低,适合在服务器上运行
|
||||
- [x] **超多接口**:实现大部分 OneBot 和 go-cqhttp 接口,超多扩展 API
|
||||
|
BIN
launcher/NapCatWinBootHook.dll
Normal file
BIN
launcher/NapCatWinBootHook.dll
Normal file
Binary file not shown.
BIN
launcher/NapCatWinBootMain.exe
Normal file
BIN
launcher/NapCatWinBootMain.exe
Normal file
Binary file not shown.
38
launcher/launcher-win10.bat
Normal file
38
launcher/launcher-win10.bat
Normal file
@@ -0,0 +1,38 @@
|
||||
@echo off
|
||||
chcp 65001
|
||||
net session >nul 2>&1
|
||||
if %errorLevel% == 0 (
|
||||
echo Administrator mode detected.
|
||||
) else (
|
||||
echo Please run this script in administrator mode.
|
||||
powershell -Command "Start-Process 'cmd.exe' -ArgumentList '/c cd /d \"%cd%\" && \"%~f0\"' -Verb runAs"
|
||||
exit
|
||||
)
|
||||
|
||||
set NAPCAT_PATCH_PATH=%cd%\patchNapCat.js
|
||||
set NAPCAT_LOAD_PATH=%cd%\loadNapCat.js
|
||||
set NAPCAT_INJECT_PATH=%cd%\NapCatWinBootHook.dll
|
||||
set NAPCAT_LAUNCHER_PATH=%cd%\NapCatWinBootMain.exe
|
||||
set NAPCAT_MAIN_PATH=%cd%\napcat.mjs
|
||||
:loop_read
|
||||
for /f "tokens=2*" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" /v "UninstallString"') do (
|
||||
set RetString=%%b
|
||||
goto :napcat_boot
|
||||
)
|
||||
|
||||
:napcat_boot
|
||||
for %%a in ("%RetString%") do (
|
||||
set "pathWithoutUninstall=%%~dpa"
|
||||
)
|
||||
|
||||
SET QQPath=%pathWithoutUninstall%QQ.exe
|
||||
|
||||
if not exist "%QQpath%" (
|
||||
echo provided QQ path is invalid: %QQpath%
|
||||
pause
|
||||
exit /b
|
||||
)
|
||||
set NAPCAT_MAIN_PATH=%NAPCAT_MAIN_PATH:\=/%
|
||||
echo (async () =^> {await import("file:///%NAPCAT_MAIN_PATH%")})() > %NAPCAT_LOAD_PATH%
|
||||
|
||||
"%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%"
|
39
launcher/launcher.bat
Normal file
39
launcher/launcher.bat
Normal file
@@ -0,0 +1,39 @@
|
||||
@echo off
|
||||
chcp 65001
|
||||
net session >nul 2>&1
|
||||
if %errorLevel% == 0 (
|
||||
echo Administrator mode detected.
|
||||
) else (
|
||||
echo Please run this script in administrator mode.
|
||||
powershell -Command "Start-Process 'wt.exe' -ArgumentList 'cmd /c cd /d \"%cd%\" && \"%~f0\"' -Verb runAs"
|
||||
exit
|
||||
)
|
||||
|
||||
set NAPCAT_PATCH_PATH=%cd%\patchNapCat.js
|
||||
set NAPCAT_LOAD_PATH=%cd%\loadNapCat.js
|
||||
set NAPCAT_INJECT_PATH=%cd%\NapCatWinBootHook.dll
|
||||
set NAPCAT_LAUNCHER_PATH=%cd%\NapCatWinBootMain.exe
|
||||
set NAPCAT_MAIN_PATH=%cd%\napcat.mjs
|
||||
:loop_read
|
||||
for /f "tokens=2*" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" /v "UninstallString"') do (
|
||||
set RetString=%%b
|
||||
goto :napcat_boot
|
||||
)
|
||||
|
||||
:napcat_boot
|
||||
for %%a in ("%RetString%") do (
|
||||
set "pathWithoutUninstall=%%~dpa"
|
||||
)
|
||||
|
||||
SET QQPath=%pathWithoutUninstall%QQ.exe
|
||||
|
||||
if not exist "%QQpath%" (
|
||||
echo provided QQ path is invalid: %QQpath%
|
||||
pause
|
||||
exit /b
|
||||
)
|
||||
|
||||
set NAPCAT_MAIN_PATH=%NAPCAT_MAIN_PATH:\=/%
|
||||
echo (async () =^> {await import("file:///%NAPCAT_MAIN_PATH%")})() > %NAPCAT_LOAD_PATH%
|
||||
|
||||
"%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%"
|
5
launcher/loadNapCat.js
Normal file
5
launcher/loadNapCat.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const path = require('path');
|
||||
const CurrentPath = path.dirname(__filename);
|
||||
(async () => {
|
||||
await import("file://" + path.join(CurrentPath, './napcat/napcat.mjs'));
|
||||
})();
|
1
launcher/patchNapCat.js
Normal file
1
launcher/patchNapCat.js
Normal file
@@ -0,0 +1 @@
|
||||
require('./launcher.node').load('external_index', module);
|
@@ -4,7 +4,7 @@
|
||||
"name": "NapCatQQ",
|
||||
"slug": "NapCat.Framework",
|
||||
"description": "高性能的 OneBot 11 协议实现",
|
||||
"version": "2.2.45",
|
||||
"version": "2.3.0",
|
||||
"icon": "./logo.png",
|
||||
"authors": [
|
||||
{
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "2.2.45",
|
||||
"version": "2.3.0",
|
||||
"scripts": {
|
||||
"build:framework": "vite build --mode framework",
|
||||
"build:shell": "vite build --mode shell",
|
||||
|
@@ -1 +1 @@
|
||||
export const napCatVersion = '2.2.45';
|
||||
export const napCatVersion = '2.3.0';
|
||||
|
@@ -247,7 +247,7 @@ export class NTQQGroupApi {
|
||||
'NodeIKernelGroupListener/onMemberInfoChange',
|
||||
1,
|
||||
forced ? 5000 : 250,
|
||||
(params) => params === GroupCode,
|
||||
(params, _, members) => params === GroupCode && members.size > 0,
|
||||
);
|
||||
const retData = await (
|
||||
this.core.eventWrapper
|
||||
|
@@ -131,20 +131,53 @@ export class NTQQWebApi {
|
||||
// return await res.json();
|
||||
// }
|
||||
|
||||
async setGroupNotice(GroupCode: string, Content: string) {
|
||||
async setGroupNotice(
|
||||
GroupCode: string,
|
||||
Content: string,
|
||||
pinned: number = 0,
|
||||
type: number = 1,
|
||||
is_show_edit_card: number = 1,
|
||||
tip_window_type: number = 1,
|
||||
confirm_required: number = 1,
|
||||
picId: string = '',
|
||||
imgWidth: number = 540,
|
||||
imgHeight: number = 300,
|
||||
) {
|
||||
interface SetNoticeRetSuccess {
|
||||
ec: number;
|
||||
em: string;
|
||||
id: number;
|
||||
ltsm: number;
|
||||
new_fid: string;
|
||||
read_only: number;
|
||||
role: number;
|
||||
srv_code: number;
|
||||
}
|
||||
|
||||
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
|
||||
let ret: any = undefined;
|
||||
|
||||
try {
|
||||
ret = await RequestUtil.HttpGetJson<any>(
|
||||
`https://web.qun.qq.com/cgi-bin/announce/add_qun_notice${new URLSearchParams({
|
||||
let settings = JSON.stringify({
|
||||
is_show_edit_card: is_show_edit_card,
|
||||
tip_window_type: tip_window_type,
|
||||
confirm_required: confirm_required
|
||||
});
|
||||
const externalParam = {
|
||||
pic: picId,
|
||||
imgWidth: imgWidth.toString(),
|
||||
imgHeight: imgHeight.toString(),
|
||||
};
|
||||
let ret: SetNoticeRetSuccess = await RequestUtil.HttpGetJson<SetNoticeRetSuccess>(
|
||||
`https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?${new URLSearchParams({
|
||||
bkn: this.getBknFromCookie(cookieObject),
|
||||
qid: GroupCode,
|
||||
text: Content,
|
||||
pinned: '0',
|
||||
type: '1',
|
||||
settings: '{"is_show_edit_card":1,"tip_window_type":1,"confirm_required":1}',
|
||||
pinned: pinned.toString(),
|
||||
type: type.toString(),
|
||||
settings: settings,
|
||||
...(picId === '' ? {} : externalParam)
|
||||
}).toString()}`,
|
||||
'GET',
|
||||
'POST',
|
||||
'',
|
||||
{ 'Cookie': this.cookieToString(cookieObject) }
|
||||
);
|
||||
|
@@ -11,7 +11,10 @@ const SchemaData = {
|
||||
content: { type: 'string' },
|
||||
image: { type: 'string' },
|
||||
pinned: { type: ['number', 'string'] },
|
||||
type: { type: ['number', 'string'] },
|
||||
confirm_required: { type: ['number', 'string'] },
|
||||
is_show_edit_card: { type: ['number', 'string'] },
|
||||
tip_window_type: { type: ['number', 'string'] },
|
||||
},
|
||||
required: ['group_id', 'content'],
|
||||
} as const satisfies JSONSchema;
|
||||
@@ -22,6 +25,7 @@ export class SendGroupNotice extends BaseAction<Payload, null> {
|
||||
actionName = ActionName.GoCQHTTP_SendGroupNotice;
|
||||
|
||||
async _handle(payload: Payload) {
|
||||
|
||||
let UploadImage: { id: string, width: number, height: number } | undefined = undefined;
|
||||
if (payload.image) {
|
||||
//公告图逻辑
|
||||
@@ -47,12 +51,28 @@ export class SendGroupNotice extends BaseAction<Payload, null> {
|
||||
}
|
||||
UploadImage = ImageUploadResult.picInfo;
|
||||
}
|
||||
const noticePinned = +(payload.pinned ?? 0);
|
||||
const noticeConfirmRequired = +(payload.confirm_required ?? 0);
|
||||
const publishGroupBulletinResult = await this.core.apis.GroupApi.publishGroupBulletin(payload.group_id.toString(), payload.content, UploadImage, noticePinned, noticeConfirmRequired);
|
||||
|
||||
if (publishGroupBulletinResult.result != 0) {
|
||||
throw `设置群公告失败,错误信息:${publishGroupBulletinResult.errMsg}`;
|
||||
const noticeType = +(payload.type ?? 1);
|
||||
const noticePinned = +(payload.pinned ?? 0);
|
||||
|
||||
const noticeShowEditCard = +(payload.is_show_edit_card ?? 0);
|
||||
const noticeTipWindowType = +(payload.tip_window_type ?? 0);
|
||||
const noticeConfirmRequired = +(payload.confirm_required ?? 1);
|
||||
//const publishGroupBulletinResult = await this.core.apis.GroupApi.publishGroupBulletin(payload.group_id.toString(), payload.content, UploadImage, noticePinned, noticeConfirmRequired);
|
||||
const publishGroupBulletinResult = await this.core.apis.WebApi.setGroupNotice(
|
||||
payload.group_id.toString(),
|
||||
payload.content,
|
||||
noticePinned,
|
||||
noticeType,
|
||||
noticeShowEditCard,
|
||||
noticeTipWindowType,
|
||||
noticeConfirmRequired,
|
||||
UploadImage?.id,
|
||||
UploadImage?.width,
|
||||
UploadImage?.height
|
||||
);
|
||||
if (!publishGroupBulletinResult || publishGroupBulletinResult.ec != 0) {
|
||||
throw `设置群公告失败,错误信息:${publishGroupBulletinResult?.em}`;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ async function onSettingWindowCreated(view: Element) {
|
||||
SettingItem(
|
||||
'<span id="napcat-update-title">Napcat</span>',
|
||||
undefined,
|
||||
SettingButton('V2.2.45', 'napcat-update-button', 'secondary'),
|
||||
SettingButton('V2.3.0', 'napcat-update-button', 'secondary'),
|
||||
),
|
||||
]),
|
||||
SettingList([
|
||||
|
@@ -164,7 +164,7 @@ async function onSettingWindowCreated(view) {
|
||||
SettingItem(
|
||||
'<span id="napcat-update-title">Napcat</span>',
|
||||
void 0,
|
||||
SettingButton("V2.2.45", "napcat-update-button", "secondary")
|
||||
SettingButton("V2.3.0", "napcat-update-button", "secondary")
|
||||
)
|
||||
]),
|
||||
SettingList([
|
||||
|
@@ -11,7 +11,6 @@ const nodeModules = [...builtinModules, builtinModules.map(m => `node:${m}`)].fl
|
||||
function genCpModule(module: string) {
|
||||
return { src: `./node_modules/${module}`, dest: `dist/node_modules/${module}`, flatten: false };
|
||||
}
|
||||
|
||||
let startScripts: string[] | undefined = undefined;
|
||||
if (process.env.NAPCAT_BUILDSYS == 'linux') {
|
||||
if (process.env.NAPCAT_BUILDARCH == 'x64') {
|
||||
@@ -82,6 +81,7 @@ const ShellBaseConfigPlugin: PluginOption[] = [
|
||||
{ src: './src/core/external/napcat.json', dest: 'dist/config/' },
|
||||
{ src: './src/onebot/config/onebot11.json', dest: 'dist/config/' },
|
||||
{ src: './package.json', dest: 'dist' },
|
||||
{ src: './launcher/', dest: 'dist', flatten: true },
|
||||
// { src: './README.md', dest: 'dist' },
|
||||
// { src: './logo.png', dest: 'dist/logs' },
|
||||
...(startScripts.map((startScript) => {
|
||||
|
Reference in New Issue
Block a user