mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b6e392fdb2 | ||
![]() |
2280e83aa2 | ||
![]() |
f49b94edb9 | ||
![]() |
2428a12221 | ||
![]() |
9c353f3760 | ||
![]() |
5b86d25d7f | ||
![]() |
2b168e8bbc | ||
![]() |
537db32847 | ||
![]() |
498b7f9f2b | ||
![]() |
9935568597 | ||
![]() |
467003af8c | ||
![]() |
4c9edcc47b | ||
![]() |
24bf9cf121 | ||
![]() |
e06f6f39a9 | ||
![]() |
98ee0c307b | ||
![]() |
5e53ea0bc3 | ||
![]() |
847d88ea77 | ||
![]() |
d5046cc2b3 | ||
![]() |
3ad64b7cbb | ||
![]() |
0dbfe8ca55 | ||
![]() |
91b794d66d | ||
![]() |
0d65e1e314 | ||
![]() |
2d8f58c6d8 | ||
![]() |
65888fa816 | ||
![]() |
857e882c6e | ||
![]() |
add2931834 | ||
![]() |
cdda5f45ee | ||
![]() |
5f73d6a913 |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "qq-chat",
|
||||
"version": "9.9.15-28060",
|
||||
"version": "9.9.15-28131",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"description": "QQ",
|
||||
@@ -15,7 +15,7 @@
|
||||
"qd": "externals/devtools/cli/index.js"
|
||||
},
|
||||
"main": "./loadNapCat.js",
|
||||
"buildVersion": "28060",
|
||||
"buildVersion": "28131",
|
||||
"isPureShell": true,
|
||||
"isByteCodeShell": true,
|
||||
"platform": "win32",
|
||||
|
@@ -4,7 +4,7 @@
|
||||
"name": "NapCatQQ",
|
||||
"slug": "NapCat.Framework",
|
||||
"description": "高性能的 OneBot 11 协议实现",
|
||||
"version": "2.6.6",
|
||||
"version": "2.6.11",
|
||||
"icon": "./logo.png",
|
||||
"authors": [
|
||||
{
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "2.6.6",
|
||||
"version": "2.6.11",
|
||||
"scripts": {
|
||||
"build:framework": "vite build --mode framework",
|
||||
"build:shell": "vite build --mode shell",
|
||||
@@ -52,4 +52,4 @@
|
||||
"strtok3": "8.0.1",
|
||||
"ws": "^8.18.0"
|
||||
}
|
||||
}
|
||||
}
|
@@ -180,11 +180,11 @@ export function getDefaultQQVersionConfigInfo(): QQVersionConfigType {
|
||||
};
|
||||
}
|
||||
return {
|
||||
baseVersion: '9.9.15-28060',
|
||||
curVersion: '9.9.15-28060',
|
||||
baseVersion: '9.9.15-28131',
|
||||
curVersion: '9.9.15-28131',
|
||||
prevVersion: '',
|
||||
onErrorVersions: [],
|
||||
buildId: '28060',
|
||||
buildId: '28131',
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -1,12 +1,8 @@
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { networkInterfaces } from 'os';
|
||||
import { randomUUID } from 'crypto';
|
||||
|
||||
// 缓解Win7设备兼容性问题
|
||||
let osName: string;
|
||||
// 设备ID
|
||||
let machineId: Promise<string>;
|
||||
|
||||
try {
|
||||
osName = os.hostname();
|
||||
@@ -14,54 +10,6 @@ try {
|
||||
osName = 'NapCat'; // + crypto.randomUUID().substring(0, 4);
|
||||
}
|
||||
|
||||
const invalidMacAddresses = new Set([
|
||||
'00:00:00:00:00:00',
|
||||
'ff:ff:ff:ff:ff:ff',
|
||||
'ac:de:48:00:11:22',
|
||||
]);
|
||||
|
||||
function validateMacAddress(candidate: string): boolean {
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
const tempCandidate = candidate.replace(/\-/g, ':').toLowerCase();
|
||||
return !invalidMacAddresses.has(tempCandidate);
|
||||
}
|
||||
|
||||
export async function getMachineId(): Promise<string> {
|
||||
if (!machineId) {
|
||||
machineId = (async () => {
|
||||
const id = await getMacMachineId();
|
||||
return id ?? randomUUID(); // fallback, generate a UUID
|
||||
})();
|
||||
}
|
||||
|
||||
return machineId;
|
||||
}
|
||||
|
||||
export function getMac(): string {
|
||||
const ifaces = networkInterfaces();
|
||||
for (const name in ifaces) {
|
||||
const networkInterface = ifaces[name];
|
||||
if (networkInterface) {
|
||||
for (const { mac } of networkInterface) {
|
||||
if (validateMacAddress(mac)) {
|
||||
return mac;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('Unable to retrieve mac address (unexpected format)');
|
||||
}
|
||||
|
||||
async function getMacMachineId(): Promise<string | undefined> {
|
||||
try {
|
||||
const crypto = await import('crypto');
|
||||
const macAddress = getMac();
|
||||
return crypto.createHash('sha256').update(macAddress, 'utf8').digest('hex');
|
||||
} catch (err) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const homeDir = os.homedir();
|
||||
|
||||
|
@@ -1 +1 @@
|
||||
export const napCatVersion = '2.6.6';
|
||||
export const napCatVersion = '2.6.11';
|
||||
|
@@ -1,14 +1,15 @@
|
||||
export interface IdMusicSignPostData {
|
||||
type: 'qq' | '163',
|
||||
type: 'qq' | '163' | 'kugou' | 'migu' | 'kuwo',
|
||||
id: string | number,
|
||||
}
|
||||
|
||||
export interface CustomMusicSignPostData {
|
||||
type: 'custom',
|
||||
type: 'qq' | '163' | 'kugou' | 'migu' | 'kuwo' | 'custom',
|
||||
id: undefined,
|
||||
url: string,
|
||||
audio: string,
|
||||
title: string,
|
||||
image?: string,
|
||||
audio?: string,
|
||||
title?: string,
|
||||
image: string,
|
||||
singer?: string
|
||||
}
|
||||
|
||||
|
14
src/core/external/appid.json
vendored
14
src/core/external/appid.json
vendored
@@ -1,10 +1,18 @@
|
||||
{
|
||||
"9.9.15-28060":{
|
||||
"9.9.15-28060": {
|
||||
"appid": 537246092,
|
||||
"qua": "V1_WIN_NQ_9.9.15_28060_GW_B"
|
||||
},
|
||||
"3.2.12-28060":{
|
||||
"9.9.15-28131": {
|
||||
"appid": 537246092,
|
||||
"qua": "V1_WIN_NQ_9.9.15_28131_GW_B"
|
||||
},
|
||||
"3.2.12-28060": {
|
||||
"appid": 537246140,
|
||||
"qua": "V1_LNX_NQ_3.2.12_28060_GW_B"
|
||||
},
|
||||
"3.2.12-28131": {
|
||||
"appid": 537246140,
|
||||
"qua": "V1_LNX_NQ_3.2.12_28131_GW_B"
|
||||
}
|
||||
}
|
||||
}
|
@@ -22,7 +22,7 @@ import { QQBasicInfoWrapper } from '@/common/qq-basic-info';
|
||||
import { NapCatPathWrapper } from '@/common/path';
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import { getMachineId, hostname, systemName, systemVersion } from '@/common/system';
|
||||
import { hostname, systemName, systemVersion } from '@/common/system';
|
||||
import { NTEventWrapper } from '@/common/event';
|
||||
import { DataSource, GroupMember, KickedOffLineInfo, SelfInfo, SelfStatusInfo } from '@/core/entities';
|
||||
import { NapCatConfigLoader } from '@/core/helper/config';
|
||||
@@ -247,10 +247,16 @@ export class NapCatCore {
|
||||
}
|
||||
}
|
||||
|
||||
export async function genSessionConfig(QQVersionAppid: string, QQVersion: string, selfUin: string, selfUid: string, account_path: string): Promise<WrapperSessionInitConfig> {
|
||||
export async function genSessionConfig(
|
||||
guid:string,
|
||||
QQVersionAppid: string,
|
||||
QQVersion: string,
|
||||
selfUin: string,
|
||||
selfUid: string,
|
||||
account_path: string
|
||||
): Promise<WrapperSessionInitConfig> {
|
||||
const downloadPath = path.join(account_path, 'NapCat', 'temp');
|
||||
fs.mkdirSync(downloadPath, { recursive: true });
|
||||
const guid: string = await getMachineId();//26702 支持JS获取guid值 在LoginService中获取 TODO mlikiow a
|
||||
//os.platform()
|
||||
let systemPlatform = PlatformType.KWINDOWS;
|
||||
switch (os.platform()) {
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { NodeIKernelLoginListener } from '@/core/listeners/NodeIKernelLoginListener';
|
||||
import { GeneralCallResult } from './common';
|
||||
|
||||
export interface LoginInitConfig {
|
||||
machineId: '';
|
||||
@@ -59,6 +60,9 @@ export interface QuickLoginResult {
|
||||
}
|
||||
|
||||
export interface NodeIKernelLoginService {
|
||||
setLoginMiscData(arg0: string, value: string): unknown;
|
||||
getMachineGuid(): string;
|
||||
|
||||
get(): NodeIKernelLoginService;
|
||||
|
||||
connect(): boolean;
|
||||
@@ -69,7 +73,7 @@ export interface NodeIKernelLoginService {
|
||||
|
||||
initConfig(config: LoginInitConfig): void;
|
||||
|
||||
getLoginMiscData(cb: (r: unknown) => void): void;
|
||||
getLoginMiscData(data: string): Promise<GeneralCallResult & { value: string }>;
|
||||
|
||||
getLoginList(): Promise<{
|
||||
result: number, // 0是ok
|
||||
|
@@ -1,6 +1,8 @@
|
||||
import { GeneralCallResult } from './common';
|
||||
|
||||
export interface NodeIKernelNodeMiscService {
|
||||
writeVersionToRegistry(version: string): void;
|
||||
|
||||
getMiniAppPath(): unknown;
|
||||
|
||||
setMiniAppVersion(version: string): unknown;
|
||||
|
@@ -4,14 +4,14 @@ export interface NodeIKernelUnitedConfigService {
|
||||
|
||||
removeKernelUnitedConfigListener(listenerId:number): void;
|
||||
|
||||
fetchUnitedCommendConfig(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
fetchUnitedSwitchConfig(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
loadUnitedConfig(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
isUnitedConfigSwitchOn(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
registerUnitedConfigPushGroupList(...args: any[]): unknown;// needs 1 arguments
|
||||
|
||||
fetchUnitedCommendConfig(ids: `${string}`[]): void
|
||||
|
||||
loadUnitedConfig(id: string): Promise<unknown>
|
||||
|
||||
}
|
||||
|
@@ -6,4 +6,6 @@ export interface NodeIO3MiscService {
|
||||
addO3MiscListener(listeners: NodeIO3MiscListener): number;
|
||||
|
||||
setAmgomDataPiece(appid: string, dataPiece: Uint8Array): void;
|
||||
|
||||
reportAmgomWeather(type: string, uk2: string, arg: Array<string>): void;
|
||||
}
|
||||
|
@@ -421,6 +421,10 @@ export class OneBotMsgApi {
|
||||
// 从face_config.json中获取表情名称
|
||||
const sysFaces = faceConfig.sysface;
|
||||
const face: any = sysFaces.find((systemFace) => systemFace.QSid === parsedFaceId.toString());
|
||||
if (!face) {
|
||||
this.core.context.logger.logError('不支持的ID', id);
|
||||
return undefined;
|
||||
}
|
||||
parsedFaceId = parseInt(parsedFaceId.toString());
|
||||
let faceType = 1;
|
||||
if (parsedFaceId >= 222) {
|
||||
@@ -543,32 +547,28 @@ export class OneBotMsgApi {
|
||||
|
||||
[OB11MessageDataType.music]: async ({ data }, context) => {
|
||||
// 保留, 直到...找到更好的解决方案
|
||||
if (data.type === 'custom') {
|
||||
if (data.id !== undefined) {
|
||||
if (!['qq', '163', 'kugou', 'kuwo', 'migu'].includes(data.type)) {
|
||||
this.core.context.logger.logError('音乐卡片type错误, 只支持qq、163、kugou、kuwo、migu,当前type:', data.type);
|
||||
return undefined;
|
||||
}
|
||||
} else {
|
||||
if (!['qq', '163', 'kugou', 'kuwo', 'migu', 'custom'].includes(data.type)) {
|
||||
this.core.context.logger.logError('音乐卡片type错误, 只支持qq、163、kugou、kuwo、migu、custom,当前type:', data.type);
|
||||
return undefined;
|
||||
}
|
||||
if (!data.url) {
|
||||
this.core.context.logger.logError('自定义音卡缺少参数url');
|
||||
return undefined;
|
||||
}
|
||||
if (!data.audio) {
|
||||
this.core.context.logger.logError('自定义音卡缺少参数audio');
|
||||
return undefined;
|
||||
}
|
||||
if (!data.title) {
|
||||
this.core.context.logger.logError('自定义音卡缺少参数title');
|
||||
return undefined;
|
||||
}
|
||||
} else {
|
||||
if (!['qq', '163'].includes(data.type)) {
|
||||
this.core.context.logger.logError('音乐卡片type错误, 只支持qq、163、custom,当前type:', data.type);
|
||||
return undefined;
|
||||
}
|
||||
if (!data.id) {
|
||||
this.core.context.logger.logError('音乐卡片缺少参数id');
|
||||
if (!data.image) {
|
||||
this.core.context.logger.logError('自定义音卡缺少参数image');
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
let postData: IdMusicSignPostData | CustomMusicSignPostData;
|
||||
if (data.type === 'custom' && data.content) {
|
||||
if (data.id === undefined && data.content) {
|
||||
const { content, ...others } = data;
|
||||
postData = { singer: content, ...others };
|
||||
} else {
|
||||
@@ -576,7 +576,7 @@ export class OneBotMsgApi {
|
||||
}
|
||||
let signUrl = this.obContext.configLoader.configData.musicSignUrl;
|
||||
if (!signUrl) {
|
||||
signUrl = 'https://ss.xingzhige.com/music_card/card';//感谢思思!
|
||||
signUrl = 'https://ss.xingzhige.com/music_card/card';//感谢思思!已获思思许可 其余地方使用请自行询问
|
||||
//throw Error('音乐消息签名地址未配置');
|
||||
}
|
||||
try {
|
||||
@@ -628,18 +628,14 @@ export class OneBotMsgApi {
|
||||
return;
|
||||
}
|
||||
for (const element of msg.elements) {
|
||||
if (element.grayTipElement) {
|
||||
if (element.grayTipElement.subElementType == NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_JSON) {
|
||||
if (element.grayTipElement.jsonGrayTipElement.busiId == 1061) {
|
||||
const PokeEvent = await this.obContext.apis.FriendApi.parsePrivatePokeEvent(element.grayTipElement);
|
||||
if (PokeEvent) return PokeEvent;
|
||||
}
|
||||
if (element.grayTipElement && element.grayTipElement.subElementType == NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_JSON) {
|
||||
if (element.grayTipElement.jsonGrayTipElement.busiId == 1061) {
|
||||
const PokeEvent = await this.obContext.apis.FriendApi.parsePrivatePokeEvent(element.grayTipElement);
|
||||
if (PokeEvent) return PokeEvent;
|
||||
}
|
||||
if (element.grayTipElement.subElementType == NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_XMLMSG) {
|
||||
//好友添加成功事件
|
||||
if (element.grayTipElement.xmlElement.templId === '10229' && msg.peerUin !== '') {
|
||||
return new OB11FriendAddNoticeEvent(this.core, parseInt(msg.peerUin) || Number(await this.core.apis.UserApi.getUinByUidV2(msg.peerUid)));
|
||||
}
|
||||
//好友添加成功事件
|
||||
if (element.grayTipElement.jsonGrayTipElement.busiId == 19324 && msg.peerUid !== '') {
|
||||
return new OB11FriendAddNoticeEvent(this.core, Number(await this.core.apis.UserApi.getUinByUidV2(msg.peerUid)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -701,36 +697,46 @@ export class OneBotMsgApi {
|
||||
}
|
||||
}
|
||||
|
||||
const msgSegments = (await Promise.allSettled(msg.elements.map(
|
||||
// 处理消息段
|
||||
const msgSegments = await Promise.allSettled(msg.elements.map(
|
||||
async (element) => {
|
||||
for (const key in element) {
|
||||
if (keyCanBeParsed(key, this.rawToOb11Converters) && element[key]) {
|
||||
return await this.rawToOb11Converters[key]?.(
|
||||
const parsedElement = await this.rawToOb11Converters[key]?.(
|
||||
// eslint-disable-next-line
|
||||
// @ts-ignore
|
||||
element[key],
|
||||
msg,
|
||||
element,
|
||||
);
|
||||
// 对于 face 类型的消息,检查是否存在
|
||||
if (key === 'faceElement' && !parsedElement) {
|
||||
return null; // 如果没有找到对应的表情,返回 null
|
||||
}
|
||||
|
||||
return parsedElement;
|
||||
}
|
||||
}
|
||||
},
|
||||
))).filter(entry => {
|
||||
));
|
||||
|
||||
// 过滤掉无效的消息段
|
||||
const validSegments = msgSegments.filter(entry => {
|
||||
if (entry.status === 'fulfilled') {
|
||||
return !!entry.value;
|
||||
} else {
|
||||
this.core.context.logger.logError('消息段解析失败', entry.reason);
|
||||
return false;
|
||||
}
|
||||
}).map((entry) => (<PromiseFulfilledResult<OB11MessageData>>entry).value);
|
||||
}).map((entry) => (<PromiseFulfilledResult<OB11MessageData>>entry).value).filter(value => value != null);
|
||||
|
||||
const msgAsCQCode = msgSegments.map(msg => encodeCQCode(msg)).join('').trim();
|
||||
const msgAsCQCode = validSegments.map(msg => encodeCQCode(msg)).join('').trim();
|
||||
|
||||
if (messagePostFormat === 'string') {
|
||||
resMsg.message = msgAsCQCode;
|
||||
resMsg.raw_message = msgAsCQCode;
|
||||
} else {
|
||||
resMsg.message = msgSegments;
|
||||
resMsg.message = validSegments;
|
||||
resMsg.raw_message = msgAsCQCode;
|
||||
}
|
||||
return resMsg;
|
||||
|
@@ -52,6 +52,7 @@ export async function NCoreInitShell() {
|
||||
const engine = wrapper.NodeIQQNTWrapperEngine.get();
|
||||
//const util = wrapper.NodeQQNTWrapperUtil.get();
|
||||
const loginService = wrapper.NodeIKernelLoginService.get();
|
||||
|
||||
const session = wrapper.NodeIQQNTWrapperSession.create();
|
||||
|
||||
// from get dataPath
|
||||
@@ -90,7 +91,7 @@ export async function NCoreInitShell() {
|
||||
app_type: 4,
|
||||
app_version: basicInfoWrapper.getFullQQVesion(),
|
||||
os_version: systemVersion,
|
||||
use_xlog: true,
|
||||
use_xlog: false,
|
||||
qua: basicInfoWrapper.QQVersionQua,
|
||||
global_path_config: {
|
||||
desktopGlobalPath: dataPathGlobal,
|
||||
@@ -118,7 +119,8 @@ export async function NCoreInitShell() {
|
||||
quickLoginUin = '';
|
||||
}
|
||||
}
|
||||
|
||||
let dataTimestape = new Date().getTime().toString();
|
||||
o3Service.reportAmgomWeather('login', 'a1', [dataTimestape, '0', '0']);
|
||||
const selfInfo = await new Promise<SelfInfo>((resolve) => {
|
||||
const loginListener = new NodeIKernelLoginListener();
|
||||
let isLogined = false;
|
||||
@@ -184,7 +186,14 @@ export async function NCoreInitShell() {
|
||||
// 遍历 res.LocalLoginInfoList[x].isQuickLogin是否可以 res.LocalLoginInfoList[x].uin 转为string 加入string[] 最后遍历完成调用WebUiDataRuntime.setQQQuickLoginList
|
||||
WebUiDataRuntime.setQQQuickLoginList(res.LocalLoginInfoList.filter((item) => item.isQuickLogin).map((item) => item.uin.toString()));
|
||||
});
|
||||
|
||||
if (basicInfoWrapper.QQVersionConfig?.curVersion) {
|
||||
loginService.getLoginMiscData('hotUpdateSign').then((res) => {
|
||||
if (res.result === 0) {
|
||||
loginService.setLoginMiscData('hotUpdateSign', res.value);
|
||||
}
|
||||
});
|
||||
session.getNodeMiscService().writeVersionToRegistry(basicInfoWrapper.QQVersionConfig?.curVersion);
|
||||
}
|
||||
WebUiDataRuntime.setQuickLoginCall(async (uin: string) => {
|
||||
return await new Promise((resolve) => {
|
||||
if (uin) {
|
||||
@@ -236,10 +245,21 @@ export async function NCoreInitShell() {
|
||||
let amgomDataPiece = 'eb1fd6ac257461580dc7438eb099f23aae04ca679f4d88f53072dc56e3bb1129';
|
||||
o3Service.setAmgomDataPiece(basicInfoWrapper.QQVersionAppid, new Uint8Array(Buffer.from(amgomDataPiece, 'hex')));
|
||||
// AFTER LOGGING IN
|
||||
//99b15bdb4c984fc69d5aa1feb9aa16xx --> 99b15bdb-4c98-4fc6-9d5a-a1feb9aa16xx
|
||||
//把guid从左向右转换为guid格式 loginService.getMachineGuid()
|
||||
|
||||
let guid = loginService.getMachineGuid();
|
||||
guid = guid.slice(0, 8) + '-' + guid.slice(8, 12) + '-' + guid.slice(12, 16) + '-' + guid.slice(16, 20) + '-' + guid.slice(20);
|
||||
//console.log('guid:', guid);
|
||||
//NodeIO3MiscService/reportAmgomWeather login a6 [ '1726748166943', '184', '329' ]
|
||||
o3Service.reportAmgomWeather('login', 'a6', [dataTimestape, '184', '329']);
|
||||
// if(session.getUnitedConfigService()){
|
||||
// session.getUnitedConfigService().fetchUnitedCommendConfig([]);
|
||||
// }
|
||||
// from initSession
|
||||
await new Promise<void>(async (resolve, reject) => {
|
||||
const sessionConfig = await genSessionConfig(
|
||||
guid,
|
||||
basicInfoWrapper.QQVersionAppid!,
|
||||
basicInfoWrapper.getFullQQVesion(),
|
||||
selfInfo.uin,
|
||||
|
@@ -30,7 +30,7 @@ async function onSettingWindowCreated(view: Element) {
|
||||
SettingItem(
|
||||
'<span id="napcat-update-title">Napcat</span>',
|
||||
undefined,
|
||||
SettingButton('V2.6.6', 'napcat-update-button', 'secondary'),
|
||||
SettingButton('V2.6.11', 'napcat-update-button', 'secondary'),
|
||||
),
|
||||
]),
|
||||
SettingList([
|
||||
|
@@ -164,7 +164,7 @@ async function onSettingWindowCreated(view) {
|
||||
SettingItem(
|
||||
'<span id="napcat-update-title">Napcat</span>',
|
||||
void 0,
|
||||
SettingButton("V2.6.6", "napcat-update-button", "secondary")
|
||||
SettingButton("V2.6.11", "napcat-update-button", "secondary")
|
||||
)
|
||||
]),
|
||||
SettingList([
|
||||
|
Reference in New Issue
Block a user