koishi-plugin-oni-sync-bot 0.0.2 → 0.0.3

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 CHANGED
@@ -36,11 +36,60 @@ __export(src_exports, {
36
36
  name: () => name
37
37
  });
38
38
  module.exports = __toCommonJS(src_exports);
39
- var import_koishi4 = require("koishi");
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
+ var DEV_TEXT_REGEX = /Dev:/g;
50
+ var MODULE_NAMESPACE_PREFIX = "Module:Dev/";
51
+ function clean_page_text(text) {
52
+ const textWithoutCrossLink = text.replace(CROSS_SITE_LINK_REGEX, "");
53
+ const textWithReplacedDev = textWithoutCrossLink.replace(
54
+ DEV_TEXT_REGEX,
55
+ MODULE_NAMESPACE_PREFIX
56
+ );
57
+ return textWithReplacedDev;
58
+ }
59
+ __name(clean_page_text, "clean_page_text");
60
+ async function getAndProcessPageContent(site, pageTitle) {
61
+ try {
62
+ const res = await site.read(pageTitle);
63
+ const rawText = res.revisions[0]?.content || "";
64
+ const processedText = clean_page_text(rawText);
65
+ return processedText.trimEnd();
66
+ } catch (err) {
67
+ throw new Error(`[${pageTitle}] 内容获取失败: ${err}`);
68
+ }
69
+ }
70
+ __name(getAndProcessPageContent, "getAndProcessPageContent");
71
+ function generatePinyinInfo(text) {
72
+ if (!text) return { pinyin_full: "", pinyin_first: "" };
73
+ const cleanText = text.replace(/[^\u4e00-\u9fa5a-zA-Z0-9]/g, "");
74
+ if (!cleanText) return { pinyin_full: "", pinyin_first: "" };
75
+ const fullPinyin = (0, import_pinyin_pro.pinyin)(cleanText, {
76
+ toneType: "none",
77
+ type: "string",
78
+ separator: ""
79
+ }).toLowerCase();
80
+ const firstLetter = (0, import_pinyin_pro.pinyin)(cleanText, {
81
+ pattern: "initial",
82
+ separator: ""
83
+ }).toLowerCase();
84
+ return {
85
+ pinyin_full: fullPinyin,
86
+ pinyin_first: firstLetter
87
+ };
88
+ }
89
+ __name(generatePinyinInfo, "generatePinyinInfo");
90
+ var logger = new import_koishi.Logger("oni-sync");
91
+
92
+ // src/utils/login.ts
44
93
  async function login(siteConfig) {
45
94
  const bot = new import_mwn.Mwn({
46
95
  apiUrl: siteConfig.api,
@@ -61,7 +110,7 @@ async function login(siteConfig) {
61
110
  }
62
111
  bot.setRequestOptions(customRequestOptions);
63
112
  await bot.login();
64
- console.log(`✅ 成功登录 ${siteConfig.name}`);
113
+ logger.info(`✅ 成功登录 ${siteConfig.name}`);
65
114
  return bot;
66
115
  }
67
116
  __name(login, "login");
@@ -89,56 +138,11 @@ function getSitesConfig(config) {
89
138
  }
90
139
  __name(getSitesConfig, "getSitesConfig");
91
140
 
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
141
  // src/sync/pageSync.ts
138
- var import_koishi2 = require("koishi");
142
+ var import_koishi3 = require("koishi");
139
143
 
140
144
  // src/sync/imgSync.ts
141
- var import_koishi = require("koishi");
145
+ var import_koishi2 = require("koishi");
142
146
  var import_node_fetch = __toESM(require("node-fetch"));
143
147
  var import_form_data = __toESM(require("form-data"));
144
148
  var CONFIG = {
@@ -168,29 +172,29 @@ async function getImageInfo(site, fileName) {
168
172
  size: imageInfo.size
169
173
  };
170
174
  } catch (error) {
171
- console.error(`[GetImageInfo] 获取 ${fileName} 信息失败:`, error);
175
+ logger.error(`[GetImageInfo] 获取 ${fileName} 信息失败:`, error);
172
176
  return null;
173
177
  }
174
178
  }
175
179
  __name(getImageInfo, "getImageInfo");
176
180
  async function syncSingleImage(sourceBot, targetBot, fileName, config) {
177
181
  if (CONFIG.IGNORED_IMAGES.includes(fileName)) {
178
- console.log(`[SyncImg] 🚫 图片 ${fileName} 在忽略列表,跳过`);
182
+ logger.info(`[SyncImg] 🚫 图片 ${fileName} 在忽略列表,跳过`);
179
183
  return { success: true, reason: "ignored" };
180
184
  }
181
185
  try {
182
- console.log(`[SyncImg] 🚀 开始处理: ${fileName}`);
186
+ logger.info(`[SyncImg] 🚀 开始处理: ${fileName}`);
183
187
  const sourceImageInfo = await getImageInfo(sourceBot, fileName);
184
188
  if (!sourceImageInfo) {
185
- console.log(`[SyncImg] ❌ 源站未找到图片: ${fileName}`);
189
+ logger.info(`[SyncImg] ❌ 源站未找到图片: ${fileName}`);
186
190
  return { success: false, reason: "source_missing" };
187
191
  }
188
192
  const targetImageInfo = await getImageInfo(targetBot, fileName);
189
193
  if (targetImageInfo && targetImageInfo.sha1 === sourceImageInfo.sha1) {
190
- console.log(`[SyncImg] 🟡 图片 ${fileName} 已存在且内容一致,跳过`);
194
+ logger.info(`[SyncImg] 🟡 图片 ${fileName} 已存在且内容一致,跳过`);
191
195
  return { success: true, reason: "no_change" };
192
196
  }
193
- console.log(`[SyncImg] 📥 下载图片: ${sourceImageInfo.url}`);
197
+ logger.info(`[SyncImg] 📥 下载图片: ${sourceImageInfo.url}`);
194
198
  const imageResponse = await (0, import_node_fetch.default)(sourceImageInfo.url, {
195
199
  headers: {
196
200
  "User-Agent": "OniSyncBot/1.0 (https://klei.vip; Charles@klei.vip)"
@@ -200,7 +204,7 @@ async function syncSingleImage(sourceBot, targetBot, fileName, config) {
200
204
  throw new Error(`图片下载失败,HTTP状态码: ${imageResponse.status}`);
201
205
  }
202
206
  const imageBuffer = Buffer.from(await imageResponse.arrayBuffer());
203
- console.log(
207
+ logger.info(
204
208
  `[SyncImg] 📤 上传图片: ${fileName} (大小: ${(imageBuffer.length / 1024).toFixed(1)} KB)`
205
209
  );
206
210
  const token = await targetBot.getCsrfToken();
@@ -227,7 +231,7 @@ async function syncSingleImage(sourceBot, targetBot, fileName, config) {
227
231
  });
228
232
  const responseData = rawResponse.data;
229
233
  if (responseData.upload && responseData.upload.result === "Success") {
230
- console.log(`[SyncImg] ✅ 图片 ${fileName} 同步成功`);
234
+ logger.info(`[SyncImg] ✅ 图片 ${fileName} 同步成功`);
231
235
  return { success: true, reason: "synced" };
232
236
  } else if (responseData.error) {
233
237
  throw new Error(`${responseData.error.code}: ${responseData.error.info}`);
@@ -236,13 +240,13 @@ async function syncSingleImage(sourceBot, targetBot, fileName, config) {
236
240
  }
237
241
  } catch (error) {
238
242
  const errMsg = error.message || String(error);
239
- console.error(`[SyncImg] ❌ 图片 ${fileName} 同步失败:`, errMsg);
243
+ logger.error(`[SyncImg] ❌ 图片 ${fileName} 同步失败:`, errMsg);
240
244
  return { success: false, reason: errMsg };
241
245
  }
242
246
  }
243
247
  __name(syncSingleImage, "syncSingleImage");
244
248
  async function getAllImages(site) {
245
- console.log(`[SyncAllImg] 📥 开始获取WikiGG所有图片`);
249
+ logger.info(`[SyncAllImg] 📥 开始获取WikiGG所有图片`);
246
250
  const allImages = [];
247
251
  const queryGen = site.continuedQueryGen({
248
252
  action: "query",
@@ -255,9 +259,9 @@ async function getAllImages(site) {
255
259
  const imageItems = res.query?.allimages || [];
256
260
  const imageTitles = imageItems.map((img) => img.title);
257
261
  allImages.push(...imageTitles);
258
- console.log(`[SyncAllImg] 📄 已获取 ${allImages.length} 个图片`);
262
+ logger.info(`[SyncAllImg] 📄 已获取 ${allImages.length} 个图片`);
259
263
  }
260
- console.log(`[SyncAllImg] 📊 总计获取到 ${allImages.length} 个图片`);
264
+ logger.info(`[SyncAllImg] 📊 总计获取到 ${allImages.length} 个图片`);
261
265
  return allImages;
262
266
  }
263
267
  __name(getAllImages, "getAllImages");
@@ -265,20 +269,20 @@ async function syncAllImages(sourceBot, targetBot, config) {
265
269
  try {
266
270
  const imageList = await getAllImages(sourceBot);
267
271
  if (imageList.length === 0) {
268
- console.log(`[SyncAllImg] 📭 源站无图片可同步,结束`);
272
+ logger.info(`[SyncAllImg] 📭 源站无图片可同步,结束`);
269
273
  return;
270
274
  }
271
275
  let successCount = 0;
272
276
  let failCount = 0;
273
277
  let skipCount = 0;
274
278
  const failedImages = [];
275
- console.log(
279
+ logger.info(
276
280
  `[SyncAllImg] 🚦 开始批量同步,总计 ${imageList.length} 个图片`
277
281
  );
278
282
  for (let i = 0; i < imageList.length; i++) {
279
283
  const fileName = imageList[i];
280
284
  const progress = (i + 1) / imageList.length * 100;
281
- console.log(
285
+ logger.info(
282
286
  `
283
287
  [SyncAllImg] 📈 进度 ${i + 1}/${imageList.length} (${progress.toFixed(1)}%)`
284
288
  );
@@ -291,23 +295,23 @@ async function syncAllImages(sourceBot, targetBot, config) {
291
295
  if (!result.success) {
292
296
  failCount++;
293
297
  failedImages.push(fileName);
294
- await (0, import_koishi.sleep)(CONFIG.SYNC_INTERVAL_FAILED);
298
+ await (0, import_koishi2.sleep)(CONFIG.SYNC_INTERVAL_FAILED);
295
299
  } else {
296
300
  successCount++;
297
301
  if (result.reason === "ignored" || result.reason === "no_change") {
298
302
  skipCount++;
299
303
  }
300
- await (0, import_koishi.sleep)(CONFIG.SYNC_INTERVAL_SUCCESS);
304
+ await (0, import_koishi2.sleep)(CONFIG.SYNC_INTERVAL_SUCCESS);
301
305
  }
302
306
  }
303
307
  if (failedImages.length > 0) {
304
- console.log(
308
+ logger.info(
305
309
  `
306
310
  [SyncAllImg] 🔄 开始重试 ${failedImages.length} 个失败图片`
307
311
  );
308
312
  const stillFailed = [];
309
313
  for (const fileName of failedImages) {
310
- console.log(`
314
+ logger.info(`
311
315
  [SyncAllImg] 🔁 重试: ${fileName}`);
312
316
  const result = await syncSingleImage(
313
317
  sourceBot,
@@ -318,31 +322,31 @@ async function syncAllImages(sourceBot, targetBot, config) {
318
322
  if (result.success) {
319
323
  successCount++;
320
324
  failCount--;
321
- console.log(`[SyncAllImg] ✅ 重试成功: ${fileName}`);
325
+ logger.info(`[SyncAllImg] ✅ 重试成功: ${fileName}`);
322
326
  } else {
323
327
  stillFailed.push(fileName);
324
- console.log(`[SyncAllImg] ❌ 重试失败: ${fileName}`);
328
+ logger.info(`[SyncAllImg] ❌ 重试失败: ${fileName}`);
325
329
  }
326
- await (0, import_koishi.sleep)(CONFIG.SYNC_INTERVAL_SUCCESS);
330
+ await (0, import_koishi2.sleep)(CONFIG.SYNC_INTERVAL_SUCCESS);
327
331
  }
328
332
  if (stillFailed.length > 0) {
329
- console.log(`
333
+ logger.info(`
330
334
  [SyncAllImg] ❌ 最终失败列表(需手动处理):`);
331
335
  stillFailed.forEach(
332
- (title, idx) => console.log(` ${idx + 1}. ${title}`)
336
+ (title, idx) => logger.info(` ${idx + 1}. ${title}`)
333
337
  );
334
338
  } else {
335
- console.log(`
339
+ logger.info(`
336
340
  [SyncAllImg] 🎉 所有失败图片重试成功!`);
337
341
  }
338
342
  }
339
- console.log(`
343
+ logger.info(`
340
344
  [SyncAllImg] 📊 同步完成!`);
341
- console.log(`├─ 总计:${imageList.length} 个图片`);
342
- console.log(`├─ 成功:${successCount} 个(含跳过 ${skipCount} 个)`);
343
- console.log(`└─ 失败:${failCount} 个`);
345
+ logger.info(`├─ 总计:${imageList.length} 个图片`);
346
+ logger.info(`├─ 成功:${successCount} 个(含跳过 ${skipCount} 个)`);
347
+ logger.info(`└─ 失败:${failCount} 个`);
344
348
  } catch (globalError) {
345
- console.error(`[SyncAllImg] 💥 同步流程异常终止:`, globalError);
349
+ logger.error(`[SyncAllImg] 💥 同步流程异常终止:`, globalError);
346
350
  throw globalError;
347
351
  }
348
352
  }
@@ -361,31 +365,31 @@ var CONFIG2 = {
361
365
  };
362
366
  async function syncSinglePage(oldSite, newSite, pageTitle, user) {
363
367
  if (CONFIG2.IGNORED_PAGES.has(pageTitle)) {
364
- console.log(`[syncSinglePage] 🚫 页面 ${pageTitle} 在忽略列表中,跳过`);
368
+ logger.info(`[syncSinglePage] 🚫 页面 ${pageTitle} 在忽略列表中,跳过`);
365
369
  return { success: true, reason: "ignored" };
366
370
  }
367
371
  try {
368
- console.log(`[syncSinglePage] 🚀 开始同步页面: ${pageTitle}`);
372
+ logger.info(`[syncSinglePage] 🚀 开始同步页面: ${pageTitle}`);
369
373
  const [oldContent, newContent] = await Promise.all([
370
374
  getAndProcessPageContent(oldSite, pageTitle),
371
375
  getAndProcessPageContent(newSite, pageTitle)
372
376
  ]);
373
377
  if (oldContent === newContent) {
374
- console.log(`[syncSinglePage] 🟡 页面 ${pageTitle} 内容未改变,跳过`);
378
+ logger.info(`[syncSinglePage] 🟡 页面 ${pageTitle} 内容未改变,跳过`);
375
379
  return { success: true, reason: "no_change" };
376
380
  }
377
381
  await newSite.save(pageTitle, oldContent, `由:${user} 触发更改,此时同步`);
378
- console.log(`[syncSinglePage] ✅ 页面 ${pageTitle} 同步成功`);
382
+ logger.info(`[syncSinglePage] ✅ 页面 ${pageTitle} 同步成功`);
379
383
  return { success: true, reason: "synced" };
380
384
  } catch (error) {
381
385
  const errMsg = error instanceof Error ? error.message : String(error);
382
- console.error(`[syncSinglePage] ❌ 页面 ${pageTitle} 同步失败:`, errMsg);
386
+ logger.error(`[syncSinglePage] ❌ 页面 ${pageTitle} 同步失败:`, errMsg);
383
387
  return { success: false, reason: errMsg };
384
388
  }
385
389
  }
386
390
  __name(syncSinglePage, "syncSinglePage");
387
391
  async function getAllPages(site) {
388
- console.log(
392
+ logger.info(
389
393
  `[SyncAllPages] 📥 开始获取原站点所有页面(命名空间${CONFIG2.NAMESPACE})`
390
394
  );
391
395
  const allPages = [];
@@ -399,9 +403,9 @@ async function getAllPages(site) {
399
403
  for await (const res of queryGen) {
400
404
  const pageTitles = res.query?.allpages?.map((page) => page.title) || [];
401
405
  allPages.push(...pageTitles);
402
- console.log(`[SyncAllPages] 📄 已获取 ${allPages.length} 个页面`);
406
+ logger.info(`[SyncAllPages] 📄 已获取 ${allPages.length} 个页面`);
403
407
  }
404
- console.log(`[SyncAllPages] 📊 原站点总计获取到 ${allPages.length} 个页面`);
408
+ logger.info(`[SyncAllPages] 📊 原站点总计获取到 ${allPages.length} 个页面`);
405
409
  return allPages;
406
410
  }
407
411
  __name(getAllPages, "getAllPages");
@@ -410,41 +414,41 @@ async function processPageWithStats(oldSite, newSite, pageTitle, user, stats, fa
410
414
  if (!syncResult.success) {
411
415
  stats.failCount++;
412
416
  failedPages.push(pageTitle);
413
- await (0, import_koishi2.sleep)(CONFIG2.SYNC_INTERVAL_FAILED);
417
+ await (0, import_koishi3.sleep)(CONFIG2.SYNC_INTERVAL_FAILED);
414
418
  } else {
415
419
  stats.successCount++;
416
420
  if (syncResult.reason === "ignored" || syncResult.reason === "no_change") {
417
421
  stats.skipCount++;
418
422
  }
419
- await (0, import_koishi2.sleep)(CONFIG2.SYNC_INTERVAL_SUCCESS);
423
+ await (0, import_koishi3.sleep)(CONFIG2.SYNC_INTERVAL_SUCCESS);
420
424
  }
421
425
  }
422
426
  __name(processPageWithStats, "processPageWithStats");
423
427
  function printProgress(current, total, pageTitle) {
424
428
  const progress = (current / total * 100).toFixed(1);
425
429
  const remaining = total - current;
426
- console.log(
430
+ logger.info(
427
431
  `
428
432
  [SyncAllPages] 📈 进度 [${current}/${total}] (${progress}%) - 处理 ${pageTitle} | 剩余 ${remaining} 个`
429
433
  );
430
434
  }
431
435
  __name(printProgress, "printProgress");
432
436
  function printFinalReport(total, successCount, failCount, skipCount, stillFailed) {
433
- console.log(`
437
+ logger.info(`
434
438
  [SyncAllPages] 📋 ===== 最终同步报告 =====`);
435
439
  if (stillFailed.length > 0) {
436
- console.log(`❌ 以下页面经过重试仍然失败,请手动检查:`);
440
+ logger.info(`❌ 以下页面经过重试仍然失败,请手动检查:`);
437
441
  stillFailed.forEach((title, idx) => {
438
- console.log(` ${idx + 1}. ${title}`);
442
+ logger.info(` ${idx + 1}. ${title}`);
439
443
  });
440
444
  } else {
441
- console.log(`🎉 所有页面同步成功(含重试)!`);
445
+ logger.info(`🎉 所有页面同步成功(含重试)!`);
442
446
  }
443
- console.log(`
447
+ logger.info(`
444
448
  [SyncAllPages] 🎯 同步流程结束!`);
445
- console.log(`├─ 总计:${total} 个页面`);
446
- console.log(`├─ 成功:${successCount} 个(含跳过 ${skipCount} 个)`);
447
- console.log(`└─ 失败:${failCount} 个`);
449
+ logger.info(`├─ 总计:${total} 个页面`);
450
+ logger.info(`├─ 成功:${successCount} 个(含跳过 ${skipCount} 个)`);
451
+ logger.info(`└─ 失败:${failCount} 个`);
448
452
  }
449
453
  __name(printFinalReport, "printFinalReport");
450
454
  async function syncPages(oldSite, newSite) {
@@ -452,12 +456,12 @@ async function syncPages(oldSite, newSite) {
452
456
  const oldPageList = await getAllPages(oldSite);
453
457
  const total = oldPageList.length;
454
458
  if (total === 0) {
455
- console.log(`[SyncAllPages] 📭 原站点无页面可同步,结束`);
459
+ logger.info(`[SyncAllPages] 📭 原站点无页面可同步,结束`);
456
460
  return;
457
461
  }
458
462
  const stats = { successCount: 0, failCount: 0, skipCount: 0 };
459
463
  const failedPages = [];
460
- console.log(`[SyncAllPages] 🚦 开始批量同步,总计 ${total} 个页面`);
464
+ logger.info(`[SyncAllPages] 🚦 开始批量同步,总计 ${total} 个页面`);
461
465
  for (let index = 0; index < total; index++) {
462
466
  const pageTitle = oldPageList[index];
463
467
  printProgress(index + 1, total, pageTitle);
@@ -472,12 +476,12 @@ async function syncPages(oldSite, newSite) {
472
476
  }
473
477
  let stillFailed = [];
474
478
  if (failedPages.length > 0) {
475
- console.log(
479
+ logger.info(
476
480
  `
477
481
  [SyncAllPages] 🔄 ===== 开始重试 ${failedPages.length} 个失败页面 =====`
478
482
  );
479
483
  for (const pageTitle of failedPages) {
480
- console.log(`
484
+ logger.info(`
481
485
  [SyncAllPages] 🔁 重试中: ${pageTitle}`);
482
486
  const syncResult = await syncSinglePage(
483
487
  oldSite,
@@ -491,12 +495,12 @@ async function syncPages(oldSite, newSite) {
491
495
  if (syncResult.reason === "ignored" || syncResult.reason === "no_change") {
492
496
  stats.skipCount++;
493
497
  }
494
- console.log(`[SyncAllPages] ✅ 页面 ${pageTitle} 重试成功`);
495
- await (0, import_koishi2.sleep)(CONFIG2.SYNC_INTERVAL_SUCCESS);
498
+ logger.info(`[SyncAllPages] ✅ 页面 ${pageTitle} 重试成功`);
499
+ await (0, import_koishi3.sleep)(CONFIG2.SYNC_INTERVAL_SUCCESS);
496
500
  } else {
497
501
  stillFailed.push(pageTitle);
498
- console.log(`[SyncAllPages] ❌ 页面 ${pageTitle} 再次失败`);
499
- await (0, import_koishi2.sleep)(CONFIG2.SYNC_INTERVAL_FAILED);
502
+ logger.info(`[SyncAllPages] ❌ 页面 ${pageTitle} 再次失败`);
503
+ await (0, import_koishi3.sleep)(CONFIG2.SYNC_INTERVAL_FAILED);
500
504
  }
501
505
  }
502
506
  }
@@ -508,7 +512,7 @@ async function syncPages(oldSite, newSite) {
508
512
  stillFailed
509
513
  );
510
514
  } catch (globalError) {
511
- console.error(`[SyncAllPages] 💥 批量同步流程异常终止:`, globalError);
515
+ logger.error(`[SyncAllPages] 💥 批量同步流程异常终止:`, globalError);
512
516
  throw globalError;
513
517
  }
514
518
  }
@@ -517,7 +521,7 @@ async function incrementalUpdate(oldSite, newSite, config) {
517
521
  try {
518
522
  const now = /* @__PURE__ */ new Date();
519
523
  const threeHoursAgo = new Date(now.getTime() - 3 * 60 * 60 * 1e3);
520
- console.log(
524
+ logger.info(
521
525
  `[增量更新流程] ⏰ 开始处理 ${threeHoursAgo.toISOString()} 到 ${now.toISOString()} 的更新...`
522
526
  );
523
527
  const queryGen = oldSite.continuedQueryGen({
@@ -536,12 +540,12 @@ async function incrementalUpdate(oldSite, newSite, config) {
536
540
  for (const page of pages) {
537
541
  const title = page.title;
538
542
  if (processedTitles.has(title)) {
539
- console.log(`[增量更新流程] ⏭️ 已经处理过 ${title}, 跳过`);
543
+ logger.info(`[增量更新流程] ⏭️ 已经处理过 ${title}, 跳过`);
540
544
  totalSkipped++;
541
545
  continue;
542
546
  }
543
547
  if (CONFIG2.IGNORED_PAGES.has(title)) {
544
- console.log(
548
+ logger.info(
545
549
  `[增量更新流程] 🚫 ${title} 在无需处理的页面列表中, 跳过`
546
550
  );
547
551
  processedTitles.add(title);
@@ -553,7 +557,7 @@ async function incrementalUpdate(oldSite, newSite, config) {
553
557
  try {
554
558
  if (title.startsWith(CONFIG2.FILE_NAMESPACE_PREFIX)) {
555
559
  const fileName = title.replace(CONFIG2.FILE_NAMESPACE_PREFIX, "");
556
- console.log(
560
+ logger.info(
557
561
  `[增量更新流程] 🖼️ 检查到图片: ${title},正在尝试转存`
558
562
  );
559
563
  await syncSingleImage(oldSite, newSite, fileName, config);
@@ -565,26 +569,26 @@ async function incrementalUpdate(oldSite, newSite, config) {
565
569
  CONFIG2.INCREMENTAL_USER
566
570
  );
567
571
  }
568
- await (0, import_koishi2.sleep)(CONFIG2.SYNC_INTERVAL_SUCCESS);
572
+ await (0, import_koishi3.sleep)(CONFIG2.SYNC_INTERVAL_SUCCESS);
569
573
  } catch (error) {
570
574
  const errMsg = error instanceof Error ? error.message : String(error);
571
- console.error(`[增量更新流程] ❌ 处理 ${title} 时出错:`, errMsg);
572
- await (0, import_koishi2.sleep)(CONFIG2.SYNC_INTERVAL_FAILED);
575
+ logger.error(`[增量更新流程] ❌ 处理 ${title} 时出错:`, errMsg);
576
+ await (0, import_koishi3.sleep)(CONFIG2.SYNC_INTERVAL_FAILED);
573
577
  }
574
578
  }
575
579
  }
576
- console.log(
580
+ logger.info(
577
581
  `[增量更新流程] ✅ 增量更新完成!处理: ${totalProcessed}, 跳过: ${totalSkipped}`
578
582
  );
579
583
  } catch (globalError) {
580
- console.error(`[增量更新流程] 💥 增量更新流程异常终止:`, globalError);
584
+ logger.error(`[增量更新流程] 💥 增量更新流程异常终止:`, globalError);
581
585
  throw globalError;
582
586
  }
583
587
  }
584
588
  __name(incrementalUpdate, "incrementalUpdate");
585
589
 
586
590
  // src/sync/moduleSync.ts
587
- var import_koishi3 = require("koishi");
591
+ var import_koishi4 = require("koishi");
588
592
  var CONFIG3 = {
589
593
  MODLE_NAMESPACE: 828,
590
594
  // 模块命名空间 (注意:这里原代码拼写为 MODLE,保留原样)
@@ -597,17 +601,17 @@ var CONFIG3 = {
597
601
  };
598
602
  async function syncSingleModule(oldSite, newSite, moduleTitle, user) {
599
603
  if (CONFIG3.IGNORED_MODULES.includes(moduleTitle)) {
600
- console.log(`[SyncModule] 🚫 模块 ${moduleTitle} 在忽略列表中,跳过`);
604
+ logger.info(`[SyncModule] 🚫 模块 ${moduleTitle} 在忽略列表中,跳过`);
601
605
  return { success: true, reason: "ignored" };
602
606
  }
603
607
  try {
604
- console.log(`[SyncModule] 🔍 开始获取模块 ${moduleTitle} 的内容`);
608
+ logger.info(`[SyncModule] 🔍 开始获取模块 ${moduleTitle} 的内容`);
605
609
  const [oldContent, newContent] = await Promise.all([
606
610
  getAndProcessPageContent(oldSite, moduleTitle),
607
611
  getAndProcessPageContent(newSite, moduleTitle)
608
612
  ]);
609
613
  if (oldContent === newContent) {
610
- console.log(`[SyncModule] 🟡 模块 ${moduleTitle} 内容未改变,跳过`);
614
+ logger.info(`[SyncModule] 🟡 模块 ${moduleTitle} 内容未改变,跳过`);
611
615
  return { success: true, reason: "no_change" };
612
616
  }
613
617
  await newSite.save(
@@ -615,17 +619,17 @@ async function syncSingleModule(oldSite, newSite, moduleTitle, user) {
615
619
  oldContent,
616
620
  `由:${user || "同步坤器人手动"} 触发更改,此时同步`
617
621
  );
618
- console.log(`[SyncModule] ✅ 模块 ${moduleTitle} 同步成功`);
622
+ logger.info(`[SyncModule] ✅ 模块 ${moduleTitle} 同步成功`);
619
623
  return { success: true, reason: "synced" };
620
624
  } catch (error) {
621
625
  const errMsg = error.message || String(error);
622
- console.error(`[SyncModule] ❌ 模块 ${moduleTitle} 同步失败:`, errMsg);
626
+ logger.error(`[SyncModule] ❌ 模块 ${moduleTitle} 同步失败:`, errMsg);
623
627
  return { success: false, reason: errMsg };
624
628
  }
625
629
  }
626
630
  __name(syncSingleModule, "syncSingleModule");
627
631
  async function getAllModules(site) {
628
- console.log(
632
+ logger.info(
629
633
  `[SyncAllModules] 📥 开始获取原站点所有模块(命名空间${CONFIG3.MODLE_NAMESPACE})`
630
634
  );
631
635
  const allModules = [];
@@ -640,9 +644,9 @@ async function getAllModules(site) {
640
644
  for await (const res of queryGen) {
641
645
  const moduleTitles = res.query?.allpages?.map((page) => page.title) || [];
642
646
  allModules.push(...moduleTitles);
643
- console.log(`[SyncAllModules] 📄 已获取 ${allModules.length} 个模块`);
647
+ logger.info(`[SyncAllModules] 📄 已获取 ${allModules.length} 个模块`);
644
648
  }
645
- console.log(
649
+ logger.info(
646
650
  `[SyncAllModules] 📊 原站点总计获取到 ${allModules.length} 个模块`
647
651
  );
648
652
  return allModules;
@@ -653,20 +657,20 @@ async function syncModules(oldSite, newSite) {
653
657
  const oldModuleList = await getAllModules(oldSite);
654
658
  const total = oldModuleList.length;
655
659
  if (total === 0) {
656
- console.log(`[SyncAllModules] 📭 原站点无模块可同步,结束`);
660
+ logger.info(`[SyncAllModules] 📭 原站点无模块可同步,结束`);
657
661
  return;
658
662
  }
659
663
  let successCount = 0;
660
664
  let failCount = 0;
661
665
  let skipCount = 0;
662
666
  const failedModules = [];
663
- console.log(`[SyncAllModules] 🚦 开始批量同步,总计 ${total} 个模块`);
667
+ logger.info(`[SyncAllModules] 🚦 开始批量同步,总计 ${total} 个模块`);
664
668
  for (let index = 0; index < total; index++) {
665
669
  const moduleTitle = oldModuleList[index];
666
670
  const current = index + 1;
667
671
  const remaining = total - current;
668
672
  const progress = (current / total * 100).toFixed(1);
669
- console.log(
673
+ logger.info(
670
674
  `
671
675
  [SyncAllModules] 📈 进度 [${current}/${total}] (${progress}%) - 处理 ${moduleTitle} | 剩余 ${remaining} 个`
672
676
  );
@@ -679,23 +683,23 @@ async function syncModules(oldSite, newSite) {
679
683
  if (!syncResult.success) {
680
684
  failCount++;
681
685
  failedModules.push(moduleTitle);
682
- await (0, import_koishi3.sleep)(CONFIG3.SYNC_INTERVAL_FAILED);
686
+ await (0, import_koishi4.sleep)(CONFIG3.SYNC_INTERVAL_FAILED);
683
687
  } else {
684
688
  successCount++;
685
689
  if (syncResult.reason === "ignored" || syncResult.reason === "no_change") {
686
690
  skipCount++;
687
691
  }
688
- await (0, import_koishi3.sleep)(CONFIG3.SYNC_INTERVAL_SUCCESS);
692
+ await (0, import_koishi4.sleep)(CONFIG3.SYNC_INTERVAL_SUCCESS);
689
693
  }
690
694
  }
691
695
  if (failedModules.length > 0) {
692
- console.log(
696
+ logger.info(
693
697
  `
694
698
  [SyncAllModules] 🔄 ===== 开始重试 ${failedModules.length} 个失败模块 =====`
695
699
  );
696
700
  const stillFailed = [];
697
701
  for (const moduleTitle of failedModules) {
698
- console.log(`
702
+ logger.info(`
699
703
  [SyncAllModules] 🔁 重试中: ${moduleTitle}`);
700
704
  const syncResult = await syncSingleModule(
701
705
  oldSite,
@@ -709,32 +713,32 @@ async function syncModules(oldSite, newSite) {
709
713
  if (syncResult.reason === "ignored" || syncResult.reason === "no_change") {
710
714
  skipCount++;
711
715
  }
712
- console.log(`[SyncAllModules] ✅ 模块 ${moduleTitle} 重试成功`);
713
- await (0, import_koishi3.sleep)(CONFIG3.SYNC_INTERVAL_SUCCESS);
716
+ logger.info(`[SyncAllModules] ✅ 模块 ${moduleTitle} 重试成功`);
717
+ await (0, import_koishi4.sleep)(CONFIG3.SYNC_INTERVAL_SUCCESS);
714
718
  } else {
715
719
  stillFailed.push(moduleTitle);
716
- console.log(`[SyncAllModules] ❌ 模块 ${moduleTitle} 再次失败`);
717
- await (0, import_koishi3.sleep)(CONFIG3.SYNC_INTERVAL_FAILED);
720
+ logger.info(`[SyncAllModules] ❌ 模块 ${moduleTitle} 再次失败`);
721
+ await (0, import_koishi4.sleep)(CONFIG3.SYNC_INTERVAL_FAILED);
718
722
  }
719
723
  }
720
- console.log(`
724
+ logger.info(`
721
725
  [SyncAllModules] 📋 ===== 最终同步报告 =====`);
722
726
  if (stillFailed.length > 0) {
723
- console.log(`❌ 以下模块经过重试仍然失败,请手动检查:`);
727
+ logger.info(`❌ 以下模块经过重试仍然失败,请手动检查:`);
724
728
  stillFailed.forEach((title, idx) => {
725
- console.log(` ${idx + 1}. ${title}`);
729
+ logger.info(` ${idx + 1}. ${title}`);
726
730
  });
727
731
  } else {
728
- console.log(`🎉 所有模块同步成功(含重试)!`);
732
+ logger.info(`🎉 所有模块同步成功(含重试)!`);
729
733
  }
730
734
  }
731
- console.log(`
735
+ logger.info(`
732
736
  [SyncAllModules] 🎯 同步完成!`);
733
- console.log(`├─ 总计:${total} 个模块`);
734
- console.log(`├─ 成功:${successCount} 个(含跳过 ${skipCount} 个)`);
735
- console.log(`└─ 失败:${failCount} 个`);
737
+ logger.info(`├─ 总计:${total} 个模块`);
738
+ logger.info(`├─ 成功:${successCount} 个(含跳过 ${skipCount} 个)`);
739
+ logger.info(`└─ 失败:${failCount} 个`);
736
740
  } catch (error) {
737
- console.error(`[SyncAllModules] 💥 批量同步流程异常终止:`, error);
741
+ logger.error(`[SyncAllModules] 💥 批量同步流程异常终止:`, error);
738
742
  throw error;
739
743
  }
740
744
  }
@@ -743,18 +747,18 @@ __name(syncModules, "syncModules");
743
747
  // src/index.ts
744
748
  var name = "oni-sync-bot";
745
749
  var inject = ["console", "database", "server", "cron"];
746
- var Config = import_koishi4.Schema.object({
747
- ggUsername: import_koishi4.Schema.string().description("WIKIGG 用户名").default("${{ env.ggUsername }}"),
748
- ggPassword: import_koishi4.Schema.string().description("WIKIGG 密码").default("${{ env.ggPassword }}"),
749
- huijiUsername: import_koishi4.Schema.string().description("灰机wiki 用户名").default("${{ env.huijiUsername }}"),
750
- huijiPassword: import_koishi4.Schema.string().description("灰机wiki 密码").default("${{ env.huijiPassword }}"),
751
- huijiUAKey: import_koishi4.Schema.string().description("灰机wiki UAKey").default("${{ env.huijiUAKey }}"),
752
- domain: import_koishi4.Schema.string().description("你的短链域名(必填,如:klei.vip)").default("klei.vip"),
753
- main_site: import_koishi4.Schema.string().description("主站域名(必填,如:oxygennotincluded.wiki.gg)").default("oxygennotincluded.wiki.gg/zh"),
754
- mirror_site: import_koishi4.Schema.string().description("镜像站域名(必填,如:wiki.biligame.com)").default("wiki.biligame.com/oni")
750
+ var Config = import_koishi5.Schema.object({
751
+ ggUsername: import_koishi5.Schema.string().description("WIKIGG 用户名").default("${{ env.ggUsername }}"),
752
+ ggPassword: import_koishi5.Schema.string().description("WIKIGG 密码").default("${{ env.ggPassword }}"),
753
+ huijiUsername: import_koishi5.Schema.string().description("灰机wiki 用户名").default("${{ env.huijiUsername }}"),
754
+ huijiPassword: import_koishi5.Schema.string().description("灰机wiki 密码").default("${{ env.huijiPassword }}"),
755
+ huijiUAKey: import_koishi5.Schema.string().description("灰机wiki UAKey").default("${{ env.huijiUAKey }}"),
756
+ domain: import_koishi5.Schema.string().description("你的短链域名(必填,如:klei.vip)").default("klei.vip"),
757
+ main_site: import_koishi5.Schema.string().description("主站域名(必填,如:oxygennotincluded.wiki.gg)").default("oxygennotincluded.wiki.gg/zh"),
758
+ mirror_site: import_koishi5.Schema.string().description("镜像站域名(必填,如:wiki.biligame.com)").default("wiki.biligame.com/oni")
755
759
  });
756
760
  function apply(ctx, config) {
757
- const logger = ctx.logger("oni-sync-bot");
761
+ const logger2 = ctx.logger("oni-sync-bot");
758
762
  let ggbot;
759
763
  let huijibot;
760
764
  ctx.inject(["console"], (ctx2) => {
@@ -794,30 +798,30 @@ function apply(ctx, config) {
794
798
  router.redirect(targetUrl);
795
799
  });
796
800
  ctx.on("ready", async () => {
797
- logger.info("初始化中...");
801
+ logger2.info("初始化中...");
798
802
  const sitesConfig = getSitesConfig(config);
799
803
  ggbot = await login(sitesConfig.gg);
800
804
  huijibot = await login(sitesConfig.huiji);
801
805
  if (ggbot.login && huijibot.login) {
802
- logger.info("登录成功,插件已准备就绪");
806
+ logger2.info("登录成功,插件已准备就绪");
803
807
  } else {
804
- logger.error("登录失败,请检查配置");
808
+ logger2.error("登录失败,请检查配置");
805
809
  }
806
810
  ctx.cron("15 * * * *", async () => {
807
811
  await incrementalUpdate(ggbot, huijibot, config);
808
812
  });
809
813
  ctx.cron("30 8 * * 4", async () => {
810
814
  await syncPages(ggbot, huijibot).then(() => {
811
- logger.info("自动任务:尝试同步所有页面,从 WIKIGG 到 灰机wiki");
815
+ logger2.info("自动任务:尝试同步所有页面,从 WIKIGG 到 灰机wiki");
812
816
  }).catch((err) => {
813
- logger.error(`同步所有页面失败,错误信息:${err}`);
817
+ logger2.error(`同步所有页面失败,错误信息:${err}`);
814
818
  });
815
819
  });
816
820
  ctx.cron("30 8 * * 3", async () => {
817
821
  await syncAllImages(ggbot, huijibot, config).then(() => {
818
- logger.info("自动任务:尝试同步所有图片,从 WIKIGG 到 灰机wiki");
822
+ logger2.info("自动任务:尝试同步所有图片,从 WIKIGG 到 灰机wiki");
819
823
  }).catch((err) => {
820
- logger.error(`同步所有图片失败,错误信息:${err}`);
824
+ logger2.error(`同步所有图片失败,错误信息:${err}`);
821
825
  });
822
826
  });
823
827
  });
@@ -989,7 +993,7 @@ function apply(ctx, config) {
989
993
  format: "json",
990
994
  aplimit: "max"
991
995
  });
992
- logger.info("主站页面查询成功");
996
+ logger2.info("主站页面查询成功");
993
997
  const pages = res.query.allpages || [];
994
998
  const pageData = pages.map((page) => {
995
999
  const { pinyin_full, pinyin_first } = generatePinyinInfo(page.title);
@@ -1004,9 +1008,9 @@ function apply(ctx, config) {
1004
1008
  await ctx.database.upsert("wikipages", pageData);
1005
1009
  }
1006
1010
  session.send(`✅ 检索到 ${pages.length} 个页面,已更新至数据库`);
1007
- logger.info(`检索到 ${pages.length} 个页面,已更新至数据库`);
1011
+ logger2.info(`检索到 ${pages.length} 个页面,已更新至数据库`);
1008
1012
  } catch (err) {
1009
- logger.error("主站缓存更新失败", err);
1013
+ logger2.error("主站缓存更新失败", err);
1010
1014
  session.send("❌ 主站缓存更新失败,请联系管理员查看日志");
1011
1015
  }
1012
1016
  });
@@ -1014,9 +1018,9 @@ function apply(ctx, config) {
1014
1018
  try {
1015
1019
  const count = await ctx.database.remove("wikipages", {});
1016
1020
  session.send(`✅ 已删除 ${count.removed} 条本地缓存`);
1017
- logger.info(`已删除 ${count.removed} 条本地缓存`);
1021
+ logger2.info(`已删除 ${count.removed} 条本地缓存`);
1018
1022
  } catch (err) {
1019
- logger.error("删除缓存失败", err);
1023
+ logger2.error("删除缓存失败", err);
1020
1024
  session.send("❌ 删除缓存失败,请联系管理员查看日志");
1021
1025
  }
1022
1026
  });
@@ -1024,9 +1028,9 @@ function apply(ctx, config) {
1024
1028
  try {
1025
1029
  const pages = await ctx.database.get("wikipages", {});
1026
1030
  session.send(`📊 数据库中缓存了 ${pages.length} 条页面`);
1027
- logger.info(`数据库中缓存了 ${pages.length} 条页面`);
1031
+ logger2.info(`数据库中缓存了 ${pages.length} 条页面`);
1028
1032
  } catch (err) {
1029
- logger.error("查询缓存状态失败", err);
1033
+ logger2.error("查询缓存状态失败", err);
1030
1034
  session.send("❌ 查询缓存状态失败,请联系管理员查看日志");
1031
1035
  }
1032
1036
  });
@@ -1042,11 +1046,11 @@ function apply(ctx, config) {
1042
1046
  `#REDIRECT [[${targetPageName}]]`,
1043
1047
  "来自qq机器人的添加重定向页面请求"
1044
1048
  );
1045
- logger.info(`已为 ${pageName} 添加重定向至 ${targetPageName}`);
1049
+ logger2.info(`已为 ${pageName} 添加重定向至 ${targetPageName}`);
1046
1050
  session.send(`✅ 已尝试添加重定向 ${pageName} -> ${targetPageName}`);
1047
1051
  await session.execute(`update`);
1048
1052
  } catch (err) {
1049
- logger.error(`添加重定向 ${pageName} -> ${targetPageName} 失败`, err);
1053
+ logger2.error(`添加重定向 ${pageName} -> ${targetPageName} 失败`, err);
1050
1054
  session.send(`❌ 添加重定向失败,请联系管理员查看日志`);
1051
1055
  }
1052
1056
  });
@@ -1,3 +1,4 @@
1
+ import { Logger } from "koishi";
1
2
  import { Mwn } from "mwn";
2
3
  /**
3
4
  * 获取并处理页面内容
@@ -15,4 +16,5 @@ declare function generatePinyinInfo(text: string): {
15
16
  pinyin_full: string;
16
17
  pinyin_first: string;
17
18
  };
18
- export { getAndProcessPageContent, generatePinyinInfo };
19
+ declare const logger: Logger;
20
+ export { getAndProcessPageContent, generatePinyinInfo, logger };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-oni-sync-bot",
3
3
  "description": "缺氧Wiki站镜像点同步-测试",
4
- "version": "0.0.2",
4
+ "version": "0.0.3",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [