@lightcone-ai/daemon 0.14.11 → 0.14.13
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/publish-job-runner.js +95 -20
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ import { KuaishouAdapter } from '../mcp-servers/publisher/adapters/kuaishou.js';
|
|
|
7
7
|
import { callOfficialTool } from '../mcp-servers/publisher/official-tool-client.js';
|
|
8
8
|
import { runPublishPrecheck } from '../mcp-servers/publisher/precheck.js';
|
|
9
9
|
import { withProfileLock } from './profile-lock.js';
|
|
10
|
+
import { profileDir as getBrowserProfileDir } from './browser-login.js';
|
|
10
11
|
|
|
11
12
|
const PLATFORM_ENV_KEYS = {
|
|
12
13
|
xhs: 'XHS_PROFILE_DIR',
|
|
@@ -36,10 +37,53 @@ function asObject(value) {
|
|
|
36
37
|
return {};
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
function
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
export function resolveProfileDir(platform, { ownerId } = {}) {
|
|
41
|
+
const envKey = PLATFORM_ENV_KEYS[platform];
|
|
42
|
+
const envValue = normalizeText(envKey ? process.env[envKey] : null);
|
|
43
|
+
if (envValue) {
|
|
44
|
+
return {
|
|
45
|
+
profileDir: envValue,
|
|
46
|
+
source: 'env',
|
|
47
|
+
envKey,
|
|
48
|
+
ownerId: normalizeText(ownerId),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const normalizedOwnerId = normalizeText(ownerId);
|
|
53
|
+
if (normalizedOwnerId) {
|
|
54
|
+
return {
|
|
55
|
+
profileDir: getBrowserProfileDir(platform, normalizedOwnerId),
|
|
56
|
+
source: 'owner',
|
|
57
|
+
envKey,
|
|
58
|
+
ownerId: normalizedOwnerId,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
profileDir: null,
|
|
64
|
+
source: 'missing_owner',
|
|
65
|
+
envKey,
|
|
66
|
+
ownerId: null,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function resolveExistingProfileDir(platform, { ownerId } = {}) {
|
|
71
|
+
const resolved = resolveProfileDir(platform, { ownerId });
|
|
72
|
+
if (!resolved.profileDir) {
|
|
73
|
+
throw new Error('publish:job missing owner_id; server must include it for cross-machine profile resolution');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!existsSync(resolved.profileDir)) {
|
|
77
|
+
if (resolved.source === 'env') {
|
|
78
|
+
throw new Error(`Profile dir from ${resolved.envKey} not found: ${resolved.profileDir}`);
|
|
79
|
+
}
|
|
80
|
+
throw new Error(
|
|
81
|
+
`Profile dir for ${platform} not found at ${resolved.profileDir}; ` +
|
|
82
|
+
'user must complete browser-login on this machine first'
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return resolved.profileDir;
|
|
43
87
|
}
|
|
44
88
|
|
|
45
89
|
function getAdapterClass(platform) {
|
|
@@ -53,22 +97,16 @@ function createStaticAdapter(platform) {
|
|
|
53
97
|
return new AdapterClass(null);
|
|
54
98
|
}
|
|
55
99
|
|
|
56
|
-
async function getAdapter(platform) {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
throw new Error(`No profile dir for platform="${platform}". Has the user logged in and authorized this machine?`);
|
|
60
|
-
}
|
|
61
|
-
const cdp = await getSession(platform, profileDir);
|
|
100
|
+
async function getAdapter(platform, { ownerId } = {}) {
|
|
101
|
+
const resolvedProfileDir = resolveExistingProfileDir(platform, { ownerId });
|
|
102
|
+
const cdp = await getSession(platform, resolvedProfileDir);
|
|
62
103
|
const AdapterClass = getAdapterClass(platform);
|
|
63
104
|
return new AdapterClass(cdp);
|
|
64
105
|
}
|
|
65
106
|
|
|
66
|
-
async function withPublisherProfile(platform, fn) {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
throw new Error(`No profile dir for platform="${platform}". Has the user logged in and authorized this machine?`);
|
|
70
|
-
}
|
|
71
|
-
return withProfileLock(platform, profileDir, {
|
|
107
|
+
async function withPublisherProfile(platform, { ownerId } = {}, fn) {
|
|
108
|
+
const resolvedProfileDir = resolveExistingProfileDir(platform, { ownerId });
|
|
109
|
+
return withProfileLock(platform, resolvedProfileDir, {
|
|
72
110
|
owner: `publisher:${platform}`,
|
|
73
111
|
timeoutMs: 30_000,
|
|
74
112
|
staleMs: 20 * 60 * 1000,
|
|
@@ -110,6 +148,31 @@ export async function fetchPublishJobWorkspaceFile({ serverUrl, machineApiKey, j
|
|
|
110
148
|
return res.json();
|
|
111
149
|
}
|
|
112
150
|
|
|
151
|
+
export async function streamPublishJobVideo({ serverUrl, machineApiKey, jobId, videoId, localPath }) {
|
|
152
|
+
const normalizedJobId = String(jobId ?? '').trim();
|
|
153
|
+
if (!normalizedJobId) {
|
|
154
|
+
throw new Error('publish job id is required to fetch video files');
|
|
155
|
+
}
|
|
156
|
+
const normalizedVideoId = String(videoId ?? '').trim();
|
|
157
|
+
if (!normalizedVideoId) {
|
|
158
|
+
throw new Error('video id is required to fetch video files');
|
|
159
|
+
}
|
|
160
|
+
const url = `${String(serverUrl).replace(/\/$/, '')}/internal/agent/publish-jobs/${encodeURIComponent(normalizedJobId)}/video-files/${encodeURIComponent(normalizedVideoId)}`;
|
|
161
|
+
const res = await fetch(url, {
|
|
162
|
+
headers: {
|
|
163
|
+
Authorization: `Bearer ${machineApiKey}`,
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
if (!res.ok) {
|
|
167
|
+
const text = await res.text().catch(() => '');
|
|
168
|
+
throw new Error(`publish-jobs video-files GET failed (${res.status}): ${text}`);
|
|
169
|
+
}
|
|
170
|
+
const data = Buffer.from(await res.arrayBuffer());
|
|
171
|
+
mkdirSync(path.dirname(localPath), { recursive: true });
|
|
172
|
+
writeFileSync(localPath, data);
|
|
173
|
+
return localPath;
|
|
174
|
+
}
|
|
175
|
+
|
|
113
176
|
export function workspacePathFromMediaPath(filePath, workspaceId) {
|
|
114
177
|
if (!filePath) return null;
|
|
115
178
|
|
|
@@ -144,6 +207,7 @@ export async function materializeWorkspaceMedia({
|
|
|
144
207
|
machineApiKey,
|
|
145
208
|
jobId,
|
|
146
209
|
fetchWorkspaceFile = fetchPublishJobWorkspaceFile,
|
|
210
|
+
streamVideoFile = streamPublishJobVideo,
|
|
147
211
|
}) {
|
|
148
212
|
if (!filePath || existsSync(filePath)) return filePath;
|
|
149
213
|
|
|
@@ -164,8 +228,18 @@ export async function materializeWorkspaceMedia({
|
|
|
164
228
|
jobId,
|
|
165
229
|
relPath: workspacePath.relPath,
|
|
166
230
|
});
|
|
167
|
-
|
|
168
|
-
|
|
231
|
+
if (data?.videoId) {
|
|
232
|
+
await streamVideoFile({
|
|
233
|
+
serverUrl,
|
|
234
|
+
machineApiKey,
|
|
235
|
+
jobId,
|
|
236
|
+
videoId: data.videoId,
|
|
237
|
+
localPath,
|
|
238
|
+
});
|
|
239
|
+
} else {
|
|
240
|
+
mkdirSync(path.dirname(localPath), { recursive: true });
|
|
241
|
+
writeFileSync(localPath, decodeWorkspaceContent(data.content));
|
|
242
|
+
}
|
|
169
243
|
return localPath;
|
|
170
244
|
}
|
|
171
245
|
|
|
@@ -368,6 +442,7 @@ export async function runPublishJob({ serverUrl, machineApiKey, agentId, workspa
|
|
|
368
442
|
video,
|
|
369
443
|
cover,
|
|
370
444
|
} = buildJobInput(job);
|
|
445
|
+
const ownerId = normalizeText(job?.owner_id ?? job?.ownerId);
|
|
371
446
|
|
|
372
447
|
if (!platform) throw new Error('publish job missing platform');
|
|
373
448
|
if (!contentType) throw new Error('publish job missing content_type');
|
|
@@ -428,8 +503,8 @@ export async function runPublishJob({ serverUrl, machineApiKey, agentId, workspa
|
|
|
428
503
|
});
|
|
429
504
|
|
|
430
505
|
try {
|
|
431
|
-
const { publishResult, healthCheck } = await withPublisherProfile(platform, async () => {
|
|
432
|
-
const adapter = await getAdapter(platform);
|
|
506
|
+
const { publishResult, healthCheck } = await withPublisherProfile(platform, { ownerId }, async () => {
|
|
507
|
+
const adapter = await getAdapter(platform, { ownerId });
|
|
433
508
|
const prePublishLogin = await adapter.checkLoginStatus();
|
|
434
509
|
if (prePublishLogin?.loggedIn === false) {
|
|
435
510
|
throw new Error(`LOGIN_EXPIRED:${platform}`);
|