@andresaya/edge-tts 1.8.1 → 1.9.0

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.
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abortReason = abortReason;
4
+ exports.runSession = runSession;
5
+ const errors_1 = require("./errors");
6
+ const protocol_1 = require("./protocol");
7
+ const CONNECTING = 0;
8
+ const OPEN = 1;
9
+ function abortReason(signal) {
10
+ if (signal.reason !== undefined)
11
+ return signal.reason;
12
+ const error = new Error('This operation was aborted');
13
+ error.name = 'AbortError';
14
+ return error;
15
+ }
16
+ function toBytes(data) {
17
+ if (data instanceof ArrayBuffer)
18
+ return new Uint8Array(data);
19
+ if (ArrayBuffer.isView(data))
20
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
21
+ return new Uint8Array(0);
22
+ }
23
+ function runSession(open, options) {
24
+ return new Promise((resolve, reject) => {
25
+ if (options.signal?.aborted) {
26
+ reject(abortReason(options.signal));
27
+ return;
28
+ }
29
+ const socket = open();
30
+ socket.binaryType = 'arraybuffer';
31
+ let settled = false;
32
+ let opened = false;
33
+ let timer;
34
+ const finish = (error) => {
35
+ if (settled)
36
+ return;
37
+ settled = true;
38
+ clearTimeout(timer);
39
+ options.signal?.removeEventListener('abort', onAbort);
40
+ if (error === undefined) {
41
+ resolve();
42
+ return;
43
+ }
44
+ if (socket.readyState === CONNECTING || socket.readyState === OPEN)
45
+ socket.close();
46
+ reject(error);
47
+ };
48
+ const arm = () => {
49
+ clearTimeout(timer);
50
+ timer = setTimeout(() => {
51
+ finish(new errors_1.EdgeTTSError('WebSocket inactivity timeout - no response from server', 'TIMEOUT'));
52
+ }, options.timeout);
53
+ };
54
+ const onAbort = () => finish(abortReason(options.signal));
55
+ options.signal?.addEventListener('abort', onAbort, { once: true });
56
+ arm();
57
+ socket.onopen = () => {
58
+ if (settled)
59
+ return;
60
+ opened = true;
61
+ arm();
62
+ socket.send(options.configMessage);
63
+ socket.send(options.ssmlMessage);
64
+ };
65
+ socket.onmessage = (event) => {
66
+ if (settled)
67
+ return;
68
+ arm();
69
+ if (typeof event.data === 'string') {
70
+ const frame = (0, protocol_1.parseTextFrame)(event.data);
71
+ if (frame.path === 'audio.metadata') {
72
+ for (const boundary of (0, protocol_1.parseMetadata)(frame.body))
73
+ options.onBoundary(boundary);
74
+ }
75
+ else if (frame.path === 'turn.end') {
76
+ socket.close();
77
+ }
78
+ return;
79
+ }
80
+ const frame = (0, protocol_1.parseBinaryFrame)(toBytes(event.data));
81
+ if (frame.path === 'audio')
82
+ options.onAudio(frame.body);
83
+ };
84
+ socket.onerror = (event) => finish(options.toError(event, opened));
85
+ socket.onclose = () => finish();
86
+ });
87
+ }
@@ -0,0 +1,7 @@
1
+ export interface Cue {
2
+ offset: number;
3
+ duration: number;
4
+ text: string;
5
+ }
6
+ export declare function toSRT(cues: Cue[]): string;
7
+ export declare function toVTT(cues: Cue[]): string;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toSRT = toSRT;
4
+ exports.toVTT = toVTT;
5
+ function timestamp(ticks, separator) {
6
+ const total = Math.max(0, Math.round(ticks / 10_000));
7
+ const ms = total % 1000;
8
+ const s = Math.floor(total / 1000) % 60;
9
+ const m = Math.floor(total / 60_000) % 60;
10
+ const h = Math.floor(total / 3_600_000);
11
+ const pad = (n, width = 2) => String(n).padStart(width, '0');
12
+ return `${pad(h)}:${pad(m)}:${pad(s)}${separator}${pad(ms, 3)}`;
13
+ }
14
+ function toSRT(cues) {
15
+ return cues
16
+ .map((cue, i) => `${i + 1}\n${timestamp(cue.offset, ',')} --> ${timestamp(cue.offset + cue.duration, ',')}\n${cue.text}\n`)
17
+ .join('\n');
18
+ }
19
+ function toVTT(cues) {
20
+ const body = cues
21
+ .map(cue => `${timestamp(cue.offset, '.')} --> ${timestamp(cue.offset + cue.duration, '.')}\n${cue.text}\n`)
22
+ .join('\n');
23
+ return `WEBVTT\n\n${body}`;
24
+ }
@@ -0,0 +1,53 @@
1
+ export interface Voice {
2
+ Name: string;
3
+ ShortName: string;
4
+ Gender: string;
5
+ Locale: string;
6
+ FriendlyName: string;
7
+ LocalName: string;
8
+ DisplayName?: string;
9
+ LocaleName?: string;
10
+ VoiceType?: string;
11
+ SecondaryLocaleList?: string[];
12
+ VoiceTag?: {
13
+ TailoredScenarios: string[];
14
+ VoicePersonalities: string[];
15
+ };
16
+ }
17
+ export type OutputFormat = 'audio-24khz-48kbitrate-mono-mp3' | 'audio-24khz-96kbitrate-mono-mp3' | 'webm-24khz-16bit-mono-opus';
18
+ export interface SynthesisOptions {
19
+ pitch?: string | number;
20
+ rate?: string | number;
21
+ volume?: string | number;
22
+ outputFormat?: OutputFormat | (string & {});
23
+ signal?: AbortSignal;
24
+ timeout?: number;
25
+ }
26
+ export interface WordBoundary {
27
+ type: "WordBoundary";
28
+ offset: number;
29
+ duration: number;
30
+ text: string;
31
+ }
32
+ export interface SentenceBoundary {
33
+ type: "SentenceBoundary";
34
+ offset: number;
35
+ duration: number;
36
+ text: string;
37
+ }
38
+ export interface EdgeTTSOptions {
39
+ wssUrl?: string;
40
+ voicesUrl?: string;
41
+ secMsGecVersion?: string;
42
+ headers?: Record<string, string>;
43
+ timeout?: number;
44
+ voicesCacheTtl?: number;
45
+ }
46
+ export interface SynthesisResult {
47
+ audio: Uint8Array;
48
+ format: string;
49
+ outputFormat: string;
50
+ wordBoundaries: WordBoundary[];
51
+ sentenceBoundaries: SentenceBoundary[];
52
+ duration: number;
53
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/index.d.ts CHANGED
@@ -1,2 +1,5 @@
1
1
  export { EdgeTTS, type Voice, type SynthesisOptions, type WordBoundary } from './services/EdgeTTS';
2
2
  export { Constants } from './config/constants';
3
+ export { EdgeTTSError, type EdgeTTSErrorCode } from './core/errors';
4
+ export { toSRT, toVTT } from './core/subtitles';
5
+ export type { EdgeTTSOptions, OutputFormat, SentenceBoundary, SynthesisResult } from './core/types';
package/dist/index.js CHANGED
@@ -1,7 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Constants = exports.EdgeTTS = void 0;
3
+ exports.toVTT = exports.toSRT = exports.EdgeTTSError = exports.Constants = exports.EdgeTTS = void 0;
4
4
  var EdgeTTS_1 = require("./services/EdgeTTS");
5
5
  Object.defineProperty(exports, "EdgeTTS", { enumerable: true, get: function () { return EdgeTTS_1.EdgeTTS; } });
6
6
  var constants_1 = require("./config/constants");
7
7
  Object.defineProperty(exports, "Constants", { enumerable: true, get: function () { return constants_1.Constants; } });
8
+ var errors_1 = require("./core/errors");
9
+ Object.defineProperty(exports, "EdgeTTSError", { enumerable: true, get: function () { return errors_1.EdgeTTSError; } });
10
+ var subtitles_1 = require("./core/subtitles");
11
+ Object.defineProperty(exports, "toSRT", { enumerable: true, get: function () { return subtitles_1.toSRT; } });
12
+ Object.defineProperty(exports, "toVTT", { enumerable: true, get: function () { return subtitles_1.toVTT; } });
@@ -1,50 +1,28 @@
1
1
  import { Buffer } from 'buffer';
2
- export interface Voice {
3
- Name: string;
4
- ShortName: string;
5
- Gender: string;
6
- Locale: string;
7
- FriendlyName: string;
8
- LocalName: string;
9
- }
10
- export interface SynthesisOptions {
11
- pitch?: string | number;
12
- rate?: string | number;
13
- volume?: string | number;
14
- outputFormat?: string;
15
- }
16
- export interface WordBoundary {
17
- type: "WordBoundary";
18
- offset: number;
19
- duration: number;
20
- text: string;
21
- }
22
- export declare class EdgeTTS {
23
- private audio_stream;
24
- private audio_format;
25
- private output_format;
26
- private word_boundaries;
2
+ import { EdgeTTSCore } from '../core/base';
3
+ import type { SocketLike } from '../core/session';
4
+ import type { EdgeTTSOptions, SynthesisOptions, SynthesisResult } from '../core/types';
5
+ export type { Voice, SynthesisOptions, WordBoundary } from '../core/types';
6
+ export declare class EdgeTTS extends EdgeTTSCore {
7
+ protected readonly defaultVoice = "en-US-AnaNeural";
27
8
  private ws;
28
- normalizeVoices(data: any[]): Promise<Voice[]>;
29
- getVoices(): Promise<Voice[]>;
30
- getVoicesByLanguage(locale: string): Promise<Voice[]>;
31
- getVoicesByGender(gender: 'Male' | 'Female'): Promise<Voice[]>;
32
- private generateUUID;
9
+ constructor(options?: EdgeTTSOptions);
10
+ generateSecMsGec: (trustedClientToken: string) => Promise<string>;
11
+ generate(text: string, voice?: string, options?: SynthesisOptions): Promise<SynthesisResult & {
12
+ audio: Buffer;
13
+ }>;
14
+ protected openSocket(url: string): SocketLike;
15
+ protected requestVoices(url: string): Promise<any[]>;
16
+ protected buildSSML(text: string, voice: string, options: SynthesisOptions): string;
17
+ protected timestamp(): string;
18
+ protected socketError(event: unknown, opened: boolean): Error;
19
+ protected recoverHandshake(): Promise<boolean>;
20
+ private serverTime;
33
21
  private validatePitch;
34
22
  private validateRate;
35
23
  private validateVolume;
36
- synthesize(text: string, voice?: string, options?: SynthesisOptions): Promise<void>;
37
- private escapeXML;
38
- private getSSML;
39
24
  private nowRFC1123;
40
- private parseRFC1123;
41
- private buildTTSConfigMessage;
42
- synthesizeStream(text: string, voice?: string, options?: SynthesisOptions): AsyncGenerator<Uint8Array, void, unknown>;
43
- private processAudioData;
44
- private parseMetadata;
45
- generateSecMsGec: (trustedClientToken: string) => Promise<string>;
46
25
  getDuration(): number;
47
- private getFileExtension;
48
26
  getAudioInfo(): {
49
27
  size: number;
50
28
  format: string;
@@ -55,5 +33,4 @@ export declare class EdgeTTS {
55
33
  toBase64(): string;
56
34
  toBuffer(): Buffer;
57
35
  saveMetadata(outputPath: string): Promise<void>;
58
- getWordBoundaries(): WordBoundary[];
59
36
  }