@cloud411716/fancy-webnovel 1.0.10 → 1.0.12
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/commands/scan/index.js +23 -0
- package/index.js +6 -7
- package/package.json +1 -1
package/commands/scan/index.js
CHANGED
|
@@ -110,6 +110,10 @@ const scan = {
|
|
|
110
110
|
|
|
111
111
|
const SCRAPERS = { qidian, fanqie, jinjiang, qimao };
|
|
112
112
|
|
|
113
|
+
// ASCII spinner sequence for live progress feedback during scraping
|
|
114
|
+
const SPINNER = ['|', '/', '—', '\\'];
|
|
115
|
+
let _spinnerIdx = 0;
|
|
116
|
+
|
|
113
117
|
/**
|
|
114
118
|
* @param {object} ctx - Cordis plugin context
|
|
115
119
|
*/
|
|
@@ -190,6 +194,22 @@ export function apply(ctx) {
|
|
|
190
194
|
}
|
|
191
195
|
|
|
192
196
|
// ---------- in-process scraping (no subprocess) ----------
|
|
197
|
+
|
|
198
|
+
// Register scan-progress listeners before scraping starts, clean up after.
|
|
199
|
+
// Each fired event sends an ASCII spinner followup so the user sees live
|
|
200
|
+
// progress instead of a blank screen while the scraper runs.
|
|
201
|
+
const disposers = [];
|
|
202
|
+
let currentRankLabel = '';
|
|
203
|
+
|
|
204
|
+
disposers.push(ctx.events.on('fancy/scan:start', (_ctx, platform, _channel, _type, label) => {
|
|
205
|
+
currentRankLabel = label;
|
|
206
|
+
llmFollowup(invocation, `[${SPINNER[_spinnerIdx++ % 4]}] 正在采集:${platformLabel(platform)} ${label} …`);
|
|
207
|
+
}));
|
|
208
|
+
|
|
209
|
+
disposers.push(ctx.events.on('fancy/scan:rank-done', (_ctx, _platform, _channel, _type, ok, written) => {
|
|
210
|
+
llmFollowup(invocation, `[${SPINNER[_spinnerIdx++ % 4]}] ${currentRankLabel} ${ok ? `✓ 写入 ${written} 条` : '✗ 失败'}`);
|
|
211
|
+
}));
|
|
212
|
+
|
|
193
213
|
const { totalBooks, totalFiles, failedRanks, lastReceipt } = await runScans(
|
|
194
214
|
ctx,
|
|
195
215
|
projectRoot,
|
|
@@ -197,6 +217,9 @@ export function apply(ctx) {
|
|
|
197
217
|
signal,
|
|
198
218
|
);
|
|
199
219
|
|
|
220
|
+
// Clean up progress listeners; runScans is done.
|
|
221
|
+
for (const d of disposers) d();
|
|
222
|
+
|
|
200
223
|
// ---------- output results ----------
|
|
201
224
|
if (lastReceipt && totalFiles > 0) {
|
|
202
225
|
notify(session, scan.notify({
|
package/index.js
CHANGED
|
@@ -57,24 +57,23 @@ export function apply(ctx) {
|
|
|
57
57
|
type: 'object',
|
|
58
58
|
additionalProperties: true,
|
|
59
59
|
properties: {
|
|
60
|
-
id: { type: 'string',
|
|
61
|
-
question: { type: 'string',
|
|
62
|
-
header: { type: 'string',
|
|
60
|
+
id: { type: 'string', required: true, description: 'Stable id for this question; echoed in the answer.' },
|
|
61
|
+
question: { type: 'string', required: true, description: 'The specific question to ask the user.' },
|
|
62
|
+
header: { type: 'string', description: 'Optional short heading for the question.' },
|
|
63
63
|
options: {
|
|
64
64
|
type: 'array',
|
|
65
|
-
required: false,
|
|
66
65
|
description: 'Optional choices to show the user.',
|
|
67
66
|
items: {
|
|
68
67
|
type: 'object',
|
|
69
68
|
additionalProperties: true,
|
|
70
69
|
properties: {
|
|
71
70
|
label: { type: 'string', required: true, description: 'Short user-facing option label.' },
|
|
72
|
-
description: { type: 'string',
|
|
71
|
+
description: { type: 'string', description: 'One sentence explaining the option.' },
|
|
73
72
|
},
|
|
74
73
|
},
|
|
75
74
|
},
|
|
76
|
-
multi_select:
|
|
77
|
-
hideCustomInput: { type: 'boolean'
|
|
75
|
+
multi_select: { type: 'boolean' },
|
|
76
|
+
hideCustomInput: { type: 'boolean' },
|
|
78
77
|
},
|
|
79
78
|
},
|
|
80
79
|
},
|