Compare commits

...
31 Commits
Author SHA1 Message Date
手瓜一十雪 2c3b7e9ee8 fix: fuck! tencent
Build Action / Build-LiteLoader (push) Canceled after 0s
Build Action / Build-Shell (push) Canceled after 0s
Build Release / check-version (push) Canceled after 0s
Build Release / Build-LiteLoader (push) Canceled after 0s
Build Release / Build-Shell (push) Canceled after 0s
Build Release / release-napcat (push) Canceled after 0s
2024-12-13 19:28:04 +08:00
手瓜一十雪 b86a28092a fix: Login Check 2024-12-13 17:38:27 +08:00
手瓜一十雪 d59e5f2133 fix 2024-12-13 16:45:35 +08:00
手瓜一十雪 3fdd187102 fix: #610 2024-12-13 14:29:11 +08:00
Mlikiowa 3f085fd8ae release: v4.2.29 2024-12-13 04:47:13 +00:00
手瓜一十雪 a4fc131aec feat: 全平台30594
Build Release / check-version (push) Canceled after 0s
Build Release / Build-LiteLoader (push) Canceled after 0s
Build Release / Build-Shell (push) Canceled after 0s
Build Release / release-napcat (push) Canceled after 0s
Build Action / Build-LiteLoader (push) Canceled after 0s
Build Action / Build-Shell (push) Canceled after 0s
2024-12-13 12:36:51 +08:00
手瓜一十雪 d7d446c3fc fix 2024-12-12 23:02:10 +08:00
手瓜一十雪 212666e603 fix 2024-12-12 18:41:46 +08:00
手瓜一十雪 b545c28340 feat: 30483全平台兼容 2024-12-12 16:57:50 +08:00
手瓜一十雪 72bc345515 feat: linux 3.2.15-30483 2024-12-12 16:53:31 +08:00
手瓜一十雪 cc5082a9e3 feat: mac 6.9.62-30483 2024-12-12 11:43:31 +08:00
手瓜一十雪 45782a6c6c chore: docs 2024-12-12 10:44:09 +08:00
手瓜一十雪 e86d646cce chore: 万里妹妹干坏事 2024-12-12 10:43:13 +08:00
手瓜一十雪 92cfc6b8c8 feat: 更换演示代码 2024-12-12 10:00:38 +08:00
手瓜一十雪 82289d9f1f chore: debug log remove 2024-12-12 09:57:52 +08:00
手瓜一十雪 4cdbdaaf4e feat: win 30483 2024-12-12 09:47:44 +08:00
手瓜一十雪 ecde2427da fix: path 2024-12-12 09:37:51 +08:00
手瓜一十雪 fed1ec5d83 Merge pull request #620 from NapNeko/plugin-support
Feat: 支持快速基于NapCat进行二次开发 不需要通过传统NetWork
2024-12-12 09:34:27 +08:00
手瓜一十雪 4fbd764ced fix 2024-12-12 09:34:13 +08:00
手瓜一十雪 5361079010 Merge pull request #616 from Ander-pixe/webui-new
fix:路由守卫
2024-12-12 09:33:23 +08:00
手瓜一十雪 002d135ef5 fix 2024-12-11 18:26:26 +08:00
手瓜一十雪 a39b0a4a78 feat: plugin 2024-12-11 17:07:21 +08:00
纸凤孤凰 eb5d68422f fix: 路由守卫 2024-12-10 16:59:57 +08:00
纸凤孤凰 3dc13e5c2e Merge remote-tracking branch 'origin/main' into webui-new 2024-12-10 15:29:27 +08:00
huankong233 16881f057a fix: solve the token error
fix: remove useless defineProps
fix: add the missing dependencies to package.json
fix: add ES2022 into tsconfig.json
2024-12-10 09:44:38 +08:00
手瓜一十雪 1cd7d0577f fix: error 2024-12-10 09:44:23 +08:00
Mlikiowa 3c872df97a release: v4.2.28 2024-12-08 14:37:51 +00:00
pk5ls20 218b7bd2a0 fix: #607
Build Release / check-version (push) Canceled after 0s
Build Release / Build-LiteLoader (push) Canceled after 0s
Build Release / Build-Shell (push) Canceled after 0s
Build Release / release-napcat (push) Canceled after 0s
Build Action / Build-LiteLoader (push) Canceled after 0s
Build Action / Build-Shell (push) Canceled after 0s
2024-12-08 22:23:01 +08:00
Mlikiowa 4552d6970d release: v4.2.27 2024-12-06 03:40:03 +00:00
手瓜一十雪 4b319d15a7 refactor: GetGroupInfo
Build Release / check-version (push) Canceled after 0s
Build Release / Build-LiteLoader (push) Canceled after 0s
Build Release / Build-Shell (push) Canceled after 0s
Build Release / release-napcat (push) Canceled after 0s
Build Action / Build-LiteLoader (push) Canceled after 0s
Build Action / Build-Shell (push) Canceled after 0s
2024-12-06 11:39:11 +08:00
Mlikiowa 0ae3a4172c release: v4.2.26 2024-12-06 02:40:53 +00:00
36 changed files with 421 additions and 85 deletions

No files matched your search

+8 -3
View File
@@ -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 标准接口,并提供兼容性保留接口,其设计理念遵守 无数据库/异步优先/后台刷新 的性能思想。
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -4,7 +4,7 @@
"name": "NapCatQQ",
"slug": "NapCat.Framework",
"description": "高性能的 OneBot 11 协议实现",
"version": "4.2.25",
"version": "4.2.29",
"icon": "./logo.png",
"authors": [
{
+1
View File
@@ -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 -1
View File
@@ -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',
+3 -3
View File
@@ -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;
}
}
} catch (error) {
+30 -28
View File
@@ -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>
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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<{
+23 -1
View File
@@ -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;
+4 -11
View File
@@ -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
View File
@@ -2,7 +2,7 @@
"name": "napcat",
"private": true,
"type": "module",
"version": "4.2.25",
"version": "4.2.29",
"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
View File
@@ -1 +1 @@
export const napCatVersion = '4.2.25';
export const napCatVersion = '4.2.29';
+14
View File
@@ -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));
}
+24
View File
@@ -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"
}
}
+40
View File
@@ -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 {
+1 -1
View File
@@ -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>[] {
+1 -1
View File
@@ -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
@@ -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
View File
@@ -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;
+11 -1
View File
@@ -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)
})
});
+3
View File
@@ -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');
}
+1 -1
View File
@@ -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);
+6 -7
View File
@@ -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(`获取群成员详细信息失败, 只能返回基础信息`);
}
+2 -1
View File
@@ -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
View File
@@ -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));
+12 -3
View File
@@ -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';
+45
View File
@@ -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;
}
}
+10
View File
@@ -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);
}
}