@andresaya/edge-tts 1.4.1 → 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.
@@ -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.0')
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
  };
@@ -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
- VERSION_MS_GEC: '1-140.0.3485.14'
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
- private generateSecMsGec;
44
+ generateSecMsGec: (trustedClientToken: string) => Promise<string>;
43
45
  getDuration(): number;
44
46
  getAudioInfo(): {
45
47
  size: number;
@@ -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 response = await fetch(`${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}`, {
34
- headers: {
35
- "User-Agent": constants_1.Constants.USER_AGENT
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 speechMessage = `X-RequestId:${reqId}\r\nContent-Type:application/ssml+xml\r\nX-Timestamp:${new Date().toISOString()}Z\r\nPath:ssml\r\n\r\n${SSML_text}`;
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
- return `X-Timestamp:${new Date().toISOString()}Z\r\nContent-Type:application/json; charset=utf-8\r\nPath:speech.config\r\n\r\n` +
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 speechMessage = `X-RequestId:${reqId}\r\nContent-Type:application/ssml+xml\r\nX-Timestamp:${new Date().toISOString()}Z\r\nPath:ssml\r\n\r\n${SSML_text}`;
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 generateSecMsGec(trustedClientToken) {
355
- const ticks = Math.floor(Date.now() / 1000) + 11644473600;
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 * 10000000;
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.1",
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": "./dist/cli/edge-tts.js"
44
+ "edge-tts": "dist/cli/edge-tts.js"
44
45
  },
45
46
  "engines": {
46
47
  "bun": ">=0.5.0"
47
48
  }
48
- }
49
+ }