koishi-plugin-oni-sync-bot 0.0.2 → 0.0.4
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/index.js +1 -1
- package/dist/style.css +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +184 -166
- package/package.json +1 -1
- package/lib/config/index.d.ts +0 -15
- package/lib/sync/imgSync.d.ts +0 -30
- package/lib/sync/moduleSync.d.ts +0 -21
- package/lib/sync/pageSync.d.ts +0 -30
- package/lib/utils/login.d.ts +0 -8
- package/lib/utils/tools.d.ts +0 -18
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{defineComponent as p,resolveComponent as
|
|
1
|
+
import{defineComponent as d,ref as p,watch as i,onMounted as g,resolveComponent as v,openBlock as m,createBlock as y,withCtx as h,createElementVNode as u,createElementBlock as _,Fragment as k,renderList as x,toDisplayString as B}from"vue";import{store as C,Time as T}from"@koishijs/client";const b="yyyy-MM-dd hh:mm:ss",M=d({__name:"page",setup(n){const t=p(),o=p([]);function s(e){const r=T.template(b,new Date(e.timestamp)),l=e.type.toUpperCase(),a=e.content.replace(/\u001b\[[0-9;]*m/g,"");return`[${r}] [${l}] ${a}`}i(()=>C.logs,e=>{if(!e)return;const r=e.filter(l=>l.name==="oni-sync").slice(-100).map(s);o.value=r},{deep:true,immediate:true});const c=()=>{t.value&&(t.value.scrollTop=t.value.scrollHeight)};return i(()=>o.value.length,()=>{setTimeout(c,0)}),g(()=>{c()}),(e,r)=>{const l=v("k-layout");return m(),y(l,null,{default:h(()=>[u("div",{class:"log-container",ref_key:"scrollRef",ref:t},[(m(true),_(k,null,x(o.value,(a,f)=>(m(),_("div",{key:f,class:"log-line"},[u("pre",null,B(a),1)]))),128))],512)]),_:1})}}}),R=(n,t)=>{const o=n.__vccOpts||n;for(const[s,c]of t)o[s]=c;return o},$=R(M,[["__scopeId","data-v-46bc7bec"]]),E=n=>{n.page({name:"同步机器人",path:"/onilogs",component:$})};export{E as default};
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
.log-container[data-v-46bc7bec]{width:100%;height:100%;overflow-y:auto;padding:12px;font-family:monospace;background:#1e1e1e;color:#d4d4d4}.log-line[data-v-46bc7bec]{line-height:1.5;font-size:13px}pre[data-v-46bc7bec]{margin:0;font-family:inherit;white-space:pre-wrap;word-break:break-all}.break-all{word-break:break-all}
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -36,11 +36,54 @@ __export(src_exports, {
|
|
|
36
36
|
name: () => name
|
|
37
37
|
});
|
|
38
38
|
module.exports = __toCommonJS(src_exports);
|
|
39
|
-
var
|
|
39
|
+
var import_koishi5 = require("koishi");
|
|
40
40
|
var import_path = require("path");
|
|
41
41
|
|
|
42
42
|
// src/utils/login.ts
|
|
43
43
|
var import_mwn = require("mwn");
|
|
44
|
+
|
|
45
|
+
// src/utils/tools.ts
|
|
46
|
+
var import_koishi = require("koishi");
|
|
47
|
+
var import_pinyin_pro = require("pinyin-pro");
|
|
48
|
+
var CROSS_SITE_LINK_REGEX = /\[\[(en|ru|pt-br):[^\]]*\]\]/g;
|
|
49
|
+
function clean_page_text(text) {
|
|
50
|
+
const textWithoutCrossLink = text.replace(CROSS_SITE_LINK_REGEX, "");
|
|
51
|
+
return textWithoutCrossLink;
|
|
52
|
+
}
|
|
53
|
+
__name(clean_page_text, "clean_page_text");
|
|
54
|
+
async function getAndProcessPageContent(site, pageTitle) {
|
|
55
|
+
try {
|
|
56
|
+
const res = await site.read(pageTitle);
|
|
57
|
+
const rawText = res.revisions[0]?.content || "";
|
|
58
|
+
const processedText = clean_page_text(rawText);
|
|
59
|
+
return processedText.trimEnd();
|
|
60
|
+
} catch (err) {
|
|
61
|
+
throw new Error(`[${pageTitle}] 内容获取失败: ${err}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
__name(getAndProcessPageContent, "getAndProcessPageContent");
|
|
65
|
+
function generatePinyinInfo(text) {
|
|
66
|
+
if (!text) return { pinyin_full: "", pinyin_first: "" };
|
|
67
|
+
const cleanText = text.replace(/[^\u4e00-\u9fa5a-zA-Z0-9]/g, "");
|
|
68
|
+
if (!cleanText) return { pinyin_full: "", pinyin_first: "" };
|
|
69
|
+
const fullPinyin = (0, import_pinyin_pro.pinyin)(cleanText, {
|
|
70
|
+
toneType: "none",
|
|
71
|
+
type: "string",
|
|
72
|
+
separator: ""
|
|
73
|
+
}).toLowerCase();
|
|
74
|
+
const firstLetter = (0, import_pinyin_pro.pinyin)(cleanText, {
|
|
75
|
+
pattern: "initial",
|
|
76
|
+
separator: ""
|
|
77
|
+
}).toLowerCase();
|
|
78
|
+
return {
|
|
79
|
+
pinyin_full: fullPinyin,
|
|
80
|
+
pinyin_first: firstLetter
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
__name(generatePinyinInfo, "generatePinyinInfo");
|
|
84
|
+
var logger = new import_koishi.Logger("oni-sync");
|
|
85
|
+
|
|
86
|
+
// src/utils/login.ts
|
|
44
87
|
async function login(siteConfig) {
|
|
45
88
|
const bot = new import_mwn.Mwn({
|
|
46
89
|
apiUrl: siteConfig.api,
|
|
@@ -61,7 +104,7 @@ async function login(siteConfig) {
|
|
|
61
104
|
}
|
|
62
105
|
bot.setRequestOptions(customRequestOptions);
|
|
63
106
|
await bot.login();
|
|
64
|
-
|
|
107
|
+
logger.info(`✅ 成功登录 ${siteConfig.name}`);
|
|
65
108
|
return bot;
|
|
66
109
|
}
|
|
67
110
|
__name(login, "login");
|
|
@@ -89,56 +132,11 @@ function getSitesConfig(config) {
|
|
|
89
132
|
}
|
|
90
133
|
__name(getSitesConfig, "getSitesConfig");
|
|
91
134
|
|
|
92
|
-
// src/utils/tools.ts
|
|
93
|
-
var import_pinyin_pro = require("pinyin-pro");
|
|
94
|
-
var CROSS_SITE_LINK_REGEX = /\[\[(en|ru|pt-br):[^\]]*\]\]/g;
|
|
95
|
-
var DEV_TEXT_REGEX = /Dev:/g;
|
|
96
|
-
var MODULE_NAMESPACE_PREFIX = "Module:Dev/";
|
|
97
|
-
function clean_page_text(text) {
|
|
98
|
-
const textWithoutCrossLink = text.replace(CROSS_SITE_LINK_REGEX, "");
|
|
99
|
-
const textWithReplacedDev = textWithoutCrossLink.replace(
|
|
100
|
-
DEV_TEXT_REGEX,
|
|
101
|
-
MODULE_NAMESPACE_PREFIX
|
|
102
|
-
);
|
|
103
|
-
return textWithReplacedDev;
|
|
104
|
-
}
|
|
105
|
-
__name(clean_page_text, "clean_page_text");
|
|
106
|
-
async function getAndProcessPageContent(site, pageTitle) {
|
|
107
|
-
try {
|
|
108
|
-
const res = await site.read(pageTitle);
|
|
109
|
-
const rawText = res.revisions[0]?.content || "";
|
|
110
|
-
const processedText = clean_page_text(rawText);
|
|
111
|
-
return processedText.trimEnd();
|
|
112
|
-
} catch (err) {
|
|
113
|
-
throw new Error(`[${pageTitle}] 内容获取失败: ${err}`);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
__name(getAndProcessPageContent, "getAndProcessPageContent");
|
|
117
|
-
function generatePinyinInfo(text) {
|
|
118
|
-
if (!text) return { pinyin_full: "", pinyin_first: "" };
|
|
119
|
-
const cleanText = text.replace(/[^\u4e00-\u9fa5a-zA-Z0-9]/g, "");
|
|
120
|
-
if (!cleanText) return { pinyin_full: "", pinyin_first: "" };
|
|
121
|
-
const fullPinyin = (0, import_pinyin_pro.pinyin)(cleanText, {
|
|
122
|
-
toneType: "none",
|
|
123
|
-
type: "string",
|
|
124
|
-
separator: ""
|
|
125
|
-
}).toLowerCase();
|
|
126
|
-
const firstLetter = (0, import_pinyin_pro.pinyin)(cleanText, {
|
|
127
|
-
pattern: "initial",
|
|
128
|
-
separator: ""
|
|
129
|
-
}).toLowerCase();
|
|
130
|
-
return {
|
|
131
|
-
pinyin_full: fullPinyin,
|
|
132
|
-
pinyin_first: firstLetter
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
__name(generatePinyinInfo, "generatePinyinInfo");
|
|
136
|
-
|
|
137
135
|
// src/sync/pageSync.ts
|
|
138
|
-
var
|
|
136
|
+
var import_koishi3 = require("koishi");
|
|
139
137
|
|
|
140
138
|
// src/sync/imgSync.ts
|
|
141
|
-
var
|
|
139
|
+
var import_koishi2 = require("koishi");
|
|
142
140
|
var import_node_fetch = __toESM(require("node-fetch"));
|
|
143
141
|
var import_form_data = __toESM(require("form-data"));
|
|
144
142
|
var CONFIG = {
|
|
@@ -168,29 +166,29 @@ async function getImageInfo(site, fileName) {
|
|
|
168
166
|
size: imageInfo.size
|
|
169
167
|
};
|
|
170
168
|
} catch (error) {
|
|
171
|
-
|
|
169
|
+
logger.error(`[GetImageInfo] 获取 ${fileName} 信息失败:`, error);
|
|
172
170
|
return null;
|
|
173
171
|
}
|
|
174
172
|
}
|
|
175
173
|
__name(getImageInfo, "getImageInfo");
|
|
176
174
|
async function syncSingleImage(sourceBot, targetBot, fileName, config) {
|
|
177
175
|
if (CONFIG.IGNORED_IMAGES.includes(fileName)) {
|
|
178
|
-
|
|
176
|
+
logger.info(`[SyncImg] 🚫 图片 ${fileName} 在忽略列表,跳过`);
|
|
179
177
|
return { success: true, reason: "ignored" };
|
|
180
178
|
}
|
|
181
179
|
try {
|
|
182
|
-
|
|
180
|
+
logger.info(`[SyncImg] 🚀 开始处理: ${fileName}`);
|
|
183
181
|
const sourceImageInfo = await getImageInfo(sourceBot, fileName);
|
|
184
182
|
if (!sourceImageInfo) {
|
|
185
|
-
|
|
183
|
+
logger.info(`[SyncImg] ❌ 源站未找到图片: ${fileName}`);
|
|
186
184
|
return { success: false, reason: "source_missing" };
|
|
187
185
|
}
|
|
188
186
|
const targetImageInfo = await getImageInfo(targetBot, fileName);
|
|
189
187
|
if (targetImageInfo && targetImageInfo.sha1 === sourceImageInfo.sha1) {
|
|
190
|
-
|
|
188
|
+
logger.info(`[SyncImg] 🟡 图片 ${fileName} 已存在且内容一致,跳过`);
|
|
191
189
|
return { success: true, reason: "no_change" };
|
|
192
190
|
}
|
|
193
|
-
|
|
191
|
+
logger.info(`[SyncImg] 📥 下载图片: ${sourceImageInfo.url}`);
|
|
194
192
|
const imageResponse = await (0, import_node_fetch.default)(sourceImageInfo.url, {
|
|
195
193
|
headers: {
|
|
196
194
|
"User-Agent": "OniSyncBot/1.0 (https://klei.vip; Charles@klei.vip)"
|
|
@@ -200,7 +198,7 @@ async function syncSingleImage(sourceBot, targetBot, fileName, config) {
|
|
|
200
198
|
throw new Error(`图片下载失败,HTTP状态码: ${imageResponse.status}`);
|
|
201
199
|
}
|
|
202
200
|
const imageBuffer = Buffer.from(await imageResponse.arrayBuffer());
|
|
203
|
-
|
|
201
|
+
logger.info(
|
|
204
202
|
`[SyncImg] 📤 上传图片: ${fileName} (大小: ${(imageBuffer.length / 1024).toFixed(1)} KB)`
|
|
205
203
|
);
|
|
206
204
|
const token = await targetBot.getCsrfToken();
|
|
@@ -227,7 +225,7 @@ async function syncSingleImage(sourceBot, targetBot, fileName, config) {
|
|
|
227
225
|
});
|
|
228
226
|
const responseData = rawResponse.data;
|
|
229
227
|
if (responseData.upload && responseData.upload.result === "Success") {
|
|
230
|
-
|
|
228
|
+
logger.info(`[SyncImg] ✅ 图片 ${fileName} 同步成功`);
|
|
231
229
|
return { success: true, reason: "synced" };
|
|
232
230
|
} else if (responseData.error) {
|
|
233
231
|
throw new Error(`${responseData.error.code}: ${responseData.error.info}`);
|
|
@@ -236,13 +234,13 @@ async function syncSingleImage(sourceBot, targetBot, fileName, config) {
|
|
|
236
234
|
}
|
|
237
235
|
} catch (error) {
|
|
238
236
|
const errMsg = error.message || String(error);
|
|
239
|
-
|
|
237
|
+
logger.error(`[SyncImg] ❌ 图片 ${fileName} 同步失败:`, errMsg);
|
|
240
238
|
return { success: false, reason: errMsg };
|
|
241
239
|
}
|
|
242
240
|
}
|
|
243
241
|
__name(syncSingleImage, "syncSingleImage");
|
|
244
242
|
async function getAllImages(site) {
|
|
245
|
-
|
|
243
|
+
logger.info(`[SyncAllImg] 📥 开始获取WikiGG所有图片`);
|
|
246
244
|
const allImages = [];
|
|
247
245
|
const queryGen = site.continuedQueryGen({
|
|
248
246
|
action: "query",
|
|
@@ -255,9 +253,9 @@ async function getAllImages(site) {
|
|
|
255
253
|
const imageItems = res.query?.allimages || [];
|
|
256
254
|
const imageTitles = imageItems.map((img) => img.title);
|
|
257
255
|
allImages.push(...imageTitles);
|
|
258
|
-
|
|
256
|
+
logger.info(`[SyncAllImg] 📄 已获取 ${allImages.length} 个图片`);
|
|
259
257
|
}
|
|
260
|
-
|
|
258
|
+
logger.info(`[SyncAllImg] 📊 总计获取到 ${allImages.length} 个图片`);
|
|
261
259
|
return allImages;
|
|
262
260
|
}
|
|
263
261
|
__name(getAllImages, "getAllImages");
|
|
@@ -265,20 +263,20 @@ async function syncAllImages(sourceBot, targetBot, config) {
|
|
|
265
263
|
try {
|
|
266
264
|
const imageList = await getAllImages(sourceBot);
|
|
267
265
|
if (imageList.length === 0) {
|
|
268
|
-
|
|
266
|
+
logger.info(`[SyncAllImg] 📭 源站无图片可同步,结束`);
|
|
269
267
|
return;
|
|
270
268
|
}
|
|
271
269
|
let successCount = 0;
|
|
272
270
|
let failCount = 0;
|
|
273
271
|
let skipCount = 0;
|
|
274
272
|
const failedImages = [];
|
|
275
|
-
|
|
273
|
+
logger.info(
|
|
276
274
|
`[SyncAllImg] 🚦 开始批量同步,总计 ${imageList.length} 个图片`
|
|
277
275
|
);
|
|
278
276
|
for (let i = 0; i < imageList.length; i++) {
|
|
279
277
|
const fileName = imageList[i];
|
|
280
278
|
const progress = (i + 1) / imageList.length * 100;
|
|
281
|
-
|
|
279
|
+
logger.info(
|
|
282
280
|
`
|
|
283
281
|
[SyncAllImg] 📈 进度 ${i + 1}/${imageList.length} (${progress.toFixed(1)}%)`
|
|
284
282
|
);
|
|
@@ -291,23 +289,23 @@ async function syncAllImages(sourceBot, targetBot, config) {
|
|
|
291
289
|
if (!result.success) {
|
|
292
290
|
failCount++;
|
|
293
291
|
failedImages.push(fileName);
|
|
294
|
-
await (0,
|
|
292
|
+
await (0, import_koishi2.sleep)(CONFIG.SYNC_INTERVAL_FAILED);
|
|
295
293
|
} else {
|
|
296
294
|
successCount++;
|
|
297
295
|
if (result.reason === "ignored" || result.reason === "no_change") {
|
|
298
296
|
skipCount++;
|
|
299
297
|
}
|
|
300
|
-
await (0,
|
|
298
|
+
await (0, import_koishi2.sleep)(CONFIG.SYNC_INTERVAL_SUCCESS);
|
|
301
299
|
}
|
|
302
300
|
}
|
|
303
301
|
if (failedImages.length > 0) {
|
|
304
|
-
|
|
302
|
+
logger.info(
|
|
305
303
|
`
|
|
306
304
|
[SyncAllImg] 🔄 开始重试 ${failedImages.length} 个失败图片`
|
|
307
305
|
);
|
|
308
306
|
const stillFailed = [];
|
|
309
307
|
for (const fileName of failedImages) {
|
|
310
|
-
|
|
308
|
+
logger.info(`
|
|
311
309
|
[SyncAllImg] 🔁 重试: ${fileName}`);
|
|
312
310
|
const result = await syncSingleImage(
|
|
313
311
|
sourceBot,
|
|
@@ -318,31 +316,31 @@ async function syncAllImages(sourceBot, targetBot, config) {
|
|
|
318
316
|
if (result.success) {
|
|
319
317
|
successCount++;
|
|
320
318
|
failCount--;
|
|
321
|
-
|
|
319
|
+
logger.info(`[SyncAllImg] ✅ 重试成功: ${fileName}`);
|
|
322
320
|
} else {
|
|
323
321
|
stillFailed.push(fileName);
|
|
324
|
-
|
|
322
|
+
logger.info(`[SyncAllImg] ❌ 重试失败: ${fileName}`);
|
|
325
323
|
}
|
|
326
|
-
await (0,
|
|
324
|
+
await (0, import_koishi2.sleep)(CONFIG.SYNC_INTERVAL_SUCCESS);
|
|
327
325
|
}
|
|
328
326
|
if (stillFailed.length > 0) {
|
|
329
|
-
|
|
327
|
+
logger.info(`
|
|
330
328
|
[SyncAllImg] ❌ 最终失败列表(需手动处理):`);
|
|
331
329
|
stillFailed.forEach(
|
|
332
|
-
(title, idx) =>
|
|
330
|
+
(title, idx) => logger.info(` ${idx + 1}. ${title}`)
|
|
333
331
|
);
|
|
334
332
|
} else {
|
|
335
|
-
|
|
333
|
+
logger.info(`
|
|
336
334
|
[SyncAllImg] 🎉 所有失败图片重试成功!`);
|
|
337
335
|
}
|
|
338
336
|
}
|
|
339
|
-
|
|
337
|
+
logger.info(`
|
|
340
338
|
[SyncAllImg] 📊 同步完成!`);
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
339
|
+
logger.info(`├─ 总计:${imageList.length} 个图片`);
|
|
340
|
+
logger.info(`├─ 成功:${successCount} 个(含跳过 ${skipCount} 个)`);
|
|
341
|
+
logger.info(`└─ 失败:${failCount} 个`);
|
|
344
342
|
} catch (globalError) {
|
|
345
|
-
|
|
343
|
+
logger.error(`[SyncAllImg] 💥 同步流程异常终止:`, globalError);
|
|
346
344
|
throw globalError;
|
|
347
345
|
}
|
|
348
346
|
}
|
|
@@ -361,31 +359,31 @@ var CONFIG2 = {
|
|
|
361
359
|
};
|
|
362
360
|
async function syncSinglePage(oldSite, newSite, pageTitle, user) {
|
|
363
361
|
if (CONFIG2.IGNORED_PAGES.has(pageTitle)) {
|
|
364
|
-
|
|
362
|
+
logger.info(`[syncSinglePage] 🚫 页面 ${pageTitle} 在忽略列表中,跳过`);
|
|
365
363
|
return { success: true, reason: "ignored" };
|
|
366
364
|
}
|
|
367
365
|
try {
|
|
368
|
-
|
|
366
|
+
logger.info(`[syncSinglePage] 🚀 开始同步页面: ${pageTitle}`);
|
|
369
367
|
const [oldContent, newContent] = await Promise.all([
|
|
370
368
|
getAndProcessPageContent(oldSite, pageTitle),
|
|
371
369
|
getAndProcessPageContent(newSite, pageTitle)
|
|
372
370
|
]);
|
|
373
371
|
if (oldContent === newContent) {
|
|
374
|
-
|
|
372
|
+
logger.info(`[syncSinglePage] 🟡 页面 ${pageTitle} 内容未改变,跳过`);
|
|
375
373
|
return { success: true, reason: "no_change" };
|
|
376
374
|
}
|
|
377
375
|
await newSite.save(pageTitle, oldContent, `由:${user} 触发更改,此时同步`);
|
|
378
|
-
|
|
376
|
+
logger.info(`[syncSinglePage] ✅ 页面 ${pageTitle} 同步成功`);
|
|
379
377
|
return { success: true, reason: "synced" };
|
|
380
378
|
} catch (error) {
|
|
381
379
|
const errMsg = error instanceof Error ? error.message : String(error);
|
|
382
|
-
|
|
380
|
+
logger.error(`[syncSinglePage] ❌ 页面 ${pageTitle} 同步失败:`, errMsg);
|
|
383
381
|
return { success: false, reason: errMsg };
|
|
384
382
|
}
|
|
385
383
|
}
|
|
386
384
|
__name(syncSinglePage, "syncSinglePage");
|
|
387
385
|
async function getAllPages(site) {
|
|
388
|
-
|
|
386
|
+
logger.info(
|
|
389
387
|
`[SyncAllPages] 📥 开始获取原站点所有页面(命名空间${CONFIG2.NAMESPACE})`
|
|
390
388
|
);
|
|
391
389
|
const allPages = [];
|
|
@@ -399,9 +397,9 @@ async function getAllPages(site) {
|
|
|
399
397
|
for await (const res of queryGen) {
|
|
400
398
|
const pageTitles = res.query?.allpages?.map((page) => page.title) || [];
|
|
401
399
|
allPages.push(...pageTitles);
|
|
402
|
-
|
|
400
|
+
logger.info(`[SyncAllPages] 📄 已获取 ${allPages.length} 个页面`);
|
|
403
401
|
}
|
|
404
|
-
|
|
402
|
+
logger.info(`[SyncAllPages] 📊 原站点总计获取到 ${allPages.length} 个页面`);
|
|
405
403
|
return allPages;
|
|
406
404
|
}
|
|
407
405
|
__name(getAllPages, "getAllPages");
|
|
@@ -410,41 +408,41 @@ async function processPageWithStats(oldSite, newSite, pageTitle, user, stats, fa
|
|
|
410
408
|
if (!syncResult.success) {
|
|
411
409
|
stats.failCount++;
|
|
412
410
|
failedPages.push(pageTitle);
|
|
413
|
-
await (0,
|
|
411
|
+
await (0, import_koishi3.sleep)(CONFIG2.SYNC_INTERVAL_FAILED);
|
|
414
412
|
} else {
|
|
415
413
|
stats.successCount++;
|
|
416
414
|
if (syncResult.reason === "ignored" || syncResult.reason === "no_change") {
|
|
417
415
|
stats.skipCount++;
|
|
418
416
|
}
|
|
419
|
-
await (0,
|
|
417
|
+
await (0, import_koishi3.sleep)(CONFIG2.SYNC_INTERVAL_SUCCESS);
|
|
420
418
|
}
|
|
421
419
|
}
|
|
422
420
|
__name(processPageWithStats, "processPageWithStats");
|
|
423
421
|
function printProgress(current, total, pageTitle) {
|
|
424
422
|
const progress = (current / total * 100).toFixed(1);
|
|
425
423
|
const remaining = total - current;
|
|
426
|
-
|
|
424
|
+
logger.info(
|
|
427
425
|
`
|
|
428
426
|
[SyncAllPages] 📈 进度 [${current}/${total}] (${progress}%) - 处理 ${pageTitle} | 剩余 ${remaining} 个`
|
|
429
427
|
);
|
|
430
428
|
}
|
|
431
429
|
__name(printProgress, "printProgress");
|
|
432
430
|
function printFinalReport(total, successCount, failCount, skipCount, stillFailed) {
|
|
433
|
-
|
|
431
|
+
logger.info(`
|
|
434
432
|
[SyncAllPages] 📋 ===== 最终同步报告 =====`);
|
|
435
433
|
if (stillFailed.length > 0) {
|
|
436
|
-
|
|
434
|
+
logger.info(`❌ 以下页面经过重试仍然失败,请手动检查:`);
|
|
437
435
|
stillFailed.forEach((title, idx) => {
|
|
438
|
-
|
|
436
|
+
logger.info(` ${idx + 1}. ${title}`);
|
|
439
437
|
});
|
|
440
438
|
} else {
|
|
441
|
-
|
|
439
|
+
logger.info(`🎉 所有页面同步成功(含重试)!`);
|
|
442
440
|
}
|
|
443
|
-
|
|
441
|
+
logger.info(`
|
|
444
442
|
[SyncAllPages] 🎯 同步流程结束!`);
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
443
|
+
logger.info(`├─ 总计:${total} 个页面`);
|
|
444
|
+
logger.info(`├─ 成功:${successCount} 个(含跳过 ${skipCount} 个)`);
|
|
445
|
+
logger.info(`└─ 失败:${failCount} 个`);
|
|
448
446
|
}
|
|
449
447
|
__name(printFinalReport, "printFinalReport");
|
|
450
448
|
async function syncPages(oldSite, newSite) {
|
|
@@ -452,12 +450,12 @@ async function syncPages(oldSite, newSite) {
|
|
|
452
450
|
const oldPageList = await getAllPages(oldSite);
|
|
453
451
|
const total = oldPageList.length;
|
|
454
452
|
if (total === 0) {
|
|
455
|
-
|
|
453
|
+
logger.info(`[SyncAllPages] 📭 原站点无页面可同步,结束`);
|
|
456
454
|
return;
|
|
457
455
|
}
|
|
458
456
|
const stats = { successCount: 0, failCount: 0, skipCount: 0 };
|
|
459
457
|
const failedPages = [];
|
|
460
|
-
|
|
458
|
+
logger.info(`[SyncAllPages] 🚦 开始批量同步,总计 ${total} 个页面`);
|
|
461
459
|
for (let index = 0; index < total; index++) {
|
|
462
460
|
const pageTitle = oldPageList[index];
|
|
463
461
|
printProgress(index + 1, total, pageTitle);
|
|
@@ -472,12 +470,12 @@ async function syncPages(oldSite, newSite) {
|
|
|
472
470
|
}
|
|
473
471
|
let stillFailed = [];
|
|
474
472
|
if (failedPages.length > 0) {
|
|
475
|
-
|
|
473
|
+
logger.info(
|
|
476
474
|
`
|
|
477
475
|
[SyncAllPages] 🔄 ===== 开始重试 ${failedPages.length} 个失败页面 =====`
|
|
478
476
|
);
|
|
479
477
|
for (const pageTitle of failedPages) {
|
|
480
|
-
|
|
478
|
+
logger.info(`
|
|
481
479
|
[SyncAllPages] 🔁 重试中: ${pageTitle}`);
|
|
482
480
|
const syncResult = await syncSinglePage(
|
|
483
481
|
oldSite,
|
|
@@ -491,12 +489,12 @@ async function syncPages(oldSite, newSite) {
|
|
|
491
489
|
if (syncResult.reason === "ignored" || syncResult.reason === "no_change") {
|
|
492
490
|
stats.skipCount++;
|
|
493
491
|
}
|
|
494
|
-
|
|
495
|
-
await (0,
|
|
492
|
+
logger.info(`[SyncAllPages] ✅ 页面 ${pageTitle} 重试成功`);
|
|
493
|
+
await (0, import_koishi3.sleep)(CONFIG2.SYNC_INTERVAL_SUCCESS);
|
|
496
494
|
} else {
|
|
497
495
|
stillFailed.push(pageTitle);
|
|
498
|
-
|
|
499
|
-
await (0,
|
|
496
|
+
logger.info(`[SyncAllPages] ❌ 页面 ${pageTitle} 再次失败`);
|
|
497
|
+
await (0, import_koishi3.sleep)(CONFIG2.SYNC_INTERVAL_FAILED);
|
|
500
498
|
}
|
|
501
499
|
}
|
|
502
500
|
}
|
|
@@ -508,7 +506,7 @@ async function syncPages(oldSite, newSite) {
|
|
|
508
506
|
stillFailed
|
|
509
507
|
);
|
|
510
508
|
} catch (globalError) {
|
|
511
|
-
|
|
509
|
+
logger.error(`[SyncAllPages] 💥 批量同步流程异常终止:`, globalError);
|
|
512
510
|
throw globalError;
|
|
513
511
|
}
|
|
514
512
|
}
|
|
@@ -517,7 +515,7 @@ async function incrementalUpdate(oldSite, newSite, config) {
|
|
|
517
515
|
try {
|
|
518
516
|
const now = /* @__PURE__ */ new Date();
|
|
519
517
|
const threeHoursAgo = new Date(now.getTime() - 3 * 60 * 60 * 1e3);
|
|
520
|
-
|
|
518
|
+
logger.info(
|
|
521
519
|
`[增量更新流程] ⏰ 开始处理 ${threeHoursAgo.toISOString()} 到 ${now.toISOString()} 的更新...`
|
|
522
520
|
);
|
|
523
521
|
const queryGen = oldSite.continuedQueryGen({
|
|
@@ -536,12 +534,12 @@ async function incrementalUpdate(oldSite, newSite, config) {
|
|
|
536
534
|
for (const page of pages) {
|
|
537
535
|
const title = page.title;
|
|
538
536
|
if (processedTitles.has(title)) {
|
|
539
|
-
|
|
537
|
+
logger.info(`[增量更新流程] ⏭️ 已经处理过 ${title}, 跳过`);
|
|
540
538
|
totalSkipped++;
|
|
541
539
|
continue;
|
|
542
540
|
}
|
|
543
541
|
if (CONFIG2.IGNORED_PAGES.has(title)) {
|
|
544
|
-
|
|
542
|
+
logger.info(
|
|
545
543
|
`[增量更新流程] 🚫 ${title} 在无需处理的页面列表中, 跳过`
|
|
546
544
|
);
|
|
547
545
|
processedTitles.add(title);
|
|
@@ -553,7 +551,7 @@ async function incrementalUpdate(oldSite, newSite, config) {
|
|
|
553
551
|
try {
|
|
554
552
|
if (title.startsWith(CONFIG2.FILE_NAMESPACE_PREFIX)) {
|
|
555
553
|
const fileName = title.replace(CONFIG2.FILE_NAMESPACE_PREFIX, "");
|
|
556
|
-
|
|
554
|
+
logger.info(
|
|
557
555
|
`[增量更新流程] 🖼️ 检查到图片: ${title},正在尝试转存`
|
|
558
556
|
);
|
|
559
557
|
await syncSingleImage(oldSite, newSite, fileName, config);
|
|
@@ -565,26 +563,26 @@ async function incrementalUpdate(oldSite, newSite, config) {
|
|
|
565
563
|
CONFIG2.INCREMENTAL_USER
|
|
566
564
|
);
|
|
567
565
|
}
|
|
568
|
-
await (0,
|
|
566
|
+
await (0, import_koishi3.sleep)(CONFIG2.SYNC_INTERVAL_SUCCESS);
|
|
569
567
|
} catch (error) {
|
|
570
568
|
const errMsg = error instanceof Error ? error.message : String(error);
|
|
571
|
-
|
|
572
|
-
await (0,
|
|
569
|
+
logger.error(`[增量更新流程] ❌ 处理 ${title} 时出错:`, errMsg);
|
|
570
|
+
await (0, import_koishi3.sleep)(CONFIG2.SYNC_INTERVAL_FAILED);
|
|
573
571
|
}
|
|
574
572
|
}
|
|
575
573
|
}
|
|
576
|
-
|
|
574
|
+
logger.info(
|
|
577
575
|
`[增量更新流程] ✅ 增量更新完成!处理: ${totalProcessed}, 跳过: ${totalSkipped}`
|
|
578
576
|
);
|
|
579
577
|
} catch (globalError) {
|
|
580
|
-
|
|
578
|
+
logger.error(`[增量更新流程] 💥 增量更新流程异常终止:`, globalError);
|
|
581
579
|
throw globalError;
|
|
582
580
|
}
|
|
583
581
|
}
|
|
584
582
|
__name(incrementalUpdate, "incrementalUpdate");
|
|
585
583
|
|
|
586
584
|
// src/sync/moduleSync.ts
|
|
587
|
-
var
|
|
585
|
+
var import_koishi4 = require("koishi");
|
|
588
586
|
var CONFIG3 = {
|
|
589
587
|
MODLE_NAMESPACE: 828,
|
|
590
588
|
// 模块命名空间 (注意:这里原代码拼写为 MODLE,保留原样)
|
|
@@ -597,17 +595,17 @@ var CONFIG3 = {
|
|
|
597
595
|
};
|
|
598
596
|
async function syncSingleModule(oldSite, newSite, moduleTitle, user) {
|
|
599
597
|
if (CONFIG3.IGNORED_MODULES.includes(moduleTitle)) {
|
|
600
|
-
|
|
598
|
+
logger.info(`[SyncModule] 🚫 模块 ${moduleTitle} 在忽略列表中,跳过`);
|
|
601
599
|
return { success: true, reason: "ignored" };
|
|
602
600
|
}
|
|
603
601
|
try {
|
|
604
|
-
|
|
602
|
+
logger.info(`[SyncModule] 🔍 开始获取模块 ${moduleTitle} 的内容`);
|
|
605
603
|
const [oldContent, newContent] = await Promise.all([
|
|
606
604
|
getAndProcessPageContent(oldSite, moduleTitle),
|
|
607
605
|
getAndProcessPageContent(newSite, moduleTitle)
|
|
608
606
|
]);
|
|
609
607
|
if (oldContent === newContent) {
|
|
610
|
-
|
|
608
|
+
logger.info(`[SyncModule] 🟡 模块 ${moduleTitle} 内容未改变,跳过`);
|
|
611
609
|
return { success: true, reason: "no_change" };
|
|
612
610
|
}
|
|
613
611
|
await newSite.save(
|
|
@@ -615,17 +613,17 @@ async function syncSingleModule(oldSite, newSite, moduleTitle, user) {
|
|
|
615
613
|
oldContent,
|
|
616
614
|
`由:${user || "同步坤器人手动"} 触发更改,此时同步`
|
|
617
615
|
);
|
|
618
|
-
|
|
616
|
+
logger.info(`[SyncModule] ✅ 模块 ${moduleTitle} 同步成功`);
|
|
619
617
|
return { success: true, reason: "synced" };
|
|
620
618
|
} catch (error) {
|
|
621
619
|
const errMsg = error.message || String(error);
|
|
622
|
-
|
|
620
|
+
logger.error(`[SyncModule] ❌ 模块 ${moduleTitle} 同步失败:`, errMsg);
|
|
623
621
|
return { success: false, reason: errMsg };
|
|
624
622
|
}
|
|
625
623
|
}
|
|
626
624
|
__name(syncSingleModule, "syncSingleModule");
|
|
627
625
|
async function getAllModules(site) {
|
|
628
|
-
|
|
626
|
+
logger.info(
|
|
629
627
|
`[SyncAllModules] 📥 开始获取原站点所有模块(命名空间${CONFIG3.MODLE_NAMESPACE})`
|
|
630
628
|
);
|
|
631
629
|
const allModules = [];
|
|
@@ -640,9 +638,9 @@ async function getAllModules(site) {
|
|
|
640
638
|
for await (const res of queryGen) {
|
|
641
639
|
const moduleTitles = res.query?.allpages?.map((page) => page.title) || [];
|
|
642
640
|
allModules.push(...moduleTitles);
|
|
643
|
-
|
|
641
|
+
logger.info(`[SyncAllModules] 📄 已获取 ${allModules.length} 个模块`);
|
|
644
642
|
}
|
|
645
|
-
|
|
643
|
+
logger.info(
|
|
646
644
|
`[SyncAllModules] 📊 原站点总计获取到 ${allModules.length} 个模块`
|
|
647
645
|
);
|
|
648
646
|
return allModules;
|
|
@@ -653,20 +651,20 @@ async function syncModules(oldSite, newSite) {
|
|
|
653
651
|
const oldModuleList = await getAllModules(oldSite);
|
|
654
652
|
const total = oldModuleList.length;
|
|
655
653
|
if (total === 0) {
|
|
656
|
-
|
|
654
|
+
logger.info(`[SyncAllModules] 📭 原站点无模块可同步,结束`);
|
|
657
655
|
return;
|
|
658
656
|
}
|
|
659
657
|
let successCount = 0;
|
|
660
658
|
let failCount = 0;
|
|
661
659
|
let skipCount = 0;
|
|
662
660
|
const failedModules = [];
|
|
663
|
-
|
|
661
|
+
logger.info(`[SyncAllModules] 🚦 开始批量同步,总计 ${total} 个模块`);
|
|
664
662
|
for (let index = 0; index < total; index++) {
|
|
665
663
|
const moduleTitle = oldModuleList[index];
|
|
666
664
|
const current = index + 1;
|
|
667
665
|
const remaining = total - current;
|
|
668
666
|
const progress = (current / total * 100).toFixed(1);
|
|
669
|
-
|
|
667
|
+
logger.info(
|
|
670
668
|
`
|
|
671
669
|
[SyncAllModules] 📈 进度 [${current}/${total}] (${progress}%) - 处理 ${moduleTitle} | 剩余 ${remaining} 个`
|
|
672
670
|
);
|
|
@@ -679,23 +677,23 @@ async function syncModules(oldSite, newSite) {
|
|
|
679
677
|
if (!syncResult.success) {
|
|
680
678
|
failCount++;
|
|
681
679
|
failedModules.push(moduleTitle);
|
|
682
|
-
await (0,
|
|
680
|
+
await (0, import_koishi4.sleep)(CONFIG3.SYNC_INTERVAL_FAILED);
|
|
683
681
|
} else {
|
|
684
682
|
successCount++;
|
|
685
683
|
if (syncResult.reason === "ignored" || syncResult.reason === "no_change") {
|
|
686
684
|
skipCount++;
|
|
687
685
|
}
|
|
688
|
-
await (0,
|
|
686
|
+
await (0, import_koishi4.sleep)(CONFIG3.SYNC_INTERVAL_SUCCESS);
|
|
689
687
|
}
|
|
690
688
|
}
|
|
691
689
|
if (failedModules.length > 0) {
|
|
692
|
-
|
|
690
|
+
logger.info(
|
|
693
691
|
`
|
|
694
692
|
[SyncAllModules] 🔄 ===== 开始重试 ${failedModules.length} 个失败模块 =====`
|
|
695
693
|
);
|
|
696
694
|
const stillFailed = [];
|
|
697
695
|
for (const moduleTitle of failedModules) {
|
|
698
|
-
|
|
696
|
+
logger.info(`
|
|
699
697
|
[SyncAllModules] 🔁 重试中: ${moduleTitle}`);
|
|
700
698
|
const syncResult = await syncSingleModule(
|
|
701
699
|
oldSite,
|
|
@@ -709,32 +707,32 @@ async function syncModules(oldSite, newSite) {
|
|
|
709
707
|
if (syncResult.reason === "ignored" || syncResult.reason === "no_change") {
|
|
710
708
|
skipCount++;
|
|
711
709
|
}
|
|
712
|
-
|
|
713
|
-
await (0,
|
|
710
|
+
logger.info(`[SyncAllModules] ✅ 模块 ${moduleTitle} 重试成功`);
|
|
711
|
+
await (0, import_koishi4.sleep)(CONFIG3.SYNC_INTERVAL_SUCCESS);
|
|
714
712
|
} else {
|
|
715
713
|
stillFailed.push(moduleTitle);
|
|
716
|
-
|
|
717
|
-
await (0,
|
|
714
|
+
logger.info(`[SyncAllModules] ❌ 模块 ${moduleTitle} 再次失败`);
|
|
715
|
+
await (0, import_koishi4.sleep)(CONFIG3.SYNC_INTERVAL_FAILED);
|
|
718
716
|
}
|
|
719
717
|
}
|
|
720
|
-
|
|
718
|
+
logger.info(`
|
|
721
719
|
[SyncAllModules] 📋 ===== 最终同步报告 =====`);
|
|
722
720
|
if (stillFailed.length > 0) {
|
|
723
|
-
|
|
721
|
+
logger.info(`❌ 以下模块经过重试仍然失败,请手动检查:`);
|
|
724
722
|
stillFailed.forEach((title, idx) => {
|
|
725
|
-
|
|
723
|
+
logger.info(` ${idx + 1}. ${title}`);
|
|
726
724
|
});
|
|
727
725
|
} else {
|
|
728
|
-
|
|
726
|
+
logger.info(`🎉 所有模块同步成功(含重试)!`);
|
|
729
727
|
}
|
|
730
728
|
}
|
|
731
|
-
|
|
729
|
+
logger.info(`
|
|
732
730
|
[SyncAllModules] 🎯 同步完成!`);
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
731
|
+
logger.info(`├─ 总计:${total} 个模块`);
|
|
732
|
+
logger.info(`├─ 成功:${successCount} 个(含跳过 ${skipCount} 个)`);
|
|
733
|
+
logger.info(`└─ 失败:${failCount} 个`);
|
|
736
734
|
} catch (error) {
|
|
737
|
-
|
|
735
|
+
logger.error(`[SyncAllModules] 💥 批量同步流程异常终止:`, error);
|
|
738
736
|
throw error;
|
|
739
737
|
}
|
|
740
738
|
}
|
|
@@ -743,18 +741,18 @@ __name(syncModules, "syncModules");
|
|
|
743
741
|
// src/index.ts
|
|
744
742
|
var name = "oni-sync-bot";
|
|
745
743
|
var inject = ["console", "database", "server", "cron"];
|
|
746
|
-
var Config =
|
|
747
|
-
ggUsername:
|
|
748
|
-
ggPassword:
|
|
749
|
-
huijiUsername:
|
|
750
|
-
huijiPassword:
|
|
751
|
-
huijiUAKey:
|
|
752
|
-
domain:
|
|
753
|
-
main_site:
|
|
754
|
-
mirror_site:
|
|
744
|
+
var Config = import_koishi5.Schema.object({
|
|
745
|
+
ggUsername: import_koishi5.Schema.string().description("WIKIGG 用户名").default("${{ env.ggUsername }}"),
|
|
746
|
+
ggPassword: import_koishi5.Schema.string().description("WIKIGG 密码").default("${{ env.ggPassword }}"),
|
|
747
|
+
huijiUsername: import_koishi5.Schema.string().description("灰机wiki 用户名").default("${{ env.huijiUsername }}"),
|
|
748
|
+
huijiPassword: import_koishi5.Schema.string().description("灰机wiki 密码").default("${{ env.huijiPassword }}"),
|
|
749
|
+
huijiUAKey: import_koishi5.Schema.string().description("灰机wiki UAKey").default("${{ env.huijiUAKey }}"),
|
|
750
|
+
domain: import_koishi5.Schema.string().description("你的短链域名(必填,如:klei.vip)").default("klei.vip"),
|
|
751
|
+
main_site: import_koishi5.Schema.string().description("主站域名(必填,如:oxygennotincluded.wiki.gg)").default("oxygennotincluded.wiki.gg/zh"),
|
|
752
|
+
mirror_site: import_koishi5.Schema.string().description("镜像站域名(必填,如:wiki.biligame.com)").default("wiki.biligame.com/oni"),
|
|
753
|
+
logsUrl: import_koishi5.Schema.string().description("日志查看地址").default("htts://klei.vip/onilogs")
|
|
755
754
|
});
|
|
756
755
|
function apply(ctx, config) {
|
|
757
|
-
const logger = ctx.logger("oni-sync-bot");
|
|
758
756
|
let ggbot;
|
|
759
757
|
let huijibot;
|
|
760
758
|
ctx.inject(["console"], (ctx2) => {
|
|
@@ -824,26 +822,34 @@ function apply(ctx, config) {
|
|
|
824
822
|
ctx.command("sync <pageTitle:string>", "同步指定页面", { authority: 2 }).action(async ({ session }, pageTitle) => {
|
|
825
823
|
await syncSinglePage(ggbot, huijibot, pageTitle, "sync-bot").then(() => {
|
|
826
824
|
session.send(
|
|
827
|
-
`✅ 已尝试同步页面:${pageTitle}
|
|
825
|
+
`✅ 已尝试同步页面:${pageTitle},请前往控制台查看:${config.logsUrl}`
|
|
828
826
|
);
|
|
829
827
|
}).catch((err) => {
|
|
830
828
|
session.send(`❌ 同步页面失败:${pageTitle},错误信息:${err}`);
|
|
831
829
|
});
|
|
832
830
|
});
|
|
833
|
-
ctx.command("sync.incrementalUpdate", "
|
|
834
|
-
|
|
831
|
+
ctx.command("sync.incrementalUpdate", "获取3h内的编辑并尝试更新", {
|
|
832
|
+
authority: 2
|
|
833
|
+
}).alias("增量更新").action(async ({ session }) => {
|
|
834
|
+
session.send(
|
|
835
|
+
`🚀 获取3h内的编辑并尝试更新,任务耗时可能较长,请前往控制台查看日志:${config.logsUrl}`
|
|
836
|
+
);
|
|
835
837
|
await incrementalUpdate(ggbot, huijibot, config).then(() => {
|
|
836
838
|
session.send(
|
|
837
|
-
`✅
|
|
839
|
+
`✅ 已尝试获取三小时前的编辑并同步,请前往控制台查看:${config.logsUrl}`
|
|
838
840
|
);
|
|
839
841
|
}).catch((err) => {
|
|
840
842
|
session.send(`❌ 同步所有页面失败,错误信息:${err}`);
|
|
841
843
|
});
|
|
842
844
|
});
|
|
843
845
|
ctx.command("sync.allpages", "同步所有页面", { authority: 2 }).action(async ({ session }) => {
|
|
844
|
-
session.send(
|
|
846
|
+
session.send(
|
|
847
|
+
`🚀 开始同步所有页面,任务耗时较长,请前往控制台查看日志:${config.logsUrl}`
|
|
848
|
+
);
|
|
845
849
|
await syncPages(ggbot, huijibot).then(() => {
|
|
846
|
-
session.send(
|
|
850
|
+
session.send(
|
|
851
|
+
`✅ 已尝试同步所有页面,请前往控制台查看:${config.logsUrl}`
|
|
852
|
+
);
|
|
847
853
|
}).catch((err) => {
|
|
848
854
|
session.send(`❌ 同步所有页面失败,错误信息:${err}`);
|
|
849
855
|
});
|
|
@@ -851,23 +857,31 @@ function apply(ctx, config) {
|
|
|
851
857
|
ctx.command("sync.module <moduleTitle:string>", "同步指定模块", {
|
|
852
858
|
authority: 2
|
|
853
859
|
}).action(async ({ session }, moduleTitle) => {
|
|
860
|
+
await session.send(`✅ 同步中,请前往控制台查看:${config.logsUrl}`);
|
|
854
861
|
await syncSingleModule(ggbot, huijibot, moduleTitle, "sync-bot").then(() => {
|
|
855
862
|
session.send(
|
|
856
|
-
`✅ 已尝试同步模块:${moduleTitle}
|
|
863
|
+
`✅ 已尝试同步模块:${moduleTitle},请前往控制台查看:${config.logsUrl}`
|
|
857
864
|
);
|
|
858
865
|
}).catch((err) => {
|
|
859
866
|
session.send(`❌ 同步模块失败:${moduleTitle},错误信息:${err}`);
|
|
860
867
|
});
|
|
861
868
|
});
|
|
862
869
|
ctx.command("sync.allmodules", "同步所有模块", { authority: 2 }).action(async ({ session }) => {
|
|
863
|
-
session.send(
|
|
870
|
+
await session.send(
|
|
871
|
+
`🚀 开始同步所有模块,任务耗时较长,请前往控制台查看:${config.logsUrl}`
|
|
872
|
+
);
|
|
864
873
|
await syncModules(ggbot, huijibot).then(() => {
|
|
865
|
-
session.send(
|
|
874
|
+
session.send(
|
|
875
|
+
`✅ 已尝试同步所有模块,请前往控制台查看:${config.logsUrl}`
|
|
876
|
+
);
|
|
866
877
|
}).catch((err) => {
|
|
867
878
|
session.send(`❌ 同步所有模块失败,错误信息:${err}`);
|
|
868
879
|
});
|
|
869
880
|
});
|
|
870
881
|
ctx.command("sync.img <imgTitle:string>", "同步指定图片", { authority: 2 }).action(async ({ session }, imgTitle) => {
|
|
882
|
+
await session.send(
|
|
883
|
+
`🚀 开始同步,任务可能耗时较长,请前往控制台查看:${config.logsUrl}`
|
|
884
|
+
);
|
|
871
885
|
await syncSingleImage(
|
|
872
886
|
ggbot,
|
|
873
887
|
huijibot,
|
|
@@ -880,9 +894,13 @@ function apply(ctx, config) {
|
|
|
880
894
|
});
|
|
881
895
|
});
|
|
882
896
|
ctx.command("sync.allimgs", "同步所有图片", { authority: 2 }).action(async ({ session }) => {
|
|
883
|
-
session.send(
|
|
897
|
+
session.send(
|
|
898
|
+
`🚀 开始同步所有图片,任务耗时较长,请前往控制台查看:${config.logsUrl}`
|
|
899
|
+
);
|
|
884
900
|
await syncAllImages(ggbot, huijibot, config).then(() => {
|
|
885
|
-
session.send(
|
|
901
|
+
session.send(
|
|
902
|
+
`✅ 已尝试同步所有图片,请前往控制台查看:${config.logsUrl}`
|
|
903
|
+
);
|
|
886
904
|
}).catch((err) => {
|
|
887
905
|
session.send(`❌ 同步所有图片失败,错误信息:${err}`);
|
|
888
906
|
});
|
package/package.json
CHANGED
package/lib/config/index.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Config } from "../index";
|
|
2
|
-
export interface ISiteConfig {
|
|
3
|
-
name: string;
|
|
4
|
-
api: string;
|
|
5
|
-
username: string;
|
|
6
|
-
password: string;
|
|
7
|
-
uakey?: string;
|
|
8
|
-
userAgent: string;
|
|
9
|
-
}
|
|
10
|
-
interface ISitesConfig {
|
|
11
|
-
gg: ISiteConfig;
|
|
12
|
-
huiji: ISiteConfig;
|
|
13
|
-
}
|
|
14
|
-
export declare function getSitesConfig(config: Config): ISitesConfig;
|
|
15
|
-
export {};
|
package/lib/sync/imgSync.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Mwn } from "mwn";
|
|
2
|
-
import { Config } from "../index";
|
|
3
|
-
export declare const CONFIG: {
|
|
4
|
-
IGNORED_IMAGES: any[];
|
|
5
|
-
SYNC_INTERVAL_SUCCESS: number;
|
|
6
|
-
SYNC_INTERVAL_FAILED: number;
|
|
7
|
-
UPLOAD_COMMENT: string;
|
|
8
|
-
UPLOAD_TEXT: string;
|
|
9
|
-
};
|
|
10
|
-
interface ImageInfo {
|
|
11
|
-
url: string;
|
|
12
|
-
sha1: string;
|
|
13
|
-
size?: number;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* 获取图片的原始URL和SHA1
|
|
17
|
-
*/
|
|
18
|
-
declare function getImageInfo(site: Mwn, fileName: string): Promise<ImageInfo | null>;
|
|
19
|
-
/**
|
|
20
|
-
* 同步单个图片
|
|
21
|
-
*/
|
|
22
|
-
declare function syncSingleImage(sourceBot: Mwn, targetBot: Mwn, fileName: string, config: Config): Promise<{
|
|
23
|
-
success: boolean;
|
|
24
|
-
reason?: string;
|
|
25
|
-
}>;
|
|
26
|
-
/**
|
|
27
|
-
* 批量同步所有图片(带失败重试)
|
|
28
|
-
*/
|
|
29
|
-
declare function syncAllImages(sourceBot: Mwn, targetBot: Mwn, config: Config): Promise<void>;
|
|
30
|
-
export { syncSingleImage, syncAllImages, getImageInfo };
|
package/lib/sync/moduleSync.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { Mwn } from "mwn";
|
|
2
|
-
/**
|
|
3
|
-
* 同步单个模块
|
|
4
|
-
* @param oldSite 原站点
|
|
5
|
-
* @param newSite 新站点
|
|
6
|
-
* @param moduleTitle 模块标题
|
|
7
|
-
* @param user 触发同步的用户
|
|
8
|
-
* @returns
|
|
9
|
-
*/
|
|
10
|
-
declare function syncSingleModule(oldSite: Mwn, newSite: Mwn, moduleTitle: string, user?: string): Promise<{
|
|
11
|
-
success: boolean;
|
|
12
|
-
reason?: string;
|
|
13
|
-
}>;
|
|
14
|
-
/**
|
|
15
|
-
* 批量同步所有模块
|
|
16
|
-
* @param oldSite 原站点
|
|
17
|
-
* @param newSite 新站点
|
|
18
|
-
* @returns
|
|
19
|
-
*/
|
|
20
|
-
declare function syncModules(oldSite: Mwn, newSite: Mwn): Promise<void>;
|
|
21
|
-
export { syncSingleModule, syncModules };
|
package/lib/sync/pageSync.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Mwn } from "mwn";
|
|
2
|
-
import { Config } from "../index";
|
|
3
|
-
/**
|
|
4
|
-
* 单页面同步
|
|
5
|
-
* @param oldSite 源站点机器人实例
|
|
6
|
-
* @param newSite 目标站点机器人实例
|
|
7
|
-
* @param pageTitle 同步的标题
|
|
8
|
-
* @param user 触发更改的用户
|
|
9
|
-
* @returns success: boolean;reason: string;
|
|
10
|
-
}
|
|
11
|
-
*/
|
|
12
|
-
declare function syncSinglePage(oldSite: Mwn, newSite: Mwn, pageTitle: string, user: string): Promise<{
|
|
13
|
-
success: boolean;
|
|
14
|
-
reason: string;
|
|
15
|
-
}>;
|
|
16
|
-
/**
|
|
17
|
-
* 同步所有页面
|
|
18
|
-
* @param oldSite 源站点机器人实例
|
|
19
|
-
* @param newSite 目标站点机器人实例
|
|
20
|
-
* @returns null
|
|
21
|
-
*/
|
|
22
|
-
declare function syncPages(oldSite: Mwn, newSite: Mwn): Promise<void>;
|
|
23
|
-
/**
|
|
24
|
-
* 增量更新
|
|
25
|
-
* @param oldSite 源站点机器人实例
|
|
26
|
-
* @param newSite 目标站点机器人实例
|
|
27
|
-
* @param config KOISHI用户配置的项
|
|
28
|
-
*/
|
|
29
|
-
declare function incrementalUpdate(oldSite: Mwn, newSite: Mwn, config: Config): Promise<void>;
|
|
30
|
-
export { syncSinglePage, syncPages, incrementalUpdate };
|
package/lib/utils/login.d.ts
DELETED
package/lib/utils/tools.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { Mwn } from "mwn";
|
|
2
|
-
/**
|
|
3
|
-
* 获取并处理页面内容
|
|
4
|
-
* @param site 机器人实例
|
|
5
|
-
* @param pageTitle 页面标题
|
|
6
|
-
* @returns 处理后的页面内容(移除跨站链接 + 全局替换 Dev: 为 Module:Dev/)
|
|
7
|
-
*/
|
|
8
|
-
declare function getAndProcessPageContent(site: Mwn, pageTitle: string): Promise<string>;
|
|
9
|
-
/**
|
|
10
|
-
* 处理文本,生成标准化的全拼和首字母
|
|
11
|
-
* @param text 中文文本
|
|
12
|
-
* @returns {pinyin_full: string, pinyin_first: string} 处理后的拼音信息
|
|
13
|
-
*/
|
|
14
|
-
declare function generatePinyinInfo(text: string): {
|
|
15
|
-
pinyin_full: string;
|
|
16
|
-
pinyin_first: string;
|
|
17
|
-
};
|
|
18
|
-
export { getAndProcessPageContent, generatePinyinInfo };
|