@andresaya/edge-tts 1.4.2 → 1.4.3
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/cli/edge-tts.js +1 -1
- package/dist/config/constants.d.ts +27 -0
- package/dist/config/constants.js +28 -1
- package/dist/services/EdgeTTS.d.ts +3 -1
- package/dist/services/EdgeTTS.js +51 -13
- package/package.json +5 -4
package/dist/cli/edge-tts.js
CHANGED
|
@@ -6,7 +6,7 @@ const VoiceListCommand_1 = require("../commands/VoiceListCommand");
|
|
|
6
6
|
const commander_1 = require("commander");
|
|
7
7
|
const program = new commander_1.Command();
|
|
8
8
|
program
|
|
9
|
-
.version('1.4.
|
|
9
|
+
.version('1.4.3')
|
|
10
10
|
.addCommand(SynthesizeCommand_1.SynthesizeCommand)
|
|
11
11
|
.addCommand(VoiceListCommand_1.VoiceListCommand);
|
|
12
12
|
try {
|
|
@@ -3,5 +3,32 @@ export declare const Constants: {
|
|
|
3
3
|
WSS_URL: string;
|
|
4
4
|
VOICES_URL: string;
|
|
5
5
|
USER_AGENT: string;
|
|
6
|
+
DEFAULT_VOICE: string;
|
|
6
7
|
VERSION_MS_GEC: string;
|
|
8
|
+
CHROMIUM_FULL_VERSION: string;
|
|
9
|
+
CHROMIUM_MAJOR_VERSION: string;
|
|
10
|
+
SEC_MS_GEC_VERSION: string;
|
|
11
|
+
BASE_HEADERS: {
|
|
12
|
+
'User-Agent': string;
|
|
13
|
+
'Accept-Encoding': string;
|
|
14
|
+
'Accept-Language': string;
|
|
15
|
+
};
|
|
16
|
+
WSS_HEADERS: {
|
|
17
|
+
Pragma: string;
|
|
18
|
+
'Cache-Control': string;
|
|
19
|
+
Origin: string;
|
|
20
|
+
'Sec-WebSocket-Protocol': string;
|
|
21
|
+
'Sec-WebSocket-Version': string;
|
|
22
|
+
'User-Agent': string;
|
|
23
|
+
};
|
|
24
|
+
VOICE_HEADERS: {
|
|
25
|
+
Authority: string;
|
|
26
|
+
'Sec-CH-UA': string;
|
|
27
|
+
'Sec-CH-UA-Mobile': string;
|
|
28
|
+
Accept: string;
|
|
29
|
+
'Sec-Fetch-Site': string;
|
|
30
|
+
'Sec-Fetch-Mode': string;
|
|
31
|
+
'Sec-Fetch-Dest': string;
|
|
32
|
+
'User-Agent': string;
|
|
33
|
+
};
|
|
7
34
|
};
|
package/dist/config/constants.js
CHANGED
|
@@ -6,5 +6,32 @@ exports.Constants = {
|
|
|
6
6
|
WSS_URL: 'wss://api.msedgeservices.com/tts/cognitiveservices/websocket/v1',
|
|
7
7
|
VOICES_URL: 'https://api.msedgeservices.com/tts/cognitiveservices/voices/list',
|
|
8
8
|
USER_AGENT: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0',
|
|
9
|
-
|
|
9
|
+
DEFAULT_VOICE: "en-US-EmmaMultilingualNeural",
|
|
10
|
+
VERSION_MS_GEC: '1-140.0.3485.14',
|
|
11
|
+
CHROMIUM_FULL_VERSION: '140.0.3485.14',
|
|
12
|
+
CHROMIUM_MAJOR_VERSION: '140',
|
|
13
|
+
SEC_MS_GEC_VERSION: '1-140.0.3485.14',
|
|
14
|
+
BASE_HEADERS: {
|
|
15
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0',
|
|
16
|
+
'Accept-Encoding': 'gzip, deflate, br, zstd',
|
|
17
|
+
'Accept-Language': 'es,es-ES;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,es-CO;q=0.5,es-MX;q=0.4',
|
|
18
|
+
},
|
|
19
|
+
WSS_HEADERS: {
|
|
20
|
+
'Pragma': 'no-cache',
|
|
21
|
+
'Cache-Control': 'no-cache',
|
|
22
|
+
'Origin': 'chrome-extension://jdiccldimpdaibmpdkjnbmckianbfold',
|
|
23
|
+
'Sec-WebSocket-Protocol': 'synthesize',
|
|
24
|
+
'Sec-WebSocket-Version': '13',
|
|
25
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0'
|
|
26
|
+
},
|
|
27
|
+
VOICE_HEADERS: {
|
|
28
|
+
'Authority': 'speech.platform.bing.com',
|
|
29
|
+
'Sec-CH-UA': '" Not;A Brand";v="99", "Microsoft Edge";v="140", "Chromium";v="140"',
|
|
30
|
+
'Sec-CH-UA-Mobile': '?0',
|
|
31
|
+
'Accept': '*/*',
|
|
32
|
+
'Sec-Fetch-Site': 'none',
|
|
33
|
+
'Sec-Fetch-Mode': 'cors',
|
|
34
|
+
'Sec-Fetch-Dest': 'empty',
|
|
35
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0'
|
|
36
|
+
},
|
|
10
37
|
};
|
|
@@ -35,11 +35,13 @@ export declare class EdgeTTS {
|
|
|
35
35
|
private detectSSML;
|
|
36
36
|
private escapeXML;
|
|
37
37
|
private getSSML;
|
|
38
|
+
private nowRFC1123;
|
|
39
|
+
private parseRFC1123;
|
|
38
40
|
private buildTTSConfigMessage;
|
|
39
41
|
synthesizeStream(text: string, voice?: string, options?: SynthesisOptions): AsyncGenerator<Uint8Array, void, unknown>;
|
|
40
42
|
private processAudioData;
|
|
41
43
|
private parseMetadata;
|
|
42
|
-
|
|
44
|
+
generateSecMsGec: (trustedClientToken: string) => Promise<string>;
|
|
43
45
|
getDuration(): number;
|
|
44
46
|
getAudioInfo(): {
|
|
45
47
|
size: number;
|
package/dist/services/EdgeTTS.js
CHANGED
|
@@ -8,6 +8,7 @@ const ws_1 = __importDefault(require("ws"));
|
|
|
8
8
|
const constants_1 = require("../config/constants");
|
|
9
9
|
const promises_1 = require("fs/promises");
|
|
10
10
|
const buffer_1 = require("buffer");
|
|
11
|
+
const https_1 = __importDefault(require("https"));
|
|
11
12
|
function ensureBuffer(data) {
|
|
12
13
|
if (buffer_1.Buffer.isBuffer(data)) {
|
|
13
14
|
return data;
|
|
@@ -30,10 +31,22 @@ class EdgeTTS {
|
|
|
30
31
|
ws;
|
|
31
32
|
async getVoices() {
|
|
32
33
|
const secMsGEC = await this.generateSecMsGec(constants_1.Constants.TRUSTED_CLIENT_TOKEN);
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
const httpsAgent = new https_1.default.Agent({
|
|
35
|
+
rejectUnauthorized: false,
|
|
36
|
+
});
|
|
37
|
+
const response = await new Promise((resolve, reject) => {
|
|
38
|
+
const req = https_1.default.request(`${constants_1.Constants.VOICES_URL}?Ocp-Apim-Subscription-Key=${constants_1.Constants.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${secMsGEC}&Sec-MS-GEC-Version=${constants_1.Constants.VERSION_MS_GEC}`, {
|
|
39
|
+
headers: {
|
|
40
|
+
"User-Agent": constants_1.Constants.USER_AGENT
|
|
41
|
+
},
|
|
42
|
+
agent: httpsAgent
|
|
43
|
+
}, (res) => {
|
|
44
|
+
let data = '';
|
|
45
|
+
res.on('data', (chunk) => (data += chunk));
|
|
46
|
+
res.on('end', () => resolve(new Response(data, { status: res.statusCode || 200 })));
|
|
47
|
+
});
|
|
48
|
+
req.on('error', reject);
|
|
49
|
+
req.end();
|
|
37
50
|
});
|
|
38
51
|
const data = await response.json();
|
|
39
52
|
return data.map((voice) => {
|
|
@@ -106,7 +119,8 @@ class EdgeTTS {
|
|
|
106
119
|
this.ws = new ws_1.default(url, {
|
|
107
120
|
headers: {
|
|
108
121
|
"User-Agent": constants_1.Constants.USER_AGENT
|
|
109
|
-
}
|
|
122
|
+
},
|
|
123
|
+
rejectUnauthorized: false
|
|
110
124
|
});
|
|
111
125
|
const SSML_text = this.getSSML(text, voice, options);
|
|
112
126
|
const timeout = setTimeout(() => {
|
|
@@ -118,7 +132,8 @@ class EdgeTTS {
|
|
|
118
132
|
this.ws.on('open', () => {
|
|
119
133
|
const message = this.buildTTSConfigMessage();
|
|
120
134
|
this.ws.send(message);
|
|
121
|
-
const
|
|
135
|
+
const timestamp = this.nowRFC1123();
|
|
136
|
+
const speechMessage = `X-RequestId:${reqId}\r\nContent-Type:application/ssml+xml\r\nX-Timestamp:${timestamp}\r\nPath:ssml\r\n\r\n${SSML_text}`;
|
|
122
137
|
this.ws.send(speechMessage);
|
|
123
138
|
});
|
|
124
139
|
this.ws.on('message', (data) => {
|
|
@@ -215,8 +230,27 @@ class EdgeTTS {
|
|
|
215
230
|
</speak>
|
|
216
231
|
`;
|
|
217
232
|
}
|
|
233
|
+
nowRFC1123(timeZone = 'UTC') {
|
|
234
|
+
const now = new Date();
|
|
235
|
+
const options = {
|
|
236
|
+
weekday: 'short',
|
|
237
|
+
year: 'numeric',
|
|
238
|
+
month: 'short',
|
|
239
|
+
day: '2-digit',
|
|
240
|
+
hour: '2-digit',
|
|
241
|
+
minute: '2-digit',
|
|
242
|
+
second: '2-digit',
|
|
243
|
+
timeZone,
|
|
244
|
+
timeZoneName: 'short'
|
|
245
|
+
};
|
|
246
|
+
return now.toLocaleString('en-US', options);
|
|
247
|
+
}
|
|
248
|
+
parseRFC1123(rfcStr) {
|
|
249
|
+
return new Date(rfcStr);
|
|
250
|
+
}
|
|
218
251
|
buildTTSConfigMessage() {
|
|
219
|
-
|
|
252
|
+
const timestamp = this.nowRFC1123();
|
|
253
|
+
return `X-Timestamp:${timestamp}\r\nContent-Type:application/json; charset=utf-8\r\nPath:speech.config\r\n\r\n` +
|
|
220
254
|
`{"context":{"synthesis":{"audio":{"metadataoptions":{"sentenceBoundaryEnabled":false,"wordBoundaryEnabled":true},"outputFormat":"audio-24khz-48kbitrate-mono-mp3"}}}}`;
|
|
221
255
|
}
|
|
222
256
|
async *synthesizeStream(text, voice = 'en-US-AnaNeural', options = {}) {
|
|
@@ -227,7 +261,8 @@ class EdgeTTS {
|
|
|
227
261
|
this.ws = new ws_1.default(url, {
|
|
228
262
|
headers: {
|
|
229
263
|
"User-Agent": constants_1.Constants.USER_AGENT
|
|
230
|
-
}
|
|
264
|
+
},
|
|
265
|
+
rejectUnauthorized: false
|
|
231
266
|
});
|
|
232
267
|
const SSML_text = this.getSSML(text, voice, options);
|
|
233
268
|
const queue = [];
|
|
@@ -249,7 +284,8 @@ class EdgeTTS {
|
|
|
249
284
|
this.ws.on('open', () => {
|
|
250
285
|
const message = this.buildTTSConfigMessage();
|
|
251
286
|
this.ws.send(message);
|
|
252
|
-
const
|
|
287
|
+
const timestamp = this.nowRFC1123();
|
|
288
|
+
const speechMessage = `X-RequestId:${reqId}\r\nContent-Type:application/ssml+xml\r\nX-Timestamp:${timestamp}\r\nPath:ssml\r\n\r\n${SSML_text}`;
|
|
253
289
|
this.ws.send(speechMessage);
|
|
254
290
|
});
|
|
255
291
|
this.ws.on('message', (data) => {
|
|
@@ -351,10 +387,12 @@ class EdgeTTS {
|
|
|
351
387
|
}
|
|
352
388
|
return null;
|
|
353
389
|
}
|
|
354
|
-
async
|
|
355
|
-
const
|
|
390
|
+
generateSecMsGec = async (trustedClientToken) => {
|
|
391
|
+
const now = this.nowRFC1123();
|
|
392
|
+
const fixedDate = this.parseRFC1123(now);
|
|
393
|
+
const ticks = Math.floor(fixedDate.getTime() / 1000) + 11644473600;
|
|
356
394
|
const rounded = ticks - (ticks % 300);
|
|
357
|
-
const windowsTicks = rounded *
|
|
395
|
+
const windowsTicks = rounded * 10_000_000;
|
|
358
396
|
const encoder = new TextEncoder();
|
|
359
397
|
const data = encoder.encode(`${windowsTicks}${trustedClientToken}`);
|
|
360
398
|
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
|
@@ -362,7 +400,7 @@ class EdgeTTS {
|
|
|
362
400
|
.map(b => b.toString(16).padStart(2, '0'))
|
|
363
401
|
.join('')
|
|
364
402
|
.toUpperCase();
|
|
365
|
-
}
|
|
403
|
+
};
|
|
366
404
|
getDuration() {
|
|
367
405
|
if (this.audio_stream.length === 0) {
|
|
368
406
|
throw new Error("No audio data available");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andresaya/edge-tts",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.3",
|
|
4
4
|
"description": "Edge TTS is a package that allows access to the online text-to-speech service used by Microsoft Edge without the need for Microsoft Edge, Windows, or an API key.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"keywords": [
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "tsc",
|
|
22
|
-
"build:bin": "bun scripts/build.ts"
|
|
22
|
+
"build:bin": "bun scripts/build.ts",
|
|
23
|
+
"prepublishOnly": "npm run build && npm run build:bin"
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|
|
25
26
|
"@types/bun": "latest",
|
|
@@ -40,9 +41,9 @@
|
|
|
40
41
|
"dist"
|
|
41
42
|
],
|
|
42
43
|
"bin": {
|
|
43
|
-
"edge-tts": "
|
|
44
|
+
"edge-tts": "dist/cli/edge-tts.js"
|
|
44
45
|
},
|
|
45
46
|
"engines": {
|
|
46
47
|
"bun": ">=0.5.0"
|
|
47
48
|
}
|
|
48
|
-
}
|
|
49
|
+
}
|