Compare commits

...

1481 Commits

Author SHA1 Message Date
手瓜一十雪
feb84809ec fix: #761 2025-02-04 21:22:36 +08:00
bietiaop
a812c568e4 fix: 文件预览 2025-02-04 21:12:13 +08:00
bietiaop
11db25e355 fix: 文件预览 2025-02-04 21:08:28 +08:00
手瓜一十雪
ecd2fba629 fix: #762 2025-02-04 20:42:13 +08:00
Mlikiowa
a6763cf5a1 release: v4.5.5 2025-02-04 11:50:37 +00:00
手瓜一十雪
c9e91a9b94 fix: defalut config 2025-02-04 19:49:56 +08:00
Mlikiowa
43fb62c5bd release: v4.5.4 2025-02-04 11:35:51 +00:00
手瓜一十雪
cb8727d487 fix: reload and parse msg 2025-02-04 19:34:51 +08:00
Mlikiowa
a94e03e2fd release: v4.5.3 2025-02-04 10:16:07 +00:00
手瓜一十雪
425c3c6432 fix: 避免重复reload 2025-02-04 18:14:13 +08:00
手瓜一十雪
89b9610016 fix: 避免read异常 2025-02-04 18:13:42 +08:00
手瓜一十雪
62fe88f868 Merge pull request #760 from NapNeko/config-refactor
refactor
2025-02-04 18:09:57 +08:00
手瓜一十雪
11a7f5fade refactor 2025-02-04 18:09:30 +08:00
bietiaop
fbde997f7c style: 调整样式 2025-02-04 17:58:38 +08:00
bietiaop
26734a35ef fix: 文件下载 2025-02-04 15:31:10 +08:00
Mlikiowa
715c4ac534 release: v4.5.2 2025-02-04 06:52:11 +00:00
bietiaop
bd4b0885a1 fix: 预览 2025-02-04 14:47:38 +08:00
手瓜一十雪
e3c7af3d91 fix: 解决nonebot可能卡死问题 2025-02-04 14:42:14 +08:00
手瓜一十雪
a7ee21bfd8 fix: #757 2025-02-04 14:34:55 +08:00
手瓜一十雪
d0f51d92ac feat: tailwind css 2025-02-04 13:52:53 +08:00
手瓜一十雪
e6dc148ea2 fix: diy status问题 2025-02-04 13:44:35 +08:00
手瓜一十雪
514ab6637f feat: 全局字体优化 2025-02-04 13:37:11 +08:00
bietiaop
377794abe8 style: font & terminal
style: font & terminal
2025-02-04 13:09:00 +08:00
bietiaop
0f3251f35b fix: 字体、终端样式 2025-02-04 12:59:51 +08:00
手瓜一十雪
8002dc5bc5 fix 2025-02-04 00:16:59 +08:00
手瓜一十雪
c75a13dcf4 fix 2025-02-04 00:14:15 +08:00
Mlikiowa
91d153bb9d release: v4.5.1 2025-02-03 12:48:00 +00:00
bietiaop
b32f9fa397 feat: 文件下载/上传 2025-02-03 19:56:33 +08:00
Mlikiowa
80593730ae release: v4.4.20 2025-02-03 08:36:59 +00:00
手瓜一十雪
090d54a78d fix: typo 2025-02-03 16:36:25 +08:00
Mlikiowa
b7d1fb181c release: v4.4.19 2025-02-03 08:34:24 +00:00
手瓜一十雪
6e56693ca7 feat: 支持set_diy_online_status 2025-02-03 16:33:31 +08:00
Mlikiowa
7403db9b20 release: v4.4.18 2025-02-03 07:05:56 +00:00
手瓜一十雪
9d167cd883 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2025-02-03 15:05:16 +08:00
手瓜一十雪
197eec40ad fix 2025-02-03 15:05:12 +08:00
Mlikiowa
07819a6618 release: v4.4.17 2025-02-03 06:50:58 +00:00
手瓜一十雪
b72156866d fix: broken pipe 2025-02-03 14:50:11 +08:00
手瓜一十雪
59a7d12a8c style: lint 2025-02-03 14:29:38 +08:00
手瓜一十雪
179351b23a Merge pull request #754 from NapNeko/qrcode-refactor
fix: thumb残留
2025-02-03 14:11:22 +08:00
手瓜一十雪
790809e8e5 fix: thumb残留 2025-02-03 14:09:51 +08:00
手瓜一十雪
1414a8a8c9 Merge pull request #753 from NapNeko/qrcode-refactor
refactor: qrcode to ts
2025-02-03 14:02:48 +08:00
bietiaop
9ab41734a5 fix: piscina src 2025-02-03 13:33:18 +08:00
手瓜一十雪
03cace2ea1 优化依赖 2025-02-03 13:07:05 +08:00
手瓜一十雪
c7371ab869 refactor: qrcode to ts 2025-02-03 12:51:50 +08:00
手瓜一十雪
b32d4b618c fix: 必须清理并回收 2025-02-03 11:40:58 +08:00
手瓜一十雪
3a27f37686 fix: pcm清理 2025-02-03 11:37:39 +08:00
手瓜一十雪
fe2d21979d Merge pull request #749 from NapNeko/type-force
style: Type force
2025-02-03 11:13:55 +08:00
手瓜一十雪
48b1f3d4f0 Merge branch 'main' into type-force 2025-02-03 11:13:46 +08:00
手瓜一十雪
93ed589ac7 Merge pull request #745 from NapNeko/dev-terminal
feat: 文件管理 & 系统终端
2025-02-03 11:13:14 +08:00
手瓜一十雪
96de9e2c16 style: 简化loader 避免全局error 2025-02-03 10:40:33 +08:00
手瓜一十雪
b25f9d3bec feat: 摇树生成&多平台统一改造 2025-02-03 10:33:10 +08:00
手瓜一十雪
15854c605b style: 强类型大法 2025-02-02 23:22:21 +08:00
手瓜一十雪
ac193cc94a style: lint 2025-02-02 20:17:28 +08:00
手瓜一十雪
d626f872e6 feat: 类型规范 2025-02-02 20:16:11 +08:00
bietiaop
3eb66fa34a fix: 关闭终端启动QQ 2025-02-02 15:34:53 +08:00
bietiaop
0fdd0175b7 fix: 重复关闭 2025-02-02 15:09:38 +08:00
pk5ls20
dec9b477e0 fix: #747 2025-02-02 14:51:36 +08:00
bietiaop
a0a4b0dd1d fix: 频率限制 2025-02-02 14:47:34 +08:00
bietiaop
8dc6da56a7 fix: node-pty 2025-02-02 14:33:39 +08:00
bietiaop
b4e07aacfe chore(terminal): 使用prebuild 2025-02-02 12:59:00 +08:00
bietiaop
19b47f0f42 fix: id生成使用uuid 2025-02-02 12:00:55 +08:00
bietiaop
f9ef3d63c7 fix: id生成使用uuid 2025-02-02 11:57:28 +08:00
bietiaop
2b574d33b5 fix: 更换重命名图标防止误解 2025-02-02 11:46:04 +08:00
bietiaop
6039e9bb46 feat: 文件管理 2025-02-02 11:37:58 +08:00
手瓜一十雪
adfd4b043f docs: fix 2025-02-02 11:02:54 +08:00
bietiaop
719189be55 feat: file manager 2025-02-01 22:47:51 +08:00
bietiaop
ef9907f4b6 style: 优化样式 2025-02-01 20:51:45 +08:00
bietiaop
16b7447df1 style: 优化样式 2025-02-01 20:47:54 +08:00
bietiaop
4157746478 feat: 系统终端 2025-02-01 20:35:01 +08:00
bietiaop
5120786708 Merge branch 'dev-terminal' of https://github.com/NapNeko/NapCatQQ into dev-terminal 2025-02-01 13:44:18 +08:00
bietiaop
0176fa75ef dev: terminal 2025-02-01 13:41:20 +08:00
bietiaop
e6968f2d80 fix(webui): name重复问题 2025-02-01 11:44:30 +08:00
bietiaop
c0dd8a53e8 chore(dep): 更新依赖,移除overrides(strtok3已经修复) 2025-01-31 19:05:40 +08:00
bietiaop
3cb3135235 feat: 登录状态机 2025-01-31 18:48:46 +08:00
bietiaop
28182cac64 chore(dep): 更新webui依赖 2025-01-31 12:07:57 +08:00
bietiaop
73b80d2482 release: v4.4.16 2025-01-30 10:42:46 +08:00
bietiaop
f22eb22409 release: v4.4.16 2025-01-30 10:12:35 +08:00
bietiaop
4a95b17a47 feat(webui): 修改token 2025-01-29 22:08:45 +08:00
bietiaop
f4a71159fd fix(dep): 尝试解决peek-readable依赖问题 2025-01-29 21:34:59 +08:00
bietiaop
c0431e3dc2 feat(webui_api): update token 2025-01-29 20:40:23 +08:00
Mlikiowa
7f87cee282 release: v4.4.15 2025-01-27 11:53:31 +00:00
手瓜一十雪
c24c704439 fix: clone object 2025-01-27 19:53:03 +08:00
Mlikiowa
232e5d55b8 release: v4.4.14 2025-01-27 11:31:15 +00:00
手瓜一十雪
da24ae7e1c fix: 空json5 2025-01-27 19:30:45 +08:00
Mlikiowa
8fc13f8a8f release: v4.4.13 2025-01-27 11:26:17 +00:00
手瓜一十雪
7e1fe31085 fix: http支持json5 2025-01-27 19:25:51 +08:00
Mlikiowa
c3cba8ba4e release: v4.4.12 2025-01-27 10:44:43 +00:00
手瓜一十雪
ba619986c9 fix: #739 2025-01-27 18:42:26 +08:00
bietiaop
dcef3f3c3b fix: 终端字符宽度&微调样式&路由切换动画 2025-01-27 15:58:27 +08:00
bietiaop
823faa2790 fix: 质量检查 2025-01-26 21:58:04 +08:00
bietiaop
ef4248d2a3 fix: 依赖缺失 2025-01-26 21:52:35 +08:00
bietiaop
3917cb0dc9 feat: webui检查更新&修复日志字体渲染 2025-01-26 21:48:45 +08:00
Mlikiowa
520cec0eaa release: v4.4.11 2025-01-26 13:03:34 +00:00
手瓜一十雪
e7655e0ff6 Merge pull request #737 from NapNeko/ffmpeg
feat: no spawn ffmpeg
2025-01-26 21:02:57 +08:00
手瓜一十雪
350ced55c0 fix 2025-01-26 21:00:47 +08:00
手瓜一十雪
2ca6d0a00e feat: 移除测试代码 2025-01-26 20:44:27 +08:00
手瓜一十雪
844abad0d0 fix: 彻底完成迁移 2025-01-26 20:42:05 +08:00
手瓜一十雪
d278e9d8bc feat: ffmpeg 2025-01-26 16:26:21 +08:00
手瓜一十雪
6e261f30c2 fix: typo 2025-01-26 13:29:47 +08:00
bietiaop
84f0e43369 feat: debug 配置记忆 2025-01-26 10:44:31 +08:00
Mlikiowa
3223a06983 release: v4.4.10 2025-01-25 12:08:25 +00:00
手瓜一十雪
1b874a0264 fix: defaultHttpUrl 2025-01-25 20:00:24 +08:00
Mlikiowa
26525a0ff9 release: v4.4.9 2025-01-25 10:59:08 +00:00
手瓜一十雪
49234ea5c7 fix: music proxy 2025-01-25 18:34:11 +08:00
Mlikiowa
c474158a09 release: v4.4.8 2025-01-25 05:40:09 +00:00
bietiaop
813a541e7f fix: config首次加载 2025-01-25 13:36:56 +08:00
Mlikiowa
efd489bfd4 release: v4.4.7 2025-01-25 04:56:25 +00:00
手瓜一十雪
9c88fcb610 style: lint 2025-01-25 12:56:02 +08:00
手瓜一十雪
c1cac8de19 fix: #736 2025-01-25 12:54:39 +08:00
手瓜一十雪
b03fa54e63 fix: fonts 2025-01-25 12:40:01 +08:00
bietiaop
9785731f25 fix: 字体路径 2025-01-25 10:50:47 +08:00
手瓜一十雪
566afde18b fix 2025-01-25 10:41:15 +08:00
手瓜一十雪
bae8dabc5c fix: 兼容JSON配置 异常检查 2025-01-25 10:24:39 +08:00
手瓜一十雪
0a9dfea20a fix 2025-01-25 01:21:06 +08:00
Mlikiowa
50498aa52d release: v4.4.6 2025-01-24 16:41:07 +00:00
手瓜一十雪
cc99fa8346 fix: renderer 2025-01-25 00:37:33 +08:00
bietiaop
500c10ea7a fix: 移除部分字体 2025-01-24 22:44:18 +08:00
bietiaop
71a62caf8f fix: sse配置缺失 2025-01-24 22:36:40 +08:00
bietiaop
fe9c565ad4 fix: 字体缺失 2025-01-24 22:23:45 +08:00
手瓜一十雪
f5f915dc91 fix: 移除nc_openwebui_ex_react 2025-01-24 22:09:41 +08:00
手瓜一十雪
eba17fd9b4 Merge pull request #734 from bietiaop/main
feat: 新版webui
2025-01-24 21:56:32 +08:00
bietiaop
86f6caa714 fix: 移除统计&添加环境变量 2025-01-24 21:44:29 +08:00
手瓜一十雪
8ec5a4d071 Merge branch 'main' into pr/734 2025-01-24 21:42:49 +08:00
手瓜一十雪
eae49667ef fix: GetProfileLike 2025-01-24 21:39:53 +08:00
bietiaop
9a87b5ec1a Merge branch 'NapNeko:main' into main 2025-01-24 21:13:57 +08:00
bietiaop
ee1291e42c feat: 新版webui 2025-01-24 21:13:44 +08:00
手瓜一十雪
15aa1fd0b8 fix: NTVoteInfo type 2025-01-24 21:03:15 +08:00
手瓜一十雪
e069e0e8aa re: 移除 FetchUserProfileLike 2025-01-24 20:42:19 +08:00
手瓜一十雪
57e72c197f fix: #733 2025-01-24 20:39:52 +08:00
手瓜一十雪
1d0d25eea2 fix: re at
6b041becb0
2025-01-24 18:55:10 +08:00
手瓜一十雪
1a6194b38c fix: Schema miss 2025-01-22 15:36:49 +08:00
手瓜一十雪
22057083ce fix 2025-01-22 15:35:21 +08:00
Wesley F. Young
6b041becb0 fix: convert signed atUin into unsigned int 2025-01-22 15:31:56 +08:00
Mlikiowa
96d4a91ee9 release: v4.4.4 2025-01-22 07:13:53 +00:00
手瓜一十雪
3069900202 fix: fallback 2025-01-22 15:07:44 +08:00
pk5ls20
c46fb0f48a fix: 6.9.63 -> 6.9.65 [skip ci] 2025-01-22 14:50:48 +08:00
pk5ls20
07cd8f883e feat: 31363 2025-01-22 14:47:48 +08:00
手瓜一十雪
cfdb9d64ad fix: #722 2025-01-22 14:45:02 +08:00
Mlikiowa
b73e3aa3b7 release: v4.4.3 2025-01-22 01:35:33 +00:00
手瓜一十雪
cd315b0e71 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2025-01-22 09:33:23 +08:00
手瓜一十雪
4d4d79e66f fix #727 2025-01-22 09:33:19 +08:00
手瓜一十雪
395ce97a78 Merge pull request #726 from Caulic/main
fix: 无法修改网络配置表单值
2025-01-22 09:16:53 +08:00
Caulic
e44e8423d0 fix: 无法修改网络配置表单值 2025-01-22 01:16:35 +08:00
手瓜一十雪
fa13a56697 Merge pull request #725 from clansty/feat/face_resultId
update face list
2025-01-21 22:45:25 +08:00
Clansty
6383164aec update face list 2025-01-21 22:42:37 +08:00
Mlikiowa
d9adfad1c0 release: v4.4.2 2025-01-21 14:15:28 +00:00
手瓜一十雪
901828f5a6 Merge pull request #724 from clansty/feat/face_resultId
为新的接龙表情提供 resultId 和 chainCount 返回
2025-01-21 22:14:18 +08:00
Clansty
2a4b0cbc09 force resultId to string 2025-01-21 22:10:52 +08:00
Clansty
c5434efd56 为新的接龙表情提供 resultId 和 chainCount 返回 2025-01-21 22:02:35 +08:00
手瓜一十雪
b73f283095 Merge pull request #717 from NapNeko/dependabot/npm_and_yarn/file-type-20.0.0
chore(deps-dev): bump file-type from 19.6.0 to 20.0.0
2025-01-21 21:55:45 +08:00
Mlikiowa
24ef54f01c release: v4.4.1 2025-01-21 13:46:31 +00:00
手瓜一十雪
bff3b85337 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2025-01-21 21:46:08 +08:00
手瓜一十雪
811d9a7237 fix 2025-01-21 21:46:00 +08:00
Mlikiowa
a764cb8dc2 release: v4.4.0 2025-01-21 13:45:37 +00:00
手瓜一十雪
9204b9b286 fix: #723 2025-01-21 21:43:11 +08:00
手瓜一十雪
da94faa9bb fix 2025-01-21 20:41:13 +08:00
手瓜一十雪
4b53e9a895 fix: 进一步重构 2025-01-21 20:40:52 +08:00
Mlikiowa
f5db96187b release: v4.3.9 2025-01-20 09:35:55 +00:00
手瓜一十雪
857b191b03 feat: sse完全体 2025-01-20 17:35:31 +08:00
Mlikiowa
09014d1ab5 release: v4.3.8 2025-01-20 09:18:32 +00:00
手瓜一十雪
7557b71869 fix: httpSseServers DefaultConfig 2025-01-20 17:02:52 +08:00
dependabot[bot]
9c4751794f chore(deps-dev): bump file-type from 19.6.0 to 20.0.0
Bumps [file-type](https://github.com/sindresorhus/file-type) from 19.6.0 to 20.0.0.
- [Release notes](https://github.com/sindresorhus/file-type/releases)
- [Commits](https://github.com/sindresorhus/file-type/compare/v19.6.0...v20.0.0)

---
updated-dependencies:
- dependency-name: file-type
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-20 08:59:49 +00:00
Mlikiowa
d07187bd5d release: v4.3.7 2025-01-20 08:48:13 +00:00
手瓜一十雪
2c6a6ba440 fix: type 2025-01-20 16:47:06 +08:00
手瓜一十雪
4592bf7817 fix: nickname可能为null 2025-01-20 16:06:34 +08:00
Mlikiowa
afd6d450a0 release: v4.3.6 2025-01-20 06:51:29 +00:00
手瓜一十雪
b134849dcf feat: 支持文件名发送&兼容单空格问题 2025-01-20 14:51:08 +08:00
手瓜一十雪
e7d0f6d6da feat: 更合适的记录与rkey限制 2025-01-19 15:55:56 +08:00
手瓜一十雪
16a29b0127 feat: file 2025-01-19 15:47:09 +08:00
pk5ls20
1f5596ef16 Merge pull request #715 from FfmpegZZZ/main
chore:移除失效链接
2025-01-19 15:19:01 +08:00
Ffmpeg
bef05432d0 Update README.md 2025-01-19 15:10:18 +08:00
手瓜一十雪
67533d7743 docs: 已重写部分实现 2025-01-13 20:37:43 +08:00
Mlikiowa
0cc86c6348 release: v4.3.5 2025-01-13 12:36:23 +00:00
手瓜一十雪
607dd68620 refactor: 标准化与提高缓存策略 2025-01-13 20:35:52 +08:00
手瓜一十雪
7c8cbc0799 style: lint 2025-01-13 20:30:57 +08:00
手瓜一十雪
ec0c2e8c33 refactor: 大部分文件处理部分 2025-01-13 20:30:08 +08:00
手瓜一十雪
7f3dbe0552 fix: groupfile file_size 2025-01-13 19:38:29 +08:00
手瓜一十雪
0e9044e0c8 drop: umami 2025-01-13 19:32:34 +08:00
手瓜一十雪
3171640193 Merge pull request #701 from Stapxs/main
HTTP SSE 消息上报模式
2025-01-13 19:26:56 +08:00
手瓜一十雪
a56cee3485 fix: #682 2025-01-13 19:25:08 +08:00
pk5ls20
c8ee371982 feat: packet ocr 2025-01-12 10:13:12 +08:00
pk5ls20
5778daeb60 refactor: packet 2025-01-11 16:23:02 +08:00
手瓜一十雪
f51f3b9861 fix 2025-01-11 14:29:44 +08:00
Mlikiowa
44dd1a0b02 release: v4.3.4 2025-01-11 04:16:54 +00:00
pk5ls20
61a00ffcbf feat: 31245 2025-01-11 12:10:46 +08:00
pk5ls20
4b0a0f0a32 feat: #702 2025-01-10 15:23:40 +08:00
stapxs
a3088fb8bc 质量保障 2025-01-09 13:42:55 +08:00
stapxs
88fd1f9eb1 http sse 消息上报模式 2025-01-09 13:22:46 +08:00
手瓜一十雪
15156bac1e fix: log 2025-01-07 20:49:49 +08:00
Mlikiowa
a898d2e7be release: v4.3.3 2025-01-07 11:31:56 +00:00
手瓜一十雪
95b003802c fix: win 31245 2025-01-07 19:31:35 +08:00
Mlikiowa
95c9eae4ed release: v4.3.2 2025-01-07 11:30:35 +00:00
手瓜一十雪
e3814403e4 fix: #682 2025-01-07 19:28:46 +08:00
手瓜一十雪
3d16d52dd8 fix: #696 fallback 2025-01-07 18:51:04 +08:00
Mlikiowa
1ae47fffb4 release: v4.2.68 2025-01-06 13:08:43 +00:00
手瓜一十雪
4e7096b9e2 feat: offset win 31219 2025-01-06 21:08:18 +08:00
Mlikiowa
8cc9b7f6a7 release: v4.2.67 2025-01-05 02:50:38 +00:00
手瓜一十雪
fb45c1020e revert: 再也不用umami了 2025-01-05 10:49:49 +08:00
Mlikiowa
e9db4ae8f4 release: v4.2.66 2025-01-04 11:52:38 +00:00
手瓜一十雪
c46ec32bd6 fix: 简化代码 2025-01-04 13:12:04 +08:00
手瓜一十雪
c58a26ed99 fix 2025-01-04 13:06:37 +08:00
手瓜一十雪
a66f5e4971 fix 2025-01-04 13:03:29 +08:00
pk5ls20
574c8c6089 fix: SendGroupAiRecord
- smtx
2025-01-04 12:48:53 +08:00
手瓜一十雪
67afd95910 feat: getUserDetailInfoV2 2025-01-03 21:38:57 +08:00
手瓜一十雪
f7d0cb0be7 fix 2025-01-03 21:07:26 +08:00
手瓜一十雪
be9b68a0b1 feat: CancelableTask&Fallback 2025-01-03 20:46:51 +08:00
Mlikiowa
4637414af2 release: v4.2.65 2025-01-03 05:14:05 +00:00
手瓜一十雪
4bd92a72bd fix: ua agent 2025-01-03 13:09:43 +08:00
手瓜一十雪
a3be26f3e4 fix: error 2025-01-03 12:44:55 +08:00
Mlikiowa
675c906cbf release: v4.2.64 2024-12-31 14:42:17 +00:00
手瓜一十雪
6be6023236 Merge pull request #679 from wu-yafeng/main
fix #678
2024-12-31 22:41:34 +08:00
WuYafeng
42cee0d018 在没有写入权限时记录warn日志 2024-12-31 22:38:01 +08:00
WuYafeng
041f725748 Update config.ts 2024-12-31 22:25:05 +08:00
WuYafeng
0594d61631 Update config.ts 2024-12-31 22:20:34 +08:00
Mlikiowa
15cae6b765 release: v4.2.63 2024-12-31 13:52:37 +00:00
pk5ls20
b984116c35 fix: #677 2024-12-31 21:34:45 +08:00
Mlikiowa
13bda6e3f4 release: v4.2.62 2024-12-31 08:35:55 +00:00
手瓜一十雪
c0d18549d1 fix 2024-12-31 15:09:08 +08:00
手瓜一十雪
3caff72fce fix: cache trace 2024-12-31 13:10:58 +08:00
Mlikiowa
1313e9c3f4 release: v4.2.61 2024-12-30 15:59:33 +00:00
手瓜一十雪
0848d5a39e feat: clouflare 2024-12-30 23:59:09 +08:00
手瓜一十雪
7660646059 fix 2024-12-30 22:16:09 +08:00
Mlikiowa
bcd90fc744 release: v4.2.60 2024-12-30 12:48:11 +00:00
手瓜一十雪
638fc22d62 fix:error 2024-12-30 20:47:50 +08:00
手瓜一十雪
c87d365b88 fix 2024-12-30 20:42:23 +08:00
Mlikiowa
aee9602f25 release: v4.2.59 2024-12-30 12:29:33 +00:00
手瓜一十雪
976fbd0220 fix: 修复精确统计 2024-12-30 20:27:28 +08:00
手瓜一十雪
afd955d06f fix: error 2024-12-30 20:14:51 +08:00
手瓜一十雪
4d548da66b fix: console-log 2024-12-30 19:56:06 +08:00
手瓜一十雪
41b70f53d1 fix: LoginErrorCode 2024-12-30 19:29:14 +08:00
Wesley F. Young
a47a618bcd make author NapNeko in manifest.json
毕竟我已经脱离一线开发挺久了(
2024-12-30 18:40:57 +08:00
Mlikiowa
62170a30af release: v4.2.58 2024-12-30 09:56:02 +00:00
手瓜一十雪
780c5ac23c fix 2024-12-30 17:55:40 +08:00
手瓜一十雪
9fba519a5a fix 2024-12-30 17:55:13 +08:00
Mlikiowa
3cd0e7d26b release: v4.2.57 2024-12-30 09:54:40 +00:00
手瓜一十雪
a8fd6af994 Merge pull request #676 from NapNeko/dependabot/npm_and_yarn/commander-13.0.0
chore(deps-dev): bump commander from 12.1.0 to 13.0.0
2024-12-30 17:54:03 +08:00
手瓜一十雪
4000b89644 fix 2024-12-30 17:53:05 +08:00
Mlikiowa
9c00bbc0b7 release: v4.2.56 2024-12-30 08:55:36 +00:00
手瓜一十雪
a2989d3b38 fix:workname 2024-12-30 16:54:40 +08:00
Mlikiowa
fc731b60d5 release: v4.2.54 2024-12-30 08:47:57 +00:00
手瓜一十雪
193980dd4a fix: trace 2024-12-30 16:47:33 +08:00
dependabot[bot]
35427b0768 chore(deps-dev): bump commander from 12.1.0 to 13.0.0
Bumps [commander](https://github.com/tj/commander.js) from 12.1.0 to 13.0.0.
- [Release notes](https://github.com/tj/commander.js/releases)
- [Changelog](https://github.com/tj/commander.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tj/commander.js/compare/v12.1.0...v13.0.0)

---
updated-dependencies:
- dependency-name: commander
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-30 08:36:27 +00:00
Mlikiowa
73ea130e40 release: v4.2.53 2024-12-30 08:34:23 +00:00
手瓜一十雪
5667e6aaee fix 2024-12-30 16:34:01 +08:00
Mlikiowa
fbd626131d release: v4.2.52 2024-12-30 08:17:53 +00:00
手瓜一十雪
7b82444338 fix 2024-12-30 16:17:29 +08:00
Mlikiowa
8108b9f565 release: v4.2.51 2024-12-30 08:15:48 +00:00
手瓜一十雪
c6ddd00cd9 Merge pull request #675 from NapNeko/test
fix: 重写远程遥测
2024-12-30 16:14:48 +08:00
手瓜一十雪
20c0c00fa0 fixfix 2024-12-30 16:14:32 +08:00
手瓜一十雪
1f90364ba6 fix: 重写远程遥测 2024-12-30 16:10:38 +08:00
手瓜一十雪
49ea4d31a5 fix 2024-12-30 13:23:33 +08:00
Mlikiowa
dc35f1456a release: v4.2.50 2024-12-30 04:33:08 +00:00
手瓜一十雪
0ebeb90804 fix 2024-12-30 12:31:43 +08:00
手瓜一十雪
3ef5436c98 Merge pull request #673 from NapNeko/fixseq
fix: #670
2024-12-30 12:28:29 +08:00
手瓜一十雪
de7996d789 refactor: 进群入群 2024-12-30 12:27:42 +08:00
手瓜一十雪
ac52d9bae2 fix: 算了能用就行 2024-12-30 11:59:16 +08:00
手瓜一十雪
cb02df3b76 Merge pull request #672 from clansty/feat/download_file-file-proto
feat: download_file 支持 file://
2024-12-29 22:45:27 +08:00
手瓜一十雪
5fc5a6f1a6 fix: #670 2024-12-29 22:44:25 +08:00
手瓜一十雪
726a0d0394 fix 2024-12-29 22:30:33 +08:00
Clansty
6edf5345a3 chore: remove unused import 2024-12-29 22:27:41 +08:00
Clansty
242bbfdb14 chore: uriToLocalFile 2024-12-29 22:03:04 +08:00
Clansty
89e7712676 feat: download_file 支持 file:// 2024-12-29 21:41:44 +08:00
手瓜一十雪
9525786929 fix 2024-12-29 16:20:41 +08:00
Mlikiowa
72088e41a8 release: v4.2.46 2024-12-29 07:47:38 +00:00
手瓜一十雪
a3ed9ff2ef Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-12-29 15:47:18 +08:00
手瓜一十雪
ff16dc73ec fix: typo 2024-12-29 15:47:16 +08:00
Mlikiowa
2da4ef5f0f release: v4.2.45 2024-12-29 07:46:08 +00:00
手瓜一十雪
eaf481799d feat: 追踪退出 2024-12-29 15:44:37 +08:00
手瓜一十雪
1f72863aba fix: 追踪登录失败 2024-12-29 15:25:51 +08:00
Mlikiowa
6b353fd8d8 release: v4.2.44 2024-12-29 06:45:43 +00:00
手瓜一十雪
56cde4ad79 fix: #669 2024-12-29 14:44:47 +08:00
手瓜一十雪
3b86d3c632 feat: umami 统计追踪 2024-12-29 14:39:17 +08:00
Mlikiowa
4ac7a25afb release: v4.2.43 2024-12-29 04:04:55 +00:00
手瓜一十雪
8248011a12 fix: #667 2024-12-29 11:54:09 +08:00
手瓜一十雪
5f454456d2 fix: #655 #663 2024-12-29 11:47:09 +08:00
手瓜一十雪
e99a619c23 Merge pull request #665 from clansty/feat/group_name
fix: wrong notice_type sub_type
2024-12-28 21:42:14 +08:00
Clansty
1fc791bb68 fix: wrong notice_type sub_type 2024-12-28 21:40:32 +08:00
手瓜一十雪
f1d83f7c16 Merge pull request #664 from clansty/feat/group_name
feat: 群名称变更事件
2024-12-28 21:05:50 +08:00
Clansty
527bb72bcf feat: 群名称变更事件 2024-12-28 20:54:41 +08:00
手瓜一十雪
d78409fd07 Merge pull request #662 from Shua-github/main
新增send_poke
2024-12-27 15:16:11 +08:00
手瓜一十雪
d5e7e8944f feat: send_poke 2024-12-27 15:14:57 +08:00
Shua-github
fb405a5c1c all_poke替换成send_poke 2024-12-27 13:15:10 +08:00
Shua-github
a9e471deca 新增all_poke 2024-12-27 00:24:35 +08:00
Mlikiowa
9cd15ae337 release: v4.2.42 2024-12-26 12:37:35 +00:00
手瓜一十雪
8ed4cc4b0a feat: send_packet 2024-12-26 20:36:53 +08:00
Mlikiowa
a62de441cf release: v4.2.41 2024-12-26 05:31:09 +00:00
手瓜一十雪
02a8999410 Merge pull request #652 from JerryZRF/main
feat: add `get_clientkey`
2024-12-25 12:51:44 +08:00
手瓜一十雪
59c7979d69 readme: new 2024-12-25 12:28:53 +08:00
手瓜一十雪
bb7b28cd8f feat: 调整logo 2024-12-25 12:24:03 +08:00
手瓜一十雪
056497b98a Merge pull request #657 from FfmpegZZZ/main
chore:修改文档链接
2024-12-24 20:22:59 +08:00
手瓜一十雪
ac2fb032c4 Merge branch 'main' into main 2024-12-24 20:22:40 +08:00
Ffmpeg
c933bdd5d9 chore:修改链接
## 我是猪咪

文档链接打错了
2024-12-24 20:07:11 +08:00
Ffmpeg
89c71a58fa 添加文档地址 (#656) 2024-12-24 19:45:34 +08:00
Ffmpeg
27ba85b4ff 添加文档地址 2024-12-24 19:41:35 +08:00
手瓜一十雪
79a75fed8e feat: 30899 2024-12-24 15:38:53 +08:00
Mlikiowa
ee7a76b29f release: v4.2.40 2024-12-24 07:29:39 +00:00
手瓜一十雪
c53bdc3ce0 feat: 30899 2024-12-24 15:19:44 +08:00
Mlikiowa
f36e328751 release: v4.2.39 2024-12-22 13:32:51 +00:00
pk5ls20
871b5688c2 feat: webui api (/QQVersion & /GetSysStatusRealTime) 2024-12-22 21:31:14 +08:00
JerryZRF
b96076b297 fix: incorrect import 2024-12-22 13:28:20 +08:00
pk5ls20
d4488e40cf feat: better system status helper
- cpu usage diff
2024-12-22 03:56:24 +08:00
pk5ls20
7e61497243 chore: remove console logs 2024-12-22 02:57:00 +08:00
pk5ls20
e71ccdd12a feat: system status helper
- remove duplicate os import
2024-12-22 02:55:49 +08:00
pk5ls20
202129d491 feat: system status helper
- remove pidusage
2024-12-22 02:24:10 +08:00
JerryZRF
a1700dd503 fix: incorrect import 2024-12-22 01:33:42 +08:00
JerryZRF
2954776539 feat: add get_clientkey 2024-12-21 20:43:15 +08:00
手瓜一十雪
fb1f122ef7 feat: 9.9.17-30851 2024-12-21 14:29:41 +08:00
手瓜一十雪
96c63e4689 refactor: 移除不再使用的代码 2024-12-21 14:19:03 +08:00
手瓜一十雪
c94936d3dc refactor: #637 2024-12-21 14:09:57 +08:00
pk5ls20
8c22f11087 feat: system status helper 2024-12-21 13:11:10 +08:00
Mlikiowa
8a089c84a9 release: v4.2.38 2024-12-20 11:46:02 +00:00
手瓜一十雪
b631e6f8a2 fix: 更精确的筛选 2024-12-20 19:44:57 +08:00
手瓜一十雪
b3b48b032c fix: 锁住esbuild版本 以缓解问题 2024-12-20 19:32:20 +08:00
手瓜一十雪
f3e8230eca fix: 暂时指定esbuild版本以缓解上游破坏
see https://github.com/evanw/esbuild/issues/4010
2024-12-20 19:30:30 +08:00
手瓜一十雪
cc9adf9d40 feat: 过滤空消息 2024-12-20 18:58:59 +08:00
手瓜一十雪
15a640d1dc fix: #637 2024-12-20 18:55:30 +08:00
凌莞~(=^▽^=)
c25b9f86db 优化私聊戳一戳事件上报 (#643) 2024-12-18 21:27:44 +08:00
Mlikiowa
ecfd033afb release: v4.2.37 2024-12-17 07:56:18 +00:00
手瓜一十雪
f3ed8c7dff fix #633 2024-12-17 15:55:18 +08:00
Mlikiowa
6089046721 release: v4.2.36 2024-12-17 03:37:26 +00:00
手瓜一十雪
44ff92ad4b style: lint 2024-12-17 09:25:10 +08:00
手瓜一十雪
892262eb85 Merge pull request #635 from NapNeko/ref/ob-network
refactor: adjust onebot network
2024-12-17 09:07:39 +08:00
pk5ls20
2d9cc4d198 fix: as design 2024-12-17 07:07:04 +08:00
pk5ls20
a0c479485d refactor: adjust onebot network 2024-12-17 05:26:27 +08:00
手瓜一十雪
5650f18e50 Merge pull request #634 from bietiaop/main
fix: handleQuickOperation error
2024-12-17 00:29:16 +08:00
bietiaop
553885d025 fix: handleQuickOperation 2024-12-17 00:27:56 +08:00
Mlikiowa
35de00c4af release: v4.2.35 2024-12-16 14:10:08 +00:00
手瓜一十雪
09583e5de5 fuck javascript 2024-12-16 22:09:37 +08:00
Mlikiowa
38b0b7cd00 release: v4.2.34 2024-12-16 13:17:43 +00:00
手瓜一十雪
8b9c7b0c27 Merge pull request #632 from q8018414/patch-1
Update AboutUs.vue
2024-12-16 21:16:39 +08:00
手瓜一十雪
1005619bf3 Merge pull request #630 from NapNeko/dependabot/npm_and_yarn/rollup/plugin-typescript-12.1.2
chore(deps-dev): bump @rollup/plugin-typescript from 11.1.6 to 12.1.2
2024-12-16 21:16:01 +08:00
手瓜一十雪
3e09cff9cb Merge branch 'main' into dependabot/npm_and_yarn/rollup/plugin-typescript-12.1.2 2024-12-16 21:15:52 +08:00
手瓜一十雪
c24384e454 Merge pull request #629 from NapNeko/dependabot/npm_and_yarn/rollup/plugin-node-resolve-16.0.0
chore(deps-dev): bump @rollup/plugin-node-resolve from 15.3.1 to 16.0.0
2024-12-16 21:15:23 +08:00
手瓜一十雪
f87a543406 fix: #631 2024-12-16 21:14:14 +08:00
手瓜一十雪
f752136283 fix: #631 2024-12-16 21:06:51 +08:00
my_key
7e71622a44 Update AboutUs.vue
新增用于显示New NapCat的tag,便于区分当前版本和最新版本
2024-12-16 20:09:40 +08:00
dependabot[bot]
da92afb379 chore(deps-dev): bump @rollup/plugin-typescript from 11.1.6 to 12.1.2
Bumps [@rollup/plugin-typescript](https://github.com/rollup/plugins/tree/HEAD/packages/typescript) from 11.1.6 to 12.1.2.
- [Changelog](https://github.com/rollup/plugins/blob/master/packages/typescript/CHANGELOG.md)
- [Commits](https://github.com/rollup/plugins/commits/typescript-v12.1.2/packages/typescript)

---
updated-dependencies:
- dependency-name: "@rollup/plugin-typescript"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 08:44:42 +00:00
dependabot[bot]
d3062de5f9 chore(deps-dev): bump @rollup/plugin-node-resolve from 15.3.1 to 16.0.0
Bumps [@rollup/plugin-node-resolve](https://github.com/rollup/plugins/tree/HEAD/packages/node-resolve) from 15.3.1 to 16.0.0.
- [Changelog](https://github.com/rollup/plugins/blob/master/packages/node-resolve/CHANGELOG.md)
- [Commits](https://github.com/rollup/plugins/commits/commonjs-v16.0.0/packages/node-resolve)

---
updated-dependencies:
- dependency-name: "@rollup/plugin-node-resolve"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 08:43:46 +00:00
Mlikiowa
f1440b03a8 release: v4.2.33 2024-12-16 05:03:59 +00:00
手瓜一十雪
9a8b266cef Merge pull request #627 from bietiaop/main
feat: 查看登录QQ信息&获取快速登录列表详细信息&获取nc的包信息&优化了部分写法
2024-12-16 13:03:09 +08:00
手瓜一十雪
2a9bc57120 fix: #628 2024-12-16 13:00:07 +08:00
bietiaop
2ed83a0e30 feat: 查看登录QQ信息&获取快速登录列表详细信息&获取nc的包信息&优化了部分写法 2024-12-16 12:46:27 +08:00
Mlikiowa
116e8fd30a release: v4.2.32 2024-12-14 07:03:02 +00:00
手瓜一十雪
891f11173b fix 2024-12-14 15:01:47 +08:00
手瓜一十雪
dfc7996c17 Merge branch 'maybe-feat/type' 2024-12-14 15:00:18 +08:00
手瓜一十雪
dc0561d34f refactor: OB11ActiveHttpAdapter 2024-12-14 14:26:23 +08:00
手瓜一十雪
4fb0845d79 fix: #619 2024-12-14 13:46:25 +08:00
pk5ls20
0e0d4837b8 feat & fix: GetMiniAppArk 2024-12-14 06:56:23 +08:00
pk5ls20
a6adde7966 feat: attempt to enhance type inference 2024-12-14 05:56:49 +08:00
手瓜一十雪
7b693132f9 fix 2024-12-13 23:27:24 +08:00
手瓜一十雪
3c3114b6ab fix: 支持类型推导 2024-12-13 23:23:58 +08:00
Mlikiowa
5cdbf58f59 release: v4.2.31 2024-12-13 14:04:13 +00:00
手瓜一十雪
6f0a4131a2 fix: 异常 2024-12-13 22:03:51 +08:00
Mlikiowa
aa520e2f5d release: v4.2.30 2024-12-13 11:28:32 +00:00
手瓜一十雪
2c3b7e9ee8 fix: fuck! tencent 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 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 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 2024-12-06 11:39:11 +08:00
Mlikiowa
0ae3a4172c release: v4.2.26 2024-12-06 02:40:53 +00:00
手瓜一十雪
bf0c12f1c4 fix: #605 2024-12-06 10:39:49 +08:00
Mlikiowa
cb5eeecb86 release: v4.2.25 2024-12-05 13:13:34 +00:00
手瓜一十雪
8d857cf2be Revert "refactor: CardChangedEvent"
This reverts commit 0e8ceeb6c9.
2024-12-05 21:13:03 +08:00
手瓜一十雪
6f232c465f Merge pull request #604 from Ander-pixe/webui-new
feat:实时日志、关于and部分样式优化
2024-12-05 21:10:08 +08:00
纸凤孤凰
032d444246 Merge remote-tracking branch 'origin/webui-new' into webui-new 2024-12-05 20:27:08 +08:00
纸凤孤凰
49488dd3fb Merge remote-tracking branch 'origin/webui-new' into webui-new 2024-12-05 20:25:14 +08:00
手瓜一十雪
9aec3865ff fix: historyLog 2024-12-05 20:22:55 +08:00
手瓜一十雪
b6b7f2051b fix 2024-12-05 20:02:24 +08:00
手瓜一十雪
46254a699a fix 2024-12-05 19:56:36 +08:00
手瓜一十雪
7b3c287137 fix: cors 2024-12-05 19:37:56 +08:00
手瓜一十雪
1a533742a5 fix: Log 2024-12-05 19:17:07 +08:00
手瓜一十雪
2027266852 fix 2024-12-05 18:56:55 +08:00
手瓜一十雪
946d8b1a7b fix: dependencies error 2024-12-05 18:49:45 +08:00
手瓜一十雪
6d2fb5de6f Merge branch 'main' into pr/604 2024-12-05 18:40:46 +08:00
pk5ls20
91c4a002dd fix: dependencies 2024-12-05 18:15:00 +08:00
纸凤孤凰
4d8112aae5 feat:实时日志、关于and部分样式优化 2024-12-05 15:31:42 +08:00
手瓜一十雪
bb53f245cf style: lint check 2024-12-05 14:50:27 +08:00
手瓜一十雪
9f31cdbf5b fix: 移除不使用api 2024-12-05 14:46:05 +08:00
手瓜一十雪
9a33039d73 fix: 暂时移除 QunAlbum 2024-12-05 14:45:12 +08:00
手瓜一十雪
7cf3be8333 refactor: predict time 2024-12-05 14:42:45 +08:00
Nanako
82afb88e53 Update README.md 2024-12-05 14:37:10 +08:00
Mlikiowa
4aa24b5d67 release: v4.2.24 2024-12-05 06:17:46 +00:00
手瓜一十雪
57112c21a2 refactor: flag handle&onebot标准化 2024-12-05 14:17:09 +08:00
手瓜一十雪
0e8ceeb6c9 refactor: CardChangedEvent 2024-12-05 11:36:06 +08:00
手瓜一十雪
f52b8d1f04 feat: 30366 全平台通用性适配 2024-12-05 11:15:10 +08:00
手瓜一十雪
f374cc77ae chore: readme 2024-12-04 23:04:37 +08:00
手瓜一十雪
7c694e7fae chore: 跑路的规范/困难的实现 2024-12-04 23:03:46 +08:00
Mlikiowa
932ffc2673 release: v4.2.23 2024-12-04 14:18:02 +00:00
手瓜一十雪
3de5438139 fix: poke report 2024-12-04 22:16:59 +08:00
手瓜一十雪
c4b5f34271 fix: 兜底 防止进入影响速度 2024-12-04 22:02:11 +08:00
手瓜一十雪
22d3ac33a2 Refactor: 更新群组通知处理逻辑,优化数据结构和异步处理 2024-12-04 21:59:53 +08:00
Mlikiowa
2e5dd6535a release: v4.2.22 2024-12-04 13:18:58 +00:00
手瓜一十雪
eac58a2a50 fix: 9.9.17-30366 2024-12-04 21:04:24 +08:00
手瓜一十雪
e939ec0e52 fix: #597 2024-12-04 20:37:08 +08:00
Mlikiowa
5b17a14a2a release: v4.2.21 2024-12-04 11:49:26 +00:00
手瓜一十雪
8fb8c888f5 refactor: 移除未使用的uidCache和uinCache逻辑 2024-12-04 19:48:59 +08:00
Mlikiowa
4a2884509e release: v4.2.20 2024-12-04 11:46:12 +00:00
手瓜一十雪
e295235a89 fix: #596 2024-12-04 19:45:46 +08:00
手瓜一十雪
ef515a38d0 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-12-04 18:50:55 +08:00
手瓜一十雪
02cff040e3 refactor: 移除未使用的createUidFromTinyId和getStatusByUid方法 2024-12-04 18:50:51 +08:00
Mlikiowa
bb0f65a52d release: v4.2.19 2024-12-04 10:42:32 +00:00
手瓜一十雪
d51d6a5cc1 refactor: getUidByUinV2/getUinByUidV2 2024-12-04 18:41:28 +08:00
手瓜一十雪
eb99379a79 fix: 性能优化 2024-12-04 18:29:33 +08:00
Mlikiowa
388eb57d0d release: v4.2.18 2024-12-04 03:40:59 +00:00
手瓜一十雪
0b8131392a chore: 移出调试 2024-12-04 11:40:36 +08:00
手瓜一十雪
229efbd006 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-12-04 11:39:09 +08:00
手瓜一十雪
a482fa3a8d refactor: 优化调整文件处理 2024-12-04 11:38:59 +08:00
Mlikiowa
6cf047af39 release: v4.2.17 2024-12-04 02:57:21 +00:00
手瓜一十雪
41748c0b3f refactor: 数据清理与刷新 2024-12-04 10:55:56 +08:00
手瓜一十雪
1ce8be3c7e fix: 精简GroupApi实现 2024-12-04 10:47:21 +08:00
手瓜一十雪
32778acf57 refactor: NTQQGroupApi 2024-12-04 10:43:48 +08:00
Mlikiowa
a3c71473ae release: v4.2.16 2024-12-03 14:15:16 +00:00
手瓜一十雪
aceece7e90 fix: code 2024-12-03 22:12:57 +08:00
Mlikiowa
52efb4f9ef release: v4.2.15 2024-12-03 14:07:35 +00:00
手瓜一十雪
6b0d96fe8d fix: 移除复杂信息 2024-12-03 22:07:11 +08:00
Mlikiowa
ad052821b0 release: v4.2.14 2024-12-03 13:50:37 +00:00
手瓜一十雪
da7636e60c fix: #592 2024-12-03 21:50:12 +08:00
Mlikiowa
ef01dd0d77 release: v4.2.13 2024-12-03 13:43:37 +00:00
手瓜一十雪
03f7d4673f fix: code 2024-12-03 21:42:08 +08:00
手瓜一十雪
94e9c87978 fix: 优化处理 2024-12-03 21:42:08 +08:00
手瓜一十雪
501bbbe4df fix 2024-12-03 21:42:08 +08:00
手瓜一十雪
c9122a3fee fix: 临时的抽象方案 2024-12-03 21:42:08 +08:00
手瓜一十雪
8a289d014e fix: error 2024-12-03 21:42:08 +08:00
手瓜一十雪
ddadd38151 refactor: GroupAdminChange 2024-12-03 21:42:08 +08:00
手瓜一十雪
0b8d0e3cac feat: 迁移事件解析原理 2024-12-03 21:42:08 +08:00
手瓜一十雪
eeb27d38bc fix: 清理旧的脚本 2024-12-03 17:33:13 +08:00
Mlikiowa
491a79ec96 release: v4.2.12 2024-12-03 09:22:43 +00:00
手瓜一十雪
f429db61af fix: #594 2024-12-03 17:16:58 +08:00
Mlikiowa
2881099602 release: v4.2.11 2024-12-02 14:08:36 +00:00
手瓜一十雪
672ae8decf fix: Once处理空格目录 中文目录 2024-12-02 22:08:08 +08:00
手瓜一十雪
2abc7e541d fix: 空格目录启动问题 2024-12-02 21:23:13 +08:00
手瓜一十雪
45b1f369ac style: 异步实现 2024-12-02 11:44:37 +08:00
手瓜一十雪
3b5d2c8f6f style: 简化写法 2024-12-02 11:16:12 +08:00
Mlikiowa
5376e16c9f release: v4.2.10 2024-12-01 11:12:10 +00:00
bietiaop
af052242fa feat:带等级的实时日志 2024-12-01 15:19:23 +08:00
手瓜一十雪
85e0b71545 chore: daily -> weekly 2024-12-01 13:26:56 +08:00
手瓜一十雪
1206d1fcf6 chore: bug report 2024-12-01 13:25:36 +08:00
手瓜一十雪
f7534dc438 fix: 自动迁移 2024-12-01 13:20:20 +08:00
手瓜一十雪
97f317254e fix: MiniApp type check 2024-12-01 13:11:56 +08:00
手瓜一十雪
9eaf51e15f fix: nullable 2024-12-01 13:04:00 +08:00
手瓜一十雪
7221f4ac02 fix: type-check 2024-12-01 12:50:13 +08:00
手瓜一十雪
1bb6dce239 refactor: type-check (#586)
* refactor: type-check

* fix: default

* refactor: type-check
2024-12-01 12:41:51 +08:00
bietiaop
d13db5e8eb feat: 实时日志 (#584)
* feat: 历史日志

* feat: 实时日志

* fix: EventEmitter实现事件监听
2024-12-01 09:31:47 +08:00
Mlikiowa
040b5535f3 release: v4.2.9 2024-11-30 06:12:44 +00:00
手瓜一十雪
b44e1618fb fix: quick error 2024-11-30 14:12:23 +08:00
手瓜一十雪
1e13483bc3 fix: type 2024-11-30 13:32:21 +08:00
手瓜一十雪
f9519d3923 style: lint 2024-11-30 13:29:10 +08:00
手瓜一十雪
86cdfbb79b feat: 取消上报 pic_type 2024-11-30 12:11:33 +08:00
手瓜一十雪
a70585e854 feat: 处理失败的情况 2024-11-30 12:08:58 +08:00
Mlikiowa
040d0a8635 release: v4.2.8 2024-11-30 01:39:59 +00:00
手瓜一十雪
efa512ab21 fix: #580 2024-11-30 09:34:03 +08:00
bietiaop
9b04aed8b3 feat: 历史日志 2024-11-30 09:30:13 +08:00
手瓜一十雪
7087eafe37 feat: Universal Package (#578)
* feat: 统一包支持

* feat: Universal
2024-11-29 15:11:35 +08:00
Mlikiowa
c81c4af653 release: v4.2.7 2024-11-29 04:48:36 +00:00
手瓜一十雪
c05cc9dd02 feat: 迁移29927 2024-11-29 12:48:03 +08:00
手瓜一十雪
1a0da00f2d refactor: webui log 移除公网输出 2024-11-29 12:41:52 +08:00
手瓜一十雪
31b0c1d3d7 refactor: react webui 2024-11-29 12:22:25 +08:00
手瓜一十雪
53c1d40bcf refactor: logger bind (#577) 2024-11-28 20:55:28 +08:00
手瓜一十雪
97cacb4383 refactor: framework的操作性 2024-11-28 20:00:24 +08:00
Mlikiowa
e03905abaf release: v4.2.6 2024-11-28 07:28:33 +00:00
手瓜一十雪
06eba28b4c fux: #574 2024-11-28 15:28:09 +08:00
手瓜一十雪
bbfeac46dd Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-28 15:27:26 +08:00
手瓜一十雪
2fe4da094a fix 2024-11-28 15:14:01 +08:00
Mlikiowa
b454d8c0f9 release: v4.2.5 2024-11-28 07:07:10 +00:00
手瓜一十雪
1f9b5453cc fix: #573 2024-11-28 15:06:47 +08:00
Mlikiowa
3261791e99 release: v4.2.4 2024-11-28 03:00:35 +00:00
手瓜一十雪
3bb12e3f45 fix: #572 2024-11-28 10:56:57 +08:00
手瓜一十雪
1dc2f7e5a2 style: lint 2024-11-28 10:46:14 +08:00
手瓜一十雪
2531b08538 refactor: 提高解析兼容 2024-11-28 10:41:51 +08:00
手瓜一十雪
9fcfb5493c fix: #571 2024-11-28 10:27:04 +08:00
Mlikiowa
4576354c51 release: v4.2.3 2024-11-28 01:54:43 +00:00
手瓜一十雪
1dcf2ef0c6 fix: error handle 2024-11-28 09:53:50 +08:00
Mlikiowa
3642c65e8c release: v4.2.2 2024-11-27 12:39:03 +00:00
手瓜一十雪
40e105994a fix: pic size 2024-11-27 20:38:39 +08:00
Mlikiowa
f2ee973882 release: v4.2.1 2024-11-27 11:07:43 +00:00
手瓜一十雪
3aa30792bf Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-27 19:07:11 +08:00
手瓜一十雪
6e336fa78e fix: 合并丢失 2024-11-27 19:07:01 +08:00
Mlikiowa
900027a6b7 release: v4.2.0 2024-11-27 10:55:36 +00:00
手瓜一十雪
38bdca2409 fix: qrcode login 2024-11-27 18:51:54 +08:00
手瓜一十雪
7196e476bf Merge pull request #567 from bietiaop/webapi-bietiaop
refactor:优化WebUI后端代码格式(无新功能添加)
2024-11-27 18:39:19 +08:00
手瓜一十雪
e0fd3785d9 Merge pull request #565 from Ander-pixe/webui-new
修改webui
2024-11-27 18:35:13 +08:00
手瓜一十雪
b53ebb6c2a refactor: parse local path 2024-11-27 18:34:33 +08:00
纸凤孤凰
1ea80f4447 fix:修复webui已知bug 2024-11-27 18:16:16 +08:00
手瓜一十雪
627d3c0a7a Merge pull request #570 from NapNeko/dependabot/npm_and_yarn/vite-6.0.1
chore(deps-dev): bump vite from 5.4.11 to 6.0.1
2024-11-27 16:51:20 +08:00
dependabot[bot]
182cccfc71 chore(deps-dev): bump vite from 5.4.11 to 6.0.1
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.4.11 to 6.0.1.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/create-vite@6.0.1/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-27 08:32:10 +00:00
手瓜一十雪
6a3713e86c fix: webui reload 2024-11-27 12:35:10 +08:00
手瓜一十雪
788da4e4f1 style 2024-11-27 12:25:37 +08:00
手瓜一十雪
fd26d34e19 fix 2024-11-27 12:20:30 +08:00
手瓜一十雪
e9fcdc7d2e feat: 简化代码 2024-11-27 11:35:51 +08:00
手瓜一十雪
0fe4911d01 fix: 优化类型 2024-11-27 11:29:03 +08:00
手瓜一十雪
d4fb09fa80 fix: 简化类型 2024-11-27 10:57:40 +08:00
手瓜一十雪
e6d5a37236 fix: menuRef 2024-11-27 10:53:50 +08:00
手瓜一十雪
79fd10ac10 Merge branch 'main' into pr/567 2024-11-26 20:06:18 +08:00
手瓜一十雪
a2e6095e44 chore: 注释不必要的代码 2024-11-26 19:44:37 +08:00
手瓜一十雪
64530471a0 fix: GroupChange 2024-11-26 19:42:35 +08:00
stapxs
e31e831309 feat: 优化网络配置卡片样式 2024-11-26 17:12:55 +08:00
手瓜一十雪
cf6871df9b Merge branch 'main' into pr/565 2024-11-26 12:56:57 +08:00
手瓜一十雪
482e7f1c75 Merge pull request #566 from NapNeko/refactor-group-event
refactor: parseGroupEvent
2024-11-26 12:51:48 +08:00
手瓜一十雪
aab501e31e Merge branch 'refactor-group-event' into pr/565 2024-11-26 12:40:19 +08:00
手瓜一十雪
ceec9e5e1b refactor: self report 2024-11-26 11:26:34 +08:00
手瓜一十雪
aadebb3cc5 refactor: event emit 2024-11-26 11:10:59 +08:00
手瓜一十雪
657ddd3341 refactor: emitRecallMsg 2024-11-26 11:08:12 +08:00
手瓜一十雪
62127b6d48 refactor: onMsgRecall 2024-11-25 22:36:07 +08:00
bietiaop
f5f405796f fix:vite配置别名framwork缺少@webapi 2024-11-25 22:29:18 +08:00
bietiaop
39873947a3 chore:移除多余依赖 2024-11-25 22:11:57 +08:00
手瓜一十雪
a1079dd948 fix 2024-11-25 21:58:35 +08:00
bietiaop
4eeabcc9e0 refactor:优化WebUI后端代码格式(无新功能添加) 2024-11-25 21:56:57 +08:00
手瓜一十雪
c3568d07e8 fix: #563 2024-11-25 21:56:34 +08:00
手瓜一十雪
1adb4a4ba8 refactor: parsePrivateMsgEvent 2024-11-25 21:53:35 +08:00
手瓜一十雪
6d0020533c chore: 可读性提高 优化代码 2024-11-25 21:44:22 +08:00
手瓜一十雪
4e6af0a655 feat: 性能优化 2024-11-25 21:28:04 +08:00
手瓜一十雪
00f726b515 fix: event parse 2024-11-25 21:20:32 +08:00
手瓜一十雪
035aa32305 fix: parseGroupUploadFileEvene 2024-11-25 21:04:33 +08:00
手瓜一十雪
62ea4b98e1 refactor: parseGroupEvent 2024-11-25 20:39:44 +08:00
pk5ls20
4be821137d feat: eslint 2024-11-25 20:02:50 +08:00
pk5ls20
7fba9960bf Merge branch 'main' into webui-new 2024-11-25 19:57:41 +08:00
手瓜一十雪
876bfbd3cb feat: tipgroup type 2024-11-25 19:32:30 +08:00
手瓜一十雪
edde2c210b feat: type 2024-11-25 19:24:51 +08:00
手瓜一十雪
f956d96d94 feat: 上报文件picType 2024-11-25 18:27:36 +08:00
手瓜一十雪
c2296fd900 fix 2024-11-25 18:24:13 +08:00
Mlikiowa
0feed5b640 release: v4.1.21 2024-11-25 07:48:50 +00:00
手瓜一十雪
93904dcb1b fix: 删除的移除 2024-11-25 15:45:07 +08:00
手瓜一十雪
86cbdf793a Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-25 15:36:01 +08:00
手瓜一十雪
56b1b9b598 chore: 移除开发debug 2024-11-25 15:35:48 +08:00
Mlikiowa
f7ec3ae131 release: v4.1.20 2024-11-25 07:16:41 +00:00
手瓜一十雪
01d11d6213 refactor: 热重载 2024-11-25 15:16:12 +08:00
Mlikiowa
74a316e758 release: v4.1.19 2024-11-25 05:27:11 +00:00
手瓜一十雪
d20c5185a4 fix: 禁止once覆写package 2024-11-25 13:19:24 +08:00
手瓜一十雪
da965e7b39 fix: qrcode刷新 2024-11-25 13:01:42 +08:00
纸凤孤凰
3fbed815a5 修改webui 2024-11-25 02:17:48 +08:00
Mlikiowa
152be29739 release: v4.1.18 2024-11-24 04:53:06 +00:00
手瓜一十雪
e521740a44 fix: error 2024-11-24 12:49:37 +08:00
手瓜一十雪
ee047e8bc1 Merge pull request #561 from NapNeko/parseMult
feat: #538
2024-11-24 12:44:16 +08:00
手瓜一十雪
5eaa9ca347 Merge branch 'main' into parseMult 2024-11-24 12:43:52 +08:00
手瓜一十雪
40f79ee816 fix: error handle 2024-11-24 12:43:28 +08:00
手瓜一十雪
f0dcef7981 fix: by ai 简化逻辑 2024-11-24 12:26:44 +08:00
手瓜一十雪
3c09ff13d0 fix: check config 2024-11-24 12:23:42 +08:00
手瓜一十雪
7158f25f37 fix: error 2024-11-24 12:18:16 +08:00
手瓜一十雪
54f805b6e4 fix: #538 2024-11-24 12:17:23 +08:00
手瓜一十雪
70c4651fbf Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-23 18:53:04 +08:00
手瓜一十雪
962d3c064f update: Limited Redistribution License 2024-11-23 18:52:53 +08:00
Mlikiowa
c6a459a111 release: v4.1.16 2024-11-23 10:27:40 +00:00
手瓜一十雪
b0242ccb62 fix: typo 2024-11-22 22:08:46 +08:00
手瓜一十雪
53f5277b08 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-22 22:08:31 +08:00
手瓜一十雪
90b54435b5 fix: typo 2024-11-22 22:04:57 +08:00
手瓜一十雪
12a1681b42 fix: poke for base emoji 2024-11-22 21:39:16 +08:00
手瓜一十雪
4277cb3f3c remove: docs 2024-11-22 20:52:11 +08:00
手瓜一十雪
8353d53589 feat: baseEmoji Service 2024-11-22 20:50:51 +08:00
手瓜一十雪
9e94d98cfb rename&docs: face 2024-11-22 20:24:45 +08:00
手瓜一十雪
b6ec1aaa9b fix: 修正定义 2024-11-22 20:15:55 +08:00
手瓜一十雪
e7e8763f1c fix: GetProfileLike 2024-11-22 15:58:40 +08:00
手瓜一十雪
515c1af676 refactor: filetype 识别 2024-11-22 15:33:52 +08:00
手瓜一十雪
6fa7a973ba style: @搜寻 2024-11-22 15:08:26 +08:00
手瓜一十雪
3e63f509bc fix: 进一步标准化类型 2024-11-22 14:45:14 +08:00
Mlikiowa
b3b02e781a release: v4.1.15 2024-11-21 14:52:41 +00:00
手瓜一十雪
6d83921e20 style: enum提高可读性 2024-11-21 19:37:11 +08:00
pk5ls20
30bd372d45 feat: version 29927 2024-11-21 18:10:01 +08:00
手瓜一十雪
63254b7e55 fix: readme thanks
Some checks failed
Build Action / Build-LiteLoader (push) Failing after 3m16s
Build Action / Build-Shell (push) Failing after 3m3s
2024-11-21 15:07:36 +08:00
Mlikiowa
f4c08d93f4 release: v4.1.14 2024-11-21 06:58:07 +00:00
手瓜一十雪
6ca1ac21e4 feat: support 29927 2024-11-21 14:55:34 +08:00
Mlikiowa
381ee1c30e release: v4.1.13 2024-11-21 06:43:58 +00:00
手瓜一十雪
902fe907bd refactor: 持续重构project结构与定义 2024-11-21 14:36:06 +08:00
手瓜一十雪
bbb4ad7d95 rename: project 2024-11-21 14:30:21 +08:00
手瓜一十雪
24bc9f35b2 fix: NTGroupRequestOperateTypes 2024-11-21 14:28:04 +08:00
手瓜一十雪
52c68a3bfb fix: NTGroupRequestOperateTypes 2024-11-21 14:27:11 +08:00
手瓜一十雪
d982bcdad5 fix: typo 2024-11-21 14:21:46 +08:00
手瓜一十雪
b8165242f0 feat: NTSex 2024-11-21 14:21:14 +08:00
手瓜一十雪
7ce95bca04 feat: NTGroupMemberRole 2024-11-21 14:15:22 +08:00
手瓜一十雪
cd212abd5f fix: TipGroupElementType 2024-11-21 14:10:52 +08:00
手瓜一十雪
e5b063accb feat: MemberAddShowType 2024-11-21 13:44:21 +08:00
手瓜一十雪
eeef5409dc fix: PicSubType 2024-11-21 13:10:49 +08:00
手瓜一十雪
2bf8d8f791 fix 标准类型 2024-11-21 13:06:13 +08:00
手瓜一十雪
56e62392a6 chore: webui backend readme 2024-11-21 12:24:53 +08:00
手瓜一十雪
2ecf04c78c chore: LICENSE 2024-11-21 12:23:51 +08:00
手瓜一十雪
a19358da5b refactor: 项目结构 2024-11-21 11:52:50 +08:00
手瓜一十雪
a5d4998933 refactor: 通过@实现定位 2024-11-21 11:39:44 +08:00
手瓜一十雪
8edbe54456 fix: index 2024-11-21 11:25:06 +08:00
手瓜一十雪
e898915d01 rename: 使用@搜寻 2024-11-21 11:16:25 +08:00
手瓜一十雪
b2075130d9 style: lint 2024-11-21 11:09:23 +08:00
手瓜一十雪
02e39b5714 fix: typo 2024-11-21 11:06:03 +08:00
手瓜一十雪
de64b03054 refactor: 旧代码移除 2024-11-21 11:01:35 +08:00
手瓜一十雪
fa70eec3d8 refactor: core类型refactor结束 2024-11-21 10:47:12 +08:00
手瓜一十雪
583ec10c7c fix: 规范化类型 2024-11-21 10:43:05 +08:00
手瓜一十雪
38a098c77d refactor: type 2024-11-21 10:36:08 +08:00
pk5ls20
d17674d06e fix: #553
Some checks failed
Build Action / Build-LiteLoader (push) Failing after 3m49s
Build Action / Build-Shell (push) Failing after 3m21s
2024-11-20 20:58:36 +08:00
pk5ls20
0b839258aa fix: ci 2024-11-20 19:51:29 +08:00
pk5ls20
50e207cf6f chore: remove useless log 2024-11-20 17:30:50 +08:00
pk5ls20
5d2d8c7123 fix: #551
Some checks failed
Build Action / Build-LiteLoader (push) Failing after 3m37s
Build Action / Build-Shell (push) Failing after 2m58s
2024-11-20 17:00:01 +08:00
pk5ls20
23702f412c chore: link 2024-11-20 16:23:04 +08:00
pk5ls20
31e94792c4 Merge pull request #548 from huankong233/main 2024-11-20 14:45:28 +08:00
huankong233
249afdce81 revent: 对手动拆分chunk进行回滚 2024-11-20 14:15:03 +08:00
huankong233
ee8f381341 feat: 增强webui对老设备的支持 2024-11-20 14:02:34 +08:00
Mlikiowa
83f3df76cd release: v4.1.12 2024-11-20 04:22:12 +00:00
手瓜一十雪
16195ca52b fix: old version handle 2024-11-20 12:21:45 +08:00
Mlikiowa
d5f492775e release: v4.1.11 2024-11-20 02:20:35 +00:00
手瓜一十雪
1f273a8799 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-20 10:20:00 +08:00
手瓜一十雪
f44f6fd1e9 fix: 文件后清除 2024-11-20 10:19:43 +08:00
Mlikiowa
21ca13789e release: v4.1.9 2024-11-20 02:18:14 +00:00
手瓜一十雪
648faedca6 fix: #544 2024-11-20 10:16:41 +08:00
Mlikiowa
3a6748ae37 release: v4.1.8
Some checks failed
Build Action / Build-LiteLoader (push) Failing after 13s
Build Action / Build-Shell (push) Failing after 3m22s
2024-11-19 10:45:26 +00:00
手瓜一十雪
4d4b1ad26c fix: #543 2024-11-19 18:44:56 +08:00
手瓜一十雪
e42fbea918 feat: 扩展rkey支持 2024-11-19 17:58:43 +08:00
Mlikiowa
48b648b0fb release: v4.17
Some checks failed
Build Action / Build-LiteLoader (push) Failing after 2m22s
Build Action / Build-Shell (push) Failing after 2m23s
2024-11-19 08:30:06 +00:00
手瓜一十雪
68e86b07c7 fix: #543 2024-11-19 16:29:33 +08:00
手瓜一十雪
12cb500818 refactor: rename OB11BaseEvent 2024-11-19 12:55:42 +08:00
手瓜一十雪
9ffaab178a refactor: Action 2024-11-19 12:49:51 +08:00
pk5ls20
d4fbbd6711 fix: #539
Some checks failed
Build Action / Build-LiteLoader (push) Failing after 2m33s
Build Action / Build-Shell (push) Failing after 2m17s
2024-11-19 01:12:49 +08:00
pk5ls20
ded53cd348 fix: link
Some checks failed
Build Action / Build-LiteLoader (push) Failing after 3m48s
Build Action / Build-Shell (push) Failing after 2m49s
2024-11-18 23:22:25 +08:00
手瓜一十雪
be9e80c87b fix: 清除无效链接 2024-11-18 20:40:43 +08:00
Mlikiowa
e9fe6f28cc release: v4.1.6 2024-11-18 11:51:39 +00:00
手瓜一十雪
0b8bf739e9 fix: event 2024-11-18 19:51:08 +08:00
手瓜一十雪
0222664db8 fix: type
Some checks failed
Build Action / Build-LiteLoader (push) Failing after 14m48s
Build Action / Build-Shell (push) Failing after 14m43s
2024-11-17 16:02:25 +08:00
手瓜一十雪
a88792e452 docs: 没有参考故移除 2024-11-17 16:01:44 +08:00
手瓜一十雪
ad45400742 docs: 调整更新速度与Packet重构 2024-11-17 15:57:21 +08:00
手瓜一十雪
53e5ba03be fix 2024-11-17 15:56:48 +08:00
手瓜一十雪
b587d6b91d fix: (SetGroupSign) BaseAction-->GetPacketStatusDepends 2024-11-17 15:37:10 +08:00
手瓜一十雪
5e750d4ee9 feat: uploadQunAlbum未测试
Some checks failed
Build Action / Build-LiteLoader (push) Failing after 2m40s
Build Action / Build-Shell (push) Failing after 2m38s
2024-11-17 13:39:57 +08:00
Mlikiowa
50fb32f81c release: v4.1.5 2024-11-17 03:39:17 +00:00
手瓜一十雪
6c46cdd947 fix: error 2024-11-17 11:33:01 +08:00
手瓜一十雪
372452fbee fix: 消息上报 2024-11-17 11:29:27 +08:00
手瓜一十雪
417ef5d335 Revert "fix"
This reverts commit 9c534f8afd.
2024-11-17 11:21:48 +08:00
手瓜一十雪
9c534f8afd fix 2024-11-17 11:12:14 +08:00
pk5ls20
ecd426bb80 refactor: webui network 2024-11-17 08:17:09 +08:00
pk5ls20
f74ef273de fix: workflow
Some checks failed
Build Action / Build-LiteLoader (push) Failing after 3m25s
Build Action / Build-Shell (push) Failing after 2m52s
2024-11-17 06:24:58 +08:00
pk5ls20
f913e0b027 chore: workflow 2024-11-17 06:23:33 +08:00
pk5ls20
f7268c30ca chore: revert todo 2024-11-17 05:28:46 +08:00
pk5ls20
0f5ef03d63 chore: try todo x2 2024-11-17 05:21:35 +08:00
pk5ls20
745276d0f0 chore: try todo 2024-11-17 05:16:18 +08:00
pk5ls20
2e108a4bd6 feat: error stack 2024-11-17 04:43:29 +08:00
pk5ls20
666da80ef5 feat: version display 2024-11-17 03:43:09 +08:00
pk5ls20
cc73104d62 chore: eslint 2024-11-17 03:35:20 +08:00
手瓜一十雪
3c10b82bab Merge branch 'main' of https://github.com/NapNeko/NapCatQQ
Some checks failed
Build Action / Build-LiteLoader (push) Failing after 11s
Build Action / Build-Shell (push) Failing after 14s
2024-11-16 20:35:31 +08:00
手瓜一十雪
9a65dae6a2 fix: #531 2024-11-16 20:32:52 +08:00
Mlikiowa
f26cd8cdc9 release: v4.1.3 2024-11-16 12:22:06 +00:00
手瓜一十雪
eeec905df0 fix: 反向ws 2024-11-16 20:21:38 +08:00
手瓜一十雪
0c6aac7f66 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-16 20:20:07 +08:00
手瓜一十雪
86d22db141 feat: remove hasBeenClosed 2024-11-16 20:15:02 +08:00
Mlikiowa
48a5d0eef3 release: v4.1.2 2024-11-16 12:14:28 +00:00
手瓜一十雪
bda174bed4 fix: 异常 2024-11-16 20:13:36 +08:00
Mlikiowa
caf98b8655 release: v4.1.1 2024-11-16 11:26:41 +00:00
手瓜一十雪
c9833c5988 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-16 19:25:58 +08:00
手瓜一十雪
55ef7e529e fix: 4.1.1 2024-11-16 19:25:54 +08:00
Mlikiowa
9b04ddcefd release: v4.1.0 2024-11-16 10:41:27 +00:00
手瓜一十雪
6dc4f38581 refactor: AdapterConfig 2024-11-16 18:38:44 +08:00
手瓜一十雪
93ce8bfb85 refactor: emitMsg 2024-11-16 18:31:24 +08:00
手瓜一十雪
e7d138448a refactor: reloadNetwork 2024-11-16 18:10:03 +08:00
手瓜一十雪
02c4a468cb fix 2024-11-16 16:56:34 +08:00
手瓜一十雪
d392e653e1 refactor: network 2024-11-16 16:56:20 +08:00
手瓜一十雪
e8faa09f1d refactor: fetch->RequestUtil
Some checks failed
Build Action / Build-LiteLoader (push) Failing after 17s
Build Action / Build-Shell (push) Failing after 9s
2024-11-16 13:58:46 +08:00
手瓜一十雪
e80ed3b33e fix: 切分依赖 2024-11-16 13:47:33 +08:00
手瓜一十雪
41a346e1cf Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-16 13:44:06 +08:00
手瓜一十雪
5e19fc112a fix: ws 0.0.0. 兼容 2024-11-16 13:44:02 +08:00
手瓜一十雪
2f7aff2b56 feat: 调整配置顺序 2024-11-16 13:35:10 +08:00
手瓜一十雪
ccb0e1fb4f docs: thank tdesign 2024-11-16 13:24:19 +08:00
手瓜一十雪
d4163c913a docs: tdesign 2024-11-16 13:23:05 +08:00
手瓜一十雪
8087ba0e4a fix: webui 2024-11-16 13:20:42 +08:00
手瓜一十雪
6700523b61 feat: 网络重载日志 2024-11-16 13:18:42 +08:00
手瓜一十雪
49f1c3f9ba fix: 翻新网络重载 2024-11-16 13:07:20 +08:00
手瓜一十雪
575ab4f1d1 fix: 打包流程 2024-11-16 12:57:12 +08:00
手瓜一十雪
3658547731 Merge pull request #524 from NapNeko/refactor-config-webui
refactor: new config & vue webui & new network & new parseMsg
2024-11-16 12:53:46 +08:00
手瓜一十雪
eb6590e9e2 feat: 打包脚本 2024-11-16 12:50:45 +08:00
手瓜一十雪
83f28795f2 feat: 移除无用代码 2024-11-16 12:45:27 +08:00
手瓜一十雪
e98bfaac11 fix: error 2024-11-16 12:34:50 +08:00
手瓜一十雪
4f4bd3c6e0 fix: 抑制警告 2024-11-16 11:45:57 +08:00
手瓜一十雪
bd1faccaa8 fix: build 2024-11-16 11:44:23 +08:00
手瓜一十雪
25751b8149 fix 2024-11-16 11:39:12 +08:00
手瓜一十雪
e34b60315c fix: build 2024-11-16 11:37:47 +08:00
手瓜一十雪
046afc0c23 Merge branch 'main' into refactor-config-webui 2024-11-16 11:35:59 +08:00
手瓜一十雪
2f61ba7f25 feat: 优化上报问题 2024-11-16 11:32:27 +08:00
手瓜一十雪
8981f12b1a fix: 修复大部分逻辑 2024-11-16 11:25:16 +08:00
手瓜一十雪
34e96b1089 fix: 逻辑操作 2024-11-16 11:14:21 +08:00
手瓜一十雪
41db435ef5 fix: 样式 2024-11-16 11:08:45 +08:00
手瓜一十雪
b525fa81bb fix: 一处样式问题 2024-11-16 10:57:15 +08:00
手瓜一十雪
6382b29da8 feat: 提升交互体验 2024-11-16 10:55:26 +08:00
手瓜一十雪
8bc0403139 feat: 微调样式 2024-11-16 10:42:01 +08:00
手瓜一十雪
9f261e78c3 fix: name保存问题 2024-11-16 10:38:03 +08:00
手瓜一十雪
15d9390ee4 feat: 基础样式 2024-11-16 10:34:31 +08:00
手瓜一十雪
572b8809a5 feat: dev webui 2024-11-16 10:20:17 +08:00
pk5ls20
623799c049 fix: migrateOneBotConfigsV1 2024-11-16 07:22:29 +08:00
pk5ls20
4271acc6ab feat: add migrateOneBotConfigsV2 2024-11-16 06:52:18 +08:00
pk5ls20
609e83a824 refactor: more comprehensive dev and prod env isolation and build process 2024-11-16 06:10:36 +08:00
pk5ls20
e98910c9ff chore: adjust eslint 2024-11-16 05:50:44 +08:00
pk5ls20
c432799580 refactor: webui network 2024-11-16 05:43:44 +08:00
pk5ls20
fa87f7c8c3 fix: vite config 2024-11-16 00:13:05 +08:00
pk5ls20
4a44062814 chore: revert package.json 2024-11-15 23:41:17 +08:00
pk5ls20
fe0bda11d3 refactor: webui 2024-11-15 23:39:19 +08:00
手瓜一十雪
1ec1040e43 feat: 产物替换 2024-11-15 20:39:57 +08:00
pk5ls20
e44595334a perf: avoid silk encoding blocking the main event loop (#527)
Some checks failed
Build Action / Build-LiteLoader (push) Failing after 13s
Build Action / Build-Shell (push) Failing after 12s
2024-11-15 20:39:18 +08:00
手瓜一十雪
f40de023b0 feat: 加入注释 2024-11-15 20:35:30 +08:00
手瓜一十雪
9799d02ad2 fix: 清除基础信息 2024-11-15 20:34:42 +08:00
手瓜一十雪
bec88fee04 feat: 修复渲染异常bug 2024-11-15 20:33:06 +08:00
手瓜一十雪
1a94e20691 fix: 关闭按钮 2024-11-15 20:26:00 +08:00
手瓜一十雪
3690307d0b fix: 添加配置 2024-11-15 20:22:42 +08:00
手瓜一十雪
2d5b4bc90a feat: 保存数据 2024-11-15 20:00:49 +08:00
手瓜一十雪
cc93ed3567 fix: shallowRef 2024-11-15 19:54:21 +08:00
手瓜一十雪
dce4988767 refactor: network 2024-11-15 19:51:19 +08:00
手瓜一十雪
5c81b60b58 feat: 渲染网络配置 2024-11-15 19:48:27 +08:00
手瓜一十雪
a668bfbc13 refactor: emitMsg 2024-11-15 18:40:35 +08:00
手瓜一十雪
bc0fc96b9b refactor: rkey get 2024-11-15 18:35:34 +08:00
手瓜一十雪
ae14692d5b refactor: parseMsg 2024-11-15 18:29:42 +08:00
手瓜一十雪
d445dc6644 refactor: 初步可用 2024-11-15 17:35:09 +08:00
手瓜一十雪
db3d435402 feat: 彻底 扬了Old WebUi 2024-11-15 16:56:53 +08:00
手瓜一十雪
7ee48f1443 feat: 迁移后端与前端 大部分逻辑 2024-11-15 16:50:12 +08:00
手瓜一十雪
a54f30acc1 feat: 翻新除了配置文件的所有代码了 2024-11-15 16:45:57 +08:00
手瓜一十雪
75e7bc7275 feat: 开始迁移webui 2024-11-15 16:10:19 +08:00
手瓜一十雪
f1b2c8b1cf fix 2024-11-15 15:24:44 +08:00
手瓜一十雪
50079e7a96 fix: 面板关于信息 2024-11-15 14:46:05 +08:00
手瓜一十雪
6d37868ae8 refactor: nnetwork -> network 2024-11-15 13:57:45 +08:00
手瓜一十雪
543961e980 feat: 调整基础样式 2024-11-15 13:52:23 +08:00
手瓜一十雪
1e2c76bb47 feat: 布局面板基础结构 2024-11-15 13:25:02 +08:00
手瓜一十雪
ddc0ed066d feat: nav 2024-11-15 13:03:18 +08:00
手瓜一十雪
6708903c65 feat: 基础逻辑拼接 2024-11-15 11:32:30 +08:00
手瓜一十雪
5ee0afb604 Merge branch 'main' into refactor-config-webui 2024-11-15 10:42:02 +08:00
手瓜一十雪
9b20e9db29 feat: 路由 2024-11-15 10:41:55 +08:00
Mlikiowa
74b4d9bf49 release: v4.0.3
Some checks failed
Build Action / Build-LiteLoader (push) Failing after 7s
Build Action / Build-Shell (push) Failing after 8s
2024-11-14 15:34:43 +00:00
手瓜一十雪
89f7892681 fix: rkey 2024-11-14 23:30:52 +08:00
手瓜一十雪
f83bf197d2 feat: QQLogin 2024-11-14 22:02:15 +08:00
手瓜一十雪
5bcc130dd7 feat: 拆分组件 2024-11-14 21:46:54 +08:00
手瓜一十雪
4be6d8ec01 feat: 初始化webui login 2024-11-14 21:41:43 +08:00
Mlikiowa
aad5ed55d2 release: v4.0.2
Some checks are pending
Build Action / Build-LiteLoader (push) Waiting to run
Build Action / Build-Shell (push) Waiting to run
2024-11-14 12:45:02 +00:00
手瓜一十雪
86da417c17 feat: add SetMsgEmojiLike 2024-11-14 20:44:14 +08:00
手瓜一十雪
ae57ab78f3 fix: adapter api 2024-11-14 20:25:08 +08:00
手瓜一十雪
4487db4e0a feat: msg push 2024-11-14 20:18:19 +08:00
手瓜一十雪
a0a50755d3 feat: mergeOnebotConfigs 2024-11-14 18:00:31 +08:00
手瓜一十雪
621e41cc96 feat: new config helper/nnetwork 2024-11-14 17:00:34 +08:00
Mlikiowa
96b1f71437 release: v4.0.1 2024-11-14 07:43:36 +00:00
手瓜一十雪
5e0b3b2f35 fix: fluent-ffmpeg 2024-11-14 15:43:11 +08:00
pk5ls20
6829fad5bd chore: workflow build check 2024-11-14 14:30:56 +08:00
pk5ls20
7af0d9e87b refactor: simplify code 2024-11-14 14:29:38 +08:00
Mlikiowa
c089ebea99 release: v4.0.0 2024-11-14 06:00:34 +00:00
手瓜一十雪
d2a2c1c39c fix: #50 2024-11-14 13:58:25 +08:00
手瓜一十雪
ce9b09e8d1 fix: 简化代码 2024-11-14 13:49:37 +08:00
手瓜一十雪
2f6dfe51f5 fix: error 2024-11-14 13:43:39 +08:00
手瓜一十雪
bd227cd0b8 refactor: getGroupHonorInfo 2024-11-14 13:42:03 +08:00
手瓜一十雪
96003724ab refactor: nc shell login 2024-11-14 13:40:01 +08:00
pk5ls20
6a08b15095 chore: eslint 2024-11-14 13:29:39 +08:00
手瓜一十雪
dab0f9ab45 refactor: getImageUrl 2024-11-14 13:26:12 +08:00
手瓜一十雪
e733a6b69a fix: error 2024-11-14 13:22:58 +08:00
手瓜一十雪
9aca98bf13 fix: type 2024-11-14 13:19:50 +08:00
手瓜一十雪
b7c95e53dc fix: unuse import 2024-11-14 13:14:27 +08:00
手瓜一十雪
f762c450ca fix: error 2024-11-14 13:10:52 +08:00
手瓜一十雪
d58bbe53da Merge pull request #521 from abc1763613206/main
feat: add `emoji_package_id` for MarketFace
2024-11-14 13:10:04 +08:00
abc1763613206
f32edd8af7 feat: add emoji_package_id for MarketFace 2024-11-14 13:07:57 +08:00
手瓜一十雪
c747a86e5b fix 2024-11-14 13:07:10 +08:00
手瓜一十雪
abfda0dd58 fix: || -> ?? 2024-11-14 13:00:25 +08:00
手瓜一十雪
f66d7b11a8 fix: error throw 2024-11-14 12:54:58 +08:00
手瓜一十雪
f425c9478e fix 2024-11-14 12:48:19 +08:00
手瓜一十雪
756dea71fc remove: todo -> work 2024-11-14 12:44:21 +08:00
手瓜一十雪
71a6c4ccc5 fix: error handle 2024-11-14 12:37:16 +08:00
手瓜一十雪
ae2f4777ec fix 2024-11-14 12:32:48 +08:00
手瓜一十雪
dcd9b8168a feat: any listener 2024-11-14 12:28:08 +08:00
手瓜一十雪
4bb03ae5ba fix 2024-11-14 12:22:28 +08:00
手瓜一十雪
8bd6f8397b fix: assertion is unnecessary 2024-11-14 12:07:26 +08:00
手瓜一十雪
096e52d93e fix: promise async 2024-11-14 12:06:45 +08:00
手瓜一十雪
037065291d fix: 代码精简 2024-11-14 12:02:24 +08:00
手瓜一十雪
4cf52e1b13 fix: error 2024-11-14 11:53:55 +08:00
手瓜一十雪
21b228552d fix 2024-11-14 11:46:37 +08:00
手瓜一十雪
76b404cdd8 rename: WsPacketClient 2024-11-14 11:40:16 +08:00
手瓜一十雪
937c594ff7 fix 2024-11-14 11:35:10 +08:00
手瓜一十雪
b463140de7 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-14 11:30:56 +08:00
手瓜一十雪
f518fb9214 fix: readonly 2024-11-14 11:28:06 +08:00
手瓜一十雪
1092831718 Merge pull request #520 from NapNeko/refactor-4.0.0
refactor: 4.0.0
2024-11-14 11:24:57 +08:00
手瓜一十雪
6b377416da refactor: fix 2024-11-14 11:24:00 +08:00
手瓜一十雪
8f5baa47ec refactor: log最佳实践 2024-11-14 11:10:26 +08:00
手瓜一十雪
5494ff0553 refactor: build 2024-11-14 11:03:11 +08:00
手瓜一十雪
7a4805b464 refactor: registerListen 2024-11-14 10:57:57 +08:00
手瓜一十雪
8435375810 style: lint 2024-11-14 10:53:50 +08:00
手瓜一十雪
c893ec6030 refactor: apiInit Refactor 2024-11-14 10:52:03 +08:00
手瓜一十雪
e8bf6fa0a6 style: lint 2024-11-14 10:45:16 +08:00
手瓜一十雪
f228129c19 refactor: Init Core 2024-11-14 10:43:37 +08:00
手瓜一十雪
cbf98ffb89 refactor: async Init 2024-11-14 10:36:51 +08:00
手瓜一十雪
f6067b002f refactor: Shell Init 2024-11-14 10:34:38 +08:00
手瓜一十雪
636d1103e3 refactor: 删除反撤回模块 未来合并到MoeHoo 2024-11-14 10:30:01 +08:00
手瓜一十雪
bede517f7e refactor: package 2024-11-14 10:27:10 +08:00
手瓜一十雪
16e4891b7d fix 2024-11-13 22:54:56 +08:00
手瓜一十雪
3bcd79fbb7 docs: 文档精简 2024-11-13 22:46:48 +08:00
Mlikiowa
aacf6c2917 release: v3.7.0 2024-11-13 09:53:56 +00:00
pk5ls20
92d720cd57 Merge pull request #512 from NapNeko/refactor/packet-2
refactor: packet
2024-11-13 17:51:00 +08:00
pk5ls20
2ea025047f feat: comment out logic that is not currently needed 2024-11-13 17:48:42 +08:00
pk5ls20
f7f7e09cab feat: sysMessage oldProto adapter 2024-11-13 17:44:12 +08:00
pk5ls20
75866b435e feat: errorStack 2024-11-13 16:52:03 +08:00
手瓜一十雪
f07941685b Merge branch 'main' into refactor/packet-2 2024-11-13 16:00:45 +08:00
Mlikiowa
60a0539216 release: v3.6.17 2024-11-13 07:57:01 +00:00
手瓜一十雪
3dd4b6549f Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-13 15:56:31 +08:00
手瓜一十雪
0802c35dc1 feat: mface emoji_id 2024-11-13 15:56:17 +08:00
Mlikiowa
7d9d7226ec release: v3.6.16 2024-11-13 07:55:21 +00:00
手瓜一十雪
b5ef6ce6b0 feat: mface key 扩展 2024-11-13 15:54:31 +08:00
pk5ls20
49ec6181b0 fix: macos 2024-11-13 15:35:07 +08:00
pk5ls20
783a534768 fix: NativePacketClient 2024-11-13 14:16:42 +08:00
Mlikiowa
704ac11cbb release: v3.6.15 2024-11-13 05:16:36 +00:00
手瓜一十雪
aa9663d85e fix: 移除chalk 2024-11-13 13:16:09 +08:00
Mlikiowa
05291f34fb release: v3.6.14 2024-11-13 04:31:12 +00:00
手瓜一十雪
2260fe32a1 Merge pull request #514 from NapNeko/refactor-log4js--winston
refactor: log4js to winston
2024-11-13 12:29:35 +08:00
手瓜一十雪
2c398a6832 fix: error 2024-11-13 12:29:17 +08:00
手瓜一十雪
3e1f566699 feat: 异常处理与log4js替换 2024-11-13 12:26:23 +08:00
手瓜一十雪
4f89f184b8 refactor: package json 2024-11-13 12:19:18 +08:00
Mlikiowa
787685c937 release: v3.6.13 2024-11-12 10:45:11 +00:00
手瓜一十雪
ed9cd2fe38 fix: #513 2024-11-12 18:37:44 +08:00
pk5ls20
740d80e851 chore: minor adjust packet module 2024-11-12 04:14:08 +08:00
pk5ls20
4520a20bd4 chore: remove debug output 2024-11-12 04:08:51 +08:00
pk5ls20
98c65c4923 refactor: packet x1 2024-11-12 04:02:19 +08:00
Mlikiowa
e287906a9d release: v3.6.12 2024-11-11 13:03:29 +00:00
手瓜一十雪
8bae789020 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-11 21:00:27 +08:00
手瓜一十雪
ce57b7b725 fix: #509 2024-11-11 21:00:12 +08:00
pk5ls20
1d9872195d fix: offset name 2024-11-11 20:57:30 +08:00
pk5ls20
98d1f8e29f feat: add some macOS offset 2024-11-11 20:54:57 +08:00
手瓜一十雪
221b3fb730 fix 2024-11-11 20:35:13 +08:00
Mlikiowa
90a834495a release: v3.6.11 2024-11-11 12:17:25 +00:00
手瓜一十雪
8bfd102232 fix: macos arm64 28971 2024-11-11 20:16:44 +08:00
Mlikiowa
65e784f169 release: v3.6.10 2024-11-11 02:45:39 +00:00
手瓜一十雪
0fc81c672f fix: once升级 2024-11-11 10:45:15 +08:00
手瓜一十雪
62ae0f4321 feat: 文档镜像 2024-11-10 12:40:18 +08:00
Mlikiowa
a01a0a1a18 release: v3.6.9 2024-11-10 04:11:16 +00:00
手瓜一十雪
4c30cc69ad fix: #73 2024-11-10 12:10:43 +08:00
Mlikiowa
1d43b75df4 release: v3.6.8 2024-11-09 10:22:17 +00:00
手瓜一十雪
d02afdfc3e fix: 缓存 2024-11-09 18:21:50 +08:00
Mlikiowa
5d6dee9fd0 release: v3.6.7 2024-11-09 04:36:58 +00:00
手瓜一十雪
60c67ef41c Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-09 12:36:21 +08:00
手瓜一十雪
917d7c1f19 feat: user boot script 2024-11-09 12:35:50 +08:00
Mlikiowa
ad19f2c99e release: v3.6.6 2024-11-09 04:22:55 +00:00
手瓜一十雪
8a61f5a03f fix: #503 2024-11-09 12:22:28 +08:00
手瓜一十雪
8c164910f6 docs: 因为优点太多所以只好去掉几条了 2024-11-08 16:23:20 +08:00
pk5ls20
a560d3d266 chore: eslint migrate 2024-11-08 15:43:27 +08:00
手瓜一十雪
532f739272 Merge pull request #501 from NapNeko/eslint9
feat: eslint9
2024-11-08 12:38:12 +08:00
手瓜一十雪
a120727f2d feat: eslint9 2024-11-08 12:36:25 +08:00
手瓜一十雪
a9bcb830a8 feat: 迁移29456为标准版本 2024-11-08 12:14:15 +08:00
Mlikiowa
56e5f0033f release: v3.6.5 2024-11-08 01:20:08 +00:00
手瓜一十雪
101106996a feat: 29456 2024-11-08 09:18:40 +08:00
pk5ls20
41a81534dc feat: support 29456 2024-11-08 00:26:09 +08:00
Mlikiowa
1425e8f229 release: v3.6.4 2024-11-07 08:14:56 +00:00
手瓜一十雪
75bb1d2193 Merge pull request #499 from kanocence/main
修复 config 页面样式
2024-11-07 16:14:01 +08:00
手瓜一十雪
2a23820f9b Merge pull request #500 from Stapxs/patch-1
fix: 在处理 file uri 时可能会意外忽略 fragment 段
2024-11-07 16:13:06 +08:00
林小槐
2ee0fed047 fix: 在处理 file uri 时可能会意外忽略 fragment 段
在处理类似 C:\\test\\test#1.txt 时 #1.txt 由于为 url fragment 而被意外截断
2024-11-07 16:10:59 +08:00
kanocence
40be6b9c43 Merge branch 'NapNeko:main' into main 2024-11-07 15:34:19 +08:00
kanocence
a06b3f0246 feat: 💄 修改页面样式 2024-11-07 15:33:57 +08:00
Mlikiowa
4787fa53b4 release: v3.6.3 2024-11-07 04:16:13 +00:00
手瓜一十雪
a06158bf01 fix: 标准化接口 2024-11-07 12:15:49 +08:00
pk5ls20
314e7485b8 chore: format 2024-11-07 10:33:01 +08:00
pk5ls20
aed5d2d9f0 chore: log 2024-11-07 10:31:50 +08:00
pk5ls20
f44e48a28b fix: remove useless import 2024-11-06 16:58:12 +08:00
手瓜一十雪
38be90450c feat: 兼容gocq标准 2024-11-06 16:48:18 +08:00
手瓜一十雪
2dd57d7676 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-06 16:45:04 +08:00
手瓜一十雪
6b3b163fa8 fix: 错误代码 2024-11-06 16:45:01 +08:00
Mlikiowa
9792ebafdc release: v3.6.2 2024-11-06 08:00:05 +00:00
手瓜一十雪
d10e7c37cb fix: link 2024-11-06 15:59:39 +08:00
Mlikiowa
d38f1853a4 release: v3.6.1 2024-11-06 06:42:33 +00:00
手瓜一十雪
bdec16266e fix: #498 2024-11-06 14:42:05 +08:00
Mlikiowa
49ca698ab9 release: v3.6.0 2024-11-06 03:30:17 +00:00
pk5ls20
3efd8163c9 fix: MoeHoo-Linux Amd64 2024-11-06 11:28:57 +08:00
pk5ls20
cc2d11449c release: v3.5.2 2024-11-06 09:28:14 +08:00
pk5ls20
7e9c19ca5b fix: MoeHoo-Linux Arm64 2024-11-06 09:26:15 +08:00
Mlikiowa
3b01b6827f release: v3.5.1 2024-11-05 14:45:36 +00:00
手瓜一十雪
8d9ef851ba fix: linux arm64 2024-11-05 22:45:00 +08:00
手瓜一十雪
b070bc59bc fix: MoeHoo-Linux Amd64 2024-11-05 22:36:47 +08:00
Mlikiowa
8d663946e1 release: v3.5.0 2024-11-05 14:13:33 +00:00
pk5ls20
2a2328b029 feat: better edge case handling 2024-11-05 22:11:01 +08:00
pk5ls20
efc9064abb fix: better log 2024-11-05 21:54:52 +08:00
Mlikiowa
dd70adf071 release: v3.4.11 2024-11-05 13:52:22 +00:00
pk5ls20
0f427375cb fix: sendCommand 2024-11-05 21:48:39 +08:00
Mlikiowa
4001270b93 release: v3.4.10 2024-11-05 13:34:25 +00:00
手瓜一十雪
e7f5ed3bcc Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-05 21:33:51 +08:00
手瓜一十雪
05cdc37d0a fix: qqnt 29271 最新版兼容问题 2024-11-05 21:33:36 +08:00
Mlikiowa
27920e0bee release: v3.4.9 2024-11-05 13:22:43 +00:00
手瓜一十雪
ae409b7249 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-05 21:22:10 +08:00
手瓜一十雪
8276258348 fix: Once 2024-11-05 21:21:59 +08:00
Mlikiowa
1bf96a97a5 release: v3.4.8 2024-11-05 13:18:35 +00:00
手瓜一十雪
d672680c4c feat: 复活吧我的arm64 2024-11-05 21:17:07 +08:00
手瓜一十雪
b89f2805e7 feat: linux.x64'packet 2024-11-05 21:12:19 +08:00
手瓜一十雪
78b4aa9295 feat: linux x64 support 2024-11-05 21:11:41 +08:00
手瓜一十雪
0a06637e78 style: lint 2024-11-05 20:59:18 +08:00
手瓜一十雪
13afa2c7ab fix: 去掉开发日志 2024-11-05 20:54:39 +08:00
手瓜一十雪
51d34d17cc feat: 去掉无用日志 2024-11-05 20:52:36 +08:00
手瓜一十雪
18a99341d5 Merge pull request #494 from NapNeko/dependabot/npm_and_yarn/vite-tsconfig-paths-5.1.0
chore(deps-dev): bump vite-tsconfig-paths from 4.3.2 to 5.1.0
2024-11-05 20:50:59 +08:00
手瓜一十雪
f01c8f0110 Merge pull request #493 from NapNeko/multi-packet
refactor: automatically select the optimal packet backend
2024-11-05 20:50:36 +08:00
手瓜一十雪
d8070eee2a fix: LL 2024-11-05 20:49:16 +08:00
手瓜一十雪
8519b7f4df update: LiteLoader 2024-11-05 20:48:28 +08:00
手瓜一十雪
591ab1b1df feat: 去掉开发输出 2024-11-05 20:40:25 +08:00
手瓜一十雪
393815b11e fix 2024-11-05 20:33:55 +08:00
dependabot[bot]
341a397bc4 chore(deps-dev): bump vite-tsconfig-paths from 4.3.2 to 5.1.0
Bumps [vite-tsconfig-paths](https://github.com/aleclarson/vite-tsconfig-paths) from 4.3.2 to 5.1.0.
- [Release notes](https://github.com/aleclarson/vite-tsconfig-paths/releases)
- [Commits](https://github.com/aleclarson/vite-tsconfig-paths/compare/v4.3.2...v5.1.0)

---
updated-dependencies:
- dependency-name: vite-tsconfig-paths
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-05 08:39:26 +00:00
pk5ls20
e46d274a75 feat: add new NapCat config key: packetBackend
- Acceptable values: `native`, `frida`, `auto`, `disable`
- Default value is set to `auto`
2024-11-05 14:45:02 +08:00
pk5ls20
ad6f21980c refactor: auto judge client 2024-11-05 14:24:54 +08:00
pk5ls20
017b8b7f15 chore: better log 2024-11-05 13:52:56 +08:00
pk5ls20
9b448b17e6 refactor: NapProto -> https://github.com/NapNeko/NapProto 2024-11-05 12:47:28 +08:00
手瓜一十雪
f9996a9987 fix: 日志乱飞版本 2024-11-05 11:24:36 +08:00
手瓜一十雪
000ef55273 fix: 一点小问题 2024-11-05 10:25:41 +08:00
手瓜一十雪
e1ac0f02b4 fix: 搞炸了 让我思考下 2024-11-05 10:22:52 +08:00
手瓜一十雪
b9297e3f1d fix 2024-11-05 10:18:11 +08:00
手瓜一十雪
34d0669ca8 fix 2024-11-05 10:16:06 +08:00
手瓜一十雪
25e42720cf fix: 开始初步调试 2024-11-05 10:14:00 +08:00
手瓜一十雪
f7c1951191 fix: 一些异常类型 2024-11-05 10:07:56 +08:00
pk5ls20
479b971b0c refactor: automatically select the optimal packet backend 2024-11-04 23:52:52 +08:00
手瓜一十雪
347ba5f354 feat: 初步封装 NativePacketClient 2024-11-04 21:09:11 +08:00
pk5ls20
81dbb9d980 perf: use cache in NapProto 2024-11-04 14:42:16 +08:00
pk5ls20
c4e1a3ab04 fix: SendGroupAiRecord wrong return id 2024-11-04 14:41:16 +08:00
pk5ls20
90ec774a21 feat: better mface toPreview 2024-11-03 17:29:50 +08:00
手瓜一十雪
db7a27e624 style: lint 2024-11-03 12:13:56 +08:00
Mlikiowa
f7d965eda2 release: v3.4.7 2024-11-03 01:50:09 +00:00
手瓜一十雪
74ca2e2e16 Merge pull request #485 from clansty/revert/get_forward_msg
revert: 还原 ob11 风格 get_forward_msg
2024-11-03 09:48:07 +08:00
Clansty
8ab550f2f5 revert: 还原 ob11 风格 get_forward_msg 2024-11-03 09:44:35 +08:00
pk5ls20
018aca4db2 fix: type hint 2024-11-03 02:45:58 +08:00
Mlikiowa
d4327166c1 release: v3.4.6 2024-11-02 05:20:34 +00:00
手瓜一十雪
fa25d2e779 feat: arm64 29271 2024-11-02 13:19:13 +08:00
手瓜一十雪
3ce1c3f0ec feat: support 3.2.13-29271-x64 2024-11-02 10:58:36 +08:00
手瓜一十雪
96dff5141e feat: packet 29271 2024-11-02 10:46:15 +08:00
手瓜一十雪
78d85d9965 feat: 29271 2024-11-02 10:02:39 +08:00
手瓜一十雪
37ec455b02 Merge pull request #484 from NapNeko/feat/ai-voice
feat: ai voice
2024-11-02 08:15:05 +08:00
pk5ls20
6ab82739a6 feat: ai voice 2024-11-02 01:51:57 +08:00
手瓜一十雪
a36917e7c0 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-11-01 12:13:24 +08:00
手瓜一十雪
21f3428b36 feat: support 6.9.58-28971 2024-11-01 12:13:04 +08:00
Mlikiowa
f8a487db25 release: v3.4.5 2024-10-31 12:30:25 +00:00
手瓜一十雪
73a859be04 fix: report self 2024-10-31 20:30:02 +08:00
手瓜一十雪
63bcee01a1 fix: report self 2024-10-31 20:27:17 +08:00
Mlikiowa
85b4966ba8 release: v3.4.4 2024-10-31 11:32:42 +00:00
手瓜一十雪
36c2c567b7 fix: #444 2024-10-31 19:32:10 +08:00
Mlikiowa
7b1ac224f6 release: v3.4.3 2024-10-31 10:18:21 +00:00
手瓜一十雪
34d9f04f15 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-10-31 18:17:53 +08:00
手瓜一十雪
be5da7cc6f fix: 正向ws异常推送事件问题 2024-10-31 18:17:41 +08:00
Mlikiowa
8d32ccb5d4 release: v3.4.2 2024-10-31 10:03:19 +00:00
手瓜一十雪
6acceb884c fix: #473 2024-10-31 18:00:55 +08:00
Hao Guan
4c834fd640 chore: Major获取Appid添加提示 (#480) 2024-10-31 16:10:27 +08:00
Mlikiowa
301278c7a9 release: v3.4.1 2024-10-31 00:36:50 +00:00
凌莞~(=^▽^=)
42ee83c54f feat: GetStrangerInfo 加回以前的完整信息 (#479) 2024-10-31 07:25:13 +08:00
Mlikiowa
e631f69621 release: v3.4.0 2024-10-30 13:11:06 +00:00
Nepenthe
ce8760a39a 修复<get_record>接口 (#478) 2024-10-30 21:09:32 +08:00
Mlikiowa
ff952956de release: v3.3.27 2024-10-30 07:28:17 +00:00
手瓜一十雪
28f3ff4971 fix: reply msg 大坐牢 #452 #477 2024-10-30 15:27:26 +08:00
手瓜一十雪
19e728c3cb feat: 提升全平台兼容性 2024-10-30 13:50:47 +08:00
Mlikiowa
269773ed6b release: v3.3.26 2024-10-30 01:23:01 +00:00
Hao Guan
e0d32417e1 chore: AppID for macOS 6.9.58-28971 (#476) 2024-10-30 09:20:32 +08:00
pk5ls20
9fa6083bed refactor: kill any (#475)
* refactor: kill any stage 1

* refactor: kill any stage 2

* refactor: kill any stage 3
2024-10-30 09:10:30 +08:00
手瓜一十雪
4d2fccdfb4 style: lint 2024-10-29 18:48:20 +08:00
Mlikiowa
c1c4bdfe94 release: v3.3.25 2024-10-29 10:42:12 +00:00
手瓜一十雪
8a0e9e8b61 release: v3.3.25 2024-10-29 18:41:39 +08:00
手瓜一十雪
1190e14171 docs: 调整文档优先级 2024-10-29 14:25:36 +08:00
Mlikiowa
00292b177a release: v3.3.22 2024-10-29 02:56:37 +00:00
手瓜一十雪
88de57f984 Merge pull request #472 from pohgxz/main
完善<set_input_status>接口
2024-10-29 10:53:29 +08:00
手瓜一十雪
61ddf38892 fix: Error 2024-10-29 10:52:50 +08:00
Nepenthe
52b3540ec3 修改<get_profile_like>接口 2024-10-29 07:51:16 +08:00
Nepenthe
5f831958c3 完善<set_input_status>接口 2024-10-28 23:21:49 +08:00
手瓜一十雪
c3d4698af3 try fix: error 2024-10-28 21:34:13 +08:00
Mlikiowa
bd6e83217d release: v3.3.21 2024-10-28 04:05:30 +00:00
pk5ls20
50ec49d9a2 feat: GetMiniAppArk 2024-10-28 10:12:24 +08:00
pk5ls20
dc3a089070 chore: rename msg to message in packet module 2024-10-28 07:59:24 +08:00
Mlikiowa
530e380178 release: v3.3.20 2024-10-27 14:46:24 +00:00
手瓜一十雪
10e4387add fix: script 2024-10-27 22:45:51 +08:00
手瓜一十雪
e925bc3aa8 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-10-27 22:44:04 +08:00
手瓜一十雪
427b3a7560 release: v3.3.18 2024-10-27 22:43:55 +08:00
Version
c8da950725 chore:version change 2024-10-27 14:42:23 +00:00
手瓜一十雪
743c5b8196 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-10-27 22:41:56 +08:00
手瓜一十雪
5e62abea57 fix: version 控制 2024-10-27 22:41:46 +08:00
Version
6bfc545582 chore:version change 2024-10-27 14:37:13 +00:00
手瓜一十雪
411108a2d2 fix: version check 2024-10-27 22:36:48 +08:00
Version
308a6fa9e4 chore:version change 2024-10-27 14:33:40 +00:00
Version
2dc7b785d0 chore:version change 2024-10-27 14:33:19 +00:00
手瓜一十雪
0e69e9e839 fix: checkVersion 2024-10-27 22:32:52 +08:00
手瓜一十雪
b83229b5da feat: 自动化版本发布控制 2024-10-27 22:30:01 +08:00
手瓜一十雪
6f053f5f7d feat: 我补药要手动release啦! 2024-10-27 22:20:11 +08:00
手瓜一十雪
c3dc53eaaf release: v3.3.12 2024-10-27 22:14:17 +08:00
手瓜一十雪
ffdc34cfe2 Merge pull request #470 from pohgxz/main
修复<get_group_at_all_remain>接口总是返回<Error: atInfo not found>
2024-10-27 22:10:55 +08:00
手瓜一十雪
4825a0e341 fix: type Error 2024-10-27 22:07:11 +08:00
Nepenthe
95a00d7f35 修复<get_group_at_all_remain>接口总是返回<Error: atInfo not found> 2024-10-27 22:04:48 +08:00
手瓜一十雪
d885bab426 feat: 类型修复 2024-10-27 22:03:22 +08:00
手瓜一十雪
e2a6a0bc02 release: v3.2.12 2024-10-27 20:56:27 +08:00
手瓜一十雪
ff7d8609ce fix: #452 修复seq搜索的老问题 可能修好了 2024-10-27 20:52:09 +08:00
手瓜一十雪
7507b90e03 fix: #458 2024-10-27 20:38:02 +08:00
手瓜一十雪
2b226a4b27 release: v3.1.11 2024-10-27 19:29:42 +08:00
手瓜一十雪
8b0232c4fe fix: error 2024-10-27 11:17:01 +08:00
手瓜一十雪
0728ee9ad6 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-10-27 11:09:00 +08:00
手瓜一十雪
8c6f04d0bc feat: #469 回收连接(未测试) 2024-10-27 11:08:48 +08:00
pk5ls20
c67fad789e fix: compatibility bigint 2024-10-27 10:50:48 +08:00
手瓜一十雪
4072339d70 release: v3.1.10 2024-10-27 10:03:07 +08:00
手瓜一十雪
3a244f5804 style: lint 2024-10-27 10:02:42 +08:00
pk5ls20
f12cf59137 feat: enhance compatibility of upload_forward_msg with go-cqhttp 2024-10-27 09:59:38 +08:00
手瓜一十雪
c76f556a11 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-10-27 09:44:26 +08:00
手瓜一十雪
e0f3d07b98 release: 3.1.9 2024-10-27 09:44:14 +08:00
手瓜一十雪
378d85dc67 Merge pull request #468 from NapNeko/refactor/msg-element
refactor: core msg entity & packet msg converter & resolve #455
2024-10-27 09:40:41 +08:00
pk5ls20
875e91fc0e chore: simplify logic 2024-10-27 09:37:17 +08:00
pk5ls20
15f7cd9814 feat: better fake forwardMsg logic & display 2024-10-27 09:33:20 +08:00
pk5ls20
1eb5cd6237 fix: downloadRawMsgMedia edge case 2024-10-27 09:04:24 +08:00
pk5ls20
ad2f843c8f fix: downloadRawMsgMedia 2024-10-27 07:31:32 +08:00
pk5ls20
8e550e216e chore: i18n for packet log messages 2024-10-27 07:04:53 +08:00
pk5ls20
9f07b07c82 feat: support node id in fake forward (with auto download richMedia in reference message) 2024-10-27 06:50:59 +08:00
pk5ls20
0be6effc32 feat: support node id in fake forward (broken impl) 2024-10-27 05:19:53 +08:00
pk5ls20
7ab6a10fc9 refactor & fix: refactor msg entity & adjust some wrong definition 2024-10-27 04:16:15 +08:00
手瓜一十雪
fb09af0e64 release: v3.1.8 2024-10-26 21:25:03 +08:00
手瓜一十雪
0d99d30b2d feat: version hint 2024-10-26 21:24:24 +08:00
手瓜一十雪
0000ec8b5b fix: fetchFavEmojiList 2024-10-26 21:15:11 +08:00
手瓜一十雪
0085bd8a1f fix: q-gate 2024-10-26 20:46:38 +08:00
手瓜一十雪
617139dfa4 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-10-26 20:36:59 +08:00
手瓜一十雪
4eb4a612d0 fix: type 2024-10-26 20:25:34 +08:00
pk5ls20
cda5e784f6 fix: payload basic check in GetPacketStatusDepends 2024-10-26 19:51:43 +08:00
手瓜一十雪
d93a280ab3 fix: 进一步getNextMemberList 2024-10-26 18:40:21 +08:00
手瓜一十雪
f7e2b3a4a7 feat: new function 2024-10-26 18:10:08 +08:00
手瓜一十雪
39d9c8fa74 release: v3.1.7 2024-10-26 16:26:30 +08:00
手瓜一十雪
8823895a03 Merge pull request #466 from cnxysoft/upmain
perf: 群成员拉取
2024-10-26 16:18:17 +08:00
手瓜一十雪
b44a9e696c Merge branch 'main' into pr/466 2024-10-26 15:47:13 +08:00
手瓜一十雪
cf28a3dc17 fix: ai solve 2024-10-26 10:49:18 +08:00
手瓜一十雪
7416e6caf6 feat: GoCQHTTPDeleteFriend 2024-10-26 10:36:41 +08:00
手瓜一十雪
90f6896f3c feat: GoCQ兼容性提高 2024-10-26 10:22:04 +08:00
Alen
eebcd0700d Merge branch 'main' into upmain 2024-10-26 07:22:25 +08:00
Alen
133eee0c66 perf: 群成员拉取
getgroupmemberlist启用no_cache
2024-10-26 07:20:40 +08:00
pk5ls20
640fb75f74 feat: support for customizing the timestamp of fake forwardMsg 2024-10-26 04:06:42 +08:00
Alen
51dcc1add6 Merge branch 'main' into upmain 2024-10-25 23:58:18 +08:00
Alen
730c928f91 Merge pull request #465 from cnxysoft/upmain
refactor: 群成员列表获取
2024-10-25 23:49:27 +08:00
Alen
c3b7e111b9 style: 2024-10-25 22:26:18 +08:00
pk5ls20
1874e48925 Merge pull request #464 from clansty/feat/nested-forward
feat: 嵌套合并转发消息
2024-10-25 22:13:32 +08:00
pk5ls20
e7a082c91c feat: better recursive parsing with depth limits 2024-10-25 22:10:24 +08:00
Alen
5d4f45407e fix: 群成员拉取 2024-10-25 21:50:19 +08:00
Clansty
17c37ec32f feat: 嵌套合并转发消息 2024-10-25 19:37:04 +08:00
手瓜一十雪
b5f8140c79 feat: v3 Logo 2024-10-25 19:31:44 +08:00
手瓜一十雪
63f746c237 style: lint 2024-10-25 18:09:41 +08:00
手瓜一十雪
dac6709f27 feat: 6.9.56-28418-mac 2024-10-25 17:57:28 +08:00
手瓜一十雪
470c8d0b29 release: v3.1.6 2024-10-25 17:44:30 +08:00
Wesley F. Young
b0d35e803b update: bump express version to 5.0.0 (Why use beta.2?) 2024-10-25 09:59:02 +08:00
pk5ls20
a71475be8b feat: allow pass string user_id in handleForwardedNodesPacket 2024-10-25 09:17:16 +08:00
pk5ls20
b9f2cc5142 feat: reject >100MB video highway upload 2024-10-25 08:59:56 +08:00
pk5ls20
2d46e55b9b feat: better highway upload log 2024-10-25 08:54:18 +08:00
pk5ls20
684e254996 feat: make PacketMsgPttElement invalid 2024-10-25 08:33:26 +08:00
手瓜一十雪
a2f7903960 Merge pull request #460 from NapNeko/feat/packet-more
feat: support more element in proto
2024-10-25 08:26:52 +08:00
pk5ls20
c0c757d6bd Merge branch 'main' into feat/packet-more 2024-10-25 08:17:28 +08:00
pk5ls20
da0fad743d feat: maybe more stable fake forwardMsg 2024-10-25 08:09:17 +08:00
手瓜一十雪
80b10d6025 Merge pull request #463 from clansty/feat/custom-forward-display
feat: 自定义合并转发外显信息
2024-10-25 08:05:41 +08:00
pk5ls20
a27c2a69c4 feat: maybe more stable fake forwardMsg 2024-10-25 07:27:35 +08:00
pk5ls20
9ed2a2fd19 refactor: simplify oidb packet pack & send 2024-10-25 06:48:01 +08:00
pk5ls20
aa9d96718c refactor: outer calculation 2024-10-25 05:54:46 +08:00
pk5ls20
aa67a2b71c chore: cv多了( 2024-10-25 05:17:01 +08:00
pk5ls20
d3405edd42 refactor: packet highway & etc, kill some todo 2024-10-25 05:11:10 +08:00
Clansty
3612098d62 feat: 自定义合并转发外显信息 2024-10-25 02:42:50 +08:00
Alen
2f08b72d69 fix: 群成员拉取 2024-10-24 23:00:38 +08:00
手瓜一十雪
ab66904c1a feat: 3.2.13-28971-arm64 2024-10-24 21:57:54 +08:00
手瓜一十雪
55542a3dbe feat: 28971 Linux 2024-10-24 20:40:58 +08:00
手瓜一十雪
8569a45114 release: v3.1.5 2024-10-24 20:16:12 +08:00
手瓜一十雪
c790311fc3 release: v3.1.5 2024-10-24 20:11:39 +08:00
手瓜一十雪
3c45c8bd80 feat: 28971 2024-10-24 20:11:07 +08:00
手瓜一十雪
d5b7b3ae31 feat: ntappid 2024-10-24 17:55:33 +08:00
手瓜一十雪
43e73a5f24 doc: big Logo 2024-10-24 17:03:23 +08:00
手瓜一十雪
698947ed97 Merge branch 'main' into feat/packet-more 2024-10-24 14:00:17 +08:00
手瓜一十雪
f3d967ae07 release: 3.1.4 2024-10-24 13:39:05 +08:00
手瓜一十雪
dbe72fa07e feat: SetGroupSign 2024-10-24 13:38:22 +08:00
pk5ls20
801a97d85b chore: remove useless log 2024-10-24 04:58:53 +08:00
pk5ls20
9f8f938c47 feat: build & upload file 2024-10-24 04:53:41 +08:00
Wesley F. Young
8fe37d1c1e chore: reformat package.json 2024-10-23 17:54:12 +08:00
pk5ls20
5cca8457e7 chore: 有笨蛋 2024-10-23 16:33:05 +08:00
pk5ls20
e9332e7646 feat: add ptt msg pack & upload 2024-10-23 16:12:31 +08:00
手瓜一十雪
31365505d8 Merge pull request #461 from huankong233/main
优化 contact 支持群聊和私聊
2024-10-23 09:09:07 +08:00
huankong233
b3fbe9e34a 优化 contact 支持群聊和私聊 2024-10-23 09:05:45 +08:00
pk5ls20
4082b651c5 feat & fix: add video msg pack & upload, fix some bugs in uploading c2c elements 2024-10-23 06:14:48 +08:00
Alen
0081000ef0 Merge branch 'main' into upmain 2024-10-23 01:08:56 +08:00
Alen
ad4d6a1070 refactor: 群成员获取 2024-10-23 01:07:52 +08:00
手瓜一十雪
5190b26399 Merge pull request #457 from huankong233/main
删除一些过时的接口
2024-10-22 17:57:04 +08:00
手瓜一十雪
29a8db96f4 fix 2024-10-22 17:56:51 +08:00
huankong233
1a4c2cabfd 删除一些过时的接口 2024-10-22 16:45:52 +08:00
手瓜一十雪
ef9189055c release: 3.1.3 2024-10-22 12:43:54 +08:00
手瓜一十雪
5cc3719125 fix: rkey 2024-10-22 12:42:24 +08:00
手瓜一十雪
5d46f41348 fix: dep 2024-10-22 12:14:43 +08:00
手瓜一十雪
3c2c1963f4 release: 3.1.2 2024-10-22 12:11:02 +08:00
手瓜一十雪
4896ca9279 fix 2024-10-22 11:37:01 +08:00
手瓜一十雪
f0afba6cd9 fix: GetOnlineClient 2024-10-22 11:34:28 +08:00
手瓜一十雪
bd717c298a fix: get_online_clients 2024-10-22 11:17:39 +08:00
手瓜一十雪
baaa8a70dc release: 3.1.1 2024-10-22 11:08:24 +08:00
手瓜一十雪
6d561c6e6f Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-10-22 11:04:43 +08:00
手瓜一十雪
e6b6947d49 feat: 标准化凭据获取 2024-10-22 11:04:28 +08:00
手瓜一十雪
52e99a2175 Merge pull request #454 from huankong233/main
简单修复一些小问题
2024-10-22 10:17:08 +08:00
手瓜一十雪
052d17a46f fix: getfile 2024-10-22 10:15:16 +08:00
huankong233
1aa1f4c212 优化 getFile 处理逻辑 2024-10-22 09:48:55 +08:00
huankong233
c3a48e3344 修复标记好友/群聊信息已读逻辑 2024-10-21 19:51:17 +08:00
手瓜一十雪
1d5483dc28 Merge pull request #451 from huankong233/main
对接口顺序和文档同步
2024-10-21 16:47:46 +08:00
huankong233
54277fa0df CleanCache 未实现 2024-10-21 16:09:27 +08:00
huankong233
ab04bd262f 对接口顺序和文档同步 2024-10-21 15:49:57 +08:00
手瓜一十雪
fb23087b65 release: 3.1.0 2024-10-21 14:35:57 +08:00
手瓜一十雪
846fee7ac8 fix: error import 2024-10-21 14:33:12 +08:00
手瓜一十雪
977eacc679 try: fix arm64 2024-10-21 14:12:10 +08:00
手瓜一十雪
dacfefe644 style: lint 2024-10-21 10:17:31 +08:00
pk5ls20
345e941e11 chore: remove unnecessary comments 2024-10-21 04:10:53 +08:00
pk5ls20
6cb7d45464 feat & refactor: decouple the forwardMsg construction logic and implement the OB11 element conversion for the forward node. 2024-10-21 04:05:02 +08:00
pk5ls20
e7222653fa release: 3.0.6 2024-10-20 23:54:21 +08:00
pk5ls20
014f0758f5 chore: 部分回滚 https://github.com/NapNeko/NapCatQQ/commit/bb72d70b 2024-10-20 23:52:36 +08:00
pk5ls20
0e8b416f6d Merge pull request #448 from pk5ls20/feat/friend-poke
feat: add `friend_poke` OneBot11 API
2024-10-20 23:18:26 +08:00
pk5ls20
09a60a2204 feat: add friend_poke OneBot11 API 2024-10-20 23:09:38 +08:00
手瓜一十雪
b0eae307c2 release: 3.0.5 2024-10-20 22:18:57 +08:00
手瓜一十雪
f5d2b54cca fix: 兼容晚启动 2024-10-20 22:18:34 +08:00
手瓜一十雪
3eefec3899 release: v3.0.4 2024-10-20 19:52:23 +08:00
手瓜一十雪
b6a8094554 release: v3.0.3 2024-10-20 18:56:52 +08:00
Version
4083b35436 chore:version change 2024-10-20 10:55:12 +00:00
手瓜一十雪
bb72d70baf fix: #444 尝试修复 2024-10-20 18:52:18 +08:00
手瓜一十雪
95d1a77f52 fix: remark 2024-10-20 18:30:14 +08:00
手瓜一十雪
051729886e fix 2024-10-20 17:16:05 +08:00
手瓜一十雪
0f00123dc7 fix 2024-10-20 17:01:09 +08:00
手瓜一十雪
0b0a089d86 release: 3.0.1 2024-10-20 10:07:19 +08:00
手瓜一十雪
c711a7d99a fix: error 2024-10-20 10:05:58 +08:00
手瓜一十雪
43f1d8c88c Merge pull request #443 from pk5ls20/feat/i18n-packet-server-error-msg
feat: More user-friendly packetServer error message
2024-10-20 08:14:33 +08:00
手瓜一十雪
e818e79d20 Merge pull request #442 from pk5ls20/feat/better-forward-msg
feat: better fake forwardMsg display
2024-10-20 08:14:18 +08:00
pk5ls20
cbad3ff1de feat: More user-friendly packetServer error message x2 2024-10-20 07:46:57 +08:00
pk5ls20
16a2e5e996 feat: More user-friendly packetServer error message 2024-10-20 07:28:55 +08:00
pk5ls20
331c6a50d0 feat: better fake forwardMsg display 2024-10-20 07:06:13 +08:00
手瓜一十雪
31c4540ec6 fix: error 2024-10-19 23:00:39 +08:00
手瓜一十雪
1e6116554f fix: error Version 2024-10-19 22:53:32 +08:00
手瓜一十雪
a12ea0e761 Merge pull request #436 from pk5ls20/refactor/proto
Progressive NapCat.Packet
2024-10-19 22:20:40 +08:00
pk5ls20
c9e3bbcd9f feat: Implement complete transform & Build & Upload FakeForwardMsg 2024-10-19 22:13:31 +08:00
手瓜一十雪
9c17dc1b8f fix: error 2024-10-19 21:21:54 +08:00
手瓜一十雪
69d1cae686 fix: 进一步简化 2024-10-19 21:21:37 +08:00
手瓜一十雪
1c2404b6af fix: 再次简化日志 2024-10-19 21:19:14 +08:00
手瓜一十雪
b33b33739d fix: 日志梳理 2024-10-19 21:17:49 +08:00
手瓜一十雪
2b7886c682 fix: 日志有点乱 2024-10-19 19:33:01 +08:00
手瓜一十雪
106d1f6374 fix 2024-10-19 18:08:25 +08:00
手瓜一十雪
e601786bd7 fix: CloudFlare Url 2024-10-19 18:00:34 +08:00
手瓜一十雪
fda2a98b40 version: 3.0.0 2024-10-19 17:54:26 +08:00
手瓜一十雪
c01d70b8fc fix: Mirrror Docs 2024-10-19 17:47:05 +08:00
手瓜一十雪
eccbcc3e28 fix:docs 2024-10-19 09:25:40 +08:00
pk5ls20
7a4a255a89 refactor: simplify the PacketClient availability check process & add action nc_get_packet_status 2024-10-19 04:41:32 +08:00
pk5ls20
83bced82b1 feat: add action get_group_file_url 2024-10-19 04:14:01 +08:00
pk5ls20
f3033ce732 feat: remove 10ms delay in sendSsoCmdReqByContend 2024-10-19 02:12:22 +08:00
pk5ls20
5c21a1727c feat: add packGroupFileDownloadReq & packC2CFileDownloadReq 2024-10-19 02:05:46 +08:00
pk5ls20
93aab437b7 chore: standardize proto file naming 2024-10-19 01:59:11 +08:00
pk5ls20
34e797270f feat: adjust FileNapCatOneBotUUID to support encode fileUUID 2024-10-19 01:39:14 +08:00
手瓜一十雪
0f337a8d8c feat: 引导使用28788 2024-10-18 22:34:58 +08:00
手瓜一十雪
cc9b83089e Merge branch 'main' into pr/436 2024-10-18 21:44:34 +08:00
手瓜一十雪
a565929686 fix 2024-10-18 21:43:54 +08:00
手瓜一十雪
6adacea774 support linux x64 2024-10-18 21:07:32 +08:00
手瓜一十雪
47ab5421ed fix: appid-msf 2024-10-18 20:04:58 +08:00
pk5ls20
10c404d455 feat: adjust packetElement & packetMsg 2024-10-18 16:57:55 +08:00
pk5ls20
dfdca11155 feat & fix: revert assert import & support MFace element 2024-10-18 16:34:45 +08:00
pk5ls20
698e095364 feat & refactor: add more packetElement & refactor packetMsg 2024-10-18 16:01:54 +08:00
手瓜一十雪
524fd258d8 fix: 定义 2024-10-18 14:35:26 +08:00
pk5ls20
17e70a4360 feat: add more msgElement 2024-10-18 04:49:38 +08:00
pk5ls20
e4a533e7b7 feat: add more msgElement 2024-10-18 04:35:23 +08:00
pk5ls20
0cb68d3737 chore: remove useless comment 2024-10-17 23:38:44 +08:00
pk5ls20
9faeadbebe feat: parse trpc.group.long_msg_interface.MsgService.SsoSendLongMsg resp 2024-10-17 23:34:29 +08:00
pk5ls20
35d201cfb8 feat: support upload c2c pic 2024-10-17 23:29:53 +08:00
pk5ls20
205174255f feat: Introduce a 10ms delay to sendSsoCmdReqByContend and cache prepareUpload requests 2024-10-17 22:41:39 +08:00
pk5ls20
8873a030ab feat: packet highway (in right impl) 2024-10-17 19:45:21 +08:00
pk5ls20
0ab61bac12 refactor: optimised code 2024-10-17 03:29:36 +08:00
pk5ls20
b1157f60f5 feat & refactor: packet highway (in almost right impl) 2024-10-17 03:03:36 +08:00
手瓜一十雪
bb93df06b2 fix 2024-10-16 21:02:28 +08:00
手瓜一十雪
82e807fd80 fix 2024-10-16 21:02:09 +08:00
手瓜一十雪
29da539467 fix: cache 2024-10-16 20:50:44 +08:00
手瓜一十雪
659aa005b0 fix: 部分离谱情况 2024-10-16 20:49:12 +08:00
手瓜一十雪
3f20733e7e refactor: groupMember 2024-10-16 20:09:01 +08:00
手瓜一十雪
b15e1174d6 update: LL 2024-10-16 19:23:38 +08:00
pk5ls20
05b05fd74e Merge remote-tracking branch 'fork/refactor/proto' into refactor/proto 2024-10-16 11:59:57 +08:00
pk5ls20
d30d467a21 feat: broken highway 2024-10-16 11:58:47 +08:00
手瓜一十雪
cd62e8ca37 fix: memberLevel 2024-10-16 11:35:12 +08:00
手瓜一十雪
f9e44820c1 style: 标准化 2024-10-15 09:20:54 +08:00
手瓜一十雪
169ae6a4d0 style: 规范写法 2024-10-15 09:11:00 +08:00
手瓜一十雪
030ba15952 style: lint 2024-10-15 09:06:47 +08:00
手瓜一十雪
964874bdad fix: 临时会话上报问题 2024-10-15 08:58:28 +08:00
手瓜一十雪
7affa081ac fix #398 2024-10-14 22:13:41 +08:00
手瓜一十雪
10e281ed35 fix #428 2024-10-14 22:08:00 +08:00
手瓜一十雪
27081ae599 fix #391 2024-10-14 22:04:02 +08:00
手瓜一十雪
61cbcdffe8 fix #431 2024-10-14 21:56:51 +08:00
手瓜一十雪
eeb15ea564 fix: #429 2024-10-14 21:49:42 +08:00
手瓜一十雪
565c820925 fix: #408 2024-10-14 21:45:36 +08:00
pk5ls20
325dff5735 feat: minor feat client & add TODO 2024-10-14 18:03:30 +08:00
pk5ls20
397c2cf5f0 refactor: further decoupling of Packet and Core parts 2024-10-14 17:51:21 +08:00
pk5ls20
1fbc339a42 feat: update type define in packet 2024-10-14 17:05:04 +08:00
pk5ls20
f2c719c60d chore: format & minor refactor 2024-10-14 15:37:02 +08:00
pk5ls20
08505fcc9a feat: simplify code 2024-10-14 15:29:20 +08:00
pk5ls20
a79c933693 refactor: add available accessor property in PacketClient 2024-10-14 15:13:44 +08:00
pk5ls20
b4cb3ddf1c refactor: packet 2024-10-14 13:59:34 +08:00
手瓜一十雪
aa188a6e89 fix 2024-10-14 09:13:03 +08:00
手瓜一十雪
a04b6b8a70 fix 2024-10-14 09:09:29 +08:00
手瓜一十雪
11149d2743 fix 2024-10-14 09:07:03 +08:00
pk5ls20
86bfd990db feat: partly impl UploadForwardMsg 2024-10-14 02:25:56 +08:00
pk5ls20
9304430889 fix: deprecate the cache in constructor in NapProtoMsg 2024-10-14 01:07:14 +08:00
手瓜一十雪
095f1c270b Merge branch 'refactor/proto' of https://github.com/pk5ls20/NapCatQQ into pr/436 2024-10-13 19:39:25 +08:00
手瓜一十雪
d3f91a832b fix 2024-10-13 19:39:03 +08:00
pk5ls20
4790a1170f Merge remote-tracking branch 'fork/refactor/proto' into refactor/proto 2024-10-13 19:31:47 +08:00
pk5ls20
501c392028 feat: flexible NapProtoStructType 2024-10-13 19:31:32 +08:00
手瓜一十雪
9200520f70 fix: add test 2024-10-13 19:23:28 +08:00
手瓜一十雪
8122561337 fix 2024-10-13 19:06:12 +08:00
手瓜一十雪
c6dc86ef8d Merge branch 'refactor/proto' of https://github.com/pk5ls20/NapCatQQ into pr/436 2024-10-13 19:03:47 +08:00
手瓜一十雪
bea3b8485f fix 2024-10-13 17:32:49 +08:00
pk5ls20
b807b89cdc Merge remote-tracking branch 'fork/refactor/proto' into refactor/proto 2024-10-13 17:23:32 +08:00
pk5ls20
daac2f7fd9 refactor: packet 2024-10-13 17:23:07 +08:00
手瓜一十雪
f0a5523174 fix 2024-10-13 17:21:03 +08:00
手瓜一十雪
eda8fbb178 fix 2024-10-13 17:15:59 +08:00
手瓜一十雪
67ca6184e9 Revert "fix"
This reverts commit d79e91fc1e.
2024-10-13 17:09:23 +08:00
手瓜一十雪
d79e91fc1e fix 2024-10-13 17:05:19 +08:00
手瓜一十雪
1cdb93baa2 feat: get_rkey 2024-10-13 16:47:22 +08:00
手瓜一十雪
f91991e25c feat: Packet Rkey 2024-10-13 16:46:12 +08:00
pk5ls20
d21da47a7d feat & fix: feat proto & revert NapProto changes 2024-10-13 16:13:34 +08:00
手瓜一十雪
b4e22a345d feat:GetUserStatus 2024-10-13 14:18:35 +08:00
手瓜一十雪
30e594ae5f fix: arch 2024-10-13 14:07:04 +08:00
手瓜一十雪
ffba3573ba feat: 区分arch 2024-10-13 14:05:40 +08:00
手瓜一十雪
9df5bee8d3 fix 2024-10-13 13:55:20 +08:00
手瓜一十雪
71c0728622 feat: buildSetSpecialTittlePacket 2024-10-13 13:54:52 +08:00
手瓜一十雪
476d8ba14d fix 2024-10-13 13:35:17 +08:00
手瓜一十雪
274c956f16 fix 2024-10-13 11:58:08 +08:00
手瓜一十雪
3068f9ee3d fix: catch 2024-10-13 11:22:33 +08:00
手瓜一十雪
a0c49d5f7f feat: errorMsg opt 2024-10-13 10:57:03 +08:00
手瓜一十雪
a8534974fe fix 2024-10-13 10:18:45 +08:00
手瓜一十雪
c517790391 fix: oidb 2024-10-13 10:10:12 +08:00
pk5ls20
b7e875c77f feat: add more proto 2024-10-13 04:15:10 +08:00
pk5ls20
befd9c0624 refactor: adjust NapProto & proto structure 2024-10-13 02:57:12 +08:00
手瓜一十雪
7a46f11089 feat: oidb_0x9067_202 2024-10-12 23:09:33 +08:00
手瓜一十雪
dc168bf8b9 feat: proto 整理 2024-10-12 22:25:10 +08:00
手瓜一十雪
eef5293ca0 refactor: Poke 2024-10-12 22:17:40 +08:00
手瓜一十雪
a2c4498694 style: NapProto 2024-10-12 21:35:49 +08:00
pk5ls20
938a84a460 feat: introduce NapProtoMsg 2024-10-12 21:27:25 +08:00
手瓜一十雪
978d2c24ee fix: 注释掉无用代码 2024-10-12 19:57:51 +08:00
手瓜一十雪
cdd00d665d fix: packet send/recv 2024-10-12 19:51:29 +08:00
手瓜一十雪
bb8b06c044 feat: linux 2024-10-12 18:05:03 +08:00
手瓜一十雪
604c5dcdc1 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-10-12 16:10:40 +08:00
手瓜一十雪
6bc2ecdbf0 Update onebot11.json 2024-10-12 16:10:28 +08:00
手瓜一十雪
e91c81def7 Merge pull request #435 from NapNeko/dev-packet
build: poke test
2024-10-12 16:09:52 +08:00
手瓜一十雪
bedd2fa15a build: poke test 2024-10-12 15:39:49 +08:00
手瓜一十雪
50465eef54 Merge pull request #434 from NapNeko/dev-packet
Dev packet
2024-10-12 15:38:16 +08:00
手瓜一十雪
07689adfcd fix 2024-10-12 15:36:30 +08:00
手瓜一十雪
8f4f898675 fix 2024-10-12 15:34:10 +08:00
手瓜一十雪
968bd7a437 fix 2024-10-12 15:27:58 +08:00
手瓜一十雪
eba5900ba8 fix: send packet 2024-10-12 15:18:20 +08:00
手瓜一十雪
69c477b104 fix: new server 2024-10-12 14:49:54 +08:00
手瓜一十雪
c8df8f4f54 release: 2.6.27 2024-10-11 23:07:26 +08:00
手瓜一十雪
d35a19b4fd release: olpush remove 2024-10-11 23:06:18 +08:00
手瓜一十雪
a97437a6e5 fix 2024-10-11 23:03:09 +08:00
手瓜一十雪
39c4473367 feat: poke oidb.0xed3_1 2024-10-10 19:04:29 +08:00
手瓜一十雪
b882bc721d release: v2.6.24 2024-10-09 20:50:00 +08:00
手瓜一十雪
405cace489 feat: 9.9.15-28498 2024-10-09 20:14:42 +08:00
手瓜一十雪
402a7b7fc9 docs: 移除误导语句 2024-10-09 14:12:13 +08:00
手瓜一十雪
8ad805e654 docs: 修正 2024-10-08 14:26:03 +08:00
手瓜一十雪
b23c357f73 release: 2.6.24 2024-10-06 10:07:39 +08:00
Wesley F. Young
f561c2b0fa refactor: rewrite switch with object mapping or if-else 2024-10-05 17:03:02 +08:00
手瓜一十雪
5a8eea668f release: 2.6.23 2024-10-02 13:23:07 +08:00
手瓜一十雪
777143e502 feat: new log 2024-10-02 13:13:55 +08:00
手瓜一十雪
0d8c9a82fe fix: 空格目录 2024-10-02 11:45:19 +08:00
手瓜一十雪
d10ab1cce3 feat: 依赖调整 2024-10-02 11:29:05 +08:00
手瓜一十雪
ec25e09d73 release: 2.6.22 2024-10-02 10:10:01 +08:00
手瓜一十雪
cba9c78ab1 release: v2.6.21 2024-10-02 10:05:01 +08:00
手瓜一十雪
c32db4a881 fix: rkey v2 2024-10-02 10:03:48 +08:00
手瓜一十雪
871add3071 Merge pull request #419 from hguandl/macos
Fix Protobuf Dependencies & macOS Support
2024-10-01 22:59:07 +08:00
Hao Guan
e661c617a3 update: macOS support 2024-10-01 22:48:51 +08:00
Hao Guan
d4bf721540 fix: protobuf dependencies 2024-10-01 22:48:31 +08:00
Wesley F. Young
d91b55faed update: log group name & sender nickname onto console 2024-10-01 11:01:32 +08:00
Alen
9687832d4d chore: 拉高linuxQQ版本 2024-10-01 02:37:44 +08:00
手瓜一十雪
fc3e436744 fix: log 2024-09-30 17:07:30 +08:00
手瓜一十雪
da90245f7b release: v2.6.20 2024-09-30 17:05:02 +08:00
手瓜一十雪
410d6a85d7 fix: protobuf #417 2024-09-30 08:30:39 +08:00
手瓜一十雪
b693342e4f fix 2024-09-30 08:18:02 +08:00
手瓜一十雪
acca361f2e release: v2.6.18 2024-09-29 20:11:30 +08:00
手瓜一十雪
b663f47713 style: ScalarType 2024-09-29 20:10:14 +08:00
手瓜一十雪
d332b199b5 refactor: protobufjs给我似! 2024-09-29 20:06:11 +08:00
Alen
78bac1dbd1 Merge pull request #416 from cnxysoft/upmain
fix: 28418下载HASH
2024-09-29 16:21:52 +08:00
Alen
724ff215f9 fix: 28418下载HASH 2024-09-29 16:20:01 +08:00
手瓜一十雪
68ea146469 release: v2.6.17 2024-09-29 13:07:52 +08:00
手瓜一十雪
82583e616f fix: #415 2024-09-29 12:57:50 +08:00
手瓜一十雪
bfc339c58d refactor: #415 2024-09-29 12:53:18 +08:00
手瓜一十雪
fe4427c076 feat: message字段返回 #415 2024-09-29 12:30:29 +08:00
手瓜一十雪
5745f388a9 feat: 简化代码 #415 2024-09-29 12:19:04 +08:00
手瓜一十雪
377e3c253f feat: parseForward for array 2024-09-29 11:26:45 +08:00
手瓜一十雪
3007a0c00e feat: nativeNode 2024-09-28 23:00:47 +08:00
手瓜一十雪
f51ffc091d Merge pull request #410 from NapNeko/hook
[Hook] NapcatNative
2024-09-28 21:38:04 +08:00
手瓜一十雪
c37c364a08 release: 2.6.16 2024-09-28 21:37:38 +08:00
手瓜一十雪
331a106e9a Merge branch 'hook' of https://github.com/NapNeko/NapCatQQ into hook 2024-09-28 21:37:17 +08:00
手瓜一十雪
cd74687b7b fix: getMsg 2024-09-28 21:36:54 +08:00
Alen
b3e145c1e6 fix: 解析增加字段 2024-09-28 21:29:18 +08:00
Alen
d8e1547736 Merge pull request #414 from NapNeko/hook_test
fix: 撤回SEQ
2024-09-28 21:00:32 +08:00
Alen
8617f01924 fix: 撤回SEQ 2024-09-28 20:58:09 +08:00
手瓜一十雪
55f9e75e6a Merge branch 'main' into hook 2024-09-28 20:17:02 +08:00
手瓜一十雪
b93e7b7ed1 feat: get pskey 2024-09-28 20:16:47 +08:00
手瓜一十雪
89cc79ad60 fix 2024-09-28 19:08:18 +08:00
手瓜一十雪
8dd0e60eea fix 2024-09-28 19:04:11 +08:00
手瓜一十雪
df6113fdf6 fix:#如好 2024-09-28 17:38:26 +08:00
手瓜一十雪
3a3095d15a feat:28418 2024-09-28 17:13:06 +08:00
手瓜一十雪
fb4d07391e Hook: GroupRecall 2024-09-28 15:41:11 +08:00
手瓜一十雪
9bef9c85cf fix 2024-09-28 15:36:25 +08:00
Alen
b77b3f227f Merge pull request #411 from cnxysoft/upmain
chore: qqnt.json增加linux版本
2024-09-28 14:25:42 +08:00
Alen
6a065f0a34 Merge branch 'main' into upmain 2024-09-28 14:22:10 +08:00
手瓜一十雪
4e1e190797 Merge pull request #409 from Zengfanqiang06/patch-1
Update README.md
2024-09-28 13:28:58 +08:00
手瓜一十雪
1ce8cd2100 napcat native 2024-09-28 13:27:13 +08:00
Alen
c03af6b9ad Merge branch 'main' into upmain 2024-09-28 13:24:47 +08:00
Alen
adca850075 chore: 增加linux目标QQ版本配置 2024-09-28 13:20:19 +08:00
Qiao
e3616b484e Update README.md
删除句号让其更统一(
2024-09-28 13:05:03 +08:00
手瓜一十雪
cfd7808169 Merge pull request #404 from NapNeko/dependabot/npm_and_yarn/types/express-5.0.0
chore(deps-dev): bump @types/express from 4.17.21 to 5.0.0
2024-09-27 17:08:57 +08:00
手瓜一十雪
addcedc588 Merge pull request #402 from NapNeko/v3
[Refactor] 推进版本重构
2024-09-27 16:47:48 +08:00
Alen
bfea786088 Merge pull request #405 from cnxysoft/upmain
chore: Once去除LL默认config
2024-09-26 17:21:31 +08:00
手瓜一十雪
50e84c3c9e Revert "feat: FrameWork调整"
This reverts commit 652fe8d21e.
2024-09-26 17:01:18 +08:00
手瓜一十雪
dc92ace85e Revert "feat: 调整"
This reverts commit 1a543928b1.
2024-09-26 17:01:13 +08:00
手瓜一十雪
1a543928b1 feat: 调整 2024-09-26 16:33:04 +08:00
手瓜一十雪
652fe8d21e feat: FrameWork调整 2024-09-26 16:22:21 +08:00
dependabot[bot]
199690f45f chore(deps-dev): bump @types/express from 4.17.21 to 5.0.0
Bumps [@types/express](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/express) from 4.17.21 to 5.0.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/express)

---
updated-dependencies:
- dependency-name: "@types/express"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-26 08:20:36 +00:00
Alen
37a4dd4b00 chore: Once去除LL默认config 2024-09-26 16:16:46 +08:00
手瓜一十雪
34d4358bfc feat: 依赖简化 2024-09-26 16:10:52 +08:00
手瓜一十雪
90906b9019 style: lint 2024-09-26 16:08:50 +08:00
手瓜一十雪
1c212ff2b4 feat: new 2024-09-26 15:54:24 +08:00
手瓜一十雪
7d709f44a8 fix: 调整逻辑 2024-09-26 15:37:07 +08:00
手瓜一十雪
ea9e88a18a fix: 不可抗力 2024-09-26 15:31:50 +08:00
Alen
0be8a9c805 chore: 拉高目标QQ版本 2024-09-26 13:00:49 +08:00
手瓜一十雪
fcf8139afe release: 2.6.15 2024-09-25 15:51:25 +08:00
手瓜一十雪
62f969b50b feat: ver28327 2024-09-25 15:33:19 +08:00
Alen
6726062500 Merge pull request #397 from cnxysoft/upmain
chore: 增加下载链接HASH
2024-09-24 13:45:59 +08:00
Alen
cf1f4bdcaf chore: 增加下载链接HASH 2024-09-24 13:44:24 +08:00
手瓜一十雪
b09a14ad4e fix 2024-09-23 16:52:35 +08:00
手瓜一十雪
1dc62c9ca3 release:2.6.14 2024-09-23 16:46:39 +08:00
手瓜一十雪
beaa89a2dc release: v2.6.14 2024-09-23 16:42:34 +08:00
手瓜一十雪
f39a000b49 fix 2024-09-23 16:39:26 +08:00
手瓜一十雪
013a74fb14 fix2 2024-09-23 16:35:54 +08:00
手瓜一十雪
7c4964753b release: 2.6.14 2024-09-23 16:33:02 +08:00
手瓜一十雪
8353533d60 v2.6.13 2024-09-23 15:52:40 +08:00
手瓜一十雪
c06df27424 feat: 修复空格与中文问题 2024-09-23 15:52:16 +08:00
手瓜一十雪
ad82919ddf fix: 2.6.12 2024-09-23 09:35:08 +08:00
手瓜一十雪
44dbba17e1 rollup 2024-09-23 09:34:44 +08:00
手瓜一十雪
5ba110e1da feat: bind 2024-09-22 16:59:45 +08:00
手瓜一十雪
b6e392fdb2 release: v2.6.11 2024-09-22 11:42:13 +08:00
手瓜一十雪
2280e83aa2 fix: type 2024-09-21 17:40:42 +08:00
手瓜一十雪
f49b94edb9 Merge pull request #392 from Fripine/feat/more-music-types
feat: support more types of music cards
2024-09-21 15:00:59 +08:00
Fripine
2428a12221 chore 2024-09-21 12:30:05 +08:00
Fripine
9c353f3760 feat: support more types of music cards 2024-09-21 12:17:05 +08:00
手瓜一十雪
5b86d25d7f Merge pull request #389 from Fripine/fix/FriendAdd
fix: FriendAddNoticeEvent
2024-09-20 21:18:14 +08:00
Fripine
2b168e8bbc fix: FriendAdd 2024-09-20 15:50:31 +08:00
手瓜一十雪
537db32847 Merge pull request #388 from NapNeko/revert-387-fix/friendAddEvent
Revert "fix: 好友添加成功事件"
2024-09-20 15:36:32 +08:00
手瓜一十雪
498b7f9f2b Revert "fix: 好友添加成功事件" 2024-09-20 14:33:52 +08:00
手瓜一十雪
9935568597 Merge pull request #387 from Fripine/fix/friendAddEvent
fix: 好友添加成功事件
2024-09-20 13:00:13 +08:00
Fripine
467003af8c chore 2024-09-20 10:24:19 +08:00
Fripine
4c9edcc47b chore 2024-09-20 10:21:26 +08:00
Fripine
24bf9cf121 chore: 换一种方法 2024-09-20 10:17:30 +08:00
手瓜一十雪
e06f6f39a9 Merge pull request #386 from 123233513/main
增加处理消息段时的检查,过滤无效消息段。
2024-09-20 07:54:52 +08:00
123233513
98ee0c307b Merge branch 'main' of https://github.com/123233513/NapCatQQ 2024-09-20 04:57:41 +08:00
Fripine
5e53ea0bc3 fix: cant emit FriendAddNoticeEvent 2024-09-20 04:38:09 +08:00
123233513
847d88ea77 Update msg.ts
处理消息段时的检查,过滤无效消息段。
2024-09-19 22:14:18 +08:00
123233513
d5046cc2b3 Merge branch 'main' of https://githubfast.com/123233513/NapCatQQ 2024-09-19 21:36:52 +08:00
123233513
3ad64b7cbb 增加处理消息段时的检查,过滤无效消息段。 2024-09-19 21:31:33 +08:00
手瓜一十雪
0dbfe8ca55 feat: 拦截不合法消息 2024-09-19 20:49:33 +08:00
手瓜一十雪
91b794d66d release: 2.6.10 2024-09-19 20:45:09 +08:00
手瓜一十雪
0d65e1e314 release: 2.6.9 2024-09-18 21:52:16 +08:00
手瓜一十雪
2d8f58c6d8 feat: close xlog 2024-09-18 20:22:21 +08:00
手瓜一十雪
65888fa816 feat: close log 2024-09-18 20:18:35 +08:00
手瓜一十雪
857e882c6e release: fk tx 2024-09-18 11:20:58 +08:00
手瓜一十雪
add2931834 remove: debug 2024-09-18 11:19:59 +08:00
手瓜一十雪
cdda5f45ee refactor: guid fk tx 2024-09-18 11:19:29 +08:00
手瓜一十雪
5f73d6a913 feat: reportAmgomWeather a1 rnm tx 2024-09-18 11:01:12 +08:00
手瓜一十雪
0637882fbc release: rnm tx 2024-09-18 10:53:37 +08:00
手瓜一十雪
3f785bab20 feat: NodeIO3MiscService 2024-09-18 10:44:35 +08:00
手瓜一十雪
a4ca89bdd6 fi: 2.6.4 2024-09-17 23:40:44 +08:00
手瓜一十雪
1a64e796bd release: 2.6.4 2024-09-17 23:17:19 +08:00
手瓜一十雪
a8b85a34f7 feat: 追平NT逻辑 2024-09-17 23:17:02 +08:00
手瓜一十雪
e7bec7d6b0 feat: systemPlatform标准化 2024-09-17 22:24:09 +08:00
手瓜一十雪
a582026037 release:2.6.3 2024-09-17 13:57:54 +08:00
手瓜一十雪
1a67a001c5 style: lint 2024-09-17 13:15:12 +08:00
手瓜一十雪
406deac592 fix:api外的推送事件 2024-09-17 13:14:18 +08:00
手瓜一十雪
e719ae0676 release: 2.6.2 2024-09-17 13:01:02 +08:00
手瓜一十雪
d8b7726440 release:2.6.1 2024-09-17 11:46:20 +08:00
手瓜一十雪
49f642e712 Merge pull request #379 from NapNeko/2.6.0
推进2.6.0大幅度重写
2024-09-17 11:43:13 +08:00
手瓜一十雪
70117016ce shell: 移除旧代码实现 2024-09-17 11:23:41 +08:00
手瓜一十雪
a4738f6281 feat: 开发依赖清理 2024-09-17 11:14:23 +08:00
手瓜一十雪
b1fc72d696 chore: 移除旧版本逻辑 2024-09-17 11:08:47 +08:00
手瓜一十雪
457c2c2b50 推进2.6.0大幅度重写 2024-09-17 11:06:07 +08:00
手瓜一十雪
48848d7d1a feat: 暂时砍掉V2Event 2024-09-17 10:59:28 +08:00
手瓜一十雪
55b07ca3ab feat: 彻底移除event旧实现 2024-09-17 09:23:19 +08:00
手瓜一十雪
a1d4882e18 feat: 规范化Promise 2024-09-17 09:19:45 +08:00
手瓜一十雪
3843795d8f Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-09-17 08:56:53 +08:00
手瓜一十雪
f2bf8d42da release: 2.5.5 2024-09-17 08:56:43 +08:00
Alen
a3b244e114 Merge pull request #378 from cnxysoft/upmain
fix: 下载文件失败
2024-09-17 03:50:22 +08:00
Alen
3093bdbc68 fix: 下载失败
优化下载逻辑
2024-09-17 03:39:43 +08:00
Alen
9ab0799283 Merge branch 'main' into upmain 2024-09-16 20:59:41 +08:00
手瓜一十雪
236bec11ed release: 2.5.4 2024-09-16 20:57:56 +08:00
手瓜一十雪
de48b0f940 Merge pull request #370 from NapNeko/28060
for: 28060
2024-09-16 20:54:54 +08:00
手瓜一十雪
4885d4db86 support: linux28060 2024-09-16 20:33:27 +08:00
手瓜一十雪
0c7bbda936 feat: Linux28060Appid 2024-09-16 20:29:04 +08:00
手瓜一十雪
fa07c2c1fb update: appid 2024-09-16 19:31:24 +08:00
手瓜一十雪
5d17a191f6 Merge branch 'main' into 28060 2024-09-16 19:12:10 +08:00
手瓜一十雪
67fb74d3c2 fix 2024-09-16 19:07:05 +08:00
手瓜一十雪
dc04cfc1b3 Revert "chore: workflow"
This reverts commit 58cd38c4a8.
2024-09-16 19:03:14 +08:00
手瓜一十雪
d61d481965 Merge branch 'main' into 28060 2024-09-16 19:02:01 +08:00
手瓜一十雪
6b346ee1de fix 2024-09-16 19:01:01 +08:00
手瓜一十雪
d0f248aaf9 fix 2024-09-16 18:53:26 +08:00
手瓜一十雪
85c9227515 Merge branch 'main' into 28060 2024-09-16 18:52:32 +08:00
手瓜一十雪
73b6d3be84 release: 2.5.3 2024-09-16 18:51:26 +08:00
手瓜一十雪
1ff6ce2343 feat: FetchOtherProfileLike 2024-09-16 18:51:05 +08:00
手瓜一十雪
c145935d46 feat: contact 2024-09-16 18:47:51 +08:00
手瓜一十雪
e9ede6924e release: 2.5.2 2024-09-16 18:12:00 +08:00
手瓜一十雪
515a21761d back: linux to 27254 2024-09-16 18:11:33 +08:00
Alen
8d6397028b Revert "style"
This reverts commit 7e74578312.
2024-09-15 17:31:01 +08:00
Alen
eb4828d81f Merge branch 'main' into upmain 2024-09-15 17:24:43 +08:00
Alen
7e74578312 style 2024-09-15 17:24:02 +08:00
Alen
640e3516d4 style 2024-09-15 17:23:10 +08:00
手瓜一十雪
bd295a4632 Merge branch 'main' into 28060 2024-09-15 17:15:03 +08:00
Alen
166c30fe2c Merge pull request #375 from cnxysoft/test
fix: friend_add
2024-09-15 16:49:10 +08:00
Alen
66c1bab629 fix: friend_add
修复该事件中user_id为0的问题
2024-09-15 16:47:46 +08:00
手瓜一十雪
66656304f9 fix 2024-09-15 16:24:08 +08:00
手瓜一十雪
07f66e379d Merge branch 'main' into 28060 2024-09-15 16:20:37 +08:00
手瓜一十雪
7ae8fd60c4 release: 2.5.1 2024-09-15 16:20:26 +08:00
手瓜一十雪
7275066994 feat: skip Qrcode When Login 2024-09-15 16:18:43 +08:00
手瓜一十雪
385adec186 Merge branch 'main' into 28060 2024-09-15 16:04:19 +08:00
手瓜一十雪
96b5bec5ab feat: revert 2024-09-15 16:04:10 +08:00
手瓜一十雪
6a9ec4e5f0 Merge branch 'main' into 28060 2024-09-15 15:52:52 +08:00
手瓜一十雪
d9851493df fix: #361 2024-09-15 15:51:23 +08:00
手瓜一十雪
efdb520414 Merge branch 'main' into 28060 2024-09-15 15:38:32 +08:00
Alen
5548644aeb Merge pull request #373 from cnxysoft/test
fix: bugs
2024-09-15 15:37:09 +08:00
Alen
e3fcd91b2d Merge branch 'main' into test 2024-09-15 15:29:50 +08:00
手瓜一十雪
2cae30ba88 Merge branch 'main' into 28060 2024-09-15 15:20:52 +08:00
手瓜一十雪
58cd38c4a8 chore: workflow 2024-09-15 15:20:44 +08:00
手瓜一十雪
3300304feb Merge branch 'main' into 28060 2024-09-15 15:00:42 +08:00
手瓜一十雪
f0e376d06b fix: 移除错误action 2024-09-15 14:55:18 +08:00
手瓜一十雪
16f7bb48f2 fix: launcher 28060 2024-09-15 14:34:47 +08:00
手瓜一十雪
7f383dd29b Merge branch 'main' into 28060 2024-09-15 09:49:49 +08:00
手瓜一十雪
3dc529edf4 fix: #369 2024-09-15 09:39:17 +08:00
手瓜一十雪
45dedb4872 fix: 28060 2024-09-15 09:35:10 +08:00
手瓜一十雪
afcdd01c0d fix: typo 9.9.15-28060 2024-09-14 19:22:36 +08:00
手瓜一十雪
1164877e9a Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-09-14 19:10:34 +08:00
手瓜一十雪
fe92a449ba feat: 准备适配9.9.15-28060版本 2024-09-14 19:10:17 +08:00
Alen
401b0e2bd0 fix: 部分语音播放速率异常 2024-09-14 17:50:09 +08:00
手瓜一十雪
cf9c71fcc1 feat: 准备适配9.9.15-28606 2024-09-14 17:24:52 +08:00
Alen
15a2400069 fix: 修复文件删除失败
此处为重复插入待删列表
2024-09-14 11:12:43 +08:00
Alen
d68a39b49e fix: 定义错误 2024-09-14 10:49:43 +08:00
Alen
066ca22e24 Merge pull request #362 from cnxysoft/upmain
fix: 点赞通知解析
2024-09-14 01:24:20 +08:00
Alen
0418b926fe fix: 点赞通知解析失败 2024-09-14 00:42:10 +08:00
手瓜一十雪
be40bbdf40 release: 2.5.0 2024-09-13 17:42:11 +08:00
手瓜一十雪
df4f42e79e fix: video name 2024-09-13 17:38:11 +08:00
Alen
5f80058f70 Merge pull request #360 from cnxysoft/upmain
fix: bugs
2024-09-13 17:30:23 +08:00
Alen
0cbe59052d Merge branch 'main' into upmain 2024-09-13 17:25:59 +08:00
Alen
af28a26e37 fix: 无法发送url视频 2024-09-13 17:22:32 +08:00
Alen
70c596df93 fix: headers分割 2024-09-13 16:11:15 +08:00
手瓜一十雪
748b51428c feat: createUidFromTinyId 2024-09-13 16:05:25 +08:00
手瓜一十雪
8ad746397c feat: JoinDragonGroupEmoji 2024-09-13 15:35:05 +08:00
手瓜一十雪
45baed2f9a tag: deprecated 2024-09-13 15:30:04 +08:00
手瓜一十雪
74185f2d33 fix 2024-09-13 14:05:04 +08:00
手瓜一十雪
90a91e4105 fix 2024-09-13 13:54:12 +08:00
手瓜一十雪
11aa3a0315 feat: fetchOtherProfileLike 2024-09-12 20:05:46 +08:00
手瓜一十雪
0c2e39214f style: lint 2024-09-12 19:55:56 +08:00
手瓜一十雪
d89620d7a6 style: folder 2024-09-12 19:55:26 +08:00
手瓜一十雪
edf80775b7 release: v2.4.9 2024-09-12 19:47:57 +08:00
手瓜一十雪
46e56ac726 remove: polyFill 2024-09-12 19:35:54 +08:00
手瓜一十雪
40b2f6bfd6 release: 2.4.7 2024-09-12 18:31:11 +08:00
手瓜一十雪
911e4921e2 fix: 删除旧文件 2024-09-12 18:15:38 +08:00
手瓜一十雪
1db9bb419d fix: 一处异常字段 2024-09-12 10:55:18 +08:00
手瓜一十雪
c6241a94e3 style: lint 2024-09-12 09:28:41 +08:00
手瓜一十雪
1cbf75ca36 style: lint 2024-09-12 09:28:26 +08:00
手瓜一十雪
8f85c897c8 refactor: SysMsg 2024-09-12 09:20:10 +08:00
手瓜一十雪
29c31b7aba release: 2.4.6 2024-09-12 09:01:13 +08:00
手瓜一十雪
402919d6f2 feat: qucikLogin 2024-09-12 09:00:53 +08:00
手瓜一十雪
82608dd5ff fix: build 2024-09-12 00:17:35 +08:00
手瓜一十雪
f312368df2 build: fix2 2024-09-11 23:40:05 +08:00
手瓜一十雪
374fc64427 feat: delFile 2024-09-11 23:29:26 +08:00
手瓜一十雪
95bd74bb0d BUILD: TEST 2024-09-11 23:18:38 +08:00
手瓜一十雪
a9f5069649 Revert "build: debug"
This reverts commit 957f7ffd8d.
2024-09-11 22:41:59 +08:00
手瓜一十雪
957f7ffd8d build: debug 2024-09-11 22:28:28 +08:00
手瓜一十雪
336dd3ce10 chore: 扩展 2024-09-11 22:13:45 +08:00
手瓜一十雪
47a7295477 fix: typo
copilot
2024-09-11 20:24:50 +08:00
手瓜一十雪
341a0e1c2a chore: code 2024-09-11 20:10:52 +08:00
手瓜一十雪
c4f73d0eb8 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-09-11 20:01:36 +08:00
手瓜一十雪
bd9258bae4 release: 2.4.5 2024-09-11 20:01:27 +08:00
手瓜一十雪
e3b3260aa0 Merge pull request #357 from cnxysoft/test
feat: 被点赞事件
2024-09-11 20:00:11 +08:00
手瓜一十雪
676766c99e refactor: protobuf 2024-09-11 19:56:51 +08:00
Alen
1025a07593 revert 2024-09-11 17:17:49 +08:00
Alen
00c3fcd033 Merge branch 'main' into test 2024-09-11 16:32:45 +08:00
Alen
b8457d4aff feat: 被点赞事件 2024-09-11 16:32:28 +08:00
手瓜一十雪
a2ecf10d19 feat: 全面迁移V2 2024-09-11 15:44:41 +08:00
Alen
1e63a2a7e7 test: 被赞事件(未完成) 2024-09-11 02:28:47 +08:00
手瓜一十雪
964014fc5c fix: #355 2024-09-10 22:27:06 +08:00
手瓜一十雪
fc2bb6d8c3 docs: 移除注释 2024-09-10 18:58:27 +08:00
手瓜一十雪
1b10252d76 remove: NTQQCacheApi 2024-09-10 18:42:49 +08:00
手瓜一十雪
ad8af12a10 refactor: fsPromise catch 2024-09-10 18:41:01 +08:00
手瓜一十雪
b040c9b118 refactor: audio 2024-09-10 18:39:14 +08:00
Alen
f6da7da90b Merge pull request #352 from cnxysoft/upmain
fix: 踢官方机器人报错
2024-09-10 00:40:58 +08:00
Alen
a745185408 fix: 踢官方机器人报错 2024-09-10 00:38:10 +08:00
手瓜一十雪
d3336f9027 release: 2.4.3 2024-09-09 21:37:22 +08:00
687 changed files with 44478 additions and 13271 deletions

View File

@@ -12,7 +12,7 @@ insert_final_newline = true
# Set default charset
charset = utf-8
# 2 space indentation
# 4 space indentation
[*.{cjs,mjs,js,jsx,ts,tsx,css,scss,sass,html,json}]
indent_style = space
indent_size = 4

2
.env.universal Normal file
View File

@@ -0,0 +1,2 @@
VITE_BUILD_TYPE = Production
VITE_BUILD_PLATFORM = Universal

View File

@@ -1,64 +0,0 @@
module.exports = {
'env': {
'browser': true,
'es2021': true,
'node': true
},
'ignorePatterns': ['src/core/proto/'],
'extends': [
'eslint:recommended',
'plugin:@typescript-eslint/recommended'
],
'overrides': [
{
'env': {
'node': true
},
'files': [
'.eslintrc.{js,cjs}'
],
'parserOptions': {
'sourceType': 'script'
}
}
],
'parser': '@typescript-eslint/parser',
'parserOptions': {
'ecmaVersion': 'latest',
'sourceType': 'module'
},
'plugins': [
'@typescript-eslint',
'import'
],
'settings': {
'import/parsers': {
'@typescript-eslint/parser': ['.ts']
},
'import/resolver': {
'typescript': {
'alwaysTryTypes': true
}
}
},
'rules': {
'indent': [
'error',
4
],
'linebreak-style': [
'error',
'unix'
],
'semi': [
'error',
'always'
],
'no-unused-vars': 'off',
'no-async-promise-executor': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-var-requires': 'off',
'object-curly-spacing': ['error', 'always'],
}
};

View File

@@ -10,13 +10,12 @@ body:
在提交新的 Bug 反馈前,请确保您:
* 已经搜索了现有的 issues并且没有找到可以解决您问题的方法
* 不与现有的某一 issue 重复
* 不涉及[已经停止维护的特性](https://github.com/NapNeko/NapCatQQ?tab=readme-ov-file#挥别昨日),例如 CQ 码
- type: input
id: system-version
attributes:
label: 系统版本
description: 运行 QQNT 的系统版本
placeholder: Windows 10 Pro Workstation 22H2
placeholder: Windows 11 24H2
validations:
required: true
- type: input
@@ -24,7 +23,7 @@ body:
attributes:
label: QQNT 版本
description: 可在 QQNT 的「关于」的设置页中找到
placeholder: 9.9.7-21804
placeholder: 9.9.16-29927
validations:
required: true
- type: input
@@ -40,21 +39,21 @@ body:
attributes:
label: OneBot 客户端
description: 连接至 NapCat 的客户端版本信息
placeholder: Overflow 2.16.0-2cf7991-SNAPSHOT
placeholder: Karin 1.0.0
validations:
required: true
- type: textarea
id: what-happened
attributes:
label: 发生了什么?
description: 填写你认为的 NapCat 的不正常行为
description: 填写你认为的 NapCat 的常行为
validations:
required: true
- type: textarea
id: how-reproduce
attributes:
label: 如何复现
description: 填写应当如何操作才能触发这个不正常行为
description: 填写应当如何操作才能触发这个常行为
placeholder: |
1. xxx
2. xxx

View File

@@ -1,11 +1,6 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: "npm" # See documentation for possible values
directory: "/" # Location of package manifests
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
interval: "weekly"

View File

@@ -1,5 +1,7 @@
name: "Build Action"
on:
push:
pull_request:
workflow_dispatch:
permissions: write-all
@@ -10,23 +12,15 @@ jobs:
steps:
- name: Clone Main Repository
uses: actions/checkout@v4
with:
repository: 'NapNeko/NapCatQQ'
submodules: true
ref: main
token: ${{ secrets.NAPCAT_BUILD }}
- name: Use Node.js 20.X
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Build NuCat Framework
- name: Build NapCat.Framework
run: |
npm i
npm run build:framework
cd dist
npm i --omit=dev
npm i && cd napcat.webui && npm i && cd .. || exit 1
npm run build:framework && npm run depend || exit 1
rm package-lock.json
cd ..
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
@@ -37,23 +31,15 @@ jobs:
steps:
- name: Clone Main Repository
uses: actions/checkout@v4
with:
repository: 'NapNeko/NapCatQQ'
submodules: true
ref: main
token: ${{ secrets.NAPCAT_BUILD }}
- name: Use Node.js 20.X
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Build NuCat LiteLoader
- name: Build NapCat.Shell
run: |
npm i
npm run build:shell
cd dist
npm i --omit=dev
npm i && cd napcat.webui && npm i && cd .. || exit 1
npm run build:shell && npm run depend || exit 1
rm package-lock.json
cd ..
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:

View File

@@ -49,6 +49,9 @@ jobs:
- name: Build NuCat Framework
run: |
npm i
cd napcat.webui
npm i
cd ..
npm run build:framework
cd dist
npm i --omit=dev
@@ -78,6 +81,9 @@ jobs:
- name: Build NuCat Shell
run: |
npm i
cd napcat.webui
npm i
cd ..
npm run build:shell
cd dist
npm i --omit=dev
@@ -93,15 +99,18 @@ jobs:
needs: [Build-LiteLoader,Build-Shell]
runs-on: ubuntu-latest
steps:
- name: Clone Main Repository
uses: actions/checkout@v4
with:
repository: 'NapNeko/NapCatQQ'
submodules: true
ref: main
token: ${{ secrets.NAPCAT_BUILD }}
- name: Download All Artifact
uses: actions/download-artifact@v4
# - name: Compress subdirectories
# run: |
# cd ./NapCat.Shell/
# zip -q -r NapCat.Shell.zip *
# cd ..
# rm ./NapCat.Shell.zip -rf
# mv ./NapCat.Shell/NapCat.Shell.zip ./
- name: Compress subdirectories
run: |
cd ./NapCat.Shell/
@@ -114,6 +123,16 @@ jobs:
rm ./NapCat.Framework.zip -rf
mv ./NapCat.Shell/NapCat.Shell.zip ./
mv ./NapCat.Framework/NapCat.Framework.zip ./
mkdir ./NapCat.Framework.Windows.Once
unzip -q ./external/LiteLoaderWrapper.zip -d ./NapCat.Framework.Windows.Once
cd ./NapCat.Framework.Windows.Once
ls
mkdir -p ./LL/plugins/NapCatQQ
unzip -q ../NapCat.Framework.zip -d ./LL/plugins/NapCatQQ
zip -q -r NapCat.Framework.Windows.Once.zip *
cd ..
mv ./NapCat.Framework.Windows.Once/NapCat.Framework.Windows.Once.zip ./
- name: Extract version from tag
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
@@ -129,4 +148,5 @@ jobs:
files: |
NapCat.Framework.zip
NapCat.Shell.zip
NapCat.Framework.Windows.Once.zip
draft: true

3
.gitignore vendored
View File

@@ -5,10 +5,9 @@ pnpm-lock.yaml
out/
dist/
/src/core.lib/common/
/localdebug/
devconfig/*
# Editor
.vscode/*
!.vscode/extensions.json
.idea/*

10
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,10 @@
{
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.expand": false,
"explorer.fileNesting.patterns": {
".env.universal": ".env.*",
"tsconfig.json": "tsconfig.*.json, env.d.ts, vite.config.ts",
"package.json": "package-lock.json, eslint*, .prettier*, .editorconfig, manifest.json, logo.png, .gitignore, LICENSE"
},
"css.customData": [".vscode/tailwindcss.json"],
}

55
.vscode/tailwindcss.json vendored Normal file
View File

@@ -0,0 +1,55 @@
{
"version": 1.1,
"atDirectives": [
{
"name": "@tailwind",
"description": "Use the `@tailwind` directive to insert Tailwind's `base`, `components`, `utilities` and `screens` styles into your CSS.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#tailwind"
}
]
},
{
"name": "@apply",
"description": "Use the `@apply` directive to inline any existing utility classes into your own custom CSS. This is useful when you find a common utility pattern in your HTML that youd like to extract to a new component.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#apply"
}
]
},
{
"name": "@responsive",
"description": "You can generate responsive variants of your own classes by wrapping their definitions in the `@responsive` directive:\n```css\n@responsive {\n .alert {\n background-color: #E53E3E;\n }\n}\n```\n",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#responsive"
}
]
},
{
"name": "@screen",
"description": "The `@screen` directive allows you to create media queries that reference your breakpoints by **name** instead of duplicating their values in your own CSS:\n```css\n@screen sm {\n /* ... */\n}\n```\n…gets transformed into this:\n```css\n@media (min-width: 640px) {\n /* ... */\n}\n```\n",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#screen"
}
]
},
{
"name": "@variants",
"description": "Generate `hover`, `focus`, `active` and other **variants** of your own utilities by wrapping their definitions in the `@variants` directive:\n```css\n@variants hover, focus {\n .btn-brand {\n background-color: #3182CE;\n }\n}\n```\n",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#variants"
}
]
}
]
}

350
LICENSE
View File

@@ -1,343 +1,19 @@
GNU GENERAL PUBLIC Without Social media promotion LICENSE
Version 2, June 1991
Limited Redistribution License for NapCat
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Copyright © 2024 Mlikiowa
Preamble
1. Usage and Reproduction:
- Unauthorized use, reproduction, modification, or distribution of this code is prohibited without explicit permission from the main author of the NapCat repository.
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
2. Redistribution:
- Redistribution of this code is permitted, provided that the full text of this license is included, and the source and copyright information is clearly stated.
- Minor modifications and extensions are allowed for redistribution purposes, but the modified code must not be publicly released.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
3. Non-Commercial Use:
- This code is not to be used for any commercial purposes.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
4. Additional Permissions:
- Any rights not explicitly addressed in this license must be requested from and granted by the main author of the NapCat repository.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
dYou may use this software in accordance with the above terms,
but you are not allowed to promote this project or your projects
based on this project on any public social media.
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
5. Disclaimer:
- This code is provided "as is," without any express or implied warranties, including but not limited to the implied warranties of merchantability and fitness for a particular purpose. In no event shall the author be liable for any damages or other liability arising from, out of, or in connection with the use or distribution of this code.

View File

@@ -1,43 +1,67 @@
<div align="center">
<img src="https://socialify.git.ci/NapNeko/NapCatQQ/image?description=1&language=1&logo=https%3A%2F%2Fraw.githubusercontent.com%2FNapNeko%2FNapCatQQ%2Fmain%2Flogo.png&name=1&stargazers=1&theme=Auto" alt="NapCatQQ" width="640" height="320" />
![NapCatQQ](https://socialify.git.ci/NapNeko/NapCatQQ/image?font=Jost&logo=https%3A%2F%2Fnapneko.github.io%2Fassets%2Fnewlogo.png&name=1&owner=1&pattern=Diagonal+Stripes&stargazers=1&theme=Auto)
</div>
---
## 欢迎回
NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现
## 欢迎回
NapCatQQ 是现代化的基于 NTQQ 的 Bot 协议端实现
## 猫猫技能
- [x] **高性能**1K+ 群聊数目、20 线程并行发送消息毫无压力
- [x] **多种启动方式**支持以无头、LiteLoader 插件、仅 QQ GUI 三种方式启动
- [x] **多平台支持**: 覆盖 Windows / Linux (可选 Docker) / Android Termux / MacOS
- [x] **安装简单**: 支持一键脚本/程序自动部署/镜像部署等多种覆盖范围
- [x] **低占用**:无头模式占用资源极低,适合在服务器上运行
- [x] **超多接口**:实现大部分 OneBot 和 go-cqhttp 接口,超多扩展 API
- [x] **WebUI**:自带 WebUI 支持,远程管理更加便捷
- [x] **低故障率**:快速适配最新版本,日常保证 0 Issue
## 特性介绍
- [x] **安装简单**:就算是笨蛋也能使用
- [x] **性能友好**:就算是低内存也能使用
- [x] **接口丰富**:就算是没有也能使用
- [x] **稳定好用**:就算是被捉也能使用
## 使用猫猫
## 使用框架
可前往 [Release](https://github.com/NapNeko/NapCatQQ/releases/) 页面下载最新版本
**首次使用**请务必前往[官方文档](https://napneko.github.io/)查看使用教程
**首次使用**请务必查看如下文档看使用教程
### 文档地址
[Cloudflare.Worker](https://doc.napneko.icu/)
[Cloudflare.HKServer](https://napcat.napneko.icu/)
[Github.IO](https://napneko.github.io/)
[Cloudflare.Pages](https://napneko.pages.dev/)
[Server.Other](https://docs.napcat.cyou/)
[NapCat.Wiki](https://www.napcat.wiki)
## 回家旅途
[QQ Group](https://qm.qq.com/q/VfjAq5HIMS)
[QQ Group#1](https://qm.qq.com/q/I6LU87a0Yq)
[Telegram Link](https://t.me/+nLZEnpne-pQ1OWFl)
[QQ Group#2](https://qm.qq.com/q/HaRcfrHpUk)
## 猫猫朋友
感谢 [LLOneBot](https://github.com/LLOneBot/LLOneBot) 提供部分参考
[Telegram](https://t.me/MelodicMoonlight)
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持
> QQ Group#2 准许Bot / Telegram与QQ Group#2 为新建Group
## 性能设计/协议标准
NapCat 已实现90+的 OneBot / GoCQ 标准接口,并提供兼容性保留接口,其设计理念遵守 无数据库/异步优先/后台刷新 的性能思想。
由此设计带来一系列好处在开发中获取群员列表通常小于50Ms单条文本消息发送在320Ms以内在1k+的群聊流畅运行同时带来一些副作用消息Id无法持久无法上报撤回消息原始内容。
NapCat 在设计理念下遵守 OneBot 规范大多数要求并且积极改进,任何合理的标准化 Issue 与 Pr 将被接收。
## 感谢他们
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持 参考部分代码 已获授权
感谢 React 强力驱动 NapCat.WebUi
不过最最重要的 还是需要感谢屏幕前的你哦~
---
## 约法三章
> [!CAUTION]\
> **请不要在 QQ 官方群聊和任何影响力较大的简中互联网平台(包括但不限于: 哔哩哔哩,微博,知乎,抖音等)发布和讨论*任何*与本项目存在相关性的信息**
## 特殊感谢
[LLOneBot](https://github.com/LLOneBot/LLOneBot) 相关的开发曾参与本项目
任何使用本仓库代码的地方,都应当严格遵守[本仓库开源许可](./LICENSE)。**此外,禁止任何项目未经授权二次分发或基于 NapCat 代码开发。**
## 开源附加
任何使用本仓库代码的地方,都应当严格遵守[本仓库开源许可](./LICENSE)。**本仓库仅用于提高IM易用性实现类似Hook推送此外禁止任何项目未经仓库主作者授权二次分发或基于 NapCat 代码开发。使用请遵守当地法律法规,由此造成的问题由使用者和提供违规使用教程者负责。**

32
eslint.config.mjs Normal file
View File

@@ -0,0 +1,32 @@
import eslint from '@eslint/js';
import tsEslintPlugin from '@typescript-eslint/eslint-plugin';
import tsEslintParser from '@typescript-eslint/parser';
import globals from "globals";
const customTsFlatConfig = [
{
name: 'typescript-eslint/base',
languageOptions: {
parser: tsEslintParser,
sourceType: 'module',
globals: {
...globals.browser,
...globals.node,
NodeJS: 'readonly', // 添加 NodeJS 全局变量
},
},
files: ['**/*.{ts,tsx}'],
rules: {
...tsEslintPlugin.configs.recommended.rules,
'quotes': ['error', 'single'], // 使用单引号
'semi': ['error', 'always'], // 强制使用分号
'indent': ['error', 4], // 使用 4 空格缩进
},
plugins: {
'@typescript-eslint': tsEslintPlugin,
},
ignores: ['src/webui/**'], // 忽略 src/webui/ 目录所有文件
},
];
export default [eslint.configs.recommended, ...customTsFlatConfig];

BIN
external/LiteLoaderWrapper.zip vendored Normal file

Binary file not shown.

BIN
external/logo.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,32 @@
@echo off
chcp 65001
set NAPCAT_PATCH_PACKAGE=%cd%\qqnt.json
set NAPCAT_LOAD_PATH=%cd%\loadNapCat.js
set NAPCAT_INJECT_PATH=%cd%\NapCatWinBootHook.dll
set NAPCAT_LAUNCHER_PATH=%cd%\NapCatWinBootMain.exe
set NAPCAT_MAIN_PATH=%cd%\napcat.mjs
: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
if not exist "%QQpath%" (
echo provided QQ path is invalid: %QQpath%
pause
exit /b
)
set NAPCAT_MAIN_PATH=%NAPCAT_MAIN_PATH:\=/%
echo (async () =^> {await import("file:///%NAPCAT_MAIN_PATH%")})() > "%NAPCAT_LOAD_PATH%"
"%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%" %1
pause

View File

@@ -0,0 +1,33 @@
@echo off
chcp 65001
set NAPCAT_PATCH_PACKAGE=%cd%\qqnt.json
set NAPCAT_LOAD_PATH=%cd%\loadNapCat.js
set NAPCAT_INJECT_PATH=%cd%\NapCatWinBootHook.dll
set NAPCAT_LAUNCHER_PATH=%cd%\NapCatWinBootMain.exe
set NAPCAT_MAIN_PATH=%cd%\napcat.mjs
: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
if not exist "%QQpath%" (
echo provided QQ path is invalid: %QQpath%
pause
exit /b
)
set NAPCAT_MAIN_PATH=%NAPCAT_MAIN_PATH:\=/%
echo (async () =^> {await import("file:///%NAPCAT_MAIN_PATH%")})() > "%NAPCAT_LOAD_PATH%"
"%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%" %1
REM "%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%" 123456
pause

View File

@@ -5,11 +5,11 @@ if %errorLevel% == 0 (
echo Administrator mode detected.
) else (
echo Please run this script in administrator mode.
powershell -Command "Start-Process 'cmd.exe' -ArgumentList '/c cd /d \"%cd%\" && \"%~f0\"' -Verb runAs"
powershell -Command "Start-Process 'cmd.exe' -ArgumentList '/c cd /d \"%cd%\" && \"%~f0\" %1' -Verb runAs"
exit
)
set NAPCAT_PATCH_PATH=%cd%\patchNapCat.js
set NAPCAT_PATCH_PACKAGE=%cd%\qqnt.json
set NAPCAT_LOAD_PATH=%cd%\loadNapCat.js
set NAPCAT_INJECT_PATH=%cd%\NapCatWinBootHook.dll
set NAPCAT_LAUNCHER_PATH=%cd%\NapCatWinBootMain.exe
@@ -33,8 +33,8 @@ if not exist "%QQpath%" (
exit /b
)
set NAPCAT_MAIN_PATH=%NAPCAT_MAIN_PATH:\=/%
echo (async () =^> {await import("file:///%NAPCAT_MAIN_PATH%")})() > %NAPCAT_LOAD_PATH%
echo (async () =^> {await import("file:///%NAPCAT_MAIN_PATH%")})() > "%NAPCAT_LOAD_PATH%"
"%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%"
"%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%" %1
REM "%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%" 123456

View File

@@ -5,11 +5,11 @@ if %errorLevel% == 0 (
echo Administrator mode detected.
) else (
echo Please run this script in administrator mode.
powershell -Command "Start-Process 'wt.exe' -ArgumentList 'cmd /c cd /d \"%cd%\" && \"%~f0\"' -Verb runAs"
powershell -Command "Start-Process 'wt.exe' -ArgumentList 'cmd /c cd /d \"%cd%\" && \"%~f0\" %1' -Verb runAs"
exit
)
set NAPCAT_PATCH_PATH=%cd%\patchNapCat.js
set NAPCAT_PATCH_PACKAGE=%cd%\qqnt.json
set NAPCAT_LOAD_PATH=%cd%\loadNapCat.js
set NAPCAT_INJECT_PATH=%cd%\NapCatWinBootHook.dll
set NAPCAT_LAUNCHER_PATH=%cd%\NapCatWinBootMain.exe
@@ -34,8 +34,6 @@ if not exist "%QQpath%" (
)
set NAPCAT_MAIN_PATH=%NAPCAT_MAIN_PATH:\=/%
echo (async () =^> {await import("file:///%NAPCAT_MAIN_PATH%")})() > %NAPCAT_LOAD_PATH%
echo (async () =^> {await import("file:///%NAPCAT_MAIN_PATH%")})() > "%NAPCAT_LOAD_PATH%"
"%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%"
REM "%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%" 123456
"%NAPCAT_LAUNCHER_PATH%" "%QQPath%" "%NAPCAT_INJECT_PATH%" %1

View File

@@ -1 +0,0 @@
require('./launcher.node').load('external_index', module);

26
launcher/qqnt.json Normal file
View File

@@ -0,0 +1,26 @@
{
"name": "qq-chat",
"version": "9.9.17-30899",
"verHash": "ececf273",
"linuxVersion": "3.2.15-30899",
"linuxVerHash": "63c751e8",
"type": "module",
"private": true,
"description": "QQ",
"productName": "QQ",
"author": {
"name": "Tencent",
"email": "QQ-Team@tencent.com"
},
"homepage": "https://im.qq.com",
"sideEffects": true,
"bin": {
"qd": "externals/devtools/cli/index.js"
},
"main": "./loadNapCat.js",
"buildVersion": "30899",
"isPureShell": true,
"isByteCodeShell": true,
"platform": "win32",
"eleArch": "x64"
}

View File

@@ -0,0 +1,4 @@
@echo off
REM ./launcher.bat 123456
REM ./launcher-win10.bat 123456
REM 带有REM的为注释 删掉你需要的系统的那行REM这三个单词 修改QQ本脚本启动即可

BIN
logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 684 KiB

View File

@@ -4,16 +4,12 @@
"name": "NapCatQQ",
"slug": "NapCat.Framework",
"description": "高性能的 OneBot 11 协议实现",
"version": "2.4.2",
"version": "4.5.5",
"icon": "./logo.png",
"authors": [
{
"name": "MliKiowa",
"link": "https://github.com/MliKiowa"
},
{
"name": "Young",
"link": "https://github.com/Wesley-Young"
"name": "NapNeko",
"link": "https://github.com/NapNeko"
}
],
"repository": {

1
napcat.webui/.env Normal file
View File

@@ -0,0 +1 @@
VITE_DEBUG_BACKEND_URL="http://127.0.0.1:6099"

32
napcat.webui/.gitignore vendored Normal file
View File

@@ -0,0 +1,32 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# NPM LOCK files
package-lock.json
yarn.lock
pnpm-lock.yaml
dist.zip

1
napcat.webui/.npmrc Normal file
View File

@@ -0,0 +1 @@
public-hoist-pattern[]=*@heroui/*

View File

@@ -0,0 +1,7 @@
dist
*.md
*.html
yarn.lock
package-lock.json
node_modules
pnpm-lock.yaml

23
napcat.webui/.prettierrc Normal file
View File

@@ -0,0 +1,23 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"singleQuote": true,
"semi": false,
"trailingComma": "none",
"bracketSpacing": true,
"importOrder": [
"<THIRD_PARTY_MODULES>",
"^@/const/(.*)$",
"^@/store/(.*)$",
"^@/components/(.*)$",
"^@/contexts/(.*)$",
"^@/hooks/(.*)$",
"^@/utils/(.*)$",
"^@/(.*)$",
"^[./]"
],
"importOrderSeparation": true,
"importOrderSortSpecifiers": true,
"plugins": ["@trivago/prettier-plugin-sort-imports"]
}

21
napcat.webui/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 bietiaop
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

32
napcat.webui/README.md Normal file
View File

@@ -0,0 +1,32 @@
# NapCat WebUI
## 功能
- WebUI登录
- QQ登录
- 网络配置
- OneBot/WebUI配置
- 日志查看(实时日志、历史日志)
- HTTP调试
- WS调试
- 在线音乐播放器,支持网易云音乐歌单(大屏在页面右下角,小屏在页面下方)
如果你有更多功能需求,欢迎在 issue 中提出。
# License
[MIT](LICENSE)
# Related Projects
- [NapCat](https://github.com/NapNeko/NapCatQQ/)
- [Karin](https://github.com/KarinJS/Karin/)
# Thanks to
- [Vercel](https://vercel.com/)
- [React](https://react.dev/)
- [HeroUI](https://nextui.org/)
- and more open-source projects
感谢群友“维拉”提供的在线音乐API。

View File

@@ -0,0 +1,91 @@
import eslint_js from '@eslint/js'
import tsEslintPlugin from '@typescript-eslint/eslint-plugin'
import tsEslintParser from '@typescript-eslint/parser'
import eslintConfigPrettier from 'eslint-config-prettier'
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
import reactPlugin from 'eslint-plugin-react'
import reactHooksPlugin from 'eslint-plugin-react-hooks'
import globals from 'globals'
const customTsFlatConfig = [
{
name: 'typescript-eslint/base',
languageOptions: {
parser: tsEslintParser,
sourceType: 'module'
},
files: ['**/*.{js,jsx,mjs,cjs,ts,tsx}'],
rules: {
...tsEslintPlugin.configs.recommended.rules
},
plugins: {
'@typescript-eslint': tsEslintPlugin
}
}
]
export default [
eslint_js.configs.recommended,
eslintPluginPrettierRecommended,
...customTsFlatConfig,
{
name: 'global config',
languageOptions: {
globals: {
...globals.es2022,
...globals.browser,
...globals.node
},
parserOptions: {
warnOnUnsupportedTypeScriptVersion: false
}
},
rules: {
'prettier/prettier': 'error',
'no-unused-vars': 'off',
'no-undef': 'off',
//关闭不能再promise中使用ansyc
'no-async-promise-executor': 'off',
//关闭不能再常量中使用??
'no-constant-binary-expression': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-unused-vars': 'off',
//禁止失去精度的字面数字
'@typescript-eslint/no-loss-of-precision': 'off',
//禁止使用any
'@typescript-eslint/no-explicit-any': 'error'
}
},
{
ignores: ['**/node_modules', '**/dist', '**/output']
},
{
name: 'react-eslint',
files: ['src/*.{js,jsx,mjs,cjs,ts,tsx}'],
plugins: {
react: reactPlugin,
'react-hooks': reactHooksPlugin
},
languageOptions: {
...reactPlugin.configs.recommended.languageOptions
},
rules: {
...reactPlugin.configs.recommended.rules,
'react/react-in-jsx-scope': 'off'
},
settings: {
react: {
// 需要显示安装 react
version: 'detect'
}
}
},
{
languageOptions: { globals: { ...globals.browser, ...globals.node } }
},
eslintConfigPrettier
]

23
napcat.webui/index.html Normal file
View File

@@ -0,0 +1,23 @@
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>NapCat WebUI</title>
<meta key="title" content="NapCat WebUI" property="og:title" />
<meta content="NapCat WebUI基于React+tailwind+NextUI" property="og:description" />
<meta content="NapCat WebUI基于React+tailwind+NextUI" name="description" />
<meta key="viewport"
content="viewport-fit=cover, width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
name="viewport" />
<link href="/favicon.ico" rel="icon" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

126
napcat.webui/package.json Normal file
View File

@@ -0,0 +1,126 @@
{
"name": "napcat-webui",
"private": true,
"version": "0.0.6",
"type": "module",
"scripts": {
"dev": "vite --host=0.0.0.0",
"build": "tsc && vite build",
"lint": "eslint -c eslint.config.mjs ./src/**/**/*.{ts,tsx} --fix",
"preview": "vite preview"
},
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@heroui/avatar": "2.2.7",
"@heroui/breadcrumbs": "2.2.7",
"@heroui/button": "2.2.10",
"@heroui/card": "2.2.10",
"@heroui/checkbox": "2.3.9",
"@heroui/chip": "2.2.7",
"@heroui/code": "2.2.7",
"@heroui/dropdown": "2.3.10",
"@heroui/form": "2.1.9",
"@heroui/image": "2.2.6",
"@heroui/input": "2.4.10",
"@heroui/kbd": "2.2.7",
"@heroui/link": "2.2.8",
"@heroui/listbox": "2.3.10",
"@heroui/modal": "2.2.8",
"@heroui/navbar": "2.2.9",
"@heroui/pagination": "^2.2.9",
"@heroui/popover": "2.3.10",
"@heroui/select": "2.4.10",
"@heroui/slider": "2.4.8",
"@heroui/snippet": "2.2.11",
"@heroui/spinner": "2.2.7",
"@heroui/switch": "2.2.9",
"@heroui/system": "2.4.7",
"@heroui/table": "^2.2.9",
"@heroui/tabs": "2.2.8",
"@heroui/theme": "2.4.6",
"@heroui/tooltip": "2.2.8",
"@monaco-editor/loader": "^1.4.0",
"@monaco-editor/react": "4.7.0-rc.0",
"@react-aria/visually-hidden": "^3.8.19",
"@reduxjs/toolkit": "^2.5.1",
"@uidotdev/usehooks": "^2.4.1",
"@xterm/addon-canvas": "^0.7.0",
"@xterm/addon-fit": "^0.10.0",
"@xterm/addon-web-links": "^0.11.0",
"@xterm/xterm": "^5.5.0",
"ahooks": "^3.8.4",
"axios": "^1.7.9",
"clsx": "^2.1.1",
"echarts": "^5.5.1",
"event-source-polyfill": "^1.0.31",
"framer-motion": "^12.0.6",
"monaco-editor": "^0.52.2",
"motion": "^12.0.6",
"path-browserify": "^1.0.1",
"qface": "^1.4.1",
"qrcode.react": "^4.2.0",
"quill": "^2.0.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-dropzone": "^14.3.5",
"react-error-boundary": "^5.0.0",
"react-hook-form": "^7.54.2",
"react-hot-toast": "^2.4.1",
"react-icons": "^5.4.0",
"react-markdown": "^9.0.3",
"react-photo-view": "^1.2.7",
"react-redux": "^9.2.0",
"react-responsive": "^10.0.0",
"react-router-dom": "^7.1.4",
"react-use-websocket": "^4.11.1",
"react-window": "^1.8.11",
"remark-gfm": "^4.0.0",
"tailwind-variants": "^0.3.0",
"tailwindcss": "^3.4.17",
"zod": "^3.24.1"
},
"devDependencies": {
"@eslint/js": "^9.19.0",
"@react-types/shared": "^3.26.0",
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"@types/event-source-polyfill": "^1.0.5",
"@types/fabric": "^5.3.9",
"@types/node": "^22.12.0",
"@types/path-browserify": "^1.0.3",
"@types/react": "^19.0.8",
"@types/react-dom": "^19.0.3",
"@types/react-window": "^1.8.8",
"@typescript-eslint/eslint-plugin": "^8.22.0",
"@typescript-eslint/parser": "^8.22.0",
"@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "^10.4.20",
"eslint": "^9.19.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "5.2.3",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-unused-imports": "^4.1.4",
"globals": "^15.14.0",
"postcss": "^8.5.1",
"prettier": "^3.4.2",
"typescript": "^5.7.3",
"vite": "^6.0.5",
"vite-plugin-static-copy": "^2.2.0",
"vite-tsconfig-paths": "^5.1.4"
},
"overrides": {
"ahooks": {
"react": "$react",
"react-dom": "$react-dom"
},
"react-window": {
"react": "$react",
"react-dom": "$react-dom"
}
}
}

View File

@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,5 @@
{
"rewrites": [
{ "source": "/(.*)", "destination": "/" }
]
}

90
napcat.webui/src/App.tsx Normal file
View File

@@ -0,0 +1,90 @@
import { Suspense, lazy, useEffect } from 'react'
import { Provider } from 'react-redux'
import { Route, Routes, useNavigate } from 'react-router-dom'
import PageBackground from '@/components/page_background'
import PageLoading from '@/components/page_loading'
import Toaster from '@/components/toaster'
import DialogProvider from '@/contexts/dialog'
import AudioProvider from '@/contexts/songs'
import useAuth from '@/hooks/auth'
import store from '@/store'
const WebLoginPage = lazy(() => import('@/pages/web_login'))
const IndexPage = lazy(() => import('@/pages/index'))
const QQLoginPage = lazy(() => import('@/pages/qq_login'))
const DashboardIndexPage = lazy(() => import('@/pages/dashboard'))
const AboutPage = lazy(() => import('@/pages/dashboard/about'))
const ConfigPage = lazy(() => import('@/pages/dashboard/config'))
const DebugPage = lazy(() => import('@/pages/dashboard/debug'))
const HttpDebug = lazy(() => import('@/pages/dashboard/debug/http'))
const WSDebug = lazy(() => import('@/pages/dashboard/debug/websocket'))
const FileManagerPage = lazy(() => import('@/pages/dashboard/file_manager'))
const LogsPage = lazy(() => import('@/pages/dashboard/logs'))
const NetworkPage = lazy(() => import('@/pages/dashboard/network'))
const TerminalPage = lazy(() => import('@/pages/dashboard/terminal'))
function App() {
return (
<DialogProvider>
<Provider store={store}>
<PageBackground />
<Toaster />
<AudioProvider>
<Suspense fallback={<PageLoading />}>
<AuthChecker>
<AppRoutes />
</AuthChecker>
</Suspense>
</AudioProvider>
</Provider>
</DialogProvider>
)
}
function AuthChecker({ children }: { children: React.ReactNode }) {
const { isAuth } = useAuth()
const navigate = useNavigate()
useEffect(() => {
if (!isAuth) {
const search = new URLSearchParams(window.location.search)
const token = search.get('token')
let url = '/web_login'
if (token) {
url += `?token=${token}`
}
navigate(url, { replace: true })
}
}, [isAuth, navigate])
return <>{children}</>
}
function AppRoutes() {
return (
<Routes>
<Route path="/" element={<IndexPage />}>
<Route index element={<DashboardIndexPage />} />
<Route path="network" element={<NetworkPage />} />
<Route path="config" element={<ConfigPage />} />
<Route path="logs" element={<LogsPage />} />
<Route path="debug" element={<DebugPage />}>
<Route path="ws" element={<WSDebug />} />
<Route path="http" element={<HttpDebug />} />
</Route>
<Route path="file_manager" element={<FileManagerPage />} />
<Route path="terminal" element={<TerminalPage />} />
<Route path="about" element={<AboutPage />} />
</Route>
<Route path="/qq_login" element={<QQLoginPage />} />
<Route path="/web_login" element={<WebLoginPage />} />
</Routes>
)
}
export default App

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 KiB

View File

@@ -0,0 +1,425 @@
import { Button } from '@heroui/button'
import { Card, CardBody, CardHeader } from '@heroui/card'
import { Image } from '@heroui/image'
import { Popover, PopoverContent, PopoverTrigger } from '@heroui/popover'
import { Slider } from '@heroui/slider'
import { Tooltip } from '@heroui/tooltip'
import { useLocalStorage } from '@uidotdev/usehooks'
import clsx from 'clsx'
import { useEffect, useRef, useState } from 'react'
import {
BiSolidSkipNextCircle,
BiSolidSkipPreviousCircle
} from 'react-icons/bi'
import {
FaPause,
FaPlay,
FaRegHandPointRight,
FaRepeat,
FaShuffle
} from 'react-icons/fa6'
import { TbRepeatOnce } from 'react-icons/tb'
import { useMediaQuery } from 'react-responsive'
import { PlayMode } from '@/const/enum'
import key from '@/const/key'
import { VolumeHighIcon, VolumeLowIcon } from './icons'
export interface AudioPlayerProps
extends React.AudioHTMLAttributes<HTMLAudioElement> {
src: string
title?: string
artist?: string
cover?: string
pressNext?: () => void
pressPrevious?: () => void
onPlayEnd?: () => void
onChangeMode?: (mode: PlayMode) => void
mode?: PlayMode
}
export default function AudioPlayer(props: AudioPlayerProps) {
const {
src,
pressNext,
pressPrevious,
cover = 'https://nextui.org/images/album-cover.png',
title = '未知',
artist = '未知',
onTimeUpdate,
onLoadedData,
onPlay,
onPause,
onPlayEnd,
onChangeMode,
autoPlay,
mode = PlayMode.Loop,
...rest
} = props
const [currentTime, setCurrentTime] = useState(0)
const [duration, setDuration] = useState(0)
const [isPlaying, setIsPlaying] = useState(false)
const [volume, setVolume] = useState(100)
const [isCollapsed, setIsCollapsed] = useLocalStorage(
key.isCollapsedMusicPlayer,
false
)
const audioRef = useRef<HTMLAudioElement>(null)
const cardRef = useRef<HTMLDivElement>(null)
const startY = useRef(0)
const startX = useRef(0)
const [translateY, setTranslateY] = useState(0)
const [translateX, setTranslateX] = useState(0)
const isSmallScreen = useMediaQuery({ maxWidth: 767 })
const isMediumUp = useMediaQuery({ minWidth: 768 })
const shouldAdd = useRef(false)
const currentProgress = (currentTime / duration) * 100
const [storageAutoPlay, setStorageAutoPlay] = useLocalStorage(
key.autoPlay,
true
)
const handleTimeUpdate = (event: React.SyntheticEvent<HTMLAudioElement>) => {
const audio = event.target as HTMLAudioElement
setCurrentTime(audio.currentTime)
onTimeUpdate?.(event)
}
const handleLoadedData = (event: React.SyntheticEvent<HTMLAudioElement>) => {
const audio = event.target as HTMLAudioElement
setDuration(audio.duration)
onLoadedData?.(event)
}
const handlePlay = (e: React.SyntheticEvent<HTMLAudioElement>) => {
setIsPlaying(true)
setStorageAutoPlay(true)
onPlay?.(e)
}
const handlePause = (e: React.SyntheticEvent<HTMLAudioElement>) => {
setIsPlaying(false)
onPause?.(e)
}
const changeMode = () => {
const modes = [PlayMode.Loop, PlayMode.Random, PlayMode.Single]
const currentIndex = modes.findIndex((_mode) => _mode === mode)
const nextIndex = currentIndex + 1
const nextMode = modes[nextIndex] || modes[0]
onChangeMode?.(nextMode)
}
const volumeChange = (value: number) => {
setVolume(value)
}
useEffect(() => {
const audio = audioRef.current
if (audio) {
audio.volume = volume / 100
}
}, [volume])
const handleTouchStart = (e: React.TouchEvent) => {
startY.current = e.touches[0].clientY
startX.current = e.touches[0].clientX
}
const handleTouchMove = (e: React.TouchEvent) => {
const deltaY = e.touches[0].clientY - startY.current
const deltaX = e.touches[0].clientX - startX.current
const container = cardRef.current
const header = cardRef.current?.querySelector('[data-header]')
const headerHeight = header?.clientHeight || 20
const addHeight = (container?.clientHeight || headerHeight) - headerHeight
const _shouldAdd = isCollapsed && deltaY < 0
if (isSmallScreen) {
shouldAdd.current = _shouldAdd
setTranslateY(_shouldAdd ? deltaY + addHeight : deltaY)
} else {
setTranslateX(deltaX)
}
}
const handleTouchEnd = () => {
if (isSmallScreen) {
const container = cardRef.current
const header = cardRef.current?.querySelector('[data-header]')
const headerHeight = header?.clientHeight || 20
const addHeight = (container?.clientHeight || headerHeight) - headerHeight
const _translateY = translateY - (shouldAdd.current ? addHeight : 0)
if (_translateY > 100) {
setIsCollapsed(true)
} else if (_translateY < -100) {
setIsCollapsed(false)
}
setTranslateY(0)
} else {
if (translateX > 100) {
setIsCollapsed(true)
} else if (translateX < -100) {
setIsCollapsed(false)
}
setTranslateX(0)
}
}
const dragTranslate = isSmallScreen
? translateY
? `translateY(${translateY}px)`
: ''
: translateX
? `translateX(${translateX}px)`
: ''
const collapsedTranslate = isCollapsed
? isSmallScreen
? 'translateY(90%)'
: 'translateX(96%)'
: ''
const translateStyle = dragTranslate || collapsedTranslate
if (!src) return null
return (
<div
className={clsx(
'fixed right-0 bottom-0 z-[52] w-full md:w-96',
!translateX && !translateY && 'transition-transform',
isCollapsed && 'md:hover:!translate-x-80'
)}
style={{
transform: translateStyle
}}
>
<audio
src={src}
onLoadedData={handleLoadedData}
onTimeUpdate={handleTimeUpdate}
onPlay={handlePlay}
onPause={handlePause}
onEnded={onPlayEnd}
autoPlay={autoPlay ?? storageAutoPlay}
{...rest}
controls={false}
hidden
ref={audioRef}
/>
<Card
ref={cardRef}
className={clsx(
'border-none bg-background/60 dark:bg-default-300/50 w-full max-w-full transform transition-transform backdrop-blur-md duration-300 overflow-visible',
isSmallScreen ? 'rounded-t-3xl' : 'md:rounded-l-xl'
)}
classNames={{
body: 'p-0'
}}
shadow="sm"
radius="none"
>
{isMediumUp && (
<Button
isIconOnly
className={clsx(
'absolute data-[hover]:bg-foreground/10 text-lg z-50',
isCollapsed
? 'top-0 left-0 w-full h-full rounded-xl bg-opacity-0 hover:bg-opacity-30'
: 'top-3 -left-8 rounded-l-full bg-opacity-50 backdrop-blur-md'
)}
variant="solid"
color="danger"
size="sm"
onPress={() => setIsCollapsed(!isCollapsed)}
>
<FaRegHandPointRight />
</Button>
)}
{isSmallScreen && (
<CardHeader
data-header
className="flex-row justify-center pt-4"
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onTouchEnd={handleTouchEnd}
onClick={() => setIsCollapsed(!isCollapsed)}
>
<div className="w-24 h-2 rounded-full bg-content2-foreground shadow-sm"></div>
</CardHeader>
)}
<CardBody>
<div className="grid grid-cols-6 md:grid-cols-12 gap-6 md:gap-4 items-center justify-center overflow-hidden p-6 md:p-2 m-0">
<div className="relative col-span-6 md:col-span-4 flex justify-center">
<Image
alt="Album cover"
className="object-cover"
classNames={{
wrapper: 'w-36 aspect-square md:w-24 flex',
img: 'block w-full h-full'
}}
shadow="md"
src={cover}
width="100%"
/>
</div>
<div className="flex flex-col col-span-6 md:col-span-8">
<div className="flex flex-col gap-0">
<h1 className="font-medium truncate">{title}</h1>
<p className="text-xs text-foreground/80 truncate">{artist}</p>
</div>
<div className="flex flex-col">
<Slider
aria-label="Music progress"
classNames={{
track: 'bg-default-500/30 border-none',
thumb: 'w-2 h-2 after:w-1.5 after:h-1.5',
filler: 'rounded-full'
}}
color="foreground"
value={currentProgress || 0}
defaultValue={0}
size="sm"
onChange={(value) => {
value = Array.isArray(value) ? value[0] : value
const audio = audioRef.current
if (audio) {
audio.currentTime = (value / 100) * duration
}
}}
/>
<div className="flex justify-between h-3">
<p className="text-xs">
{Math.floor(currentTime / 60)}:
{Math.floor(currentTime % 60)
.toString()
.padStart(2, '0')}
</p>
<p className="text-xs text-foreground/50">
{Math.floor(duration / 60)}:
{Math.floor(duration % 60)
.toString()
.padStart(2, '0')}
</p>
</div>
</div>
<div className="flex w-full items-center justify-center">
<Tooltip
content={
mode === PlayMode.Loop
? '列表循环'
: mode === PlayMode.Random
? '随机播放'
: '单曲循环'
}
>
<Button
isIconOnly
className="data-[hover]:bg-foreground/10 text-lg md:text-medium"
radius="full"
variant="light"
size="md"
onPress={changeMode}
>
{mode === PlayMode.Loop && (
<FaRepeat className="text-foreground/80" />
)}
{mode === PlayMode.Random && (
<FaShuffle className="text-foreground/80" />
)}
{mode === PlayMode.Single && (
<TbRepeatOnce className="text-foreground/80 text-xl" />
)}
</Button>
</Tooltip>
<Tooltip content="上一首">
<Button
isIconOnly
className="data-[hover]:bg-foreground/10 text-2xl md:text-xl"
radius="full"
variant="light"
size="md"
onPress={pressPrevious}
>
<BiSolidSkipPreviousCircle />
</Button>
</Tooltip>
<Tooltip content={isPlaying ? '暂停' : '播放'}>
<Button
isIconOnly
className="data-[hover]:bg-foreground/10 text-3xl md:text-3xl"
radius="full"
variant="light"
size="lg"
onPress={() => {
if (isPlaying) {
audioRef.current?.pause()
setStorageAutoPlay(false)
} else {
audioRef.current?.play()
}
}}
>
{isPlaying ? <FaPause /> : <FaPlay className="ml-1" />}
</Button>
</Tooltip>
<Tooltip content="下一首">
<Button
isIconOnly
className="data-[hover]:bg-foreground/10 text-2xl md:text-xl"
radius="full"
variant="light"
size="md"
onPress={pressNext}
>
<BiSolidSkipNextCircle />
</Button>
</Tooltip>
<Popover
placement="top"
classNames={{
content: 'bg-opacity-30 backdrop-blur-md'
}}
>
<PopoverTrigger>
<Button
isIconOnly
className="data-[hover]:bg-foreground/10 text-xl md:text-xl"
radius="full"
variant="light"
size="md"
>
<VolumeHighIcon />
</Button>
</PopoverTrigger>
<PopoverContent>
<Slider
orientation="vertical"
showTooltip
aria-label="Volume"
className="h-40"
color="primary"
defaultValue={volume}
onChange={(value) => {
value = Array.isArray(value) ? value[0] : value
volumeChange(value)
}}
startContent={<VolumeHighIcon className="text-2xl" />}
size="sm"
endContent={<VolumeLowIcon className="text-2xl" />}
/>
</PopoverContent>
</Popover>
</div>
</div>
</div>
</CardBody>
</Card>
</div>
)
}

View File

@@ -0,0 +1,208 @@
import { Button } from '@heroui/button'
import {
Dropdown,
DropdownItem,
DropdownMenu,
DropdownTrigger
} from '@heroui/dropdown'
import { Tooltip } from '@heroui/tooltip'
import { FaRegCircleQuestion } from 'react-icons/fa6'
import { IoAddCircleOutline } from 'react-icons/io5'
import {
HTTPClientIcon,
HTTPServerIcon,
PCIcon,
PlusIcon,
WebsocketIcon
} from '../icons'
export interface AddButtonProps {
onOpen: (key: keyof OneBotConfig['network']) => void
}
const AddButton: React.FC<AddButtonProps> = (props) => {
const { onOpen } = props
return (
<Dropdown
classNames={{
content: 'bg-opacity-30 backdrop-blur-md'
}}
placement="right"
>
<DropdownTrigger>
<Button
color="danger"
startContent={<IoAddCircleOutline className="text-2xl" />}
>
</Button>
</DropdownTrigger>
<DropdownMenu
aria-label="Create Network Config"
color="primary"
variant="flat"
onAction={(key) => {
onOpen(key as keyof OneBotConfig['network'])
}}
>
<DropdownItem
key="title"
isReadOnly
className="cursor-default hover:!bg-transparent"
textValue="title"
>
<div className="flex items-center gap-2 justify-center">
<div className="w-5 h-5 -ml-3">
<PlusIcon />
</div>
<div className="text-primary-400"></div>
</div>
</DropdownItem>
<DropdownItem
key="httpServers"
textValue="httpServers"
startContent={
<div className="w-6 h-6">
<HTTPServerIcon />
</div>
}
>
<div className="flex gap-1 items-center">
HTTP服务器
<Tooltip
content="「由NapCat建立」一个HTTP服务器你可以「使用框架连接」此服务器或者「自己构造请求发送」至此服务器。NapCat会根据你配置的IP和端口等建立一个地址你或者你的框架应该连接到这个地址。"
showArrow
className="max-w-64"
>
<Button
isIconOnly
radius="full"
size="sm"
variant="light"
className="w-4 h-4 min-w-0"
>
<FaRegCircleQuestion />
</Button>
</Tooltip>
</div>
</DropdownItem>
<DropdownItem
key="httpSseServers"
textValue="httpSseServers"
startContent={
<div className="w-6 h-6">
<HTTPServerIcon />
</div>
}
>
<div className="flex gap-1 items-center">
HTTP SSE服务器
<Tooltip
content="「由NapCat建立」一个HTTP SSE服务器你可以「使用框架连接」此服务器或者「自己构造请求发送」至此服务器。NapCat会根据你配置的IP和端口等建立一个地址你或者你的框架应该连接到这个地址。"
showArrow
className="max-w-64"
>
<Button
isIconOnly
radius="full"
size="sm"
variant="light"
className="w-4 h-4 min-w-0"
>
<FaRegCircleQuestion />
</Button>
</Tooltip>
</div>
</DropdownItem>
<DropdownItem
key="httpClients"
textValue="httpClients"
startContent={
<div className="w-6 h-6">
<HTTPClientIcon />
</div>
}
>
<div className="flex gap-1 items-center">
HTTP客户端
<Tooltip
content="「由框架或者你自己建立」的一个用于「接收」NapCat向你发送请求的客户端通常框架会提供一个HTTP地址。这个地址是你使用的框架提供的NapCat会主动连接它。"
showArrow
className="max-w-64"
>
<Button
isIconOnly
radius="full"
size="sm"
variant="light"
className="w-4 h-4 min-w-0"
>
<FaRegCircleQuestion />
</Button>
</Tooltip>
</div>
</DropdownItem>
<DropdownItem
key="websocketServers"
textValue="websocketServers"
startContent={
<div className="w-6 h-6">
<WebsocketIcon />
</div>
}
>
<div className="flex gap-1 items-center">
Websocket服务器
<Tooltip
content="「由NapCat建立」一个WebSocket服务器你的框架应该连接到此服务器。NapCat会根据你配置的IP和端口等建立一个WebSocket地址你或者你的框架应该连接到这个地址。"
showArrow
className="max-w-64"
>
<Button
isIconOnly
radius="full"
size="sm"
variant="light"
className="w-4 h-4 min-w-0"
>
<FaRegCircleQuestion />
</Button>
</Tooltip>
</div>
</DropdownItem>
<DropdownItem
key="websocketClients"
textValue="websocketClients"
startContent={
<div className="w-6 h-6">
<PCIcon />
</div>
}
>
<div className="flex gap-1 items-center">
Websocket客户端
<Tooltip
content="「由框架或者你自己建立」的WebSocket通常框架会「提供」一个ws地址NapCat会主动连接它。"
showArrow
className="max-w-64"
>
<Button
isIconOnly
radius="full"
size="sm"
variant="light"
className="w-4 h-4 min-w-0"
>
<FaRegCircleQuestion />
</Button>
</Tooltip>
</div>
</DropdownItem>
</DropdownMenu>
</Dropdown>
)
}
export default AddButton

View File

@@ -0,0 +1,51 @@
import { Button } from '@heroui/button'
import toast from 'react-hot-toast'
import { IoMdRefresh } from 'react-icons/io'
export interface SaveButtonsProps {
onSubmit: () => void
reset: () => void
refresh?: () => void
isSubmitting: boolean
}
const SaveButtons: React.FC<SaveButtonsProps> = ({
onSubmit,
reset,
isSubmitting,
refresh
}) => (
<div className="max-w-full mx-3 w-96 flex flex-col justify-center gap-3">
<div className="flex items-center justify-center gap-2 mt-5">
<Button
color="default"
onPress={() => {
reset()
toast.success('重置成功')
}}
>
</Button>
<Button
color="danger"
isLoading={isSubmitting}
onPress={() => onSubmit()}
>
</Button>
{refresh && (
<Button
isIconOnly
color="secondary"
radius="full"
variant="flat"
onPress={() => refresh()}
>
<IoMdRefresh size={24} />
</Button>
)}
</div>
</div>
)
export default SaveButtons

View File

@@ -0,0 +1,254 @@
import { Button } from '@heroui/button'
import { Input } from '@heroui/input'
import { Popover, PopoverContent, PopoverTrigger } from '@heroui/popover'
import { Tooltip } from '@heroui/tooltip'
import clsx from 'clsx'
import { useEffect, useRef, useState } from 'react'
import toast from 'react-hot-toast'
import { FaMicrophone } from 'react-icons/fa6'
import { IoMic } from 'react-icons/io5'
import { MdEdit, MdUpload } from 'react-icons/md'
import useShowStructuredMessage from '@/hooks/use_show_strcuted_message'
import { isURI } from '@/utils/url'
import type { OB11Segment } from '@/types/onebot'
const AudioInsert = () => {
const [audioUrl, setAudioUrl] = useState<string>('')
const audioInputRef = useRef<HTMLInputElement>(null)
const showStructuredMessage = useShowStructuredMessage()
const showAudioSegment = (file: string) => {
const messages: OB11Segment[] = [
{
type: 'record',
data: {
file: file
}
}
]
showStructuredMessage(messages)
}
const [isRecording, setIsRecording] = useState(false)
const mediaRecorderRef = useRef<MediaRecorder | null>(null)
const audioChunksRef = useRef<Blob[]>([])
const [audioPreview, setAudioPreview] = useState<string | null>(null)
const [showPreview, setShowPreview] = useState(false)
const streamRef = useRef<MediaStream | null>(null)
const [recordingTime, setRecordingTime] = useState(0)
const recordingIntervalRef = useRef<NodeJS.Timeout | null>(null)
useEffect(() => {
if (isRecording) {
navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
streamRef.current = stream
const recorder = new MediaRecorder(stream)
mediaRecorderRef.current = recorder
recorder.start()
recorder.ondataavailable = (event) => {
if (event.data.size > 0) {
audioChunksRef.current.push(event.data)
}
}
recorder.onstop = () => {
if (audioChunksRef.current.length > 0) {
const audioBlob = new Blob(audioChunksRef.current, {
type: 'audio/wav'
})
const reader = new FileReader()
reader.readAsDataURL(audioBlob)
reader.onloadend = () => {
const base64Audio = reader.result as string
setAudioPreview(base64Audio)
setShowPreview(true)
}
audioChunksRef.current = []
}
stream.getTracks().forEach((track) => track.stop())
}
})
recordingIntervalRef.current = setInterval(() => {
setRecordingTime((prevTime) => prevTime + 1)
}, 1000)
} else {
mediaRecorderRef.current?.stop()
if (recordingIntervalRef.current) {
clearInterval(recordingIntervalRef.current)
recordingIntervalRef.current = null
}
}
}, [isRecording])
const startRecording = () => {
setAudioPreview(null)
setShowPreview(false)
setRecordingTime(0)
setIsRecording(true)
}
const stopRecording = () => {
setIsRecording(false)
}
const handleShowPreview = () => {
if (audioPreview) {
showAudioSegment(audioPreview)
}
}
const formatTime = (time: number) => {
const minutes = Math.floor(time / 60)
const seconds = time % 60
return `${minutes}:${seconds.toString().padStart(2, '0')}`
}
return (
<>
<Popover>
<Tooltip content="发送音频">
<div className="max-w-fit">
<PopoverTrigger>
<Button color="danger" variant="flat" isIconOnly radius="full">
<IoMic className="text-xl" />
</Button>
</PopoverTrigger>
</div>
</Tooltip>
<PopoverContent className="flex-row gap-2 p-4">
<Tooltip content="上传音频">
<Button
className="text-lg"
color="danger"
isIconOnly
variant="flat"
radius="full"
onPress={() => {
audioInputRef?.current?.click()
}}
>
<MdUpload />
</Button>
</Tooltip>
<Popover>
<Tooltip content="输入音频地址">
<div className="max-w-fit">
<PopoverTrigger tooltip="输入音频地址">
<Button
className="text-lg"
color="danger"
isIconOnly
variant="flat"
radius="full"
>
<MdEdit />
</Button>
</PopoverTrigger>
</div>
</Tooltip>
<PopoverContent className="flex-row gap-1 p-2">
<Input
value={audioUrl}
onChange={(e) => setAudioUrl(e.target.value)}
placeholder="请输入音频地址"
/>
<Button
color="danger"
variant="flat"
isIconOnly
radius="full"
onPress={() => {
if (!isURI(audioUrl)) {
toast.error('请输入正确的音频地址')
return
}
showAudioSegment(audioUrl)
setAudioUrl('')
}}
>
<FaMicrophone />
</Button>
</PopoverContent>
</Popover>
<Popover>
<Tooltip content="录制音频">
<div className="max-w-fit">
<PopoverTrigger>
<Button
className="text-lg"
color="danger"
isIconOnly
variant="flat"
radius="full"
>
<IoMic />
</Button>
</PopoverTrigger>
</div>
</Tooltip>
<PopoverContent className="flex-col gap-2 p-4">
<div className="flex gap-2">
<Button
color={isRecording ? 'danger' : 'danger'}
variant="flat"
onPress={isRecording ? stopRecording : startRecording}
>
{isRecording ? '停止录制' : '开始录制'}
</Button>
{showPreview && audioPreview && (
<Button
color="danger"
variant="flat"
onPress={handleShowPreview}
>
</Button>
)}
</div>
{(isRecording || audioPreview) && (
<div className="flex gap-1 items-center">
<span
className={clsx(
'w-4 h-4 rounded-full',
isRecording
? 'animate-pulse bg-danger-400'
: 'bg-success-400'
)}
></span>
<span>: {formatTime(recordingTime)}</span>
</div>
)}
{showPreview && audioPreview && (
<audio controls src={audioPreview} />
)}
</PopoverContent>
</Popover>
</PopoverContent>
</Popover>
<input
type="file"
ref={audioInputRef}
hidden
accept="audio/*"
className="hidden"
onChange={(e) => {
const file = e.target.files?.[0]
if (!file) {
return
}
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = (event) => {
const dataURL = event.target?.result
showAudioSegment(dataURL as string)
e.target.value = ''
}
}}
/>
</>
)
}
export default AudioInsert

View File

@@ -0,0 +1,31 @@
import { Button } from '@heroui/button'
import { Tooltip } from '@heroui/tooltip'
import { BsDice3Fill } from 'react-icons/bs'
import useShowStructuredMessage from '@/hooks/use_show_strcuted_message'
const DiceInsert = () => {
const showStructuredMessage = useShowStructuredMessage()
return (
<Tooltip content="发送骰子">
<Button
color="danger"
variant="flat"
isIconOnly
radius="full"
onPress={() => {
showStructuredMessage([
{
type: 'dice'
}
])
}}
>
<BsDice3Fill className="text-lg" />
</Button>
</Tooltip>
)
}
export default DiceInsert

View File

@@ -0,0 +1,83 @@
import { Button } from '@heroui/button'
import { Image } from '@heroui/image'
import { Popover, PopoverContent, PopoverTrigger } from '@heroui/popover'
import { Tooltip } from '@heroui/tooltip'
import { data, getUrl } from 'qface'
import { useEffect, useRef, useState } from 'react'
import { MdEmojiEmotions } from 'react-icons/md'
import { EmojiValue } from '../formats/emoji_blot'
const emojis = data.map((item) => {
return {
alt: item.QDes,
src: getUrl(item.QSid),
id: item.QSid
} as EmojiValue
})
export interface EmojiPickerProps {
onInsertEmoji: (emoji: EmojiValue) => void
onOpenChange: (open: boolean) => void
}
const EmojiPicker = ({ onInsertEmoji, onOpenChange }: EmojiPickerProps) => {
const [visibleEmojis, setVisibleEmojis] = useState<EmojiValue[]>([])
const [isPopoverOpen, setIsPopoverOpen] = useState<boolean>(false)
const containerRef = useRef<HTMLDivElement>(null)
useEffect(() => {
if (isPopoverOpen) {
setVisibleEmojis([]) // Reset visible emojis
requestAnimationFrame(() => loadEmojis()) // Start loading emojis
}
}, [isPopoverOpen])
const loadEmojis = (index = 0, batchSize = 10) => {
if (index < emojis.length) {
setVisibleEmojis((prev) => [
...prev,
...emojis.slice(index, index + batchSize)
])
requestAnimationFrame(() => loadEmojis(index + batchSize, batchSize))
}
}
return (
<div ref={containerRef}>
<Popover
portalContainer={containerRef.current!}
shouldCloseOnScroll={false}
placement="right-start"
onOpenChange={(v) => {
onOpenChange(v)
setIsPopoverOpen(v)
}}
>
<Tooltip content="插入表情">
<div className="max-w-fit">
<PopoverTrigger>
<Button color="danger" variant="flat" isIconOnly radius="full">
<MdEmojiEmotions className="text-xl" />
</Button>
</PopoverTrigger>
</div>
</Tooltip>
<PopoverContent className="grid grid-cols-8 gap-1 flex-wrap justify-start items-start overflow-y-auto max-w-full max-h-96 p-2">
{visibleEmojis.map((emoji) => (
<Button
key={emoji.id}
color="danger"
variant="flat"
isIconOnly
radius="full"
onPress={() => onInsertEmoji(emoji)}
>
<Image src={emoji.src} alt={emoji.alt} className="w-6 h-6" />
</Button>
))}
</PopoverContent>
</Popover>
</div>
)
}
export default EmojiPicker

View File

@@ -0,0 +1,125 @@
import { Button } from '@heroui/button'
import { Input } from '@heroui/input'
import { Popover, PopoverContent, PopoverTrigger } from '@heroui/popover'
import { Tooltip } from '@heroui/tooltip'
import { useRef, useState } from 'react'
import toast from 'react-hot-toast'
import { FaFolder } from 'react-icons/fa6'
import { LuFilePlus2 } from 'react-icons/lu'
import { MdEdit, MdUpload } from 'react-icons/md'
import useShowStructuredMessage from '@/hooks/use_show_strcuted_message'
import { isURI } from '@/utils/url'
import type { OB11Segment } from '@/types/onebot'
const FileInsert = () => {
const [fileUrl, setFileUrl] = useState<string>('')
const fileInputRef = useRef<HTMLInputElement>(null)
const showStructuredMessage = useShowStructuredMessage()
const showFileSegment = (file: string) => {
const messages: OB11Segment[] = [
{
type: 'file',
data: {
file: file
}
}
]
showStructuredMessage(messages)
}
return (
<>
<Popover>
<Tooltip content="发送文件">
<div className="max-w-fit">
<PopoverTrigger>
<Button color="danger" variant="flat" isIconOnly radius="full">
<FaFolder className="text-lg" />
</Button>
</PopoverTrigger>
</div>
</Tooltip>
<PopoverContent className="flex-row gap-2 p-4">
<Tooltip content="上传文件">
<Button
className="text-lg"
color="danger"
isIconOnly
variant="flat"
radius="full"
onPress={() => {
fileInputRef?.current?.click()
}}
>
<MdUpload />
</Button>
</Tooltip>
<Popover>
<Tooltip content="输入文件地址">
<div className="max-w-fit">
<PopoverTrigger tooltip="输入文件地址">
<Button
className="text-lg"
color="danger"
isIconOnly
variant="flat"
radius="full"
>
<MdEdit />
</Button>
</PopoverTrigger>
</div>
</Tooltip>
<PopoverContent className="flex-row gap-1 p-2">
<Input
value={fileUrl}
onChange={(e) => setFileUrl(e.target.value)}
placeholder="请输入文件地址"
/>
<Button
color="danger"
variant="flat"
isIconOnly
radius="full"
onPress={() => {
if (!isURI(fileUrl)) {
toast.error('请输入正确的文件地址')
return
}
showFileSegment(fileUrl)
setFileUrl('')
}}
>
<LuFilePlus2 />
</Button>
</PopoverContent>
</Popover>
</PopoverContent>
</Popover>
<input
type="file"
ref={fileInputRef}
hidden
className="hidden"
onChange={(e) => {
const file = e.target.files?.[0]
if (!file) {
return
}
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = (event) => {
const dataURL = event.target?.result
showFileSegment(dataURL as string)
e.target.value = ''
}
}}
/>
</>
)
}
export default FileInsert

View File

@@ -0,0 +1,114 @@
import { Button } from '@heroui/button'
import { Input } from '@heroui/input'
import { Popover, PopoverContent, PopoverTrigger } from '@heroui/popover'
import { Tooltip } from '@heroui/tooltip'
import { useRef, useState } from 'react'
import toast from 'react-hot-toast'
import { MdAddPhotoAlternate, MdEdit, MdImage, MdUpload } from 'react-icons/md'
import { isURI } from '@/utils/url'
export interface ImageInsertProps {
insertImage: (url: string) => void
onOpenChange: (open: boolean) => void
}
const ImageInsert = ({ insertImage, onOpenChange }: ImageInsertProps) => {
const [imgUrl, setImgUrl] = useState<string>('')
const imageInputRef = useRef<HTMLInputElement>(null)
return (
<>
<Popover onOpenChange={onOpenChange}>
<Tooltip content="插入图片">
<div className="max-w-fit">
<PopoverTrigger>
<Button color="danger" variant="flat" isIconOnly radius="full">
<MdImage className="text-xl" />
</Button>
</PopoverTrigger>
</div>
</Tooltip>
<PopoverContent className="flex-row gap-2 p-4">
<Tooltip content="上传图片">
<Button
className="text-lg"
color="danger"
isIconOnly
variant="flat"
radius="full"
onPress={() => {
imageInputRef?.current?.click()
}}
>
<MdUpload />
</Button>
</Tooltip>
<Popover>
<Tooltip content="输入图片地址">
<div className="max-w-fit">
<PopoverTrigger tooltip="输入图片地址">
<Button
className="text-lg"
color="danger"
isIconOnly
variant="flat"
radius="full"
>
<MdEdit />
</Button>
</PopoverTrigger>
</div>
</Tooltip>
<PopoverContent className="flex-row gap-1 p-2">
<Input
value={imgUrl}
onChange={(e) => setImgUrl(e.target.value)}
placeholder="请输入图片地址"
/>
<Button
color="danger"
variant="flat"
isIconOnly
radius="full"
onPress={() => {
if (!isURI(imgUrl)) {
toast.error('请输入正确的图片地址')
return
}
insertImage(imgUrl)
setImgUrl('')
}}
>
<MdAddPhotoAlternate />
</Button>
</PopoverContent>
</Popover>
</PopoverContent>
</Popover>
<input
type="file"
ref={imageInputRef}
hidden
accept="image/*"
className="hidden"
onChange={(e) => {
const file = e.target.files?.[0]
if (!file) {
return
}
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = (event) => {
const dataURL = event.target?.result
insertImage(dataURL as string)
e.target.value = ''
}
}}
/>
</>
)
}
export default ImageInsert

View File

@@ -0,0 +1,256 @@
import { Button } from '@heroui/button'
import { Form } from '@heroui/form'
import { Input } from '@heroui/input'
import { Popover, PopoverContent, PopoverTrigger } from '@heroui/popover'
import { Select, SelectItem } from '@heroui/select'
import type { SharedSelection } from '@heroui/system'
import { Tab, Tabs } from '@heroui/tabs'
import { Tooltip } from '@heroui/tooltip'
import type { Key } from '@react-types/shared'
import { useRef, useState } from 'react'
import { Controller, useForm } from 'react-hook-form'
import toast from 'react-hot-toast'
import { IoMusicalNotes } from 'react-icons/io5'
import { TbMusicPlus } from 'react-icons/tb'
import useShowStructuredMessage from '@/hooks/use_show_strcuted_message'
import { isURI } from '@/utils/url'
import type {
CustomMusicSegment,
MusicSegment,
OB11Segment
} from '@/types/onebot'
type MusicData = CustomMusicSegment['data'] | MusicSegment['data']
const MusicInsert = () => {
const [musicId, setMusicId] = useState<string>('')
const [musicType, setMusicType] = useState<SharedSelection>(new Set(['163']))
const [mode, setMode] = useState<Key>('default')
const containerRef = useRef<HTMLDivElement>(null)
const { control, handleSubmit, reset } = useForm<
Omit<CustomMusicSegment['data'], 'type'>
>({
defaultValues: {
url: '',
audio: '',
title: '',
image: '',
content: ''
}
})
const showStructuredMessage = useShowStructuredMessage()
const showMusicSegment = (data: MusicData) => {
const messages: OB11Segment[] = []
if (data.type === 'custom') {
messages.push({
type: 'music',
data: {
...data,
type: 'custom'
}
})
} else {
messages.push({
type: 'music',
data
})
}
showStructuredMessage(messages)
}
const onSubmit = (data: Omit<CustomMusicSegment['data'], 'type'>) => {
showMusicSegment({
type: 'custom',
...data
})
reset()
}
return (
<div ref={containerRef} className="overflow-visible">
<Popover
placement="right-start"
shouldCloseOnScroll={false}
portalContainer={containerRef.current!}
>
<Tooltip content="发送音乐">
<div className="max-w-fit">
<PopoverTrigger>
<Button color="danger" variant="flat" isIconOnly radius="full">
<IoMusicalNotes className="text-xl" />
</Button>
</PopoverTrigger>
</div>
</Tooltip>
<PopoverContent className="gap-2 p-4">
<Tabs
placement="top"
className="w-96"
fullWidth
selectedKey={mode}
onSelectionChange={setMode}
>
<Tab title="主流平台" key="default" className="flex flex-col gap-2">
<Select
onClick={(e) => e.stopPropagation()}
aria-label="音乐平台"
selectedKeys={musicType}
label="音乐平台"
placeholder="请选择音乐平台"
items={[
{
name: 'QQ音乐',
id: 'qq'
},
{
name: '网易云音乐',
id: '163'
},
{
name: '虾米音乐',
id: 'xm'
}
]}
onSelectionChange={setMusicType}
>
{(item) => (
<SelectItem key={item.id} value={item.id}>
{item.name}
</SelectItem>
)}
</Select>
<Input
value={musicId}
onChange={(e) => setMusicId(e.target.value)}
placeholder="请输入音乐ID"
label="音乐ID"
/>
<Button
fullWidth
size="lg"
color="danger"
variant="flat"
radius="full"
onPress={() => {
if (!musicId) {
toast.error('请输入音乐ID')
return
}
showMusicSegment({
type: Array.from(
musicType
)[0] as MusicSegment['data']['type'],
id: musicId
})
setMusicId('')
}}
startContent={<TbMusicPlus />}
>
{Array.from(musicType)[0] === '163' ? '网易云' : 'QQ'}
</Button>
</Tab>
<Tab
title="自定义音乐"
key="custom"
className="flex flex-col gap-2"
>
<Form
onSubmit={handleSubmit(onSubmit)}
className="flex flex-col gap-2"
validationBehavior="native"
>
<Controller
name="url"
control={control}
render={({ field }) => (
<Input
{...field}
isRequired
validate={(v) => {
return !isURI(v) ? '请输入正确的音乐URL' : null
}}
size="sm"
placeholder="请输入音乐URL"
label="音乐URL"
/>
)}
/>
<Controller
name="audio"
control={control}
render={({ field }) => (
<Input
{...field}
isRequired
validate={(v) => {
return !isURI(v) ? '请输入正确的音频URL' : null
}}
size="sm"
placeholder="请输入音频URL"
label="音频URL"
/>
)}
/>
<Controller
name="title"
control={control}
render={({ field }) => (
<Input
{...field}
isRequired
size="sm"
errorMessage="请输入音乐标题"
placeholder="请输入音乐标题"
label="音乐标题"
/>
)}
/>
<Controller
name="image"
control={control}
render={({ field }) => (
<Input
{...field}
size="sm"
placeholder="请输入封面图片URL"
label="封面图片URL"
/>
)}
/>
<Controller
name="content"
control={control}
render={({ field }) => (
<Input
{...field}
size="sm"
placeholder="请输入音乐描述"
label="音乐描述"
/>
)}
/>
<Button
fullWidth
size="lg"
color="danger"
variant="flat"
radius="full"
type="submit"
startContent={<TbMusicPlus />}
>
</Button>
</Form>
</Tab>
</Tabs>
</PopoverContent>
</Popover>
</div>
)
}
export default MusicInsert

View File

@@ -0,0 +1,58 @@
import { Button } from '@heroui/button'
import { Input } from '@heroui/input'
import { Popover, PopoverContent, PopoverTrigger } from '@heroui/popover'
import { Tooltip } from '@heroui/tooltip'
import { useState } from 'react'
import { BsChatQuoteFill } from 'react-icons/bs'
import { MdAdd } from 'react-icons/md'
export interface ReplyInsertProps {
insertReply: (messageId: string) => void
}
const ReplyInsert = ({ insertReply }: ReplyInsertProps) => {
const [replyId, setReplyId] = useState<string>('')
return (
<>
<Popover>
<Tooltip content="回复消息">
<div className="max-w-fit">
<PopoverTrigger>
<Button color="danger" variant="flat" isIconOnly radius="full">
<BsChatQuoteFill className="text-lg" />
</Button>
</PopoverTrigger>
</div>
</Tooltip>
<PopoverContent className="flex-row gap-2 p-4">
<Input
placeholder="输入消息 ID"
value={replyId}
onChange={(e) => {
const value = e.target.value
const isNumberReg = /^(?:0|(?:-?[1-9]\d*))$/
if (isNumberReg.test(value)) {
setReplyId(value)
}
}}
/>
<Button
color="danger"
variant="flat"
radius="full"
isIconOnly
onPress={() => {
insertReply(replyId)
setReplyId('')
}}
>
<MdAdd />
</Button>
</PopoverContent>
</Popover>
</>
)
}
export default ReplyInsert

View File

@@ -0,0 +1,31 @@
import { Button } from '@heroui/button'
import { Tooltip } from '@heroui/tooltip'
import { LiaHandScissors } from 'react-icons/lia'
import useShowStructuredMessage from '@/hooks/use_show_strcuted_message'
const RPSInsert = () => {
const showStructuredMessage = useShowStructuredMessage()
return (
<Tooltip content="发送猜拳">
<Button
color="danger"
variant="flat"
isIconOnly
radius="full"
onPress={() => {
showStructuredMessage([
{
type: 'rps'
}
])
}}
>
<LiaHandScissors className="text-2xl" />
</Button>
</Tooltip>
)
}
export default RPSInsert

View File

@@ -0,0 +1,32 @@
import { Snippet } from '@heroui/snippet'
import { OB11Segment } from '@/types/onebot'
export interface ShowStructedMessageProps {
messages: OB11Segment[]
}
const ShowStructedMessage = ({ messages }: ShowStructedMessageProps) => {
return (
<Snippet
hideSymbol
tooltipProps={{
content: '点击复制'
}}
classNames={{
copyButton: 'self-start sticky top-0 right-0'
}}
className="bg-content1 h-96 overflow-y-scroll items-start"
>
{JSON.stringify(messages, null, 2)
.split('\n')
.map((line, i) => (
<span key={i} className="whitespace-pre-wrap break-all">
{line}
</span>
))}
</Snippet>
)
}
export default ShowStructedMessage

View File

@@ -0,0 +1,126 @@
import { Button } from '@heroui/button'
import { Input } from '@heroui/input'
import { Popover, PopoverContent, PopoverTrigger } from '@heroui/popover'
import { Tooltip } from '@heroui/tooltip'
import { useRef, useState } from 'react'
import toast from 'react-hot-toast'
import { IoVideocam } from 'react-icons/io5'
import { MdEdit, MdUpload } from 'react-icons/md'
import { TbVideoPlus } from 'react-icons/tb'
import useShowStructuredMessage from '@/hooks/use_show_strcuted_message'
import { isURI } from '@/utils/url'
import type { OB11Segment } from '@/types/onebot'
const VideoInsert = () => {
const [videoUrl, setVideoUrl] = useState<string>('')
const videoInputRef = useRef<HTMLInputElement>(null)
const showStructuredMessage = useShowStructuredMessage()
const showVideoSegment = (file: string) => {
const messages: OB11Segment[] = [
{
type: 'video',
data: {
file: file
}
}
]
showStructuredMessage(messages)
}
return (
<>
<Popover>
<Tooltip content="发送视频">
<div className="max-w-fit">
<PopoverTrigger>
<Button color="danger" variant="flat" isIconOnly radius="full">
<IoVideocam className="text-xl" />
</Button>
</PopoverTrigger>
</div>
</Tooltip>
<PopoverContent className="flex-row gap-2 p-4">
<Tooltip content="上传视频">
<Button
className="text-lg"
color="danger"
isIconOnly
variant="flat"
radius="full"
onPress={() => {
videoInputRef?.current?.click()
}}
>
<MdUpload />
</Button>
</Tooltip>
<Popover>
<Tooltip content="输入视频地址">
<div className="max-w-fit">
<PopoverTrigger tooltip="输入视频地址">
<Button
className="text-lg"
color="danger"
isIconOnly
variant="flat"
radius="full"
>
<MdEdit />
</Button>
</PopoverTrigger>
</div>
</Tooltip>
<PopoverContent className="flex-row gap-1 p-2">
<Input
value={videoUrl}
onChange={(e) => setVideoUrl(e.target.value)}
placeholder="请输入视频地址"
/>
<Button
color="danger"
variant="flat"
isIconOnly
radius="full"
onPress={() => {
if (!isURI(videoUrl)) {
toast.error('请输入正确的视频地址')
return
}
showVideoSegment(videoUrl)
setVideoUrl('')
}}
>
<TbVideoPlus />
</Button>
</PopoverContent>
</Popover>
</PopoverContent>
</Popover>
<input
type="file"
ref={videoInputRef}
hidden
accept="video/*"
className="hidden"
onChange={(e) => {
const file = e.target.files?.[0]
if (!file) {
return
}
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = (event) => {
const dataURL = event.target?.result
showVideoSegment(dataURL as string)
e.target.value = ''
}
}}
/>
</>
)
}
export default VideoInsert

View File

@@ -0,0 +1,41 @@
import Quill from 'quill'
// eslint-disable-next-line
const Embed = Quill.import('blots/embed') as any
export interface EmojiValue {
alt: string
src: string
id: string
}
class EmojiBlot extends Embed {
static blotName: string = 'emoji'
static tagName: string = 'img'
static classNames: string[] = ['w-6', 'h-6']
static create(value: HTMLImageElement) {
const node = super.create(value)
node.setAttribute('alt', value.alt)
node.setAttribute('src', value.src)
node.setAttribute('data-id', value.id)
node.classList.add(...EmojiBlot.classNames)
return node
}
static formats(node: HTMLImageElement): EmojiValue {
return {
alt: node.getAttribute('alt') ?? '',
src: node.getAttribute('src') ?? '',
id: node.getAttribute('data-id') ?? ''
}
}
static value(node: HTMLImageElement): EmojiValue {
return {
alt: node.getAttribute('alt') ?? '',
src: node.getAttribute('src') ?? '',
id: node.getAttribute('data-id') ?? ''
}
}
}
export default EmojiBlot

View File

@@ -0,0 +1,30 @@
import Quill from 'quill'
// eslint-disable-next-line
const Embed = Quill.import('blots/embed') as any
export interface ImageValue {
alt: string
src: string
}
class ImageBlot extends Embed {
static blotName = 'image'
static tagName = 'img'
static classNames: string[] = ['max-w-48', 'max-h-48', 'align-bottom']
static create(value: ImageValue) {
let node = super.create()
node.setAttribute('alt', value.alt)
node.setAttribute('src', value.src)
node.classList.add(...ImageBlot.classNames)
return node
}
static value(node: HTMLImageElement): ImageValue {
return {
alt: node.getAttribute('alt') ?? '',
src: node.getAttribute('src') ?? ''
}
}
}
export default ImageBlot

View File

@@ -0,0 +1,43 @@
import Quill from 'quill'
// eslint-disable-next-line
const BlockEmbed = Quill.import('blots/block/embed') as any
export interface ReplyBlockValue {
messageId: string
}
class ReplyBlock extends BlockEmbed {
static blotName = 'reply'
static tagName = 'div'
static classNames = [
'p-2',
'select-none',
'bg-default-100',
'rounded-md',
'pointer-events-none'
]
static create(value: ReplyBlockValue) {
const node = super.create()
node.setAttribute('data-message-id', value.messageId)
node.setAttribute('contenteditable', 'false')
node.classList.add(...ReplyBlock.classNames)
const innerDom = document.createElement('div')
innerDom.classList.add('text-sm', 'text-default-500', 'relative')
const svgContainer = document.createElement('div')
svgContainer.classList.add('w-3', 'h-3', 'absolute', 'top-0', 'right-0')
const svg = `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M15.9082 12.3714H20.5982C20.5182 17.0414 19.5982 17.8114 16.7282 19.5114C16.3982 19.7114 16.2882 20.1314 16.4882 20.4714C16.6882 20.8014 17.1082 20.9114 17.4482 20.7114C20.8282 18.7114 22.0082 17.4914 22.0082 11.6714V6.28141C22.0082 4.57141 20.6182 3.19141 18.9182 3.19141H15.9182C14.1582 3.19141 12.8282 4.52141 12.8282 6.28141V9.28141C12.8182 11.0414 14.1482 12.3714 15.9082 12.3714Z" fill="#292D32"></path> <path d="M5.09 12.3714H9.78C9.7 17.0414 8.78 17.8114 5.91 19.5114C5.58 19.7114 5.47 20.1314 5.67 20.4714C5.87 20.8014 6.29 20.9114 6.63 20.7114C10.01 18.7114 11.19 17.4914 11.19 11.6714V6.28141C11.19 4.57141 9.8 3.19141 8.1 3.19141H5.1C3.33 3.19141 2 4.52141 2 6.28141V9.28141C2 11.0414 3.33 12.3714 5.09 12.3714Z" fill="#292D32"></path> </g></svg>`
svgContainer.innerHTML = svg
innerDom.innerHTML = `消息ID${value.messageId}`
innerDom.appendChild(svgContainer)
node.appendChild(innerDom)
return node
}
static value(node: HTMLElement): ReplyBlockValue {
return {
messageId: node.getAttribute('data-message-id') || ''
}
}
}
export default ReplyBlock

View File

@@ -0,0 +1,207 @@
import { Button } from '@heroui/button'
import type { Range } from 'quill'
import 'quill/dist/quill.core.css'
import { useRef } from 'react'
import toast from 'react-hot-toast'
import { useCustomQuill } from '@/hooks/use_custom_quill'
import useShowStructuredMessage from '@/hooks/use_show_strcuted_message'
import { quillToMessage } from '@/utils/onebot'
import type { OB11Segment } from '@/types/onebot'
import AudioInsert from './components/audio_insert'
import DiceInsert from './components/dice_insert'
import EmojiPicker from './components/emoji_picker'
import FileInsert from './components/file_insert'
import ImageInsert from './components/image_insert'
import MusicInsert from './components/music_insert'
import ReplyInsert from './components/reply_insert'
import RPSInsert from './components/rps_insert'
import VideoInsert from './components/video_insert'
import EmojiBlot from './formats/emoji_blot'
import type { EmojiValue } from './formats/emoji_blot'
import ImageBlot from './formats/image_blot'
import ReplyBlock from './formats/reply_blot'
const ChatInput = () => {
const memorizedRange = useRef<Range | null>(null)
const showStructuredMessage = useShowStructuredMessage()
const formats: string[] = ['image', 'emoji', 'reply']
const modules = {
toolbar: '#toolbar'
}
const { quillRef, quill, Quill } = useCustomQuill({
modules,
formats,
placeholder: '请输入消息'
})
if (Quill && !quill) {
Quill.register('formats/emoji', EmojiBlot)
Quill.register('formats/image', ImageBlot, true)
Quill.register('formats/reply', ReplyBlock)
}
if (quill) {
quill.on('selection-change', (range) => {
if (range) {
const editorContent = quill.getContents()
const firstOp = editorContent.ops[0]
if (
typeof firstOp?.insert !== 'string' &&
firstOp?.insert?.reply &&
range.index === 0 &&
range.length !== quill.getLength()
) {
quill.setSelection(1, Quill.sources.SILENT)
}
}
})
quill.on('text-change', () => {
const editorContent = quill.getContents()
const firstOp = editorContent.ops[0]
if (
firstOp &&
typeof firstOp.insert !== 'string' &&
firstOp.insert?.reply &&
quill.getLength() === 1
) {
quill.insertText(1, '\n', Quill.sources.SILENT)
}
})
quill.on('editor-change', (eventName: string) => {
if (eventName === 'text-change') {
const editorContent = quill.getContents()
const firstOp = editorContent.ops[0]
if (
firstOp &&
typeof firstOp.insert !== 'string' &&
firstOp.insert?.reply &&
quill.getLength() === 1
) {
quill.insertText(1, '\n', Quill.sources.SILENT)
}
}
})
quill.root.addEventListener('compositionstart', () => {
const editorContent = quill.getContents()
const firstOp = editorContent.ops[0]
if (
firstOp &&
typeof firstOp.insert !== 'string' &&
firstOp.insert?.reply &&
quill.getLength() === 1
) {
quill.insertText(1, '\n', Quill.sources.SILENT)
}
})
}
const onOpenChange = (open: boolean) => {
if (open) {
const selection = quill?.getSelection()
if (selection) memorizedRange.current = selection
}
}
const insertImage = (url: string) => {
const selection = memorizedRange.current || quill?.getSelection()
quill?.deleteText(selection?.index || 0, selection?.length || 0)
quill?.insertEmbed(selection?.index || 0, 'image', {
src: url,
alt: '图片'
})
quill?.setSelection((selection?.index || 0) + 1, 0)
}
function insertReplyBlock(messageId: string) {
const isNumberReg = /^(?:0|(?:-?[1-9]\d*))$/
if (!isNumberReg.test(messageId)) {
toast.error('请输入正确的消息ID')
return
}
const editorContent = quill?.getContents()
const firstOp = editorContent?.ops[0]
const currentSelection = quill?.getSelection()
if (
firstOp &&
typeof firstOp.insert !== 'string' &&
firstOp.insert?.reply
) {
const delta = quill?.getContents()
if (delta) {
delta.ops[0] = {
insert: { reply: { messageId } }
}
quill?.setContents(delta, Quill.sources.USER)
}
} else {
quill?.insertEmbed(0, 'reply', { messageId }, Quill.sources.USER)
}
quill?.setSelection((currentSelection?.index || 0) + 1, 0)
quill?.blur()
}
const onInsertEmoji = (emoji: EmojiValue) => {
const selection = memorizedRange.current || quill?.getSelection()
quill?.deleteText(selection?.index || 0, selection?.length || 0)
quill?.insertEmbed(selection?.index || 0, 'emoji', {
alt: emoji.alt,
src: emoji.src,
id: emoji.id
})
quill?.setSelection((selection?.index || 0) + 1, 0)
}
const getChatMessage = () => {
const delta = quill?.getContents()
const ops =
delta?.ops?.filter((op) => {
return op.insert !== '\n'
}) ?? []
const messages: OB11Segment[] = ops.map((op) => {
return quillToMessage(op)
})
return messages
}
return (
<div>
<div
ref={quillRef}
className="border border-default-200 rounded-md !mb-2 !text-base !h-64"
/>
<div id="toolbar" className="!border-none flex gap-2">
<ImageInsert insertImage={insertImage} onOpenChange={onOpenChange} />
<EmojiPicker
onInsertEmoji={onInsertEmoji}
onOpenChange={onOpenChange}
/>
<ReplyInsert insertReply={insertReplyBlock} />
<FileInsert />
<AudioInsert />
<VideoInsert />
<MusicInsert />
<DiceInsert />
<RPSInsert />
<Button
color="danger"
onPress={() => {
const messages = getChatMessage()
showStructuredMessage(messages)
}}
className="ml-auto"
>
JSON格式
</Button>
</div>
</div>
)
}
export default ChatInput

View File

@@ -0,0 +1,49 @@
import { Button } from '@heroui/button'
import {
Modal,
ModalBody,
ModalContent,
ModalFooter,
ModalHeader,
useDisclosure
} from '@heroui/modal'
import ChatInput from '.'
export default function ChatInputModal() {
const { isOpen, onOpen, onOpenChange } = useDisclosure()
return (
<>
<Button onPress={onOpen} color="danger" radius="full" variant="flat">
</Button>
<Modal
size="4xl"
scrollBehavior="inside"
isOpen={isOpen}
onOpenChange={onOpenChange}
>
<ModalContent>
{(onClose) => (
<>
<ModalHeader className="flex flex-col gap-1">
</ModalHeader>
<ModalBody className="overflow-y-auto">
<div className="overflow-y-auto">
<ChatInput />
</div>
</ModalBody>
<ModalFooter>
<Button color="danger" onPress={onClose} variant="flat">
</Button>
</ModalFooter>
</>
)}
</ModalContent>
</Modal>
</>
)
}

View File

@@ -0,0 +1,55 @@
import Editor, { OnMount } from '@monaco-editor/react'
import { loader } from '@monaco-editor/react'
import React from 'react'
import { useTheme } from '@/hooks/use-theme'
import monaco from '@/monaco'
loader.config({
monaco,
paths: {
vs: '/webui/monaco-editor/min/vs'
}
})
loader.config({
'vs/nls': {
availableLanguages: { '*': 'zh-cn' }
}
})
export interface CodeEditorProps extends React.ComponentProps<typeof Editor> {
test?: string
}
export type CodeEditorRef = monaco.editor.IStandaloneCodeEditor
const CodeEditor = React.forwardRef<CodeEditorRef, CodeEditorProps>(
(props, ref) => {
const { isDark } = useTheme()
const handleEditorDidMount: OnMount = (editor, monaco) => {
if (ref) {
if (typeof ref === 'function') {
ref(editor)
} else {
;(ref as React.RefObject<CodeEditorRef>).current = editor
}
}
if (props.onMount) {
props.onMount(editor, monaco)
}
}
return (
<Editor
{...props}
onMount={handleEditorDidMount}
theme={isDark ? 'vs-dark' : 'light'}
/>
)
}
)
export default CodeEditor

View File

@@ -0,0 +1,120 @@
import { Button, ButtonGroup } from '@heroui/button'
import { Switch } from '@heroui/switch'
import { useState } from 'react'
import { CgDebug } from 'react-icons/cg'
import { FiEdit3 } from 'react-icons/fi'
import { MdDeleteForever } from 'react-icons/md'
import DisplayCardContainer from './container'
type NetworkType = OneBotConfig['network']
export type NetworkDisplayCardFields<T extends keyof NetworkType> = Array<{
label: string
value: NetworkType[T][0][keyof NetworkType[T][0]]
render?: (
value: NetworkType[T][0][keyof NetworkType[T][0]]
) => React.ReactNode
}>
export interface NetworkDisplayCardProps<T extends keyof NetworkType> {
data: NetworkType[T][0]
showType?: boolean
typeLabel: string
fields: NetworkDisplayCardFields<T>
onEdit: () => void
onEnable: () => Promise<void>
onDelete: () => Promise<void>
onEnableDebug: () => Promise<void>
}
const NetworkDisplayCard = <T extends keyof NetworkType>({
data,
showType,
typeLabel,
fields,
onEdit,
onEnable,
onDelete,
onEnableDebug
}: NetworkDisplayCardProps<T>) => {
const { name, enable, debug } = data
const [editing, setEditing] = useState(false)
const handleEnable = () => {
setEditing(true)
onEnable().finally(() => setEditing(false))
}
const handleDelete = () => {
setEditing(true)
onDelete().finally(() => setEditing(false))
}
const handleEnableDebug = () => {
setEditing(true)
onEnableDebug().finally(() => setEditing(false))
}
return (
<DisplayCardContainer
action={
<ButtonGroup
fullWidth
isDisabled={editing}
radius="full"
size="sm"
variant="shadow"
>
<Button color="warning" startContent={<FiEdit3 />} onPress={onEdit}>
</Button>
<Button
color={debug ? 'success' : 'default'}
startContent={<CgDebug />}
onPress={handleEnableDebug}
>
{debug ? '关闭调试' : '开启调试'}
</Button>
<Button
color="danger"
startContent={<MdDeleteForever />}
onPress={handleDelete}
>
</Button>
</ButtonGroup>
}
enableSwitch={
<Switch
isDisabled={editing}
isSelected={enable}
onChange={handleEnable}
/>
}
tag={showType && typeLabel}
title={name}
>
<div className="grid grid-cols-2 gap-1">
{fields.map((field, index) => (
<div
key={index}
className={`flex items-center gap-2 ${
field.label === 'URL' ? 'col-span-2' : ''
}`}
>
<span className="text-default-400">{field.label}</span>
{field.render ? (
field.render(field.value)
) : (
<span>{field.value}</span>
)}
</div>
))}
</div>
</DisplayCardContainer>
)
}
export default NetworkDisplayCard

View File

@@ -0,0 +1,57 @@
import { Card, CardBody, CardFooter, CardHeader } from '@heroui/card'
import clsx from 'clsx'
import { title } from '../primitives'
export interface ContainerProps {
title: string
tag?: React.ReactNode
action: React.ReactNode
enableSwitch: React.ReactNode
children: React.ReactNode
}
export interface DisplayCardProps {
showType?: boolean
onEdit: () => void
onEnable: () => Promise<void>
onDelete: () => Promise<void>
onEnableDebug: () => Promise<void>
}
const DisplayCardContainer: React.FC<ContainerProps> = ({
title: _title,
action,
tag,
enableSwitch,
children
}) => {
return (
<Card className="bg-opacity-50 backdrop-blur-sm">
<CardHeader className={'pb-0 flex items-center'}>
{tag && (
<div className="text-center text-default-400 mb-1 absolute top-0 left-1/2 -translate-x-1/2 text-sm pointer-events-none bg-warning-100 dark:bg-warning-50 px-2 rounded-b">
{tag}
</div>
)}
<h2
className={clsx(
title({
color: 'foreground',
size: 'xs',
shadow: true
}),
'truncate'
)}
>
{_title}
</h2>
<div className="ml-auto">{enableSwitch}</div>
</CardHeader>
<CardBody className="text-sm">{children}</CardBody>
<CardFooter>{action}</CardFooter>
</Card>
)
}
export default DisplayCardContainer

View File

@@ -0,0 +1,47 @@
import { Chip } from '@heroui/chip'
import NetworkDisplayCard from './common_card'
import type { NetworkDisplayCardFields } from './common_card'
interface HTTPClientDisplayCardProps {
data: OneBotConfig['network']['httpClients'][0]
showType?: boolean
onEdit: () => void
onEnable: () => Promise<void>
onDelete: () => Promise<void>
onEnableDebug: () => Promise<void>
}
const HTTPClientDisplayCard: React.FC<HTTPClientDisplayCardProps> = (props) => {
const { data, showType, onEdit, onEnable, onDelete, onEnableDebug } = props
const { url, reportSelfMessage, messagePostFormat } = data
const fields: NetworkDisplayCardFields<'httpClients'> = [
{ label: 'URL', value: url },
{ label: '消息格式', value: messagePostFormat },
{
label: '上报自身消息',
value: reportSelfMessage,
render: (value) => (
<Chip color={value ? 'success' : 'default'} size="sm" variant="flat">
{value ? '是' : '否'}
</Chip>
)
}
]
return (
<NetworkDisplayCard
data={data}
showType={showType}
typeLabel="HTTP客户端"
fields={fields}
onEdit={onEdit}
onEnable={onEnable}
onDelete={onDelete}
onEnableDebug={onEnableDebug}
/>
)
}
export default HTTPClientDisplayCard

View File

@@ -0,0 +1,57 @@
import { Chip } from '@heroui/chip'
import NetworkDisplayCard from './common_card'
import type { NetworkDisplayCardFields } from './common_card'
interface HTTPServerDisplayCardProps {
data: OneBotConfig['network']['httpServers'][0]
showType?: boolean
onEdit: () => void
onEnable: () => Promise<void>
onDelete: () => Promise<void>
onEnableDebug: () => Promise<void>
}
const HTTPServerDisplayCard: React.FC<HTTPServerDisplayCardProps> = (props) => {
const { data, showType, onEdit, onEnable, onDelete, onEnableDebug } = props
const { host, port, enableCors, enableWebsocket, messagePostFormat } = data
const fields: NetworkDisplayCardFields<'httpServers'> = [
{ label: '主机', value: host },
{ label: '端口', value: port },
{ label: '消息格式', value: messagePostFormat },
{
label: 'CORS',
value: enableCors,
render: (value) => (
<Chip color={value ? 'success' : 'default'} size="sm" variant="flat">
{value ? '已启用' : '未启用'}
</Chip>
)
},
{
label: 'WS',
value: enableWebsocket,
render: (value) => (
<Chip color={value ? 'success' : 'default'} size="sm" variant="flat">
{value ? '已启用' : '未启用'}
</Chip>
)
}
]
return (
<NetworkDisplayCard
data={data}
showType={showType}
typeLabel="HTTP服务器"
fields={fields}
onEdit={onEdit}
onEnable={onEnable}
onDelete={onDelete}
onEnableDebug={onEnableDebug}
/>
)
}
export default HTTPServerDisplayCard

View File

@@ -0,0 +1,59 @@
import { Chip } from '@heroui/chip'
import NetworkDisplayCard from './common_card'
import type { NetworkDisplayCardFields } from './common_card'
interface HTTPSSEServerDisplayCardProps {
data: OneBotConfig['network']['httpSseServers'][0]
showType?: boolean
onEdit: () => void
onEnable: () => Promise<void>
onDelete: () => Promise<void>
onEnableDebug: () => Promise<void>
}
const HTTPSSEServerDisplayCard: React.FC<HTTPSSEServerDisplayCardProps> = (
props
) => {
const { data, showType, onEdit, onEnable, onDelete, onEnableDebug } = props
const { host, port, enableCors, enableWebsocket, messagePostFormat } = data
const fields: NetworkDisplayCardFields<'httpServers'> = [
{ label: '主机', value: host },
{ label: '端口', value: port },
{ label: '消息格式', value: messagePostFormat },
{
label: 'CORS',
value: enableCors,
render: (value) => (
<Chip color={value ? 'success' : 'default'} size="sm" variant="flat">
{value ? '已启用' : '未启用'}
</Chip>
)
},
{
label: 'WS',
value: enableWebsocket,
render: (value) => (
<Chip color={value ? 'success' : 'default'} size="sm" variant="flat">
{value ? '已启用' : '未启用'}
</Chip>
)
}
]
return (
<NetworkDisplayCard
data={data}
showType={showType}
typeLabel="HTTP服务器"
fields={fields}
onEdit={onEdit}
onEnable={onEnable}
onDelete={onDelete}
onEnableDebug={onEnableDebug}
/>
)
}
export default HTTPSSEServerDisplayCard

View File

@@ -0,0 +1,57 @@
import { Chip } from '@heroui/chip'
import NetworkDisplayCard from './common_card'
import type { NetworkDisplayCardFields } from './common_card'
interface WebsocketClientDisplayCardProps {
data: OneBotConfig['network']['websocketClients'][0]
showType?: boolean
onEdit: () => void
onEnable: () => Promise<void>
onDelete: () => Promise<void>
onEnableDebug: () => Promise<void>
}
const WebsocketClientDisplayCard: React.FC<WebsocketClientDisplayCardProps> = (
props
) => {
const { data, showType, onEdit, onEnable, onDelete, onEnableDebug } = props
const {
url,
heartInterval,
reconnectInterval,
messagePostFormat,
reportSelfMessage
} = data
const fields: NetworkDisplayCardFields<'websocketClients'> = [
{ label: 'URL', value: url },
{ label: '重连间隔', value: `${reconnectInterval}ms` },
{ label: '心跳间隔', value: `${heartInterval}ms` },
{ label: '消息格式', value: messagePostFormat },
{
label: '上报自身消息',
value: reportSelfMessage,
render: (value) => (
<Chip color={value ? 'success' : 'default'} size="sm" variant="flat">
{value ? '是' : '否'}
</Chip>
)
}
]
return (
<NetworkDisplayCard
data={data}
showType={showType}
typeLabel="Websocket客户端"
fields={fields}
onEdit={onEdit}
onEnable={onEnable}
onDelete={onDelete}
onEnableDebug={onEnableDebug}
/>
)
}
export default WebsocketClientDisplayCard

View File

@@ -0,0 +1,67 @@
import { Chip } from '@heroui/chip'
import NetworkDisplayCard from './common_card'
import type { NetworkDisplayCardFields } from './common_card'
interface WebsocketServerDisplayCardProps {
data: OneBotConfig['network']['websocketServers'][0]
showType?: boolean
onEdit: () => void
onEnable: () => Promise<void>
onDelete: () => Promise<void>
onEnableDebug: () => Promise<void>
}
const WebsocketServerDisplayCard: React.FC<WebsocketServerDisplayCardProps> = (
props
) => {
const { data, showType, onEdit, onEnable, onDelete, onEnableDebug } = props
const {
host,
port,
heartInterval,
messagePostFormat,
reportSelfMessage,
enableForcePushEvent
} = data
const fields: NetworkDisplayCardFields<'websocketServers'> = [
{ label: '主机', value: host },
{ label: '端口', value: port },
{ label: '心跳间隔', value: `${heartInterval}ms` },
{ label: '消息格式', value: messagePostFormat },
{
label: '上报自身消息',
value: reportSelfMessage,
render: (value) => (
<Chip color={value ? 'success' : 'default'} size="sm" variant="flat">
{value ? '是' : '否'}
</Chip>
)
},
{
label: '强制推送事件',
value: enableForcePushEvent,
render: (value) => (
<Chip color={value ? 'success' : 'default'} size="sm" variant="flat">
{value ? '是' : '否'}
</Chip>
)
}
]
return (
<NetworkDisplayCard
data={data}
showType={showType}
typeLabel="Websocket服务器"
fields={fields}
onEdit={onEdit}
onEnable={onEnable}
onDelete={onDelete}
onEnableDebug={onEnableDebug}
/>
)
}
export default WebsocketServerDisplayCard

View File

@@ -0,0 +1,58 @@
import { Card, CardBody } from '@heroui/card'
import clsx from 'clsx'
import { title } from '@/components/primitives'
export interface NetworkItemDisplayProps {
count: number
label: string
size?: 'sm' | 'md'
}
const NetworkItemDisplay: React.FC<NetworkItemDisplayProps> = ({
count,
label,
size = 'md'
}) => {
return (
<Card
className={clsx(
'bg-opacity-60 shadow-sm md:rounded-3xl',
size === 'md'
? 'col-span-8 md:col-span-2 bg-danger-50 shadow-danger-100'
: 'col-span-2 md:col-span-1 bg-warning-100 shadow-warning-200'
)}
shadow="sm"
>
<CardBody className="items-center md:gap-1 p-1 md:p-2">
<div
className={clsx(
'flex-1',
size === 'md' ? 'text-2xl md:text-3xl' : 'text-xl md:text-2xl',
title({
color: size === 'md' ? 'pink' : 'yellow',
size
})
)}
>
{count}
</div>
<div
className={clsx(
'whitespace-nowrap text-nowrap flex-shrink-0',
size === 'md' ? 'text-sm md:text-base' : 'text-xs md:text-sm',
title({
color: size === 'md' ? 'pink' : 'yellow',
shadow: true,
size: 'xxs'
})
)}
>
{label}
</div>
</CardBody>
</Card>
)
}
export default NetworkItemDisplay

View File

@@ -0,0 +1,109 @@
import { Card, CardProps } from '@heroui/card'
import clsx from 'clsx'
import React from 'react'
export interface HoverEffectCardProps extends CardProps {
children: React.ReactNode
maxXRotation?: number
maxYRotation?: number
lightClassName?: string
lightStyle?: React.CSSProperties
}
const HoverEffectCard: React.FC<HoverEffectCardProps> = (props) => {
const {
children,
maxXRotation = 5,
maxYRotation = 5,
className,
style,
lightClassName,
lightStyle
} = props
const cardRef = React.useRef<HTMLDivElement | null>(null)
const lightRef = React.useRef<HTMLDivElement | null>(null)
const [isShowLight, setIsShowLight] = React.useState(false)
const [pos, setPos] = React.useState({
left: 0,
top: 0
})
return (
<Card
{...props}
ref={cardRef}
className={clsx(
'relative overflow-hidden bg-opacity-50 backdrop-blur-lg',
className
)}
style={{
willChange: 'transform',
transform:
'perspective(1000px) rotateX(0deg) rotateY(0deg) scale3d(1, 1, 1)',
...style
}}
onMouseEnter={() => {
if (cardRef.current) {
cardRef.current.style.transition = 'transform 0.3s ease-out'
}
}}
onMouseLeave={() => {
setIsShowLight(false)
if (cardRef.current) {
cardRef.current.style.transition = 'transform 0.5s'
cardRef.current.style.transform =
'perspective(1000px) rotateX(0deg) rotateY(0deg) scale3d(1, 1, 1)'
}
}}
onMouseMove={(e: React.MouseEvent<HTMLDivElement>) => {
if (cardRef.current) {
setIsShowLight(true)
const { x, y } = cardRef.current.getBoundingClientRect()
const { clientX, clientY } = e
const offsetX = clientX - x
const offsetY = clientY - y
const lightWidth = lightStyle?.width?.toString() || '100'
const lightHeight = lightStyle?.height?.toString() || '100'
const lightWidthNum = parseInt(lightWidth)
const lightHeightNum = parseInt(lightHeight)
const left = offsetX - lightWidthNum / 2
const top = offsetY - lightHeightNum / 2
setPos({
left,
top
})
cardRef.current.style.transition = 'transform 0.1s'
const rangeX = 400 / 2
const rangeY = 400 / 2
const rotateX = ((offsetY - rangeY) / rangeY) * maxXRotation
const rotateY = -1 * ((offsetX - rangeX) / rangeX) * maxYRotation
cardRef.current.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`
}
}}
>
<div
ref={lightRef}
className={clsx(
isShowLight ? 'opacity-100' : 'opacity-0',
'absolute rounded-full blur-[150px] filter transition-opacity duration-300 dark:bg-[#2850ff] bg-[#ff4132] w-[100px] h-[100px]',
lightClassName
)}
style={{
...pos
}}
/>
{children}
</Card>
)
}
export default HoverEffectCard

View File

@@ -0,0 +1,30 @@
import { Button } from '@heroui/button'
import { Code } from '@heroui/code'
import { MdError } from 'react-icons/md'
export interface ErrorFallbackProps {
error: Error
resetErrorBoundary: () => void
}
function errorFallbackRender({
error,
resetErrorBoundary
}: ErrorFallbackProps) {
return (
<div className="pt-32 flex flex-col justify-center items-center">
<div className="flex items-center">
<MdError className="mr-2" color="red" size={30} />
<h1 className="text-2xl"></h1>
</div>
<div className="my-6 flex flex-col justify-center items-center">
<p className="mb-2"></p>
<Code>{error.message}</Code>
</div>
<Button color="primary" size="md" onPress={resetErrorBoundary}>
</Button>
</div>
)
}
export default errorFallbackRender

View File

@@ -0,0 +1,166 @@
import {
FaFile,
FaFileAudio,
FaFileCode,
FaFileCsv,
FaFileExcel,
FaFileImage,
FaFileLines,
FaFilePdf,
FaFilePowerpoint,
FaFileVideo,
FaFileWord,
FaFileZipper,
FaFolderClosed
} from 'react-icons/fa6'
export interface FileIconProps {
name?: string
isDirectory?: boolean
}
const FileIcon = (props: FileIconProps) => {
const { name, isDirectory = false } = props
if (isDirectory) {
return <FaFolderClosed className="text-yellow-500" />
}
const ext = name?.split('.').pop() || ''
if (ext) {
switch (ext.toLowerCase()) {
case 'jpg':
case 'jpeg':
case 'png':
case 'gif':
case 'svg':
case 'bmp':
case 'ico':
case 'webp':
case 'tiff':
case 'tif':
case 'heic':
case 'heif':
case 'avif':
case 'apng':
case 'flif':
case 'ai':
case 'psd':
case 'xcf':
case 'sketch':
case 'fig':
case 'xd':
case 'svgz':
return <FaFileImage className="text-green-500" />
case 'pdf':
return <FaFilePdf className="text-red-500" />
case 'doc':
case 'docx':
return <FaFileWord className="text-blue-500" />
case 'xls':
case 'xlsx':
return <FaFileExcel className="text-green-500" />
case 'csv':
return <FaFileCsv className="text-green-500" />
case 'ppt':
case 'pptx':
return <FaFilePowerpoint className="text-red-500" />
case 'zip':
case 'rar':
case '7z':
case 'tar':
case 'gz':
case 'bz2':
case 'xz':
case 'lz':
case 'lzma':
case 'zst':
case 'zstd':
case 'z':
case 'taz':
case 'tz':
case 'tzo':
return <FaFileZipper className="text-green-500" />
case 'txt':
return <FaFileLines className="text-gray-500" />
case 'mp3':
case 'wav':
case 'flac':
return <FaFileAudio className="text-green-500" />
case 'mp4':
case 'avi':
case 'mov':
case 'wmv':
return <FaFileVideo className="text-red-500" />
case 'html':
case 'css':
case 'js':
case 'ts':
case 'jsx':
case 'tsx':
case 'json':
case 'xml':
case 'yaml':
case 'yml':
case 'md':
case 'sh':
case 'py':
case 'java':
case 'c':
case 'cpp':
case 'cs':
case 'go':
case 'php':
case 'rb':
case 'pl':
case 'swift':
case 'kt':
case 'rs':
case 'sql':
case 'r':
case 'scala':
case 'groovy':
case 'dart':
case 'lua':
case 'perl':
case 'h':
case 'm':
case 'mm':
case 'makefile':
case 'cmake':
case 'dockerfile':
case 'gradle':
case 'properties':
case 'ini':
case 'conf':
case 'env':
case 'bat':
case 'cmd':
case 'ps1':
case 'psm1':
case 'psd1':
case 'ps1xml':
case 'psc1':
case 'pssc':
case 'nuspec':
case 'resx':
case 'resw':
case 'csproj':
case 'vbproj':
case 'vcxproj':
case 'fsproj':
case 'sln':
case 'suo':
case 'user':
case 'userosscache':
case 'sln.docstates':
case 'dll':
return <FaFileCode className="text-blue-500" />
default:
return <FaFile className="text-gray-500" />
}
}
return <FaFile className="text-gray-500" />
}
export default FileIcon

View File

@@ -0,0 +1,64 @@
import { Button, ButtonGroup } from '@heroui/button'
import { Input } from '@heroui/input'
import {
Modal,
ModalBody,
ModalContent,
ModalFooter,
ModalHeader
} from '@heroui/modal'
interface CreateFileModalProps {
isOpen: boolean
fileType: 'file' | 'directory'
newFileName: string
onTypeChange: (type: 'file' | 'directory') => void
onNameChange: (e: React.ChangeEvent<HTMLInputElement>) => void
onClose: () => void
onCreate: () => void
}
export default function CreateFileModal({
isOpen,
fileType,
newFileName,
onTypeChange,
onNameChange,
onClose,
onCreate
}: CreateFileModalProps) {
return (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalContent>
<ModalHeader></ModalHeader>
<ModalBody>
<div className="flex flex-col gap-4">
<ButtonGroup color="danger">
<Button
variant={fileType === 'file' ? 'solid' : 'flat'}
onPress={() => onTypeChange('file')}
>
</Button>
<Button
variant={fileType === 'directory' ? 'solid' : 'flat'}
onPress={() => onTypeChange('directory')}
>
</Button>
</ButtonGroup>
<Input label="名称" value={newFileName} onChange={onNameChange} />
</div>
</ModalBody>
<ModalFooter>
<Button color="danger" variant="flat" onPress={onClose}>
</Button>
<Button color="danger" onPress={onCreate}>
</Button>
</ModalFooter>
</ModalContent>
</Modal>
)
}

View File

@@ -0,0 +1,94 @@
import { Button } from '@heroui/button'
import { Code } from '@heroui/code'
import {
Modal,
ModalBody,
ModalContent,
ModalFooter,
ModalHeader
} from '@heroui/modal'
import CodeEditor from '@/components/code_editor'
interface FileEditModalProps {
isOpen: boolean
file: { path: string; content: string } | null
onClose: () => void
onSave: () => void
onContentChange: (newContent?: string) => void
}
export default function FileEditModal({
isOpen,
file,
onClose,
onSave,
onContentChange
}: FileEditModalProps) {
// 根据文件后缀返回对应语言
const getLanguage = (filePath: string) => {
if (filePath.endsWith('.js')) return 'javascript'
if (filePath.endsWith('.ts')) return 'typescript'
if (filePath.endsWith('.tsx')) return 'tsx'
if (filePath.endsWith('.jsx')) return 'jsx'
if (filePath.endsWith('.vue')) return 'vue'
if (filePath.endsWith('.svelte')) return 'svelte'
if (filePath.endsWith('.json')) return 'json'
if (filePath.endsWith('.html')) return 'html'
if (filePath.endsWith('.css')) return 'css'
if (filePath.endsWith('.scss')) return 'scss'
if (filePath.endsWith('.less')) return 'less'
if (filePath.endsWith('.md')) return 'markdown'
if (filePath.endsWith('.yaml') || filePath.endsWith('.yml')) return 'yaml'
if (filePath.endsWith('.xml')) return 'xml'
if (filePath.endsWith('.sql')) return 'sql'
if (filePath.endsWith('.sh')) return 'shell'
if (filePath.endsWith('.bat')) return 'bat'
if (filePath.endsWith('.php')) return 'php'
if (filePath.endsWith('.java')) return 'java'
if (filePath.endsWith('.c')) return 'c'
if (filePath.endsWith('.cpp')) return 'cpp'
if (filePath.endsWith('.h')) return 'h'
if (filePath.endsWith('.hpp')) return 'hpp'
if (filePath.endsWith('.go')) return 'go'
if (filePath.endsWith('.py')) return 'python'
if (filePath.endsWith('.rb')) return 'ruby'
if (filePath.endsWith('.cs')) return 'csharp'
if (filePath.endsWith('.swift')) return 'swift'
if (filePath.endsWith('.vb')) return 'vb'
if (filePath.endsWith('.lua')) return 'lua'
if (filePath.endsWith('.pl')) return 'perl'
if (filePath.endsWith('.r')) return 'r'
return 'plaintext'
}
return (
<Modal size="full" isOpen={isOpen} onClose={onClose}>
<ModalContent>
<ModalHeader className="flex items-center gap-2 bg-content2 bg-opacity-50">
<span></span>
<Code className="text-xs">{file?.path}</Code>
</ModalHeader>
<ModalBody className="p-0">
<div className="h-full">
<CodeEditor
height="100%"
value={file?.content || ''}
onChange={onContentChange}
options={{ wordWrap: 'on' }}
language={file?.path ? getLanguage(file.path) : 'plaintext'}
/>
</div>
</ModalBody>
<ModalFooter>
<Button color="danger" variant="flat" onPress={onClose}>
</Button>
<Button color="danger" onPress={onSave}>
</Button>
</ModalFooter>
</ModalContent>
</Modal>
)
}

View File

@@ -0,0 +1,92 @@
import { Button } from '@heroui/button'
import {
Modal,
ModalBody,
ModalContent,
ModalFooter,
ModalHeader
} from '@heroui/modal'
import { Spinner } from '@heroui/spinner'
import { useRequest } from 'ahooks'
import path from 'path-browserify'
import { useEffect } from 'react'
import FileManager from '@/controllers/file_manager'
interface FilePreviewModalProps {
isOpen: boolean
filePath: string
onClose: () => void
}
export const videoExts = ['.mp4', '.webm']
export const audioExts = ['.mp3', '.wav']
export const supportedPreviewExts = [...videoExts, ...audioExts]
export default function FilePreviewModal({
isOpen,
filePath,
onClose
}: FilePreviewModalProps) {
const ext = path.extname(filePath).toLowerCase()
const { data, loading, error, run } = useRequest(
async () => FileManager.downloadToURL(filePath),
{
refreshDeps: [filePath],
manual: true,
refreshDepsAction: () => {
const ext = path.extname(filePath).toLowerCase()
if (!filePath || !supportedPreviewExts.includes(ext)) {
return
}
run()
}
}
)
useEffect(() => {
if (filePath) {
run()
}
}, [filePath])
let contentElement = null
if (!supportedPreviewExts.includes(ext)) {
contentElement = <div></div>
} else if (error) {
contentElement = <div></div>
} else if (loading || !data) {
contentElement = (
<div className="flex justify-center items-center h-full">
<Spinner />
</div>
)
} else if (videoExts.includes(ext)) {
contentElement = <video src={data} controls className="max-w-full" />
} else if (audioExts.includes(ext)) {
contentElement = <audio src={data} controls className="w-full" />
} else {
contentElement = (
<div className="flex justify-center items-center h-full">
<Spinner />
</div>
)
}
return (
<Modal isOpen={isOpen} onClose={onClose} scrollBehavior="inside" size="3xl">
<ModalContent>
<ModalHeader></ModalHeader>
<ModalBody className="flex justify-center items-center">
{contentElement}
</ModalBody>
<ModalFooter>
<Button color="danger" variant="flat" onPress={onClose}>
</Button>
</ModalFooter>
</ModalContent>
</Modal>
)
}

View File

@@ -0,0 +1,245 @@
import { Button, ButtonGroup } from '@heroui/button'
import { Pagination } from '@heroui/pagination'
import { Spinner } from '@heroui/spinner'
import {
type Selection,
type SortDescriptor,
Table,
TableBody,
TableCell,
TableColumn,
TableHeader,
TableRow
} from '@heroui/table'
import path from 'path-browserify'
import { useCallback, useEffect, useState } from 'react'
import { BiRename } from 'react-icons/bi'
import { FiCopy, FiDownload, FiMove, FiTrash2 } from 'react-icons/fi'
import { PhotoSlider } from 'react-photo-view'
import FileIcon from '@/components/file_icon'
import type { FileInfo } from '@/controllers/file_manager'
import { supportedPreviewExts } from './file_preview_modal'
import ImageNameButton, { PreviewImage, imageExts } from './image_name_button'
export interface FileTableProps {
files: FileInfo[]
currentPath: string
loading: boolean
sortDescriptor: SortDescriptor
onSortChange: (descriptor: SortDescriptor) => void
selectedFiles: Selection
onSelectionChange: (selected: Selection) => void
onDirectoryClick: (dirPath: string) => void
onEdit: (filePath: string) => void
onPreview: (filePath: string) => void
onRenameRequest: (name: string) => void
onMoveRequest: (name: string) => void
onCopyPath: (fileName: string) => void
onDelete: (filePath: string) => void
onDownload: (filePath: string) => void
}
const PAGE_SIZE = 20
export default function FileTable({
files,
currentPath,
loading,
sortDescriptor,
onSortChange,
selectedFiles,
onSelectionChange,
onDirectoryClick,
onEdit,
onPreview,
onRenameRequest,
onMoveRequest,
onCopyPath,
onDelete,
onDownload
}: FileTableProps) {
const [page, setPage] = useState(1)
const pages = Math.ceil(files.length / PAGE_SIZE) || 1
const start = (page - 1) * PAGE_SIZE
const end = start + PAGE_SIZE
const displayFiles = files.slice(start, end)
const [showImage, setShowImage] = useState(false)
const [previewIndex, setPreviewIndex] = useState(0)
const [previewImages, setPreviewImages] = useState<PreviewImage[]>([])
const addPreviewImage = useCallback((image: PreviewImage) => {
setPreviewImages((prev) => {
const exists = prev.some((p) => p.key === image.key)
if (exists) return prev
return [...prev, image]
})
}, [])
useEffect(() => {
setPreviewImages([])
setPreviewIndex(0)
setShowImage(false)
}, [files])
const onPreviewImage = (name: string, images: PreviewImage[]) => {
const index = images.findIndex((image) => image.key === name)
if (index === -1) {
return
}
setPreviewIndex(index)
setShowImage(true)
}
return (
<>
<PhotoSlider
images={previewImages}
visible={showImage}
onClose={() => setShowImage(false)}
index={previewIndex}
onIndexChange={setPreviewIndex}
/>
<Table
aria-label="文件列表"
sortDescriptor={sortDescriptor}
onSortChange={onSortChange}
onSelectionChange={onSelectionChange}
defaultSelectedKeys={[]}
selectedKeys={selectedFiles}
selectionMode="multiple"
bottomContent={
<div className="flex w-full justify-center">
<Pagination
isCompact
showControls
showShadow
color="danger"
page={page}
total={pages}
onChange={(page) => setPage(page)}
/>
</div>
}
>
<TableHeader>
<TableColumn key="name" allowsSorting>
</TableColumn>
<TableColumn key="type" allowsSorting>
</TableColumn>
<TableColumn key="size" allowsSorting>
</TableColumn>
<TableColumn key="mtime" allowsSorting>
</TableColumn>
<TableColumn key="actions"></TableColumn>
</TableHeader>
<TableBody
isLoading={loading}
loadingContent={
<div className="flex justify-center items-center h-full">
<Spinner />
</div>
}
>
{displayFiles.map((file: FileInfo) => {
const filePath = path.join(currentPath, file.name)
const ext = path.extname(file.name).toLowerCase()
const previewable = supportedPreviewExts.includes(ext)
const images = previewImages
return (
<TableRow key={file.name}>
<TableCell>
{imageExts.includes(ext) ? (
<ImageNameButton
name={file.name}
filePath={filePath}
onPreview={() => onPreviewImage(file.name, images)}
onAddPreview={addPreviewImage}
/>
) : (
<Button
variant="light"
onPress={() =>
file.isDirectory
? onDirectoryClick(file.name)
: previewable
? onPreview(filePath)
: onEdit(filePath)
}
className="text-left justify-start"
startContent={
<FileIcon
name={file.name}
isDirectory={file.isDirectory}
/>
}
>
{file.name}
</Button>
)}
</TableCell>
<TableCell>{file.isDirectory ? '目录' : '文件'}</TableCell>
<TableCell>
{isNaN(file.size) || file.isDirectory
? '-'
: `${file.size} 字节`}
</TableCell>
<TableCell>{new Date(file.mtime).toLocaleString()}</TableCell>
<TableCell>
<ButtonGroup size="sm">
<Button
isIconOnly
color="danger"
variant="flat"
onPress={() => onRenameRequest(file.name)}
>
<BiRename />
</Button>
<Button
isIconOnly
color="danger"
variant="flat"
onPress={() => onMoveRequest(file.name)}
>
<FiMove />
</Button>
<Button
isIconOnly
color="danger"
variant="flat"
onPress={() => onCopyPath(file.name)}
>
<FiCopy />
</Button>
<Button
isIconOnly
color="danger"
variant="flat"
onPress={() => onDownload(filePath)}
>
<FiDownload />
</Button>
<Button
isIconOnly
color="danger"
variant="flat"
onPress={() => onDelete(filePath)}
>
<FiTrash2 />
</Button>
</ButtonGroup>
</TableCell>
</TableRow>
)
})}
</TableBody>
</Table>
</>
)
}

View File

@@ -0,0 +1,85 @@
import { Button } from '@heroui/button'
import { Image } from '@heroui/image'
import { Spinner } from '@heroui/spinner'
import { useRequest } from 'ahooks'
import path from 'path-browserify'
import { useEffect } from 'react'
import FileManager from '@/controllers/file_manager'
import FileIcon from '../file_icon'
export interface PreviewImage {
key: string
src: string
alt: string
}
export const imageExts = ['.png', '.jpg', '.jpeg', '.gif', '.bmp']
export interface ImageNameButtonProps {
name: string
filePath: string
onPreview: () => void
onAddPreview: (image: PreviewImage) => void
}
export default function ImageNameButton({
name,
filePath,
onPreview,
onAddPreview
}: ImageNameButtonProps) {
const { data, loading, error, run } = useRequest(
async () => FileManager.downloadToURL(filePath),
{
refreshDeps: [filePath],
manual: true,
refreshDepsAction: () => {
const ext = path.extname(filePath).toLowerCase()
if (!filePath || !imageExts.includes(ext)) {
return
}
run()
}
}
)
useEffect(() => {
if (data) {
onAddPreview({
key: name,
src: data,
alt: name
})
}
}, [data, name, onAddPreview])
useEffect(() => {
if (filePath) {
run()
}
}, [])
return (
<Button
variant="light"
className="text-left justify-start"
onPress={onPreview}
startContent={
error ? (
<FileIcon name={name} isDirectory={false} />
) : loading || !data ? (
<Spinner size="sm" />
) : (
<Image
src={data}
alt={name}
className="w-8 h-8 flex-shrink-0"
radius="sm"
/>
)
}
>
{name}
</Button>
)
}

View File

@@ -0,0 +1,168 @@
import { Button } from '@heroui/button'
import {
Modal,
ModalBody,
ModalContent,
ModalFooter,
ModalHeader
} from '@heroui/modal'
import { Spinner } from '@heroui/spinner'
import clsx from 'clsx'
import path from 'path-browserify'
import { useState } from 'react'
import { IoAdd, IoRemove } from 'react-icons/io5'
import FileManager from '@/controllers/file_manager'
interface MoveModalProps {
isOpen: boolean
moveTargetPath: string
selectionInfo: string
onClose: () => void
onMove: () => void
onSelect: (dir: string) => void // 新增回调
}
// 将 DirectoryTree 改为递归组件
// 新增 selectedPath 属性,用于标识当前选中的目录
function DirectoryTree({
basePath,
onSelect,
selectedPath
}: {
basePath: string
onSelect: (dir: string) => void
selectedPath?: string
}) {
const [dirs, setDirs] = useState<string[]>([])
const [expanded, setExpanded] = useState(false)
// 新增loading状态
const [loading, setLoading] = useState(false)
const fetchDirectories = async () => {
try {
// 直接使用 basePath 调用接口,移除 process.platform 判断
const list = await FileManager.listDirectories(basePath)
setDirs(list.map((item) => item.name))
} catch (error) {
// ...error handling...
}
}
const handleToggle = async () => {
if (!expanded) {
setExpanded(true)
setLoading(true)
await fetchDirectories()
setLoading(false)
} else {
setExpanded(false)
}
}
const handleClick = () => {
onSelect(basePath)
handleToggle()
}
// 计算显示的名称
const getDisplayName = () => {
if (basePath === '/') return '/'
if (/^[A-Z]:$/i.test(basePath)) return basePath
return path.basename(basePath)
}
// 更新 Button 的 variant 逻辑
const isSeleted = selectedPath === basePath
const variant = isSeleted
? 'solid'
: selectedPath && path.dirname(selectedPath) === basePath
? 'flat'
: 'light'
return (
<div className="ml-4">
<Button
onPress={handleClick}
className="py-1 px-2 text-left justify-start min-w-0 min-h-0 h-auto text-sm rounded-md"
size="sm"
color="danger"
variant={variant}
startContent={
<div
className={clsx(
'rounded-md',
isSeleted ? 'bg-danger-600' : 'bg-danger-50'
)}
>
{expanded ? <IoRemove /> : <IoAdd />}
</div>
}
>
{getDisplayName()}
</Button>
{expanded && (
<div>
{loading ? (
<div className="flex py-1 px-8">
<Spinner size="sm" color="danger" />
</div>
) : (
dirs.map((dirName) => {
const childPath =
basePath === '/' && /^[A-Z]:$/i.test(dirName)
? dirName
: path.join(basePath, dirName)
return (
<DirectoryTree
key={childPath}
basePath={childPath}
onSelect={onSelect}
selectedPath={selectedPath}
/>
)
})
)}
</div>
)}
</div>
)
}
export default function MoveModal({
isOpen,
moveTargetPath,
selectionInfo,
onClose,
onMove,
onSelect
}: MoveModalProps) {
return (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalContent>
<ModalHeader></ModalHeader>
<ModalBody>
<div className="rounded-md p-2 border border-default-300 overflow-auto max-h-60">
<DirectoryTree
basePath="/"
onSelect={onSelect}
selectedPath={moveTargetPath}
/>
</div>
<p className="text-sm text-default-500 mt-2">
{moveTargetPath || '未选择'}
</p>
<p className="text-sm text-default-500">{selectionInfo}</p>
</ModalBody>
<ModalFooter>
<Button color="danger" variant="flat" onPress={onClose}>
</Button>
<Button color="danger" onPress={onMove}>
</Button>
</ModalFooter>
</ModalContent>
</Modal>
)
}

View File

@@ -0,0 +1,44 @@
import { Button } from '@heroui/button'
import { Input } from '@heroui/input'
import {
Modal,
ModalBody,
ModalContent,
ModalFooter,
ModalHeader
} from '@heroui/modal'
interface RenameModalProps {
isOpen: boolean
newFileName: string
onNameChange: (e: React.ChangeEvent<HTMLInputElement>) => void
onClose: () => void
onRename: () => void
}
export default function RenameModal({
isOpen,
newFileName,
onNameChange,
onClose,
onRename
}: RenameModalProps) {
return (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalContent>
<ModalHeader></ModalHeader>
<ModalBody>
<Input label="新名称" value={newFileName} onChange={onNameChange} />
</ModalBody>
<ModalFooter>
<Button color="danger" variant="flat" onPress={onClose}>
</Button>
<Button color="danger" onPress={onRename}>
</Button>
</ModalFooter>
</ModalContent>
</Modal>
)
}

View File

@@ -0,0 +1,19 @@
import clsx from 'clsx'
export interface IconWrapperProps {
children?: React.ReactNode
className?: string
}
const IconWrapper = ({ children, className }: IconWrapperProps) => (
<div
className={clsx(
className,
'flex items-center rounded-small justify-center w-7 h-7'
)}
>
{children}
</div>
)
export default IconWrapper

View File

@@ -0,0 +1,10 @@
import { ChevronRightIcon } from '../icons'
const ItemCounter = ({ number }: { number: number }) => (
<div className="flex items-center gap-1 text-default-400">
<span className="text-small">{number}</span>
<ChevronRightIcon className="text-xl" />
</div>
)
export default ItemCounter

View File

@@ -0,0 +1,40 @@
import { useEffect, useState } from 'react'
import { getReleaseTime } from '@/utils/time'
import type { GithubRelease as GithubReleaseType } from '@/types/github'
export interface GithubReleaseProps {
releaseData: GithubReleaseType
}
const GithubRelease: React.FC<GithubReleaseProps> = (props) => {
const { releaseData } = props
const [releaseTime, setReleaseTime] = useState<string | null>(null)
useEffect(() => {
if (releaseData) {
const timer = setInterval(() => {
const time = getReleaseTime(releaseData.published_at)
setReleaseTime(time)
}, 1000)
return () => clearInterval(timer)
}
}, [releaseData])
return (
<div className="flex flex-col gap-1">
<span>Releases</span>
<div className="px-2 py-1 rounded-small bg-default-100 bg-opacity-50 backdrop-blur-sm group-data-[hover=true]:bg-default-200">
<span className="text-tiny text-default-600">{releaseData.name}</span>
<div className="flex gap-2 text-tiny">
<span className="text-default-500">{releaseTime}</span>
<span className="text-success">Latest</span>
</div>
</div>
</div>
)
}
export default GithubRelease

View File

@@ -0,0 +1,76 @@
import { Button } from '@heroui/button'
import { Tooltip } from '@heroui/tooltip'
import { useRequest } from 'ahooks'
import toast from 'react-hot-toast'
import { IoCopy, IoRefresh } from 'react-icons/io5'
import { request } from '@/utils/request'
import PageLoading from './page_loading'
export default function Hitokoto() {
const {
data: dataOri,
error,
loading,
run
} = useRequest(() => request.get<IHitokoto>('https://hitokoto.152710.xyz/'), {
pollingInterval: 10000,
throttleWait: 1000
})
const data = dataOri?.data
const onCopy = () => {
try {
const text = `${data?.hitokoto} —— ${data?.from} ${data?.from_who}`
navigator.clipboard.writeText(text)
toast.success('复制成功')
} catch (error) {
toast.error('复制失败, 请手动复制')
}
}
return (
<div>
<div className="relative">
{loading && <PageLoading />}
{error ? (
<div className="text-danger-400">{error.message}</div>
) : (
<>
<div>{data?.hitokoto}</div>
<div className="text-right">
<span className="text-default-400">{data?.from}</span>{' '}
{data?.from_who}
</div>
</>
)}
</div>
<div className="flex gap-2">
<Tooltip content="刷新" placement="top">
<Button
onPress={run}
size="sm"
isLoading={loading}
isIconOnly
radius="full"
color="danger"
variant="flat"
>
<IoRefresh />
</Button>
</Tooltip>
<Tooltip content="复制" placement="top">
<Button
onPress={onCopy}
size="sm"
isIconOnly
radius="full"
color="success"
variant="flat"
>
<IoCopy />
</Button>
</Tooltip>
</div>
</div>
)
}

View File

@@ -0,0 +1,146 @@
import { motion, useMotionValue, useSpring } from 'motion/react'
import { useRef, useState } from 'react'
const springValues = {
damping: 30,
stiffness: 100,
mass: 2
}
export interface HoverTiltedCardProps {
imageSrc: string
altText?: string
captionText?: string
containerHeight?: string
containerWidth?: string
imageHeight?: string
imageWidth?: string
scaleOnHover?: number
rotateAmplitude?: number
showTooltip?: boolean
overlayContent?: React.ReactNode
displayOverlayContent?: boolean
}
export default function HoverTiltedCard({
imageSrc,
altText = 'NapCat',
captionText = 'NapCat',
containerHeight = '200px',
containerWidth = '100%',
imageHeight = '200px',
imageWidth = '200px',
scaleOnHover = 1.1,
rotateAmplitude = 14,
showTooltip = false,
overlayContent = (
<div className="text-center mt-6 px-4 py-0.5 shadow-lg rounded-full bg-danger-600 text-default-100 bg-opacity-80">
NapCat
</div>
),
displayOverlayContent = true
}: HoverTiltedCardProps) {
const ref = useRef<HTMLDivElement>(null)
const x = useMotionValue(0)
const y = useMotionValue(0)
const rotateX = useSpring(useMotionValue(0), springValues)
const rotateY = useSpring(useMotionValue(0), springValues)
const scale = useSpring(1, springValues)
const opacity = useSpring(0)
const rotateFigcaption = useSpring(0, {
stiffness: 350,
damping: 30,
mass: 1
})
const [lastY, setLastY] = useState(0)
function handleMouse(e: React.MouseEvent) {
if (!ref.current) return
const rect = ref.current.getBoundingClientRect()
const offsetX = e.clientX - rect.left - rect.width / 2
const offsetY = e.clientY - rect.top - rect.height / 2
const rotationX = (offsetY / (rect.height / 2)) * -rotateAmplitude
const rotationY = (offsetX / (rect.width / 2)) * rotateAmplitude
rotateX.set(rotationX)
rotateY.set(rotationY)
x.set(e.clientX - rect.left)
y.set(e.clientY - rect.top)
const velocityY = offsetY - lastY
rotateFigcaption.set(-velocityY * 0.6)
setLastY(offsetY)
}
function handleMouseEnter() {
scale.set(scaleOnHover)
opacity.set(1)
}
function handleMouseLeave() {
opacity.set(0)
scale.set(1)
rotateX.set(0)
rotateY.set(0)
rotateFigcaption.set(0)
}
return (
<figure
ref={ref}
className="relative w-full h-full [perspective:800px] flex flex-col items-center justify-center"
style={{
height: containerHeight,
width: containerWidth
}}
onMouseMove={handleMouse}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<motion.div
className="relative [transform-style:preserve-3d]"
style={{
width: imageWidth,
height: imageHeight,
rotateX,
rotateY,
scale
}}
>
<motion.img
src={imageSrc}
alt={altText}
className="absolute top-0 left-0 object-cover rounded-md will-change-transform [transform:translateZ(0)] pointer-events-none select-none"
style={{
width: imageWidth,
height: imageHeight
}}
/>
{displayOverlayContent && overlayContent && (
<motion.div className="absolute top-0 left-0 right-0 z-10 flex justify-center will-change-transform [transform:translateZ(30px)]">
{overlayContent}
</motion.div>
)}
</motion.div>
{showTooltip && (
<motion.figcaption
className="pointer-events-none absolute left-0 top-0 rounded-md bg-white px-2 py-1 text-sm text-default-900 opacity-0 z-10 hidden sm:block"
style={{
x,
y,
opacity,
rotate: rotateFigcaption
}}
>
{captionText}
</motion.figcaption>
)}
</figure>
)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
import { Button } from '@heroui/button'
import { Image } from '@heroui/image'
import { Input } from '@heroui/input'
import { useRef } from 'react'
export interface ImageInputProps {
onChange: (base64: string) => void
value: string
label?: string
}
const ImageInput: React.FC<ImageInputProps> = ({ onChange, value, label }) => {
const inputRef = useRef<HTMLInputElement>(null)
return (
<div className="flex items-end gap-2">
<div className="w-5 h-5 flex-shrink-0">
<Image
src={value}
alt={label}
className="w-5 h-5 flex-shrink-0 rounded-none"
/>
</div>
<Input
ref={inputRef}
label={label}
type="file"
placeholder="选择图片"
accept="image/*"
onChange={async (e) => {
const file = e.target.files?.[0]
if (file) {
const reader = new FileReader()
reader.onload = async () => {
const base64 = reader.result as string
onChange(base64)
}
reader.readAsDataURL(file)
}
}}
/>
<Button
onPress={() => {
onChange('')
if (inputRef.current) inputRef.current.value = ''
}}
color="danger"
variant="flat"
size="sm"
>
</Button>
</div>
)
}
export default ImageInput

View File

@@ -0,0 +1,136 @@
import { Button } from '@heroui/button'
import { Card, CardBody, CardHeader } from '@heroui/card'
import { Select, SelectItem } from '@heroui/select'
import type { Selection } from '@react-types/shared'
import { useEffect, useRef, useState } from 'react'
import { colorizeLogLevel } from '@/utils/terminal'
import PageLoading from '../page_loading'
import XTerm from '../xterm'
import type { XTermRef } from '../xterm'
import LogLevelSelect from './log_level_select'
export interface HistoryLogsProps {
list: string[]
onSelect: (name: string) => void
selectedLog?: string
refreshList: () => void
refreshLog: () => void
listLoading?: boolean
logLoading?: boolean
listError?: Error
logContent?: string
}
const HistoryLogs: React.FC<HistoryLogsProps> = (props) => {
const {
list,
onSelect,
selectedLog,
refreshList,
refreshLog,
listLoading,
logContent,
listError,
logLoading
} = props
const Xterm = useRef<XTermRef>(null)
const [logLevel, setLogLevel] = useState<Selection>(
new Set(['info', 'warn', 'error'])
)
const logToColored = (log: string) => {
const logs = log
.split('\n')
.map((line) => {
const colored = colorizeLogLevel(line)
return colored
})
.filter((log) => {
if (logLevel === 'all') {
return true
}
return logLevel.has(log.level)
})
.map((log) => log.content)
.join('\r\n')
return logs
}
const onDownloadLog = () => {
if (!logContent) {
return
}
const blob = new Blob([logContent], { type: 'text/plain' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `${selectedLog}.log`
a.click()
URL.revokeObjectURL(url)
}
useEffect(() => {
if (!Xterm.current || !logContent) {
return
}
Xterm.current.clear()
const _logContent = logToColored(logContent)
Xterm.current.write(_logContent + '\r\nnapcat@webui:~$ ')
}, [logContent, logLevel])
return (
<>
<title> - NapCat WebUI</title>
<Card className="max-w-full h-full bg-opacity-50 backdrop-blur-sm">
<CardHeader className="flex-row justify-start gap-3">
<Select
label="选择日志"
size="sm"
isLoading={listLoading}
errorMessage={listError?.message}
classNames={{
trigger:
'hover:!bg-content3 bg-opacity-50 backdrop-blur-sm hover:!bg-opacity-60'
}}
placeholder="选择日志"
onChange={(e) => {
const value = e.target.value
if (!value) {
return
}
onSelect(value)
}}
selectedKeys={[selectedLog || '']}
items={list.map((name) => ({
value: name,
label: name
}))}
>
{(item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
)}
</Select>
<LogLevelSelect
selectedKeys={logLevel}
onSelectionChange={setLogLevel}
/>
<Button className="flex-shrink-0" onPress={onDownloadLog}>
</Button>
<Button onPress={refreshList}></Button>
<Button onPress={refreshLog}></Button>
</CardHeader>
<CardBody className="relative">
<PageLoading loading={logLoading} />
<XTerm className="w-full h-full" ref={Xterm} />
</CardBody>
</Card>
</>
)
}
export default HistoryLogs

View File

@@ -0,0 +1,87 @@
import { Chip } from '@heroui/chip'
import { Select, SelectItem } from '@heroui/select'
import { SharedSelection } from '@heroui/system'
import type { Selection } from '@react-types/shared'
import { LogLevel } from '@/const/enum'
export interface LogLevelSelectProps {
selectedKeys: Selection
onSelectionChange: (keys: SharedSelection) => void
}
const logLevelColor: {
[key in LogLevel]:
| 'default'
| 'primary'
| 'secondary'
| 'success'
| 'warning'
| 'danger'
} = {
[LogLevel.DEBUG]: 'default',
[LogLevel.INFO]: 'primary',
[LogLevel.WARN]: 'warning',
[LogLevel.ERROR]: 'danger',
[LogLevel.FATAL]: 'danger'
}
const LogLevelSelect = (props: LogLevelSelectProps) => {
const { selectedKeys, onSelectionChange } = props
return (
<Select
selectedKeys={selectedKeys}
onSelectionChange={(selectedKeys) => {
if (selectedKeys !== 'all' && selectedKeys?.size === 0) {
selectedKeys = 'all'
}
onSelectionChange(selectedKeys)
}}
label="日志级别"
selectionMode="multiple"
aria-label="Log Level"
classNames={{
label: 'mb-2',
trigger: 'bg-opacity-50 backdrop-blur-sm hover:!bg-opacity-60',
popoverContent: 'bg-opacity-50 backdrop-blur-sm'
}}
size="sm"
items={[
{ label: 'Debug', value: LogLevel.DEBUG },
{ label: 'Info', value: LogLevel.INFO },
{ label: 'Warn', value: LogLevel.WARN },
{ label: 'Error', value: LogLevel.ERROR },
{ label: 'Fatal', value: LogLevel.FATAL }
]}
renderValue={(value) => {
if (value.length === 5) {
return (
<Chip size="sm" color="primary" variant="flat">
</Chip>
)
}
return (
<div className="flex gap-2">
{value.map((v) => (
<Chip
size="sm"
key={v.key}
color={logLevelColor[v.data?.value as LogLevel]}
variant="flat"
>
{v.data?.label}
</Chip>
))}
</div>
)
}}
>
{(item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
)}
</Select>
)
}
export default LogLevelSelect

View File

@@ -0,0 +1,114 @@
import { Button } from '@heroui/button'
import type { Selection } from '@react-types/shared'
import { useEffect, useRef, useState } from 'react'
import toast from 'react-hot-toast'
import { IoDownloadOutline } from 'react-icons/io5'
import { colorizeLogLevelWithTag } from '@/utils/terminal'
import WebUIManager, { Log } from '@/controllers/webui_manager'
import type { XTermRef } from '../xterm'
import XTerm from '../xterm'
import LogLevelSelect from './log_level_select'
const RealTimeLogs = () => {
const Xterm = useRef<XTermRef>(null)
const [logLevel, setLogLevel] = useState<Selection>(
new Set(['info', 'warn', 'error'])
)
const [dataArr, setDataArr] = useState<Log[]>([])
const onDownloadLog = () => {
const logContent = dataArr
.filter((log) => {
if (logLevel === 'all') {
return true
}
return logLevel.has(log.level)
})
.map((log) => colorizeLogLevelWithTag(log.message, log.level))
.join('\r\n')
const blob = new Blob([logContent], { type: 'text/plain' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = 'napcat.log'
a.click()
URL.revokeObjectURL(url)
}
const writeStream = () => {
try {
const _data = dataArr
.filter((log) => {
if (logLevel === 'all') {
return true
}
return logLevel.has(log.level)
})
.map((log) => colorizeLogLevelWithTag(log.message, log.level))
.join('\r\n')
Xterm.current?.clear()
Xterm.current?.write(_data)
} catch (error) {
console.error(error)
toast.error('获取实时日志失败')
}
}
useEffect(() => {
writeStream()
}, [logLevel, dataArr])
useEffect(() => {
const subscribeLogs = () => {
try {
const source = WebUIManager.getRealTimeLogs((data) => {
setDataArr((prev) => {
const newData = [...prev, ...data]
if (newData.length > 1000) {
newData.splice(0, newData.length - 1000)
}
return newData
})
})
return () => {
source.close()
}
} catch (error) {
toast.error('获取实时日志失败')
}
}
const close = subscribeLogs()
return () => {
console.log('close')
close?.()
}
}, [])
return (
<>
<title> - NapCat WebUI</title>
<div className="flex items-center gap-2">
<LogLevelSelect
selectedKeys={logLevel}
onSelectionChange={setLogLevel}
/>
<Button
className="flex-shrink-0"
onPress={onDownloadLog}
startContent={<IoDownloadOutline className="text-lg" />}
>
</Button>
</div>
<div className="flex-1 h-full overflow-hidden">
<XTerm ref={Xterm} />
</div>
</>
)
}
export default RealTimeLogs

View File

@@ -0,0 +1,97 @@
import { Button } from '@heroui/button'
import {
ModalBody,
ModalContent,
ModalFooter,
ModalHeader,
Modal as NextUIModal,
useDisclosure
} from '@heroui/modal'
import React from 'react'
export interface ModalProps {
content: React.ReactNode
title?: React.ReactNode
size?: React.ComponentProps<typeof NextUIModal>['size']
scrollBehavior?: React.ComponentProps<typeof NextUIModal>['scrollBehavior']
onClose?: () => void
onConfirm?: () => void
onCancel?: () => void
backdrop?: 'opaque' | 'blur' | 'transparent'
showCancel?: boolean
dismissible?: boolean
confirmText?: string
cancelText?: string
}
const Modal: React.FC<ModalProps> = React.memo((props) => {
const {
backdrop = 'blur',
title,
content,
showCancel = true,
dismissible,
confirmText = '确定',
cancelText = '取消',
onClose,
onConfirm,
onCancel,
...rest
} = props
const { onClose: onNativeClose } = useDisclosure()
return (
<NextUIModal
defaultOpen
backdrop={backdrop}
isDismissable={dismissible}
onClose={() => {
onClose?.()
onNativeClose()
}}
classNames={{
backdrop: 'z-[99]',
wrapper: 'z-[99]'
}}
{...rest}
>
<ModalContent>
{(nativeClose) => (
<>
{title && (
<ModalHeader className="flex flex-col gap-1">{title}</ModalHeader>
)}
<ModalBody className="break-all">{content}</ModalBody>
<ModalFooter>
{showCancel && (
<Button
color="danger"
variant="light"
onPress={() => {
onCancel?.()
nativeClose()
}}
>
{cancelText}
</Button>
)}
<Button
color="danger"
onPress={() => {
onConfirm?.()
nativeClose()
}}
>
{confirmText}
</Button>
</ModalFooter>
</>
)}
</ModalContent>
</NextUIModal>
)
})
Modal.displayName = 'Modal'
export default Modal

View File

@@ -0,0 +1,241 @@
import { Listbox, ListboxItem } from '@heroui/listbox'
import { Spinner } from '@heroui/spinner'
import { useRequest } from 'ahooks'
import { MdError } from 'react-icons/md'
import IconWrapper from '@/components/github_info/icon_wrapper'
import ItemCounter from '@/components/github_info/item_counter'
import GithubRelease from '@/components/github_info/release'
import {
BookIcon,
BugIcon,
PullRequestIcon,
StarIcon,
TagIcon,
UsersIcon,
WatchersIcon
} from '@/components/icons'
import { request } from '@/utils/request'
import { openUrl } from '@/utils/url'
import type {
GirhubRepo,
GithubContributor,
GithubPullRequest,
GithubRelease as GithubReleaseType
} from '@/types/github'
function displayData(data: number, loading: boolean, error?: Error) {
if (error) {
return <MdError className="text-danger-400" />
}
if (loading) {
return <Spinner size="sm" />
}
return <ItemCounter number={data} />
}
export default function NapCatRepoInfo() {
// repo info
const {
data: repoOriData,
error: repoError,
loading: repoLoading
} = useRequest(() =>
request.get<GirhubRepo>('https://api.github.com/repos/NapNeko/NapCatQQ')
)
// release info
const {
data: releaseOriData,
error: releaseError,
loading: releaseLoading
} = useRequest(() =>
request.get<GithubReleaseType[]>(
'https://api.github.com/repos/NapNeko/NapCatQQ/releases'
)
)
// pr info
const {
data: prData,
error: prError,
loading: prLoading
} = useRequest(() =>
request.get<GithubPullRequest[]>(
'https://api.github.com/repos/NapNeko/NapCatQQ/pulls'
)
)
// contributors info
const {
data: contributorsData,
error: contributorsError,
loading: contributorsLoading
} = useRequest(() =>
request.get<GithubContributor[]>(
'https://api.github.com/repos/NapNeko/NapCatQQ/contributors'
)
)
const repoData = repoOriData?.data
const releaseData = releaseOriData?.data?.[0]
const prCount = prData?.data?.length || 0
const contributorsCount = contributorsData?.data?.length || 0
const releaseCount = releaseOriData?.data?.length || 0
return (
<Listbox
aria-label="NapCat Repo Info"
className="p-0 gap-0 divide-y divide-default-300/50 dark:divide-default-100/80 bg-content1 max-w-[300px] overflow-visible shadow-small rounded-medium bg-opacity-50 backdrop-blur-sm"
itemClasses={{
base: 'px-3 first:rounded-t-medium last:rounded-b-medium rounded-none gap-3 h-12 data-[hover=true]:bg-default-100/80'
}}
onAction={(key: React.Key) => {
switch (key) {
case 'releases':
openUrl('https://github.com/NapNeko/NapCatQQ/releases', true)
break
case 'contributors':
openUrl(
'https://github.com/NapNeko/NapCatQQ/graphs/contributors',
true
)
break
case 'license':
openUrl(
'https://github.com/NapNeko/NapCatQQ/blob/main/LICENSE',
true
)
break
case 'watchers':
openUrl('https://github.com/NapNeko/NapCatQQ/watchers', true)
break
case 'star':
openUrl('https://github.com/NapNeko/NapCatQQ/stargazers', true)
break
case 'issues':
openUrl('https://github.com/NapNeko/NapCatQQ/issues', true)
break
case 'pull_requests':
openUrl('https://github.com/NapNeko/NapCatQQ/pulls', true)
break
default:
openUrl('https://github.com/NapNeko/NapCatQQ', true)
}
}}
>
<ListboxItem
key="star"
endContent={displayData(
repoData?.stargazers_count ?? 0,
false,
repoError
)}
startContent={
<IconWrapper className="bg-success/10 text-success">
<StarIcon className="text-lg" />
</IconWrapper>
}
>
Star
</ListboxItem>
<ListboxItem
key="issues"
endContent={displayData(
repoData?.open_issues_count ?? 0,
false,
repoError
)}
startContent={
<IconWrapper className="bg-success/10 text-success">
<BugIcon className="text-lg" />
</IconWrapper>
}
>
Issues
</ListboxItem>
<ListboxItem
key="pull_requests"
endContent={displayData(prCount, prLoading, prError)}
startContent={
<IconWrapper className="bg-primary/10 text-primary">
<PullRequestIcon className="text-lg" />
</IconWrapper>
}
>
Pull Requests
</ListboxItem>
<ListboxItem
key="releases"
className="group h-auto py-3"
endContent={
releaseError ? (
<MdError className="text-danger-400" />
) : releaseLoading ? (
<Spinner size="sm" />
) : (
<ItemCounter number={releaseCount} />
)
}
startContent={
<IconWrapper className="bg-primary/10 text-primary">
<TagIcon className="text-lg" />
</IconWrapper>
}
textValue="Releases"
>
{releaseData && <GithubRelease releaseData={releaseData} />}
</ListboxItem>
<ListboxItem
key="contributors"
endContent={displayData(
contributorsCount,
contributorsLoading,
contributorsError
)}
startContent={
<IconWrapper className="bg-warning/10 text-warning">
<UsersIcon />
</IconWrapper>
}
>
Contributors
</ListboxItem>
<ListboxItem
key="watchers"
endContent={displayData(
repoData?.watchers_count ?? 0,
repoLoading,
repoError
)}
startContent={
<IconWrapper className="bg-default/50 text-foreground">
<WatchersIcon />
</IconWrapper>
}
>
Watchers
</ListboxItem>
<ListboxItem
key="license"
endContent={
<span className="text-small text-default-400">
{repoData?.license?.name ?? 'unknown'}
</span>
}
startContent={
<IconWrapper className="bg-danger/10 text-danger dark:text-danger-500">
<BookIcon />
</IconWrapper>
}
>
License
</ListboxItem>
</Listbox>
)
}

View File

@@ -0,0 +1,172 @@
import { Button } from '@heroui/button'
import { Input } from '@heroui/input'
import { ModalBody, ModalFooter } from '@heroui/modal'
import { Select, SelectItem } from '@heroui/select'
import { ReactElement, useEffect } from 'react'
import { Controller, useForm } from 'react-hook-form'
import type {
DefaultValues,
Path,
PathValue,
SubmitHandler
} from 'react-hook-form'
import toast from 'react-hot-toast'
import SwitchCard from '../switch_card'
export type FieldTypes = 'input' | 'select' | 'switch'
type NetworkConfigType = OneBotConfig['network']
export interface Field<T extends keyof OneBotConfig['network']> {
name: keyof NetworkConfigType[T][0]
label: string
type: FieldTypes
options?: Array<{ key: string; value: string }>
placeholder?: string
isRequired?: boolean
isDisabled?: boolean
description?: string
colSpan?: 1 | 2
}
export interface GenericFormProps<T extends keyof NetworkConfigType> {
data?: NetworkConfigType[T][0]
defaultValues: DefaultValues<NetworkConfigType[T][0]>
onClose: () => void
onSubmit: (data: NetworkConfigType[T][0]) => Promise<void>
fields: Array<Field<T>>
}
const GenericForm = <T extends keyof NetworkConfigType>({
data,
defaultValues,
onClose,
onSubmit,
fields
}: GenericFormProps<T>): ReactElement => {
const { control, handleSubmit, formState, setValue, reset } = useForm<
NetworkConfigType[T][0]
>({
defaultValues
})
const submitAction: SubmitHandler<NetworkConfigType[T][0]> = async (data) => {
await onSubmit(data)
onClose()
}
const _onSubmit = handleSubmit(submitAction, (e) => {
for (const error in e) {
toast.error(e[error]?.message as string)
return
}
})
useEffect(() => {
if (data) {
const keys = Object.keys(data) as Path<NetworkConfig[T][0]>[]
for (const key of keys) {
const value = data[key] as PathValue<
NetworkConfig[T][0],
Path<NetworkConfig[T][0]>
>
setValue(key, value)
}
} else {
reset()
}
}, [data, reset, setValue])
return (
<>
<ModalBody>
<div className="grid grid-cols-2 gap-y-4 gap-x-2 w-full">
{fields.map((field) => (
<div
key={field.name as string}
className={field.colSpan === 1 ? 'col-span-1' : 'col-span-2'}
>
<Controller
control={control}
name={field.name as Path<NetworkConfig[T][0]>}
rules={
field.isRequired
? {
required: `请填写${field.label}`
}
: void 0
}
render={({ field: controllerField }) => {
switch (field.type) {
case 'input':
return (
<Input
value={controllerField.value as string}
onChange={controllerField.onChange}
onBlur={controllerField.onBlur}
ref={controllerField.ref}
isRequired={field.isRequired}
isDisabled={field.isDisabled}
label={field.label}
placeholder={field.placeholder}
/>
)
case 'select':
return (
<Select
{...controllerField}
ref={controllerField.ref}
isRequired={field.isRequired}
label={field.label}
placeholder={field.placeholder}
selectedKeys={[controllerField.value as string]}
value={controllerField.value.toString()}
>
{field.options?.map((option) => (
<SelectItem key={option.key} value={option.value}>
{option.value}
</SelectItem>
)) || <></>}
</Select>
)
case 'switch':
return (
<SwitchCard
{...controllerField}
value={controllerField.value as boolean}
description={field.description}
label={field.label}
/>
)
default:
return <></>
}
}}
/>
</div>
))}
</div>
</ModalBody>
<ModalFooter>
<Button
color="danger"
isDisabled={formState.isSubmitting}
variant="light"
onPress={onClose}
>
</Button>
<Button
color="primary"
isLoading={formState.isSubmitting}
onPress={() => _onSubmit()}
>
</Button>
</ModalFooter>
</>
)
}
export default GenericForm

View File

@@ -0,0 +1,95 @@
import GenericForm from './generic_form'
import type { Field } from './generic_form'
export interface HTTPClientFormProps {
data?: OneBotConfig['network']['httpClients'][0]
onClose: () => void
onSubmit: (data: OneBotConfig['network']['httpClients'][0]) => Promise<void>
}
type HTTPClientFormType = OneBotConfig['network']['httpClients']
const HTTPClientForm: React.FC<HTTPClientFormProps> = ({
data,
onClose,
onSubmit
}) => {
const defaultValues: HTTPClientFormType[0] = {
enable: false,
name: '',
url: 'http://localhost:8080',
reportSelfMessage: false,
messagePostFormat: 'array',
token: '',
debug: false
}
const fields: Field<'httpClients'>[] = [
{
name: 'enable',
label: '启用',
type: 'switch',
description: '保存后启用此配置',
colSpan: 1
},
{
name: 'debug',
label: '开启Debug',
type: 'switch',
description: '是否开启调试模式',
colSpan: 1
},
{
name: 'name',
label: '名称',
type: 'input',
placeholder: '请输入名称',
isRequired: true,
isDisabled: !!data
},
{
name: 'url',
label: 'URL',
type: 'input',
placeholder: '请输入URL',
isRequired: true
},
{
name: 'reportSelfMessage',
label: '上报自身消息',
type: 'switch',
description: '是否上报自身消息',
colSpan: 1
},
{
name: 'messagePostFormat',
label: '消息格式',
type: 'select',
placeholder: '请选择消息格式',
isRequired: true,
options: [
{ key: 'array', value: 'Array' },
{ key: 'string', value: 'String' }
],
colSpan: 1
},
{
name: 'token',
label: 'Token',
type: 'input',
placeholder: '请输入Token'
}
]
return (
<GenericForm
data={data}
defaultValues={defaultValues}
onClose={onClose}
onSubmit={onSubmit}
fields={fields}
/>
)
}
export default HTTPClientForm

View File

@@ -0,0 +1,110 @@
import GenericForm from './generic_form'
import type { Field } from './generic_form'
export interface HTTPServerFormProps {
data?: OneBotConfig['network']['httpServers'][0]
onClose: () => void
onSubmit: (data: OneBotConfig['network']['httpServers'][0]) => Promise<void>
}
type HTTPServerFormType = OneBotConfig['network']['httpServers']
const HTTPServerForm: React.FC<HTTPServerFormProps> = ({
data,
onClose,
onSubmit
}) => {
const defaultValues: HTTPServerFormType[0] = {
enable: false,
name: '',
host: '0.0.0.0',
port: 3000,
enableCors: true,
enableWebsocket: true,
messagePostFormat: 'array',
token: '',
debug: false
}
const fields: Field<'httpServers'>[] = [
{
name: 'enable',
label: '启用',
type: 'switch',
description: '保存后启用此配置',
colSpan: 1
},
{
name: 'debug',
label: '开启Debug',
type: 'switch',
description: '是否开启调试模式',
colSpan: 1
},
{
name: 'name',
label: '名称',
type: 'input',
placeholder: '请输入名称',
isRequired: true,
isDisabled: !!data
},
{
name: 'host',
label: 'Host',
type: 'input',
placeholder: '请输入主机地址',
isRequired: true
},
{
name: 'port',
label: 'Port',
type: 'input',
placeholder: '请输入端口',
isRequired: true
},
{
name: 'enableCors',
label: '启用CORS',
type: 'switch',
description: '是否启用CORS跨域',
colSpan: 1
},
{
name: 'enableWebsocket',
label: '启用Websocket',
type: 'switch',
description: '是否启用Websocket',
colSpan: 1
},
{
name: 'messagePostFormat',
label: '消息格式',
type: 'select',
placeholder: '请选择消息格式',
isRequired: true,
options: [
{ key: 'array', value: 'Array' },
{ key: 'string', value: 'String' }
]
},
{
name: 'token',
label: 'Token',
type: 'input',
placeholder: '请输入Token'
}
]
return (
<GenericForm
data={data}
defaultValues={defaultValues}
onClose={onClose}
onSubmit={onSubmit}
fields={fields}
/>
)
}
export default HTTPServerForm

View File

@@ -0,0 +1,120 @@
import GenericForm from './generic_form'
import type { Field } from './generic_form'
export interface HTTPServerSSEFormProps {
data?: OneBotConfig['network']['httpSseServers'][0]
onClose: () => void
onSubmit: (
data: OneBotConfig['network']['httpSseServers'][0]
) => Promise<void>
}
type HTTPServerSSEFormType = OneBotConfig['network']['httpSseServers']
const HTTPServerSSEForm: React.FC<HTTPServerSSEFormProps> = ({
data,
onClose,
onSubmit
}) => {
const defaultValues: HTTPServerSSEFormType[0] = {
enable: false,
name: '',
host: '0.0.0.0',
port: 3000,
enableCors: true,
enableWebsocket: true,
messagePostFormat: 'array',
token: '',
debug: false,
reportSelfMessage: false
}
const fields: Field<'httpSseServers'>[] = [
{
name: 'enable',
label: '启用',
type: 'switch',
description: '保存后启用此配置',
colSpan: 1
},
{
name: 'debug',
label: '开启Debug',
type: 'switch',
description: '是否开启调试模式',
colSpan: 1
},
{
name: 'name',
label: '名称',
type: 'input',
placeholder: '请输入名称',
isRequired: true,
isDisabled: !!data
},
{
name: 'host',
label: 'Host',
type: 'input',
placeholder: '请输入主机地址',
isRequired: true
},
{
name: 'port',
label: 'Port',
type: 'input',
placeholder: '请输入端口',
isRequired: true
},
{
name: 'enableCors',
label: '启用CORS',
type: 'switch',
description: '是否启用CORS跨域',
colSpan: 1
},
{
name: 'enableWebsocket',
label: '启用Websocket',
type: 'switch',
description: '是否启用Websocket',
colSpan: 1
},
{
name: 'messagePostFormat',
label: '消息格式',
type: 'select',
placeholder: '请选择消息格式',
isRequired: true,
options: [
{ key: 'array', value: 'Array' },
{ key: 'string', value: 'String' }
]
},
{
name: 'token',
label: 'Token',
type: 'input',
placeholder: '请输入Token'
},
{
name: 'reportSelfMessage',
label: '上报自身消息',
type: 'switch',
description: '是否上报自身消息',
colSpan: 1
}
]
return (
<GenericForm
data={data}
defaultValues={defaultValues}
onClose={onClose}
onSubmit={onSubmit}
fields={fields}
/>
)
}
export default HTTPServerSSEForm

View File

@@ -0,0 +1,123 @@
import { Modal, ModalContent, ModalHeader } from '@heroui/modal'
import toast from 'react-hot-toast'
import useConfig from '@/hooks/use-config'
import HTTPClientForm from './http_client'
import HTTPServerForm from './http_server'
import HTTPServerSSEForm from './http_sse'
import WebsocketClientForm from './ws_client'
import WebsocketServerForm from './ws_server'
const modalTitle = {
httpServers: 'HTTP Server',
httpClients: 'HTTP Client',
httpSseServers: 'HTTP SSE Server',
websocketServers: 'Websocket Server',
websocketClients: 'Websocket Client'
}
export interface NetworkFormModalProps<
T extends keyof OneBotConfig['network']
> {
isOpen: boolean
field: T
data?: OneBotConfig['network'][T][0]
onOpenChange: (isOpen: boolean) => void
}
const NetworkFormModal = <T extends keyof OneBotConfig['network']>(
props: NetworkFormModalProps<T>
) => {
const { isOpen, onOpenChange, field, data } = props
const { createNetworkConfig, updateNetworkConfig } = useConfig()
const isCreate = !data
const onSubmit = async (data: OneBotConfig['network'][typeof field][0]) => {
try {
if (isCreate) {
await createNetworkConfig(field, data)
} else {
await updateNetworkConfig(field, data)
}
toast.success('保存配置成功')
} catch (error) {
const msg = (error as Error).message
toast.error(`保存配置失败: ${msg}`)
throw error
}
}
const renderFormComponent = (onClose: () => void) => {
switch (field) {
case 'httpServers':
return (
<HTTPServerForm
data={data as OneBotConfig['network']['httpServers'][0]}
onClose={onClose}
onSubmit={onSubmit}
/>
)
case 'httpClients':
return (
<HTTPClientForm
data={data as OneBotConfig['network']['httpClients'][0]}
onClose={onClose}
onSubmit={onSubmit}
/>
)
case 'websocketServers':
return (
<WebsocketServerForm
data={data as OneBotConfig['network']['websocketServers'][0]}
onClose={onClose}
onSubmit={onSubmit}
/>
)
case 'websocketClients':
return (
<WebsocketClientForm
data={data as OneBotConfig['network']['websocketClients'][0]}
onClose={onClose}
onSubmit={onSubmit}
/>
)
case 'httpSseServers':
return (
<HTTPServerSSEForm
data={data as OneBotConfig['network']['httpSseServers'][0]}
onClose={onClose}
onSubmit={onSubmit}
/>
)
default:
return null
}
}
return (
<Modal
backdrop="blur"
isDismissable={false}
isOpen={isOpen}
size="lg"
scrollBehavior="outside"
onOpenChange={onOpenChange}
>
<ModalContent>
{(onClose) => (
<>
<ModalHeader className="flex flex-col gap-1">
{modalTitle[field]}
</ModalHeader>
{renderFormComponent(onClose)}
</>
)}
</ModalContent>
</Modal>
)
}
export default NetworkFormModal

Some files were not shown because too many files have changed in this diff Show More