pixivflow 2.27.0 → 2.28.0
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/delivery/HttpMultipartDelivery.js +5 -0
- package/dist/delivery/types.d.ts +4 -0
- package/dist/notification/NotificationPolicy.js +19 -9
- package/dist/package.json +1 -1
- package/dist/scheduler/TargetOutcome.d.ts +13 -0
- package/dist/scheduler/TargetOutcome.js +32 -0
- package/dist/version.js +1 -1
- package/dist/webui/package.json +1 -1
- package/package.json +1 -1
|
@@ -171,6 +171,11 @@ class HttpMultipartDelivery {
|
|
|
171
171
|
work_type: t.workType,
|
|
172
172
|
status: t.status,
|
|
173
173
|
work_id: t.workId ?? null,
|
|
174
|
+
terminal_reason_code: t.terminal_reason_code ?? null,
|
|
175
|
+
reason: t.reason ?? null,
|
|
176
|
+
stage: t.stage ?? null,
|
|
177
|
+
retryable: t.retryable ?? null,
|
|
178
|
+
operator_hint: t.operator_hint ?? null,
|
|
174
179
|
})),
|
|
175
180
|
}
|
|
176
181
|
: { text: request.text, idempotency_key: request.idempotencyKey };
|
package/dist/delivery/types.d.ts
CHANGED
|
@@ -142,6 +142,10 @@ export interface DeliveryNotificationRequest {
|
|
|
142
142
|
terminal_reason_code?: string | null;
|
|
143
143
|
/** User-facing business reason message for the failure. */
|
|
144
144
|
reason?: string | null;
|
|
145
|
+
stage?: string | null;
|
|
146
|
+
/** Whether a later/manual attempt may succeed; terminal does not mean auto-retry pending. */
|
|
147
|
+
retryable?: boolean | null;
|
|
148
|
+
operator_hint?: string | null;
|
|
145
149
|
}>;
|
|
146
150
|
};
|
|
147
151
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.NotificationPolicy = void 0;
|
|
4
4
|
const DeliveryService_1 = require("../delivery/DeliveryService");
|
|
5
|
+
const TargetOutcome_1 = require("../scheduler/TargetOutcome");
|
|
5
6
|
const SlotCoordinator_1 = require("../scheduler/SlotCoordinator");
|
|
6
7
|
const logger_1 = require("../logger");
|
|
7
8
|
/**
|
|
@@ -130,15 +131,22 @@ class NotificationPolicy {
|
|
|
130
131
|
},
|
|
131
132
|
}
|
|
132
133
|
: {}),
|
|
133
|
-
targets: rows.map((r) =>
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
134
|
+
targets: rows.map((r) => {
|
|
135
|
+
const code = r.terminal_reason_code;
|
|
136
|
+
const operational = code ? (0, TargetOutcome_1.operationalReasonForCode)(code, r.reason) : null;
|
|
137
|
+
return {
|
|
138
|
+
targetId: r.targetId,
|
|
139
|
+
workType: r.workType,
|
|
140
|
+
status: r.status,
|
|
141
|
+
workId: r.workId,
|
|
142
|
+
error: r.error,
|
|
143
|
+
terminal_reason_code: code ?? null,
|
|
144
|
+
reason: operational?.message ?? r.reason ?? null,
|
|
145
|
+
stage: operational?.stage ?? null,
|
|
146
|
+
retryable: operational?.retryable ?? null,
|
|
147
|
+
operator_hint: operational?.operatorHint ?? null,
|
|
148
|
+
};
|
|
149
|
+
}),
|
|
142
150
|
});
|
|
143
151
|
}
|
|
144
152
|
}
|
|
@@ -179,6 +187,8 @@ class NotificationPolicy {
|
|
|
179
187
|
...cell, label: cell.targetId,
|
|
180
188
|
workType: targets.find((target) => target.id === cell.targetId)?.type ?? 'unknown',
|
|
181
189
|
error: cell.error ?? null,
|
|
190
|
+
terminal_reason_code: cell.terminalReasonCode ?? null,
|
|
191
|
+
reason: cell.terminalReasonMessage ?? null,
|
|
182
192
|
})));
|
|
183
193
|
}
|
|
184
194
|
}
|
package/dist/package.json
CHANGED
|
@@ -277,6 +277,19 @@ export interface TerminalReason {
|
|
|
277
277
|
/** Business-language message an operator/reviewer reads directly. */
|
|
278
278
|
message: string;
|
|
279
279
|
}
|
|
280
|
+
/** Operator-facing recovery semantics derived from the stable reason code.
|
|
281
|
+
*
|
|
282
|
+
* These fields are deliberately derived instead of persisted as a second
|
|
283
|
+
* failure record. The durable SSOT remains the cell's terminal reason code;
|
|
284
|
+
* wording and policy can evolve without rewriting historical slot rows.
|
|
285
|
+
*/
|
|
286
|
+
export interface OperationalReason extends TerminalReason {
|
|
287
|
+
stage: 'acquisition' | 'download' | 'delivery' | 'execution' | 'configuration';
|
|
288
|
+
/** A later/manual attempt may succeed; this does not mean auto-retry is pending. */
|
|
289
|
+
retryable: boolean;
|
|
290
|
+
operatorHint: string;
|
|
291
|
+
}
|
|
292
|
+
export declare function operationalReasonForCode(code: string, message?: string | null): OperationalReason | null;
|
|
280
293
|
/** User-facing business messages — never stack traces, paths, SQL or tokens. */
|
|
281
294
|
export declare const TERMINAL_REASON_MESSAGES: Record<TerminalReasonCode, string>;
|
|
282
295
|
/**
|
|
@@ -11,6 +11,7 @@ exports.hasTransientFailure = hasTransientFailure;
|
|
|
11
11
|
exports.mergeScanSummaries = mergeScanSummaries;
|
|
12
12
|
exports.classifyCandidateFailure = classifyCandidateFailure;
|
|
13
13
|
exports.classifyJobLevelOutage = classifyJobLevelOutage;
|
|
14
|
+
exports.operationalReasonForCode = operationalReasonForCode;
|
|
14
15
|
exports.terminalReasonFor = terminalReasonFor;
|
|
15
16
|
/**
|
|
16
17
|
* A scan that attempted nothing. The real pipeline always reports its own scan;
|
|
@@ -226,6 +227,34 @@ function classifyJobLevelOutage(error) {
|
|
|
226
227
|
const failure = classifyCandidateFailure(error, '');
|
|
227
228
|
return failure.scope === 'job' ? failure.outage : null;
|
|
228
229
|
}
|
|
230
|
+
const OPERATIONAL_REASON_POLICY = {
|
|
231
|
+
no_candidate: { stage: 'acquisition', retryable: true, operatorHint: '可等待下次任务,或使用“放宽条件重试”。' },
|
|
232
|
+
duplicate_exhausted: { stage: 'acquisition', retryable: true, operatorHint: '候选均已处理,可等待新作品或放宽条件重试。' },
|
|
233
|
+
filter_exhausted: { stage: 'acquisition', retryable: true, operatorHint: '检查筛选条件,或使用“放宽条件重试”。' },
|
|
234
|
+
download_timeout: { stage: 'download', retryable: true, operatorHint: '可稍后重试;若持续发生,请检查 Pixiv 连接。' },
|
|
235
|
+
download_failed: { stage: 'download', retryable: true, operatorHint: '可稍后重试;若持续发生,请检查网络与存储空间。' },
|
|
236
|
+
metadata_failed: { stage: 'acquisition', retryable: true, operatorHint: '可稍后重试;若只影响单个作品,请检查作品是否已删除或转为私密。' },
|
|
237
|
+
rate_limited: { stage: 'acquisition', retryable: true, operatorHint: '等待限流窗口结束后再重试。' },
|
|
238
|
+
auth_failed: { stage: 'acquisition', retryable: false, operatorHint: '检查并刷新对应 Pixiv 账号的认证状态。' },
|
|
239
|
+
remote_http_error: { stage: 'acquisition', retryable: true, operatorHint: '可稍后重试;若持续发生,请检查 Pixiv 服务状态。' },
|
|
240
|
+
delivery_failed: { stage: 'delivery', retryable: true, operatorHint: '检查 TelePost 可达性与投稿接口状态后重试。' },
|
|
241
|
+
telepost_rejected: { stage: 'delivery', retryable: false, operatorHint: '检查投稿内容和 TelePost 接口契约。' },
|
|
242
|
+
telegram_failed: { stage: 'delivery', retryable: true, operatorHint: '检查 Telegram 可达性与 Bot 权限后重试。' },
|
|
243
|
+
network_error: { stage: 'execution', retryable: true, operatorHint: '检查执行端网络;恢复后可重试。' },
|
|
244
|
+
execution_timeout: { stage: 'execution', retryable: true, operatorHint: '检查执行耗时和资源使用后重试。' },
|
|
245
|
+
configuration_error: { stage: 'configuration', retryable: false, operatorHint: '修正配置并完成校验后再重试。' },
|
|
246
|
+
internal_error: { stage: 'execution', retryable: false, operatorHint: '查看对应执行记录;若重复发生,请提交诊断信息。' },
|
|
247
|
+
};
|
|
248
|
+
function operationalReasonForCode(code, message) {
|
|
249
|
+
if (!(code in OPERATIONAL_REASON_POLICY))
|
|
250
|
+
return null;
|
|
251
|
+
const knownCode = code;
|
|
252
|
+
return {
|
|
253
|
+
code: knownCode,
|
|
254
|
+
message: message?.trim() || exports.TERMINAL_REASON_MESSAGES[knownCode],
|
|
255
|
+
...OPERATIONAL_REASON_POLICY[knownCode],
|
|
256
|
+
};
|
|
257
|
+
}
|
|
229
258
|
/** User-facing business messages — never stack traces, paths, SQL or tokens. */
|
|
230
259
|
exports.TERMINAL_REASON_MESSAGES = {
|
|
231
260
|
no_candidate: '没有找到合适的新作品',
|
|
@@ -317,6 +346,9 @@ function classifyFailedReason(message, scan) {
|
|
|
317
346
|
? { code: 'download_timeout', message: exports.TERMINAL_REASON_MESSAGES.download_timeout }
|
|
318
347
|
: { code: 'execution_timeout', message: exports.TERMINAL_REASON_MESSAGES.execution_timeout };
|
|
319
348
|
}
|
|
349
|
+
if (/\b(?:download|image fetch|image write)\b.{0,80}\b(?:fail|failed|error|unable)\b|\b(?:failed|unable)\b.{0,40}\b(?:download|fetch image|write image)\b/i.test(text)) {
|
|
350
|
+
return { code: 'download_failed', message: exports.TERMINAL_REASON_MESSAGES.download_failed };
|
|
351
|
+
}
|
|
320
352
|
if (/502|503|504|bad gateway|service unavailable|server error|5\d\d/i.test(text)) {
|
|
321
353
|
return { code: 'remote_http_error', message: exports.TERMINAL_REASON_MESSAGES.remote_http_error };
|
|
322
354
|
}
|
package/dist/version.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BUILD = void 0;
|
|
4
4
|
// GENERATED by scripts/write-version.js — do not edit manually.
|
|
5
|
-
exports.BUILD = { version: '2.
|
|
5
|
+
exports.BUILD = { version: '2.28.0', commit: 'baec8d0803d6' };
|
|
6
6
|
//# sourceMappingURL=version.js.map
|
package/dist/webui/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pixivflow",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.28.0",
|
|
4
4
|
"description": "🎨 Pixiv 下载、筛选与自动收集工具 - 批量下载插画和小说、按标签/热度/日期筛选、定时任务与可靠 HTTP 交付 | Pixiv downloader and automation toolkit with filtering, scheduling and reliable HTTP delivery",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|