@lightcone-ai/daemon 0.9.71 → 0.9.72
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.
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Douyin (抖音) publisher adapter.
|
|
3
3
|
* Uses 抖音创作服务平台: https://creator.douyin.com
|
|
4
4
|
*/
|
|
5
|
+
import { formatTextWithTags } from '../text.js';
|
|
5
6
|
|
|
6
7
|
function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
|
|
7
8
|
|
|
@@ -51,7 +52,7 @@ export class DouyinAdapter {
|
|
|
51
52
|
await sleep(3000);
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
const fullText =
|
|
55
|
+
const fullText = formatTextWithTags(text, tags);
|
|
55
56
|
await this._fillField('[class*="content"] [contenteditable], [placeholder*="添加作品描述"]', fullText);
|
|
56
57
|
|
|
57
58
|
if (title) {
|
|
@@ -78,7 +79,7 @@ export class DouyinAdapter {
|
|
|
78
79
|
await this._uploadFiles([video], 'video');
|
|
79
80
|
await this._waitForText('上传成功', 120000);
|
|
80
81
|
|
|
81
|
-
const fullText =
|
|
82
|
+
const fullText = formatTextWithTags(text, tags);
|
|
82
83
|
await this._fillField('[placeholder*="添加作品描述"], [class*="content"] [contenteditable]', fullText);
|
|
83
84
|
|
|
84
85
|
if (title) {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Kuaishou (快手) publisher adapter.
|
|
3
3
|
* Uses 快手创作者平台: https://cp.kuaishou.com
|
|
4
4
|
*/
|
|
5
|
+
import { formatTextWithTags } from '../text.js';
|
|
5
6
|
|
|
6
7
|
function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
|
|
7
8
|
|
|
@@ -55,7 +56,7 @@ export class KuaishouAdapter {
|
|
|
55
56
|
await this._fillField('[placeholder*="标题"]', title);
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
const fullText =
|
|
59
|
+
const fullText = formatTextWithTags(text, tags);
|
|
59
60
|
await this._fillField('[placeholder*="描述"], [contenteditable]', fullText);
|
|
60
61
|
|
|
61
62
|
await sleep(1000);
|
|
@@ -82,7 +83,7 @@ export class KuaishouAdapter {
|
|
|
82
83
|
await this._fillField('[placeholder*="标题"]', title);
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
const fullText =
|
|
86
|
+
const fullText = formatTextWithTags(text, tags);
|
|
86
87
|
await this._fillField('[placeholder*="描述"], [contenteditable]', fullText);
|
|
87
88
|
|
|
88
89
|
await sleep(1000);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* XHS (小红书) publisher adapter.
|
|
3
3
|
* Uses deterministic CDP operations — no AI vision required.
|
|
4
4
|
*/
|
|
5
|
+
import { formatTextWithTags } from '../text.js';
|
|
5
6
|
|
|
6
7
|
function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
|
|
7
8
|
function randomInt(min, max) { return Math.floor(min + Math.random() * (max - min + 1)); }
|
|
@@ -97,8 +98,8 @@ export class XhsAdapter {
|
|
|
97
98
|
await humanPause(1200, 2800, 'after-title');
|
|
98
99
|
}
|
|
99
100
|
|
|
100
|
-
// Fill content text
|
|
101
|
-
const fullText =
|
|
101
|
+
// Fill content text and only append tags that are not already present.
|
|
102
|
+
const fullText = formatTextWithTags(text, tags);
|
|
102
103
|
await this._fillField(CONTENT_SELECTOR, fullText);
|
|
103
104
|
|
|
104
105
|
await humanPause(4500, 9000, 'before-publish-check');
|
|
@@ -142,7 +143,7 @@ export class XhsAdapter {
|
|
|
142
143
|
await humanPause(1200, 2800, 'after-title');
|
|
143
144
|
}
|
|
144
145
|
|
|
145
|
-
const fullText =
|
|
146
|
+
const fullText = formatTextWithTags(text, tags);
|
|
146
147
|
await this._fillField(CONTENT_SELECTOR, fullText);
|
|
147
148
|
|
|
148
149
|
await humanPause(4500, 9000, 'before-publish-check');
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
function escapeRegExp(value) {
|
|
2
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function normalizeTags(tags = []) {
|
|
6
|
+
const seen = new Set();
|
|
7
|
+
const normalized = [];
|
|
8
|
+
for (const raw of tags) {
|
|
9
|
+
const tag = String(raw ?? '').trim().replace(/^[##]+/, '').trim();
|
|
10
|
+
if (!tag || seen.has(tag)) continue;
|
|
11
|
+
seen.add(tag);
|
|
12
|
+
normalized.push(tag);
|
|
13
|
+
}
|
|
14
|
+
return normalized;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function formatTextWithTags(text, tags = []) {
|
|
18
|
+
const base = String(text ?? '').trimEnd();
|
|
19
|
+
const missingTags = normalizeTags(tags).filter(tag => {
|
|
20
|
+
const pattern = new RegExp(`(^|[\\s,,。!?!?::;;、])(?:#|#)${escapeRegExp(tag)}(?=$|[\\s,,。!?!?::;;、])`);
|
|
21
|
+
return !pattern.test(base);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
if (missingTags.length === 0) return base;
|
|
25
|
+
const suffix = missingTags.map(tag => `#${tag}`).join(' ');
|
|
26
|
+
return base ? `${base}\n${suffix}` : suffix;
|
|
27
|
+
}
|