karin-plugin-qgroup-file2openlist 0.0.30 → 0.0.31
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/config/config.json +1 -1
- package/lib/apps/groupFiles.backup.js +1 -1
- package/lib/apps/groupFiles.js +1 -1
- package/lib/apps/groupSyncConfig.js +2 -2
- package/lib/apps/scheduler.js +2 -2
- package/lib/apps/sendMsg.js +4 -4
- package/lib/{chunk-KB5N77CR.js → chunk-2Z6KEH2L.js} +103 -33
- package/lib/{chunk-CE6KVBH4.js → chunk-DR4WWLFE.js} +1 -1
- package/package.json +1 -1
package/config/config.json
CHANGED
package/lib/apps/groupFiles.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handleGroupSyncConfigCommand
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-DR4WWLFE.js";
|
|
4
|
+
import "../chunk-2Z6KEH2L.js";
|
|
5
5
|
import "../chunk-YQPHJTEB.js";
|
|
6
6
|
import "../chunk-NWUWEQLH.js";
|
|
7
7
|
import "../chunk-DA4U55JC.js";
|
package/lib/apps/scheduler.js
CHANGED
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
} from "../chunk-VVJJTF2N.js";
|
|
4
4
|
import {
|
|
5
5
|
runNightlyGroupBackup
|
|
6
|
-
} from "../chunk-
|
|
7
|
-
import "../chunk-
|
|
6
|
+
} from "../chunk-DR4WWLFE.js";
|
|
7
|
+
import "../chunk-2Z6KEH2L.js";
|
|
8
8
|
import "../chunk-YQPHJTEB.js";
|
|
9
9
|
import "../chunk-NWUWEQLH.js";
|
|
10
10
|
import {
|
package/lib/apps/sendMsg.js
CHANGED
|
@@ -38,7 +38,7 @@ ${randomMsg}`;
|
|
|
38
38
|
/** 谁可以触发这个插件 'all' | 'master' | 'admin' | 'group.owner' | 'group.admin' */
|
|
39
39
|
permission: "all"
|
|
40
40
|
});
|
|
41
|
-
var forwardMessage = karin.command(
|
|
41
|
+
var forwardMessage = karin.command(/^#测dscvdf试转发$/, async (e) => {
|
|
42
42
|
if (!e.isPrivate) return false;
|
|
43
43
|
const message = [
|
|
44
44
|
segment.text("\u{1F31F} \u8FD9\u662F\u8F6C\u53D1\u7684\u7B2C\u4E00\u6761\u6D88\u606F \u{1F31F}"),
|
|
@@ -58,7 +58,7 @@ var forwardMessage = karin.command(/^#测试转发$/, async (e) => {
|
|
|
58
58
|
/** 谁可以触发这个插件 'all' | 'master' | 'admin' | 'group.owner' | 'group.admin' */
|
|
59
59
|
permission: "all"
|
|
60
60
|
});
|
|
61
|
-
var randomEmoji = karin.command(
|
|
61
|
+
var randomEmoji = karin.command(/^#随机sdccasc表情$/, async (e) => {
|
|
62
62
|
if (!e.isPrivate) return false;
|
|
63
63
|
const emojiUrls = [
|
|
64
64
|
"https://i.imgur.com/XaUdU2C.gif",
|
|
@@ -80,7 +80,7 @@ var randomEmoji = karin.command(/^#随机表情$/, async (e) => {
|
|
|
80
80
|
name: "\u968F\u673A\u8868\u60C5\u5305demo",
|
|
81
81
|
permission: "all"
|
|
82
82
|
});
|
|
83
|
-
var dailyQuote = karin.command(
|
|
83
|
+
var dailyQuote = karin.command(/^#每日ds cas一言$/, async (e) => {
|
|
84
84
|
if (!e.isPrivate) return false;
|
|
85
85
|
const quotes = [
|
|
86
86
|
"\u4ECA\u5929\u4E5F\u662F\u5145\u6EE1\u5E0C\u671B\u7684\u4E00\u5929\uFF01\u52A0\u6CB9\uFF01\u2728",
|
|
@@ -103,7 +103,7 @@ var dailyQuote = karin.command(/^#每日一言$/, async (e) => {
|
|
|
103
103
|
name: "\u6BCF\u65E5\u4E00\u8A00demo",
|
|
104
104
|
permission: "all"
|
|
105
105
|
});
|
|
106
|
-
var weatherForecast = karin.command(
|
|
106
|
+
var weatherForecast = karin.command(/^#今日 sdvsdv天气$/, async (e) => {
|
|
107
107
|
if (!e.isPrivate) return false;
|
|
108
108
|
const weathers = [
|
|
109
109
|
"\u2600\uFE0F \u6674\u5929\uFF0C\u6E29\u5EA625\xB0C\uFF0C\u9002\u5408\u51FA\u95E8\u73A9\u800D~",
|
|
@@ -103,7 +103,13 @@ var getGroupFileListCompat = async (bot, groupId, folderId) => {
|
|
|
103
103
|
}
|
|
104
104
|
throw new Error("\u5F53\u524D\u9002\u914D\u5668\u4E0D\u652F\u6301\u83B7\u53D6\u7FA4\u6587\u4EF6\u5217\u8868\uFF08getGroupFileList / getGroupRootFiles / getGroupFilesByFolder \u5747\u4E0D\u53EF\u7528\uFF09");
|
|
105
105
|
};
|
|
106
|
-
var
|
|
106
|
+
var isRetryableResolveGroupFileUrlError = (error) => {
|
|
107
|
+
const msg = formatErrorMessage(error);
|
|
108
|
+
if (/缺少 fileId|群号无法转换为 number|未找到可用接口/.test(msg)) return false;
|
|
109
|
+
if (/不存在|not found|file not found/i.test(msg)) return false;
|
|
110
|
+
return /请求错误|sendApi|限流|频繁|风控|rate|limit|429|Too Many Requests|getFileUrl|nc_getFile|getGroupFileUrl|超时|timeout|ECONNRESET|ETIMEDOUT|EAI_AGAIN|ENOTFOUND|ECONNREFUSED|UND_ERR|socket hang up/i.test(msg);
|
|
111
|
+
};
|
|
112
|
+
var resolveGroupFileUrlOnce = async (bot, contact, groupId, file) => {
|
|
107
113
|
if (!file.fileId) throw new Error("\u7F3A\u5C11 fileId");
|
|
108
114
|
const reasons = [];
|
|
109
115
|
if (typeof bot?.getFileUrl === "function") {
|
|
@@ -160,6 +166,27 @@ var resolveGroupFileUrl = async (bot, contact, groupId, file) => {
|
|
|
160
166
|
}
|
|
161
167
|
throw new Error(reasons[0] ?? "\u65E0\u6CD5\u83B7\u53D6\u4E0B\u8F7D URL\uFF08\u672A\u627E\u5230\u53EF\u7528\u63A5\u53E3\uFF09");
|
|
162
168
|
};
|
|
169
|
+
var resolveGroupFileUrl = async (bot, contact, groupId, file, options) => {
|
|
170
|
+
const retries = Math.max(0, Math.floor(options?.retries ?? 2));
|
|
171
|
+
const delayMs = Math.max(0, Math.floor(options?.delayMs ?? 1200));
|
|
172
|
+
const maxDelayMs = Math.max(delayMs, Math.floor(options?.maxDelayMs ?? 15e3));
|
|
173
|
+
let lastError;
|
|
174
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
175
|
+
try {
|
|
176
|
+
return await resolveGroupFileUrlOnce(bot, contact, groupId, file);
|
|
177
|
+
} catch (error) {
|
|
178
|
+
lastError = error;
|
|
179
|
+
if (attempt >= retries) break;
|
|
180
|
+
if (!isRetryableResolveGroupFileUrlError(error)) break;
|
|
181
|
+
const backoff = delayMs * Math.pow(2, attempt);
|
|
182
|
+
const capped = Math.min(maxDelayMs, backoff);
|
|
183
|
+
const jittered = Math.floor(capped * (0.8 + Math.random() * 0.4));
|
|
184
|
+
if (jittered > 0) await sleep(jittered);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (lastError) throw lastError;
|
|
188
|
+
throw new Error("\u65E0\u6CD5\u83B7\u53D6\u4E0B\u8F7D URL");
|
|
189
|
+
};
|
|
163
190
|
var collectAllGroupFiles = async (bot, groupId, startFolderId) => {
|
|
164
191
|
const files = [];
|
|
165
192
|
const visitedFolders = /* @__PURE__ */ new Set();
|
|
@@ -366,6 +393,34 @@ var MAX_FILE_TIMEOUT_SEC = 3e3;
|
|
|
366
393
|
var MIN_FILE_TIMEOUT_SEC = 10;
|
|
367
394
|
var DEFAULT_PROGRESS_REPORT_EVERY = 10;
|
|
368
395
|
var MAX_TRANSFER_CONCURRENCY = 5;
|
|
396
|
+
var createAsyncLimiter = (concurrency) => {
|
|
397
|
+
const limit = Math.max(1, Math.floor(concurrency) || 1);
|
|
398
|
+
let active = 0;
|
|
399
|
+
const queue = [];
|
|
400
|
+
const acquire = async () => {
|
|
401
|
+
if (active < limit) {
|
|
402
|
+
active++;
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
await new Promise((resolve) => queue.push(resolve));
|
|
406
|
+
};
|
|
407
|
+
const release = () => {
|
|
408
|
+
const next = queue.shift();
|
|
409
|
+
if (next) {
|
|
410
|
+
next();
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
active = Math.max(0, active - 1);
|
|
414
|
+
};
|
|
415
|
+
return async (fn) => {
|
|
416
|
+
await acquire();
|
|
417
|
+
try {
|
|
418
|
+
return await fn();
|
|
419
|
+
} finally {
|
|
420
|
+
release();
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
};
|
|
369
424
|
var buildRemotePathForItem = (item, targetDir, flat) => {
|
|
370
425
|
const relativeParts = (flat ? [item.name] : item.path.split("/")).filter(Boolean).map(safePathSegment);
|
|
371
426
|
return normalizePosixPath(path2.posix.join(targetDir, ...relativeParts));
|
|
@@ -483,24 +538,38 @@ var syncGroupFilesToOpenListCore = async (params) => {
|
|
|
483
538
|
report && await report(`\u6CA1\u6709\u9700\u8981\u540C\u6B65\u7684\u6587\u4EF6\uFF08\u589E\u91CF\u6A21\u5F0F\u5DF2\u8DF3\u8FC7 ${skipped} \u6761\uFF09\u3002`);
|
|
484
539
|
return { total: limitedList.length, skipped, urlOk: 0, ok: 0, fail: 0 };
|
|
485
540
|
}
|
|
541
|
+
report && await report("\u5C06\u6309\u9700\u89E3\u6790\u4E0B\u8F7D URL\uFF08\u907F\u514D\u6279\u91CF\u9884\u53D6\u5BFC\u81F4 URL \u8FC7\u671F/\u89E6\u53D1\u9650\u6D41\uFF09");
|
|
486
542
|
const urlErrors = [];
|
|
487
|
-
await runWithConcurrency(needSync, Math.max(1, Math.floor(urlConcurrency) || 1), async ({ item }) => {
|
|
488
|
-
try {
|
|
489
|
-
item.url = await resolveGroupFileUrl(bot, groupContact, groupId, item);
|
|
490
|
-
} catch (error) {
|
|
491
|
-
urlErrors.push({ fileId: item.fileId, path: item.path, message: formatErrorMessage(error) });
|
|
492
|
-
}
|
|
493
|
-
});
|
|
494
|
-
const withUrl = needSync.filter(({ item }) => typeof item.url === "string" && item.url).map((v) => v);
|
|
495
|
-
report && await report(`URL\u83B7\u53D6\u5B8C\u6210\uFF1A\u6210\u529F ${withUrl.length} / \u5931\u8D25 ${needSync.length - withUrl.length}\uFF08\u589E\u91CF\u8DF3\u8FC7 ${skipped}\uFF09`);
|
|
496
|
-
if (!withUrl.length) {
|
|
497
|
-
report && await report("\u6CA1\u6709\u53EF\u7528\u7684\u4E0B\u8F7D URL\uFF0C\u65E0\u6CD5\u540C\u6B65\u5230 OpenList");
|
|
498
|
-
return { total: limitedList.length, skipped, urlOk: 0, ok: 0, fail: 0 };
|
|
499
|
-
}
|
|
500
543
|
const syncErrors = [];
|
|
544
|
+
const urlOkSet = /* @__PURE__ */ new Set();
|
|
501
545
|
let okCount = 0;
|
|
502
546
|
const shouldRefreshUrl = (message) => {
|
|
503
|
-
return /403|URL已过期|url已过期|url可能已失效|需要重新获取|下载超时/.test(message);
|
|
547
|
+
return /401|403|404|URL已过期|url已过期|url可能已失效|需要重新获取|下载超时/.test(message);
|
|
548
|
+
};
|
|
549
|
+
const resolveUrlWithLimit = createAsyncLimiter(Math.max(1, Math.floor(urlConcurrency) || 1));
|
|
550
|
+
const urlResolveOptions = {
|
|
551
|
+
retries: 2,
|
|
552
|
+
delayMs: retryDelayMs > 0 ? Math.floor(retryDelayMs) : void 0,
|
|
553
|
+
maxDelayMs: 2e4
|
|
554
|
+
};
|
|
555
|
+
const ensureItemUrl = async (item, remotePath) => {
|
|
556
|
+
const existing = typeof item.url === "string" ? item.url.trim() : "";
|
|
557
|
+
if (existing) {
|
|
558
|
+
urlOkSet.add(remotePath);
|
|
559
|
+
return existing;
|
|
560
|
+
}
|
|
561
|
+
try {
|
|
562
|
+
const url = await resolveUrlWithLimit(
|
|
563
|
+
() => resolveGroupFileUrl(bot, groupContact, groupId, item, urlResolveOptions)
|
|
564
|
+
);
|
|
565
|
+
const cleaned = typeof url === "string" ? url.trim() : "";
|
|
566
|
+
if (!cleaned) throw new Error("\u8FD4\u56DE\u7A7A URL");
|
|
567
|
+
item.url = cleaned;
|
|
568
|
+
urlOkSet.add(remotePath);
|
|
569
|
+
return cleaned;
|
|
570
|
+
} catch (error) {
|
|
571
|
+
throw new Error(`URL\u83B7\u53D6\u5931\u8D25: ${formatErrorMessage(error)}`);
|
|
572
|
+
}
|
|
504
573
|
};
|
|
505
574
|
const transferOne = async (sourceUrl, targetUrl, expectedSize) => {
|
|
506
575
|
await downloadAndUploadByWebDav({
|
|
@@ -516,7 +585,7 @@ var syncGroupFilesToOpenListCore = async (params) => {
|
|
|
516
585
|
const transferInitial = Math.min(MAX_TRANSFER_CONCURRENCY, Math.max(1, Math.floor(transferConcurrency) || 1));
|
|
517
586
|
const adaptiveTransfer = effectiveRateLimitBytesPerSec <= 0;
|
|
518
587
|
const transferFn = async ({ item, remotePath }, index) => {
|
|
519
|
-
logger2.info(`[\u7FA4\u6587\u4EF6\u540C\u6B65][${groupId}] \u540C\u6B65\u4E2D(${index + 1}/${
|
|
588
|
+
logger2.info(`[\u7FA4\u6587\u4EF6\u540C\u6B65][${groupId}] \u540C\u6B65\u4E2D(${index + 1}/${needSync.length}): ${item.path}`);
|
|
520
589
|
const remoteDir = normalizePosixPath(path2.posix.dirname(remotePath));
|
|
521
590
|
const targetUrl = `${davBaseUrl}${encodePathForUrl(remotePath)}`;
|
|
522
591
|
let lastError;
|
|
@@ -525,8 +594,7 @@ var syncGroupFilesToOpenListCore = async (params) => {
|
|
|
525
594
|
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
526
595
|
try {
|
|
527
596
|
await dirEnsurer.ensureDir(remoteDir);
|
|
528
|
-
const currentUrl = item
|
|
529
|
-
if (!currentUrl) throw new Error("\u7F3A\u5C11\u4E0B\u8F7D URL");
|
|
597
|
+
const currentUrl = await ensureItemUrl(item, remotePath);
|
|
530
598
|
await transferOne(currentUrl, targetUrl, item.size);
|
|
531
599
|
okCount++;
|
|
532
600
|
succeeded = true;
|
|
@@ -545,10 +613,7 @@ var syncGroupFilesToOpenListCore = async (params) => {
|
|
|
545
613
|
const msg = formatErrorMessage(error);
|
|
546
614
|
if (attempt < attempts) {
|
|
547
615
|
if (shouldRefreshUrl(msg)) {
|
|
548
|
-
|
|
549
|
-
item.url = await resolveGroupFileUrl(bot, groupContact, groupId, item);
|
|
550
|
-
} catch {
|
|
551
|
-
}
|
|
616
|
+
item.url = void 0;
|
|
552
617
|
}
|
|
553
618
|
const delay = Math.max(0, Math.floor(retryDelayMs) || 0) * Math.pow(2, attempt - 1);
|
|
554
619
|
if (delay > 0) await new Promise((resolve) => setTimeout(resolve, delay));
|
|
@@ -557,19 +622,24 @@ var syncGroupFilesToOpenListCore = async (params) => {
|
|
|
557
622
|
}
|
|
558
623
|
}
|
|
559
624
|
if (!succeeded && lastError) {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
fileId: item.fileId,
|
|
563
|
-
|
|
564
|
-
|
|
625
|
+
const message = formatErrorMessage(lastError);
|
|
626
|
+
if (message.startsWith("URL\u83B7\u53D6\u5931\u8D25:")) {
|
|
627
|
+
urlErrors.push({ fileId: item.fileId, path: item.path, message });
|
|
628
|
+
} else {
|
|
629
|
+
syncErrors.push({
|
|
630
|
+
path: item.path,
|
|
631
|
+
fileId: item.fileId,
|
|
632
|
+
message
|
|
633
|
+
});
|
|
634
|
+
}
|
|
565
635
|
}
|
|
566
636
|
if (safeProgressReportEvery > 0 && (index + 1) % safeProgressReportEvery === 0) {
|
|
567
|
-
report && await report(`\u540C\u6B65\u8FDB\u5EA6\uFF1A${index + 1}/${
|
|
637
|
+
report && await report(`\u540C\u6B65\u8FDB\u5EA6\uFF1A${index + 1}/${needSync.length}\uFF08\u6210\u529F ${okCount}\uFF09`);
|
|
568
638
|
}
|
|
569
639
|
};
|
|
570
640
|
if (adaptiveTransfer) {
|
|
571
641
|
logger2.info(`[\u7FA4\u6587\u4EF6\u540C\u6B65][${groupId}] \u672A\u914D\u7F6E\u9650\u901F\uFF0C\u5C06\u81EA\u9002\u5E94\u8C03\u6574\u4F20\u8F93\u5E76\u53D1\uFF08\u6700\u591A ${MAX_TRANSFER_CONCURRENCY}\uFF09`);
|
|
572
|
-
await runWithAdaptiveConcurrency(
|
|
642
|
+
await runWithAdaptiveConcurrency(needSync, {
|
|
573
643
|
initial: transferInitial,
|
|
574
644
|
max: MAX_TRANSFER_CONCURRENCY,
|
|
575
645
|
fn: transferFn,
|
|
@@ -578,13 +648,13 @@ var syncGroupFilesToOpenListCore = async (params) => {
|
|
|
578
648
|
}
|
|
579
649
|
});
|
|
580
650
|
} else {
|
|
581
|
-
await runWithConcurrency(
|
|
651
|
+
await runWithConcurrency(needSync, transferInitial, transferFn);
|
|
582
652
|
}
|
|
583
653
|
state.lastSyncAt = Date.now();
|
|
584
654
|
writeGroupSyncState(groupId, state);
|
|
585
|
-
const failCount =
|
|
655
|
+
const failCount = needSync.length - okCount;
|
|
586
656
|
report && await report(`\u540C\u6B65\u5B8C\u6210\uFF1A\u6210\u529F ${okCount} / \u5931\u8D25 ${failCount}\uFF08\u589E\u91CF\u8DF3\u8FC7 ${skipped}\uFF09`);
|
|
587
|
-
if (
|
|
657
|
+
if (syncErrors.length) {
|
|
588
658
|
const preview = syncErrors.slice(0, 5).map((it) => `${it.path} (${it.fileId})
|
|
589
659
|
${it.message}`).join("\n\n");
|
|
590
660
|
report && await report(`\u5931\u8D25\u793A\u4F8B\uFF08\u524D5\u6761\uFF09\uFF1A
|
|
@@ -596,7 +666,7 @@ ${it.message}`).join("\n\n");
|
|
|
596
666
|
report && await report(`URL\u83B7\u53D6\u5931\u8D25\u793A\u4F8B\uFF08\u524D5\u6761\uFF09\uFF1A
|
|
597
667
|
${preview}`);
|
|
598
668
|
}
|
|
599
|
-
return { total: limitedList.length, skipped, urlOk:
|
|
669
|
+
return { total: limitedList.length, skipped, urlOk: urlOkSet.size, ok: okCount, fail: failCount };
|
|
600
670
|
});
|
|
601
671
|
};
|
|
602
672
|
|