@web-auto/webauto 0.1.8 → 0.1.9
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/apps/desktop-console/dist/main/index.mjs +800 -89
- package/apps/desktop-console/dist/main/preload.mjs +3 -0
- package/apps/desktop-console/dist/renderer/index.html +9 -1
- package/apps/desktop-console/dist/renderer/index.js +784 -331
- package/apps/desktop-console/entry/ui-cli.mjs +23 -8
- package/apps/desktop-console/entry/ui-console.mjs +8 -3
- package/apps/webauto/entry/account.mjs +69 -8
- package/apps/webauto/entry/lib/account-detect.mjs +106 -25
- package/apps/webauto/entry/lib/account-store.mjs +121 -22
- package/apps/webauto/entry/lib/schedule-store.mjs +0 -12
- package/apps/webauto/entry/profilepool.mjs +45 -3
- package/apps/webauto/entry/schedule.mjs +44 -2
- package/apps/webauto/entry/weibo-unified.mjs +2 -2
- package/apps/webauto/entry/xhs-install.mjs +220 -51
- package/apps/webauto/entry/xhs-unified.mjs +33 -6
- package/bin/webauto.mjs +80 -4
- package/dist/modules/camo-runtime/src/utils/browser-service.mjs +4 -0
- package/dist/services/unified-api/server.js +5 -0
- package/dist/services/unified-api/task-state.js +2 -0
- package/modules/camo-runtime/src/autoscript/action-providers/xhs/interaction.mjs +142 -14
- package/modules/camo-runtime/src/autoscript/action-providers/xhs/search.mjs +16 -1
- package/modules/camo-runtime/src/autoscript/action-providers/xhs.mjs +104 -0
- package/modules/camo-runtime/src/autoscript/runtime.mjs +14 -4
- package/modules/camo-runtime/src/autoscript/schema.mjs +9 -0
- package/modules/camo-runtime/src/autoscript/xhs-unified-template.mjs +9 -2
- package/modules/camo-runtime/src/container/runtime-core/checkpoint.mjs +107 -1
- package/modules/camo-runtime/src/container/runtime-core/subscription.mjs +24 -2
- package/modules/camo-runtime/src/utils/browser-service.mjs +4 -0
- package/package.json +6 -3
- package/scripts/bump-version.mjs +120 -0
- package/services/unified-api/server.ts +4 -0
- package/services/unified-api/task-state.ts +5 -0
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
const INDEX_FILE = 'index.json';
|
|
12
12
|
const META_FILE = 'meta.json';
|
|
13
13
|
const DEFAULT_PLATFORM = 'xiaohongshu';
|
|
14
|
+
const DEFAULT_PROFILE_PREFIX = 'profile';
|
|
14
15
|
const STATUS_ACTIVE = 'active';
|
|
15
16
|
const STATUS_VALID = 'valid';
|
|
16
17
|
const STATUS_INVALID = 'invalid';
|
|
@@ -213,21 +214,31 @@ function saveIndex(index) {
|
|
|
213
214
|
return payload;
|
|
214
215
|
}
|
|
215
216
|
|
|
216
|
-
function
|
|
217
|
+
function resolveLegacyProfilePrefix(platform) {
|
|
217
218
|
if (platform === 'xiaohongshu') return 'xiaohongshu-batch';
|
|
218
219
|
const slug = toSlug(platform) || 'account';
|
|
219
220
|
return `${slug}-account`;
|
|
220
221
|
}
|
|
221
222
|
|
|
223
|
+
function resolveProfilePrefix() {
|
|
224
|
+
return DEFAULT_PROFILE_PREFIX;
|
|
225
|
+
}
|
|
226
|
+
|
|
222
227
|
function resolveProfileSeq(profileId, platform) {
|
|
223
228
|
const value = String(profileId || '').trim();
|
|
224
229
|
if (!value) return null;
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
230
|
+
const prefixes = [
|
|
231
|
+
resolveProfilePrefix(),
|
|
232
|
+
resolveLegacyProfilePrefix(platform),
|
|
233
|
+
].filter(Boolean);
|
|
234
|
+
for (const prefix of prefixes) {
|
|
235
|
+
const match = value.match(new RegExp(`^${prefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}-([0-9]+)$`));
|
|
236
|
+
if (!match) continue;
|
|
237
|
+
const seq = Number(match[1]);
|
|
238
|
+
if (!Number.isFinite(seq) || seq < 0) return null;
|
|
239
|
+
return seq;
|
|
240
|
+
}
|
|
241
|
+
return null;
|
|
231
242
|
}
|
|
232
243
|
|
|
233
244
|
function resolveUsedAutoSeq(index, platform) {
|
|
@@ -280,23 +291,34 @@ function resolveAccountOrThrow(index, key) {
|
|
|
280
291
|
throw new Error(`account not found: ${idOrAlias}`);
|
|
281
292
|
}
|
|
282
293
|
|
|
283
|
-
function
|
|
294
|
+
function resolveBindingKey(profileId, platform) {
|
|
295
|
+
const pid = String(profileId || '').trim();
|
|
296
|
+
const pf = normalizePlatform(platform);
|
|
297
|
+
if (!pid) return '';
|
|
298
|
+
return `${pid}::${pf}`;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function resolveAccountByProfile(index, profileId, platform = null) {
|
|
284
302
|
const value = String(profileId || '').trim();
|
|
285
303
|
if (!value) return null;
|
|
304
|
+
const wantedPlatform = platform ? normalizePlatform(platform) : null;
|
|
286
305
|
let matched = null;
|
|
287
306
|
for (const item of index.accounts) {
|
|
288
307
|
if (String(item?.profileId || '').trim() !== value) continue;
|
|
308
|
+
if (wantedPlatform && normalizePlatform(item?.platform) !== wantedPlatform) continue;
|
|
289
309
|
matched = pickNewerRecord(matched, item);
|
|
290
310
|
}
|
|
291
311
|
return matched;
|
|
292
312
|
}
|
|
293
313
|
|
|
294
|
-
function resolveAccountByAccountId(index, accountId) {
|
|
314
|
+
function resolveAccountByAccountId(index, accountId, platform = null) {
|
|
295
315
|
const value = normalizeText(accountId);
|
|
296
316
|
if (!value) return null;
|
|
317
|
+
const wantedPlatform = platform ? normalizePlatform(platform) : null;
|
|
297
318
|
let matched = null;
|
|
298
319
|
for (const item of index.accounts) {
|
|
299
320
|
if (normalizeText(item?.accountId) !== value) continue;
|
|
321
|
+
if (wantedPlatform && normalizePlatform(item?.platform) !== wantedPlatform) continue;
|
|
300
322
|
matched = pickNewerRecord(matched, item);
|
|
301
323
|
}
|
|
302
324
|
return matched;
|
|
@@ -342,39 +364,76 @@ function buildProfileAccountView(profileId, record = null) {
|
|
|
342
364
|
};
|
|
343
365
|
}
|
|
344
366
|
|
|
345
|
-
export function listAccountProfiles() {
|
|
367
|
+
export function listAccountProfiles(options = {}) {
|
|
346
368
|
const index = loadIndex();
|
|
369
|
+
const platformFilter = normalizeText(options?.platform) ? normalizePlatform(options.platform) : null;
|
|
347
370
|
const byAccountId = new Map();
|
|
348
371
|
for (const record of index.accounts) {
|
|
372
|
+
const recordPlatform = normalizePlatform(record?.platform);
|
|
373
|
+
if (platformFilter && recordPlatform !== platformFilter) continue;
|
|
349
374
|
const accountId = normalizeText(record?.accountId);
|
|
350
375
|
if (!accountId) continue;
|
|
351
|
-
|
|
376
|
+
const key = `${recordPlatform}::${accountId}`;
|
|
377
|
+
byAccountId.set(key, pickNewerRecord(byAccountId.get(key), record));
|
|
352
378
|
}
|
|
353
379
|
const deduped = [];
|
|
354
380
|
for (const record of index.accounts) {
|
|
381
|
+
const recordPlatform = normalizePlatform(record?.platform);
|
|
382
|
+
if (platformFilter && recordPlatform !== platformFilter) continue;
|
|
355
383
|
const accountId = normalizeText(record?.accountId);
|
|
356
384
|
if (accountId) {
|
|
357
|
-
|
|
385
|
+
const key = `${recordPlatform}::${accountId}`;
|
|
386
|
+
if (byAccountId.get(key) !== record) continue;
|
|
358
387
|
}
|
|
359
388
|
deduped.push(record);
|
|
360
389
|
}
|
|
361
|
-
const
|
|
390
|
+
const byBinding = new Map();
|
|
362
391
|
for (const record of deduped) {
|
|
363
392
|
const profileId = normalizeText(record?.profileId);
|
|
364
393
|
if (!profileId) continue;
|
|
365
|
-
|
|
394
|
+
const key = resolveBindingKey(profileId, record?.platform);
|
|
395
|
+
if (!key) continue;
|
|
396
|
+
byBinding.set(key, pickNewerRecord(byBinding.get(key), record));
|
|
397
|
+
}
|
|
398
|
+
const rows = Array.from(byBinding.values())
|
|
399
|
+
.sort((a, b) => {
|
|
400
|
+
const seqCmp = Number(a?.seq || 0) - Number(b?.seq || 0);
|
|
401
|
+
if (seqCmp !== 0) return seqCmp;
|
|
402
|
+
const pCmp = String(a?.profileId || '').localeCompare(String(b?.profileId || ''));
|
|
403
|
+
if (pCmp !== 0) return pCmp;
|
|
404
|
+
return normalizePlatform(a?.platform).localeCompare(normalizePlatform(b?.platform));
|
|
405
|
+
})
|
|
406
|
+
.map((record) => buildProfileAccountView(record?.profileId, record));
|
|
407
|
+
const validProfilesSet = new Set();
|
|
408
|
+
const invalidProfilesSet = new Set();
|
|
409
|
+
const validProfilesByPlatform = {};
|
|
410
|
+
const invalidProfilesByPlatform = {};
|
|
411
|
+
for (const row of rows) {
|
|
412
|
+
const platform = normalizePlatform(row.platform);
|
|
413
|
+
if (!validProfilesByPlatform[platform]) validProfilesByPlatform[platform] = [];
|
|
414
|
+
if (!invalidProfilesByPlatform[platform]) invalidProfilesByPlatform[platform] = [];
|
|
415
|
+
if (row.valid) {
|
|
416
|
+
validProfilesSet.add(row.profileId);
|
|
417
|
+
if (!validProfilesByPlatform[platform].includes(row.profileId)) {
|
|
418
|
+
validProfilesByPlatform[platform].push(row.profileId);
|
|
419
|
+
}
|
|
420
|
+
} else {
|
|
421
|
+
invalidProfilesSet.add(row.profileId);
|
|
422
|
+
if (!invalidProfilesByPlatform[platform].includes(row.profileId)) {
|
|
423
|
+
invalidProfilesByPlatform[platform].push(row.profileId);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
366
426
|
}
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
.map(([profileId, record]) => buildProfileAccountView(profileId, record));
|
|
370
|
-
const validProfiles = rows.filter((item) => item.valid).map((item) => item.profileId);
|
|
371
|
-
const invalidProfiles = rows.filter((item) => !item.valid).map((item) => item.profileId);
|
|
427
|
+
const validProfiles = Array.from(validProfilesSet);
|
|
428
|
+
const invalidProfiles = Array.from(invalidProfilesSet).filter((profileId) => !validProfilesSet.has(profileId));
|
|
372
429
|
return {
|
|
373
430
|
root: resolveAccountsRoot(),
|
|
374
431
|
count: rows.length,
|
|
375
432
|
profiles: rows,
|
|
376
433
|
validProfiles,
|
|
377
434
|
invalidProfiles,
|
|
435
|
+
validProfilesByPlatform,
|
|
436
|
+
invalidProfilesByPlatform,
|
|
378
437
|
};
|
|
379
438
|
}
|
|
380
439
|
|
|
@@ -426,6 +485,39 @@ export async function addAccount(input = {}) {
|
|
|
426
485
|
status === STATUS_VALID
|
|
427
486
|
? null
|
|
428
487
|
: (status === STATUS_PENDING ? 'waiting_login' : 'missing_account_id');
|
|
488
|
+
|
|
489
|
+
if (accountId) {
|
|
490
|
+
const existing = resolveAccountByAccountId(index, accountId, platform);
|
|
491
|
+
if (existing) {
|
|
492
|
+
const next = {
|
|
493
|
+
...existing,
|
|
494
|
+
platform,
|
|
495
|
+
status,
|
|
496
|
+
valid: status === STATUS_VALID,
|
|
497
|
+
reason,
|
|
498
|
+
accountId,
|
|
499
|
+
name: accountId,
|
|
500
|
+
alias: alias || existing.alias || null,
|
|
501
|
+
username: normalizeText(input.username) || existing.username || null,
|
|
502
|
+
profileId,
|
|
503
|
+
fingerprintId,
|
|
504
|
+
updatedAt: createdAt,
|
|
505
|
+
aliasSource: alias ? (normalizeAlias(input.alias) ? 'manual' : 'username') : existing.aliasSource || null,
|
|
506
|
+
};
|
|
507
|
+
if (alias) ensureAliasUnique(index.accounts, alias, existing.id);
|
|
508
|
+
const rowIndex = index.accounts.findIndex((item) => item?.id === existing.id);
|
|
509
|
+
if (rowIndex < 0) throw new Error(`account not found: ${existing.id}`);
|
|
510
|
+
index.accounts[rowIndex] = next;
|
|
511
|
+
saveIndex(index);
|
|
512
|
+
persistAccountMeta(next);
|
|
513
|
+
return {
|
|
514
|
+
root: resolveAccountsRoot(),
|
|
515
|
+
account: next,
|
|
516
|
+
deduped: true,
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
429
521
|
const account = {
|
|
430
522
|
id,
|
|
431
523
|
seq,
|
|
@@ -553,8 +645,8 @@ export function upsertProfileAccountState(input = {}) {
|
|
|
553
645
|
const status = accountId ? STATUS_VALID : (pendingMode ? STATUS_PENDING : STATUS_INVALID);
|
|
554
646
|
|
|
555
647
|
const index = loadIndex();
|
|
556
|
-
const existingByProfile = resolveAccountByProfile(index, profileId);
|
|
557
|
-
const existingByAccountId = accountId ? resolveAccountByAccountId(index, accountId) : null;
|
|
648
|
+
const existingByProfile = resolveAccountByProfile(index, profileId, platform);
|
|
649
|
+
const existingByAccountId = accountId ? resolveAccountByAccountId(index, accountId, platform) : null;
|
|
558
650
|
let target = existingByAccountId || existingByProfile || null;
|
|
559
651
|
const purgeIds = new Set();
|
|
560
652
|
|
|
@@ -611,7 +703,11 @@ export function upsertProfileAccountState(input = {}) {
|
|
|
611
703
|
}
|
|
612
704
|
|
|
613
705
|
const staleIds = index.accounts
|
|
614
|
-
.filter((item) =>
|
|
706
|
+
.filter((item) => (
|
|
707
|
+
String(item?.profileId || '').trim() === profileId
|
|
708
|
+
&& normalizePlatform(item?.platform) === platform
|
|
709
|
+
&& !hasPersistentAccountId(item)
|
|
710
|
+
))
|
|
615
711
|
.map((item) => String(item?.id || '').trim())
|
|
616
712
|
.filter(Boolean);
|
|
617
713
|
if (staleIds.length > 0) {
|
|
@@ -677,6 +773,7 @@ export function upsertProfileAccountState(input = {}) {
|
|
|
677
773
|
if (accountId) {
|
|
678
774
|
for (const row of index.accounts) {
|
|
679
775
|
if (!row || row.id === target.id) continue;
|
|
776
|
+
if (normalizePlatform(row?.platform) !== platform) continue;
|
|
680
777
|
if (normalizeText(row.accountId) === accountId) {
|
|
681
778
|
purgeIds.add(row.id);
|
|
682
779
|
}
|
|
@@ -727,6 +824,7 @@ export function markProfileInvalid(profileId, reason = 'login_guard') {
|
|
|
727
824
|
const id = ensureSafeName(normalizeText(profileId), 'profileId');
|
|
728
825
|
return upsertProfileAccountState({
|
|
729
826
|
profileId: id,
|
|
827
|
+
platform: DEFAULT_PLATFORM,
|
|
730
828
|
accountId: null,
|
|
731
829
|
reason,
|
|
732
830
|
});
|
|
@@ -736,6 +834,7 @@ export function markProfilePending(profileId, reason = 'waiting_login') {
|
|
|
736
834
|
const id = ensureSafeName(normalizeText(profileId), 'profileId');
|
|
737
835
|
return upsertProfileAccountState({
|
|
738
836
|
profileId: id,
|
|
837
|
+
platform: DEFAULT_PLATFORM,
|
|
739
838
|
accountId: null,
|
|
740
839
|
status: STATUS_PENDING,
|
|
741
840
|
reason,
|
|
@@ -464,20 +464,11 @@ function validateCommand(task) {
|
|
|
464
464
|
|
|
465
465
|
function validateXhsCommand(argv) {
|
|
466
466
|
const keyword = normalizeText(argv.keyword || argv.k);
|
|
467
|
-
const profile = normalizeText(argv.profile);
|
|
468
|
-
const profiles = normalizeText(argv.profiles);
|
|
469
|
-
const profilepool = normalizeText(argv.profilepool);
|
|
470
467
|
if (!keyword) throw new Error('task command argv missing keyword');
|
|
471
|
-
if (!profile && !profiles && !profilepool) {
|
|
472
|
-
throw new Error('task command argv missing profile/profiles/profilepool');
|
|
473
|
-
}
|
|
474
468
|
}
|
|
475
469
|
|
|
476
470
|
function validateGenericCommand(argv, platform, commandType = '') {
|
|
477
471
|
const keyword = normalizeText(argv.keyword || argv.k);
|
|
478
|
-
const profile = normalizeText(argv.profile);
|
|
479
|
-
const profiles = normalizeText(argv.profiles);
|
|
480
|
-
const profilepool = normalizeText(argv.profilepool);
|
|
481
472
|
let weiboTaskType = '';
|
|
482
473
|
if (platform === 'weibo') {
|
|
483
474
|
weiboTaskType = String(argv['task-type'] || argv.taskType || '').trim();
|
|
@@ -495,9 +486,6 @@ function validateGenericCommand(argv, platform, commandType = '') {
|
|
|
495
486
|
if (!keyword && (platform !== 'weibo' || weiboTaskType === 'search')) {
|
|
496
487
|
throw new Error('task command argv missing keyword');
|
|
497
488
|
}
|
|
498
|
-
if (!profile && !profiles && !profilepool) {
|
|
499
|
-
throw new Error('task command argv missing profile/profiles/profilepool');
|
|
500
|
-
}
|
|
501
489
|
}
|
|
502
490
|
|
|
503
491
|
function normalizeScheduleFields(input = {}, fallback = {}) {
|
|
@@ -173,6 +173,46 @@ async function cmdMigrateFingerprints(jsonMode) {
|
|
|
173
173
|
output({ ok: true, checked: profiles.length, ensured: created.length }, jsonMode);
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
async function cmdGotoProfile(profileId, argv, jsonMode) {
|
|
177
|
+
const id = String(profileId || '').trim();
|
|
178
|
+
if (!id) throw new Error('profileId is required');
|
|
179
|
+
const url = String(argv.url || argv._?.[2] || '').trim();
|
|
180
|
+
if (!url) throw new Error('url is required');
|
|
181
|
+
await ensureProfile(id);
|
|
182
|
+
|
|
183
|
+
const gotoRet = runCamo(['goto', id, url], { rootDir: ROOT, timeoutMs: 30000 });
|
|
184
|
+
if (gotoRet.ok) {
|
|
185
|
+
output({
|
|
186
|
+
ok: true,
|
|
187
|
+
profileId: id,
|
|
188
|
+
url,
|
|
189
|
+
mode: 'goto',
|
|
190
|
+
result: gotoRet.json || null,
|
|
191
|
+
}, jsonMode);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const idleTimeout = String(argv['idle-timeout'] || process.env.WEBAUTO_LOGIN_IDLE_TIMEOUT || '30m').trim() || '30m';
|
|
196
|
+
const startRet = runCamo(['start', id, '--url', url, '--idle-timeout', idleTimeout], { rootDir: ROOT });
|
|
197
|
+
if (!startRet.ok) {
|
|
198
|
+
output({
|
|
199
|
+
ok: false,
|
|
200
|
+
profileId: id,
|
|
201
|
+
url,
|
|
202
|
+
mode: 'start',
|
|
203
|
+
error: startRet.stderr || startRet.stdout || gotoRet.stderr || gotoRet.stdout || 'goto/start failed',
|
|
204
|
+
}, jsonMode);
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
output({
|
|
208
|
+
ok: true,
|
|
209
|
+
profileId: id,
|
|
210
|
+
url,
|
|
211
|
+
mode: 'start',
|
|
212
|
+
session: startRet.json || null,
|
|
213
|
+
}, jsonMode);
|
|
214
|
+
}
|
|
215
|
+
|
|
176
216
|
async function main() {
|
|
177
217
|
const argv = minimist(process.argv.slice(2));
|
|
178
218
|
const cmd = String(argv._[0] || '').trim();
|
|
@@ -180,14 +220,16 @@ async function main() {
|
|
|
180
220
|
const jsonMode = argv.json === true;
|
|
181
221
|
|
|
182
222
|
if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
|
|
183
|
-
console.log('Usage: node apps/webauto/entry/profilepool.mjs <list|add|login|login-profile|migrate-fingerprints> ... [--json]');
|
|
223
|
+
console.log('Usage: node apps/webauto/entry/profilepool.mjs <list|add|login|login-profile|goto-profile|migrate-fingerprints> ... [--json]');
|
|
224
|
+
console.log('Default profile prefix: profile (e.g. profile-0, profile-1)');
|
|
184
225
|
return;
|
|
185
226
|
}
|
|
186
227
|
|
|
187
228
|
if (cmd === 'list') return cmdList(arg1, jsonMode);
|
|
188
|
-
if (cmd === 'add') return cmdAdd(arg1 || '
|
|
229
|
+
if (cmd === 'add') return cmdAdd(arg1 || 'profile', jsonMode);
|
|
189
230
|
if (cmd === 'login-profile') return cmdLoginProfile(arg1, argv, jsonMode);
|
|
190
|
-
if (cmd === '
|
|
231
|
+
if (cmd === 'goto-profile') return cmdGotoProfile(arg1, argv, jsonMode);
|
|
232
|
+
if (cmd === 'login') return cmdLogin(arg1 || 'profile', argv, jsonMode);
|
|
191
233
|
if (cmd === 'migrate-fingerprints') return cmdMigrateFingerprints(jsonMode);
|
|
192
234
|
|
|
193
235
|
throw new Error(`unknown command: ${cmd}`);
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
resolveSchedulesRoot,
|
|
23
23
|
updateScheduleTask,
|
|
24
24
|
} from './lib/schedule-store.mjs';
|
|
25
|
+
import { listAccountProfiles } from './lib/account-store.mjs';
|
|
25
26
|
|
|
26
27
|
let xhsRunnerPromise = null;
|
|
27
28
|
let weiboRunnerPromise = null;
|
|
@@ -70,6 +71,46 @@ function parseJson(text, fallback = {}) {
|
|
|
70
71
|
return JSON.parse(raw.replace(/^\uFEFF/, ''));
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
function normalizePlatformByCommandType(commandType) {
|
|
75
|
+
const value = String(commandType || '').trim().toLowerCase();
|
|
76
|
+
if (value.startsWith('weibo')) return 'weibo';
|
|
77
|
+
if (value.startsWith('1688')) return '1688';
|
|
78
|
+
return 'xiaohongshu';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function hasProfileArg(argv = {}) {
|
|
82
|
+
return Boolean(
|
|
83
|
+
String(argv?.profile || '').trim()
|
|
84
|
+
|| String(argv?.profiles || '').trim()
|
|
85
|
+
|| String(argv?.profilepool || '').trim(),
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function pickAutoProfile(platform) {
|
|
90
|
+
const rows = listAccountProfiles({ platform }).profiles || [];
|
|
91
|
+
const validRows = rows
|
|
92
|
+
.filter((row) => row?.valid === true && String(row?.accountId || '').trim())
|
|
93
|
+
.sort((a, b) => {
|
|
94
|
+
const ta = Date.parse(String(a?.updatedAt || '')) || 0;
|
|
95
|
+
const tb = Date.parse(String(b?.updatedAt || '')) || 0;
|
|
96
|
+
if (tb !== ta) return tb - ta;
|
|
97
|
+
return String(a?.profileId || '').localeCompare(String(b?.profileId || ''));
|
|
98
|
+
});
|
|
99
|
+
return String(validRows[0]?.profileId || '').trim();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function ensureProfileArgForTask(commandType, commandArgv = {}) {
|
|
103
|
+
const argv = commandArgv && typeof commandArgv === 'object' ? { ...commandArgv } : {};
|
|
104
|
+
if (hasProfileArg(argv)) return argv;
|
|
105
|
+
const platform = normalizePlatformByCommandType(commandType);
|
|
106
|
+
const profile = pickAutoProfile(platform);
|
|
107
|
+
if (!profile) {
|
|
108
|
+
throw new Error(`missing profile/profiles/profilepool and no valid account for platform=${platform}`);
|
|
109
|
+
}
|
|
110
|
+
argv.profile = profile;
|
|
111
|
+
return argv;
|
|
112
|
+
}
|
|
113
|
+
|
|
73
114
|
function safeReadJsonFile(filePath) {
|
|
74
115
|
const raw = fs.readFileSync(filePath, 'utf8');
|
|
75
116
|
return parseJson(raw, {});
|
|
@@ -265,14 +306,15 @@ async function executeTask(task, options = {}) {
|
|
|
265
306
|
const quietExecutors = options.quietExecutors === true;
|
|
266
307
|
try {
|
|
267
308
|
const commandType = String(task?.commandType || 'xhs-unified').trim();
|
|
309
|
+
const commandArgv = ensureProfileArgForTask(commandType, task?.commandArgv || {});
|
|
268
310
|
const result = await withConsoleSilenced(quietExecutors, async () => {
|
|
269
311
|
if (commandType === 'xhs-unified') {
|
|
270
312
|
const runUnified = await getXhsRunner();
|
|
271
|
-
return runUnified(
|
|
313
|
+
return runUnified(commandArgv);
|
|
272
314
|
}
|
|
273
315
|
if (commandType.startsWith('weibo-')) {
|
|
274
316
|
const runWeiboUnified = await getWeiboRunner();
|
|
275
|
-
return runWeiboUnified(
|
|
317
|
+
return runWeiboUnified(commandArgv);
|
|
276
318
|
}
|
|
277
319
|
if (commandType === '1688-search') {
|
|
278
320
|
throw new Error(`executor_not_implemented: ${commandType}`);
|
|
@@ -4,7 +4,7 @@ import { runWorkflowById } from '../../../dist/modules/workflow/src/runner.js';
|
|
|
4
4
|
import { pathToFileURL } from 'node:url';
|
|
5
5
|
|
|
6
6
|
const WEIBO_HOME_URL = 'https://www.weibo.com';
|
|
7
|
-
const DEFAULT_PROFILE = '
|
|
7
|
+
const DEFAULT_PROFILE = 'profile-0';
|
|
8
8
|
|
|
9
9
|
async function runCommand(argv) {
|
|
10
10
|
const profile = String(argv.profile || DEFAULT_PROFILE).trim();
|
|
@@ -106,7 +106,7 @@ if (isDirectExec) {
|
|
|
106
106
|
export async function runWeiboUnified(argv) {
|
|
107
107
|
const workflowId = String(argv.workflow || 'weibo-search-v1').trim();
|
|
108
108
|
const keyword = String(argv.keyword || argv.k || '').trim();
|
|
109
|
-
const profile = String(argv.profile ||
|
|
109
|
+
const profile = String(argv.profile || DEFAULT_PROFILE).trim();
|
|
110
110
|
const targetCount = Number(argv['max-notes'] || argv.target || argv['max-notes'] || 50);
|
|
111
111
|
const maxComments = Number(argv['max-comments'] || 0);
|
|
112
112
|
const env = String(argv.env || 'debug').trim();
|