channel-worker 1.6.3 → 1.6.4

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.
@@ -75,6 +75,9 @@ class CommandPoller {
75
75
  case 'restart_worker':
76
76
  await this.handleRestartWorker(command);
77
77
  break;
78
+ case 'launch_veo3_profile':
79
+ await this.handleLaunchVeo3Profile(command);
80
+ break;
78
81
  default:
79
82
  // Other commands (scan_facebook_pages, etc.) handled by extension
80
83
  console.log(`[commands] Skipping ${command.type} — handled by extension`);
@@ -167,6 +170,83 @@ class CommandPoller {
167
170
  }
168
171
  }
169
172
 
173
+ async handleLaunchVeo3Profile(command) {
174
+ const { nst_profile_id, name, veo3_worker_id, os, proxy } = command.payload || {};
175
+ console.log(`[commands] Launching Veo3 profile: ${nst_profile_id} (${name}) os=${os || 'windows'}`);
176
+
177
+ try {
178
+ if (!this.nst) {
179
+ const apiKey = await this.api.getSetting('nst_api_key');
180
+ if (apiKey) {
181
+ this.nst = new NstManager(apiKey);
182
+ } else {
183
+ throw new Error('Nstbrowser API key not configured.');
184
+ }
185
+ }
186
+
187
+ // Auto-create Nstbrowser profile if not exists
188
+ await this.nst.ensureProfile(nst_profile_id, { os: os || 'windows' });
189
+
190
+ // Use Content Creator extension path (separate from channel-manager-ext)
191
+ const baseExtPath = this.config.content_creator_ext_path || '';
192
+ if (!baseExtPath) throw new Error('content_creator_ext_path not configured in worker config.');
193
+
194
+ let extensionPath = baseExtPath;
195
+
196
+ // Create unique extension dir per profile
197
+ if (nst_profile_id) {
198
+ const fs = require('fs');
199
+ const path = require('path');
200
+ const ts = Date.now();
201
+ const uniqueExtPath = baseExtPath + '-' + nst_profile_id + '-' + ts;
202
+ try {
203
+ fs.mkdirSync(uniqueExtPath, { recursive: true });
204
+ const files = fs.readdirSync(baseExtPath);
205
+ for (const f of files) {
206
+ const src = path.join(baseExtPath, f);
207
+ if (fs.statSync(src).isFile()) fs.copyFileSync(src, path.join(uniqueExtPath, f));
208
+ }
209
+ // Write Veo3-specific config.json
210
+ fs.writeFileSync(path.join(uniqueExtPath, 'config.json'), JSON.stringify({
211
+ channelManagerApi: 'https://api.channel.tunasm.art',
212
+ profileId: nst_profile_id,
213
+ workerToken: this.config.worker_token || '',
214
+ workerType: 'veo3',
215
+ }));
216
+ extensionPath = uniqueExtPath;
217
+ console.log(`[commands] Veo3 ext dir: ${uniqueExtPath}`);
218
+
219
+ // Cleanup old dirs
220
+ const parent = path.dirname(baseExtPath);
221
+ const baseName = path.basename(baseExtPath);
222
+ const oldDirs = fs.readdirSync(parent)
223
+ .filter(d => d.startsWith(baseName + '-' + nst_profile_id) && d !== path.basename(uniqueExtPath))
224
+ .map(d => path.join(parent, d))
225
+ .filter(d => { try { return fs.statSync(d).isDirectory(); } catch { return false; } });
226
+ for (const d of oldDirs) {
227
+ try { fs.rmSync(d, { recursive: true }); } catch {}
228
+ }
229
+ } catch (e) {
230
+ console.warn(`[commands] Unique Veo3 ext dir failed: ${e.message}, using base`);
231
+ }
232
+ }
233
+
234
+ const result = await this.nst.launchProfile(nst_profile_id, { proxy: proxy || null, extensionPath });
235
+ console.log(`[commands] Veo3 profile ${nst_profile_id} launched${proxy ? ' (proxy)' : ''}`);
236
+
237
+ await this.api.updateCommand(command._id, {
238
+ status: 'done',
239
+ result: { profile_id: result.profileId, launched_at: new Date().toISOString() },
240
+ });
241
+ } catch (err) {
242
+ console.error(`[commands] Failed to launch Veo3 profile: ${err.message}`);
243
+ await this.api.updateCommand(command._id, {
244
+ status: 'failed',
245
+ error: err.message,
246
+ });
247
+ }
248
+ }
249
+
170
250
  async handleScanFacebookPages(command) {
171
251
  const { profile_id } = command.payload || {};
172
252
  console.log(`[commands] Scan Facebook pages — launching profile: ${profile_id}`);
@@ -65,19 +65,20 @@ class NstManager {
65
65
  }
66
66
 
67
67
  // Create profile if not exists, return profileId
68
- async ensureProfile(name) {
68
+ async ensureProfile(name, options = {}) {
69
69
  const existing = await this.findProfile(name);
70
70
  if (existing) {
71
71
  console.log(`[nst] Profile "${name}" exists: ${existing}`);
72
72
  return existing;
73
73
  }
74
74
 
75
- console.log(`[nst] WARNING: Profile "${name}" NOT FOUND creating new profile...`);
75
+ const platform = (options.os || 'windows').toLowerCase() === 'mac' ? 'MacOS' : 'Windows';
76
+ console.log(`[nst] WARNING: Profile "${name}" NOT FOUND — creating new profile (${platform})...`);
76
77
  const res = await this.api('/profiles', {
77
78
  method: 'POST',
78
79
  body: JSON.stringify({
79
80
  name,
80
- platform: 'Windows',
81
+ platform,
81
82
  kernelMilestone: '132',
82
83
  fingerprint: {
83
84
  flags: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "channel-worker",
3
- "version": "1.6.3",
3
+ "version": "1.6.4",
4
4
  "description": "Channel Manager worker daemon — runs on remote machines to execute video pipeline jobs",
5
5
  "main": "lib/daemon.js",
6
6
  "bin": {