mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
914136b750 | ||
![]() |
f9a60795f5 | ||
![]() |
19640927c7 | ||
![]() |
22faac7e36 | ||
![]() |
30d260ab32 | ||
![]() |
115120d066 | ||
![]() |
1327844736 | ||
![]() |
29904f3cb7 | ||
![]() |
50395594b7 | ||
![]() |
9360af88b3 | ||
![]() |
376370336c | ||
![]() |
70df6e3302 | ||
![]() |
0a1fc2dc12 | ||
![]() |
9857f6e437 | ||
![]() |
56d6ebe916 | ||
![]() |
81134ea2d4 | ||
![]() |
a9f3e7fc54 | ||
![]() |
eb84e2f8c9 |
@@ -1,21 +1,21 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf|crlf
|
||||
insert_final_newline = true
|
||||
|
||||
# Matches multiple files with brace expansion notation
|
||||
# Set default charset
|
||||
charset = utf-8
|
||||
|
||||
# 2 space indentation
|
||||
[*.{cjs,mjs,js,jsx,ts,tsx,css,scss,sass,html,json}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# Unfortunately, EditorConfig doesn't support space configuration inside import braces directly.
|
||||
# You'll need to rely on your linter/formatter like ESLint or Prettier for that.
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# Matches multiple files with brace expansion notation
|
||||
# Set default charset
|
||||
charset = utf-8
|
||||
|
||||
# 2 space indentation
|
||||
[*.{cjs,mjs,js,jsx,ts,tsx,css,scss,sass,html,json}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# Unfortunately, EditorConfig doesn't support space configuration inside import braces directly.
|
||||
# You'll need to rely on your linter/formatter like ESLint or Prettier for that.
|
||||
|
18
docs/changelogs/CHANGELOG.v1.6.5.md
Normal file
18
docs/changelogs/CHANGELOG.v1.6.5.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# v1.6.5
|
||||
|
||||
QQ Version: Windows 9.9.12-26000 / Linux 3.2.9-26000
|
||||
## 使用前警告
|
||||
1. 在最近版本由于QQ本体大幅变动,为了保证NapCat可用性,NapCat近期启动与安装方式将将大幅变动,请关注文档和社群获取。
|
||||
2. 在Core上完全执行开源,请不要用于违法用途,如此可能造成NapCat完全停止更新。
|
||||
3. 针对原启动方式的围堵,NapCat研发了多种方式,除此其余理论与扩展的分析和思路将部分展示于Docs,以便各位参与开发与维护NapCat。
|
||||
## 其余·备注
|
||||
启动方式: WayBoot.03 (Electron Main进程为Node 直接注入代码 同理项目: LiteLoader)
|
||||
|
||||
## 修复与优化
|
||||
1. 优化了WrapperNative载入代码
|
||||
2. 优化缓存
|
||||
|
||||
## 新增与调整
|
||||
没有哦
|
||||
|
||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
@@ -2,7 +2,7 @@
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "1.6.4",
|
||||
"version": "1.6.5",
|
||||
"scripts": {
|
||||
"watch:dev": "vite --mode development",
|
||||
"watch:prod": "vite --mode production",
|
||||
|
28
script/NapCat.164.bat
Normal file
28
script/NapCat.164.bat
Normal file
@@ -0,0 +1,28 @@
|
||||
@echo off
|
||||
chcp 65001
|
||||
:: 检查是否有管理员权限
|
||||
net session >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo 请求管理员权限...
|
||||
powershell -Command "Start-Process '%~f0' -Verb runAs"
|
||||
exit /b
|
||||
)
|
||||
:: 如果有管理员权限,继续执行
|
||||
setlocal enabledelayedexpansion
|
||||
:loop_read
|
||||
for /f "tokens=2*" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" /v "UninstallString"') do (
|
||||
set "RetString=%%b"
|
||||
goto :napcat_boot
|
||||
)
|
||||
|
||||
:napcat_boot
|
||||
for %%a in ("!RetString!") do (
|
||||
set "pathWithoutUninstall=%%~dpa"
|
||||
)
|
||||
|
||||
set "QQPath=!pathWithoutUninstall!QQ.exe"
|
||||
|
||||
echo !QQPath!
|
||||
"!QQPath!" --enable-logging %*
|
||||
|
||||
pause
|
@@ -1,4 +1,3 @@
|
||||
import { NodeIKernelMsgListener } from '@/core';
|
||||
import { NodeIQQNTWrapperSession } from '@/core/wrapper';
|
||||
import { randomUUID } from 'crypto';
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { logError, logDebug } from '@/common/utils/log';
|
||||
import { logError, logDebug } from "@/common/utils/log";
|
||||
|
||||
type group_id = number;
|
||||
type user_id = number;
|
||||
@@ -31,7 +31,7 @@ class LRU<T> {
|
||||
private tail: cacheNode<T> | null = null;
|
||||
private onFuncs: ((node: cacheNode<T>) => void)[] = [];
|
||||
|
||||
constructor(maxAge: number = 2e4, maxSize: number = 5e3) {
|
||||
constructor(maxAge: number = 6e4, maxSize: number = 5e3) {
|
||||
this.maxAge = maxAge;
|
||||
this.maxSize = maxSize;
|
||||
this.cache = Object.create(null);
|
||||
@@ -44,7 +44,7 @@ class LRU<T> {
|
||||
// 移除LRU节点
|
||||
private removeLRUNode(node: cacheNode<T>) {
|
||||
logDebug(
|
||||
'removeLRUNode',
|
||||
"removeLRUNode",
|
||||
node.groupId,
|
||||
node.userId,
|
||||
node.value,
|
||||
@@ -140,6 +140,26 @@ class LRU<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
public get(groupId: group_id): { userId: user_id; value: T }[];
|
||||
public get(groupId: group_id, userId: user_id): null | { userId: user_id; value: T };
|
||||
public get(groupId: group_id, userId?: user_id): any {
|
||||
const groupObject = this.cache[groupId];
|
||||
if(!groupObject) return userId === undefined ? [] : null;
|
||||
|
||||
if (userId === undefined) {
|
||||
return Object.entries(groupObject).map(([userId, { value }]) => ({
|
||||
userId: Number(userId),
|
||||
value,
|
||||
}));
|
||||
}
|
||||
|
||||
if (groupObject[userId]) {
|
||||
return { userId, value: groupObject[userId].value };
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export default LRU;
|
||||
|
@@ -408,10 +408,12 @@ class DBUtil extends DBUtilBase {
|
||||
logDebug('读取发言时间', groupId);
|
||||
return new Promise<IRember[]>((resolve, reject) => {
|
||||
this.db!.all(`SELECT * FROM "${groupId}" `, (err, rows: IRember[]) => {
|
||||
const cache = this.LURCache.get(groupId).map(e=>({user_id:e.userId, last_sent_time:e.value}));
|
||||
if (err) {
|
||||
logError('查询发言时间失败', groupId);
|
||||
return resolve([]);
|
||||
return resolve(cache.map(e=>({...e, join_time:0})));
|
||||
}
|
||||
Object.assign(rows, cache)
|
||||
logDebug('查询发言时间成功', groupId, rows);
|
||||
resolve(rows);
|
||||
});
|
||||
|
@@ -160,7 +160,12 @@ export async function httpDownload(options: string | HttpDownloadOptions): Promi
|
||||
}
|
||||
}
|
||||
}
|
||||
const fetchRes = await fetch(url, { headers });
|
||||
const fetchRes = await fetch(url, { headers }).catch((err) => {
|
||||
if (err.cause) {
|
||||
throw err.cause;
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
if (!fetchRes.ok) throw new Error(`下载文件失败: ${fetchRes.statusText}`);
|
||||
|
||||
const blob = await fetchRes.blob();
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { ModifyProfileParams, SelfInfo, User, UserDetailInfoByUin } from '@/core/entities';
|
||||
import { selfInfo } from '@/core/data';
|
||||
import { friends, selfInfo } from '@/core/data';
|
||||
import { CacheClassFuncAsync } from '@/common/utils/helper';
|
||||
import { GeneralCallResult, napCatCore } from '@/core';
|
||||
import { GeneralCallResult, napCatCore, NTQQFriendApi } from '@/core';
|
||||
import { ProfileListener } from '@/core/listeners';
|
||||
import { rejects } from 'assert';
|
||||
import { randomUUID } from 'crypto';
|
||||
@@ -170,7 +170,30 @@ export class NTQQUserApi {
|
||||
5000,
|
||||
[Uin]
|
||||
);
|
||||
return ret.uidInfo.get(Uin);
|
||||
let uid = ret.uidInfo.get(Uin); //通过QQ默认方式转换
|
||||
if (!uid) {
|
||||
Array.from(friends.values()).forEach((t) => {
|
||||
if (t.uin == Uin) {
|
||||
//logDebug('getUidByUin', t.uid, t.uin, Uin);
|
||||
uid = t.uid;
|
||||
}
|
||||
//console.log(t.uid, t.uin, Uin);
|
||||
});
|
||||
//uid = Array.from(friends.values()).find((t) => { t.uin == Uin })?.uid; // 从NC维护的QQ Buddy缓存 转换
|
||||
}
|
||||
if (!uid) {
|
||||
uid = (await NTQQFriendApi.getFriends(false)).find((t) => { t.uin == Uin })?.uid; //从QQ Native 缓存转换 方法一
|
||||
}
|
||||
if (!uid) {
|
||||
uid = (await NTQQFriendApi.getFriends(true)).find((t) => { t.uin == Uin })?.uid; //从QQ Native 非缓存转换 方法二
|
||||
}
|
||||
if (!uid) {
|
||||
let unveifyUid = (await NTQQUserApi.getUserDetailInfoByUin(Uin)).info.uid;//从QQ Native 特殊转换 方法三
|
||||
if (unveifyUid.indexOf("*") == -1) {
|
||||
uid = unveifyUid;
|
||||
}
|
||||
}
|
||||
return uid;
|
||||
}
|
||||
static async getUinByUid(Uid: string | undefined) {
|
||||
if (!Uid) {
|
||||
|
@@ -171,7 +171,7 @@ export interface NodeIQQNTWrapperSession {
|
||||
getTicketService(): NodeIKernelTicketService;
|
||||
|
||||
getTipOffService(): NodeIKernelTipOffService;
|
||||
|
||||
|
||||
getNodeMiscService(): NodeIKernelNodeMiscService;
|
||||
|
||||
getRichMediaService(): NodeIKernelRichMediaService;
|
||||
@@ -286,11 +286,7 @@ let wrapperNodePath = path.resolve(path.dirname(process.execPath), './resources/
|
||||
if (!fs.existsSync(wrapperNodePath)) {
|
||||
wrapperNodePath = path.join(path.dirname(process.execPath), `resources/app/versions/${qqVersionConfigInfo.curVersion}/wrapper.node`);
|
||||
}
|
||||
let WrapperLoader = path.join(__dirname, "WrapperLoader.cjs");
|
||||
//此处待优化
|
||||
fs.writeFileSync(WrapperLoader, `
|
||||
module.exports = require("${wrapperNodePath.replace(/\\/g, "\\\\")}");
|
||||
exports = module.exports;
|
||||
`)
|
||||
const QQWrapper: WrapperNodeApi = (await import("file://" + WrapperLoader)).default;
|
||||
const nativemodule: any = { exports: {} };
|
||||
process.dlopen(nativemodule, wrapperNodePath);
|
||||
const QQWrapper: WrapperNodeApi = nativemodule.exports;
|
||||
export default QQWrapper;
|
||||
|
@@ -1,2 +0,0 @@
|
||||
//统一到处入口
|
||||
export * from './main';
|
@@ -1,29 +0,0 @@
|
||||
enum NapCatCorePlatform {
|
||||
Node = 'Node',//命令行模式加载
|
||||
LiteLoader = 'LiteLoader',//LL插件模式加载
|
||||
}
|
||||
class NewNapCatCore {
|
||||
platform: NapCatCorePlatform; // 平台
|
||||
constructor(platform: NapCatCorePlatform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
}
|
||||
export class NapCatCoreManger {
|
||||
static core: NewNapCatCore | undefined = undefined;
|
||||
static defaultPlatform: NapCatCorePlatform = NapCatCorePlatform.Node;
|
||||
static SetDefaultCore(platform: NapCatCorePlatform) {
|
||||
if (this.core !== undefined) {
|
||||
return;
|
||||
}
|
||||
this.defaultPlatform = platform;
|
||||
}
|
||||
static GetPlatform(): NapCatCorePlatform {
|
||||
return NapCatCoreManger.defaultPlatform;
|
||||
}
|
||||
static GetInstance(): NewNapCatCore {
|
||||
if (this.core === undefined) {
|
||||
this.core = new NewNapCatCore(NapCatCoreManger.defaultPlatform);
|
||||
}
|
||||
return this.core;
|
||||
}
|
||||
}
|
@@ -1 +0,0 @@
|
||||
//拦截proxy到会话
|
@@ -1 +0,0 @@
|
||||
//初始化跟之前一样
|
@@ -1 +0,0 @@
|
||||
//proxy封装工具类
|
@@ -102,6 +102,7 @@ async function createContext(payload: OB11PostSendMsg, contextMode: ContextMode)
|
||||
if ((contextMode === ContextMode.Private || contextMode === ContextMode.Normal) && payload.user_id) {
|
||||
const Uid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
|
||||
const isBuddy = await NTQQFriendApi.isBuddy(Uid!);
|
||||
//console.log("[调试代码] UIN:", payload.user_id, " UID:", Uid, " IsBuddy:", isBuddy);
|
||||
return {
|
||||
peer: {
|
||||
chatType: isBuddy ? ChatType.friend : ChatType.temp,
|
||||
|
@@ -1 +1 @@
|
||||
export const version = '1.6.4';
|
||||
export const version = '1.6.5';
|
||||
|
@@ -29,7 +29,7 @@ async function onSettingWindowCreated(view: Element) {
|
||||
SettingItem(
|
||||
'<span id="napcat-update-title">Napcat</span>',
|
||||
undefined,
|
||||
SettingButton('V1.6.4', 'napcat-update-button', 'secondary')
|
||||
SettingButton('V1.6.5', 'napcat-update-button', 'secondary')
|
||||
),
|
||||
]),
|
||||
SettingList([
|
||||
|
@@ -167,7 +167,7 @@ async function onSettingWindowCreated(view) {
|
||||
SettingItem(
|
||||
'<span id="napcat-update-title">Napcat</span>',
|
||||
void 0,
|
||||
SettingButton("V1.6.4", "napcat-update-button", "secondary")
|
||||
SettingButton("V1.6.5", "napcat-update-button", "secondary")
|
||||
)
|
||||
]),
|
||||
SettingList([
|
||||
|
Reference in New Issue
Block a user