tt-help-cli-ycl 1.3.17 → 1.3.18
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/package.json +1 -1
- package/src/cli/attach.js +54 -34
- package/src/watch/data-store.js +23 -1
- package/src/watch/server.js +17 -1
package/package.json
CHANGED
package/src/cli/attach.js
CHANGED
|
@@ -22,10 +22,11 @@ async function apiGet(url) {
|
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
|
|
26
|
+
async function apiPost(url, body) {
|
|
27
|
+
return withRetry(`POST ${url}`, async () => {
|
|
27
28
|
const res = await fetch(url, {
|
|
28
|
-
method: '
|
|
29
|
+
method: 'POST',
|
|
29
30
|
headers: { 'Content-Type': 'application/json' },
|
|
30
31
|
body: JSON.stringify(body),
|
|
31
32
|
});
|
|
@@ -111,37 +112,56 @@ export async function handleAttach(options) {
|
|
|
111
112
|
})
|
|
112
113
|
);
|
|
113
114
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
115
|
+
let successCount = 0;
|
|
116
|
+
let failCount = 0;
|
|
117
|
+
let needRestart = false;
|
|
118
|
+
|
|
119
|
+
// 收集抓取成功的任务,记录抓取失败的
|
|
120
|
+
const successTasks = [];
|
|
121
|
+
for (const result of results) {
|
|
122
|
+
if (result.status === 'fulfilled') {
|
|
123
|
+
const { uniqueId, info, error } = result.value;
|
|
124
|
+
if (error) {
|
|
125
|
+
if (isBrowserClosedError(error)) {
|
|
126
|
+
needRestart = true;
|
|
127
|
+
}
|
|
128
|
+
console.error(` ✗ @${uniqueId} 获取失败: ${error.message || '未知错误'}`);
|
|
129
|
+
failCount++;
|
|
130
|
+
} else if (info) {
|
|
131
|
+
successTasks.push({ uniqueId, info });
|
|
132
|
+
} else {
|
|
133
|
+
console.error(` ✗ @${uniqueId} 未获取到用户信息`);
|
|
134
|
+
failCount++;
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
console.error(` ✗ 任务执行异常: ${result.reason?.message || '未知错误'}`);
|
|
138
|
+
failCount++;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 批量提交成功的结果
|
|
143
|
+
if (successTasks.length > 0) {
|
|
144
|
+
try {
|
|
145
|
+
const batchRet = await apiPost(`${serverUrl}/api/user-info-batch`, { updates: successTasks });
|
|
146
|
+
if (batchRet && batchRet.results) {
|
|
147
|
+
for (const r of batchRet.results) {
|
|
148
|
+
if (r.ok) {
|
|
149
|
+
successCount++;
|
|
150
|
+
console.error(` ✓ @${r.uniqueId} 已提交更新`);
|
|
151
|
+
} else {
|
|
152
|
+
failCount++;
|
|
153
|
+
console.error(` ✗ @${r.uniqueId} 提交失败: ${r.error}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
successCount = successTasks.length;
|
|
158
|
+
console.error(` ✓ 批量提交完成 (${successTasks.length} 条)`);
|
|
159
|
+
}
|
|
160
|
+
} catch (err) {
|
|
161
|
+
failCount += successTasks.length;
|
|
162
|
+
console.error(` ✗ 批量提交失败: ${err.message}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
145
165
|
|
|
146
166
|
console.error(` 本批结果: ${successCount} 成功, ${failCount} 失败\n`);
|
|
147
167
|
|
package/src/watch/data-store.js
CHANGED
|
@@ -605,6 +605,28 @@ export function createStore(filePath) {
|
|
|
605
605
|
return { ok: true, userUpdateCount: user.userUpdateCount };
|
|
606
606
|
}
|
|
607
607
|
|
|
608
|
+
function batchUpdateUserInfo(updates) {
|
|
609
|
+
const results = [];
|
|
610
|
+
for (const item of updates) {
|
|
611
|
+
const user = getUser(item.uniqueId);
|
|
612
|
+
if (!user) {
|
|
613
|
+
results.push({ uniqueId: item.uniqueId, error: 'user not found' });
|
|
614
|
+
continue;
|
|
615
|
+
}
|
|
616
|
+
for (const key of Object.keys(item.info)) {
|
|
617
|
+
if (key === 'uniqueId' || key === 'sources') continue;
|
|
618
|
+
if (item.info[key] !== undefined && item.info[key] !== null && item.info[key] !== '') {
|
|
619
|
+
user[key] = item.info[key];
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
user.userUpdateCount = (user.userUpdateCount || 0) + 1;
|
|
623
|
+
user.updatedAt = Date.now();
|
|
624
|
+
results.push({ uniqueId: item.uniqueId, ok: true, userUpdateCount: user.userUpdateCount });
|
|
625
|
+
}
|
|
626
|
+
save();
|
|
627
|
+
return results;
|
|
628
|
+
}
|
|
629
|
+
|
|
608
630
|
// 视频登记
|
|
609
631
|
function registerVideos(sourceUser, videoList, locationCreated, ttSeller) {
|
|
610
632
|
if (!videoList || !Array.isArray(videoList) || videoList.length === 0) {
|
|
@@ -649,7 +671,7 @@ export function createStore(filePath) {
|
|
|
649
671
|
getPendingUsers, getProcessedUsers, getAllUsers, getStats,
|
|
650
672
|
claimNextJob, commitJob, commitNewExplore, resetJob, togglePin,
|
|
651
673
|
getNextRedoJob, commitRedoJob,
|
|
652
|
-
getPendingUserUpdateTasks, updateUserInfo,
|
|
674
|
+
getPendingUserUpdateTasks, updateUserInfo, batchUpdateUserInfo,
|
|
653
675
|
reportClientError, deleteClientError, getClientErrors,
|
|
654
676
|
registerVideos, getVideos, getVideoCount,
|
|
655
677
|
stopBackup,
|
package/src/watch/server.js
CHANGED
|
@@ -309,7 +309,23 @@ export function startWatchServer(outputFile, port = 3000, existingStore) {
|
|
|
309
309
|
return;
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
-
|
|
312
|
+
if (req.method === 'POST' && routePath === '/api/user-info-batch') {
|
|
313
|
+
try {
|
|
314
|
+
const body = await readBody(req);
|
|
315
|
+
const updates = body.updates || [];
|
|
316
|
+
const results = store.batchUpdateUserInfo(updates);
|
|
317
|
+
const okCount = results.filter(r => r.ok).length;
|
|
318
|
+
const errCount = results.filter(r => r.error).length;
|
|
319
|
+
const ts = new Date().toISOString().slice(11, 19);
|
|
320
|
+
console.error(`[JOB ${ts}] USER-INFO-BATCH: ${okCount} ok, ${errCount} error (total=${updates.length})`);
|
|
321
|
+
sendJSON(res, 200, { results, total: updates.length, ok: okCount, error: errCount });
|
|
322
|
+
} catch (e) {
|
|
323
|
+
sendJSON(res, 400, { error: e.message });
|
|
324
|
+
}
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const userInfoCommitMatch = routePath.match(/^\/api\/user-info\/([^/]+)$/);
|
|
313
329
|
if (req.method === 'PUT' && userInfoCommitMatch) {
|
|
314
330
|
const uniqueId = userInfoCommitMatch[1];
|
|
315
331
|
try {
|