@andresaya/edge-tts 1.7.1 → 1.8.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.
@@ -1,24 +1,24 @@
1
- var A=Object.defineProperty;var y=(p,e,t)=>e in p?A(p,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):p[e]=t;var w=(p,e,t)=>y(p,typeof e!="symbol"?e+"":e,t);var a={TRUSTED_CLIENT_TOKEN:"6A5AA1D4EAFF4E9FB37E23D68491D6F4",BASE_URL:"https://api.msedgeservices.com/tts/cognitiveservices",WSS_URL:"wss://api.msedgeservices.com/tts/cognitiveservices/websocket/v1",VOICES_URL:"https://api.msedgeservices.com/tts/cognitiveservices/voices/list",CHROMIUM_FULL_VERSION:"142.0.3595.0",CHROMIUM_MAJOR_VERSION:"142",VERSION_MS_GEC:"1-142.0.3595",token32(){let p=new Uint8Array(16);return crypto.getRandomValues(p),Array.from(p).map(e=>e.toString(16).padStart(2,"0")).join("").toUpperCase()},getBaseHeaders(){return{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0","Accept-Encoding":"gzip, deflate, br, zstd","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",Cookie:"MUID="+this.token32()}},WSS_HEADERS:{Pragma:"no-cache","Cache-Control":"no-cache",Origin:"chrome-extension://jdiccldimpdaibmpdkjnbmckianbfold","Sec-WebSocket-Protocol":"synthesize","Sec-WebSocket-Version":"13","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0"},VOICE_HEADERS:{"Sec-CH-UA":'" Not;A Brand";v="99", "Microsoft Edge";v="140", "Chromium";v="140"',"Sec-CH-UA-Mobile":"?0",Accept:"*/*","Sec-Fetch-Site":"none","Sec-Fetch-Mode":"cors","Sec-Fetch-Dest":"empty"},OUTPUT_FORMAT:{AMR_WB_16000HZ:"amr-wb-16000hz",AUDIO_16KHZ_16BIT_32KBPS_MONO_OPUS:"audio-16khz-16bit-32kbps-mono-opus",AUDIO_16KHZ_32KBITRATE_MONO_MP3:"audio-16khz-32kbitrate-mono-mp3",AUDIO_16KHZ_64KBITRATE_MONO_MP3:"audio-16khz-64kbitrate-mono-mp3",AUDIO_16KHZ_128KBITRATE_MONO_MP3:"audio-16khz-128kbitrate-mono-mp3",AUDIO_24KHZ_16BIT_24KBPS_MONO_OPUS:"audio-24khz-16bit-24kbps-mono-opus",AUDIO_24KHZ_16BIT_48KBPS_MONO_OPUS:"audio-24khz-16bit-48kbps-mono-opus",AUDIO_24KHZ_48KBITRATE_MONO_MP3:"audio-24khz-48kbitrate-mono-mp3",AUDIO_24KHZ_96KBITRATE_MONO_MP3:"audio-24khz-96kbitrate-mono-mp3",AUDIO_24KHZ_160KBITRATE_MONO_MP3:"audio-24khz-160kbitrate-mono-mp3",AUDIO_48KHZ_96KBITRATE_MONO_MP3:"audio-48khz-96kbitrate-mono-mp3",AUDIO_48KHZ_192KBITRATE_MONO_MP3:"audio-48khz-192kbitrate-mono-mp3",G722_16KHZ_64KBPS:"g722-16khz-64kbps",OGG_16KHZ_16BIT_MONO_OPUS:"ogg-16khz-16bit-mono-opus",OGG_24KHZ_16BIT_MONO_OPUS:"ogg-24khz-16bit-mono-opus",OGG_48KHZ_16BIT_MONO_OPUS:"ogg-48khz-16bit-mono-opus",RAW_8KHZ_8BIT_MONO_ALAW:"raw-8khz-8bit-mono-alaw",RAW_8KHZ_8BIT_MONO_MULAW:"raw-8khz-8bit-mono-mulaw",RAW_8KHZ_16BIT_MONO_PCM:"raw-8khz-16bit-mono-pcm",RAW_16KHZ_16BIT_MONO_PCM:"raw-16khz-16bit-mono-pcm",RAW_16KHZ_16BIT_MONO_TRUESILK:"raw-16khz-16bit-mono-truesilk",RAW_22050HZ_16BIT_MONO_PCM:"raw-22050hz-16bit-mono-pcm",RAW_24KHZ_16BIT_MONO_PCM:"raw-24khz-16bit-mono-pcm",RAW_24KHZ_16BIT_MONO_TRUESILK:"raw-24khz-16bit-mono-truesilk",RAW_44100HZ_16BIT_MONO_PCM:"raw-44100hz-16bit-mono-pcm",RAW_48KHZ_16BIT_MONO_PCM:"raw-48khz-16bit-mono-pcm",WEBM_16KHZ_16BIT_MONO_OPUS:"webm-16khz-16bit-mono-opus",WEBM_24KHZ_16BIT_24KBPS_MONO_OPUS:"webm-24khz-16bit-24kbps-mono-opus",WEBM_24KHZ_16BIT_MONO_OPUS:"webm-24khz-16bit-mono-opus",RIFF_8KHZ_8BIT_MONO_ALAW:"riff-8khz-8bit-mono-alaw",RIFF_8KHZ_8BIT_MONO_MULAW:"riff-8khz-8bit-mono-mulaw",RIFF_8KHZ_16BIT_MONO_PCM:"riff-8khz-16bit-mono-pcm",RIFF_22050HZ_16BIT_MONO_PCM:"riff-22050hz-16bit-mono-pcm",RIFF_24KHZ_16BIT_MONO_PCM:"riff-24khz-16bit-mono-pcm",RIFF_44100HZ_16BIT_MONO_PCM:"riff-44100hz-16bit-mono-pcm",RIFF_48KHZ_16BIT_MONO_PCM:"riff-48khz-16bit-mono-pcm"}};var I=class{constructor(){w(this,"audio_stream",[]);w(this,"ws")}async getVoices(){let e=await this.generateSecMsGec(a.TRUSTED_CLIENT_TOKEN);return(await(await fetch(`${a.VOICES_URL}?Ocp-Apim-Subscription-Key=${a.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${e}&Sec-MS-GEC-Version=${a.VERSION_MS_GEC}`,{headers:a.getBaseHeaders()})).json()).map(s=>(s.FriendlyName=s.FriendlyName||s.LocalName,delete s.SampleRateHertz,delete s.Status,s))}async getVoicesByLanguage(e){return(await this.getVoices()).filter(i=>i.Locale.startsWith(e))}async getVoicesByGender(e){return(await this.getVoices()).filter(i=>i.Gender===e)}generateUUID(){return"xxxxxxxx-xxxx-xxxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){let t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}validatePitch(e){return typeof e=="number"?e>=0?`+${e}Hz`:`${e}Hz`:e}validateRate(e){let t;return typeof e=="string"?t=parseFloat(e.replace("%","")):t=e,t>=0?`+${t}%`:`${t}%`}validateVolume(e){let t;return typeof e=="string"?t=parseInt(e.replace("%",""),10):t=e,`${t}%`}detectSSML(e){let t=e.trim();if(!/^<\?xml|^<speak/i.test(t))return{isValid:!0,isSSML:!1};let s=[],r=/<speak\b[^>]*>[\s\S]*<\/speak>/i.test(t),l=/<voice\b[^>]*>[\s\S]*<\/voice>/i.test(t);if(!r)throw new Error("Invalid SSML: Missing <speak> tag");if(!l)throw new Error("Invalid SSML: Missing <voice> tag");if(!/xmlns="http:\/\/www\.w3\.org\/2001\/10\/synthesis"/i.test(t)&&r)throw new Error("Invalid SSML: Missing or incorrect namespace declaration");return{isValid:s.length===0,isSSML:r||l,errors:s.length>0?s:void 0}}escapeXML(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}getSSML(e,t,i={}){let s=i.inputType||"auto",r=!1;if(s==="ssml")r=!0;else if(s==="text")r=!1;else{let n=this.detectSSML(e);r=n.isSSML,n.isSSML?(console.log("\u2192 Detected SSML input"),n.isValid||console.warn("\u26A0 SSML validation warnings:",n.errors)):console.log("\u2192 Detected plain text input")}if(r){let n=e.trim();return n.includes("xmlns=")||(n=n.replace(/<speak([^>]*)>/i,'<speak$1 xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="https://www.w3.org/2001/mstts">')),!/<voice\b[^>]*>/i.test(n)&&t&&(n=n.replace(/(<speak[^>]*>)([\s\S]*?)(<\/speak>)/i,`$1<voice name="${t}">$2</voice>$3`)),n}let l=this.validatePitch(i.pitch??0),h=this.validateRate(i.rate??0),m=this.validateVolume(i.volume??0),_=this.escapeXML(e);return`<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="https://www.w3.org/2001/mstts" xml:lang="en-US">
2
- <voice name="${t}">
3
- <prosody pitch="${l}" rate="${h}" volume="${m}">
4
- ${_}
1
+ var N=Object.defineProperty;var M=(p,e,s)=>e in p?N(p,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):p[e]=s;var T=(p,e,s)=>M(p,typeof e!="symbol"?e+"":e,s);var a={TRUSTED_CLIENT_TOKEN:"6A5AA1D4EAFF4E9FB37E23D68491D6F4",BASE_URL:"https://speech.platform.bing.com/consumer/speech/synthesize/readaloud",WSS_URL:"wss://speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1",VOICES_URL:"https://speech.platform.bing.com/consumer/speech/synthesize/readaloud/voices/list",CHROMIUM_FULL_VERSION:"143.0.3650.75",CHROMIUM_MAJOR_VERSION:"143",VERSION_MS_GEC:"1-143.0.3650",token32(){let p=new Uint8Array(16);return crypto.getRandomValues(p),Array.from(p).map(e=>e.toString(16).padStart(2,"0")).join("").toUpperCase()},getBaseHeaders(){return{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0","Accept-Encoding":"gzip, deflate, br, zstd","Accept-Language":"en-US,en;q=0.9",Cookie:"MUID="+this.token32()}},WSS_HEADERS:{Pragma:"no-cache","Cache-Control":"no-cache",Origin:"chrome-extension://jdiccldimpdaibmpdkjnbmckianbfold","Sec-WebSocket-Protocol":"synthesize","Sec-WebSocket-Version":"13","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.3650.75 Safari/537.36 Edg/143.0.3650.75"},VOICE_HEADERS:{"Sec-CH-UA":'" Not;A Brand";v="99", "Microsoft Edge";v="143", "Chromium";v="143"',"Sec-CH-UA-Mobile":"?0",Accept:"*/*","Sec-Fetch-Site":"none","Sec-Fetch-Mode":"cors","Sec-Fetch-Dest":"empty"},OUTPUT_FORMAT:{AUDIO_24KHZ_48KBITRATE_MONO_MP3:"audio-24khz-48kbitrate-mono-mp3",AUDIO_24KHZ_96KBITRATE_MONO_MP3:"audio-24khz-96kbitrate-mono-mp3",WEBM_24KHZ_16BIT_MONO_OPUS:"webm-24khz-16bit-mono-opus"}};var _=class{constructor(){T(this,"audio_stream",[]);T(this,"ws")}async normalizeVoices(e){let s=[];for(let t of e||[]){let r=t?.ShortName||"",o=t?.Locale||"",l=r.replace(/^[a-z]{2}-[A-Z]{2}-/,"");l=l.replace(/NeuralHD$/,"").replace(/Neural$/,"").trim();let g=`${t?.Name||""} ${r}`,u=t?.VoiceType||(/NeuralHD/i.test(g)?"NeuralHD":"Neural"),d=t?.LocaleName||o||null,i=t?.DisplayName||t?.FriendlyName||l||r;i=i.replace(/^Microsoft\s+/i,""),i=i.split(" - ")[0].trim(),i=i.replace(/\s*Online\s*\(Natural\)\s*/i," "),i=i.replace(/\s*Online\s*/i," "),i=i.replace(/\s+/g," ").trim();let n=t?.VoiceTag&&typeof t.VoiceTag=="object"?t.VoiceTag:{},y=Array.isArray(n.TailoredScenarios)?n.TailoredScenarios:Array.isArray(n.ContentCategories)?n.ContentCategories:[],m=Array.isArray(n.VoicePersonalities)?n.VoicePersonalities:[];s.push({Name:r||t?.Name||"",DisplayName:i,LocalName:i,ShortName:r||t?.Name||"",Gender:t?.Gender??null,Locale:o||null,LocaleName:d,SecondaryLocaleList:Array.isArray(t?.SecondaryLocaleList)?t.SecondaryLocaleList:[],VoiceType:u,VoiceTag:{TailoredScenarios:y,VoicePersonalities:m},FriendlyName:`${i} (${u}) - ${d}`})}return s}async getVoices(){let e=await this.generateSecMsGec(a.TRUSTED_CLIENT_TOKEN),t=await(await fetch(`${a.VOICES_URL}?TrustedClientToken=${a.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${e}&Sec-MS-GEC-Version=${a.VERSION_MS_GEC}`,{headers:a.getBaseHeaders()})).json();return this.normalizeVoices(t.voices||[])}async getVoicesByLanguage(e){return(await this.getVoices()).filter(t=>t.Locale.startsWith(e))}async getVoicesByGender(e){return(await this.getVoices()).filter(t=>t.Gender===e)}generateUUID(){return"xxxxxxxx-xxxx-xxxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){let s=Math.random()*16|0;return(e==="x"?s:s&3|8).toString(16)})}validatePitch(e){return typeof e=="number"?e>=0?`+${e}Hz`:`${e}Hz`:e}validateRate(e){let s;return typeof e=="string"?s=parseFloat(e.replace("%","")):s=e,s>=0?`+${s}%`:`${s}%`}validateVolume(e){let s;return typeof e=="string"?s=parseInt(e.replace("%",""),10):s=e,`${s}%`}escapeXML(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}getSSML(e,s,t={}){let r=this.validatePitch(t.pitch??0),o=this.validateRate(t.rate??0),l=this.validateVolume(t.volume??0),g=this.escapeXML(e);return`<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="https://www.w3.org/2001/mstts" xml:lang="en-US">
2
+ <voice name="${s}">
3
+ <prosody pitch="${r}" rate="${o}" volume="${l}">
4
+ ${g}
5
5
  </prosody>
6
6
  </voice>
7
7
  </speak>`}nowRFC1123(){return new Date().toUTCString()}parseRFC1123(e){return new Date(e)}buildTTSConfigMessage(){return`X-Timestamp:${this.nowRFC1123()}\r
8
8
  Content-Type:application/json; charset=utf-8\r
9
9
  Path:speech.config\r
10
10
  \r
11
- {"context":{"synthesis":{"audio":{"metadataoptions":{"sentenceBoundaryEnabled":false,"wordBoundaryEnabled":true},"outputFormat":"audio-24khz-48kbitrate-mono-mp3"}}}}`}async synthesize(e,t="en-US-JennyNeural",i={}){let s=await this.generateSecMsGec(a.TRUSTED_CLIENT_TOKEN);return new Promise((r,l)=>{this.audio_stream=[];let h=this.generateUUID(),m=`${a.WSS_URL}?Ocp-Apim-Subscription-Key=${a.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${s}&Sec-MS-GEC-Version=${a.VERSION_MS_GEC}&ConnectionId=${h}`;console.log("WebSocket URL:",m),this.ws=new WebSocket(m);let _=this.getSSML(e,t,i),n=!1,o,O=()=>{clearTimeout(o),o=window.setTimeout(()=>{n=!0,this.ws&&this.ws.readyState===WebSocket.OPEN&&this.ws.close(),l(new Error("WebSocket inactivity timeout - no response from server"))},3e4)};this.ws.onopen=()=>{O();let d=this.buildTTSConfigMessage();this.ws.send(d);let u=this.nowRFC1123(),g=`X-RequestId:${h}\r
11
+ {"context":{"synthesis":{"audio":{"metadataoptions":{"sentenceBoundaryEnabled":false,"wordBoundaryEnabled":true},"outputFormat":"audio-24khz-48kbitrate-mono-mp3"}}}}`}async synthesize(e,s="en-US-JennyNeural",t={}){let r=await this.generateSecMsGec(a.TRUSTED_CLIENT_TOKEN);return new Promise((o,l)=>{this.audio_stream=[];let g=this.generateUUID(),u=`${a.WSS_URL}?TrustedClientToken=${a.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${r}&Sec-MS-GEC-Version=${a.VERSION_MS_GEC}&ConnectionId=${g}`;this.ws=new WebSocket(u);let d=this.getSSML(e,s,t),i=!1,n,y=()=>{clearTimeout(n),n=window.setTimeout(()=>{i=!0,this.ws&&this.ws.readyState===WebSocket.OPEN&&this.ws.close(),l(new Error("WebSocket inactivity timeout - no response from server"))},3e4)};this.ws.onopen=()=>{y();let m=this.buildTTSConfigMessage();this.ws.send(m);let h=this.nowRFC1123(),f=`X-RequestId:${g}\r
12
12
  Content-Type:application/ssml+xml\r
13
- X-Timestamp:${u}\r
13
+ X-Timestamp:${h}\r
14
14
  Path:ssml\r
15
15
  \r
16
- ${_}`;this.ws.send(g)},this.ws.onmessage=d=>{if(O(),typeof d.data=="string")d.data.includes("Path:turn.end")&&this.ws?.close();else{let u=new FileReader;u.onload=()=>{let g=u.result,c=new Uint8Array(g);this.processAudioData(c)},u.readAsArrayBuffer(d.data)}},this.ws.onerror=d=>{clearTimeout(o),this.ws&&this.ws.readyState===WebSocket.OPEN&&this.ws.close(),l(new Error("WebSocket error"))},this.ws.onclose=()=>{clearTimeout(o),n||r()}})}async*synthesizeStream(e,t="en-US-JennyNeural",i={}){this.audio_stream=[];let s=this.generateUUID(),r=await this.generateSecMsGec(a.TRUSTED_CLIENT_TOKEN),l=`${a.WSS_URL}?Ocp-Apim-Subscription-Key=${a.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${r}&Sec-MS-GEC-Version=${a.VERSION_MS_GEC}&ConnectionId=${s}`;this.ws=new WebSocket(l);let h=this.getSSML(e,t,i),m=[],_=!1,n=null,o=null,O=c=>{m.push(c),o&&(o(),o=null)},d=!1,u,g=()=>{clearTimeout(u),u=window.setTimeout(()=>{d=!0,n=new Error("WebSocket inactivity timeout - no response from server"),_=!0,this.ws&&this.ws.readyState===WebSocket.OPEN&&this.ws.close(),o&&(o(),o=null)},3e4)};for(this.ws.onopen=()=>{g();let c=this.buildTTSConfigMessage();this.ws.send(c);let S=this.nowRFC1123(),M=`X-RequestId:${s}\r
16
+ ${d}`;this.ws.send(f)},this.ws.onmessage=m=>{if(y(),typeof m.data=="string")m.data.includes("Path:turn.end")&&this.ws?.close();else{let h=new FileReader;h.onload=()=>{let f=h.result,c=new Uint8Array(f);this.processAudioData(c)},h.readAsArrayBuffer(m.data)}},this.ws.onerror=m=>{clearTimeout(n),this.ws&&this.ws.readyState===WebSocket.OPEN&&this.ws.close(),l(new Error("WebSocket error"))},this.ws.onclose=()=>{clearTimeout(n),i||o()}})}async*synthesizeStream(e,s="en-US-JennyNeural",t={}){this.audio_stream=[];let r=this.generateUUID(),o=await this.generateSecMsGec(a.TRUSTED_CLIENT_TOKEN),l=`${a.WSS_URL}?TrustedClientToken=${a.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${o}&Sec-MS-GEC-Version=${a.VERSION_MS_GEC}&ConnectionId=${r}`;this.ws=new WebSocket(l);let g=this.getSSML(e,s,t),u=[],d=!1,i=null,n=null,y=c=>{u.push(c),n&&(n(),n=null)},m=!1,h,f=()=>{clearTimeout(h),h=window.setTimeout(()=>{m=!0,i=new Error("WebSocket inactivity timeout - no response from server"),d=!0,this.ws&&this.ws.readyState===WebSocket.OPEN&&this.ws.close(),n&&(n(),n=null)},3e4)};for(this.ws.onopen=()=>{f();let c=this.buildTTSConfigMessage();this.ws.send(c);let S=this.nowRFC1123(),w=`X-RequestId:${r}\r
17
17
  Content-Type:application/ssml+xml\r
18
18
  X-Timestamp:${S}\r
19
19
  Path:ssml\r
20
20
  \r
21
- ${h}`;this.ws.send(M)},this.ws.onmessage=c=>{if(g(),typeof c.data=="string")c.data.includes("Path:turn.end")&&this.ws?.close();else{let S=new FileReader;S.onload=()=>{let M=S.result,T=new Uint8Array(M),f=new TextEncoder().encode(`Path:audio\r
22
- `),k=this.indexOf(T,f);if(k!==-1){let b=T.slice(k+f.length);this.audio_stream.push(b),O(b)}},S.readAsArrayBuffer(c.data)}},this.ws.onerror=c=>{clearTimeout(u),n=new Error("WebSocket error"),_=!0,o&&(o(),o=null)},this.ws.onclose=()=>{clearTimeout(u),_=!0,o&&(o(),o=null)};!_||m.length>0;){if(m.length===0){await new Promise(S=>o=S);continue}let c=m.shift();c&&(yield c)}if(n)throw n}processAudioData(e){let t=new TextEncoder().encode(`Path:audio\r
23
- `),i=this.indexOf(e,t);if(i!==-1){let s=e.slice(i+t.length);this.audio_stream.push(s)}}indexOf(e,t){for(let i=0;i<=e.length-t.length;i++){let s=!0;for(let r=0;r<t.length;r++)if(e[i+r]!==t[r]){s=!1;break}if(s)return i}return-1}async generateSecMsGec(e){let t=this.nowRFC1123(),i=this.parseRFC1123(t),s=Math.floor(i.getTime()/1e3)+11644473600,l=(s-s%300)*1e7,m=new TextEncoder().encode(`${l}${e}`),_=await crypto.subtle.digest("SHA-256",m);return Array.from(new Uint8Array(_)).map(n=>n.toString(16).padStart(2,"0")).join("").toUpperCase()}getAudioData(){if(this.audio_stream.length===0)throw new Error("No audio data available");let e=this.audio_stream.reduce((s,r)=>s+r.length,0),t=new Uint8Array(e),i=0;for(let s of this.audio_stream)t.set(s,i),i+=s.length;return t}};export{I as EdgeTTS};
21
+ ${g}`;this.ws.send(w)},this.ws.onmessage=c=>{if(f(),typeof c.data=="string")c.data.includes("Path:turn.end")&&this.ws?.close();else{let S=new FileReader;S.onload=()=>{let w=S.result,E=new Uint8Array(w),C=new TextEncoder().encode(`Path:audio\r
22
+ `),x=this.indexOf(E,C);if(x!==-1){let A=E.slice(x+C.length);this.audio_stream.push(A),y(A)}},S.readAsArrayBuffer(c.data)}},this.ws.onerror=c=>{clearTimeout(h),i=new Error("WebSocket error"),d=!0,n&&(n(),n=null)},this.ws.onclose=()=>{clearTimeout(h),d=!0,n&&(n(),n=null)};!d||u.length>0;){if(u.length===0){await new Promise(S=>n=S);continue}let c=u.shift();c&&(yield c)}if(i)throw i}processAudioData(e){let s=new TextEncoder().encode(`Path:audio\r
23
+ `),t=this.indexOf(e,s);if(t!==-1){let r=e.slice(t+s.length);this.audio_stream.push(r)}}indexOf(e,s){for(let t=0;t<=e.length-s.length;t++){let r=!0;for(let o=0;o<s.length;o++)if(e[t+o]!==s[o]){r=!1;break}if(r)return t}return-1}async generateSecMsGec(e){let s=this.nowRFC1123(),t=this.parseRFC1123(s),r=Math.floor(t.getTime()/1e3)+11644473600,l=(r-r%300)*1e7,u=new TextEncoder().encode(`${l}${e}`),d=await crypto.subtle.digest("SHA-256",u);return Array.from(new Uint8Array(d)).map(i=>i.toString(16).padStart(2,"0")).join("").toUpperCase()}getAudioData(){if(this.audio_stream.length===0)throw new Error("No audio data available");let e=this.audio_stream.reduce((r,o)=>r+o.length,0),s=new Uint8Array(e),t=0;for(let r of this.audio_stream)s.set(r,t),t+=r.length;return s}};export{_ as EdgeTTS};
24
24
  //# sourceMappingURL=edge-tts.esm.min.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/config/constants.ts", "../../src/browser/EdgeTTS.browser.ts"],
4
- "sourcesContent": ["export const Constants = {\r\n TRUSTED_CLIENT_TOKEN: '6A5AA1D4EAFF4E9FB37E23D68491D6F4',\r\n BASE_URL: 'https://api.msedgeservices.com/tts/cognitiveservices',\r\n WSS_URL: 'wss://api.msedgeservices.com/tts/cognitiveservices/websocket/v1',\r\n VOICES_URL: 'https://api.msedgeservices.com/tts/cognitiveservices/voices/list',\r\n\r\n CHROMIUM_FULL_VERSION: '142.0.3595.0',\r\n CHROMIUM_MAJOR_VERSION: '142',\r\n VERSION_MS_GEC: '1-142.0.3595',\r\n\r\n token32() {\r\n const bytes = new Uint8Array(16);\r\n crypto.getRandomValues(bytes);\r\n\r\n return Array.from(bytes)\r\n .map(b => b.toString(16).padStart(2, '0'))\r\n .join('')\r\n .toUpperCase();\r\n },\r\n\r\n getBaseHeaders() {\r\n return {\r\n 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0',\r\n 'Accept-Encoding': 'gzip, deflate, br, zstd',\r\n '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',\r\n 'Cookie': 'MUID=' + this.token32()\r\n };\r\n },\r\n\r\n WSS_HEADERS: {\r\n 'Pragma': 'no-cache',\r\n 'Cache-Control': 'no-cache',\r\n 'Origin': 'chrome-extension://jdiccldimpdaibmpdkjnbmckianbfold',\r\n 'Sec-WebSocket-Protocol': 'synthesize',\r\n 'Sec-WebSocket-Version': '13',\r\n 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0'\r\n },\r\n\r\n VOICE_HEADERS: {\r\n 'Sec-CH-UA': '\" Not;A Brand\";v=\"99\", \"Microsoft Edge\";v=\"140\", \"Chromium\";v=\"140\"',\r\n 'Sec-CH-UA-Mobile': '?0',\r\n 'Accept': '*/*',\r\n 'Sec-Fetch-Site': 'none',\r\n 'Sec-Fetch-Mode': 'cors',\r\n 'Sec-Fetch-Dest': 'empty'\r\n },\r\n \r\n // https://learn.microsoft.com/en-us/azure/ai-services/speech-service/rest-text-to-speech?tabs=nonstreaming\r\n OUTPUT_FORMAT: {\r\n // Streaming \r\n AMR_WB_16000HZ: 'amr-wb-16000hz',\r\n AUDIO_16KHZ_16BIT_32KBPS_MONO_OPUS: 'audio-16khz-16bit-32kbps-mono-opus',\r\n AUDIO_16KHZ_32KBITRATE_MONO_MP3: 'audio-16khz-32kbitrate-mono-mp3',\r\n AUDIO_16KHZ_64KBITRATE_MONO_MP3: 'audio-16khz-64kbitrate-mono-mp3',\r\n AUDIO_16KHZ_128KBITRATE_MONO_MP3: 'audio-16khz-128kbitrate-mono-mp3',\r\n AUDIO_24KHZ_16BIT_24KBPS_MONO_OPUS: 'audio-24khz-16bit-24kbps-mono-opus',\r\n AUDIO_24KHZ_16BIT_48KBPS_MONO_OPUS: 'audio-24khz-16bit-48kbps-mono-opus',\r\n AUDIO_24KHZ_48KBITRATE_MONO_MP3: 'audio-24khz-48kbitrate-mono-mp3',\r\n AUDIO_24KHZ_96KBITRATE_MONO_MP3: 'audio-24khz-96kbitrate-mono-mp3',\r\n AUDIO_24KHZ_160KBITRATE_MONO_MP3: 'audio-24khz-160kbitrate-mono-mp3',\r\n AUDIO_48KHZ_96KBITRATE_MONO_MP3: 'audio-48khz-96kbitrate-mono-mp3',\r\n AUDIO_48KHZ_192KBITRATE_MONO_MP3: 'audio-48khz-192kbitrate-mono-mp3',\r\n G722_16KHZ_64KBPS: 'g722-16khz-64kbps',\r\n OGG_16KHZ_16BIT_MONO_OPUS: 'ogg-16khz-16bit-mono-opus',\r\n OGG_24KHZ_16BIT_MONO_OPUS: 'ogg-24khz-16bit-mono-opus',\r\n OGG_48KHZ_16BIT_MONO_OPUS: 'ogg-48khz-16bit-mono-opus',\r\n RAW_8KHZ_8BIT_MONO_ALAW: 'raw-8khz-8bit-mono-alaw',\r\n RAW_8KHZ_8BIT_MONO_MULAW: 'raw-8khz-8bit-mono-mulaw',\r\n RAW_8KHZ_16BIT_MONO_PCM: 'raw-8khz-16bit-mono-pcm',\r\n RAW_16KHZ_16BIT_MONO_PCM: 'raw-16khz-16bit-mono-pcm',\r\n RAW_16KHZ_16BIT_MONO_TRUESILK: 'raw-16khz-16bit-mono-truesilk',\r\n RAW_22050HZ_16BIT_MONO_PCM: 'raw-22050hz-16bit-mono-pcm',\r\n RAW_24KHZ_16BIT_MONO_PCM: 'raw-24khz-16bit-mono-pcm',\r\n RAW_24KHZ_16BIT_MONO_TRUESILK: 'raw-24khz-16bit-mono-truesilk',\r\n RAW_44100HZ_16BIT_MONO_PCM: 'raw-44100hz-16bit-mono-pcm',\r\n RAW_48KHZ_16BIT_MONO_PCM: 'raw-48khz-16bit-mono-pcm',\r\n WEBM_16KHZ_16BIT_MONO_OPUS: 'webm-16khz-16bit-mono-opus',\r\n WEBM_24KHZ_16BIT_24KBPS_MONO_OPUS: 'webm-24khz-16bit-24kbps-mono-opus',\r\n WEBM_24KHZ_16BIT_MONO_OPUS: 'webm-24khz-16bit-mono-opus',\r\n // NonStreaming \r\n RIFF_8KHZ_8BIT_MONO_ALAW: 'riff-8khz-8bit-mono-alaw',\r\n RIFF_8KHZ_8BIT_MONO_MULAW: 'riff-8khz-8bit-mono-mulaw',\r\n RIFF_8KHZ_16BIT_MONO_PCM: 'riff-8khz-16bit-mono-pcm',\r\n RIFF_22050HZ_16BIT_MONO_PCM: 'riff-22050hz-16bit-mono-pcm',\r\n RIFF_24KHZ_16BIT_MONO_PCM: 'riff-24khz-16bit-mono-pcm',\r\n RIFF_44100HZ_16BIT_MONO_PCM: 'riff-44100hz-16bit-mono-pcm',\r\n RIFF_48KHZ_16BIT_MONO_PCM: 'riff-48khz-16bit-mono-pcm'\r\n }\r\n\r\n\r\n};\r\n", "import { Constants } from '../config/constants';\r\n\r\nexport interface Voice {\r\n Name: string;\r\n ShortName: string;\r\n Gender: string;\r\n Locale: string;\r\n FriendlyName: string;\r\n LocalName: string;\r\n}\r\n\r\nexport interface SynthesisOptions {\r\n pitch?: string | number;\r\n rate?: string | number;\r\n volume?: string | number;\r\n inputType?: 'auto' | 'ssml' | 'text';\r\n}\r\n\r\ninterface SSMLValidationResult {\r\n isValid: boolean;\r\n isSSML: boolean;\r\n errors?: string[];\r\n}\r\n\r\nexport class EdgeTTS {\r\n private audio_stream: Uint8Array[] = [];\r\n private ws?: WebSocket;\r\n\r\n async getVoices(): Promise<Voice[]> {\r\n const secMsGEC = await this.generateSecMsGec(Constants.TRUSTED_CLIENT_TOKEN);\r\n \r\n const response = await fetch(\r\n `${Constants.VOICES_URL}?Ocp-Apim-Subscription-Key=${Constants.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${secMsGEC}&Sec-MS-GEC-Version=${Constants.VERSION_MS_GEC}`,\r\n { headers: Constants.getBaseHeaders() }\r\n );\r\n \r\n const data = await response.json();\r\n return data.map((voice: any) => {\r\n voice.FriendlyName = voice.FriendlyName || voice.LocalName;\r\n delete voice.SampleRateHertz;\r\n delete voice.Status;\r\n return voice;\r\n });\r\n }\r\n\r\n async getVoicesByLanguage(locale: string): Promise<Voice[]> {\r\n const voices = await this.getVoices();\r\n return voices.filter(voice => voice.Locale.startsWith(locale));\r\n }\r\n\r\n async getVoicesByGender(gender: 'Male' | 'Female'): Promise<Voice[]> {\r\n const voices = await this.getVoices();\r\n return voices.filter(voice => voice.Gender === gender);\r\n }\r\n\r\n private generateUUID(): string {\r\n return 'xxxxxxxx-xxxx-xxxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\r\n const r = Math.random() * 16 | 0;\r\n const v = c === 'x' ? r : (r & 0x3 | 0x8);\r\n return v.toString(16);\r\n });\r\n }\r\n\r\n private validatePitch(pitch: string | number): string {\r\n if (typeof pitch === 'number') {\r\n return (pitch >= 0 ? `+${pitch}Hz` : `${pitch}Hz`);\r\n }\r\n return pitch;\r\n }\r\n\r\n private validateRate(rate: string | number): string {\r\n let rateValue: number;\r\n if (typeof rate === 'string') {\r\n rateValue = parseFloat(rate.replace('%', ''));\r\n } else {\r\n rateValue = rate;\r\n }\r\n return rateValue >= 0 ? `+${rateValue}%` : `${rateValue}%`;\r\n }\r\n\r\n private validateVolume(volume: string | number): string {\r\n let volumeValue: number;\r\n if (typeof volume === 'string') {\r\n volumeValue = parseInt(volume.replace('%', ''), 10);\r\n } else {\r\n volumeValue = volume;\r\n }\r\n return `${volumeValue}%`;\r\n }\r\n\r\n private detectSSML(content: string): SSMLValidationResult {\r\n const trimmedContent = content.trim();\r\n const looksLikeSSML = /^<\\?xml|^<speak/i.test(trimmedContent);\r\n\r\n if (!looksLikeSSML) {\r\n return { isValid: true, isSSML: false };\r\n }\r\n\r\n const errors: string[] = [];\r\n const hasSpeakTag = /<speak\\b[^>]*>[\\s\\S]*<\\/speak>/i.test(trimmedContent);\r\n const hasVoiceTag = /<voice\\b[^>]*>[\\s\\S]*<\\/voice>/i.test(trimmedContent);\r\n\r\n if (!hasSpeakTag) {\r\n throw new Error('Invalid SSML: Missing <speak> tag');\r\n }\r\n\r\n if (!hasVoiceTag) {\r\n throw new Error('Invalid SSML: Missing <voice> tag');\r\n }\r\n\r\n const hasCorrectNamespace = /xmlns=\"http:\\/\\/www\\.w3\\.org\\/2001\\/10\\/synthesis\"/i.test(trimmedContent);\r\n if (!hasCorrectNamespace && hasSpeakTag) {\r\n throw new Error('Invalid SSML: Missing or incorrect namespace declaration');\r\n }\r\n\r\n return {\r\n isValid: errors.length === 0,\r\n isSSML: hasSpeakTag || hasVoiceTag,\r\n errors: errors.length > 0 ? errors : undefined\r\n };\r\n }\r\n\r\n private escapeXML(text: string): string {\r\n return text\r\n .replace(/&/g, '&amp;')\r\n .replace(/</g, '&lt;')\r\n .replace(/>/g, '&gt;')\r\n .replace(/\"/g, '&quot;')\r\n .replace(/'/g, '&apos;');\r\n }\r\n\r\n private getSSML(content: string, voice: string, options: SynthesisOptions = {}): string {\r\n const inputType = options.inputType || 'auto';\r\n let treatAsSSML = false;\r\n\r\n if (inputType === 'ssml') {\r\n treatAsSSML = true;\r\n } else if (inputType === 'text') {\r\n treatAsSSML = false;\r\n } else { // 'auto'\r\n const detection = this.detectSSML(content);\r\n treatAsSSML = detection.isSSML;\r\n\r\n if (detection.isSSML) {\r\n console.log('\u2192 Detected SSML input');\r\n if (!detection.isValid) {\r\n console.warn('\u26A0 SSML validation warnings:', detection.errors);\r\n }\r\n } else {\r\n console.log('\u2192 Detected plain text input');\r\n }\r\n }\r\n\r\n if (treatAsSSML) {\r\n let ssml = content.trim();\r\n\r\n if (!ssml.includes('xmlns=')) {\r\n ssml = ssml.replace(\r\n /<speak([^>]*)>/i,\r\n '<speak$1 xmlns=\"http://www.w3.org/2001/10/synthesis\" xmlns:mstts=\"https://www.w3.org/2001/mstts\">'\r\n );\r\n }\r\n\r\n if (!/<voice\\b[^>]*>/i.test(ssml) && voice) {\r\n ssml = ssml.replace(\r\n /(<speak[^>]*>)([\\s\\S]*?)(<\\/speak>)/i,\r\n `$1<voice name=\"${voice}\">$2</voice>$3`\r\n );\r\n }\r\n\r\n return ssml;\r\n }\r\n\r\n const pitch = this.validatePitch(options.pitch ?? 0);\r\n const rate = this.validateRate(options.rate ?? 0);\r\n const volume = this.validateVolume(options.volume ?? 0);\r\n const escapedText = this.escapeXML(content);\r\n\r\n return `<speak version=\"1.0\" xmlns=\"http://www.w3.org/2001/10/synthesis\" xmlns:mstts=\"https://www.w3.org/2001/mstts\" xml:lang=\"en-US\">\r\n <voice name=\"${voice}\">\r\n <prosody pitch=\"${pitch}\" rate=\"${rate}\" volume=\"${volume}\">\r\n ${escapedText}\r\n </prosody>\r\n </voice>\r\n </speak>`;\r\n }\r\n\r\n private nowRFC1123(): string {\r\n return new Date().toUTCString();\r\n }\r\n\r\n private parseRFC1123(rfcStr: string): Date {\r\n return new Date(rfcStr);\r\n }\r\n\r\n private buildTTSConfigMessage(): string {\r\n const timestamp = this.nowRFC1123();\r\n return `X-Timestamp:${timestamp}\\r\\nContent-Type:application/json; charset=utf-8\\r\\nPath:speech.config\\r\\n\\r\\n` +\r\n `{\"context\":{\"synthesis\":{\"audio\":{\"metadataoptions\":{\"sentenceBoundaryEnabled\":false,\"wordBoundaryEnabled\":true},\"outputFormat\":\"audio-24khz-48kbitrate-mono-mp3\"}}}}`;\r\n }\r\n\r\n async synthesize(text: string, voice: string = 'en-US-JennyNeural', options: SynthesisOptions = {}): Promise<void> {\r\n const secMsGEC = await this.generateSecMsGec(Constants.TRUSTED_CLIENT_TOKEN);\r\n\r\n return new Promise((resolve, reject) => {\r\n this.audio_stream = [];\r\n const reqId = this.generateUUID();\r\n const url = `${Constants.WSS_URL}?Ocp-Apim-Subscription-Key=${Constants.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${secMsGEC}&Sec-MS-GEC-Version=${Constants.VERSION_MS_GEC}&ConnectionId=${reqId}`;\r\n \r\n console.log('WebSocket URL:', url);\r\n this.ws = new WebSocket(url);\r\n\r\n const SSML_text = this.getSSML(text, voice, options);\r\n \r\n let timedOut = false;\r\n let inactivityTimeout: number;\r\n \r\n const resetInactivityTimeout = () => {\r\n clearTimeout(inactivityTimeout);\r\n inactivityTimeout = window.setTimeout(() => {\r\n timedOut = true;\r\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\r\n this.ws.close();\r\n }\r\n reject(new Error(\"WebSocket inactivity timeout - no response from server\"));\r\n }, 30000); // 30 seconds of inactivity\r\n };\r\n\r\n this.ws.onopen = () => {\r\n resetInactivityTimeout(); // start the inactivity timeout\r\n const message = this.buildTTSConfigMessage();\r\n this.ws!.send(message);\r\n const timestamp = this.nowRFC1123();\r\n const speechMessage = `X-RequestId:${reqId}\\r\\nContent-Type:application/ssml+xml\\r\\nX-Timestamp:${timestamp}\\r\\nPath:ssml\\r\\n\\r\\n${SSML_text}`;\r\n this.ws!.send(speechMessage);\r\n };\r\n\r\n this.ws.onmessage = (event) => {\r\n resetInactivityTimeout(); // restart inactivity timeout \r\n if (typeof event.data === 'string') {\r\n if (event.data.includes('Path:turn.end')) {\r\n this.ws?.close();\r\n }\r\n } else {\r\n const reader = new FileReader();\r\n reader.onload = () => {\r\n const arrayBuffer = reader.result as ArrayBuffer;\r\n const uint8Array = new Uint8Array(arrayBuffer);\r\n this.processAudioData(uint8Array);\r\n };\r\n reader.readAsArrayBuffer(event.data);\r\n }\r\n };\r\n\r\n this.ws.onerror = (err: any) => {\r\n clearTimeout(inactivityTimeout);\r\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\r\n this.ws.close();\r\n }\r\n reject(new Error('WebSocket error'));\r\n };\r\n\r\n this.ws.onclose = () => {\r\n clearTimeout(inactivityTimeout);\r\n if (!timedOut) {\r\n resolve();\r\n }\r\n };\r\n });\r\n }\r\n\r\n async *synthesizeStream(text: string, voice: string = 'en-US-JennyNeural', options: SynthesisOptions = {}): AsyncGenerator<Uint8Array, void, unknown> {\r\n this.audio_stream = [];\r\n\r\n const reqId = this.generateUUID();\r\n const secMsGEC = await this.generateSecMsGec(Constants.TRUSTED_CLIENT_TOKEN);\r\n\r\n const url = `${Constants.WSS_URL}?Ocp-Apim-Subscription-Key=${Constants.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${secMsGEC}&Sec-MS-GEC-Version=${Constants.VERSION_MS_GEC}&ConnectionId=${reqId}`;\r\n\r\n this.ws = new WebSocket(url);\r\n\r\n const SSML_text = this.getSSML(text, voice, options);\r\n\r\n const queue: Uint8Array[] = [];\r\n let done = false;\r\n let error: Error | null = null;\r\n let notify: (() => void) | null = null;\r\n\r\n const push = (chunk: Uint8Array) => {\r\n queue.push(chunk);\r\n if (notify) {\r\n notify();\r\n notify = null;\r\n }\r\n };\r\n\r\n let timedOut = false;\r\n let inactivityTimeout: number;\r\n \r\n const resetInactivityTimeout = () => {\r\n clearTimeout(inactivityTimeout);\r\n inactivityTimeout = window.setTimeout(() => {\r\n timedOut = true;\r\n error = new Error(\"WebSocket inactivity timeout - no response from server\");\r\n done = true;\r\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\r\n this.ws.close();\r\n }\r\n if (notify) {\r\n notify();\r\n notify = null;\r\n }\r\n }, 30000); // 30 seconds of inactivity\r\n };\r\n\r\n this.ws.onopen = () => {\r\n resetInactivityTimeout(); // start the inactivity timeout\r\n const message = this.buildTTSConfigMessage();\r\n this.ws!.send(message);\r\n\r\n const timestamp = this.nowRFC1123();\r\n const speechMessage = `X-RequestId:${reqId}\\r\\nContent-Type:application/ssml+xml\\r\\nX-Timestamp:${timestamp}\\r\\nPath:ssml\\r\\n\\r\\n${SSML_text}`;\r\n this.ws!.send(speechMessage);\r\n };\r\n\r\n this.ws.onmessage = (event) => {\r\n resetInactivityTimeout(); // restart inactivity timeout\r\n if (typeof event.data === 'string') {\r\n if (event.data.includes('Path:turn.end')) {\r\n this.ws?.close();\r\n }\r\n } else {\r\n const reader = new FileReader();\r\n reader.onload = () => {\r\n const arrayBuffer = reader.result as ArrayBuffer;\r\n const uint8Array = new Uint8Array(arrayBuffer);\r\n \r\n const needle = new TextEncoder().encode(\"Path:audio\\r\\n\");\r\n const audioStartIndex = this.indexOf(uint8Array, needle);\r\n\r\n if (audioStartIndex !== -1) {\r\n const audioChunk = uint8Array.slice(audioStartIndex + needle.length);\r\n this.audio_stream.push(audioChunk);\r\n push(audioChunk);\r\n }\r\n };\r\n reader.readAsArrayBuffer(event.data);\r\n }\r\n };\r\n\r\n this.ws.onerror = (err: any) => {\r\n clearTimeout(inactivityTimeout);\r\n error = new Error('WebSocket error');\r\n done = true;\r\n if (notify) {\r\n notify();\r\n notify = null;\r\n }\r\n };\r\n\r\n this.ws.onclose = () => {\r\n clearTimeout(inactivityTimeout);\r\n done = true;\r\n if (notify) {\r\n notify();\r\n notify = null;\r\n }\r\n };\r\n\r\n while (!done || queue.length > 0) {\r\n if (queue.length === 0) {\r\n await new Promise<void>(resolve => (notify = resolve));\r\n continue;\r\n }\r\n const chunk = queue.shift();\r\n if (chunk) {\r\n yield chunk;\r\n }\r\n }\r\n\r\n if (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n private processAudioData(buffer: Uint8Array): void {\r\n const needle = new TextEncoder().encode(\"Path:audio\\r\\n\");\r\n const audioStartIndex = this.indexOf(buffer, needle);\r\n\r\n if (audioStartIndex !== -1) {\r\n const audioChunk = buffer.slice(audioStartIndex + needle.length);\r\n this.audio_stream.push(audioChunk);\r\n }\r\n }\r\n\r\n private indexOf(arr: Uint8Array, subarr: Uint8Array): number {\r\n for (let i = 0; i <= arr.length - subarr.length; i++) {\r\n let match = true;\r\n for (let j = 0; j < subarr.length; j++) {\r\n if (arr[i + j] !== subarr[j]) {\r\n match = false;\r\n break;\r\n }\r\n }\r\n if (match) return i;\r\n }\r\n return -1;\r\n }\r\n\r\n private async generateSecMsGec(trustedClientToken: string): Promise<string> {\r\n const now = this.nowRFC1123();\r\n const fixedDate = this.parseRFC1123(now);\r\n const ticks = Math.floor(fixedDate.getTime() / 1000) + 11644473600;\r\n const rounded = ticks - (ticks % 300);\r\n const windowsTicks = rounded * 10_000_000;\r\n\r\n const encoder = new TextEncoder();\r\n const data = encoder.encode(`${windowsTicks}${trustedClientToken}`);\r\n const hashBuffer = await crypto.subtle.digest('SHA-256', data);\r\n\r\n return Array.from(new Uint8Array(hashBuffer))\r\n .map(b => b.toString(16).padStart(2, '0'))\r\n .join('')\r\n .toUpperCase();\r\n }\r\n\r\n getAudioData(): Uint8Array {\r\n if (this.audio_stream.length === 0) {\r\n throw new Error(\"No audio data available\");\r\n }\r\n const totalLength = this.audio_stream.reduce((acc, chunk) => acc + chunk.length, 0);\r\n const result = new Uint8Array(totalLength);\r\n let offset = 0;\r\n for (const chunk of this.audio_stream) {\r\n result.set(chunk, offset);\r\n offset += chunk.length;\r\n }\r\n return result;\r\n }\r\n}\r\n"],
5
- "mappings": "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",
6
- "names": ["Constants", "bytes", "b", "EdgeTTS", "__publicField", "secMsGEC", "Constants", "voice", "locale", "gender", "c", "r", "pitch", "rate", "rateValue", "volume", "volumeValue", "content", "trimmedContent", "errors", "hasSpeakTag", "hasVoiceTag", "text", "options", "inputType", "treatAsSSML", "detection", "ssml", "escapedText", "rfcStr", "resolve", "reject", "reqId", "url", "SSML_text", "timedOut", "inactivityTimeout", "resetInactivityTimeout", "message", "timestamp", "speechMessage", "event", "reader", "arrayBuffer", "uint8Array", "err", "queue", "done", "error", "notify", "push", "chunk", "needle", "audioStartIndex", "audioChunk", "buffer", "arr", "subarr", "match", "j", "trustedClientToken", "now", "fixedDate", "ticks", "windowsTicks", "data", "hashBuffer", "b", "totalLength", "acc", "result", "offset"]
4
+ "sourcesContent": ["export const Constants = {\r\n TRUSTED_CLIENT_TOKEN: '6A5AA1D4EAFF4E9FB37E23D68491D6F4',\r\n BASE_URL: 'https://speech.platform.bing.com/consumer/speech/synthesize/readaloud',\r\n WSS_URL: 'wss://speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1',\r\n VOICES_URL: 'https://speech.platform.bing.com/consumer/speech/synthesize/readaloud/voices/list',\r\n\r\n CHROMIUM_FULL_VERSION: '143.0.3650.75',\r\n CHROMIUM_MAJOR_VERSION: '143',\r\n VERSION_MS_GEC: '1-143.0.3650',\r\n\r\n token32() {\r\n const bytes = new Uint8Array(16);\r\n crypto.getRandomValues(bytes);\r\n\r\n return Array.from(bytes)\r\n .map(b => b.toString(16).padStart(2, '0'))\r\n .join('')\r\n .toUpperCase();\r\n },\r\n\r\n getBaseHeaders() {\r\n return {\r\n 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0',\r\n 'Accept-Encoding': 'gzip, deflate, br, zstd',\r\n 'Accept-Language': 'en-US,en;q=0.9',\r\n 'Cookie': 'MUID=' + this.token32()\r\n };\r\n },\r\n\r\n WSS_HEADERS: {\r\n 'Pragma': 'no-cache',\r\n 'Cache-Control': 'no-cache',\r\n 'Origin': 'chrome-extension://jdiccldimpdaibmpdkjnbmckianbfold',\r\n 'Sec-WebSocket-Protocol': 'synthesize',\r\n 'Sec-WebSocket-Version': '13',\r\n 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.3650.75 Safari/537.36 Edg/143.0.3650.75'\r\n },\r\n\r\n VOICE_HEADERS: {\r\n 'Sec-CH-UA': '\" Not;A Brand\";v=\"99\", \"Microsoft Edge\";v=\"143\", \"Chromium\";v=\"143\"',\r\n 'Sec-CH-UA-Mobile': '?0',\r\n 'Accept': '*/*',\r\n 'Sec-Fetch-Site': 'none',\r\n 'Sec-Fetch-Mode': 'cors',\r\n 'Sec-Fetch-Dest': 'empty'\r\n },\r\n\r\n // https://learn.microsoft.com/en-us/azure/ai-services/speech-service/rest-text-to-speech?tabs=nonstreaming\r\n OUTPUT_FORMAT: {\r\n 'AUDIO_24KHZ_48KBITRATE_MONO_MP3': 'audio-24khz-48kbitrate-mono-mp3',\r\n 'AUDIO_24KHZ_96KBITRATE_MONO_MP3': 'audio-24khz-96kbitrate-mono-mp3',\r\n 'WEBM_24KHZ_16BIT_MONO_OPUS': 'webm-24khz-16bit-mono-opus',\r\n }\r\n\r\n\r\n};\r\n", "import { Constants } from '../config/constants';\r\n\r\nexport interface Voice {\r\n Name: string;\r\n ShortName: string;\r\n Gender: string;\r\n Locale: string;\r\n FriendlyName: string;\r\n LocalName: string;\r\n}\r\n\r\nexport interface SynthesisOptions {\r\n pitch?: string | number;\r\n rate?: string | number;\r\n volume?: string | number;\r\n}\r\n\r\nexport class EdgeTTS {\r\n private audio_stream: Uint8Array[] = [];\r\n private ws?: WebSocket;\r\n\r\n\r\n async normalizeVoices(data: any[]): Promise<Voice[]> {\r\n const out = [];\r\n for (const v of data || []) {\r\n const short = v?.ShortName || \"\";\r\n const locale = v?.Locale || \"\";\r\n\r\n // base: remove locale prefix and Neural/NeuralHD suffix\r\n let base = short.replace(/^[a-z]{2}-[A-Z]{2}-/, \"\");\r\n base = base.replace(/NeuralHD$/, \"\").replace(/Neural$/, \"\").trim();\r\n\r\n // VoiceType: if NeuralHD/Neural in Name or ShortName\r\n const mix = `${v?.Name || \"\"} ${short}`;\r\n const voiceType =\r\n v?.VoiceType || (/NeuralHD/i.test(mix) ? \"NeuralHD\" : \"Neural\");\r\n\r\n // LocaleName: prefer LocaleName -> LanguageName -> locale\r\n const localeName = v?.LocaleName || (locale || null);\r\n\r\n // DisplayName: prefer DisplayName -> FriendlyName -> base -> short\r\n let display = v?.DisplayName || v?.FriendlyName || base || short;\r\n display = display.replace(/^Microsoft\\s+/i, \"\");\r\n display = display.split(\" - \")[0].trim();\r\n\r\n display = display.replace(/\\s*Online\\s*\\(Natural\\)\\s*/i, \" \");\r\n display = display.replace(/\\s*Online\\s*/i, \" \");\r\n display = display.replace(/\\s+/g, \" \").trim();\r\n\r\n // VoiceTag parsing\r\n const tag = (v?.VoiceTag && typeof v.VoiceTag === \"object\") ? v.VoiceTag : {};\r\n const tailored = Array.isArray(tag.TailoredScenarios)\r\n ? tag.TailoredScenarios\r\n : (Array.isArray(tag.ContentCategories) ? tag.ContentCategories : []);\r\n const personalities = Array.isArray(tag.VoicePersonalities)\r\n ? tag.VoicePersonalities\r\n : [];\r\n\r\n out.push({\r\n Name: short || (v?.Name || \"\"),\r\n DisplayName: display,\r\n LocalName: display,\r\n ShortName: short || (v?.Name || \"\"),\r\n Gender: v?.Gender ?? null,\r\n Locale: locale || null,\r\n LocaleName: localeName,\r\n SecondaryLocaleList: Array.isArray(v?.SecondaryLocaleList) ? v.SecondaryLocaleList : [],\r\n VoiceType: voiceType,\r\n VoiceTag: {\r\n TailoredScenarios: tailored,\r\n VoicePersonalities: personalities,\r\n },\r\n FriendlyName: `${display} (${voiceType}) - ${localeName}`,\r\n });\r\n }\r\n\r\n return out;\r\n }\r\n\r\n async getVoices(): Promise<Voice[]> {\r\n const secMsGEC = await this.generateSecMsGec(Constants.TRUSTED_CLIENT_TOKEN);\r\n\r\n const response = await fetch(\r\n `${Constants.VOICES_URL}?TrustedClientToken=${Constants.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${secMsGEC}&Sec-MS-GEC-Version=${Constants.VERSION_MS_GEC}`,\r\n { headers: Constants.getBaseHeaders() }\r\n );\r\n\r\n const data = await response.json();\r\n return this.normalizeVoices(data.voices || []);\r\n }\r\n\r\n async getVoicesByLanguage(locale: string): Promise<Voice[]> {\r\n const voices = await this.getVoices();\r\n return voices.filter(voice => voice.Locale.startsWith(locale));\r\n }\r\n\r\n async getVoicesByGender(gender: 'Male' | 'Female'): Promise<Voice[]> {\r\n const voices = await this.getVoices();\r\n return voices.filter(voice => voice.Gender === gender);\r\n }\r\n\r\n private generateUUID(): string {\r\n return 'xxxxxxxx-xxxx-xxxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\r\n const r = Math.random() * 16 | 0;\r\n const v = c === 'x' ? r : (r & 0x3 | 0x8);\r\n return v.toString(16);\r\n });\r\n }\r\n\r\n private validatePitch(pitch: string | number): string {\r\n if (typeof pitch === 'number') {\r\n return (pitch >= 0 ? `+${pitch}Hz` : `${pitch}Hz`);\r\n }\r\n return pitch;\r\n }\r\n\r\n private validateRate(rate: string | number): string {\r\n let rateValue: number;\r\n if (typeof rate === 'string') {\r\n rateValue = parseFloat(rate.replace('%', ''));\r\n } else {\r\n rateValue = rate;\r\n }\r\n return rateValue >= 0 ? `+${rateValue}%` : `${rateValue}%`;\r\n }\r\n\r\n private validateVolume(volume: string | number): string {\r\n let volumeValue: number;\r\n if (typeof volume === 'string') {\r\n volumeValue = parseInt(volume.replace('%', ''), 10);\r\n } else {\r\n volumeValue = volume;\r\n }\r\n return `${volumeValue}%`;\r\n }\r\n\r\n private escapeXML(text: string): string {\r\n return text\r\n .replace(/&/g, '&amp;')\r\n .replace(/</g, '&lt;')\r\n .replace(/>/g, '&gt;')\r\n .replace(/\"/g, '&quot;')\r\n .replace(/'/g, '&apos;');\r\n }\r\n\r\n private getSSML(content: string, voice: string, options: SynthesisOptions = {}): string { \r\n const pitch = this.validatePitch(options.pitch ?? 0);\r\n const rate = this.validateRate(options.rate ?? 0);\r\n const volume = this.validateVolume(options.volume ?? 0);\r\n const escapedText = this.escapeXML(content);\r\n\r\n return `<speak version=\"1.0\" xmlns=\"http://www.w3.org/2001/10/synthesis\" xmlns:mstts=\"https://www.w3.org/2001/mstts\" xml:lang=\"en-US\">\r\n <voice name=\"${voice}\">\r\n <prosody pitch=\"${pitch}\" rate=\"${rate}\" volume=\"${volume}\">\r\n ${escapedText}\r\n </prosody>\r\n </voice>\r\n </speak>`;\r\n }\r\n\r\n private nowRFC1123(): string {\r\n return new Date().toUTCString();\r\n }\r\n\r\n private parseRFC1123(rfcStr: string): Date {\r\n return new Date(rfcStr);\r\n }\r\n\r\n private buildTTSConfigMessage(): string {\r\n const timestamp = this.nowRFC1123();\r\n return `X-Timestamp:${timestamp}\\r\\nContent-Type:application/json; charset=utf-8\\r\\nPath:speech.config\\r\\n\\r\\n` +\r\n `{\"context\":{\"synthesis\":{\"audio\":{\"metadataoptions\":{\"sentenceBoundaryEnabled\":false,\"wordBoundaryEnabled\":true},\"outputFormat\":\"audio-24khz-48kbitrate-mono-mp3\"}}}}`;\r\n }\r\n\r\n async synthesize(text: string, voice: string = 'en-US-JennyNeural', options: SynthesisOptions = {}): Promise<void> {\r\n const secMsGEC = await this.generateSecMsGec(Constants.TRUSTED_CLIENT_TOKEN);\r\n\r\n return new Promise((resolve, reject) => {\r\n this.audio_stream = [];\r\n const reqId = this.generateUUID();\r\n const url = `${Constants.WSS_URL}?TrustedClientToken=${Constants.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${secMsGEC}&Sec-MS-GEC-Version=${Constants.VERSION_MS_GEC}&ConnectionId=${reqId}`;\r\n\r\n this.ws = new WebSocket(url);\r\n\r\n const SSML_text = this.getSSML(text, voice, options);\r\n\r\n let timedOut = false;\r\n let inactivityTimeout: number;\r\n\r\n const resetInactivityTimeout = () => {\r\n clearTimeout(inactivityTimeout);\r\n inactivityTimeout = window.setTimeout(() => {\r\n timedOut = true;\r\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\r\n this.ws.close();\r\n }\r\n reject(new Error(\"WebSocket inactivity timeout - no response from server\"));\r\n }, 30000); // 30 seconds of inactivity\r\n };\r\n\r\n this.ws.onopen = () => {\r\n resetInactivityTimeout(); // start the inactivity timeout\r\n const message = this.buildTTSConfigMessage();\r\n this.ws!.send(message);\r\n const timestamp = this.nowRFC1123();\r\n const speechMessage = `X-RequestId:${reqId}\\r\\nContent-Type:application/ssml+xml\\r\\nX-Timestamp:${timestamp}\\r\\nPath:ssml\\r\\n\\r\\n${SSML_text}`;\r\n this.ws!.send(speechMessage);\r\n };\r\n\r\n this.ws.onmessage = (event) => {\r\n resetInactivityTimeout(); // restart inactivity timeout \r\n if (typeof event.data === 'string') {\r\n if (event.data.includes('Path:turn.end')) {\r\n this.ws?.close();\r\n }\r\n } else {\r\n const reader = new FileReader();\r\n reader.onload = () => {\r\n const arrayBuffer = reader.result as ArrayBuffer;\r\n const uint8Array = new Uint8Array(arrayBuffer);\r\n this.processAudioData(uint8Array);\r\n };\r\n reader.readAsArrayBuffer(event.data);\r\n }\r\n };\r\n\r\n this.ws.onerror = (err: any) => {\r\n clearTimeout(inactivityTimeout);\r\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\r\n this.ws.close();\r\n }\r\n reject(new Error('WebSocket error'));\r\n };\r\n\r\n this.ws.onclose = () => {\r\n clearTimeout(inactivityTimeout);\r\n if (!timedOut) {\r\n resolve();\r\n }\r\n };\r\n });\r\n }\r\n\r\n async *synthesizeStream(text: string, voice: string = 'en-US-JennyNeural', options: SynthesisOptions = {}): AsyncGenerator<Uint8Array, void, unknown> {\r\n this.audio_stream = [];\r\n\r\n const reqId = this.generateUUID();\r\n const secMsGEC = await this.generateSecMsGec(Constants.TRUSTED_CLIENT_TOKEN);\r\n\r\n const url = `${Constants.WSS_URL}?TrustedClientToken=${Constants.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${secMsGEC}&Sec-MS-GEC-Version=${Constants.VERSION_MS_GEC}&ConnectionId=${reqId}`;\r\n\r\n this.ws = new WebSocket(url);\r\n\r\n const SSML_text = this.getSSML(text, voice, options);\r\n\r\n const queue: Uint8Array[] = [];\r\n let done = false;\r\n let error: Error | null = null;\r\n let notify: (() => void) | null = null;\r\n\r\n const push = (chunk: Uint8Array) => {\r\n queue.push(chunk);\r\n if (notify) {\r\n notify();\r\n notify = null;\r\n }\r\n };\r\n\r\n let timedOut = false;\r\n let inactivityTimeout: number;\r\n\r\n const resetInactivityTimeout = () => {\r\n clearTimeout(inactivityTimeout);\r\n inactivityTimeout = window.setTimeout(() => {\r\n timedOut = true;\r\n error = new Error(\"WebSocket inactivity timeout - no response from server\");\r\n done = true;\r\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\r\n this.ws.close();\r\n }\r\n if (notify) {\r\n notify();\r\n notify = null;\r\n }\r\n }, 30000); // 30 seconds of inactivity\r\n };\r\n\r\n this.ws.onopen = () => {\r\n resetInactivityTimeout(); // start the inactivity timeout\r\n const message = this.buildTTSConfigMessage();\r\n this.ws!.send(message);\r\n\r\n const timestamp = this.nowRFC1123();\r\n const speechMessage = `X-RequestId:${reqId}\\r\\nContent-Type:application/ssml+xml\\r\\nX-Timestamp:${timestamp}\\r\\nPath:ssml\\r\\n\\r\\n${SSML_text}`;\r\n this.ws!.send(speechMessage);\r\n };\r\n\r\n this.ws.onmessage = (event) => {\r\n resetInactivityTimeout(); // restart inactivity timeout\r\n if (typeof event.data === 'string') {\r\n if (event.data.includes('Path:turn.end')) {\r\n this.ws?.close();\r\n }\r\n } else {\r\n const reader = new FileReader();\r\n reader.onload = () => {\r\n const arrayBuffer = reader.result as ArrayBuffer;\r\n const uint8Array = new Uint8Array(arrayBuffer);\r\n\r\n const needle = new TextEncoder().encode(\"Path:audio\\r\\n\");\r\n const audioStartIndex = this.indexOf(uint8Array, needle);\r\n\r\n if (audioStartIndex !== -1) {\r\n const audioChunk = uint8Array.slice(audioStartIndex + needle.length);\r\n this.audio_stream.push(audioChunk);\r\n push(audioChunk);\r\n }\r\n };\r\n reader.readAsArrayBuffer(event.data);\r\n }\r\n };\r\n\r\n this.ws.onerror = (err: any) => {\r\n clearTimeout(inactivityTimeout);\r\n error = new Error('WebSocket error');\r\n done = true;\r\n if (notify) {\r\n notify();\r\n notify = null;\r\n }\r\n };\r\n\r\n this.ws.onclose = () => {\r\n clearTimeout(inactivityTimeout);\r\n done = true;\r\n if (notify) {\r\n notify();\r\n notify = null;\r\n }\r\n };\r\n\r\n while (!done || queue.length > 0) {\r\n if (queue.length === 0) {\r\n await new Promise<void>(resolve => (notify = resolve));\r\n continue;\r\n }\r\n const chunk = queue.shift();\r\n if (chunk) {\r\n yield chunk;\r\n }\r\n }\r\n\r\n if (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n private processAudioData(buffer: Uint8Array): void {\r\n const needle = new TextEncoder().encode(\"Path:audio\\r\\n\");\r\n const audioStartIndex = this.indexOf(buffer, needle);\r\n\r\n if (audioStartIndex !== -1) {\r\n const audioChunk = buffer.slice(audioStartIndex + needle.length);\r\n this.audio_stream.push(audioChunk);\r\n }\r\n }\r\n\r\n private indexOf(arr: Uint8Array, subarr: Uint8Array): number {\r\n for (let i = 0; i <= arr.length - subarr.length; i++) {\r\n let match = true;\r\n for (let j = 0; j < subarr.length; j++) {\r\n if (arr[i + j] !== subarr[j]) {\r\n match = false;\r\n break;\r\n }\r\n }\r\n if (match) return i;\r\n }\r\n return -1;\r\n }\r\n\r\n private async generateSecMsGec(trustedClientToken: string): Promise<string> {\r\n const now = this.nowRFC1123();\r\n const fixedDate = this.parseRFC1123(now);\r\n const ticks = Math.floor(fixedDate.getTime() / 1000) + 11644473600;\r\n const rounded = ticks - (ticks % 300);\r\n const windowsTicks = rounded * 10_000_000;\r\n\r\n const encoder = new TextEncoder();\r\n const data = encoder.encode(`${windowsTicks}${trustedClientToken}`);\r\n const hashBuffer = await crypto.subtle.digest('SHA-256', data);\r\n\r\n return Array.from(new Uint8Array(hashBuffer))\r\n .map(b => b.toString(16).padStart(2, '0'))\r\n .join('')\r\n .toUpperCase();\r\n }\r\n\r\n getAudioData(): Uint8Array {\r\n if (this.audio_stream.length === 0) {\r\n throw new Error(\"No audio data available\");\r\n }\r\n const totalLength = this.audio_stream.reduce((acc, chunk) => acc + chunk.length, 0);\r\n const result = new Uint8Array(totalLength);\r\n let offset = 0;\r\n for (const chunk of this.audio_stream) {\r\n result.set(chunk, offset);\r\n offset += chunk.length;\r\n }\r\n return result;\r\n }\r\n}\r\n"],
5
+ "mappings": "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",
6
+ "names": ["Constants", "bytes", "b", "EdgeTTS", "__publicField", "data", "out", "v", "short", "locale", "base", "mix", "voiceType", "localeName", "display", "tag", "tailored", "personalities", "secMsGEC", "Constants", "voice", "gender", "c", "r", "pitch", "rate", "rateValue", "volume", "volumeValue", "text", "content", "options", "escapedText", "rfcStr", "resolve", "reject", "reqId", "url", "SSML_text", "timedOut", "inactivityTimeout", "resetInactivityTimeout", "message", "timestamp", "speechMessage", "event", "reader", "arrayBuffer", "uint8Array", "err", "queue", "done", "error", "notify", "push", "chunk", "needle", "audioStartIndex", "audioChunk", "buffer", "arr", "subarr", "i", "match", "j", "trustedClientToken", "now", "fixedDate", "ticks", "windowsTicks", "hashBuffer", "b", "totalLength", "acc", "result", "offset"]
7
7
  }
@@ -29,12 +29,12 @@ var EdgeTTSModule = (() => {
29
29
  // src/config/constants.ts
30
30
  var Constants = {
31
31
  TRUSTED_CLIENT_TOKEN: "6A5AA1D4EAFF4E9FB37E23D68491D6F4",
32
- BASE_URL: "https://api.msedgeservices.com/tts/cognitiveservices",
33
- WSS_URL: "wss://api.msedgeservices.com/tts/cognitiveservices/websocket/v1",
34
- VOICES_URL: "https://api.msedgeservices.com/tts/cognitiveservices/voices/list",
35
- CHROMIUM_FULL_VERSION: "142.0.3595.0",
36
- CHROMIUM_MAJOR_VERSION: "142",
37
- VERSION_MS_GEC: "1-142.0.3595",
32
+ BASE_URL: "https://speech.platform.bing.com/consumer/speech/synthesize/readaloud",
33
+ WSS_URL: "wss://speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1",
34
+ VOICES_URL: "https://speech.platform.bing.com/consumer/speech/synthesize/readaloud/voices/list",
35
+ CHROMIUM_FULL_VERSION: "143.0.3650.75",
36
+ CHROMIUM_MAJOR_VERSION: "143",
37
+ VERSION_MS_GEC: "1-143.0.3650",
38
38
  token32() {
39
39
  const bytes = new Uint8Array(16);
40
40
  crypto.getRandomValues(bytes);
@@ -42,9 +42,9 @@ var EdgeTTSModule = (() => {
42
42
  },
43
43
  getBaseHeaders() {
44
44
  return {
45
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0",
45
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0",
46
46
  "Accept-Encoding": "gzip, deflate, br, zstd",
47
- "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",
47
+ "Accept-Language": "en-US,en;q=0.9",
48
48
  "Cookie": "MUID=" + this.token32()
49
49
  };
50
50
  },
@@ -54,10 +54,10 @@ var EdgeTTSModule = (() => {
54
54
  "Origin": "chrome-extension://jdiccldimpdaibmpdkjnbmckianbfold",
55
55
  "Sec-WebSocket-Protocol": "synthesize",
56
56
  "Sec-WebSocket-Version": "13",
57
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0"
57
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.3650.75 Safari/537.36 Edg/143.0.3650.75"
58
58
  },
59
59
  VOICE_HEADERS: {
60
- "Sec-CH-UA": '" Not;A Brand";v="99", "Microsoft Edge";v="140", "Chromium";v="140"',
60
+ "Sec-CH-UA": '" Not;A Brand";v="99", "Microsoft Edge";v="143", "Chromium";v="143"',
61
61
  "Sec-CH-UA-Mobile": "?0",
62
62
  "Accept": "*/*",
63
63
  "Sec-Fetch-Site": "none",
@@ -66,44 +66,9 @@ var EdgeTTSModule = (() => {
66
66
  },
67
67
  // https://learn.microsoft.com/en-us/azure/ai-services/speech-service/rest-text-to-speech?tabs=nonstreaming
68
68
  OUTPUT_FORMAT: {
69
- // Streaming
70
- AMR_WB_16000HZ: "amr-wb-16000hz",
71
- AUDIO_16KHZ_16BIT_32KBPS_MONO_OPUS: "audio-16khz-16bit-32kbps-mono-opus",
72
- AUDIO_16KHZ_32KBITRATE_MONO_MP3: "audio-16khz-32kbitrate-mono-mp3",
73
- AUDIO_16KHZ_64KBITRATE_MONO_MP3: "audio-16khz-64kbitrate-mono-mp3",
74
- AUDIO_16KHZ_128KBITRATE_MONO_MP3: "audio-16khz-128kbitrate-mono-mp3",
75
- AUDIO_24KHZ_16BIT_24KBPS_MONO_OPUS: "audio-24khz-16bit-24kbps-mono-opus",
76
- AUDIO_24KHZ_16BIT_48KBPS_MONO_OPUS: "audio-24khz-16bit-48kbps-mono-opus",
77
- AUDIO_24KHZ_48KBITRATE_MONO_MP3: "audio-24khz-48kbitrate-mono-mp3",
78
- AUDIO_24KHZ_96KBITRATE_MONO_MP3: "audio-24khz-96kbitrate-mono-mp3",
79
- AUDIO_24KHZ_160KBITRATE_MONO_MP3: "audio-24khz-160kbitrate-mono-mp3",
80
- AUDIO_48KHZ_96KBITRATE_MONO_MP3: "audio-48khz-96kbitrate-mono-mp3",
81
- AUDIO_48KHZ_192KBITRATE_MONO_MP3: "audio-48khz-192kbitrate-mono-mp3",
82
- G722_16KHZ_64KBPS: "g722-16khz-64kbps",
83
- OGG_16KHZ_16BIT_MONO_OPUS: "ogg-16khz-16bit-mono-opus",
84
- OGG_24KHZ_16BIT_MONO_OPUS: "ogg-24khz-16bit-mono-opus",
85
- OGG_48KHZ_16BIT_MONO_OPUS: "ogg-48khz-16bit-mono-opus",
86
- RAW_8KHZ_8BIT_MONO_ALAW: "raw-8khz-8bit-mono-alaw",
87
- RAW_8KHZ_8BIT_MONO_MULAW: "raw-8khz-8bit-mono-mulaw",
88
- RAW_8KHZ_16BIT_MONO_PCM: "raw-8khz-16bit-mono-pcm",
89
- RAW_16KHZ_16BIT_MONO_PCM: "raw-16khz-16bit-mono-pcm",
90
- RAW_16KHZ_16BIT_MONO_TRUESILK: "raw-16khz-16bit-mono-truesilk",
91
- RAW_22050HZ_16BIT_MONO_PCM: "raw-22050hz-16bit-mono-pcm",
92
- RAW_24KHZ_16BIT_MONO_PCM: "raw-24khz-16bit-mono-pcm",
93
- RAW_24KHZ_16BIT_MONO_TRUESILK: "raw-24khz-16bit-mono-truesilk",
94
- RAW_44100HZ_16BIT_MONO_PCM: "raw-44100hz-16bit-mono-pcm",
95
- RAW_48KHZ_16BIT_MONO_PCM: "raw-48khz-16bit-mono-pcm",
96
- WEBM_16KHZ_16BIT_MONO_OPUS: "webm-16khz-16bit-mono-opus",
97
- WEBM_24KHZ_16BIT_24KBPS_MONO_OPUS: "webm-24khz-16bit-24kbps-mono-opus",
98
- WEBM_24KHZ_16BIT_MONO_OPUS: "webm-24khz-16bit-mono-opus",
99
- // NonStreaming
100
- RIFF_8KHZ_8BIT_MONO_ALAW: "riff-8khz-8bit-mono-alaw",
101
- RIFF_8KHZ_8BIT_MONO_MULAW: "riff-8khz-8bit-mono-mulaw",
102
- RIFF_8KHZ_16BIT_MONO_PCM: "riff-8khz-16bit-mono-pcm",
103
- RIFF_22050HZ_16BIT_MONO_PCM: "riff-22050hz-16bit-mono-pcm",
104
- RIFF_24KHZ_16BIT_MONO_PCM: "riff-24khz-16bit-mono-pcm",
105
- RIFF_44100HZ_16BIT_MONO_PCM: "riff-44100hz-16bit-mono-pcm",
106
- RIFF_48KHZ_16BIT_MONO_PCM: "riff-48khz-16bit-mono-pcm"
69
+ "AUDIO_24KHZ_48KBITRATE_MONO_MP3": "audio-24khz-48kbitrate-mono-mp3",
70
+ "AUDIO_24KHZ_96KBITRATE_MONO_MP3": "audio-24khz-96kbitrate-mono-mp3",
71
+ "WEBM_24KHZ_16BIT_MONO_OPUS": "webm-24khz-16bit-mono-opus"
107
72
  }
108
73
  };
109
74
 
@@ -113,19 +78,52 @@ var EdgeTTSModule = (() => {
113
78
  __publicField(this, "audio_stream", []);
114
79
  __publicField(this, "ws");
115
80
  }
81
+ async normalizeVoices(data) {
82
+ const out = [];
83
+ for (const v of data || []) {
84
+ const short = v?.ShortName || "";
85
+ const locale = v?.Locale || "";
86
+ let base = short.replace(/^[a-z]{2}-[A-Z]{2}-/, "");
87
+ base = base.replace(/NeuralHD$/, "").replace(/Neural$/, "").trim();
88
+ const mix = `${v?.Name || ""} ${short}`;
89
+ const voiceType = v?.VoiceType || (/NeuralHD/i.test(mix) ? "NeuralHD" : "Neural");
90
+ const localeName = v?.LocaleName || (locale || null);
91
+ let display = v?.DisplayName || v?.FriendlyName || base || short;
92
+ display = display.replace(/^Microsoft\s+/i, "");
93
+ display = display.split(" - ")[0].trim();
94
+ display = display.replace(/\s*Online\s*\(Natural\)\s*/i, " ");
95
+ display = display.replace(/\s*Online\s*/i, " ");
96
+ display = display.replace(/\s+/g, " ").trim();
97
+ const tag = v?.VoiceTag && typeof v.VoiceTag === "object" ? v.VoiceTag : {};
98
+ const tailored = Array.isArray(tag.TailoredScenarios) ? tag.TailoredScenarios : Array.isArray(tag.ContentCategories) ? tag.ContentCategories : [];
99
+ const personalities = Array.isArray(tag.VoicePersonalities) ? tag.VoicePersonalities : [];
100
+ out.push({
101
+ Name: short || (v?.Name || ""),
102
+ DisplayName: display,
103
+ LocalName: display,
104
+ ShortName: short || (v?.Name || ""),
105
+ Gender: v?.Gender ?? null,
106
+ Locale: locale || null,
107
+ LocaleName: localeName,
108
+ SecondaryLocaleList: Array.isArray(v?.SecondaryLocaleList) ? v.SecondaryLocaleList : [],
109
+ VoiceType: voiceType,
110
+ VoiceTag: {
111
+ TailoredScenarios: tailored,
112
+ VoicePersonalities: personalities
113
+ },
114
+ FriendlyName: `${display} (${voiceType}) - ${localeName}`
115
+ });
116
+ }
117
+ return out;
118
+ }
116
119
  async getVoices() {
117
120
  const secMsGEC = await this.generateSecMsGec(Constants.TRUSTED_CLIENT_TOKEN);
118
121
  const response = await fetch(
119
- `${Constants.VOICES_URL}?Ocp-Apim-Subscription-Key=${Constants.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${secMsGEC}&Sec-MS-GEC-Version=${Constants.VERSION_MS_GEC}`,
122
+ `${Constants.VOICES_URL}?TrustedClientToken=${Constants.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${secMsGEC}&Sec-MS-GEC-Version=${Constants.VERSION_MS_GEC}`,
120
123
  { headers: Constants.getBaseHeaders() }
121
124
  );
122
125
  const data = await response.json();
123
- return data.map((voice) => {
124
- voice.FriendlyName = voice.FriendlyName || voice.LocalName;
125
- delete voice.SampleRateHertz;
126
- delete voice.Status;
127
- return voice;
128
- });
126
+ return this.normalizeVoices(data.voices || []);
129
127
  }
130
128
  async getVoicesByLanguage(locale) {
131
129
  const voices = await this.getVoices();
@@ -166,69 +164,10 @@ var EdgeTTSModule = (() => {
166
164
  }
167
165
  return `${volumeValue}%`;
168
166
  }
169
- detectSSML(content) {
170
- const trimmedContent = content.trim();
171
- const looksLikeSSML = /^<\?xml|^<speak/i.test(trimmedContent);
172
- if (!looksLikeSSML) {
173
- return { isValid: true, isSSML: false };
174
- }
175
- const errors = [];
176
- const hasSpeakTag = /<speak\b[^>]*>[\s\S]*<\/speak>/i.test(trimmedContent);
177
- const hasVoiceTag = /<voice\b[^>]*>[\s\S]*<\/voice>/i.test(trimmedContent);
178
- if (!hasSpeakTag) {
179
- throw new Error("Invalid SSML: Missing <speak> tag");
180
- }
181
- if (!hasVoiceTag) {
182
- throw new Error("Invalid SSML: Missing <voice> tag");
183
- }
184
- const hasCorrectNamespace = /xmlns="http:\/\/www\.w3\.org\/2001\/10\/synthesis"/i.test(trimmedContent);
185
- if (!hasCorrectNamespace && hasSpeakTag) {
186
- throw new Error("Invalid SSML: Missing or incorrect namespace declaration");
187
- }
188
- return {
189
- isValid: errors.length === 0,
190
- isSSML: hasSpeakTag || hasVoiceTag,
191
- errors: errors.length > 0 ? errors : void 0
192
- };
193
- }
194
167
  escapeXML(text) {
195
168
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
196
169
  }
197
170
  getSSML(content, voice, options = {}) {
198
- const inputType = options.inputType || "auto";
199
- let treatAsSSML = false;
200
- if (inputType === "ssml") {
201
- treatAsSSML = true;
202
- } else if (inputType === "text") {
203
- treatAsSSML = false;
204
- } else {
205
- const detection = this.detectSSML(content);
206
- treatAsSSML = detection.isSSML;
207
- if (detection.isSSML) {
208
- console.log("\u2192 Detected SSML input");
209
- if (!detection.isValid) {
210
- console.warn("\u26A0 SSML validation warnings:", detection.errors);
211
- }
212
- } else {
213
- console.log("\u2192 Detected plain text input");
214
- }
215
- }
216
- if (treatAsSSML) {
217
- let ssml = content.trim();
218
- if (!ssml.includes("xmlns=")) {
219
- ssml = ssml.replace(
220
- /<speak([^>]*)>/i,
221
- '<speak$1 xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="https://www.w3.org/2001/mstts">'
222
- );
223
- }
224
- if (!/<voice\b[^>]*>/i.test(ssml) && voice) {
225
- ssml = ssml.replace(
226
- /(<speak[^>]*>)([\s\S]*?)(<\/speak>)/i,
227
- `$1<voice name="${voice}">$2</voice>$3`
228
- );
229
- }
230
- return ssml;
231
- }
232
171
  const pitch = this.validatePitch(options.pitch ?? 0);
233
172
  const rate = this.validateRate(options.rate ?? 0);
234
173
  const volume = this.validateVolume(options.volume ?? 0);
@@ -260,8 +199,7 @@ Path:speech.config\r
260
199
  return new Promise((resolve, reject) => {
261
200
  this.audio_stream = [];
262
201
  const reqId = this.generateUUID();
263
- const url = `${Constants.WSS_URL}?Ocp-Apim-Subscription-Key=${Constants.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${secMsGEC}&Sec-MS-GEC-Version=${Constants.VERSION_MS_GEC}&ConnectionId=${reqId}`;
264
- console.log("WebSocket URL:", url);
202
+ const url = `${Constants.WSS_URL}?TrustedClientToken=${Constants.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${secMsGEC}&Sec-MS-GEC-Version=${Constants.VERSION_MS_GEC}&ConnectionId=${reqId}`;
265
203
  this.ws = new WebSocket(url);
266
204
  const SSML_text = this.getSSML(text, voice, options);
267
205
  let timedOut = false;
@@ -324,7 +262,7 @@ ${SSML_text}`;
324
262
  this.audio_stream = [];
325
263
  const reqId = this.generateUUID();
326
264
  const secMsGEC = await this.generateSecMsGec(Constants.TRUSTED_CLIENT_TOKEN);
327
- const url = `${Constants.WSS_URL}?Ocp-Apim-Subscription-Key=${Constants.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${secMsGEC}&Sec-MS-GEC-Version=${Constants.VERSION_MS_GEC}&ConnectionId=${reqId}`;
265
+ const url = `${Constants.WSS_URL}?TrustedClientToken=${Constants.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${secMsGEC}&Sec-MS-GEC-Version=${Constants.VERSION_MS_GEC}&ConnectionId=${reqId}`;
328
266
  this.ws = new WebSocket(url);
329
267
  const SSML_text = this.getSSML(text, voice, options);
330
268
  const queue = [];