koishi-plugin-cfmrmod 1.0.7 → 1.0.9
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/dist/cfmr/index.js +32 -5
- package/dist/mcmod/index.js +12 -9
- package/dist/notify.js +47 -4
- package/package.json +7 -4
package/dist/cfmr/index.js
CHANGED
|
@@ -1893,6 +1893,28 @@ async function fetchCurseForgeDetail(id, apiKey, timeout, cfUrl = null) {
|
|
|
1893
1893
|
}
|
|
1894
1894
|
// 搜索入口 (MR)
|
|
1895
1895
|
async function searchModrinth(query, type, timeout) {
|
|
1896
|
+
// 先尝试直接通过ID/slug获取项目详情
|
|
1897
|
+
try {
|
|
1898
|
+
const project = await fetchJson(`${MR_BASE}/project/${encodeURIComponent(query)}`, {}, timeout);
|
|
1899
|
+
if (project && project.slug) {
|
|
1900
|
+
// 成功获取到项目,返回单个结果
|
|
1901
|
+
return [{
|
|
1902
|
+
platform: 'Modrinth',
|
|
1903
|
+
id: project.slug,
|
|
1904
|
+
name: project.title,
|
|
1905
|
+
author: project.author || 'Unknown',
|
|
1906
|
+
summary: project.description,
|
|
1907
|
+
type,
|
|
1908
|
+
icon: project.icon_url,
|
|
1909
|
+
downloads: project.downloads || 0,
|
|
1910
|
+
updated: new Date(project.updated || project.published).toLocaleDateString()
|
|
1911
|
+
}];
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
catch (e) {
|
|
1915
|
+
// ID/slug获取失败,继续使用搜索API
|
|
1916
|
+
}
|
|
1917
|
+
// 使用搜索API
|
|
1896
1918
|
const facet = MR_FACET_MAP[type];
|
|
1897
1919
|
const url = `${MR_BASE}/search?query=${encodeURIComponent(query)}&facets=[["${facet}"]]&limit=20`;
|
|
1898
1920
|
const json = await fetchJson(url, {}, timeout);
|
|
@@ -2029,8 +2051,10 @@ function apply(ctx, config) {
|
|
|
2029
2051
|
'\n请输入序号查看详情 (p/n 翻页)';
|
|
2030
2052
|
};
|
|
2031
2053
|
const handleSearch = async (session, platform, type, keyword) => {
|
|
2032
|
-
if (!keyword)
|
|
2033
|
-
|
|
2054
|
+
if (!keyword) {
|
|
2055
|
+
await session.send('请输入关键词');
|
|
2056
|
+
return;
|
|
2057
|
+
}
|
|
2034
2058
|
let results = [];
|
|
2035
2059
|
try {
|
|
2036
2060
|
if (platform === 'mr')
|
|
@@ -2039,10 +2063,13 @@ function apply(ctx, config) {
|
|
|
2039
2063
|
results = await searchCurseForge(keyword, type, config.curseforgeApiKey, config.requestTimeout, config.curseforgeGameId);
|
|
2040
2064
|
}
|
|
2041
2065
|
catch (e) {
|
|
2042
|
-
|
|
2066
|
+
await session.send(`搜索出错: ${e.message}`);
|
|
2067
|
+
return;
|
|
2068
|
+
}
|
|
2069
|
+
if (!results.length) {
|
|
2070
|
+
await session.send('未找到结果');
|
|
2071
|
+
return;
|
|
2043
2072
|
}
|
|
2044
|
-
if (!results.length)
|
|
2045
|
-
return session.send('未找到结果');
|
|
2046
2073
|
if (results.length === 1) {
|
|
2047
2074
|
const item = results[0];
|
|
2048
2075
|
try {
|
package/dist/mcmod/index.js
CHANGED
|
@@ -2653,7 +2653,7 @@ function apply(ctx, config) {
|
|
|
2653
2653
|
const sentMessageIds = await session.send(listText);
|
|
2654
2654
|
searchStates.set(session.cid, {
|
|
2655
2655
|
results,
|
|
2656
|
-
|
|
2656
|
+
pageIndex: 0,
|
|
2657
2657
|
type: 'mod',
|
|
2658
2658
|
messageIds: Array.isArray(sentMessageIds) ? sentMessageIds : [sentMessageIds],
|
|
2659
2659
|
timer: setTimeout(() => {
|
|
@@ -2686,6 +2686,7 @@ function apply(ctx, config) {
|
|
|
2686
2686
|
if (input === 'p' || input === 'n') {
|
|
2687
2687
|
// 加入队列处理翻页,防止并发
|
|
2688
2688
|
enqueue(session, 'page-turn', async () => {
|
|
2689
|
+
var _a, _b;
|
|
2689
2690
|
// 重新获取状态,防止排队期间状态丢失
|
|
2690
2691
|
const currentState = searchStates.get(session.cid);
|
|
2691
2692
|
if (!currentState)
|
|
@@ -2693,10 +2694,11 @@ function apply(ctx, config) {
|
|
|
2693
2694
|
clearTimeout(currentState.timer);
|
|
2694
2695
|
currentState.timer = setTimeout(() => searchStates.delete(session.cid), TIMEOUT_MS);
|
|
2695
2696
|
const total = Math.ceil(currentState.results.length / PAGE_SIZE);
|
|
2696
|
-
|
|
2697
|
-
|
|
2697
|
+
const currentPage = Number((_b = (_a = currentState.pageIndex) !== null && _a !== void 0 ? _a : currentState.page) !== null && _b !== void 0 ? _b : 0) || 0;
|
|
2698
|
+
let newIndex = currentPage;
|
|
2699
|
+
if (input === 'n' && currentPage < total - 1)
|
|
2698
2700
|
newIndex++;
|
|
2699
|
-
else if (input === 'p' &&
|
|
2701
|
+
else if (input === 'p' && currentPage > 0)
|
|
2700
2702
|
newIndex--;
|
|
2701
2703
|
else {
|
|
2702
2704
|
await session.send('没有更多页面了。');
|
|
@@ -2705,8 +2707,8 @@ function apply(ctx, config) {
|
|
|
2705
2707
|
// 撤回旧列表(可选,为了整洁)
|
|
2706
2708
|
await tryWithdraw(session, currentState.messageIds);
|
|
2707
2709
|
currentState.pageIndex = newIndex;
|
|
2708
|
-
const newMsgIds = await session.send(formatListPage(currentState.results,
|
|
2709
|
-
currentState.messageIds = newMsgIds;
|
|
2710
|
+
const newMsgIds = await session.send(formatListPage(currentState.results, newIndex, currentState.type));
|
|
2711
|
+
currentState.messageIds = Array.isArray(newMsgIds) ? newMsgIds : [newMsgIds];
|
|
2710
2712
|
});
|
|
2711
2713
|
return;
|
|
2712
2714
|
}
|
|
@@ -2715,12 +2717,13 @@ function apply(ctx, config) {
|
|
|
2715
2717
|
if (!isNaN(choice) && choice >= 1) {
|
|
2716
2718
|
// 加入队列处理生成卡片
|
|
2717
2719
|
enqueue(session, 'select-item', async () => {
|
|
2718
|
-
var _a;
|
|
2720
|
+
var _a, _b, _c;
|
|
2719
2721
|
const currentState = searchStates.get(session.cid);
|
|
2720
2722
|
if (!currentState)
|
|
2721
2723
|
return; // 状态可能已过期
|
|
2722
2724
|
const idx = choice - 1;
|
|
2723
|
-
const
|
|
2725
|
+
const currentPage = Number((_b = (_a = currentState.pageIndex) !== null && _a !== void 0 ? _a : currentState.page) !== null && _b !== void 0 ? _b : 0) || 0;
|
|
2726
|
+
const pageStart = currentPage * PAGE_SIZE;
|
|
2724
2727
|
const pageEnd = Math.min(pageStart + PAGE_SIZE, currentState.results.length);
|
|
2725
2728
|
if (choice < pageStart + 1 || choice > pageEnd) {
|
|
2726
2729
|
// 如果序号不在当前页,忽略或提示
|
|
@@ -2738,7 +2741,7 @@ function apply(ctx, config) {
|
|
|
2738
2741
|
if (currentState.type === 'author')
|
|
2739
2742
|
img = await drawAuthorCard(item.link);
|
|
2740
2743
|
else if (currentState.type === 'user') {
|
|
2741
|
-
const uid = ((
|
|
2744
|
+
const uid = ((_c = item.link.match(/\/(\d+)(?:\.html|\/)?$/)) === null || _c === void 0 ? void 0 : _c[1]) || '0';
|
|
2742
2745
|
img = await drawCenterCardImpl(uid, logger);
|
|
2743
2746
|
}
|
|
2744
2747
|
else if (currentState.type === 'mod' || currentState.type === 'pack')
|
package/dist/notify.js
CHANGED
|
@@ -513,10 +513,53 @@ function apply(ctx, config, options) {
|
|
|
513
513
|
await updateState(sub.channelId, sub.platform, sub.projectId, latest.version || '');
|
|
514
514
|
return { sent: true, updated: true };
|
|
515
515
|
};
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
516
|
+
// 自动检查更新定时器
|
|
517
|
+
const startAutoCheck = async () => {
|
|
518
|
+
// 首先加载配置文件
|
|
519
|
+
await loadConfigFromFile();
|
|
520
|
+
// 计算轮询间隔:取所有订阅中最小的 interval,最小不低于 1 分钟
|
|
521
|
+
const getMinInterval = () => {
|
|
522
|
+
const subs = getConfigSubs();
|
|
523
|
+
if (!subs.length)
|
|
524
|
+
return Number(config.interval) || 30 * 60 * 1000;
|
|
525
|
+
const intervals = subs.map(s => s.interval);
|
|
526
|
+
return Math.min(...intervals);
|
|
527
|
+
};
|
|
528
|
+
// 使用较短的基准轮询间隔(1分钟),让 checkOnce 内部判断每个订阅是否到期
|
|
529
|
+
// 这样可以支持每个订阅的独立 interval
|
|
530
|
+
const baseTick = 60 * 1000; // 1 分钟基准轮询
|
|
531
|
+
// 自动轮询函数:每次都检查 config.enabled
|
|
532
|
+
const autoCheckLoop = async () => {
|
|
533
|
+
try {
|
|
534
|
+
await loadConfigFromFile();
|
|
535
|
+
if (config.enabled) {
|
|
536
|
+
const subs = getConfigSubs();
|
|
537
|
+
if (subs.length > 0) {
|
|
538
|
+
logger.debug(`自动检查更新开始,共 ${subs.length} 个订阅...`);
|
|
539
|
+
const stats = await checkOnce();
|
|
540
|
+
if (stats) {
|
|
541
|
+
logger.debug(`自动检查完成: checked=${stats.checked}, updated=${stats.updated}, skipped=${stats.skipped}, failed=${stats.failed}`);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
catch (e) {
|
|
547
|
+
logger.warn(`自动检查更新失败: ${e.message}`);
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
// 启动时延迟执行一次初始检查(给 bot 连接时间)
|
|
551
|
+
ctx.setTimeout(async () => {
|
|
552
|
+
await autoCheckLoop();
|
|
553
|
+
}, 10 * 1000);
|
|
554
|
+
// 设置定时器,每分钟轮询一次,由 checkOnce 内部判断哪些订阅到期
|
|
555
|
+
ctx.setInterval(autoCheckLoop, baseTick);
|
|
556
|
+
const minInterval = getMinInterval();
|
|
557
|
+
logger.info(`自动更新检查已启动,基准轮询间隔: 1 分钟,最短订阅间隔: ${Math.round(minInterval / 60000)} 分钟`);
|
|
558
|
+
};
|
|
559
|
+
// 使用 ctx.on('ready') 确保在 Koishi 完全就绪后启动
|
|
560
|
+
ctx.on('ready', () => {
|
|
561
|
+
startAutoCheck().catch(e => logger.warn(`启动自动检查失败: ${e.message}`));
|
|
562
|
+
});
|
|
520
563
|
ctx.command('notify.add <platform> <projectId>', '添加更新订阅')
|
|
521
564
|
.action(async ({ session }, platform, projectId) => {
|
|
522
565
|
await loadConfigFromFile();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-cfmrmod",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "Koishi 插件:搜索 CurseForge/Modrinth/MCMod 并渲染图片卡片",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"pub": "npm run build && npm publish --access public"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"koishi": "^
|
|
43
|
-
"
|
|
42
|
+
"@ltxhhz/koishi-plugin-skia-canvas": "^0.0.10",
|
|
43
|
+
"koishi": "^4.0.0"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"cheerio": "^1.0.0-rc.12",
|
|
@@ -55,7 +55,10 @@
|
|
|
55
55
|
"zh": "从 CurseForge/Modrinth/MCMod 搜索模组/整合包/光影等内容,并生成图片卡片。"
|
|
56
56
|
},
|
|
57
57
|
"service": {
|
|
58
|
-
"required": [
|
|
58
|
+
"required": [
|
|
59
|
+
"skia",
|
|
60
|
+
"database"
|
|
61
|
+
]
|
|
59
62
|
}
|
|
60
63
|
}
|
|
61
64
|
}
|