koishi-plugin-oni-sync-bot 0.8.5 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +154 -14
- package/lib/plugins/queryCommands.d.ts +8 -2
- package/package.json +1 -1
- package/readme.md +245 -169
package/lib/index.js
CHANGED
|
@@ -1424,18 +1424,21 @@ var QueryCommands = class {
|
|
|
1424
1424
|
}
|
|
1425
1425
|
static inject = ["database"];
|
|
1426
1426
|
config;
|
|
1427
|
+
ctx;
|
|
1427
1428
|
constructor(ctx, config) {
|
|
1429
|
+
this.ctx = ctx;
|
|
1428
1430
|
this.config = config;
|
|
1429
1431
|
this.registerCommands(ctx);
|
|
1430
1432
|
}
|
|
1431
1433
|
registerCommands(ctx) {
|
|
1432
|
-
ctx.command("x <itemName>", "查询缺氧中文wiki,精准匹配+拼音模糊匹配").alias("/查wiki").action(async ({ session }, itemName = "") => {
|
|
1434
|
+
ctx.command("x <itemName:text>", "查询缺氧中文wiki,精准匹配+拼音模糊匹配").alias("/查wiki").action(async ({ session }, itemName = "") => {
|
|
1433
1435
|
const queryKey = itemName.trim().toLowerCase();
|
|
1434
1436
|
if (!queryKey) {
|
|
1435
|
-
return this.
|
|
1437
|
+
return this.renderUsageMessage(session);
|
|
1436
1438
|
}
|
|
1437
1439
|
if (SPECIAL_CASES.has(queryKey)) {
|
|
1438
|
-
|
|
1440
|
+
const content = SPECIAL_CASES.get(queryKey);
|
|
1441
|
+
return this.sendResponse(session, content);
|
|
1439
1442
|
}
|
|
1440
1443
|
const { pinyin_full: queryPinyinFull, pinyin_first: queryPinyinFirst } = generatePinyinInfo(queryKey);
|
|
1441
1444
|
const preciseMatch = await this.findPreciseMatch(
|
|
@@ -1445,14 +1448,18 @@ var QueryCommands = class {
|
|
|
1445
1448
|
queryPinyinFirst
|
|
1446
1449
|
);
|
|
1447
1450
|
if (preciseMatch) {
|
|
1448
|
-
return this.
|
|
1451
|
+
return this.renderResultMessage(
|
|
1452
|
+
session,
|
|
1449
1453
|
preciseMatch,
|
|
1450
1454
|
preciseMatch.prefix
|
|
1451
1455
|
);
|
|
1452
1456
|
}
|
|
1453
1457
|
const allPages = await ctx.database.get("wikipages", {});
|
|
1454
1458
|
if (allPages.length === 0) {
|
|
1455
|
-
return
|
|
1459
|
+
return this.sendResponse(
|
|
1460
|
+
session,
|
|
1461
|
+
"❌ 本地缓存为空,请联系管理员执行【update】指令更新缓存!"
|
|
1462
|
+
);
|
|
1456
1463
|
}
|
|
1457
1464
|
const fuzzyMatches = this.findFuzzyMatches(
|
|
1458
1465
|
allPages,
|
|
@@ -1461,23 +1468,139 @@ var QueryCommands = class {
|
|
|
1461
1468
|
queryPinyinFirst
|
|
1462
1469
|
);
|
|
1463
1470
|
if (fuzzyMatches.length === 0) {
|
|
1464
|
-
return
|
|
1471
|
+
return this.sendResponse(
|
|
1472
|
+
session,
|
|
1473
|
+
`❌ 未找到【${queryKey}】相关内容,请按游戏内标准名称重新查询!`
|
|
1474
|
+
);
|
|
1465
1475
|
}
|
|
1466
1476
|
return await this.handleSelection(session, fuzzyMatches);
|
|
1467
1477
|
});
|
|
1468
1478
|
}
|
|
1469
|
-
|
|
1479
|
+
isQQPlatform(session) {
|
|
1480
|
+
return session?.platform === "qq";
|
|
1481
|
+
}
|
|
1482
|
+
buildLinkButton(idSuffix, label, url) {
|
|
1483
|
+
return {
|
|
1484
|
+
id: `btn-${idSuffix}`,
|
|
1485
|
+
render_data: {
|
|
1486
|
+
label,
|
|
1487
|
+
visited_label: "已打开",
|
|
1488
|
+
style: 1
|
|
1489
|
+
},
|
|
1490
|
+
action: {
|
|
1491
|
+
type: 0,
|
|
1492
|
+
permission: {
|
|
1493
|
+
type: 2
|
|
1494
|
+
},
|
|
1495
|
+
data: url
|
|
1496
|
+
}
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
buildQQKeyboard(matches) {
|
|
1500
|
+
const rows = [];
|
|
1501
|
+
for (let i = 0; i < matches.length; i += 2) {
|
|
1502
|
+
const buttonsInRow = matches.slice(i, i + 2).map((item) => {
|
|
1503
|
+
const label = item.title.length > 10 ? item.title.slice(0, 10) : item.title;
|
|
1504
|
+
return this.buildLinkButton(
|
|
1505
|
+
`${item.id}`,
|
|
1506
|
+
label,
|
|
1507
|
+
`https://${this.config.domain}/bw/${item.id}`
|
|
1508
|
+
);
|
|
1509
|
+
});
|
|
1510
|
+
rows.push({ buttons: buttonsInRow });
|
|
1511
|
+
}
|
|
1512
|
+
return {
|
|
1513
|
+
content: { rows }
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1516
|
+
async sendResponse(session, content, keyboard) {
|
|
1517
|
+
if (this.isQQPlatform(session)) {
|
|
1518
|
+
try {
|
|
1519
|
+
const payload = {
|
|
1520
|
+
msg_id: session.messageId,
|
|
1521
|
+
msg_type: 2,
|
|
1522
|
+
markdown: {
|
|
1523
|
+
content
|
|
1524
|
+
}
|
|
1525
|
+
};
|
|
1526
|
+
if (keyboard) {
|
|
1527
|
+
payload.keyboard = keyboard;
|
|
1528
|
+
}
|
|
1529
|
+
await session.bot.internal.sendMessage(session.channelId, payload);
|
|
1530
|
+
return;
|
|
1531
|
+
} catch (e) {
|
|
1532
|
+
this.ctx.logger("oni-sync-bot").warn("QQ Markdown 发送失败,降级为纯文本:", e);
|
|
1533
|
+
return content;
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
return content;
|
|
1537
|
+
}
|
|
1538
|
+
renderUsageMessage(session) {
|
|
1539
|
+
if (this.isQQPlatform(session)) {
|
|
1540
|
+
const md = `**以下是使用说明:**
|
|
1541
|
+
> GG原站点: [https://${this.config.domain}/gg/88888888](https://${this.config.domain}/gg/88888888)
|
|
1542
|
+
|
|
1543
|
+
> bwiki: [https://${this.config.domain}/bw/88888888](https://${this.config.domain}/bw/88888888)
|
|
1544
|
+
`;
|
|
1545
|
+
return this.sendResponse(session, md);
|
|
1546
|
+
}
|
|
1470
1547
|
return `以下是使用说明:
|
|
1471
|
-
原站点: https://${this.config.domain}/gg/88888888
|
|
1548
|
+
GG原站点: https://${this.config.domain}/gg/88888888
|
|
1472
1549
|
|
|
1473
1550
|
bwiki: https://${this.config.domain}/bw/88888888`;
|
|
1474
1551
|
}
|
|
1475
|
-
|
|
1552
|
+
buildResultKeyboard(match) {
|
|
1553
|
+
return {
|
|
1554
|
+
content: {
|
|
1555
|
+
rows: [
|
|
1556
|
+
{
|
|
1557
|
+
buttons: [
|
|
1558
|
+
this.buildLinkButton(
|
|
1559
|
+
`gg-${match.id}`,
|
|
1560
|
+
"GG 原站",
|
|
1561
|
+
`https://${this.config.domain}/gg/${match.id}`
|
|
1562
|
+
)
|
|
1563
|
+
]
|
|
1564
|
+
},
|
|
1565
|
+
{
|
|
1566
|
+
buttons: [
|
|
1567
|
+
this.buildLinkButton(
|
|
1568
|
+
`bw-${match.id}`,
|
|
1569
|
+
"Bwiki 镜像",
|
|
1570
|
+
`https://${this.config.domain}/bw/${match.id}`
|
|
1571
|
+
)
|
|
1572
|
+
]
|
|
1573
|
+
},
|
|
1574
|
+
{
|
|
1575
|
+
buttons: [
|
|
1576
|
+
this.buildLinkButton(
|
|
1577
|
+
`wiki-${match.id}`,
|
|
1578
|
+
"GG直链",
|
|
1579
|
+
`https://oxygennotincluded.wiki.gg/zh/${encodeURIComponent(match.title)}`
|
|
1580
|
+
)
|
|
1581
|
+
]
|
|
1582
|
+
}
|
|
1583
|
+
]
|
|
1584
|
+
}
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
renderResultMessage(session, match, prefix) {
|
|
1588
|
+
if (this.isQQPlatform(session)) {
|
|
1589
|
+
let md = "";
|
|
1590
|
+
if (prefix) {
|
|
1591
|
+
md += `**${prefix}**
|
|
1592
|
+
`;
|
|
1593
|
+
}
|
|
1594
|
+
md += `**📖 ${match.title}**
|
|
1595
|
+
`;
|
|
1596
|
+
const keyboard = this.buildResultKeyboard(match);
|
|
1597
|
+
return this.sendResponse(session, md, keyboard);
|
|
1598
|
+
}
|
|
1476
1599
|
let message = "";
|
|
1477
1600
|
if (prefix) {
|
|
1478
1601
|
message += prefix + "\n";
|
|
1479
1602
|
}
|
|
1480
|
-
message +=
|
|
1603
|
+
message += `GG原站点: https://${this.config.domain}/gg/${match.id}
|
|
1481
1604
|
|
|
1482
1605
|
bwiki: https://${this.config.domain}/bw/${match.id}`;
|
|
1483
1606
|
return message;
|
|
@@ -1544,7 +1667,20 @@ bwiki: https://${this.config.domain}/bw/${match.id}`;
|
|
|
1544
1667
|
}
|
|
1545
1668
|
async handleSelection(session, matches) {
|
|
1546
1669
|
const resultCount = matches.length;
|
|
1547
|
-
let replyMsg
|
|
1670
|
+
let replyMsg;
|
|
1671
|
+
if (this.isQQPlatform(session)) {
|
|
1672
|
+
let md = `**🔍 为你找到【 ${resultCount} 】个相似结果,请点击下方按钮查看详情:**
|
|
1673
|
+
`;
|
|
1674
|
+
matches.forEach((item, index) => {
|
|
1675
|
+
md += `
|
|
1676
|
+
> \`${index + 1}\`. **${item.title}**
|
|
1677
|
+
`;
|
|
1678
|
+
});
|
|
1679
|
+
const keyboard = this.buildQQKeyboard(matches);
|
|
1680
|
+
await this.sendResponse(session, md, keyboard);
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1683
|
+
replyMsg = `🔍 未找到精准匹配,为你找到【 ${resultCount} 】个相似结果,请输入序号选择(10秒内有效):
|
|
1548
1684
|
`;
|
|
1549
1685
|
matches.forEach((item, index) => {
|
|
1550
1686
|
replyMsg += `${index + 1}. ${item.title}
|
|
@@ -1552,15 +1688,19 @@ bwiki: https://${this.config.domain}/bw/${match.id}`;
|
|
|
1552
1688
|
});
|
|
1553
1689
|
replyMsg += `
|
|
1554
1690
|
❗️ 提示:超时将静默结束,无任何回应`;
|
|
1555
|
-
await
|
|
1691
|
+
await this.sendResponse(session, replyMsg);
|
|
1556
1692
|
const userInput = await session.prompt(15e3);
|
|
1557
1693
|
if (!userInput) return;
|
|
1558
1694
|
const selectNum = parseInt(userInput.trim(), 10);
|
|
1559
1695
|
if (isNaN(selectNum) || selectNum < 1 || selectNum > resultCount) {
|
|
1560
|
-
return
|
|
1696
|
+
return this.sendResponse(
|
|
1697
|
+
session,
|
|
1698
|
+
`❌ 输入无效!请输入 1-${resultCount} 之间的数字序号`
|
|
1699
|
+
);
|
|
1561
1700
|
}
|
|
1562
1701
|
const selected = matches[selectNum - 1];
|
|
1563
|
-
return this.
|
|
1702
|
+
return this.renderResultMessage(
|
|
1703
|
+
session,
|
|
1564
1704
|
selected,
|
|
1565
1705
|
"✅ 选择成功"
|
|
1566
1706
|
);
|
|
@@ -5,10 +5,16 @@ export interface QueryCommandsConfig {
|
|
|
5
5
|
export declare class QueryCommands {
|
|
6
6
|
static readonly inject: string[];
|
|
7
7
|
config: QueryCommandsConfig;
|
|
8
|
+
private ctx;
|
|
8
9
|
constructor(ctx: Context, config: QueryCommandsConfig);
|
|
9
10
|
private registerCommands;
|
|
10
|
-
private
|
|
11
|
-
private
|
|
11
|
+
private isQQPlatform;
|
|
12
|
+
private buildLinkButton;
|
|
13
|
+
private buildQQKeyboard;
|
|
14
|
+
private sendResponse;
|
|
15
|
+
private renderUsageMessage;
|
|
16
|
+
private buildResultKeyboard;
|
|
17
|
+
private renderResultMessage;
|
|
12
18
|
private findPreciseMatch;
|
|
13
19
|
private calculateScore;
|
|
14
20
|
private findFuzzyMatches;
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -2,235 +2,311 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/koishi-plugin-oni-sync-bot)
|
|
4
4
|
[](https://koishi.chat)
|
|
5
|
+
[](LICENSE)
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
**缺氧 Wiki 镜像站同步机器人插件** — 实现 [oxygennotincluded.wiki.gg](https://oxygennotincluded.wiki.gg) 与 B站 Wiki 镜像的双向内容同步、拼音匹配页面查询、模块同步管理,以及页面短链接重定向服务。
|
|
7
8
|
|
|
8
|
-
##
|
|
9
|
+
## ✨ 核心功能
|
|
9
10
|
|
|
10
|
-
###
|
|
11
|
+
### 📄 Wiki 同步
|
|
11
12
|
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
13
|
+
- **双向登录** — 自动登录 wiki.gg 与 B站 Wiki(bwiki)两个站点
|
|
14
|
+
- **页面同步** — 单个/批量页面从 wiki.gg 同步到 bwiki
|
|
15
|
+
- **模块同步** — 批量同步 Module 命名空间页面
|
|
16
|
+
- **图片同步** — 同步页面引用的图片文件(支持单个/批量)
|
|
17
|
+
- **增量更新** — 每小时自动检测最近编辑并同步到镜像站
|
|
18
|
+
- **自动重连** — 登录过期自动检测并重新登录(3次重试机制)
|
|
19
|
+
- **登录重试** — 单次登录失败自动重试(最多3次,间隔5秒)
|
|
19
20
|
|
|
20
|
-
###
|
|
21
|
+
### 🔍 页面查询
|
|
21
22
|
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
- 🕐 **定时任务** - 每周一同步模块,每周二检查状态
|
|
27
|
-
- 🎨 **可爱风格** - 萌系风格的 UI 设计
|
|
28
|
-
- 🔍 **搜索筛选** - 支持关键词搜索和状态筛选
|
|
29
|
-
- 📄 **分页显示** - 支持分页和自定义每页条数
|
|
30
|
-
- 📱 **移动端适配** - 响应式设计,支持手机访问
|
|
23
|
+
- **精准匹配** — 标题/全拼/首字母精确匹配
|
|
24
|
+
- **拼音模糊匹配** — 支持中文名称的拼音搜索
|
|
25
|
+
- **QQ Markdown 按钮** — QQ群查询结果以可点击按钮形式呈现(点击即跳转页面)
|
|
26
|
+
- **命令别名** — `x` / `查wiki` 快捷命令
|
|
31
27
|
|
|
32
|
-
|
|
28
|
+
### 📋 模块同步 TodoList
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
## 配置
|
|
41
|
-
|
|
42
|
-
在 Koishi 控制台中配置以下参数:
|
|
30
|
+
- **自动同步** — 每周一 00:00 自动同步 wiki.gg 所有 Module 到待办
|
|
31
|
+
- **状态检查** — 每周二 00:00 自动检查模块同步状态(对比修订时间)
|
|
32
|
+
- **控制台管理** — 萌系风格可视化管理界面,支持搜索/筛选/分页
|
|
33
|
+
- **增删改查** — 完整的待办管理命令和控制台操作
|
|
34
|
+
- **权限控制** — 删除/清空操作需权限 2,删除缓存需权限 4
|
|
43
35
|
|
|
44
|
-
|
|
45
|
-
| --------------- | ------------- | ------ |
|
|
46
|
-
| `ggUsername` | WIKIGG 用户名 | 1 |
|
|
47
|
-
| `ggPassword` | WIKIGG 密码 | 1 |
|
|
48
|
-
| `bwikiusername` | bwiki 用户名 | 1 |
|
|
49
|
-
| `bwikipassword` | bwiki 密码 | 1 |
|
|
36
|
+
### � 路由重定向
|
|
50
37
|
|
|
51
|
-
|
|
38
|
+
- **短链接服务** — `/:id` → 跳转至完整 Wiki 页面 URL
|
|
39
|
+
- **GG 原站跳转** — `/gg/:id` → 跳转至 oxygennotincluded.wiki.gg 对应页面
|
|
40
|
+
- **Bwiki 镜像跳转** — `/bw/:id` → 跳转至 wiki.biligame.com/oni 对应页面
|
|
41
|
+
- **通配路径转发** — `/ggwiki/*` → 转发任意路径和查询参数到原站
|
|
42
|
+
- **持久化缓存** — 页面标题和页面ID映射保存在本地数据库,首次启动需执行 `update`
|
|
52
43
|
|
|
53
|
-
###
|
|
44
|
+
### 🎮 特殊指令
|
|
54
45
|
|
|
55
|
-
|
|
56
|
-
| -------------------- | ---------------------- |
|
|
57
|
-
| `sync.page <标题>` | 同步单个页面到 bwiki |
|
|
58
|
-
| `sync.gg <标题>` | 同步单个页面到 WIKIGG |
|
|
59
|
-
| `sync.module <前缀>` | 同步指定前缀的所有页面 |
|
|
60
|
-
| `sync.img <标题>` | 同步页面引用的图片 |
|
|
61
|
-
| `sync.update` | 执行增量更新 |
|
|
46
|
+
- **火箭计算器** — 查询 "火箭计算器" 返回计算器工具链接提示
|
|
62
47
|
|
|
63
|
-
|
|
48
|
+
## 📦 项目结构
|
|
64
49
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
50
|
+
```
|
|
51
|
+
oni-sync-bot/
|
|
52
|
+
├── src/
|
|
53
|
+
│ ├── index.ts # 插件入口(子插件注册表)
|
|
54
|
+
│ ├── services/
|
|
55
|
+
│ │ ├── wikiBotService.ts # Wiki 机器人核心服务(登录、重连、代理)
|
|
56
|
+
│ │ └── consoleLogProvider.ts # 控制台日志服务
|
|
57
|
+
│ ├── plugins/
|
|
58
|
+
│ │ ├── databaseExtension.ts # 数据库模型扩展(wikipages 表)
|
|
59
|
+
│ │ ├── queryCommands.ts # 页面查询命令(x / 查wiki)
|
|
60
|
+
│ │ ├── syncCommands.ts # Wiki 同步命令(sync.*)+ 定时任务
|
|
61
|
+
│ │ ├── updateCommands.ts # 缓存管理命令(update.* / redirect / relogin)
|
|
62
|
+
│ │ ├── routeRedirect.ts # 路由重定向服务(/gg / /bw / /ggwiki)
|
|
63
|
+
│ │ └── todoList.ts # TodoList 模块同步管理(命令 + 控制台 + 定时任务)
|
|
64
|
+
│ ├── sync/
|
|
65
|
+
│ │ ├── pageSync.ts # 页面同步逻辑(单页、全量、增量)
|
|
66
|
+
│ │ ├── moduleSync.ts # 模块同步逻辑
|
|
67
|
+
│ │ └── imgSync.ts # 图片同步逻辑
|
|
68
|
+
│ └── utils/
|
|
69
|
+
│ └── tools.ts # 工具函数(拼音生成、日志、错误处理)
|
|
70
|
+
├── client/
|
|
71
|
+
│ ├── Rocketcalculator/ # 火箭计算器前端页面
|
|
72
|
+
│ │ ├── calculator.ts
|
|
73
|
+
│ │ ├── calculator.vue
|
|
74
|
+
│ │ ├── config.ts
|
|
75
|
+
│ │ ├── index.vue
|
|
76
|
+
│ ├── onitodolist/ # TodoList 管理前端页面
|
|
77
|
+
│ │ ├── index.vue
|
|
78
|
+
│ │ └── todolist.vue
|
|
79
|
+
│ ├── index.ts
|
|
80
|
+
│ ├── page.vue # 日志查看页面
|
|
81
|
+
│ └── tsconfig.json
|
|
82
|
+
├── package.json
|
|
83
|
+
├── tsconfig.json
|
|
84
|
+
└── README.md
|
|
85
|
+
```
|
|
78
86
|
|
|
79
|
-
|
|
80
|
-
| --------- | ---------------------- |
|
|
81
|
-
| `relogin` | 手动重新登录两个机器人 |
|
|
87
|
+
## 🔧 架构设计
|
|
82
88
|
|
|
83
|
-
|
|
89
|
+
### 子插件模式
|
|
84
90
|
|
|
85
|
-
|
|
91
|
+
主入口 `src/index.ts` 采用依赖顺序注册子插件:
|
|
86
92
|
|
|
87
93
|
```
|
|
88
|
-
|
|
94
|
+
Service 层(数据库、WikiBot 服务)
|
|
95
|
+
↓
|
|
96
|
+
Core 层(同步逻辑、路由重定向)
|
|
97
|
+
↓
|
|
98
|
+
Command 层(查询命令、同步命令、更新命令、TodoList)
|
|
99
|
+
↓
|
|
100
|
+
UI 层(控制台日志、TodoList 可视化面板、火箭计算器)
|
|
89
101
|
```
|
|
90
102
|
|
|
91
|
-
###
|
|
103
|
+
### 数据库模型
|
|
104
|
+
|
|
105
|
+
| 表名 | 字段 | 说明 |
|
|
106
|
+
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- |
|
|
107
|
+
| `wikipages` | `id` (integer), `title` (string), `pinyin_full` (string), `pinyin_first` (string) | Wiki 页面索引缓存,支持拼音检索 |
|
|
108
|
+
| `onitodos` | `id` (unsigned, auto), `title` (string), `content` (text), `completed` (boolean), `createdBy` (string), `createdAt` (timestamp), `updatedAt` (timestamp) | 模块同步待办事项 |
|
|
109
|
+
|
|
110
|
+
### 核心技术
|
|
111
|
+
|
|
112
|
+
| 技术 | 用途 |
|
|
113
|
+
| ---------------------------- | -------------------------------------------- |
|
|
114
|
+
| **TypeScript** | 完整类型支持,严格模式编译 |
|
|
115
|
+
| **Koishi 4** | 机器人框架,基于 Service 和 Plugin 架构 |
|
|
116
|
+
| **Mwn** | MediaWiki API 客户端(wiki.gg / bwiki 交互) |
|
|
117
|
+
| **pinyin-pro** | 中文转拼音,支持页面名称模糊匹配 |
|
|
118
|
+
| **koishi-plugin-cron** | 定时任务调度(每小时增量更新、每周同步等) |
|
|
119
|
+
| **@koishijs/plugin-console** | Koishi 控制台(提供可视化管理界面) |
|
|
120
|
+
| **@koishijs/plugin-server** | HTTP 服务器(提供短链接重定向路由) |
|
|
121
|
+
|
|
122
|
+
## ⚙️ 配置项
|
|
123
|
+
|
|
124
|
+
| 参数 | 说明 | 默认值 | 必需 |
|
|
125
|
+
| --------------- | ------------------- | ------------------------------ | ---- |
|
|
126
|
+
| `ggUsername` | WIKIGG 用户名 | `1` | ✅ |
|
|
127
|
+
| `ggPassword` | WIKIGG 密码 | `1` | ✅ |
|
|
128
|
+
| `bwikiusername` | Bwiki 用户名 | `1` | ✅ |
|
|
129
|
+
| `bwikipassword` | Bwiki 密码 | `1` | ✅ |
|
|
130
|
+
| `domain` | 你的短链域名 | `klei.vip` | ✅ |
|
|
131
|
+
| `main_site` | 主站域名(wiki.gg) | `oxygennotincluded.wiki.gg/zh` | ✅ |
|
|
132
|
+
| `bwiki_site` | 镜像站域名(bwiki) | `wiki.biligame.com/oni` | ✅ |
|
|
133
|
+
| `logsUrl` | 日志查看地址 | `https://klei.vip/onilogs` | - |
|
|
134
|
+
|
|
135
|
+
## 📚 命令列表
|
|
136
|
+
|
|
137
|
+
### 🔍 查询命令
|
|
138
|
+
|
|
139
|
+
| 命令 | 别名 | 说明 | 权限 |
|
|
140
|
+
| --------------- | -------- | ------------------------------ | ---- |
|
|
141
|
+
| `x <itemName>` | `查wiki` | 查询页面(标题/拼音/模糊匹配) | - |
|
|
142
|
+
| `查询 <关键词>` | - | 同上(备用命令名) | - |
|
|
143
|
+
|
|
144
|
+
### 🔄 同步命令
|
|
145
|
+
|
|
146
|
+
| 命令 | 别名 | 说明 | 权限 |
|
|
147
|
+
| ------------------------ | ---------- | -------------------- | ---- |
|
|
148
|
+
| `sync <标题>` | - | 同步单个页面到 bwiki | 2 |
|
|
149
|
+
| `sync.allpages` | - | 同步所有页面 | 2 |
|
|
150
|
+
| `sync.module <模块名>` | - | 同步单个模块 | 2 |
|
|
151
|
+
| `sync.allmodules` | - | 同步所有模块 | 2 |
|
|
152
|
+
| `sync.img <图片名>` | - | 同步单张图片 | 2 |
|
|
153
|
+
| `sync.allimgs` | - | 同步所有图片 | 2 |
|
|
154
|
+
| `sync.incrementalUpdate` | `增量更新` | 执行增量更新 | 2 |
|
|
155
|
+
|
|
156
|
+
### 📝 缓存管理
|
|
157
|
+
|
|
158
|
+
| 命令 | 别名 | 说明 | 权限 |
|
|
159
|
+
| ------------------------------ | ---------- | ----------------------------------- | ---- |
|
|
160
|
+
| `update` | - | 更新本地页面缓存(从 wiki.gg 获取) | 2 |
|
|
161
|
+
| `update.status` | - | 查询缓存数量和状态 | 1 |
|
|
162
|
+
| `update.delete` | - | 清空页面缓存 | 4 |
|
|
163
|
+
| `redirect <原页面> <目标页面>` | `重定向` | 在 wiki.gg 创建重定向页面 | 2 |
|
|
164
|
+
| `relogin` | `重新登录` | 手动重新登录两个 Wiki 机器人 | 2 |
|
|
165
|
+
|
|
166
|
+
### ✅ TodoList 命令
|
|
167
|
+
|
|
168
|
+
| 命令 | 别名 | 说明 | 权限 |
|
|
169
|
+
| ---------------------- | -------- | ---------------------------------------- | ---- |
|
|
170
|
+
| `todolist` | `todo` | 查看 TodoList(跳转网页) | - |
|
|
171
|
+
| `todo.list` | `todo.l` | 查看 TodoList(跳转网页) | - |
|
|
172
|
+
| `todo.add <标题>` | `todo.a` | 添加待办事项(支持 `-c` `-u` 选项) | - |
|
|
173
|
+
| `todo.edit <id>` | `todo.e` | 编辑待办事项(支持 `-t` `-c` `-u` 选项) | - |
|
|
174
|
+
| `todo.complete <id>` | `todo.c` | 标记待办为完成 | - |
|
|
175
|
+
| `todo.uncomplete <id>` | `todo.u` | 标记待办为未完成 | - |
|
|
176
|
+
| `todo.delete <id>` | `todo.d` | 删除待办事项 | 2 |
|
|
177
|
+
| `todo.clear` | - | 清空 TodoList | 2 |
|
|
178
|
+
| `todo.syncmodules` | - | 手动同步 wiki.gg 模块到 TodoList | - |
|
|
179
|
+
| `todo.checksync` | - | 手动检查模块同步状态 | - |
|
|
180
|
+
|
|
181
|
+
## ⏰ 定时任务
|
|
182
|
+
|
|
183
|
+
| 时间 | 任务 | 说明 |
|
|
184
|
+
| ---------------- | ------------------- | -------------------------------------- |
|
|
185
|
+
| **每小时 15 分** | 增量更新 | 获取最近编辑并同步到 bwiki |
|
|
186
|
+
| **每周四 08:30** | 同步所有页面 | 从 wiki.gg 全量同步页面到 bwiki |
|
|
187
|
+
| **每周三 08:30** | 同步所有图片 | 从 wiki.gg 全量同步图片资源 |
|
|
188
|
+
| **每周一 00:00** | 同步模块到 TodoList | 获取所有 Module 命名空间页面并写入待办 |
|
|
189
|
+
| **每周二 00:00** | 检查模块同步状态 | 对比修订时间,自动标记完成/未完成 |
|
|
190
|
+
|
|
191
|
+
## 🔌 路由接口
|
|
192
|
+
|
|
193
|
+
| 路径 | 方法 | 说明 |
|
|
194
|
+
| ----------- | ---- | --------------------------------------------------------- |
|
|
195
|
+
| `/gg/:id` | GET | 跳转至 oxygennotincluded.wiki.gg 对应页面(自动编码标题) |
|
|
196
|
+
| `/bw/:id` | GET | 跳转至 wiki.biligame.com/oni 对应页面 |
|
|
197
|
+
| `/ggwiki/*` | GET | 通配路径转发至 oxygennotincluded.wiki.gg,保留查询参数 |
|
|
198
|
+
|
|
199
|
+
> � **提示**:首次部署请先执行 `update` 命令填充 `wikipages` 表,否则路由跳转将返回"未找到页面"提示。
|
|
200
|
+
|
|
201
|
+
## 🚀 安装
|
|
92
202
|
|
|
93
|
-
```
|
|
94
|
-
|
|
203
|
+
```bash
|
|
204
|
+
npm install koishi-plugin-oni-sync-bot
|
|
205
|
+
# 或
|
|
206
|
+
yarn add koishi-plugin-oni-sync-bot
|
|
95
207
|
```
|
|
96
208
|
|
|
97
|
-
|
|
209
|
+
## 🔨 开发
|
|
98
210
|
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
|
|
211
|
+
```bash
|
|
212
|
+
# 克隆项目
|
|
213
|
+
git clone https://github.com/Charles-LF/oni-sync-bot.git
|
|
102
214
|
|
|
103
|
-
|
|
215
|
+
# 安装依赖
|
|
216
|
+
yarn install
|
|
104
217
|
|
|
105
|
-
|
|
106
|
-
|
|
218
|
+
# 构建
|
|
219
|
+
yarn build
|
|
220
|
+
|
|
221
|
+
# 开发模式
|
|
222
|
+
yarn dev
|
|
107
223
|
```
|
|
108
224
|
|
|
109
|
-
|
|
225
|
+
### 依赖服务
|
|
110
226
|
|
|
111
|
-
|
|
227
|
+
插件正常运行需以下 Koishi 核心插件(Koishi 默认已提供):
|
|
112
228
|
|
|
113
|
-
|
|
229
|
+
- **@koishijs/plugin-database** — 数据持久化(wikipages / onitodos)
|
|
230
|
+
- **@koishijs/plugin-server** — HTTP 服务器(短链接路由)
|
|
231
|
+
- **@koishijs/plugin-console** — 控制台 UI(TodoList 管理界面)
|
|
232
|
+
- **koishi-plugin-cron** — 定时任务调度
|
|
233
|
+
- **@koishijs/plugin-adapter-\*(可选)** — 如 QQ 适配器,以获得 Markdown 按钮效果
|
|
114
234
|
|
|
115
|
-
|
|
116
|
-
- 🔍 **搜索功能** - 快速搜索日志内容
|
|
117
|
-
- ⏬ **自动滚动** - 新日志自动滚动到底部
|
|
118
|
-
- 🎯 **一键滚动** - 手动跳转到顶部或底部
|
|
235
|
+
## 📊 使用示例
|
|
119
236
|
|
|
120
|
-
###
|
|
237
|
+
### 🔍 查询页面
|
|
121
238
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
- ✏️ **编辑待办** - 修改待办内容和状态
|
|
125
|
-
- ✅ **完成标记** - 一键标记完成/未完成
|
|
126
|
-
- 🔍 **搜索筛选** - 支持按标题、内容搜索,按状态筛选
|
|
127
|
-
- 📄 **分页显示** - 超过 8 条自动分页,支持自定义每页条数
|
|
128
|
-
- 📊 **统计信息** - 显示总数、已完成、未完成数量
|
|
129
|
-
- 📱 **移动端适配** - 响应式布局,完美支持手机访问
|
|
239
|
+
```
|
|
240
|
+
> x 精炼器
|
|
130
241
|
|
|
131
|
-
|
|
242
|
+
🔍 为你找到【3】个相似结果,请点击下方按钮查看详情:
|
|
132
243
|
|
|
133
|
-
|
|
244
|
+
1. [精炼器]
|
|
245
|
+
2. [蒸汽精炼器]
|
|
246
|
+
3. [岩浆精炼器]
|
|
134
247
|
|
|
135
|
-
|
|
248
|
+
(QQ 平台显示可点击按钮,点击即跳转 Wiki 页面;非 QQ 平台返回纯文本)
|
|
249
|
+
```
|
|
136
250
|
|
|
137
|
-
|
|
138
|
-
- **每周二 00:00** - 自动检查模块同步状态,更新完成标记
|
|
251
|
+
### 🔄 同步页面
|
|
139
252
|
|
|
140
|
-
|
|
253
|
+
```
|
|
254
|
+
> sync 精炼器
|
|
141
255
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
- 🔌 **服务化设计** - 核心功能封装为独立服务
|
|
145
|
-
- 🧩 **模块化** - 功能拆分为独立子插件
|
|
146
|
-
- 🔄 **自动重试** - 登录失败自动重试(最多 3 次)
|
|
147
|
-
- 🔐 **自动重连** - 登录过期自动重新登录
|
|
148
|
-
- 🛡️ **错误处理** - 完善的错误处理和日志记录
|
|
149
|
-
- ⏱️ **API 限流** - 模块同步时请求间隔 1 秒
|
|
150
|
-
- 🔄 **API 重试** - API 调用失败自动重试(最多 3 次)
|
|
151
|
-
- 📦 **数据库持久化** - TodoList 数据存储在数据库中
|
|
256
|
+
✅ 已尝试同步页面:精炼器,请前往控制台查看
|
|
257
|
+
```
|
|
152
258
|
|
|
153
|
-
|
|
259
|
+
### ✅ 标记待办完成
|
|
154
260
|
|
|
155
261
|
```
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
│ │ ├── wikiBotService.ts # Wiki 机器人服务
|
|
160
|
-
│ │ └── consoleLogProvider.ts # 日志控制台服务
|
|
161
|
-
│ ├── plugins/ # 插件层
|
|
162
|
-
│ │ ├── queryCommands.ts # 查询命令插件
|
|
163
|
-
│ │ ├── syncCommands.ts # 同步命令插件
|
|
164
|
-
│ │ ├── updateCommands.ts # 更新命令插件
|
|
165
|
-
│ │ ├── todoList.ts # TodoList 插件
|
|
166
|
-
│ │ ├── databaseExtension.ts # 数据库扩展
|
|
167
|
-
│ │ └── routeRedirect.ts # 路由重定向
|
|
168
|
-
│ ├── sync/ # 同步逻辑
|
|
169
|
-
│ │ ├── pageSync.ts # 页面同步
|
|
170
|
-
│ │ ├── moduleSync.ts # 模块同步
|
|
171
|
-
│ │ └── imgSync.ts # 图片同步
|
|
172
|
-
│ ├── utils/ # 工具函数
|
|
173
|
-
│ │ └── tools.ts # 通用工具
|
|
174
|
-
│ ├── client/ # 前端
|
|
175
|
-
│ │ ├── page.vue # 日志页面
|
|
176
|
-
│ │ ├── onitodolist/ # TodoList 页面
|
|
177
|
-
│ │ │ └── todolist.vue # TodoList 主组件
|
|
178
|
-
│ │ └── index.ts # 入口
|
|
179
|
-
│ └── index.ts # 主入口
|
|
180
|
-
├── package.json
|
|
181
|
-
└── tsconfig.json
|
|
262
|
+
> todo.complete 5
|
|
263
|
+
|
|
264
|
+
✅ 已标记完成,请访问 https://klei.vip/onitodos 查看
|
|
182
265
|
```
|
|
183
266
|
|
|
184
|
-
##
|
|
267
|
+
## 🎨 控制台界面
|
|
185
268
|
|
|
186
|
-
|
|
269
|
+
插件在 Koishi 控制台提供以下管理页面:
|
|
187
270
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
- `createdBy` = 修订用户
|
|
194
|
-
- `createdAt` / `updatedAt` = 修订时间
|
|
195
|
-
- `completed` = false(默认未完成)
|
|
271
|
+
| 页面 | 功能 |
|
|
272
|
+
| ------------------------------------ | ---------------------------------------------------- |
|
|
273
|
+
| **日志控制台** (`page.vue`) | 按级别筛选日志,搜索内容,自动滚动,快速跳转 |
|
|
274
|
+
| **TodoList 管理** (`onitodolist/`) | 萌系 UI 设计,新增/编辑/标记完成,搜索筛选,分页显示 |
|
|
275
|
+
| **火箭计算器** (`Rocketcalculator/`) | ONI 火箭设计计算器 |
|
|
196
276
|
|
|
197
|
-
|
|
277
|
+
## 🔒 安全与权限
|
|
198
278
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
- 对比时间:
|
|
204
|
-
- 如果 bwikia 时间 ≥ wiki.gg 时间 → 标记为已完成
|
|
205
|
-
- 如果 bwikia 时间 < wiki.gg 时间 → 标记为未完成
|
|
279
|
+
- 所有 Wiki 编辑操作(同步、创建重定向)需权限 **2**
|
|
280
|
+
- 删除页面缓存需权限 **4**
|
|
281
|
+
- 登录凭证(用户名/密码)仅保存在 Koishi 配置中,不会写入日志
|
|
282
|
+
- WikiBotService 通过 **Proxy** 模式透明处理登录过期,自动重新登录后继续执行原请求
|
|
206
283
|
|
|
207
|
-
##
|
|
284
|
+
## 🐛 故障排查
|
|
208
285
|
|
|
209
|
-
|
|
210
|
-
# 创建 KOISHI 项目
|
|
211
|
-
yarn create koishi
|
|
286
|
+
### "❌ 本地缓存为空"
|
|
212
287
|
|
|
213
|
-
|
|
214
|
-
git clone https://github.com/Charles-LF/oni-sync-bot.git
|
|
288
|
+
请管理员执行 `update` 命令从 wiki.gg 获取页面列表。
|
|
215
289
|
|
|
216
|
-
|
|
217
|
-
yarn install
|
|
290
|
+
### "❌ Wiki 机器人未就绪"
|
|
218
291
|
|
|
219
|
-
|
|
220
|
-
yarn build
|
|
292
|
+
检查配置中的账号密码是否正确;可执行 `relogin` 手动重新登录。
|
|
221
293
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
294
|
+
### "❌ 未找到ID为【...】的页面"
|
|
295
|
+
|
|
296
|
+
页面ID不在本地缓存中,可能是最近新增的页面。执行 `update` 更新缓存后再试。
|
|
297
|
+
|
|
298
|
+
### QQ 机器人只显示纯文本
|
|
299
|
+
|
|
300
|
+
QQ 平台的 Markdown 与按钮效果需要 `session.platform === "qq"` 检测生效。请确认适配器正确上报平台信息。
|
|
225
301
|
|
|
226
|
-
## License
|
|
302
|
+
## 📜 License
|
|
227
303
|
|
|
228
304
|
MIT License
|
|
229
305
|
|
|
230
|
-
## 贡献
|
|
306
|
+
## 🤝 贡献
|
|
231
307
|
|
|
232
308
|
欢迎提交 Issue 和 Pull Request!
|
|
233
309
|
|
|
234
|
-
## 支持
|
|
310
|
+
## 📧 支持
|
|
235
311
|
|
|
236
|
-
如有问题,请在 GitHub 上提交 Issue
|
|
312
|
+
如有问题,请在 GitHub 上提交 Issue,或访问 <https://klei.vip>。
|