mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
35 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
01d11d6213 | ||
![]() |
74a316e758 | ||
![]() |
d20c5185a4 | ||
![]() |
da965e7b39 | ||
![]() |
152be29739 | ||
![]() |
e521740a44 | ||
![]() |
ee047e8bc1 | ||
![]() |
5eaa9ca347 | ||
![]() |
40f79ee816 | ||
![]() |
f0dcef7981 | ||
![]() |
3c09ff13d0 | ||
![]() |
7158f25f37 | ||
![]() |
54f805b6e4 | ||
![]() |
70c4651fbf | ||
![]() |
962d3c064f | ||
![]() |
c6a459a111 | ||
![]() |
b0242ccb62 | ||
![]() |
53f5277b08 | ||
![]() |
90b54435b5 | ||
![]() |
12a1681b42 | ||
![]() |
4277cb3f3c | ||
![]() |
8353d53589 | ||
![]() |
9e94d98cfb | ||
![]() |
b6ec1aaa9b | ||
![]() |
e7e8763f1c | ||
![]() |
515c1af676 | ||
![]() |
6fa7a973ba | ||
![]() |
3e63f509bc | ||
![]() |
b3b02e781a | ||
![]() |
6d83921e20 | ||
![]() |
30bd372d45 | ||
![]() |
63254b7e55 | ||
![]() |
f4c08d93f4 | ||
![]() |
6ca1ac21e4 | ||
![]() |
381ee1c30e |
210
LICENSE
210
LICENSE
@@ -1,201 +1,19 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
Limited Redistribution License for NapCat
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
Copyright © 2024 Mlikiowa
|
||||
|
||||
1. Definitions.
|
||||
1. Usage and Reproduction:
|
||||
- Unauthorized use, reproduction, modification, or distribution of this code is prohibited without explicit permission from the main author of the NapCat repository.
|
||||
|
||||
2. Redistribution:
|
||||
- Redistribution of this code is permitted, provided that the full text of this license is included, and the source and copyright information is clearly stated.
|
||||
- Minor modifications and extensions are allowed for redistribution purposes, but the modified code must not be publicly released.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
3. Non-Commercial Use:
|
||||
- This code is not to be used for any commercial purposes.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
4. Additional Permissions:
|
||||
- Any rights not explicitly addressed in this license must be requested from and granted by the main author of the NapCat repository.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
5. Disclaimer:
|
||||
- This code is provided "as is," without any express or implied warranties, including but not limited to the implied warranties of merchantability and fitness for a particular purpose. In no event shall the author be liable for any damages or other liability arising from, out of, or in connection with the use or distribution of this code.
|
||||
|
@@ -45,12 +45,8 @@ NapCatQQ 是现代化的基于 NTQQ 的 Bot 协议端实现
|
||||
|
||||
---
|
||||
|
||||
## 延缓Native模块与NapCat对新版QQ适配
|
||||
为未来持续与高效的使用Native模块 模块代码转为完全非Git仓库的本地保存源码 并进行相关重构
|
||||
|
||||
同时为了保证稳定 NapCat 本体通常会在3 Week+的周期进行新版本适配
|
||||
|
||||
因此此时推荐使用release指定版本
|
||||
## 特殊感谢
|
||||
[LLOneBot](https://github.com/LLOneBot/LLOneBot) 相关的开发曾参与本项目
|
||||
|
||||
## 开源附加
|
||||
|
||||
|
BIN
external/LiteLoaderWrapper.zip
vendored
BIN
external/LiteLoaderWrapper.zip
vendored
Binary file not shown.
@@ -4,7 +4,7 @@
|
||||
"name": "NapCatQQ",
|
||||
"slug": "NapCat.Framework",
|
||||
"description": "高性能的 OneBot 11 协议实现",
|
||||
"version": "4.1.12",
|
||||
"version": "4.1.19",
|
||||
"icon": "./logo.png",
|
||||
"authors": [
|
||||
{
|
||||
|
@@ -74,6 +74,26 @@ export class QQLoginManager {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public async checkQQLoginStatusWithQrcode(): Promise<{ qrcodeurl: string, isLogin: string } | undefined> {
|
||||
try {
|
||||
const QQLoginResponse = await fetch(`${this.apiPrefix}/QQLogin/CheckLoginStatus`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + this.retCredential,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
if (QQLoginResponse.status == 200) {
|
||||
const QQLoginResponseJson = await QQLoginResponse.json();
|
||||
if (QQLoginResponseJson.code == 0) {
|
||||
return QQLoginResponseJson.data;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking QQ login status:', error);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public async checkWebUiLogined(): Promise<boolean> {
|
||||
try {
|
||||
|
@@ -2,28 +2,14 @@
|
||||
<div class="login-container">
|
||||
<h2 class="sotheby-font">QQ Login</h2>
|
||||
<div class="login-methods">
|
||||
<t-button
|
||||
id="quick-login"
|
||||
class="login-method"
|
||||
:class="{ active: loginMethod === 'quick' }"
|
||||
@click="loginMethod = 'quick'"
|
||||
>Quick Login</t-button
|
||||
>
|
||||
<t-button
|
||||
id="qrcode-login"
|
||||
class="login-method"
|
||||
:class="{ active: loginMethod === 'qrcode' }"
|
||||
@click="loginMethod = 'qrcode'"
|
||||
>QR Code</t-button
|
||||
>
|
||||
<t-button id="quick-login" class="login-method" :class="{ active: loginMethod === 'quick' }"
|
||||
@click="loginMethod = 'quick'">Quick Login</t-button>
|
||||
<t-button id="qrcode-login" class="login-method" :class="{ active: loginMethod === 'qrcode' }"
|
||||
@click="loginMethod = 'qrcode'">QR Code</t-button>
|
||||
</div>
|
||||
<div v-show="loginMethod === 'quick'" id="quick-login-dropdown" class="login-form">
|
||||
<t-select
|
||||
id="quick-login-select"
|
||||
v-model="selectedAccount"
|
||||
placeholder="Select Account"
|
||||
@change="selectAccount"
|
||||
>
|
||||
<t-select id="quick-login-select" v-model="selectedAccount" placeholder="Select Account"
|
||||
@change="selectAccount">
|
||||
<t-option v-for="account in quickLoginList" :key="account" :value="account">{{ account }}</t-option>
|
||||
</t-select>
|
||||
</div>
|
||||
@@ -47,7 +33,7 @@ const selectedAccount = ref<string>('');
|
||||
const qrcodeCanvas = ref<HTMLCanvasElement | null>(null);
|
||||
const qqLoginManager = new QQLoginManager(localStorage.getItem('auth') || '');
|
||||
let heartBeatTimer: number | null = null;
|
||||
|
||||
let qrcodeUrl: string = '';
|
||||
const selectAccount = async (accountName: string): Promise<void> => {
|
||||
const { result, errMsg } = await qqLoginManager.setQuickLogin(accountName);
|
||||
if (result) {
|
||||
@@ -73,19 +59,26 @@ const generateQrCode = (data: string, canvas: HTMLCanvasElement | null): void =>
|
||||
};
|
||||
|
||||
const HeartBeat = async (): Promise<void> => {
|
||||
const isLogined = await qqLoginManager.checkQQLoginStatus();
|
||||
if (isLogined) {
|
||||
const isLogined = await qqLoginManager.checkQQLoginStatusWithQrcode();
|
||||
if (isLogined?.isLogin) {
|
||||
if (heartBeatTimer) {
|
||||
clearInterval(heartBeatTimer);
|
||||
}
|
||||
//判断是否已经调转
|
||||
if (router.currentRoute.value.path !== '/dashboard/basic-info') {
|
||||
return;
|
||||
}
|
||||
await router.push({ path: '/dashboard/basic-info' });
|
||||
} else if (isLogined?.qrcodeurl && qrcodeUrl !== isLogined.qrcodeurl) {
|
||||
qrcodeUrl = isLogined.qrcodeurl;
|
||||
generateQrCode(qrcodeUrl, qrcodeCanvas.value);
|
||||
}
|
||||
};
|
||||
|
||||
const InitPages = async (): Promise<void> => {
|
||||
quickLoginList.value = await qqLoginManager.getQQQuickLoginList();
|
||||
const qrcodeData = await qqLoginManager.getQQLoginQrcode();
|
||||
generateQrCode(qrcodeData, qrcodeCanvas.value);
|
||||
qrcodeUrl = await qqLoginManager.getQQLoginQrcode();
|
||||
generateQrCode(qrcodeUrl, qrcodeCanvas.value);
|
||||
heartBeatTimer = window.setInterval(HeartBeat, 3000);
|
||||
};
|
||||
|
||||
|
@@ -11,6 +11,9 @@
|
||||
<t-form-item label="启用本地文件到URL" name="enableLocalFile2Url" class="form-item">
|
||||
<t-switch v-model="otherConfig.enableLocalFile2Url" />
|
||||
</t-form-item>
|
||||
<t-form-item label="启用上报解析合并消息" name="parseMultMsg" class="form-item">
|
||||
<t-switch v-model="otherConfig.parseMultMsg" />
|
||||
</t-form-item>
|
||||
</t-form>
|
||||
<div class="button-container">
|
||||
<t-button @click="saveConfig">保存</t-button>
|
||||
@@ -28,6 +31,7 @@ import { QQLoginManager } from '@/backend/shell';
|
||||
const otherConfig = ref<Partial<OneBotConfig>>({
|
||||
musicSignUrl: '',
|
||||
enableLocalFile2Url: false,
|
||||
parseMultMsg: true
|
||||
});
|
||||
|
||||
const getOB11Config = async (): Promise<OneBotConfig | undefined> => {
|
||||
@@ -56,6 +60,7 @@ const loadConfig = async () => {
|
||||
if (userConfig) {
|
||||
otherConfig.value.musicSignUrl = userConfig.musicSignUrl;
|
||||
otherConfig.value.enableLocalFile2Url = userConfig.enableLocalFile2Url;
|
||||
otherConfig.value.parseMultMsg = userConfig.parseMultMsg;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading config:', error);
|
||||
@@ -68,6 +73,7 @@ const saveConfig = async () => {
|
||||
if (userConfig) {
|
||||
userConfig.musicSignUrl = otherConfig.value.musicSignUrl || '';
|
||||
userConfig.enableLocalFile2Url = otherConfig.value.enableLocalFile2Url ?? false;
|
||||
userConfig.parseMultMsg = otherConfig.value.parseMultMsg ?? true;
|
||||
const success = await setOB11Config(userConfig);
|
||||
if (success) {
|
||||
MessagePlugin.success('配置保存成功');
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "4.1.12",
|
||||
"version": "4.1.19",
|
||||
"scripts": {
|
||||
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",
|
||||
"build:shell": "npm run build:webui && vite build --mode shell || exit 1",
|
||||
|
@@ -19,14 +19,6 @@ type Uri2LocalRes = {
|
||||
path: string
|
||||
}
|
||||
|
||||
export function isGIF(path: string) {
|
||||
const buffer = Buffer.alloc(4);
|
||||
const fd = fs.openSync(path, 'r');
|
||||
fs.readSync(fd, buffer, 0, 4, 0);
|
||||
fs.closeSync(fd);
|
||||
return buffer.toString() === 'GIF8';
|
||||
}
|
||||
|
||||
// 定义一个异步函数来检查文件是否存在
|
||||
export function checkFileExist(path: string, timeout: number = 3000): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@@ -1 +1 @@
|
||||
export const napCatVersion = '4.1.12';
|
||||
export const napCatVersion = '4.1.19';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { MsfChangeReasonType, MsfStatusType } from "../types/adapter";
|
||||
import { MsfChangeReasonType, MsfStatusType } from "@/core/types/adapter";
|
||||
|
||||
export class NodeIDependsAdapter {
|
||||
onMSFStatusChange(statusType: MsfStatusType, changeReasonType: MsfChangeReasonType) {
|
||||
|
@@ -20,13 +20,14 @@ import { InstanceContext, NapCatCore, SearchResultItem } from '@/core';
|
||||
import * as fileType from 'file-type';
|
||||
import imageSize from 'image-size';
|
||||
import { ISizeCalculationResult } from 'image-size/dist/types/interface';
|
||||
import { RkeyManager } from '../helper/rkey';
|
||||
import { calculateFileMD5, isGIF } from '@/common/file';
|
||||
import { RkeyManager } from '@/core/helper/rkey';
|
||||
import { calculateFileMD5 } from '@/common/file';
|
||||
import pathLib from 'node:path';
|
||||
import { defaultVideoThumbB64, getVideoInfo } from '@/common/video';
|
||||
import ffmpeg from 'fluent-ffmpeg';
|
||||
import { encodeSilk } from '@/common/audio';
|
||||
import { MessageContext } from '@/onebot/api';
|
||||
import { getFileTypeForSendType } from '../helper/msg';
|
||||
|
||||
export class NTQQFileApi {
|
||||
context: InstanceContext;
|
||||
@@ -130,7 +131,7 @@ export class NTQQFileApi {
|
||||
fileName: fileName,
|
||||
sourcePath: path,
|
||||
original: true,
|
||||
picType: isGIF(picPath) ? PicType.NEWPIC_GIF : PicType.NEWPIC_JPEG,
|
||||
picType: await getFileTypeForSendType(picPath),
|
||||
picSubType: subType,
|
||||
fileUuid: '',
|
||||
fileSubId: '',
|
||||
|
@@ -18,30 +18,19 @@ export class NTQQUserApi {
|
||||
async getStatusByUid(uid: string) {
|
||||
return this.context.session.getProfileService().getStatus(uid);
|
||||
}
|
||||
async getProfileLike(uid: string, start: number, count: number) {
|
||||
// 默认获取自己的 type = 2 获取别人 type = 1
|
||||
async getProfileLike(uid: string, start: number, count: number, type: number = 2) {
|
||||
return this.context.session.getProfileLikeService().getBuddyProfileLike({
|
||||
friendUids: [uid],
|
||||
basic: 1,
|
||||
vote: 1,
|
||||
favorite: 0,
|
||||
userProfile: 1,
|
||||
type: 2,
|
||||
type: type,
|
||||
start: start,
|
||||
limit: count,
|
||||
});
|
||||
}
|
||||
async fetchOtherProfileLike(uid: string) {
|
||||
return this.context.session.getProfileLikeService().getBuddyProfileLike({
|
||||
friendUids: [uid],
|
||||
basic: 1,
|
||||
vote: 1,
|
||||
favorite: 0,
|
||||
userProfile: 0,
|
||||
type: 1,
|
||||
start: 0,
|
||||
limit: 20,
|
||||
});
|
||||
}
|
||||
async setLongNick(longNick: string) {
|
||||
return this.context.session.getProfileService().setLongNick(longNick);
|
||||
}
|
||||
|
12
src/core/external/appid.json
vendored
12
src/core/external/appid.json
vendored
@@ -86,5 +86,17 @@
|
||||
"6.9.59-29456": {
|
||||
"appid": 537249961,
|
||||
"qua": "V1_MAC_NQ_6.9.59_29456_GW_B"
|
||||
},
|
||||
"9.9.16-29927": {
|
||||
"appid": 537255812,
|
||||
"qua": "V1_WIN_NQ_9.9.16_29927_GW_B"
|
||||
},
|
||||
"3.2.13-29927": {
|
||||
"appid": 537255847,
|
||||
"qua": "V1_LNX_NQ_3.2.13_29927_GW_B"
|
||||
},
|
||||
"6.9.61-29927": {
|
||||
"appid": 537255836,
|
||||
"qua": "V1_MAC_NQ_6.9.61_29927_GW_B"
|
||||
}
|
||||
}
|
||||
|
20
src/core/external/offset.json
vendored
20
src/core/external/offset.json
vendored
@@ -82,5 +82,25 @@
|
||||
"6.9.59-29456-arm64": {
|
||||
"send": "4005FE8",
|
||||
"recv": "4008800"
|
||||
},
|
||||
"9.9.16-29927-x64": {
|
||||
"send": "3869C50",
|
||||
"recv": "386E084"
|
||||
},
|
||||
"3.2.13-29927-x64": {
|
||||
"send": "A1913A0",
|
||||
"recv": "A194CA0"
|
||||
},
|
||||
"3.2.13-29927-arm64": {
|
||||
"send": "6F1C7E0",
|
||||
"recv": "6F20018"
|
||||
},
|
||||
"6.9.61-29927-x64": {
|
||||
"send": "44FCC60",
|
||||
"recv": "44FF4CC"
|
||||
},
|
||||
"6.9.61-29927-arm64": {
|
||||
"send": "4038740",
|
||||
"recv": "403AF58"
|
||||
}
|
||||
}
|
||||
|
14
src/core/helper/msg.ts
Normal file
14
src/core/helper/msg.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import * as fileType from 'file-type';
|
||||
import { PicType } from '../types';
|
||||
export async function getFileTypeForSendType(picPath: string): Promise<PicType> {
|
||||
const fileTypeResult = (await fileType.fileTypeFromFile(picPath))?.ext ?? 'jpg';
|
||||
const picTypeMap: { [key: string]: PicType } = {
|
||||
'webp': PicType.NEWPIC_WEBP,
|
||||
'gif': PicType.NEWPIC_GIF,
|
||||
'png': PicType.NEWPIC_APNG,
|
||||
'jpg': PicType.NEWPIC_JPEG,
|
||||
'jpeg': PicType.NEWPIC_JPEG,
|
||||
'bmp': PicType.NEWPIC_BMP,
|
||||
};
|
||||
return picTypeMap[fileTypeResult] ?? PicType.NEWPIC_JPEG;
|
||||
}
|
@@ -14,6 +14,8 @@ import {
|
||||
GroupFileExtra
|
||||
} from "@/core/packet/transformer/proto";
|
||||
import {
|
||||
BaseEmojiType,
|
||||
FaceType,
|
||||
NTMsgAtType,
|
||||
PicType,
|
||||
SendArkElement,
|
||||
@@ -162,7 +164,7 @@ export class PacketMsgFaceElement extends IPacketMsgElement<SendFaceElement> {
|
||||
constructor(element: SendFaceElement) {
|
||||
super(element);
|
||||
this.faceId = element.faceElement.faceIndex;
|
||||
this.isLargeFace = element.faceElement.faceType === 3;
|
||||
this.isLargeFace = element.faceElement.faceType === FaceType.AniSticke;
|
||||
}
|
||||
|
||||
buildElement(): NapProtoEncodeStructType<typeof Elem>[] {
|
||||
|
17
src/core/services/NodeIKernelBaseEmojiService.ts
Normal file
17
src/core/services/NodeIKernelBaseEmojiService.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { DownloadBaseEmojiByIdReq, DownloadBaseEmojiByUrlReq, GetBaseEmojiPathReq, PullSysEmojisReq } from '../types';
|
||||
|
||||
export interface NodeIKernelBaseEmojiService {
|
||||
removeKernelBaseEmojiListener(listenerId: number): void;
|
||||
|
||||
addKernelBaseEmojiListener(listener: unknown): number;
|
||||
|
||||
isBaseEmojiPathExist(args: Array<string>): unknown;
|
||||
|
||||
fetchFullSysEmojis(pullSysEmojisReq: PullSysEmojisReq): unknown;
|
||||
|
||||
getBaseEmojiPathByIds(getBaseEmojiPathReqs: Array<GetBaseEmojiPathReq>): unknown;
|
||||
|
||||
downloadBaseEmojiByIdWithUrl(downloadBaseEmojiByUrlReq: DownloadBaseEmojiByUrlReq): unknown;
|
||||
|
||||
downloadBaseEmojiById(downloadBaseEmojiByIdReq: DownloadBaseEmojiByIdReq): unknown;
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
import { GeneralCallResult } from '@/core/services/common';
|
||||
import { NodeIKernelBuddyListener } from '@/core/listeners';
|
||||
import { BuddyListReqType } from '../types/user';
|
||||
import { BuddyListReqType } from '@/core/types/user';
|
||||
|
||||
export interface NodeIKernelBuddyService {
|
||||
getBuddyListV2(callFrom: string, reqType: BuddyListReqType): Promise<GeneralCallResult & {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { ElementType, MessageElement, Peer, RawMessage, SendMessageElement } from '@/core/types';
|
||||
import { NodeIKernelMsgListener } from '@/core/listeners/NodeIKernelMsgListener';
|
||||
import { GeneralCallResult } from '@/core/services/common';
|
||||
import { MsgReqType, QueryMsgsParams, TmpChatInfoApi } from '../types/msg';
|
||||
import { MsgReqType, QueryMsgsParams, TmpChatInfoApi } from '@/core/types/msg';
|
||||
|
||||
export interface NodeIKernelMsgService {
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { ChatType, Peer } from '@/core/types';
|
||||
import { NodeIKernelRecentContactListener } from '../listeners/NodeIKernelRecentContactListener';
|
||||
import { GeneralCallResult } from './common';
|
||||
import { FSABRecentContactParams } from '../types/contact';
|
||||
import { NodeIKernelRecentContactListener } from '@/core/listeners/NodeIKernelRecentContactListener';
|
||||
import { GeneralCallResult } from '@/core/services/common';
|
||||
import { FSABRecentContactParams } from '@/core/types/contact';
|
||||
|
||||
export interface NodeIKernelRecentContactService {
|
||||
setGuildDisplayStatus(...args: unknown[]): unknown; // 2 arguments
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { NodeIO3MiscListener } from "../listeners/NodeIO3MiscListener";
|
||||
import { NodeIO3MiscListener } from "@/core/listeners/NodeIO3MiscListener";
|
||||
|
||||
export interface NodeIO3MiscService {
|
||||
get(): NodeIO3MiscService;
|
||||
|
@@ -1,11 +1,11 @@
|
||||
export enum MsfStatusType {
|
||||
KUNKNOWN,
|
||||
KDISCONNECTED,
|
||||
KCONNECTED
|
||||
KUNKNOWN = 0,
|
||||
KDISCONNECTED = 1,
|
||||
KCONNECTED = 2
|
||||
}
|
||||
export enum MsfChangeReasonType {
|
||||
KUNKNOWN,
|
||||
KUSERLOGININ,
|
||||
KUSERLOGINOUT,
|
||||
KAUTO
|
||||
KUNKNOWN = 0,
|
||||
KUSERLOGININ = 1,
|
||||
KUSERLOGINOUT = 2,
|
||||
KAUTO = 3
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
import { ElementType, FaceType, MessageElement, NTGrayTipElementSubTypeV2, PicSubType, PicType, TipAioOpGrayTipElement, TipGroupElement, NTVideoType } from "./msg";
|
||||
import { ElementType, MessageElement, NTGrayTipElementSubTypeV2, PicSubType, PicType, TipAioOpGrayTipElement, TipGroupElement, NTVideoType, FaceType } from "./msg";
|
||||
|
||||
type ElementFullBase = Omit<MessageElement, 'elementType' | 'elementId' | 'extBufForUI'>;
|
||||
|
||||
@@ -253,7 +253,7 @@ export interface FaceBubbleElement {
|
||||
faceFlag: number;
|
||||
content: string;
|
||||
oldVersionStr: string;
|
||||
faceType: number;
|
||||
faceType: FaceType;
|
||||
others: string;
|
||||
yellowFaceInfo: {
|
||||
index: number;
|
||||
|
54
src/core/types/emoji.ts
Normal file
54
src/core/types/emoji.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
export enum PullMomentType {
|
||||
REINSTALL = 0,
|
||||
RESTART_FIRST_AIO = 1,
|
||||
LOGIN_APP = 2,
|
||||
SINGEL_PULL_NOTIFY = 3,
|
||||
TRIGGER_SPECIFIC_EMOJI_RANDOM_RESULT = 4
|
||||
}
|
||||
|
||||
export interface PullSysEmojisReq {
|
||||
fetchAdvaceSource: boolean;
|
||||
fetchBaseSource: boolean;
|
||||
pullMoment: PullMomentType;
|
||||
pullType: number;
|
||||
refresh: boolean;
|
||||
thresholdValue: number;
|
||||
}
|
||||
|
||||
export enum BaseEmojiType {
|
||||
NORMAL_EMOJI = 0,
|
||||
SUPER_EMOJI = 1,
|
||||
RANDOM_SUPER_EMOJI = 2,
|
||||
CHAIN_SUPER_EMOJI = 3,
|
||||
EMOJI_EMOJI = 4
|
||||
}
|
||||
|
||||
export interface GetBaseEmojiPathReq {
|
||||
emojiId: string;
|
||||
type: BaseEmojiType;
|
||||
}
|
||||
export enum EmojiPanelCategory {
|
||||
OTHER_PANEL = 0,
|
||||
NORMAL_PANEL = 1,
|
||||
SUPER_PANEL = 2,
|
||||
RED_HEART_PANEL = 3
|
||||
}
|
||||
|
||||
export interface DownloadBaseEmojiInfo {
|
||||
baseResDownloadUrl: string;
|
||||
advancedResDownloadUrl: string;
|
||||
}
|
||||
|
||||
export interface DownloadBaseEmojiByUrlReq {
|
||||
emojiId: string;
|
||||
groupName: string;
|
||||
panelCategory: EmojiPanelCategory;
|
||||
downloadInfo: DownloadBaseEmojiInfo;
|
||||
}
|
||||
|
||||
export interface DownloadBaseEmojiByIdReq {
|
||||
emojiId: string;
|
||||
groupName: string;
|
||||
panelCategory: EmojiPanelCategory;
|
||||
qzoneCode: string;
|
||||
}
|
74
src/core/types/graytip.ts
Normal file
74
src/core/types/graytip.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
export enum JsonGrayBusiId {
|
||||
AIO_AV_C2C_NOTICE = 2021,
|
||||
AIO_AV_GROUP_NOTICE = 2022,
|
||||
AIO_C2C_DONT_DISTURB = 2100,
|
||||
AIO_CRM_FLAGS_TIPS = 2050,
|
||||
AIO_GROUP_ESSENCE_MSG_TIP = 2401,
|
||||
AIO_NUDGE_CUSTOM_GUIDE = 2041,
|
||||
AIO_PUSH_GUIDE_GRAY_TIPS = 2701,
|
||||
AIO_RECALL_MSGCUSTOM_WORDINGGUIDE = 2000,
|
||||
AIO_ROBOT_SAFETY_TIP = 2201,
|
||||
AIO_ZPLAN_EMOTICON_GUIDE = 2301,
|
||||
AIO_ZPLAN_SCENE_LINKAGE = 2302,
|
||||
AIO_ZPLAN_SEND_MEME = 2300,
|
||||
DISBAND_DISCUSSION_GRAY_TIP_ID = 2603,
|
||||
FILE_SENDING_SIZE_4GB_LIMIT = 3003,
|
||||
GROUP_AIO_CONFIGURABLE_GRAY_TIPS = 2407,
|
||||
GROUP_AIO_HOME_SCHOOL_WELCOME_GRAY_TIP_ID = 2404,
|
||||
GROUP_AIO_MSG_FREQUENCY_GRAY_TIP_ID = 2406,
|
||||
GROUP_AIO_SHUTUP_GRAY_TIP_ID = 2402,
|
||||
GROUP_AIO_TEMPORARY_GRAY_TIP_ID = 2405,
|
||||
GROUP_AIO_UNREAD_MSG_AI_SUMMARY = 2408,
|
||||
GROUP_AIO_UPLOAD_PERMISSIONS_GRAY_TIP_ID = 2403,
|
||||
LITE_ACTION = 86,
|
||||
ONLINE_FILE_CANCEL_RECV_ON_RECVING = 4,
|
||||
ONLINE_FILE_GO_OFFLINE = 11,
|
||||
ONLINE_FILE_GO_OFFLINE_ALL = 12,
|
||||
ONLINE_FILE_RECV_BY_MOBILE = 13,
|
||||
ONLINE_FILE_RECV_ERROR = 10,
|
||||
ONLINE_FILE_REFUSE_ALL_RECV = 7,
|
||||
ONLINE_FILE_REFUSE_ALL_RECV_ON_RECVING = 8,
|
||||
ONLINE_FILE_REFUSE_RECV = 3,
|
||||
ONLINE_FILE_SEND_ERROR = 9,
|
||||
ONLINE_FILE_STOP_ALL_SEND = 5,
|
||||
ONLINE_FILE_STOP_ALL_SEND_ON_SENDING = 6,
|
||||
ONLINE_FILE_STOP_SEND = 1,
|
||||
ONLINE_FILE_STOP_SEND_ON_SENDING = 2,
|
||||
ONLINE_GROUP_HOME_WORK = 51,
|
||||
PTT_AUTO_CHANGE_GUIDE = 2060,
|
||||
QCIRCLE_SHOW_FULE_TIPS = 2601,
|
||||
QWALLET_GRAY_TIP_ID = 2602,
|
||||
RED_BAG = 81,
|
||||
RELATION_C2C_GROUP_AIO_SETUP_GROUP_AND_REMARK = 1005,
|
||||
RELATION_C2C_LOVER_BONUS = 1003,
|
||||
RELATION_C2C_MEMBER_ADD = 1017,
|
||||
RELATION_C2C_REACTIVE_DEGRADE_MSG = 1019,
|
||||
RELATION_C2C_REACTIVE_UPGRADE_MSG = 1018,
|
||||
RELATION_C2C_SAY_HELLO = 1004,
|
||||
RELATION_CHAIN_BLACKED = 1000,
|
||||
RELATION_CHAIN_MATCH_FRIEND = 1007,
|
||||
RELATION_CREATE_GROUP_GRAY_TIP_ID = 1009,
|
||||
RELATION_EMOJIEGG_SHOW = 1001,
|
||||
RELATION_EMOJIEGG_WILL_DEGRADE = 1002,
|
||||
RELATION_FRIEND_CLONE_INFO = 1006,
|
||||
RELATION_GROUP_BATCH_ADD_FRIEND = 1020,
|
||||
RELATION_GROUP_MEMBER_ADD = 1022,
|
||||
RELATION_GROUP_MEMBER_ADD_WITH_MODIFY_NAME = 1015,
|
||||
RELATION_GROUP_MEMBER_ADD_WITH_WELCOME = 1016,
|
||||
RELATION_GROUP_MEMBER_RECOMMEND = 1021,
|
||||
RELATION_GROUP_SHUT_UP = 1014,
|
||||
RELATION_LIMIT_TMP_CONVERSATION_SET = 1011,
|
||||
RELATION_NEARBY_GOTO_VERIFY = 1008,
|
||||
RELATION_ONEWAY_FRIEND_GRAY_TIP_ID = 1012,
|
||||
RELATION_ONEWAY_FRIEND_NEW_GRAY_TIP_ID = 1013,
|
||||
RELATION_YQT = 1010,
|
||||
TROOP_ADD_FRIEND_ACTIVE = 19264,
|
||||
TROOP_ADD_FRIEND_HOT_CHAT = 19265,
|
||||
TROOP_ADD_FRIEND_NEW_MEMBER = 19267,
|
||||
TROOP_ADD_FRIEND_REPLY_OR_AT = 19266,
|
||||
TROOP_BREAK_ICE = 10405,
|
||||
TROOP_FLAME_IGNITED = 19273,
|
||||
UI_RESERVE_100000_110000 = 100000,
|
||||
VAS_FILE_UPLOAD_OVER_1G = 3002,
|
||||
VAS_FILE_UPLOAD_OVER_LIMIT = 3001,
|
||||
}
|
@@ -63,16 +63,16 @@ export interface KickMemberV2Req {
|
||||
|
||||
// 数据来源类型
|
||||
export enum DataSource {
|
||||
LOCAL,
|
||||
REMOTE
|
||||
LOCAL = 0,
|
||||
REMOTE = 1
|
||||
}
|
||||
|
||||
// 群列表更新类型
|
||||
export enum GroupListUpdateType {
|
||||
REFRESHALL,
|
||||
GETALL,
|
||||
MODIFIED,
|
||||
REMOVE
|
||||
REFRESHALL = 0,
|
||||
GETALL = 1,
|
||||
MODIFIED = 2,
|
||||
REMOVE = 3
|
||||
}
|
||||
|
||||
export interface GroupMemberCache {
|
||||
|
@@ -7,4 +7,6 @@ export * from './system';
|
||||
export * from './webapi';
|
||||
export * from './sign';
|
||||
export * from './element';
|
||||
export * from './constant';
|
||||
export * from './constant';
|
||||
export * from './graytip';
|
||||
export * from './emoji';
|
@@ -1,6 +1,10 @@
|
||||
import { NTGroupMemberRole } from '@/core';
|
||||
import { ActionBarElement, ArkElement, AvRecordElement, CalendarElement, FaceBubbleElement, FaceElement, FileElement, GiphyElement, GrayTipElement, MarketFaceElement, PicElement, PttElement, RecommendedMsgElement, ReplyElement, ShareLocationElement, StructLongMsgElement, TaskTopMsgElement, TextElement, TofuRecordElement, VideoElement, YoloGameResultElement } from './element';
|
||||
|
||||
/*
|
||||
* 2024/11/22 Refactor Mlikiowa
|
||||
*/
|
||||
|
||||
/**
|
||||
* 表示对等方的信息
|
||||
*/
|
||||
@@ -127,7 +131,7 @@ export enum PicSubType {
|
||||
KRELATED = 7
|
||||
}
|
||||
/**
|
||||
* 消息@类型枚举
|
||||
* 消息AT类型枚举
|
||||
*/
|
||||
export enum NTMsgAtType {
|
||||
ATTYPEALL = 1,
|
||||
@@ -260,16 +264,6 @@ export enum NTGrayTipElementSubTypeV2 {
|
||||
GRAYTIP_ELEMENT_SUBTYPE_XMLMSG = 12,
|
||||
}
|
||||
|
||||
/**
|
||||
* 表情类型枚举
|
||||
*/
|
||||
export enum FaceType {
|
||||
normal = 1, // 小黄脸
|
||||
normal2 = 2, // 新小黄脸
|
||||
dice = 3, // 骰子
|
||||
poke = 5 // 拍一拍
|
||||
}
|
||||
|
||||
/**
|
||||
* Poke 类型枚举
|
||||
*/
|
||||
@@ -288,8 +282,8 @@ export enum PokeType {
|
||||
* 表情索引枚举
|
||||
*/
|
||||
export enum FaceIndex {
|
||||
dice = 358,
|
||||
rps = 359
|
||||
DICE = 358,
|
||||
RPS = 359
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -532,4 +526,16 @@ export interface MsgReqType {
|
||||
includeSelf: boolean,
|
||||
includeDeleteMsg: boolean,
|
||||
extraCnt: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 表情类型枚举
|
||||
*/
|
||||
export enum FaceType {
|
||||
Unknown = 0,
|
||||
OldFace = 1, // 老表情
|
||||
Normal = 2, // 常规表情
|
||||
AniSticke = 3, // 动画贴纸
|
||||
Lottie = 4,// 新格式表情
|
||||
Poke = 5 // 可变Poke
|
||||
}
|
@@ -1,20 +1,20 @@
|
||||
export enum GroupNotifyMsgType {
|
||||
UN_SPECIFIED,
|
||||
INVITED_BY_MEMBER,
|
||||
REFUSE_INVITED,
|
||||
REFUSED_BY_ADMINI_STRATOR,
|
||||
AGREED_TOJOIN_DIRECT,// 有人接受了邀请入群
|
||||
INVITED_NEED_ADMINI_STRATOR_PASS,
|
||||
AGREED_TO_JOIN_BY_ADMINI_STRATOR,
|
||||
REQUEST_JOIN_NEED_ADMINI_STRATOR_PASS,
|
||||
SET_ADMIN,
|
||||
KICK_MEMBER_NOTIFY_ADMIN,
|
||||
KICK_MEMBER_NOTIFY_KICKED,
|
||||
MEMBER_LEAVE_NOTIFY_ADMIN,// 主动退出
|
||||
CANCEL_ADMIN_NOTIFY_CANCELED,
|
||||
CANCEL_ADMIN_NOTIFY_ADMIN,// 其他人取消管理员
|
||||
TRANSFER_GROUP_NOTIFY_OLDOWNER,
|
||||
TRANSFER_GROUP_NOTIFY_ADMIN
|
||||
UN_SPECIFIED = 0,
|
||||
INVITED_BY_MEMBER = 1,
|
||||
REFUSE_INVITED = 2,
|
||||
REFUSED_BY_ADMINI_STRATOR = 3,
|
||||
AGREED_TOJOIN_DIRECT = 4,// 有人接受了邀请入群
|
||||
INVITED_NEED_ADMINI_STRATOR_PASS = 5,
|
||||
AGREED_TO_JOIN_BY_ADMINI_STRATOR = 6,
|
||||
REQUEST_JOIN_NEED_ADMINI_STRATOR_PASS = 7,
|
||||
SET_ADMIN = 8,
|
||||
KICK_MEMBER_NOTIFY_ADMIN = 9,
|
||||
KICK_MEMBER_NOTIFY_KICKED = 10,
|
||||
MEMBER_LEAVE_NOTIFY_ADMIN = 11,// 主动退出
|
||||
CANCEL_ADMIN_NOTIFY_CANCELED = 12,
|
||||
CANCEL_ADMIN_NOTIFY_ADMIN = 13,// 其他人取消管理员
|
||||
TRANSFER_GROUP_NOTIFY_OLDOWNER = 14,
|
||||
TRANSFER_GROUP_NOTIFY_ADMIN = 15
|
||||
}
|
||||
|
||||
export interface GroupNotifies {
|
||||
@@ -24,24 +24,24 @@ export interface GroupNotifies {
|
||||
}
|
||||
|
||||
export enum GroupNotifyMsgStatus {
|
||||
KINIT,//初始化
|
||||
KUNHANDLE,//未处理
|
||||
KAGREED,//同意
|
||||
KREFUSED,//拒绝
|
||||
KIGNORED//忽略
|
||||
KINIT = 0,//初始化
|
||||
KUNHANDLE = 1,//未处理
|
||||
KAGREED = 2,//同意
|
||||
KREFUSED = 3,//拒绝
|
||||
KIGNORED = 4//忽略
|
||||
}
|
||||
|
||||
export enum GroupInviteStatus {
|
||||
INIT,
|
||||
WAIT_TO_APPROVE,
|
||||
JOINED,
|
||||
REFUSED_BY_ADMINI_STRATOR
|
||||
INIT = 0,
|
||||
WAIT_TO_APPROVE = 1,
|
||||
JOINED = 2,
|
||||
REFUSED_BY_ADMINI_STRATOR = 3
|
||||
}
|
||||
|
||||
export enum GroupInviteType {
|
||||
BYBUDDY,
|
||||
BYGROUPMEMBER,
|
||||
BYDISCUSSMEMBER
|
||||
BYBUDDY = 0,
|
||||
BYGROUPMEMBER = 1,
|
||||
BYDISCUSSMEMBER = 2
|
||||
}
|
||||
export interface ShutUpGroupHonor {
|
||||
[key: string]: number;
|
||||
@@ -116,20 +116,20 @@ export enum NTGroupRequestOperateTypes {
|
||||
}
|
||||
|
||||
export enum BuddyReqType {
|
||||
KMEINITIATOR,
|
||||
KPEERINITIATOR,
|
||||
KMEAGREED,
|
||||
KMEAGREEDANDADDED,
|
||||
KPEERAGREED,
|
||||
KPEERAGREEDANDADDED,
|
||||
KPEERREFUSED,
|
||||
KMEREFUSED,
|
||||
KMEIGNORED,
|
||||
KMEAGREEANYONE,
|
||||
KMESETQUESTION,
|
||||
KMEAGREEANDADDFAILED,
|
||||
KMSGINFO,
|
||||
KMEINITIATORWAITPEERCONFIRM
|
||||
KMEINITIATOR = 0,
|
||||
KPEERINITIATOR = 1,
|
||||
KMEAGREED = 2,
|
||||
KMEAGREEDANDADDED = 3,
|
||||
KPEERAGREED = 4,
|
||||
KPEERAGREEDANDADDED = 5,
|
||||
KPEERREFUSED = 6,
|
||||
KMEREFUSED = 7,
|
||||
KMEIGNORED = 8,
|
||||
KMEAGREEANYONE = 9,
|
||||
KMESETQUESTION = 10,
|
||||
KMEAGREEANDADDFAILED = 11,
|
||||
KMSGINFO = 12,
|
||||
KMEINITIATORWAITPEERCONFIRM = 13
|
||||
}
|
||||
|
||||
export interface FriendRequest {
|
||||
|
@@ -322,8 +322,8 @@ export type Friend = User;
|
||||
|
||||
// 业务键枚举
|
||||
export enum BizKey {
|
||||
KPRIVILEGEICON,
|
||||
KPHOTOWALL
|
||||
KPRIVILEGEICON = 0,
|
||||
KPHOTOWALL = 1
|
||||
}
|
||||
|
||||
// 根据UIN获取用户详细信息
|
||||
@@ -347,9 +347,9 @@ export enum UserDetailSource {
|
||||
|
||||
// 个人资料业务类型枚举
|
||||
export enum ProfileBizType {
|
||||
KALL,
|
||||
KBASEEXTEND,
|
||||
KVAS,
|
||||
KQZONE,
|
||||
KOTHER
|
||||
KALL = 0,
|
||||
KBASEEXTEND = 1,
|
||||
KVAS = 2,
|
||||
KQZONE = 3,
|
||||
KOTHER = 4
|
||||
}
|
@@ -1,7 +1,6 @@
|
||||
import { ActionName, BaseCheckResult } from './router';
|
||||
import Ajv, { ErrorObject, ValidateFunction } from 'ajv';
|
||||
import { NapCatCore } from '@/core';
|
||||
import { isNull } from '@/common/helper';
|
||||
import { NapCatOneBot11Adapter, OB11Return } from '@/onebot';
|
||||
|
||||
export class OB11Response {
|
||||
@@ -66,7 +65,7 @@ export abstract class OneBotAction<PayloadType, ReturnDataType> {
|
||||
return OB11Response.ok(resData);
|
||||
} catch (e: any) {
|
||||
this.core.context.logger.logError('发生错误', e);
|
||||
return OB11Response.error(e?.toString() || e?.stack?.toString() || '未知错误,可能操作超时', 200);
|
||||
return OB11Response.error((e as Error).message.toString() || e?.stack?.toString() || '未知错误,可能操作超时', 200);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +79,7 @@ export abstract class OneBotAction<PayloadType, ReturnDataType> {
|
||||
return OB11Response.ok(resData, echo);
|
||||
} catch (e: any) {
|
||||
this.core.context.logger.logError('发生错误', e);
|
||||
return OB11Response.error(e.toString() || e.stack?.toString(), 1200, echo);
|
||||
return OB11Response.error((e as Error).message.toString() || e.stack?.toString(), 1200, echo);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,18 +1,31 @@
|
||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||
import { ActionName } from '@/onebot/action/router';
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
|
||||
interface Payload {
|
||||
start: number,
|
||||
count: number
|
||||
}
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
user_id: { type: ['number', 'string'] },
|
||||
start: { type: ['number', 'string'] },
|
||||
count: { type: ['number', 'string'] },
|
||||
type: { type: ['number', 'string'] },
|
||||
},
|
||||
} as const satisfies JSONSchema;
|
||||
|
||||
type Payload = FromSchema<typeof SchemaData>;
|
||||
|
||||
export class GetProfileLike extends OneBotAction<Payload, any> {
|
||||
actionName = ActionName.GetProfileLike;
|
||||
|
||||
payloadSchema = SchemaData;
|
||||
async _handle(payload: Payload) {
|
||||
const start = payload.start ? Number(payload.start) : 0;
|
||||
const count = payload.count ? Number(payload.count) : 10;
|
||||
const ret = await this.core.apis.UserApi.getProfileLike(this.core.selfInfo.uid, start, count);
|
||||
const type = payload.count ? Number(payload.count) : 2;
|
||||
const user_uid =
|
||||
this.core.selfInfo.uin === payload.user_id || !payload.user_id ?
|
||||
this.core.selfInfo.uid :
|
||||
await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||
const ret = await this.core.apis.UserApi.getProfileLike(user_uid ?? this.core.selfInfo.uid, start, count, type);
|
||||
const listdata = ret.info.userLikeInfos[0].voteInfo.userInfos;
|
||||
for (const item of listdata) {
|
||||
item.uin = parseInt((await this.core.apis.UserApi.getUinByUidV2(item.uid)) || '');
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { GetPacketStatusDepends } from '../packet/GetPacketStatus';
|
||||
import { GetPacketStatusDepends } from '@/onebot/action/packet/GetPacketStatus';
|
||||
import { ActionName } from '@/onebot/action/router';
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
|
||||
|
@@ -41,7 +41,7 @@ export class GoCQHTTPGetForwardMsgAction extends OneBotAction<Payload, any> {
|
||||
for (const msgdata of message.message) {
|
||||
if ((msgdata as OB11MessageData).type === OB11MessageDataType.forward) {
|
||||
const newNode = this.createTemplateNode(message);
|
||||
newNode.data.message = await this.parseForward((msgdata as OB11MessageForward).data.content);
|
||||
newNode.data.message = await this.parseForward((msgdata as OB11MessageForward).data.content ?? []);
|
||||
|
||||
templateNode.data.message.push(newNode);
|
||||
} else {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import SendMsg, { normalize } from '../msg/SendMsg';
|
||||
import { OB11PostSendMsg } from '../../types';
|
||||
import SendMsg, { normalize } from '@/onebot/action/msg/SendMsg';
|
||||
import { OB11PostSendMsg } from '@/onebot/types';
|
||||
import { ActionName } from '@/onebot/action/router';
|
||||
|
||||
// 未验证
|
||||
|
@@ -5,7 +5,7 @@ import fs from 'fs';
|
||||
import { uri2local } from '@/common/file';
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
import { MessageContext } from '@/onebot/api';
|
||||
import { ContextMode, createContext } from '../msg/SendMsg';
|
||||
import { ContextMode, createContext } from '@/onebot/action/msg/SendMsg';
|
||||
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import SendMsg, { ContextMode } from '../msg/SendMsg';
|
||||
import { ActionName, BaseCheckResult } from '../router';
|
||||
import { OB11PostSendMsg } from '../../types';
|
||||
import SendMsg, { ContextMode } from '@/onebot/action/msg/SendMsg';
|
||||
import { ActionName, BaseCheckResult } from '@/onebot/action/router';
|
||||
import { OB11PostSendMsg } from '@/onebot/types';
|
||||
|
||||
// 未检测参数
|
||||
class SendGroupMsg extends SendMsg {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import SendMsg, { ContextMode } from './SendMsg';
|
||||
import { ActionName, BaseCheckResult } from '../router';
|
||||
import { OB11PostSendMsg } from '../../types';
|
||||
import { ActionName, BaseCheckResult } from '@/onebot/action/router';
|
||||
import { OB11PostSendMsg } from '@/onebot/types';
|
||||
|
||||
// 未检测参数
|
||||
class SendPrivateMsg extends SendMsg {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { OneBotAction } from '@/onebot/action/OneBotAction';
|
||||
import { ActionName, BaseCheckResult } from '../router';
|
||||
import { ActionName, BaseCheckResult } from '@/onebot/action/router';
|
||||
|
||||
|
||||
export abstract class GetPacketStatusDepends<PT, RT> extends OneBotAction<PT, RT> {
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { GrayTipElement, NapCatCore } from '@/core';
|
||||
|
||||
import { NapCatOneBot11Adapter } from '@/onebot';
|
||||
import { OB11FriendPokeEvent } from '../event/notice/OB11PokeEvent';
|
||||
import { OB11FriendPokeEvent } from '@/onebot/event/notice/OB11PokeEvent';
|
||||
|
||||
export class OneBotFriendApi {
|
||||
obContext: NapCatOneBot11Adapter;
|
||||
|
@@ -1,17 +1,18 @@
|
||||
import {
|
||||
ChatType,
|
||||
GrayTipElement,
|
||||
JsonGrayBusiId,
|
||||
NapCatCore,
|
||||
NTGrayTipElementSubTypeV2,
|
||||
RawMessage,
|
||||
TipGroupElementType,
|
||||
} from '@/core';
|
||||
import { NapCatOneBot11Adapter } from '@/onebot';
|
||||
import { OB11GroupBanEvent } from '../event/notice/OB11GroupBanEvent';
|
||||
import { OB11GroupIncreaseEvent } from '../event/notice/OB11GroupIncreaseEvent';
|
||||
import { OB11GroupDecreaseEvent } from '../event/notice/OB11GroupDecreaseEvent';
|
||||
import { OB11GroupBanEvent } from '@/onebot/event/notice/OB11GroupBanEvent';
|
||||
import { OB11GroupIncreaseEvent } from '@/onebot/event/notice/OB11GroupIncreaseEvent';
|
||||
import { OB11GroupDecreaseEvent } from '@/onebot/event/notice/OB11GroupDecreaseEvent';
|
||||
import fastXmlParser from 'fast-xml-parser';
|
||||
import { OB11GroupMsgEmojiLikeEvent } from '../event/notice/OB11MsgEmojiLikeEvent';
|
||||
import { OB11GroupMsgEmojiLikeEvent } from '@/onebot/event/notice/OB11MsgEmojiLikeEvent';
|
||||
import { MessageUnique } from '@/common/message-unique';
|
||||
import { OB11GroupCardEvent } from '@/onebot/event/notice/OB11GroupCardEvent';
|
||||
import { OB11GroupUploadNoticeEvent } from '@/onebot/event/notice/OB11GroupUploadNoticeEvent';
|
||||
@@ -115,7 +116,7 @@ export class OneBotGroupApi {
|
||||
);
|
||||
}
|
||||
}
|
||||
if (element.grayTipElement.jsonGrayTipElement.busiId == 2401) {
|
||||
if (element.grayTipElement.jsonGrayTipElement.busiId == JsonGrayBusiId.AIO_GROUP_ESSENCE_MSG_TIP) {
|
||||
const searchParams = new URL(json.items[0].jp).searchParams;
|
||||
const msgSeq = searchParams.get('msgSeq')!;
|
||||
const Group = searchParams.get('groupCode');
|
||||
@@ -138,7 +139,7 @@ export class OneBotGroupApi {
|
||||
);
|
||||
// 获取MsgSeq+Peer可获取具体消息
|
||||
}
|
||||
if (element.grayTipElement.jsonGrayTipElement.busiId == 2407) {
|
||||
if (element.grayTipElement.jsonGrayTipElement.busiId == JsonGrayBusiId.GROUP_AIO_CONFIGURABLE_GRAY_TIPS) {
|
||||
const type = json.items[json.items.length - 1]?.txt;
|
||||
if (type === "头衔") {
|
||||
const memberUin = json.items[1].param[0];
|
||||
|
@@ -7,7 +7,6 @@ import {
|
||||
CustomMusicSignPostData,
|
||||
ElementType,
|
||||
FaceIndex,
|
||||
FaceType,
|
||||
IdMusicSignPostData,
|
||||
MessageElement,
|
||||
NapCatCore,
|
||||
@@ -16,9 +15,11 @@ import {
|
||||
RawMessage,
|
||||
SendMessageElement,
|
||||
SendTextElement,
|
||||
BaseEmojiType,
|
||||
FaceType,
|
||||
} from '@/core';
|
||||
import faceConfig from '@/core/external/face_config.json';
|
||||
import { NapCatOneBot11Adapter, OB11Message, OB11MessageData, OB11MessageDataType, OB11MessageFileBase, } from '@/onebot';
|
||||
import { NapCatOneBot11Adapter, OB11Message, OB11MessageData, OB11MessageDataType, OB11MessageFileBase, OB11MessageForward, } from '@/onebot';
|
||||
import { OB11Construct } from '@/onebot/helper/data';
|
||||
import { EventType } from '@/onebot/event/OneBotEvent';
|
||||
import { encodeCQCode } from '@/onebot/helper/cqcode';
|
||||
@@ -36,21 +37,26 @@ type RawToOb11Converters = {
|
||||
element: Exclude<MessageElement[Key], null | undefined>,
|
||||
msg: RawMessage,
|
||||
elementWrapper: MessageElement,
|
||||
context: RecvMessageContext
|
||||
) => PromiseLike<OB11MessageData | null>
|
||||
}
|
||||
|
||||
type Ob11ToRawConverters = {
|
||||
[Key in OB11MessageDataType]: (
|
||||
sendMsg: Extract<OB11MessageData, { type: Key }>,
|
||||
context: MessageContext,
|
||||
context: SendMessageContext,
|
||||
) => Promise<SendMessageElement | undefined>
|
||||
}
|
||||
|
||||
export type MessageContext = {
|
||||
export type SendMessageContext = {
|
||||
deleteAfterSentFiles: string[],
|
||||
peer: Peer
|
||||
}
|
||||
|
||||
export type RecvMessageContext = {
|
||||
parseMultMsg: boolean
|
||||
}
|
||||
|
||||
function keyCanBeParsed(key: string, parser: RawToOb11Converters): key is keyof RawToOb11Converters {
|
||||
return key in parser;
|
||||
}
|
||||
@@ -144,14 +150,14 @@ export class OneBotMsgApi {
|
||||
|
||||
faceElement: async element => {
|
||||
const faceIndex = element.faceIndex;
|
||||
if (faceIndex === FaceIndex.dice) {
|
||||
if (faceIndex === FaceIndex.DICE) {
|
||||
return {
|
||||
type: OB11MessageDataType.dice,
|
||||
data: {
|
||||
result: element.resultId!,
|
||||
},
|
||||
};
|
||||
} else if (faceIndex === FaceIndex.rps) {
|
||||
} else if (faceIndex === FaceIndex.RPS) {
|
||||
return {
|
||||
type: OB11MessageDataType.rps,
|
||||
data: {
|
||||
@@ -337,42 +343,26 @@ export class OneBotMsgApi {
|
||||
};
|
||||
},
|
||||
|
||||
multiForwardMsgElement: async (_, msg) => {
|
||||
// const message_data: OB11MessageForward = {
|
||||
// data: {} as any,
|
||||
// type: OB11MessageDataType.forward,
|
||||
// };
|
||||
// message_data.data.id = msg.msgId;
|
||||
multiForwardMsgElement: async (_, msg, wrapper, context) => {
|
||||
const parentMsgPeer = msg.parentMsgPeer ?? {
|
||||
chatType: msg.chatType,
|
||||
guildId: '',
|
||||
peerUid: msg.peerUid,
|
||||
};
|
||||
//判断是否在合并消息内
|
||||
msg.parentMsgIdList = msg.parentMsgIdList ?? [];
|
||||
//首次列表不存在则开始创建
|
||||
msg.parentMsgIdList.push(msg.msgId);
|
||||
//let parentMsgId = msg.parentMsgIdList[msg.parentMsgIdList.length - 2 < 0 ? 0 : msg.parentMsgIdList.length - 2];
|
||||
//加入自身MsgId
|
||||
const multiMsgs = (await this.core.apis.MsgApi.getMultiMsg(parentMsgPeer, msg.parentMsgIdList[0], msg.msgId))?.msgList;
|
||||
//拉取下级消息
|
||||
const multiMsgs = await this.getMultiMessages(msg, parentMsgPeer);
|
||||
// 拉取失败则跳过
|
||||
if (!multiMsgs) return null;
|
||||
//拉取失败则跳过
|
||||
|
||||
return {
|
||||
const forward: OB11MessageForward = {
|
||||
type: OB11MessageDataType.forward,
|
||||
data: {
|
||||
id: msg.msgId,
|
||||
content: (await Promise.all(multiMsgs.map(
|
||||
async multiMsgItem => {
|
||||
multiMsgItem.parentMsgPeer = parentMsgPeer;
|
||||
multiMsgItem.parentMsgIdList = msg.parentMsgIdList;
|
||||
multiMsgItem.id = MessageUnique.createUniqueMsgId(parentMsgPeer, multiMsgItem.msgId); //该ID仅用查看 无法调用
|
||||
return await this.parseMessage(multiMsgItem, 'array');
|
||||
},
|
||||
))).filter(item => item !== undefined),
|
||||
},
|
||||
data: { id: msg.msgId }
|
||||
};
|
||||
if (!context.parseMultMsg) return forward;
|
||||
forward.data.content = await this.parseMultiMessageContent(
|
||||
multiMsgs,
|
||||
parentMsgPeer,
|
||||
msg.parentMsgIdList
|
||||
);
|
||||
return forward;
|
||||
},
|
||||
|
||||
arkElement: async (element) => {
|
||||
@@ -546,8 +536,8 @@ export class OneBotMsgApi {
|
||||
elementType: ElementType.FACE,
|
||||
elementId: '',
|
||||
faceElement: {
|
||||
faceIndex: FaceIndex.dice,
|
||||
faceType: FaceType.dice,
|
||||
faceIndex: FaceIndex.DICE,
|
||||
faceType: FaceType.AniSticke,
|
||||
faceText: '[骰子]',
|
||||
packId: '1',
|
||||
stickerId: '33',
|
||||
@@ -562,9 +552,9 @@ export class OneBotMsgApi {
|
||||
elementType: ElementType.FACE,
|
||||
elementId: '',
|
||||
faceElement: {
|
||||
faceIndex: FaceIndex.rps,
|
||||
faceIndex: FaceIndex.RPS,
|
||||
faceText: '[包剪锤]',
|
||||
faceType: 3,
|
||||
faceType: FaceType.AniSticke,
|
||||
packId: '1',
|
||||
stickerId: '34',
|
||||
sourceType: 1,
|
||||
@@ -691,18 +681,48 @@ export class OneBotMsgApi {
|
||||
}
|
||||
}
|
||||
|
||||
private async getMultiMessages(msg: RawMessage, parentMsgPeer: Peer) {
|
||||
//判断是否在合并消息内
|
||||
msg.parentMsgIdList = msg.parentMsgIdList ?? [];
|
||||
//首次列表不存在则开始创建
|
||||
msg.parentMsgIdList.push(msg.msgId);
|
||||
//拉取下级消息
|
||||
return (await this.core.apis.MsgApi.getMultiMsg(
|
||||
parentMsgPeer,
|
||||
msg.parentMsgIdList[0],
|
||||
msg.msgId
|
||||
))?.msgList;
|
||||
}
|
||||
|
||||
private async parseMultiMessageContent(
|
||||
multiMsgs: RawMessage[],
|
||||
parentMsgPeer: Peer,
|
||||
parentMsgIdList: string[]
|
||||
) {
|
||||
const parsed = await Promise.all(multiMsgs.map(async msg => {
|
||||
msg.parentMsgPeer = parentMsgPeer;
|
||||
msg.parentMsgIdList = parentMsgIdList;
|
||||
msg.id = MessageUnique.createUniqueMsgId(parentMsgPeer, msg.msgId);
|
||||
//该ID仅用查看 无法调用
|
||||
return await this.parseMessage(msg, 'array', true);
|
||||
}));
|
||||
return parsed.filter(item => item !== undefined);
|
||||
}
|
||||
|
||||
async parseMessage(
|
||||
msg: RawMessage,
|
||||
messagePostFormat: string,
|
||||
parseMultMsg: boolean = true
|
||||
) {
|
||||
if (messagePostFormat === 'string') {
|
||||
return (await this.parseMessageV2(msg))?.stringMsg;
|
||||
return (await this.parseMessageV2(msg, parseMultMsg))?.stringMsg;
|
||||
}
|
||||
return (await this.parseMessageV2(msg))?.arrayMsg;
|
||||
return (await this.parseMessageV2(msg, parseMultMsg))?.arrayMsg;
|
||||
}
|
||||
|
||||
async parseMessageV2(
|
||||
msg: RawMessage,
|
||||
parseMultMsg: boolean = true
|
||||
) {
|
||||
if (msg.senderUin == '0' || msg.senderUin == '') return;
|
||||
if (msg.peerUin == '0' || msg.peerUin == '') return;
|
||||
@@ -766,11 +786,15 @@ export class OneBotMsgApi {
|
||||
element: Exclude<MessageElement[keyof RawToOb11Converters], null | undefined>,
|
||||
msg: RawMessage,
|
||||
elementWrapper: MessageElement,
|
||||
context: RecvMessageContext
|
||||
) => PromiseLike<OB11MessageData | null>;
|
||||
const parsedElement = await converters?.(
|
||||
element[key],
|
||||
msg,
|
||||
element,
|
||||
{
|
||||
parseMultMsg: parseMultMsg
|
||||
}
|
||||
);
|
||||
// 对于 face 类型的消息,检查是否存在
|
||||
if (key === 'faceElement' && !parsedElement) {
|
||||
@@ -818,7 +842,7 @@ export class OneBotMsgApi {
|
||||
}
|
||||
const converter = this.ob11ToRawConverters[sendMsg.type] as (
|
||||
sendMsg: Extract<OB11MessageData, { type: OB11MessageData['type'] }>,
|
||||
context: MessageContext,
|
||||
context: SendMessageContext,
|
||||
) => Promise<SendMessageElement | undefined>;
|
||||
const callResult = converter(
|
||||
sendMsg,
|
||||
@@ -877,7 +901,7 @@ export class OneBotMsgApi {
|
||||
|
||||
private async handleOb11FileLikeMessage(
|
||||
{ data: inputdata }: OB11MessageFileBase,
|
||||
{ deleteAfterSentFiles }: MessageContext,
|
||||
{ deleteAfterSentFiles }: SendMessageContext,
|
||||
) {
|
||||
const realUri = inputdata.url || inputdata.file || inputdata.path || '';
|
||||
if (realUri.length === 0) {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { NapCatCore } from '@/core';
|
||||
import { NapCatOneBot11Adapter } from '@/onebot';
|
||||
import { OB11ProfileLikeEvent } from '../event/notice/OB11ProfileLikeEvent';
|
||||
import { OB11ProfileLikeEvent } from '@/onebot/event/notice/OB11ProfileLikeEvent';
|
||||
import { decodeProfileLikeTip } from "@/core/helper/adaptDecoder";
|
||||
|
||||
export class OneBotUserApi {
|
||||
|
@@ -103,6 +103,7 @@ export interface OneBotConfig {
|
||||
network: NetworkConfig; // 网络配置
|
||||
musicSignUrl: string; // 音乐签名地址
|
||||
enableLocalFile2Url: boolean;
|
||||
parseMultMsg: boolean;
|
||||
}
|
||||
|
||||
const createDefaultConfig = <T>(config: T): T => config;
|
||||
@@ -116,6 +117,7 @@ export const defaultOneBotConfigs = createDefaultConfig<OneBotConfig>({
|
||||
},
|
||||
musicSignUrl: '',
|
||||
enableLocalFile2Url: false,
|
||||
parseMultMsg: true
|
||||
});
|
||||
|
||||
export const mergeNetworkDefaultConfig = {
|
||||
@@ -149,9 +151,12 @@ export function mergeOneBotConfigs(
|
||||
if (userConfig.musicSignUrl !== undefined) {
|
||||
mergedConfig.musicSignUrl = userConfig.musicSignUrl;
|
||||
}
|
||||
if(userConfig.enableLocalFile2Url !== undefined) {
|
||||
if (userConfig.enableLocalFile2Url !== undefined) {
|
||||
mergedConfig.enableLocalFile2Url = userConfig.enableLocalFile2Url;
|
||||
}
|
||||
if (userConfig.parseMultMsg !== undefined) {
|
||||
mergedConfig.parseMultMsg = userConfig.parseMultMsg;
|
||||
}
|
||||
return mergedConfig;
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { EventType, OneBotEvent } from '../OneBotEvent';
|
||||
import { EventType, OneBotEvent } from '@/onebot/event/OneBotEvent';
|
||||
|
||||
export abstract class OB11BaseMessageEvent extends OneBotEvent {
|
||||
post_type = EventType.MESSAGE;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { OB11BaseNoticeEvent } from '../notice/OB11BaseNoticeEvent';
|
||||
import { EventType } from '../OneBotEvent';
|
||||
import { OB11BaseNoticeEvent } from '@/onebot/event/notice/OB11BaseNoticeEvent';
|
||||
import { EventType } from '@/onebot/event/OneBotEvent';
|
||||
import { NapCatCore } from '@/core';
|
||||
|
||||
export class OB11FriendRequestEvent extends OB11BaseNoticeEvent {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { OB11GroupNoticeEvent } from '../notice/OB11GroupNoticeEvent';
|
||||
import { EventType } from '../OneBotEvent';
|
||||
import { OB11GroupNoticeEvent } from '@/onebot/event/notice/OB11GroupNoticeEvent';
|
||||
import { EventType } from '@/onebot/event/OneBotEvent';
|
||||
import { NapCatCore } from '@/core';
|
||||
|
||||
export class OB11GroupRequestEvent extends OB11GroupNoticeEvent {
|
||||
|
@@ -176,67 +176,33 @@ export class NapCatOneBot11Adapter {
|
||||
};
|
||||
}
|
||||
|
||||
private async reloadNetwork(prev: OneBotConfig, now: OneBotConfig) {
|
||||
private async reloadNetwork(prev: OneBotConfig, now: OneBotConfig): Promise<void> {
|
||||
const prevLog = await this.creatOneBotLog(prev);
|
||||
const newLog = await this.creatOneBotLog(now);
|
||||
this.context.logger.log(`[Notice] [OneBot11] 配置变更前:\n${prevLog}`);
|
||||
this.context.logger.log(`[Notice] [OneBot11] 配置变更后:\n${newLog}`);
|
||||
|
||||
const { added: addedHttpServers, removed: removedHttpServers } = this.findDifference(prev.network.httpServers, now.network.httpServers);
|
||||
const { added: addedHttpClients, removed: removedHttpClients } = this.findDifference(prev.network.httpClients, now.network.httpClients);
|
||||
const { added: addedWebSocketServers, removed: removedWebSocketServers } = this.findDifference(prev.network.websocketServers, now.network.websocketServers);
|
||||
const { added: addedWebSocketClients, removed: removedWebSocketClients } = this.findDifference(prev.network.websocketClients, now.network.websocketClients);
|
||||
|
||||
await this.handleRemovedAdapters(removedHttpServers);
|
||||
await this.handleRemovedAdapters(removedHttpClients);
|
||||
await this.handleRemovedAdapters(removedWebSocketServers);
|
||||
await this.handleRemovedAdapters(removedWebSocketClients);
|
||||
|
||||
await this.handlerConfigChange(now.network.httpServers);
|
||||
await this.handlerConfigChange(now.network.httpClients);
|
||||
await this.handlerConfigChange(now.network.websocketServers);
|
||||
await this.handlerConfigChange(now.network.websocketClients);
|
||||
|
||||
await this.handleAddedAdapters(addedHttpServers, OB11PassiveHttpAdapter);
|
||||
await this.handleAddedAdapters(addedHttpClients, OB11ActiveHttpAdapter);
|
||||
await this.handleAddedAdapters(addedWebSocketServers, OB11PassiveWebSocketAdapter);
|
||||
await this.handleAddedAdapters(addedWebSocketClients, OB11ActiveWebSocketAdapter);
|
||||
|
||||
await this.handleConfigChange(now.network.httpServers, OB11PassiveHttpAdapter);
|
||||
await this.handleConfigChange(now.network.httpClients, OB11ActiveHttpAdapter);
|
||||
await this.handleConfigChange(now.network.websocketServers, OB11PassiveWebSocketAdapter);
|
||||
await this.handleConfigChange(now.network.websocketClients, OB11ActiveWebSocketAdapter);
|
||||
}
|
||||
|
||||
private async handlerConfigChange(adapters: Array<NetworkConfigAdapter>) {
|
||||
|
||||
private async handleConfigChange(adapters: NetworkConfigAdapter[], adapterClass: new (...args: any[]) => IOB11NetworkAdapter): Promise<void> {
|
||||
for (const adapterConfig of adapters) {
|
||||
const existingAdapter = this.networkManager.findSomeAdapter(adapterConfig.name);
|
||||
if (existingAdapter) {
|
||||
const networkChange = await existingAdapter.reload(adapterConfig);
|
||||
if (networkChange === OB11NetworkReloadType.NetWorkClose) {
|
||||
this.networkManager.closeSomeAdapters([existingAdapter]);
|
||||
|
||||
await this.networkManager.closeSomeAdaterWhenOpen([existingAdapter]);
|
||||
}
|
||||
} else {
|
||||
const newAdapter = new adapterClass(adapterConfig.name, adapterConfig, this.core, this.actions);
|
||||
await this.networkManager.registerAdapterAndOpen(newAdapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async handleRemovedAdapters(adapters: Array<{ name: string }>): Promise<void> {
|
||||
for (const adapter of adapters) {
|
||||
await this.networkManager.closeAdapterByPredicate((existingAdapter) => existingAdapter.name === adapter.name);
|
||||
}
|
||||
}
|
||||
|
||||
private async handleAddedAdapters<T extends new (...args: any[]) => IOB11NetworkAdapter>(addedAdapters: Array<NetworkConfigAdapter>, AdapterClass: T) {
|
||||
for (const adapter of addedAdapters) {
|
||||
if (adapter.enable) {
|
||||
const newAdapter = new AdapterClass(adapter.name, adapter, this.core, this.actions);
|
||||
await newAdapter.open();
|
||||
this.networkManager.registerAdapter(newAdapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
private findDifference<T>(prev: T[], now: T[]): { added: T[]; removed: T[] } {
|
||||
const added = now.filter((item) => !prev.includes(item));
|
||||
const removed = prev.filter((item) => !now.includes(item));
|
||||
return { added, removed };
|
||||
}
|
||||
|
||||
private initMsgListener() {
|
||||
const msgListener = new NodeIKernelMsgListener();
|
||||
msgListener.onRecvSysMsg = (msg) => {
|
||||
@@ -551,7 +517,7 @@ export class NapCatOneBot11Adapter {
|
||||
}
|
||||
private async handleMsg(message: RawMessage, network: Array<AdapterConfigWrap>) {
|
||||
try {
|
||||
const ob11Msg = await this.apis.MsgApi.parseMessageV2(message);
|
||||
const ob11Msg = await this.apis.MsgApi.parseMessageV2(message, this.configLoader.configData.parseMultMsg);
|
||||
if (ob11Msg) {
|
||||
const isSelfMsg = this.isSelfMessage(ob11Msg);
|
||||
this.context.logger.logDebug('转化为 OB11Message', ob11Msg);
|
||||
|
@@ -5,8 +5,8 @@ import { QuickAction, QuickActionEvent } from '@/onebot/types';
|
||||
import { NapCatCore } from '@/core';
|
||||
import { NapCatOneBot11Adapter } from '..';
|
||||
import { RequestUtil } from '@/common/request';
|
||||
import { HttpClientConfig } from '../config/config';
|
||||
import { ActionMap } from '../action';
|
||||
import { HttpClientConfig } from '@/onebot/config/config';
|
||||
import { ActionMap } from '@/onebot/action';
|
||||
|
||||
export class OB11ActiveHttpAdapter implements IOB11NetworkAdapter {
|
||||
logger: LogWrapper;
|
||||
|
@@ -1,13 +1,13 @@
|
||||
import { IOB11NetworkAdapter, OB11EmitEventContent, OB11NetworkReloadType } from '@/onebot/network/index';
|
||||
import { WebSocket } from 'ws';
|
||||
import { OB11HeartbeatEvent } from '../event/meta/OB11HeartbeatEvent';
|
||||
import { OB11HeartbeatEvent } from '@/onebot/event/meta/OB11HeartbeatEvent';
|
||||
import { NapCatCore } from '@/core';
|
||||
import { ActionName } from '@/onebot/action/router';
|
||||
import { OB11Response } from '@/onebot/action/OneBotAction';
|
||||
import { LogWrapper } from '@/common/log';
|
||||
import { ActionMap } from '@/onebot/action';
|
||||
import { LifeCycleSubType, OB11LifeCycleEvent } from '../event/meta/OB11LifeCycleEvent';
|
||||
import { WebsocketClientConfig } from '../config/config';
|
||||
import { LifeCycleSubType, OB11LifeCycleEvent } from '@/onebot/event/meta/OB11LifeCycleEvent';
|
||||
import { WebsocketClientConfig } from '@/onebot/config/config';
|
||||
|
||||
export class OB11ActiveWebSocketAdapter implements IOB11NetworkAdapter {
|
||||
isEnable: boolean = false;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { OneBotEvent } from '@/onebot/event/OneBotEvent';
|
||||
import { OB11Message } from '@/onebot';
|
||||
import { ActionMap } from '@/onebot/action';
|
||||
import { NetworkConfigAdapter } from '../config/config';
|
||||
import { NetworkConfigAdapter } from '@/onebot/config/config';
|
||||
|
||||
export type OB11EmitEventContent = OneBotEvent | OB11Message;
|
||||
export enum OB11NetworkReloadType {
|
||||
@@ -68,6 +68,14 @@ export class OB11NetworkManager {
|
||||
await adapter.close();
|
||||
}
|
||||
}
|
||||
async closeSomeAdaterWhenOpen(adaptersToClose: IOB11NetworkAdapter[]) {
|
||||
for (const adapter of adaptersToClose) {
|
||||
this.adapters.delete(adapter.name);
|
||||
if(adapter.isEnable){
|
||||
await adapter.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
findSomeAdapter(name: string) {
|
||||
return this.adapters.get(name);
|
||||
|
@@ -5,7 +5,7 @@ import { NapCatCore } from '@/core';
|
||||
import { OB11Response } from '@/onebot/action/OneBotAction';
|
||||
import { ActionMap } from '@/onebot/action';
|
||||
import cors from 'cors';
|
||||
import { HttpServerConfig } from '../config/config';
|
||||
import { HttpServerConfig } from '@/onebot/config/config';
|
||||
|
||||
export class OB11PassiveHttpAdapter implements IOB11NetworkAdapter {
|
||||
private app: Express | undefined;
|
||||
|
@@ -3,14 +3,14 @@ import urlParse from 'url';
|
||||
import { WebSocket, WebSocketServer } from 'ws';
|
||||
import { Mutex } from 'async-mutex';
|
||||
import { OB11Response } from '@/onebot/action/OneBotAction';
|
||||
import { ActionName } from '../action/router';
|
||||
import { ActionName } from '@/onebot/action/router';
|
||||
import { NapCatCore } from '@/core';
|
||||
import { LogWrapper } from '@/common/log';
|
||||
import { OB11HeartbeatEvent } from '../event/meta/OB11HeartbeatEvent';
|
||||
import { OB11HeartbeatEvent } from '@/onebot/event/meta/OB11HeartbeatEvent';
|
||||
import { IncomingMessage } from 'http';
|
||||
import { ActionMap } from '@/onebot/action';
|
||||
import { LifeCycleSubType, OB11LifeCycleEvent } from '../event/meta/OB11LifeCycleEvent';
|
||||
import { WebsocketServerConfig } from '../config/config';
|
||||
import { LifeCycleSubType, OB11LifeCycleEvent } from '@/onebot/event/meta/OB11LifeCycleEvent';
|
||||
import { WebsocketServerConfig } from '@/onebot/config/config';
|
||||
|
||||
export class OB11PassiveWebSocketAdapter implements IOB11NetworkAdapter {
|
||||
wsServer: WebSocketServer;
|
||||
@@ -31,13 +31,9 @@ export class OB11PassiveWebSocketAdapter implements IOB11NetworkAdapter {
|
||||
) {
|
||||
this.config = structuredClone(config);
|
||||
this.logger = core.context.logger;
|
||||
if (this.config.host === '0.0.0.0') {
|
||||
//兼容配置同时处理0.0.0.0逻辑
|
||||
this.config.host = '';
|
||||
}
|
||||
this.wsServer = new WebSocketServer({
|
||||
port: this.config.port,
|
||||
host: this.config.host,
|
||||
host: this.config.host === '0.0.0.0' ? '' : this.config.host,
|
||||
maxPayload: 1024 * 1024 * 1024,
|
||||
});
|
||||
this.wsServer.on('connection', async (wsClient, wsReq) => {
|
||||
@@ -202,11 +198,13 @@ export class OB11PassiveWebSocketAdapter implements IOB11NetworkAdapter {
|
||||
this.open();
|
||||
return OB11NetworkReloadType.NetWorkOpen;
|
||||
} else if (!newConfig.enable && wasEnabled) {
|
||||
console.log(newConfig.enable, wasEnabled);
|
||||
this.close();
|
||||
return OB11NetworkReloadType.NetWorkClose;
|
||||
}
|
||||
|
||||
if (oldPort !== newConfig.port || oldHost !== newConfig.host) {
|
||||
console.log(oldPort, newConfig.port, oldHost, newConfig.host);
|
||||
this.close();
|
||||
this.wsServer = new WebSocketServer({
|
||||
port: newConfig.port,
|
||||
|
@@ -236,7 +236,7 @@ export interface OB11MessageForward {
|
||||
type: OB11MessageDataType.forward;
|
||||
data: {
|
||||
id: string;
|
||||
content: OB11Message[];
|
||||
content?: OB11Message[];
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { OB11BaseMetaEvent } from '../event/meta/OB11BaseMetaEvent';
|
||||
import { OB11BaseNoticeEvent } from '../event/notice/OB11BaseNoticeEvent';
|
||||
import { OB11Message } from './message';
|
||||
import { OB11BaseMetaEvent } from '@/onebot/event/meta/OB11BaseMetaEvent';
|
||||
import { OB11BaseNoticeEvent } from '@/onebot/event/notice/OB11BaseNoticeEvent';
|
||||
import { OB11Message } from '@/onebot/types/message';
|
||||
|
||||
export type QuickActionEvent = OB11Message | OB11BaseMetaEvent | OB11BaseNoticeEvent;
|
||||
export type PostEventType = OB11Message | OB11BaseMetaEvent | OB11BaseNoticeEvent;
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { RequestHandler } from 'express';
|
||||
import { WebUiDataRuntime } from '../helper/Data';
|
||||
|
||||
export const LogFileListHandler: RequestHandler = async (req, res) => {
|
||||
res.send({
|
||||
|
@@ -33,6 +33,7 @@ export const QQCheckLoginStatusHandler: RequestHandler = async (req, res) => {
|
||||
message: 'success',
|
||||
data: {
|
||||
isLogin: await WebUiDataRuntime.getQQLoginStatus(),
|
||||
qrcodeurl: await WebUiDataRuntime.getQQLoginQrcodeURL()
|
||||
},
|
||||
});
|
||||
};
|
||||
|
Reference in New Issue
Block a user