edge-tts-generator
Version:
Generate text-to-speech narration for free, leveraging the Read Aloud feature in Microsoft Edge
1 lines • 25 kB
Source Map (JSON)
{"version":3,"sources":["../src/constants.ts","../src/edge-tts.ts","../src/generate-mp3.ts","../src/utils.ts"],"sourcesContent":["export enum OUTPUT_FORMAT {\n AUDIO_24KHZ_48KBITRATE_MONO_MP3 = \"audio-24khz-48kbitrate-mono-mp3\",\n AUDIO_24KHZ_96KBITRATE_MONO_MP3 = \"audio-24khz-96kbitrate-mono-mp3\",\n WEBM_24KHZ_16BIT_MONO_OPUS = \"webm-24khz-16bit-mono-opus\",\n}\n\nexport enum PITCH {\n X_LOW = \"x-low\",\n LOW = \"low\",\n MEDIUM = \"medium\",\n HIGH = \"high\",\n X_HIGH = \"x-high\",\n DEFAULT = \"default\",\n}\n\nexport enum RATE {\n X_SLOW = \"x-slow\",\n SLOW = \"slow\",\n MEDIUM = \"medium\",\n FAST = \"fast\",\n X_FAST = \"x-fast\",\n DEFAULT = \"default\",\n}\n\nexport enum VOLUME {\n SILENT = \"silent\",\n X_SOFT = \"x-soft\",\n SOFT = \"soft\",\n MEDIUM = \"medium\",\n LOUD = \"loud\",\n X_LOUD = \"x-LOUD\",\n DEFAULT = \"default\",\n}\n","import { Buffer } from 'buffer';\nimport type { PITCH, RATE, VOLUME } from './constants';\nimport { OUTPUT_FORMAT } from './constants';\nimport { WebSocket } from 'ws';\nimport fetch from 'node-fetch';\nimport { randomBytes } from 'crypto';\nimport { TextEncoder } from 'util';\n\n// Generates a random hex string of the specified length\nfunction generateRandomHex(length: number): string {\n const randomBuffer = randomBytes(length);\n return randomBuffer.toString('hex');\n}\n\ntype EventType = \"data\" | \"close\" | \"end\" | \"error\";\n\nclass EventEmitter {\n private eventListeners: Record<EventType, ((...args: any[]) => void)[]>;\n\n constructor() {\n this.eventListeners = { data: [], close: [], end: [], error: [] };\n }\n\n on(event: EventType, callback: (...args: any[]) => void) {\n this.eventListeners[event].push(callback);\n }\n\n emit(event: EventType, data: any) {\n this.eventListeners[event].forEach((callback) => callback(data));\n }\n}\n\nexport type Voice = {\n Name: string;\n ShortName: string;\n Gender: string;\n Locale: string;\n SuggestedCodec: string;\n FriendlyName: string;\n Status: string;\n};\n\ntype Metadata = {\n Type: \"WordBoundary\" | \"SentenceBoundary\";\n Data: {\n Offset: number;\n Duration: number;\n text: {\n Text: string;\n Length: number;\n BoundaryType: \"WordBoundary\" | \"SentenceBoundary\";\n };\n };\n}[];\n\nexport class ProsodyOptions {\n pitch: PITCH | string = \"+0Hz\";\n rate: RATE | string | number = 1.0;\n volume: VOLUME | string | number = 100.0;\n}\n\nexport class EdgeTTSClient {\n static OUTPUT_FORMAT = OUTPUT_FORMAT;\n private static CLIENT_TOKEN = \"6A5AA1D4EAFF4E9FB37E23D68491D6F4\";\n private static VOICES_URL = `https://speech.platform.bing.com/consumer/speech/synthesize/readaloud/voices/list?trustedclienttoken=${EdgeTTSClient.CLIENT_TOKEN}`;\n private static SYNTH_URL = `wss://speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1?TrustedClientToken=${EdgeTTSClient.CLIENT_TOKEN}`;\n private static BINARY_DELIM = \"Path:audio\\r\\n\";\n private static VOICE_LANG_REGEX = /\\w{2}-\\w{2}/;\n\n private enableLogging: boolean;\n private ws: WebSocket | null = null;\n private voice: string | null = null;\n private voiceLocale: string | null = null;\n private outputFormat: OUTPUT_FORMAT | null = null;\n private requestQueue: Record<string, EventEmitter> = {};\n private connectionStartTime = 0;\n\n constructor(enableLogging = false) {\n this.enableLogging = enableLogging;\n }\n\n private log(...args: any[]) {\n if (this.enableLogging) console.log(...args);\n }\n\n private async sendMessage(message: string) {\n for (let attempt = 1; attempt <= 3 && (this.ws === null || this.ws.readyState !== WebSocket.OPEN); attempt++) {\n if (attempt === 1) this.connectionStartTime = Date.now();\n this.log(`Connecting... attempt ${attempt}`);\n await this.initWebSocket();\n }\n this.ws?.send(message);\n }\n\n private initWebSocket() {\n this.ws = new WebSocket(EdgeTTSClient.SYNTH_URL);\n this.ws.binaryType = \"arraybuffer\";\n let metadataBuffer: Metadata = [];\n\n return new Promise<void>((resolve, reject) => {\n this.ws!.onopen = () => {\n this.log(\"Connected in\", (Date.now() - this.connectionStartTime) / 1000, \"seconds\");\n this.sendMessage(this.getConfigMessage()).then(resolve);\n };\n\n this.ws!.onmessage = (event) => this.handleMessage(event, metadataBuffer);\n this.ws!.onclose = () => this.handleClose();\n this.ws!.onerror = (error: any) => reject(`Connection Error: ${error.message}`);\n });\n }\n\n private handleMessage(event: any, metadataBuffer: Metadata) {\n const buffer = Buffer.from(event.data as ArrayBuffer);\n const message = buffer.toString();\n const requestIdMatch = /X-RequestId:(.*?)\\r\\n/.exec(message);\n const requestId = requestIdMatch ? requestIdMatch[1] : \"\";\n\n if (message.includes(\"Path:turn.start\")) {\n metadataBuffer.length = 0;\n } else if (message.includes(\"Path:turn.end\")) {\n this.requestQueue[requestId]?.emit(\"end\", metadataBuffer);\n } else if (message.includes(\"Path:audio\")) {\n this.cacheAudioData(buffer, requestId);\n } else if (message.includes(\"Path:audio.metadata\")) {\n const startIndex = message.indexOf(\"{\");\n metadataBuffer.push(JSON.parse(message.slice(startIndex)).Metadata[0]);\n } else {\n this.log(\"Unknown Message\", message);\n }\n }\n\n private handleClose() {\n this.log(\"Disconnected after:\", (Date.now() - this.connectionStartTime) / 1000, \"seconds\");\n for (const requestId in this.requestQueue) {\n this.requestQueue[requestId].emit(\"close\", null);\n }\n }\n\n private cacheAudioData(buffer: Buffer, requestId: string) {\n // Convert the BINARY_DELIM string to a Uint8Array using TextEncoder\n const binaryDelimBytes = new TextEncoder().encode(EdgeTTSClient.BINARY_DELIM);\n\n // Use the helper function to find the delimiter index in the buffer\n const delimiterIndex = this.findDelimiterIndex(buffer, binaryDelimBytes);\n if (delimiterIndex === -1) {\n this.log('Delimiter not found in the buffer.');\n return;\n }\n\n const audioDataStart = delimiterIndex + binaryDelimBytes.length;\n const audioData = buffer.subarray(audioDataStart); // Use subarray for Buffer\n this.requestQueue[requestId]?.emit(\"data\", audioData);\n this.log(\"Received audio chunk of size:\", audioData?.length);\n }\n\n // Helper function to find the index of a byte sequence within another byte sequence\n private findDelimiterIndex(buffer: Buffer, delimiter: Uint8Array): number {\n for (let i = 0; i <= buffer.length - delimiter.length; i++) {\n let match = true;\n for (let j = 0; j < delimiter.length; j++) {\n if (buffer[i + j] !== delimiter[j]) {\n match = false;\n break;\n }\n }\n if (match) return i;\n }\n return -1;\n }\n\n private getConfigMessage(): string {\n return `Content-Type:application/json; charset=utf-8\\r\\nPath:speech.config\\r\\n\\r\\n{\n \"context\": {\n \"synthesis\": {\n \"audio\": {\n \"metadataoptions\": {\n \"sentenceBoundaryEnabled\": \"true\",\n \"wordBoundaryEnabled\": \"true\"\n },\n \"outputFormat\": \"${this.outputFormat}\"\n }\n }\n }\n }`;\n }\n\n async getVoices(): Promise<Voice[]> {\n try {\n const response = await fetch(EdgeTTSClient.VOICES_URL);\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n return await response.json() as Voice[];\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n async setMetadata(voiceName: string, outputFormat: OUTPUT_FORMAT, voiceLocale?: string) {\n this.voice = voiceName;\n this.outputFormat = outputFormat;\n this.voiceLocale = voiceLocale || this.inferLocaleFromVoiceName(voiceName);\n\n if (!this.voiceLocale) {\n throw new Error(\"Could not infer voiceLocale from voiceName!\");\n }\n\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n this.connectionStartTime = Date.now();\n await this.initWebSocket();\n }\n }\n\n private inferLocaleFromVoiceName(voiceName: string): string | null {\n const match = EdgeTTSClient.VOICE_LANG_REGEX.exec(voiceName);\n return match ? match[0] : null;\n }\n\n close() {\n this.ws?.close();\n }\n\n toStream(text: string, options: ProsodyOptions = new ProsodyOptions()): EventEmitter {\n return this.sendSSMLRequest(this.buildSSML(text, options));\n }\n\n private buildSSML(text: string, options: ProsodyOptions): string {\n return `<speak version=\"1.0\" xmlns=\"http://www.w3.org/2001/10/synthesis\" xmlns:mstts=\"https://www.w3.org/2001/mstts\" xml:lang=\"${this.voiceLocale}\">\n <voice name=\"${this.voice}\">\n <prosody pitch=\"${options.pitch}\" rate=\"${options.rate}\" volume=\"${options.volume}\">\n ${text}\n </prosody>\n </voice>\n </speak>`;\n }\n\n private sendSSMLRequest(ssml: string): EventEmitter {\n if (!this.ws) {\n throw new Error(\"WebSocket not initialized. Call setMetadata first.\");\n }\n\n const requestId = generateRandomHex(16);\n const requestMessage = `X-RequestId:${requestId}\\r\\nContent-Type:application/ssml+xml\\r\\nPath:ssml\\r\\n\\r\\n${ssml.trim()}`;\n\n const eventEmitter = new EventEmitter();\n this.requestQueue[requestId] = eventEmitter;\n this.sendMessage(requestMessage).then();\n\n return eventEmitter;\n }\n}","import * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { EdgeTTSClient, ProsodyOptions, Voice } from './edge-tts';\nimport { OUTPUT_FORMAT } from './constants';\nimport { filterMarkdown } from './utils';\n\nconst DEFAULT_OPTIONS: TextToSpeechOptions = {\n voice: 'en-GB-RyanNeural',\n speed: 1.1,\n enableLogging: false,\n disableFilter: false,\n}\n\nexport type TextToSpeechOptions = {\n voice?: string;\n speed?: number;\n enableLogging?: boolean;\n disableFilter?: boolean;\n}\n\nexport type TextToSpeechProps = {\n text: string;\n outputPath: string;\n fileName: string;\n options?: TextToSpeechOptions;\n}\n\nexport async function textToSpeechMp3({\n text,\n outputPath,\n fileName,\n options = DEFAULT_OPTIONS,\n}: TextToSpeechProps): Promise<void> {\n\n const client = new EdgeTTSClient(options.enableLogging);\n\n try {\n // Ensure fileName ends with .mp3\n const finalFileName = fileName.toLowerCase().endsWith('.mp3')\n ? fileName\n : `${fileName}.mp3`;\n\n // Combine directory path and filename\n const fullOutputPath = path.join(outputPath, finalFileName);\n\n // Create output directory if it doesn't exist\n await fs.mkdir(outputPath, { recursive: true });\n\n // Not necessary\n // const voices = await client.getVoices();\n // const voiceSelection: Voice | undefined = voices.find(v => v.ShortName === options.voice);\n\n // if (!voiceSelection) {\n // throw new Error(`Voice with short name \"${voiceSelection}\" not found.`);\n // }\n\n await client.setMetadata(options.voice, OUTPUT_FORMAT.AUDIO_24KHZ_48KBITRATE_MONO_MP3);\n\n const prosodyOptions = new ProsodyOptions();\n prosodyOptions.rate = options.speed ?? DEFAULT_OPTIONS.speed;\n\n if (!options.disableFilter) {\n text = filterMarkdown(text);\n }\n\n const stream = client.toStream(text, prosodyOptions);\n\n const chunks: Buffer[] = [];\n stream.on('data', (chunk: Buffer) => {\n chunks.push(chunk);\n });\n\n return new Promise<void>((resolve, reject) => {\n stream.on('end', async () => {\n const audioBuffer = Buffer.concat(chunks);\n\n try {\n await fs.writeFile(fullOutputPath, audioBuffer);\n console.log(`Audio saved to ${fullOutputPath}`);\n resolve();\n } catch (err) {\n console.error('Error writing audio to file:', err);\n reject(err);\n } finally {\n client.close();\n }\n });\n\n stream.on('error', (error: any) => {\n console.error('Stream error:', error);\n client.close();\n reject(error);\n });\n });\n\n } catch (error) {\n console.error('Error during text-to-speech:', error);\n client.close();\n throw error;\n }\n}\n\nexport type TextToSpeechInput = {\n text: string;\n title: string;\n options?: TextToSpeechOptions;\n}\n\nexport async function batchTextToSpeechMp3(\n inputs: TextToSpeechInput[],\n outputPath: string,\n globalOptions: TextToSpeechOptions = DEFAULT_OPTIONS\n): Promise<void> {\n // Create output directory if it doesn't exist\n await fs.mkdir(outputPath, { recursive: true });\n\n // Process all inputs sequentially to avoid overwhelming the TTS service\n for (const input of inputs) {\n try {\n await textToSpeechMp3({\n text: input.text,\n outputPath,\n fileName: input.title,\n options: {\n ...globalOptions,\n ...input.options || {},\n }\n });\n } catch (error) {\n console.error(`Failed to process \"${input.title}\":`, error);\n // Continue with next item even if one fails\n }\n }\n}\n\n// Example usage:\n// async function runBatchExample() {\n// const inputs: TextToSpeechInput[] = [\n// {\n// text: \"This is the first audio file\",\n// title: \"first-audio\",\n// options: { voice: 'en-US-GuyNeural', speed: 1.0 }\n// },\n// {\n// text: \"This is the second audio file\",\n// title: \"second-audio\"\n// }\n// ];\n//\n// const outputDir = './output';\n//\n// try {\n// await batchTextToSpeechMp3(\n// inputs,\n// outputDir,\n// { \n// voice: 'en-GB-RyanNeural',\n// speed: 1.2,\n// enableLogging: true \n// }\n// );\n// console.log('Batch text-to-speech conversion completed!');\n// } catch (error) {\n// console.error('Batch conversion failed:', error);\n// }\n// }","/* eslint-disable @typescript-eslint/no-inferrable-types */\n/* eslint-disable no-useless-escape */\n\n/**\n * Filters out the frontmatter from a Markdown text.\n * Frontmatter is defined as a block of YAML enclosed by `---` or `...` at the start of the file.\n * @param text - The Markdown text from which to remove frontmatter.\n * @returns The text without the frontmatter block.\n */\nexport function filterFrontmatter(text: string): string {\n // Define the regular expression for frontmatter blocks\n const frontmatterRegex = /^(---|\\.\\.\\.)([\\s\\S]*?)\\1\\n?/;\n\n // Remove frontmatter if it exists\n return text.replace(frontmatterRegex, '').trim();\n}\n\nexport function replaceComparisonSymbols(text: string): string {\n return text\n .replace(/>=/g, '≥') // Replace \">=\" with \"≥\"\n .replace(/<=/g, '≤'); // Replace \"<=\" with \"≤\"\n}\n\nexport function escapeAmpersand(text: string): string {\n return text.replace(/&/g, '&') // Escape '&'\n}\n\nexport function escapeXml(text: string): string {\n return text\n // .replace(/&/g, '&') // Escape '&' first to avoid double escaping\n .replace(/</g, '<') // Escape '<'\n .replace(/>/g, '>') // Escape '>'\n .replace(/\"/g, '"') // Escape '\"'\n .replace(/'/g, '''); // Escape \"'\"\n}\n\nexport function filterMarkdown(text: string, overrideAmpersandEscape = false): string {\n // Remove frontmatter (e.g., YAML between triple dashes \"---\")\n const noFrontmatter = text.replace(/^-{3}[\\s\\S]*?-{3}\\n?/, '');\n\n // Remove URLs\n const noUrls = noFrontmatter.replace(/https?:\\/\\/[^\\s]+/g, '');\n\n // Remove code blocks (e.g., fenced with ``` or indented by 4 spaces)\n const noCodeBlocks = noUrls.replace(/```[\\s\\S]*?```/g, '').replace(/^( {4}|\\t).+/gm, '');\n\n // Remove inline markdown syntax\n let cleanedMarkdown = noCodeBlocks\n // Remove bold (**text** or __text__) and italics (*text* or _text_)\n .replace(/(\\*\\*|__)(.*?)\\1/g, '$2') // Bold\n .replace(/(\\*|_)(.*?)\\1/g, '$2') // Italics\n // Remove inline code markers (`code`)\n .replace(/`([^`]*)`/g, '$1')\n // Remove strikethrough (~~text~~)\n .replace(/~~(.*?)~~/g, '$1')\n // Remove other markdown characters (e.g., #, -, *, etc., not part of inline code)\n .replace(/^[#*-]+\\s*/gm, '')\n // Remove unordered list markers (e.g., \"- \", \"* \", \"+ \")\n .replace(/^[\\-\\+\\*]\\s+/gm, '')\n // Remove ordered list numbers (e.g., \"1. \", \"2. \")\n .replace(/^\\d+\\.\\s+/gm, '')\n // Remove blockquote markers (e.g., \"> \") only at the start of a line\n .replace(/^>\\s+/gm, '')\n // Remove horizontal rules (e.g., \"---\", \"***\")\n .replace(/^[-*]{3,}\\s*$/gm, '');\n\n cleanedMarkdown = replaceComparisonSymbols(cleanedMarkdown);\n\n // Remove HTML tags explicitly while preserving `<` and `>` symbols in text\n cleanedMarkdown = cleanedMarkdown.replace(/<([^>\\s]+)[^>]*>/g, '');\n\n // Trim leading and trailing whitespace and escape '&' if indicated\n cleanedMarkdown = (overrideAmpersandEscape) ? cleanedMarkdown.trim() : escapeAmpersand(cleanedMarkdown.trim());\n\n const finalText = escapeXml(cleanedMarkdown);\n\n return finalText;\n}"],"mappings":"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","names":["OUTPUT_FORMAT","PITCH","RATE","VOLUME","Buffer","Buffer"]}