@lightcone-ai/daemon 0.9.64 → 0.9.66
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.
|
@@ -24,6 +24,7 @@ const REQUIREMENTS = {
|
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
const PUBLISH_URL = 'https://creator.xiaohongshu.com/publish/publish';
|
|
27
|
+
const IMAGE_PUBLISH_URL = 'https://creator.xiaohongshu.com/publish/publish?target=image';
|
|
27
28
|
const VIDEO_PUBLISH_URL = 'https://creator.xiaohongshu.com/publish/publish?source=video';
|
|
28
29
|
|
|
29
30
|
const CREATOR_HOME_URL = 'https://creator.xiaohongshu.com/new/home';
|
|
@@ -135,13 +136,21 @@ export class XhsAdapter {
|
|
|
135
136
|
async _openPublishComposer(kind) {
|
|
136
137
|
const targetTabText = kind === 'image' ? '上传图文' : '上传视频';
|
|
137
138
|
const inputSelector = kind === 'image' ? IMAGE_FILE_INPUT_SELECTOR : VIDEO_FILE_INPUT_SELECTOR;
|
|
138
|
-
const url = kind === 'video' ? VIDEO_PUBLISH_URL :
|
|
139
|
+
const url = kind === 'video' ? VIDEO_PUBLISH_URL : IMAGE_PUBLISH_URL;
|
|
139
140
|
|
|
140
141
|
await this._cdp.send('Page.navigate', { url });
|
|
141
142
|
await this._waitForCreatorShell(20_000);
|
|
142
143
|
await this._assertReadyForPublish();
|
|
143
144
|
|
|
144
|
-
await this.
|
|
145
|
+
if (await this._hasSelector(inputSelector)) return;
|
|
146
|
+
|
|
147
|
+
const clicked = await this._clickVisibleByText(targetTabText, '.creator-tab, button, [role="button"], span, div', { throwOnMissing: false });
|
|
148
|
+
if (clicked) {
|
|
149
|
+
await this._waitForAny([inputSelector], 15_000);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
await this._cdp.send('Page.navigate', { url: kind === 'image' ? `${PUBLISH_URL}?from=tab_switch&target=image` : VIDEO_PUBLISH_URL });
|
|
145
154
|
await this._waitForAny([inputSelector], 15_000);
|
|
146
155
|
}
|
|
147
156
|
|
|
@@ -186,6 +195,14 @@ export class XhsAdapter {
|
|
|
186
195
|
throw new Error(`Timeout waiting for any of: ${combined}`);
|
|
187
196
|
}
|
|
188
197
|
|
|
198
|
+
async _hasSelector(selector) {
|
|
199
|
+
const result = await this._cdp.send('Runtime.evaluate', {
|
|
200
|
+
expression: `!!document.querySelector(${JSON.stringify(selector)})`,
|
|
201
|
+
returnByValue: true,
|
|
202
|
+
});
|
|
203
|
+
return result.result?.value === true;
|
|
204
|
+
}
|
|
205
|
+
|
|
189
206
|
async _waitForText(text, timeoutMs = 8000) {
|
|
190
207
|
const deadline = Date.now() + timeoutMs;
|
|
191
208
|
while (Date.now() < deadline) {
|
|
@@ -364,7 +381,7 @@ export class XhsAdapter {
|
|
|
364
381
|
await sleep(500);
|
|
365
382
|
}
|
|
366
383
|
|
|
367
|
-
async _clickVisibleByText(text, selector) {
|
|
384
|
+
async _clickVisibleByText(text, selector, { throwOnMissing = true } = {}) {
|
|
368
385
|
const result = await this._cdp.send('Runtime.evaluate', {
|
|
369
386
|
expression: `
|
|
370
387
|
(function() {
|
|
@@ -374,7 +391,11 @@ export class XhsAdapter {
|
|
|
374
391
|
return r.width > 0 && r.height > 0 && r.left > -100 && s.display !== 'none' && s.visibility !== 'hidden';
|
|
375
392
|
};
|
|
376
393
|
const els = [...document.querySelectorAll(${JSON.stringify(selector)})].filter(visible);
|
|
377
|
-
const
|
|
394
|
+
const targetText = ${JSON.stringify(text)};
|
|
395
|
+
const el = els.find(e => {
|
|
396
|
+
const t = (e.innerText || e.textContent || '').trim();
|
|
397
|
+
return t === targetText || t.split(/\\s+/).includes(targetText) || t.includes(targetText);
|
|
398
|
+
});
|
|
378
399
|
const target = el?.closest('.creator-tab, button, [role="button"]') || el;
|
|
379
400
|
if (target) { target.click(); return true; }
|
|
380
401
|
return false;
|
|
@@ -382,8 +403,10 @@ export class XhsAdapter {
|
|
|
382
403
|
`,
|
|
383
404
|
returnByValue: true,
|
|
384
405
|
});
|
|
385
|
-
|
|
386
|
-
|
|
406
|
+
const clicked = result.result?.value === true;
|
|
407
|
+
if (!clicked && throwOnMissing) throw new Error(`PUBLISH_FAILED: 找不到小红书发布入口:${text}`);
|
|
408
|
+
if (clicked) await sleep(1000);
|
|
409
|
+
return clicked;
|
|
387
410
|
}
|
|
388
411
|
|
|
389
412
|
async _clickByText(text) {
|
package/package.json
CHANGED
package/src/browser-login.js
CHANGED
|
@@ -317,17 +317,32 @@ export class BrowserLoginSession {
|
|
|
317
317
|
const textHit = hit(textEl, textEl ? 'text:' + (textEl.innerText || textEl.textContent || '').trim() : '');
|
|
318
318
|
if (textHit) return textHit;
|
|
319
319
|
|
|
320
|
-
|
|
320
|
+
const fallbackHit = (function() {
|
|
321
|
+
${this._config.qrFallbackScript ?? 'return null;'}
|
|
322
|
+
})();
|
|
323
|
+
if (fallbackHit) return fallbackHit;
|
|
324
|
+
|
|
325
|
+
if (location.hostname.includes('xiaohongshu.com')) {
|
|
326
|
+
return {
|
|
327
|
+
via: 'xhs-calibrated-corner',
|
|
328
|
+
point: {
|
|
329
|
+
x: Math.round(window.innerWidth * 0.897),
|
|
330
|
+
y: Math.round(window.innerHeight * 0.339)
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
return null;
|
|
321
335
|
})()`,
|
|
322
336
|
returnByValue: true,
|
|
323
337
|
});
|
|
324
338
|
|
|
325
339
|
const hit = result.result?.value;
|
|
326
340
|
const rect = hit?.rect;
|
|
327
|
-
|
|
341
|
+
const point = hit?.point;
|
|
342
|
+
if (!rect && !point) return null;
|
|
328
343
|
|
|
329
|
-
const x = Math.round(rect.left + rect.width / 2);
|
|
330
|
-
const y = Math.round(rect.top + rect.height / 2);
|
|
344
|
+
const x = point?.x ?? Math.round(rect.left + rect.width / 2);
|
|
345
|
+
const y = point?.y ?? Math.round(rect.top + rect.height / 2);
|
|
331
346
|
await this.send('Input.dispatchMouseEvent', { type: 'mouseMoved', x, y }, 5_000);
|
|
332
347
|
await this.send('Input.dispatchMouseEvent', { type: 'mousePressed', x, y, button: 'left', clickCount: 1 }, 5_000);
|
|
333
348
|
await this.send('Input.dispatchMouseEvent', { type: 'mouseReleased', x, y, button: 'left', clickCount: 1 }, 5_000);
|