n8n-nodes-tts-bigboss 1.0.6 → 1.0.7
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/dist/TTSBigBoss.node.js +134 -36
- package/nodes/TTSBigBoss/TTSBigBoss.node.ts +141 -39
- package/package.json +1 -1
package/dist/TTSBigBoss.node.js
CHANGED
|
@@ -125,7 +125,7 @@ class TTSBigBoss {
|
|
|
125
125
|
{
|
|
126
126
|
name: 'Coqui TTS (Local Server)',
|
|
127
127
|
value: 'coqui',
|
|
128
|
-
description: 'Connect to a running Coqui TTS/XTTS server
|
|
128
|
+
description: 'Connect to a running Coqui TTS/XTTS server.',
|
|
129
129
|
},
|
|
130
130
|
{
|
|
131
131
|
name: 'System Command (Custom)',
|
|
@@ -277,11 +277,11 @@ class TTSBigBoss {
|
|
|
277
277
|
description: 'Name from Hugging Face (e.g. en_US-bryce-medium) or full URL to .onnx file.',
|
|
278
278
|
},
|
|
279
279
|
{
|
|
280
|
-
displayName: 'Server URL',
|
|
280
|
+
displayName: 'Base Server URL',
|
|
281
281
|
name: 'coquiUrl',
|
|
282
282
|
type: 'string',
|
|
283
|
-
default: 'http://
|
|
284
|
-
description: 'URL of
|
|
283
|
+
default: 'http://host.docker.internal:5002',
|
|
284
|
+
description: 'Base URL of Coqui server (e.g. http://172.17.0.1:5002 if in Docker). Do not include /api/tts.',
|
|
285
285
|
displayOptions: {
|
|
286
286
|
show: {
|
|
287
287
|
engine: ['coqui'],
|
|
@@ -289,23 +289,56 @@ class TTSBigBoss {
|
|
|
289
289
|
},
|
|
290
290
|
},
|
|
291
291
|
{
|
|
292
|
-
displayName: 'Speaker
|
|
292
|
+
displayName: 'Speaker',
|
|
293
293
|
name: 'coquiSpeaker',
|
|
294
|
+
type: 'options',
|
|
295
|
+
typeOptions: {
|
|
296
|
+
loadOptionsMethod: 'getCoquiSpeakers',
|
|
297
|
+
loadOptionsDependsOn: ['coquiUrl'],
|
|
298
|
+
},
|
|
299
|
+
default: '',
|
|
300
|
+
description: 'Select a speaker ID loaded from the server.',
|
|
301
|
+
displayOptions: {
|
|
302
|
+
show: {
|
|
303
|
+
engine: ['coqui'],
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
displayName: 'Use Custom WAV Path',
|
|
309
|
+
name: 'coquiUseWav',
|
|
310
|
+
type: 'boolean',
|
|
311
|
+
default: false,
|
|
312
|
+
description: 'Check to use a local WAV file path instead of a Speaker ID (for cloning).',
|
|
313
|
+
displayOptions: {
|
|
314
|
+
show: {
|
|
315
|
+
engine: ['coqui'],
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
displayName: 'WAV Path',
|
|
321
|
+
name: 'coquiWavPath',
|
|
294
322
|
type: 'string',
|
|
295
323
|
default: '',
|
|
296
|
-
description: '
|
|
324
|
+
description: 'Absolute path to the reference WAV file on the server.',
|
|
297
325
|
displayOptions: {
|
|
298
326
|
show: {
|
|
299
327
|
engine: ['coqui'],
|
|
328
|
+
coquiUseWav: [true],
|
|
300
329
|
},
|
|
301
330
|
},
|
|
302
331
|
},
|
|
303
332
|
{
|
|
304
333
|
displayName: 'Language',
|
|
305
334
|
name: 'coquiLang',
|
|
306
|
-
type: '
|
|
335
|
+
type: 'options',
|
|
336
|
+
typeOptions: {
|
|
337
|
+
loadOptionsMethod: 'getCoquiLanguages',
|
|
338
|
+
loadOptionsDependsOn: ['coquiUrl'],
|
|
339
|
+
},
|
|
307
340
|
default: 'en',
|
|
308
|
-
description: '
|
|
341
|
+
description: 'Select language.',
|
|
309
342
|
displayOptions: {
|
|
310
343
|
show: {
|
|
311
344
|
engine: ['coqui'],
|
|
@@ -314,6 +347,60 @@ class TTSBigBoss {
|
|
|
314
347
|
},
|
|
315
348
|
],
|
|
316
349
|
};
|
|
350
|
+
this.methods = {
|
|
351
|
+
loadOptions: {
|
|
352
|
+
async getCoquiSpeakers() {
|
|
353
|
+
const baseUrl = this.getNodeParameter('coquiUrl');
|
|
354
|
+
const cleanUrl = baseUrl.replace(/\/$/, '');
|
|
355
|
+
const targetUrl = `${cleanUrl}/api/speakers`;
|
|
356
|
+
try {
|
|
357
|
+
const data = await httpRequest(targetUrl);
|
|
358
|
+
const json = JSON.parse(data.toString());
|
|
359
|
+
let speakers = [];
|
|
360
|
+
if (Array.isArray(json))
|
|
361
|
+
speakers = json;
|
|
362
|
+
else if (json.speakers)
|
|
363
|
+
speakers = json.speakers;
|
|
364
|
+
else if (typeof json === 'object')
|
|
365
|
+
speakers = Object.keys(json);
|
|
366
|
+
return speakers.map((s) => {
|
|
367
|
+
const name = typeof s === 'string' ? s : (s.name || s.id);
|
|
368
|
+
const value = typeof s === 'string' ? s : (s.id || s.name);
|
|
369
|
+
return { name, value };
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
catch (e) {
|
|
373
|
+
return [{ name: `Error loading: ${e.message}. Check URL & Connection.`, value: '' }];
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
async getCoquiLanguages() {
|
|
377
|
+
const baseUrl = this.getNodeParameter('coquiUrl');
|
|
378
|
+
const cleanUrl = baseUrl.replace(/\/$/, '');
|
|
379
|
+
const targetUrl = `${cleanUrl}/api/languages`;
|
|
380
|
+
try {
|
|
381
|
+
const data = await httpRequest(targetUrl);
|
|
382
|
+
const json = JSON.parse(data.toString());
|
|
383
|
+
let langs = [];
|
|
384
|
+
if (Array.isArray(json))
|
|
385
|
+
langs = json;
|
|
386
|
+
else if (json.languages)
|
|
387
|
+
langs = json.languages;
|
|
388
|
+
return langs.map((l) => {
|
|
389
|
+
const name = typeof l === 'string' ? l : (l.name || l.code);
|
|
390
|
+
const value = typeof l === 'string' ? l : (l.code || l.name);
|
|
391
|
+
return { name, value };
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
catch (e) {
|
|
395
|
+
return [
|
|
396
|
+
{ name: 'English (en)', value: 'en' },
|
|
397
|
+
{ name: 'Arabic (ar)', value: 'ar' },
|
|
398
|
+
{ name: 'Examples (Fix URL to load)', value: 'en' }
|
|
399
|
+
];
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
},
|
|
403
|
+
};
|
|
317
404
|
}
|
|
318
405
|
async execute() {
|
|
319
406
|
const items = this.getInputData();
|
|
@@ -384,38 +471,23 @@ class TTSBigBoss {
|
|
|
384
471
|
fs.unlinkSync(outFile);
|
|
385
472
|
}
|
|
386
473
|
else if (engine === 'coqui') {
|
|
387
|
-
|
|
388
|
-
|
|
474
|
+
let url = this.getNodeParameter('coquiUrl', i);
|
|
475
|
+
url = url.replace(/\/$/, '') + '/api/tts';
|
|
476
|
+
const speakerSelection = this.getNodeParameter('coquiSpeaker', i);
|
|
477
|
+
const useWav = this.getNodeParameter('coquiUseWav', i, false);
|
|
478
|
+
const wavPath = this.getNodeParameter('coquiWavPath', i, '');
|
|
389
479
|
const lang = this.getNodeParameter('coquiLang', i);
|
|
390
480
|
const payload = {
|
|
391
481
|
text: text,
|
|
392
482
|
language_id: lang,
|
|
393
483
|
};
|
|
394
|
-
if (
|
|
395
|
-
payload.
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
'Content-Type': 'application/json',
|
|
402
|
-
}
|
|
403
|
-
}, (res) => {
|
|
404
|
-
const chunks = [];
|
|
405
|
-
res.on('data', (d) => chunks.push(d));
|
|
406
|
-
res.on('end', () => {
|
|
407
|
-
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
408
|
-
resolve(Buffer.concat(chunks));
|
|
409
|
-
}
|
|
410
|
-
else {
|
|
411
|
-
reject(new Error(`Coqui Server Error ${res.statusCode}: ${Buffer.concat(chunks).toString()}`));
|
|
412
|
-
}
|
|
413
|
-
});
|
|
414
|
-
});
|
|
415
|
-
req.on('error', reject);
|
|
416
|
-
req.write(JSON.stringify(payload));
|
|
417
|
-
req.end();
|
|
418
|
-
});
|
|
484
|
+
if (useWav && wavPath) {
|
|
485
|
+
payload.speaker_wav = wavPath;
|
|
486
|
+
}
|
|
487
|
+
else if (speakerSelection) {
|
|
488
|
+
payload.speaker_id = speakerSelection;
|
|
489
|
+
}
|
|
490
|
+
audioBuffer = await httpRequest(url, 'POST', payload);
|
|
419
491
|
srtBuffer = Buffer.from(generateHeuristicSRT(text, audioBuffer.length), 'utf8');
|
|
420
492
|
}
|
|
421
493
|
else {
|
|
@@ -481,7 +553,7 @@ async function runEdgeTTS(text, voice, rate, pitch) {
|
|
|
481
553
|
return new Promise((resolve, reject) => {
|
|
482
554
|
const ws = new ws_1.default(EDGE_URL, {
|
|
483
555
|
headers: {
|
|
484
|
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
556
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0',
|
|
485
557
|
'Origin': 'chrome-extension://jdiccldimpdaibmpdkjnbmckianbfold',
|
|
486
558
|
'TrustedClientToken': '6A5AA1D4EAFF4E9FB37E23D68491D6F4'
|
|
487
559
|
}
|
|
@@ -736,3 +808,29 @@ async function downloadFile(url, dest) {
|
|
|
736
808
|
});
|
|
737
809
|
});
|
|
738
810
|
}
|
|
811
|
+
async function httpRequest(url, method = 'GET', body = null) {
|
|
812
|
+
const requestModule = url.startsWith('https') ? https : http;
|
|
813
|
+
return new Promise((resolve, reject) => {
|
|
814
|
+
const req = requestModule.request(url, {
|
|
815
|
+
method: method,
|
|
816
|
+
headers: {
|
|
817
|
+
'Content-Type': 'application/json',
|
|
818
|
+
}
|
|
819
|
+
}, (res) => {
|
|
820
|
+
const chunks = [];
|
|
821
|
+
res.on('data', (d) => chunks.push(d));
|
|
822
|
+
res.on('end', () => {
|
|
823
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
824
|
+
resolve(Buffer.concat(chunks));
|
|
825
|
+
}
|
|
826
|
+
else {
|
|
827
|
+
reject(new Error(`Server Request Failed ${res.statusCode}: ${Buffer.concat(chunks).toString()}`));
|
|
828
|
+
}
|
|
829
|
+
});
|
|
830
|
+
});
|
|
831
|
+
req.on('error', reject);
|
|
832
|
+
if (body)
|
|
833
|
+
req.write(JSON.stringify(body));
|
|
834
|
+
req.end();
|
|
835
|
+
});
|
|
836
|
+
}
|
|
@@ -3,6 +3,8 @@ import {
|
|
|
3
3
|
INodeExecutionData,
|
|
4
4
|
INodeType,
|
|
5
5
|
INodeTypeDescription,
|
|
6
|
+
ILoadOptionsFunctions,
|
|
7
|
+
INodePropertyOptions,
|
|
6
8
|
} from 'n8n-workflow';
|
|
7
9
|
import { v4 as uuidv4 } from 'uuid';
|
|
8
10
|
import * as fs from 'fs';
|
|
@@ -123,7 +125,7 @@ export class TTSBigBoss implements INodeType {
|
|
|
123
125
|
{
|
|
124
126
|
name: 'Coqui TTS (Local Server)',
|
|
125
127
|
value: 'coqui',
|
|
126
|
-
description: 'Connect to a running Coqui TTS/XTTS server
|
|
128
|
+
description: 'Connect to a running Coqui TTS/XTTS server.',
|
|
127
129
|
},
|
|
128
130
|
{
|
|
129
131
|
name: 'System Command (Custom)',
|
|
@@ -290,11 +292,11 @@ export class TTSBigBoss implements INodeType {
|
|
|
290
292
|
// Coqui Server Settings
|
|
291
293
|
// ----------------------------------
|
|
292
294
|
{
|
|
293
|
-
displayName: 'Server URL',
|
|
295
|
+
displayName: 'Base Server URL',
|
|
294
296
|
name: 'coquiUrl',
|
|
295
297
|
type: 'string',
|
|
296
|
-
default: 'http://
|
|
297
|
-
description: 'URL of
|
|
298
|
+
default: 'http://host.docker.internal:5002',
|
|
299
|
+
description: 'Base URL of Coqui server (e.g. http://172.17.0.1:5002 if in Docker). Do not include /api/tts.',
|
|
298
300
|
displayOptions: {
|
|
299
301
|
show: {
|
|
300
302
|
engine: ['coqui'],
|
|
@@ -302,23 +304,56 @@ export class TTSBigBoss implements INodeType {
|
|
|
302
304
|
},
|
|
303
305
|
},
|
|
304
306
|
{
|
|
305
|
-
displayName: 'Speaker
|
|
307
|
+
displayName: 'Speaker',
|
|
306
308
|
name: 'coquiSpeaker',
|
|
309
|
+
type: 'options',
|
|
310
|
+
typeOptions: {
|
|
311
|
+
loadOptionsMethod: 'getCoquiSpeakers',
|
|
312
|
+
loadOptionsDependsOn: ['coquiUrl'],
|
|
313
|
+
},
|
|
314
|
+
default: '',
|
|
315
|
+
description: 'Select a speaker ID loaded from the server.',
|
|
316
|
+
displayOptions: {
|
|
317
|
+
show: {
|
|
318
|
+
engine: ['coqui'],
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
displayName: 'Use Custom WAV Path',
|
|
324
|
+
name: 'coquiUseWav',
|
|
325
|
+
type: 'boolean',
|
|
326
|
+
default: false,
|
|
327
|
+
description: 'Check to use a local WAV file path instead of a Speaker ID (for cloning).',
|
|
328
|
+
displayOptions: {
|
|
329
|
+
show: {
|
|
330
|
+
engine: ['coqui'],
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
displayName: 'WAV Path',
|
|
336
|
+
name: 'coquiWavPath',
|
|
307
337
|
type: 'string',
|
|
308
338
|
default: '',
|
|
309
|
-
description: '
|
|
339
|
+
description: 'Absolute path to the reference WAV file on the server.',
|
|
310
340
|
displayOptions: {
|
|
311
341
|
show: {
|
|
312
342
|
engine: ['coqui'],
|
|
343
|
+
coquiUseWav: [true],
|
|
313
344
|
},
|
|
314
345
|
},
|
|
315
346
|
},
|
|
316
347
|
{
|
|
317
348
|
displayName: 'Language',
|
|
318
349
|
name: 'coquiLang',
|
|
319
|
-
type: '
|
|
350
|
+
type: 'options',
|
|
351
|
+
typeOptions: {
|
|
352
|
+
loadOptionsMethod: 'getCoquiLanguages',
|
|
353
|
+
loadOptionsDependsOn: ['coquiUrl'],
|
|
354
|
+
},
|
|
320
355
|
default: 'en',
|
|
321
|
-
description: '
|
|
356
|
+
description: 'Select language.',
|
|
322
357
|
displayOptions: {
|
|
323
358
|
show: {
|
|
324
359
|
engine: ['coqui'],
|
|
@@ -328,6 +363,63 @@ export class TTSBigBoss implements INodeType {
|
|
|
328
363
|
],
|
|
329
364
|
};
|
|
330
365
|
|
|
366
|
+
methods = {
|
|
367
|
+
loadOptions: {
|
|
368
|
+
async getCoquiSpeakers(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
|
369
|
+
const baseUrl = this.getNodeParameter('coquiUrl') as string;
|
|
370
|
+
// clean url
|
|
371
|
+
const cleanUrl = baseUrl.replace(/\/$/, '');
|
|
372
|
+
const targetUrl = `${cleanUrl}/api/speakers`; // Assumption: endpoints exist
|
|
373
|
+
|
|
374
|
+
try {
|
|
375
|
+
const data = await httpRequest(targetUrl);
|
|
376
|
+
// Assume data is [ {name: "id", ...} ] or [ "id", "id" ] or { "speakers": [...] }
|
|
377
|
+
const json = JSON.parse(data.toString());
|
|
378
|
+
let speakers: any[] = [];
|
|
379
|
+
|
|
380
|
+
if (Array.isArray(json)) speakers = json;
|
|
381
|
+
else if (json.speakers) speakers = json.speakers;
|
|
382
|
+
else if (typeof json === 'object') speakers = Object.keys(json);
|
|
383
|
+
|
|
384
|
+
return speakers.map((s: any) => {
|
|
385
|
+
const name = typeof s === 'string' ? s : (s.name || s.id);
|
|
386
|
+
const value = typeof s === 'string' ? s : (s.id || s.name);
|
|
387
|
+
return { name, value };
|
|
388
|
+
});
|
|
389
|
+
} catch (e: any) {
|
|
390
|
+
return [{ name: `Error loading: ${e.message}. Check URL & Connection.`, value: '' }];
|
|
391
|
+
}
|
|
392
|
+
},
|
|
393
|
+
async getCoquiLanguages(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
|
394
|
+
const baseUrl = this.getNodeParameter('coquiUrl') as string;
|
|
395
|
+
const cleanUrl = baseUrl.replace(/\/$/, '');
|
|
396
|
+
const targetUrl = `${cleanUrl}/api/languages`;
|
|
397
|
+
|
|
398
|
+
try {
|
|
399
|
+
const data = await httpRequest(targetUrl);
|
|
400
|
+
const json = JSON.parse(data.toString());
|
|
401
|
+
let langs: any[] = [];
|
|
402
|
+
|
|
403
|
+
if (Array.isArray(json)) langs = json;
|
|
404
|
+
else if (json.languages) langs = json.languages;
|
|
405
|
+
|
|
406
|
+
return langs.map((l: any) => {
|
|
407
|
+
const name = typeof l === 'string' ? l : (l.name || l.code);
|
|
408
|
+
const value = typeof l === 'string' ? l : (l.code || l.name);
|
|
409
|
+
return { name, value };
|
|
410
|
+
});
|
|
411
|
+
} catch (e) {
|
|
412
|
+
// Fallback defaults if api fails
|
|
413
|
+
return [
|
|
414
|
+
{ name: 'English (en)', value: 'en' },
|
|
415
|
+
{ name: 'Arabic (ar)', value: 'ar' },
|
|
416
|
+
{ name: 'Examples (Fix URL to load)', value: 'en' }
|
|
417
|
+
];
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
};
|
|
422
|
+
|
|
331
423
|
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
|
332
424
|
const items = this.getInputData();
|
|
333
425
|
const returnData: INodeExecutionData[] = [];
|
|
@@ -426,43 +518,28 @@ export class TTSBigBoss implements INodeType {
|
|
|
426
518
|
// ----------------------------------
|
|
427
519
|
// COQUI SEVER EXECUTION
|
|
428
520
|
// ----------------------------------
|
|
429
|
-
|
|
430
|
-
|
|
521
|
+
let url = this.getNodeParameter('coquiUrl', i) as string;
|
|
522
|
+
url = url.replace(/\/$/, '') + '/api/tts'; // Append standard endpoint
|
|
523
|
+
|
|
524
|
+
const speakerSelection = this.getNodeParameter('coquiSpeaker', i) as string;
|
|
525
|
+
const useWav = this.getNodeParameter('coquiUseWav', i, false) as boolean;
|
|
526
|
+
const wavPath = this.getNodeParameter('coquiWavPath', i, '') as string;
|
|
431
527
|
const lang = this.getNodeParameter('coquiLang', i) as string;
|
|
432
528
|
|
|
433
529
|
// Construct Payload
|
|
434
|
-
// Standard XTTS/Coqui API expects: text, speaker_id, language_id
|
|
435
530
|
const payload: any = {
|
|
436
531
|
text: text,
|
|
437
532
|
language_id: lang,
|
|
438
533
|
};
|
|
439
|
-
if (speaker) payload.speaker_id = speaker;
|
|
440
|
-
|
|
441
|
-
// Allow http and https
|
|
442
|
-
const requestModule = url.startsWith('https') ? https : http;
|
|
443
534
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
}
|
|
450
|
-
}, (res: any) => {
|
|
451
|
-
const chunks: any[] = [];
|
|
452
|
-
res.on('data', (d: any) => chunks.push(d));
|
|
453
|
-
res.on('end', () => {
|
|
454
|
-
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
455
|
-
resolve(Buffer.concat(chunks));
|
|
456
|
-
} else {
|
|
457
|
-
reject(new Error(`Coqui Server Error ${res.statusCode}: ${Buffer.concat(chunks).toString()}`));
|
|
458
|
-
}
|
|
459
|
-
});
|
|
460
|
-
});
|
|
461
|
-
req.on('error', reject);
|
|
462
|
-
req.write(JSON.stringify(payload));
|
|
463
|
-
req.end();
|
|
464
|
-
});
|
|
535
|
+
if (useWav && wavPath) {
|
|
536
|
+
payload.speaker_wav = wavPath;
|
|
537
|
+
} else if (speakerSelection) {
|
|
538
|
+
payload.speaker_id = speakerSelection;
|
|
539
|
+
}
|
|
465
540
|
|
|
541
|
+
// Execute Request
|
|
542
|
+
audioBuffer = await httpRequest(url, 'POST', payload);
|
|
466
543
|
srtBuffer = Buffer.from(generateHeuristicSRT(text, audioBuffer.length), 'utf8');
|
|
467
544
|
|
|
468
545
|
} else {
|
|
@@ -540,7 +617,7 @@ export class TTSBigBoss implements INodeType {
|
|
|
540
617
|
|
|
541
618
|
returnData.push(newItem);
|
|
542
619
|
|
|
543
|
-
} catch (error) {
|
|
620
|
+
} catch (error: any) {
|
|
544
621
|
if (this.continueOnFail()) {
|
|
545
622
|
returnData.push({ json: { error: error.message }, binary: {} });
|
|
546
623
|
continue;
|
|
@@ -560,8 +637,8 @@ async function runEdgeTTS(text: string, voice: string, rate: string, pitch: stri
|
|
|
560
637
|
return new Promise((resolve, reject) => {
|
|
561
638
|
const ws = new WebSocket(EDGE_URL, {
|
|
562
639
|
headers: {
|
|
563
|
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
564
|
-
'Origin': 'chrome-extension://jdiccldimpdaibmpdkjnbmckianbfold',
|
|
640
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0', // Updated UA to Edge
|
|
641
|
+
'Origin': 'chrome-extension://jdiccldimpdaibmpdkjnbmckianbfold', // Keep origin for now, usually required
|
|
565
642
|
'TrustedClientToken': '6A5AA1D4EAFF4E9FB37E23D68491D6F4'
|
|
566
643
|
}
|
|
567
644
|
});
|
|
@@ -907,3 +984,28 @@ async function downloadFile(url: string, dest: string): Promise<void> {
|
|
|
907
984
|
});
|
|
908
985
|
});
|
|
909
986
|
}
|
|
987
|
+
|
|
988
|
+
async function httpRequest(url: string, method: string = 'GET', body: any = null): Promise<Buffer> {
|
|
989
|
+
const requestModule = url.startsWith('https') ? https : http;
|
|
990
|
+
return new Promise((resolve, reject) => {
|
|
991
|
+
const req = requestModule.request(url, {
|
|
992
|
+
method: method,
|
|
993
|
+
headers: {
|
|
994
|
+
'Content-Type': 'application/json',
|
|
995
|
+
}
|
|
996
|
+
}, (res: any) => {
|
|
997
|
+
const chunks: any[] = [];
|
|
998
|
+
res.on('data', (d: any) => chunks.push(d));
|
|
999
|
+
res.on('end', () => {
|
|
1000
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
1001
|
+
resolve(Buffer.concat(chunks));
|
|
1002
|
+
} else {
|
|
1003
|
+
reject(new Error(`Server Request Failed ${res.statusCode}: ${Buffer.concat(chunks).toString()}`));
|
|
1004
|
+
}
|
|
1005
|
+
});
|
|
1006
|
+
});
|
|
1007
|
+
req.on('error', reject);
|
|
1008
|
+
if (body) req.write(JSON.stringify(body));
|
|
1009
|
+
req.end();
|
|
1010
|
+
});
|
|
1011
|
+
}
|