Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f0a4131a2 | ||
|
|
aa520e2f5d | ||
|
|
2c3b7e9ee8 | ||
|
|
b86a28092a | ||
|
|
d59e5f2133 | ||
|
|
3fdd187102 | ||
|
|
3f085fd8ae | ||
|
|
a4fc131aec | ||
|
|
d7d446c3fc | ||
|
|
212666e603 | ||
|
|
b545c28340 | ||
|
|
72bc345515 | ||
|
|
cc5082a9e3 | ||
|
|
45782a6c6c | ||
|
|
e86d646cce | ||
|
|
92cfc6b8c8 | ||
|
|
82289d9f1f | ||
|
|
4cdbdaaf4e | ||
|
|
ecde2427da | ||
|
|
fed1ec5d83 | ||
|
|
4fbd764ced | ||
|
|
5361079010 | ||
|
|
002d135ef5 | ||
|
|
a39b0a4a78 | ||
|
|
eb5d68422f | ||
|
|
3dc13e5c2e | ||
|
|
16881f057a | ||
|
|
1cd7d0577f | ||
|
|
3c872df97a | ||
|
|
218b7bd2a0 | ||
|
|
4552d6970d | ||
|
|
4b319d15a7 | ||
|
|
0ae3a4172c |
No files matched your search
@@ -30,11 +30,16 @@ NapCatQQ 是现代化的基于 NTQQ 的 Bot 协议端实现
|
||||
|
||||
[Cloudflare.Pages](https://napneko.pages.dev/)
|
||||
|
||||
[Server.Other](https://napcat.cyou/)
|
||||
|
||||
[Server.Other](https://docs.napcat.cyou/)
|
||||
|
||||
## 回家旅途
|
||||
[QQ Group](https://qm.qq.com/q/I6LU87a0Yq)
|
||||
[QQ Group#1](https://qm.qq.com/q/I6LU87a0Yq)
|
||||
|
||||
[QQ Group#2](https://qm.qq.com/q/uqh4I87KoM)
|
||||
|
||||
[Telegram](https://t.me/MelodicMoonlight)
|
||||
|
||||
> QQ Group#2 准许Bot / Telegram与QQ Group#2 为新建Group
|
||||
|
||||
## 性能设计/协议标准
|
||||
NapCat 已实现90%+的 OneBot / GoCQ 标准接口,并提供兼容性保留接口,其设计理念遵守 无数据库/异步优先/后台刷新 的性能思想。
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -4,7 +4,7 @@
|
||||
"name": "NapCatQQ",
|
||||
"slug": "NapCat.Framework",
|
||||
"description": "高性能的 OneBot 11 协议实现",
|
||||
"version": "4.2.25",
|
||||
"version": "4.2.30",
|
||||
"icon": "./logo.png",
|
||||
"authors": [
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"dependencies": {
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"event-source-polyfill": "^1.0.31",
|
||||
"mitt": "^3.0.1",
|
||||
"qrcode": "^1.5.4",
|
||||
"tdesign-icons-vue-next": "^0.3.3",
|
||||
"tdesign-vue-next": "^1.10.3",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export class githubApiManager {
|
||||
public async GetBaseData(): Promise<Response | null> {
|
||||
try {
|
||||
const ConfigResponse= await fetch('https://api.github.com/repos/NapNeko/NapCatQQ', {
|
||||
const ConfigResponse = await fetch('https://api.github.com/repos/NapNeko/NapCatQQ', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { OneBotConfig } from '../../../src/onebot/config/config';
|
||||
|
||||
import { ResponseCode } from '../../../src/webui/src/const/status';
|
||||
export class QQLoginManager {
|
||||
private retCredential: string;
|
||||
private readonly apiPrefix: string;
|
||||
@@ -22,8 +22,8 @@ export class QQLoginManager {
|
||||
});
|
||||
if (ConfigResponse.status == 200) {
|
||||
const ConfigResponseJson = await ConfigResponse.json();
|
||||
if (ConfigResponseJson.code == 0) {
|
||||
return ConfigResponseJson?.data as OneBotConfig;
|
||||
if (ConfigResponseJson.code == ResponseCode.Success) {
|
||||
return ConfigResponseJson.data;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -4,31 +4,17 @@
|
||||
<h2 class="sotheby-font">QQ Login</h2>
|
||||
<div class="login-methods">
|
||||
<t-tooltip content="快速登录">
|
||||
<t-button
|
||||
id="quick-login"
|
||||
class="login-method"
|
||||
:class="{ active: loginMethod === 'quick' }"
|
||||
@click="loginMethod = 'quick'"
|
||||
>Quick Login</t-button
|
||||
>
|
||||
<t-button id="quick-login" class="login-method" :class="{ active: loginMethod === 'quick' }"
|
||||
@click="loginMethod = 'quick'">Quick Login</t-button>
|
||||
</t-tooltip>
|
||||
<t-tooltip content="二维码登录">
|
||||
<t-button
|
||||
id="qrcode-login"
|
||||
class="login-method"
|
||||
:class="{ active: loginMethod === 'qrcode' }"
|
||||
@click="loginMethod = 'qrcode'"
|
||||
>QR Code</t-button
|
||||
>
|
||||
<t-button id="qrcode-login" class="login-method" :class="{ active: loginMethod === 'qrcode' }"
|
||||
@click="loginMethod = 'qrcode'">QR Code</t-button>
|
||||
</t-tooltip>
|
||||
</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>
|
||||
@@ -41,7 +27,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
|
||||
import * as QRCode from 'qrcode';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { MessagePlugin } from 'tdesign-vue-next';
|
||||
@@ -55,6 +41,7 @@ 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) {
|
||||
@@ -88,10 +75,6 @@ const HeartBeat = async (): Promise<void> => {
|
||||
if (heartBeatTimer) {
|
||||
clearInterval(heartBeatTimer);
|
||||
}
|
||||
// //判断是否已经调转
|
||||
// if (router.currentRoute.value.path !== '/dashboard/basic-info') {
|
||||
// return;
|
||||
// }
|
||||
await MessagePlugin.success('登录成功即将跳转');
|
||||
await router.push({ path: '/dashboard/basic-info' });
|
||||
} else if (isLogined?.qrcodeurl && qrcodeUrl !== isLogined.qrcodeurl) {
|
||||
@@ -103,19 +86,38 @@ const HeartBeat = async (): Promise<void> => {
|
||||
const InitPages = async (): Promise<void> => {
|
||||
quickLoginList.value = await qqLoginManager.getQQQuickLoginList();
|
||||
qrcodeUrl = await qqLoginManager.getQQLoginQrcode();
|
||||
await nextTick();
|
||||
generateQrCode(qrcodeUrl, qrcodeCanvas.value);
|
||||
heartBeatTimer = window.setInterval(HeartBeat, 3000);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
InitPages();
|
||||
InitPages().then().catch((err) => {
|
||||
console.error('InitPages Error:', err);
|
||||
});
|
||||
heartBeatTimer = window.setInterval(HeartBeat, 3000);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (heartBeatTimer) {
|
||||
clearInterval(heartBeatTimer);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
watch(loginMethod, async (newMethod) => {
|
||||
if (newMethod === 'qrcode') {
|
||||
await nextTick();
|
||||
generateQrCode(qrcodeUrl, qrcodeCanvas.value);
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.layout {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
@@ -182,4 +184,4 @@ onMounted(() => {
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
@@ -33,7 +33,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, defineProps, onMounted, watch } from 'vue';
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import emitter from '@/ts/event-bus';
|
||||
|
||||
type MenuItem = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<t-head-menu theme="light" class="bottom-menu">
|
||||
<t-head-menu theme="light" class="bottom-menu">
|
||||
<router-link v-for="item in menuItems" :key="item.value" :to="item.route">
|
||||
<t-tooltip :content="item.label" placement="top">
|
||||
<t-menu-item :value="item.value" :disabled="item.disabled" class="menu-item">
|
||||
@@ -7,15 +7,13 @@
|
||||
<t-icon :name="item.icon" />
|
||||
</template>
|
||||
|
||||
<!-- {{item.label}}-->
|
||||
<!-- {{item.label}}-->
|
||||
</t-menu-item>
|
||||
</t-tooltip>
|
||||
</router-link>
|
||||
</t-head-menu>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from 'vue';
|
||||
|
||||
type MenuItem = {
|
||||
value: string;
|
||||
label: string;
|
||||
|
||||
@@ -46,7 +46,7 @@ import {
|
||||
Loading as TLoading,
|
||||
HeadMenu as THeadMenu
|
||||
} from 'tdesign-vue-next';
|
||||
import { router } from './router';
|
||||
import router from './router';
|
||||
import 'tdesign-vue-next/es/style/index.css';
|
||||
const app = createApp(App);
|
||||
app.use(router);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps, ref, watch } from 'vue';
|
||||
import { ref, watch } from 'vue';
|
||||
import { HttpClientConfig } from '../../../../src/onebot/config/config';
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps, ref, watch } from 'vue';
|
||||
import { ref, watch } from 'vue';
|
||||
import { HttpServerConfig } from '../../../../src/onebot/config/config';
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps, ref, watch } from 'vue';
|
||||
import { ref, watch } from 'vue';
|
||||
import { WebsocketClientConfig } from '../../../../src/onebot/config/config';
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps, ref, watch } from 'vue';
|
||||
import { ref, watch } from 'vue';
|
||||
import { WebsocketServerConfig } from '../../../../src/onebot/config/config';
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -7,6 +7,8 @@ import NetWork from '../pages/NetWork.vue';
|
||||
import QQLogin from '../components/QQLogin.vue';
|
||||
import WebUiLogin from '../components/WebUiLogin.vue';
|
||||
import OtherConfig from '../pages/OtherConfig.vue';
|
||||
import { MessagePlugin } from 'tdesign-vue-next';
|
||||
import { QQLoginManager } from '@/backend/shell';
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{ path: '/', redirect: '/webui' },
|
||||
@@ -26,7 +28,27 @@ const routes: Array<RouteRecordRaw> = [
|
||||
},
|
||||
];
|
||||
|
||||
export const router = createRouter({
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
});
|
||||
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
const isPublicRoute = ['/webui', '/qqlogin'].includes(to.path);
|
||||
const token = localStorage.getItem('auth');
|
||||
|
||||
if (!isPublicRoute) {
|
||||
if (!token) {
|
||||
MessagePlugin.error('请先登录');
|
||||
return next('/webui');
|
||||
}
|
||||
const login = await new QQLoginManager(token).checkWebUiLogined();
|
||||
if (!login) {
|
||||
MessagePlugin.error('请先登录');
|
||||
return next('/webui');
|
||||
}
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -3,22 +3,15 @@
|
||||
"target": "ESNext",
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "vue",
|
||||
"lib": [
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
||||
"baseUrl": ".",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
"@/*": ["src/*"]
|
||||
},
|
||||
"resolveJsonModule": true,
|
||||
"types": [
|
||||
"vite/client"
|
||||
],
|
||||
"types": ["vite/client"],
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"noUnusedLocals": true,
|
||||
@@ -30,5 +23,5 @@
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules"],
|
||||
"references": [{"path": "./tsconfig.node.json"}]
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "4.2.25",
|
||||
"version": "4.2.30",
|
||||
"scripts": {
|
||||
"build:universal": "npm run build:webui && vite build --mode universal || exit 1",
|
||||
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const napCatVersion = '4.2.25';
|
||||
export const napCatVersion = '4.2.30';
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
MemberExtSourceType,
|
||||
NapCatCore,
|
||||
GroupNotify,
|
||||
GroupInfoSource,
|
||||
} from '@/core';
|
||||
import { isNumeric, solveAsyncProblem } from '@/common/helper';
|
||||
import { LimitedHashTable } from '@/common/message-unique';
|
||||
@@ -24,6 +25,19 @@ export class NTQQGroupApi {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
async fetchGroupDetail(groupCode: string) {
|
||||
let [, detailInfo] = await this.core.eventWrapper.callNormalEventV2(
|
||||
'NodeIKernelGroupService/getGroupDetailInfo',
|
||||
'NodeIKernelGroupListener/onGroupDetailInfoChange',
|
||||
[groupCode, GroupInfoSource.KDATACARD],
|
||||
(ret) => ret.result === 0,
|
||||
(detailInfo) => detailInfo.groupCode === groupCode,
|
||||
1,
|
||||
5000
|
||||
);
|
||||
return detailInfo;
|
||||
}
|
||||
|
||||
async initApi() {
|
||||
this.initCache().then().catch(e => this.context.logger.logError(e));
|
||||
}
|
||||
|
||||
Vendored
+24
@@ -110,5 +110,29 @@
|
||||
"6.9.62-30366": {
|
||||
"appid": 537258401,
|
||||
"qua": "V1_MAC_NQ_6.9.62_30366_GW_B"
|
||||
},
|
||||
"9.9.17-30483": {
|
||||
"appid": 537258439,
|
||||
"qua": "V1_WIN_NQ_9.9.17_30483_GW_B"
|
||||
},
|
||||
"6.9.62-30483": {
|
||||
"appid": 537258463,
|
||||
"qua": "V1_MAC_NQ_6.9.62_30483_GW_B"
|
||||
},
|
||||
"3.2.15-30483": {
|
||||
"appid": 537258474,
|
||||
"qua": "V1_LNX_NQ_3.2.15_30483_GW_B"
|
||||
},
|
||||
"9.9.17-30594": {
|
||||
"appid": 537258439,
|
||||
"qua": "V1_WIN_NQ_9.9.17_30594_GW_B"
|
||||
},
|
||||
"6.9.62-30594": {
|
||||
"appid": 537258463,
|
||||
"qua": "V1_MAC_NQ_6.9.62_30594_GW_B"
|
||||
},
|
||||
"3.2.15-30594": {
|
||||
"appid": 537258474,
|
||||
"qua": "V1_LNX_NQ_3.2.15_30594_GW_B"
|
||||
}
|
||||
}
|
||||
Vendored
+40
@@ -122,5 +122,45 @@
|
||||
"6.9.62-30366-arm64": {
|
||||
"send": "4189770",
|
||||
"recv": "418BF88"
|
||||
},
|
||||
"9.9.17-30483-x64": {
|
||||
"send": "39AC1B0",
|
||||
"recv": "39B05E4"
|
||||
},
|
||||
"6.9.62-30483-arm64": {
|
||||
"send": "41896B0",
|
||||
"recv": "418bec8"
|
||||
},
|
||||
"6.9.62-30483-x64": {
|
||||
"send": "4669460",
|
||||
"recv": "466BCCC"
|
||||
},
|
||||
"3.2.15-30483-x64": {
|
||||
"send": "A402540",
|
||||
"recv": "A405E40"
|
||||
},
|
||||
"3.2.15-30483-arm64": {
|
||||
"send": "70C40E8",
|
||||
"recv": "70C7920"
|
||||
},
|
||||
"9.9.17-30594-x64": {
|
||||
"send": "39AC1B0",
|
||||
"recv": "39B05E4"
|
||||
},
|
||||
"6.9.62-30594-arm64": {
|
||||
"send": "41896B0",
|
||||
"recv": "418bec8"
|
||||
},
|
||||
"6.9.62-30594-x64": {
|
||||
"send": "4669460",
|
||||
"recv": "466BCCC"
|
||||
},
|
||||
"3.2.15-30594-x64": {
|
||||
"send": "A402540",
|
||||
"recv": "A405E40"
|
||||
},
|
||||
"3.2.15-30594-arm64": {
|
||||
"send": "70C40E8",
|
||||
"recv": "70C7920"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DataSource, Group, GroupListUpdateType, GroupMember, GroupNotify, ShutUpGroupMember } from '@/core/types';
|
||||
import { DataSource, Group, GroupDetailInfo, GroupListUpdateType, GroupMember, GroupNotify, ShutUpGroupMember } from '@/core/types';
|
||||
|
||||
export class NodeIKernelGroupListener {
|
||||
onGroupListInited(listEmpty: boolean): any { }
|
||||
@@ -28,7 +28,7 @@ export class NodeIKernelGroupListener {
|
||||
onGroupConfMemberChange(...args: unknown[]): any {
|
||||
}
|
||||
|
||||
onGroupDetailInfoChange(...args: unknown[]): any {
|
||||
onGroupDetailInfoChange(detailInfo: GroupDetailInfo): any {
|
||||
}
|
||||
|
||||
onGroupExtListUpdate(...args: unknown[]): any {
|
||||
|
||||
@@ -124,7 +124,7 @@ export class PacketMsgReplyElement extends IPacketMsgElement<SendReplyElement> {
|
||||
}
|
||||
|
||||
get isGroupReply(): boolean {
|
||||
return this.messageClientSeq !== 0;
|
||||
return this.messageClientSeq === 0;
|
||||
}
|
||||
|
||||
buildElement(): NapProtoEncodeStructType<typeof Elem>[] {
|
||||
|
||||
@@ -149,7 +149,7 @@ export interface NodeIKernelGroupService {
|
||||
|
||||
getGroupExtList(force: boolean): Promise<GeneralCallResult>;
|
||||
|
||||
getGroupDetailInfo(groupCode: string, groupInfoSource: GroupInfoSource): Promise<unknown>;
|
||||
getGroupDetailInfo(groupCode: string, groupInfoSource: GroupInfoSource): Promise<GeneralCallResult>;
|
||||
|
||||
getMemberExtInfo(param: GroupExtParam): Promise<unknown>;//req
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { GeneralCallResult } from '@/core/services/common';
|
||||
import { MsgReqType, QueryMsgsParams, TmpChatInfoApi } from '@/core/types/msg';
|
||||
|
||||
export interface NodeIKernelMsgService {
|
||||
buildMultiForwardMsg(req: { srcMsgIds: Array<string>, srcContact: Peer }): Promise<GeneralCallResult & { rspInfo: { elements: unknown } }>;
|
||||
|
||||
generateMsgUniqueId(chatType: number, time: string): string;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ export interface NodeIKernelSearchService {
|
||||
penetrate: string
|
||||
}): Promise<GeneralCallResult>;// needs 1 arguments
|
||||
|
||||
searchLocalInfo(keywords: string, unknown: number/*4*/): unknown;
|
||||
searchLocalInfo(keywords: string, type: number/*4*/): unknown;
|
||||
|
||||
cancelSearchLocalInfo(...args: any[]): unknown;// needs 3 arguments
|
||||
|
||||
|
||||
+154
-1
@@ -17,7 +17,160 @@ export enum GroupInfoSource {
|
||||
KRECENTCONTACT,
|
||||
KMOREPANEL
|
||||
}
|
||||
|
||||
export interface GroupDetailInfo {
|
||||
groupCode: string;
|
||||
groupUin: string;
|
||||
ownerUid: string;
|
||||
ownerUin: string;
|
||||
groupFlag: number;
|
||||
groupFlagExt: number;
|
||||
maxMemberNum: number;
|
||||
memberNum: number;
|
||||
groupOption: number;
|
||||
classExt: number;
|
||||
groupName: string;
|
||||
fingerMemo: string;
|
||||
groupQuestion: string;
|
||||
certType: number;
|
||||
richFingerMemo: string;
|
||||
tagRecord: any[];
|
||||
shutUpAllTimestamp: number;
|
||||
shutUpMeTimestamp: number;
|
||||
groupTypeFlag: number;
|
||||
privilegeFlag: number;
|
||||
groupSecLevel: number;
|
||||
groupFlagExt3: number;
|
||||
isConfGroup: number;
|
||||
isModifyConfGroupFace: number;
|
||||
isModifyConfGroupName: number;
|
||||
groupFlagExt4: number;
|
||||
groupMemo: string;
|
||||
cmdUinMsgSeq: number;
|
||||
cmdUinJoinTime: number;
|
||||
cmdUinUinFlag: number;
|
||||
cmdUinMsgMask: number;
|
||||
groupSecLevelInfo: number;
|
||||
cmdUinPrivilege: number;
|
||||
cmdUinFlagEx2: number;
|
||||
appealDeadline: number;
|
||||
remarkName: string;
|
||||
isTop: boolean;
|
||||
groupFace: number;
|
||||
groupGeoInfo: {
|
||||
ownerUid: string;
|
||||
SetTime: number;
|
||||
CityId: number;
|
||||
Longitude: string;
|
||||
Latitude: string;
|
||||
GeoContent: string;
|
||||
poiId: string;
|
||||
};
|
||||
certificationText: string;
|
||||
cmdUinRingtoneId: number;
|
||||
longGroupName: string;
|
||||
autoAgreeJoinGroupUserNumForConfGroup: number;
|
||||
autoAgreeJoinGroupUserNumForNormalGroup: number;
|
||||
cmdUinFlagExt3Grocery: number;
|
||||
groupCardPrefix: {
|
||||
introduction: string;
|
||||
rptPrefix: any[];
|
||||
};
|
||||
groupExt: {
|
||||
groupInfoExtSeq: number;
|
||||
reserve: number;
|
||||
luckyWordId: string;
|
||||
lightCharNum: number;
|
||||
luckyWord: string;
|
||||
starId: number;
|
||||
essentialMsgSwitch: number;
|
||||
todoSeq: number;
|
||||
blacklistExpireTime: number;
|
||||
isLimitGroupRtc: number;
|
||||
companyId: number;
|
||||
hasGroupCustomPortrait: number;
|
||||
bindGuildId: string;
|
||||
groupOwnerId: {
|
||||
memberUin: string;
|
||||
memberUid: string;
|
||||
memberQid: string;
|
||||
};
|
||||
essentialMsgPrivilege: number;
|
||||
msgEventSeq: string;
|
||||
inviteRobotSwitch: number;
|
||||
gangUpId: string;
|
||||
qqMusicMedalSwitch: number;
|
||||
showPlayTogetherSwitch: number;
|
||||
groupFlagPro1: string;
|
||||
groupBindGuildIds: {
|
||||
guildIds: any[];
|
||||
};
|
||||
viewedMsgDisappearTime: string;
|
||||
groupExtFlameData: {
|
||||
switchState: number;
|
||||
state: number;
|
||||
dayNums: any[];
|
||||
version: number;
|
||||
updateTime: string;
|
||||
isDisplayDayNum: boolean;
|
||||
};
|
||||
groupBindGuildSwitch: number;
|
||||
groupAioBindGuildId: string;
|
||||
groupExcludeGuildIds: {
|
||||
guildIds: any[];
|
||||
};
|
||||
fullGroupExpansionSwitch: number;
|
||||
fullGroupExpansionSeq: string;
|
||||
inviteRobotMemberSwitch: number;
|
||||
inviteRobotMemberExamine: number;
|
||||
groupSquareSwitch: number;
|
||||
};
|
||||
msgLimitFrequency: number;
|
||||
hlGuildAppid: number;
|
||||
hlGuildSubType: number;
|
||||
isAllowRecallMsg: number;
|
||||
confUin: string;
|
||||
confMaxMsgSeq: number;
|
||||
confToGroupTime: number;
|
||||
groupSchoolInfo: {
|
||||
location: string;
|
||||
grade: number;
|
||||
school: string;
|
||||
};
|
||||
activeMemberNum: number;
|
||||
groupGrade: number;
|
||||
groupCreateTime: number;
|
||||
subscriptionUin: string;
|
||||
subscriptionUid: string;
|
||||
noFingerOpenFlag: number;
|
||||
noCodeFingerOpenFlag: number;
|
||||
isGroupFreeze: number;
|
||||
allianceId: string;
|
||||
groupExtOnly: {
|
||||
tribeId: number;
|
||||
moneyForAddGroup: number;
|
||||
};
|
||||
isAllowConfGroupMemberModifyGroupName: number;
|
||||
isAllowConfGroupMemberNick: number;
|
||||
isAllowConfGroupMemberAtAll: number;
|
||||
groupClassText: string;
|
||||
groupFreezeReason: number;
|
||||
headPortraitSeq: number;
|
||||
groupHeadPortrait: {
|
||||
portraitCnt: number;
|
||||
portraitInfo: any[];
|
||||
defaultId: number;
|
||||
verifyingPortraitCnt: number;
|
||||
verifyingPortraitInfo: any[];
|
||||
};
|
||||
cmdUinJoinMsgSeq: number;
|
||||
cmdUinJoinRealMsgSeq: number;
|
||||
groupAnswer: string;
|
||||
groupAdminMaxNum: number;
|
||||
inviteNoAuthNumLimit: string;
|
||||
hlGuildOrgId: number;
|
||||
isAllowHlGuildBinary: number;
|
||||
localExitGroupReason: number;
|
||||
}
|
||||
export interface GroupExt0xEF0InfoFilter {
|
||||
bindGuildId: number;
|
||||
blacklistExpireTime: number;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//LiteLoader需要提供部分IPC接口,以便于其他插件调用
|
||||
const { ipcMain } = require('electron');
|
||||
const { ipcMain, BrowserWindow } = require('electron');
|
||||
const napcat = require('./napcat.cjs');
|
||||
const { shell } = require('electron');
|
||||
ipcMain.handle('napcat_get_webtoken', async (event, arg) => {
|
||||
@@ -13,4 +13,14 @@ ipcMain.handle('napcat_get_reactweb', async (event, arg) => {
|
||||
let port = url.port;
|
||||
let token = url.searchParams.get('token');
|
||||
return `https://napcat.152710.xyz/web_login?back=http://127.0.0.1:${port}&token=${token}`;
|
||||
});
|
||||
|
||||
ipcMain.on('napcat_open_inner_url', (event, url) => {
|
||||
const win = new BrowserWindow({
|
||||
autoHideMenuBar: true,
|
||||
});
|
||||
win.loadURL(url);
|
||||
win.webContents.setWindowOpenHandler(details => {
|
||||
win.loadURL(details.url)
|
||||
})
|
||||
});
|
||||
@@ -6,6 +6,9 @@ const napcat = {
|
||||
openExternalUrl: async (url) => {
|
||||
ipcRenderer.send('open_external_url', url);
|
||||
},
|
||||
openInnerUrl: async (url) => {
|
||||
ipcRenderer.send('napcat_open_inner_url', url);
|
||||
},
|
||||
getWebUiUrlReact: async () => {
|
||||
return ipcRenderer.invoke('napcat_get_reactweb');
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ export const onSettingWindowCreated = async (view) => {
|
||||
`;
|
||||
|
||||
view.querySelector('.nc_openwebui').addEventListener('click', () => {
|
||||
window.open(webui, '_blank');
|
||||
window.napcat.openInnerUrl(webui);
|
||||
});
|
||||
view.querySelector('.nc_openwebui_ex').addEventListener('click', () => {
|
||||
window.napcat.openExternalUrl(webui);
|
||||
|
||||
@@ -17,15 +17,14 @@ class GetGroupInfo extends OneBotAction<Payload, OB11Group> {
|
||||
async _handle(payload: Payload) {
|
||||
const group = (await this.core.apis.GroupApi.getGroups()).find(e => e.groupCode == payload.group_id.toString());
|
||||
if (!group) {
|
||||
const data = await this.core.apis.GroupApi.searchGroup(payload.group_id.toString());
|
||||
if (!data) throw new Error('Group not found');
|
||||
const data = await this.core.apis.GroupApi.fetchGroupDetail(payload.group_id.toString());
|
||||
return {
|
||||
...data.searchGroupInfo,
|
||||
...data,
|
||||
group_id: +payload.group_id,
|
||||
group_name: data.searchGroupInfo.groupName,
|
||||
member_count: data.searchGroupInfo.memberNum,
|
||||
max_member_count: data.searchGroupInfo.maxMemberNum,
|
||||
};
|
||||
group_name: data.groupName,
|
||||
member_count: data.memberNum,
|
||||
max_member_count: data.maxMemberNum,
|
||||
}
|
||||
}
|
||||
return OB11Construct.group(group);
|
||||
}
|
||||
|
||||
@@ -29,13 +29,14 @@ class GetGroupMemberInfo extends OneBotAction<Payload, OB11GroupMember> {
|
||||
async _handle(payload: Payload) {
|
||||
const isNocache = this.parseBoolean(payload.no_cache ?? true);
|
||||
const uid = await this.getUid(payload.user_id);
|
||||
const [member, info] = await Promise.all([
|
||||
const groupMember = this.core.apis.GroupApi.groupMemberCache.get(payload.group_id.toString())?.get(uid);
|
||||
let [member, info] = await Promise.all([
|
||||
this.core.apis.GroupApi.getGroupMemberEx(payload.group_id.toString(), uid, isNocache),
|
||||
this.core.apis.UserApi.getUserDetailInfo(uid),
|
||||
]);
|
||||
if (!member) throw new Error(`群(${payload.group_id})成员${payload.user_id}不存在`);
|
||||
if (!member || !groupMember) throw new Error(`群(${payload.group_id})成员${payload.user_id}不存在`);
|
||||
if (info) {
|
||||
Object.assign(member, info);
|
||||
member = { ...groupMember, ...member, ...info };
|
||||
} else {
|
||||
this.core.context.logger.logDebug(`获取群成员详细信息失败, 只能返回基础信息`);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ interface v1Config {
|
||||
export interface AdapterConfigInner {
|
||||
name: string;
|
||||
enable: boolean;
|
||||
|
||||
}
|
||||
export type AdapterConfigWrap = AdapterConfigInner & Partial<NetworkConfigAdapter>;
|
||||
|
||||
@@ -127,7 +128,7 @@ export const mergeNetworkDefaultConfig = {
|
||||
websocketClients: websocketClientDefaultConfigs,
|
||||
} as const;
|
||||
|
||||
export type NetworkConfigAdapter = HttpServerConfig | HttpClientConfig | WebsocketServerConfig | WebsocketClientConfig;
|
||||
export type NetworkConfigAdapter = HttpServerConfig | HttpClientConfig | WebsocketServerConfig | WebsocketClientConfig | AdapterConfig;
|
||||
type NetworkConfigKeys = keyof typeof mergeNetworkDefaultConfig;
|
||||
|
||||
export function mergeOneBotConfigs(
|
||||
|
||||
+9
-3
@@ -47,6 +47,7 @@ import { NodeIKernelRecentContactListener } from '@/core/listeners/NodeIKernelRe
|
||||
import { BotOfflineEvent } from './event/notice/BotOfflineEvent';
|
||||
import { AdapterConfigWrap, mergeOneBotConfigs, migrateOneBotConfigsV1, NetworkConfigAdapter, OneBotConfig } from './config/config';
|
||||
import { OB11Message } from './types';
|
||||
import { OB11PluginAdapter } from './network/plugin';
|
||||
|
||||
//OneBot实现类
|
||||
export class NapCatOneBot11Adapter {
|
||||
@@ -106,7 +107,12 @@ export class NapCatOneBot11Adapter {
|
||||
const serviceInfo = await this.creatOneBotLog(ob11Config);
|
||||
this.context.logger.log(`[Notice] [OneBot11] ${serviceInfo}`);
|
||||
|
||||
// //创建NetWork服务
|
||||
//创建NetWork服务
|
||||
|
||||
// 注册Plugin 如果需要基于NapCat进行快速开发
|
||||
// this.networkManager.registerAdapter(
|
||||
// new OB11PluginAdapter('plugin', this.core, this,this.actions)
|
||||
// );
|
||||
for (const key of ob11Config.network.httpServers) {
|
||||
if (key.enable) {
|
||||
this.networkManager.registerAdapter(
|
||||
@@ -443,7 +449,7 @@ export class NapCatOneBot11Adapter {
|
||||
}
|
||||
|
||||
private async emitMsg(message: RawMessage) {
|
||||
const network = Object.values(this.configLoader.configData.network).flat() as Array<AdapterConfigWrap>;
|
||||
const network = await this.networkManager.getAllConfig();
|
||||
this.context.logger.logDebug('收到新消息 RawMessage', message);
|
||||
await Promise.allSettled([
|
||||
this.handleMsg(message, network),
|
||||
@@ -483,7 +489,7 @@ export class NapCatOneBot11Adapter {
|
||||
ob11Msg.stringMsg.target_id = parseInt(message.peerUin);
|
||||
ob11Msg.arrayMsg.target_id = parseInt(message.peerUin);
|
||||
}
|
||||
if (e.messagePostFormat == 'string') {
|
||||
if ('messagePostFormat' in e && e.messagePostFormat == 'string') {
|
||||
msgMap.set(e.name, structuredClone(ob11Msg.stringMsg));
|
||||
} else {
|
||||
msgMap.set(e.name, structuredClone(ob11Msg.arrayMsg));
|
||||
|
||||
@@ -34,7 +34,11 @@ export class OB11NetworkManager {
|
||||
}
|
||||
|
||||
async emitEvent(event: OB11EmitEventContent) {
|
||||
return Promise.all(Array.from(this.adapters.values()).map(adapter => adapter.onEvent(event)));
|
||||
return Promise.all(Array.from(this.adapters.values()).map(adapter => {
|
||||
if (adapter.isEnable) {
|
||||
return adapter.onEvent(event);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
async emitEvents(events: OB11EmitEventContent[]) {
|
||||
@@ -44,19 +48,21 @@ export class OB11NetworkManager {
|
||||
async emitEventByName(names: string[], event: OB11EmitEventContent) {
|
||||
return Promise.all(names.map(name => {
|
||||
const adapter = this.adapters.get(name);
|
||||
if (adapter) {
|
||||
if (adapter && adapter.isEnable) {
|
||||
return adapter.onEvent(event);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
async emitEventByNames(map: Map<string, OB11EmitEventContent>) {
|
||||
return Promise.all(Array.from(map.entries()).map(([name, event]) => {
|
||||
const adapter = this.adapters.get(name);
|
||||
if (adapter) {
|
||||
if (adapter && adapter.isEnable) {
|
||||
return adapter.onEvent(event);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
registerAdapter(adapter: IOB11NetworkAdapter) {
|
||||
this.adapters.set(adapter.name, adapter);
|
||||
}
|
||||
@@ -104,6 +110,9 @@ export class OB11NetworkManager {
|
||||
async readloadSomeAdapters<T>(configMap: Map<string, T>) {
|
||||
await Promise.all(Array.from(configMap.entries()).map(([name, config]) => this.readloadAdapter(name, config)));
|
||||
}
|
||||
async getAllConfig() {
|
||||
return Array.from(this.adapters.values()).map(adapter => adapter.config);
|
||||
}
|
||||
}
|
||||
|
||||
export * from './active-http';
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { IOB11NetworkAdapter, OB11EmitEventContent, OB11NetworkReloadType } from './index';
|
||||
import { NapCatOneBot11Adapter, OB11Message } from '@/onebot';
|
||||
import { NapCatCore } from '@/core';
|
||||
import { ActionMap } from '../action';
|
||||
import { AdapterConfig } from '../config/config';
|
||||
import { plugin_onmessage } from '@/plugin';
|
||||
|
||||
export class OB11PluginAdapter implements IOB11NetworkAdapter {
|
||||
isEnable: boolean = true;
|
||||
public config: AdapterConfig;
|
||||
|
||||
constructor(
|
||||
public name: string,
|
||||
public core: NapCatCore,
|
||||
public obCore: NapCatOneBot11Adapter,
|
||||
public actions: ActionMap,
|
||||
) {
|
||||
// 基础配置
|
||||
this.config = {
|
||||
name: name,
|
||||
messagePostFormat: 'array',
|
||||
reportSelfMessage: false,
|
||||
enable: true,
|
||||
debug: false,
|
||||
}
|
||||
}
|
||||
|
||||
onEvent<T extends OB11EmitEventContent>(event: T) {
|
||||
if (event.post_type === 'message') {
|
||||
plugin_onmessage(this.config.name, this.core, this.obCore, event as OB11Message).then().catch();
|
||||
}
|
||||
}
|
||||
|
||||
open() {
|
||||
|
||||
}
|
||||
|
||||
async close() {
|
||||
|
||||
}
|
||||
|
||||
async reload() {
|
||||
return OB11NetworkReloadType.Normal;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { NapCatOneBot11Adapter, OB11Message } from "@/onebot";
|
||||
import { NapCatCore } from "../core";
|
||||
import { SetSpecialTittle } from "@/onebot/action/extends/SetSpecialTittle";
|
||||
|
||||
export const plugin_onmessage = async (adapter: string, core: NapCatCore, obCore: NapCatOneBot11Adapter, message: OB11Message) => {
|
||||
if (message.raw_message.startsWith('设置头衔') && message.group_id) {
|
||||
const ret = await new SetSpecialTittle(obCore, core)
|
||||
.handle({ group_id: message.group_id, user_id: message.user_id, special_title: message.raw_message.replace('设置头衔', '') }, adapter);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user