# 牛津高阶10 TTS，近期全平台失效问题的讨论

**URL:** <https://forum.freemdict.com/t/topic/42406>\
**Category:** 技术交流与词典编修\
**Created:** [2025 年12 月 23 日 03:32 UTC](https://forum.freemdict.com/t/topic/42406 "2025-12-23T03:32:40Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

作者： ![fanqi987](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/fanqi987/32/83038_2.png) [@fanqi987](https://forum.freemdict.com/u/fanqi987)\
发布日期： [2026 年1 月 26 日 07:54 UTC](https://forum.freemdict.com/t/topic/42406/44 "2026-01-26T07:54:35Z")

</div>

分享一下我后来搭的TTS链接，和上面k兄的替换方法一致

**解决方案2** ：js中搜索`speech.platform.bing.com` 替换为`public.fanqi987.dpdns.org/public/wss/speech.platform.bing.com`

---

<div class="post-metadata">

作者： ![GP125](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/gp125/32/82649_2.png) [@GP125](https://forum.freemdict.com/u/GP125)\
发布日期： [2026 年1 月 26 日 08:10 UTC](https://forum.freemdict.com/t/topic/42406/45 "2026-01-26T08:10:46Z")

</div>

感谢分享！能用。

---

<div class="post-metadata">

作者： ![fuzzygz](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/f/9e8a1a/32.png) [@fuzzygz](https://forum.freemdict.com/u/fuzzygz)\
发布日期： [2026 年1 月 26 日 12:45 UTC](https://forum.freemdict.com/t/topic/42406/46 "2026-01-26T12:45:18Z")

</div>

Hip, hip, hooray!

---

<div class="post-metadata">

作者： ![海上朝阳](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/%E6%B5%B7/9dc877/32.png) [@海上朝阳](https://forum.freemdict.com/u/%E6%B5%B7%E4%B8%8A%E6%9C%9D%E9%98%B3)\
发布日期： [2026 年1 月 26 日 13:41 UTC](https://forum.freemdict.com/t/topic/42406/47 "2026-01-26T13:41:01Z")

</div>

> [@fanqi987](#):
>
> `public.fanqi987.dpdns.org/public/wss/speech.platform.bing.com`

感谢分享，可以用。

---

<div class="post-metadata">

作者： ![xianjue114](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/x/a587f6/32.png) [@xianjue114](https://forum.freemdict.com/u/xianjue114)\
发布日期： [2026 年1 月 26 日 22:58 UTC](https://forum.freemdict.com/t/topic/42406/48 "2026-01-26T22:58:32Z")

</div>

实测，深蓝，可用！谢谢！！！

---

<div class="post-metadata">

作者： ![harderwu](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/h/b3f665/32.png) [@harderwu](https://forum.freemdict.com/u/harderwu)\
发布日期： [2026 年2 月 8 日 05:00 UTC](https://forum.freemdict.com/t/topic/42406/49 "2026-02-08T05:00:53Z")

</div>

[quote=“fanqi987, post:44, topic:42406”]  
[public.fanqi987.dpdns.org/public/wss/speech.platform.bing.com](http://public.fanqi987.dpdns.org/public/wss/speech.platform.bing.com)  
实测了，原来两个灰的小喇叭都可以朗读，感谢 👏

---

<div class="post-metadata">

作者： ![xingxingla](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/x/ccd318/32.png) [@xingxingla](https://forum.freemdict.com/u/xingxingla)\
发布日期： [2026 年2 月 26 日 06:35 UTC](https://forum.freemdict.com/t/topic/42406/50 "2026-02-26T06:35:08Z")

</div>

dictango（电脑端）为什么可以朗读……是因为用的edge webview还是自己实现了tts..

---

<div class="post-metadata">

作者： ![YYDWHY](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/y/6a8cbe/32.png) [@YYDWHY](https://forum.freemdict.com/u/YYDWHY)\
发布日期： [2026 年3 月 1 日 18:04 UTC](https://forum.freemdict.com/t/topic/42406/51 "2026-03-01T18:04:59Z")

</div>

真好！真强！感谢！

---

<div class="post-metadata">

作者： ![zkxning](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/z/e68b1a/32.png) [@zkxning](https://forum.freemdict.com/u/zkxning)\
发布日期： [2026 年3 月 5 日 02:54 UTC](https://forum.freemdict.com/t/topic/42406/52 "2026-03-05T02:54:06Z")

</div>

平板上实测可用，感谢🙏

---

<div class="post-metadata">

作者： ![csucjh](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/c/8dc957/32.png) [@csucjh](https://forum.freemdict.com/u/csucjh)\
发布日期： [2026 年4 月 2 日 15:59 UTC](https://forum.freemdict.com/t/topic/42406/53 "2026-04-02T15:59:06Z")

</div>

> [@fanqi987](#):
>
> [blic.fanqi987.dpdns.org/public/wss/](http://blic.fanqi987.dpdns.org/public/wss/)

请问修改这个地址需要梯子吗？没有梯子能用吗

---

<div class="post-metadata">

作者： ![xingxingla](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/x/ccd318/32.png) [@xingxingla](https://forum.freemdict.com/u/xingxingla)\
发布日期： [2026 年4 月 4 日 03:48 UTC](https://forum.freemdict.com/t/topic/42406/54 "2026-04-04T03:48:36Z")

</div>

不需要梯子啊

---

<div class="post-metadata">

作者： ![aiguo](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/aiguo/32/64210_2.png) [@aiguo](https://forum.freemdict.com/u/aiguo)\
发布日期： [2026 年4 月 9 日 07:26 UTC](https://forum.freemdict.com/t/topic/42406/55 "2026-04-09T07:26:03Z")

</div>

Everything’s running smoothly as of 04.09.26! Thanks a lot!

---

<div class="post-metadata">

作者： ![naisme](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/n/ac91a4/32.png) [@naisme](https://forum.freemdict.com/u/naisme)\
发布日期： [2026 年10 月 16 日 02:37 UTC](https://forum.freemdict.com/t/topic/42406/56 "2026-10-16T02:37:32Z")

</div>

又失效了。顺问对EdgeTTS现在有可靠的websocket fetch方法吗？手机app貌似只支持这种

---

<div class="post-metadata">

作者： ![goodman168](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/g/22d042/32.png) [@goodman168](https://forum.freemdict.com/u/goodman168)\
发布日期： [2026 年10 月 16 日 02:46 UTC](https://forum.freemdict.com/t/topic/42406/57 "2026-10-16T02:46:52Z")

</div>

使用国内引擎让TTS本地化，这个可行性如何

---

<div class="post-metadata">

作者： ![naisme](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/n/ac91a4/32.png) [@naisme](https://forum.freemdict.com/u/naisme)\
发布日期： [2026 年10 月 16 日 04:35 UTC](https://forum.freemdict.com/t/topic/42406/58 "2026-10-16T04:35:21Z")

</div>

PC上容易解决，手机上较难，有很多限制。

---

<div class="post-metadata">

作者： ![GP125](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/gp125/32/82649_2.png) [@GP125](https://forum.freemdict.com/u/GP125)\
发布日期： [2026 年10 月 16 日 05:37 UTC](https://forum.freemdict.com/t/topic/42406/59 "2026-10-16T05:37:02Z")

</div>

TTS 签名算法升级为 GEC v2，可以叫AI改一下

---

<div class="post-metadata">

作者： ![naisme](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/n/ac91a4/32.png) [@naisme](https://forum.freemdict.com/u/naisme)\
发布日期： [2026 年10 月 16 日 08:29 UTC](https://forum.freemdict.com/t/topic/42406/60 "2026-10-16T08:29:06Z")

</div>

> [@GP125](#):
>
> TTS 签名算法升级为 GEC v2

Deepseek帮改后还是没有效果

---

<div class="post-metadata">

作者： ![GP125](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/gp125/32/82649_2.png) [@GP125](https://forum.freemdict.com/u/GP125)\
发布日期： [2026 年10 月 16 日 08:44 UTC](https://forum.freemdict.com/t/topic/42406/61 "2026-10-16T08:44:17Z")

</div>

# OALD10：将 Edge TTS 签名升级为 GEC v2

## 适用范围

适用于 `oald.js` 中使用 `createEdgeTTS()`、`generateSecMsGecToken()`，并携带旧版 `Sec-MS-GEC-Version=1-130.0.2849.68` 的 OALD10 版本。

本文代码取自已部署脚本。签名算法移植自 `edge-tts 7.3.1` 的 `edge_tts/drm.py`。这是对当时接口的兼容修复，不保证微软后续修改协议后仍永久有效。

**只修改两处：签名函数、协议版本。不要只改版本号。** 公共代理地址、音色、音频解析、界面和 CSS 均无需改动。

## 一、备份原文件

先备份词典目录中的 `oald.js`，例如另存为 `oald.before-gecv2.js`。用支持 UTF-8 的代码编辑器打开原文件，尽量保留原来的换行符。

若文件已经使用本文的完整 GEC v2 函数及版本号，无须重复修改。

## 二、替换整个签名函数

在 `createEdgeTTS()` 内找到：

```javascript
function generateSecMsGecToken() {
    // 原来的签名代码
}

```

将整个函数（包括函数体及末尾花括号）替换为下面的完整代码。**保留后面原有的 `async function ensureSocketReady()`，不要一并删除。**

此函数继续使用 `createEdgeTTS()` 内原有的 `TRUSTED_CLIENT_TOKEN` 常量。无需添加 Python 服务或额外的 JS 文件。

```javascript
function generateSecMsGecToken() {
    // GEC v2; port of edge-tts DRM. All arithmetic is modulo 2^32.
    var C = {"initial":[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225],"state":[4255104674,2435071207,3192492180,3442351626,1811967817,79508907,4272990180,66059218],"schedule":[3945054110,358115615,2696978146,217723578,2787307148,3520959633,3235718560,4192668342,4039316851,1884868174,1904797190,15051571,3529027680,1920361828],"rounds":[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],"adjustment":3386640039,"coefficients":[[3895366065,3005677776],[1155409094,2296378653],[1005282748,693190712],[3365689651,3005795295],[2367603217,3557143765],[827258325,652566332],[3911487921,1618477510],[4037392853,2192753147],[101076211,4199654362],[3665427040,545047652],[3201434976,1010595059],[2314848760,3536931681],[905590982,3137643201],[3410617286,3311559015]]};
    function rol(v) { return ((v << 16) | (v >>> 16)) >>> 0; }
    function rr(v,n) { return (v >>> n) | (v << (32-n)); }
    function s0(v) { return (rr(v,7)^rr(v,18)^(v>>>3))>>>0; }
    function s1(v) { return (rr(v,17)^rr(v,19)^(v>>>10))>>>0; }
    function expand(w,start) {
        for(var i=start;i<64;i++) w[i]=(s1(w[i-2])+w[i-7]+s0(w[i-15])+w[i-16])>>>0;
    }
    function rounds(state,w,first) {
        var a=state[0],b=state[1],c=state[2],d=state[3],e=state[4],f=state[5],g=state[6],h=state[7];
        for(var i=first;i<64;i++) {
            var k=(first===14 && i===14)?C.adjustment:C.rounds[i];
            // Explicit unsigned conversions: JS XOR returns a signed int32.
            var t1=(h+((rr(e,6)^rr(e,11)^rr(e,25))>>>0)+((g^(e&(f^g)))>>>0)+k+w[i])>>>0;
            var t2=(((rr(a,2)^rr(a,13)^rr(a,22))>>>0)+(((a&b)|(c&(a|b)))>>>0))>>>0;
            h=g;g=f;f=e;e=(d+t1)>>>0;d=c;c=b;b=a;a=(t1+t2)>>>0;
        }
        return [a,b,c,d,e,f,g,h];
    }
    function sum(a,b) { return a.map(function(x,i){return (x+b[i])>>>0;}); }
    var seconds=Math.floor((Date.now()/1000+11644473600)/300)*300;
    var text=String(BigInt(seconds)*BigInt(10000000))+TRUSTED_CLIENT_TOKEN;
    var data=Array.prototype.map.call(text,function(x){return x.charCodeAt(0);});
    function be(bytes,p) { return ((bytes[p]<<24)|(bytes[p+1]<<16)|(bytes[p+2]<<8)|bytes[p+3])>>>0; }
    function le(bytes,p) { return ((bytes[p]||0)|((bytes[p+1]||0)<<8)|((bytes[p+2]||0)<<16)|((bytes[p+3]||0)<<24))>>>0; }
    var w=Array(14).fill(0);
    w.push((data[0]<<16)|(data[1]<<8)|data[2]);w.push(be(data,3));
    for(var i=16;i<30;i++) {
        var v=C.schedule[i-16];
        if(i-2>=14) v+=i===16?(s1(w[i-2])^0x000B92C0)>>>0:s1(w[i-2]);
        if(i-7>=14) v+=w[i-7];
        if(i-15>=14) v+=i===29?(s0(w[i-15])^0x059C0B80)>>>0:s0(w[i-15]);
        w.push(v>>>0);
    }
    w.push((s1(w[28])+w[23]+s0(w[15])+w[14]+C.adjustment-C.rounds[14])>>>0);
    expand(w,31);
    var state=sum(C.initial,rounds(C.state,w,14));
    var length=57+data.length,padded=data.slice(7);padded.push(128);
    var zeroes=((55-length)%64+64)%64;
    while(zeroes-->0)padded.push(0);
    var bits=length*8;
    padded.push(0,0,0,0,(bits>>>24)&255,(bits>>>16)&255,(bits>>>8)&255,bits&255);
    for(var p=0;p<padded.length;p+=64) {
        w=[];for(var j=0;j<16;j++)w.push(be(padded,p+j*4));
        expand(w,16);state=sum(state,rounds(state,w,0));
    }
    var digest=[];
    state.forEach(function(v){digest.push(v>>>24,(v>>>16)&255,(v>>>8)&255,v&255);});
    var keyA=(le(digest,0)|1)>>>0,keyB=(le(digest,4)|1)>>>0;
    var factors=[Math.imul(keyA,0x82893933)>>>0,Math.imul(keyB,0x82893933)>>>0];
    var terms=[],offsets=[];
    C.coefficients.forEach(function(pair,i){terms.push(Math.imul(pair[0],factors[i%2])>>>0);offsets.push(pair[1]);});
    var wordsData=[0].concat(data);
    var count=Math.ceil(wordsData.length/4);if(count%2)count++;
    for(i=0;i<count;i++) {
        var word=le(wordsData,i*4),term=Math.imul(word,i%2?keyB:keyA),offset=Math.imul(rol(word),i%2?0xC31713DB:0xEF0569FB);
        if(i===0){term+=Math.imul(0xF2F90B1A,factors[0]);offset+=0x0B1A0000;}
        terms.push(term>>>0);offsets.push(offset>>>0);
    }
    var swapAcc=0,swapLast=0,csState=0,acc=0,t,q;
    for(i=0;i<terms.length;i+=2) {
        var x=terms[i],y=terms[i+1];
        t=rol((offsets[i]+x)>>>0);q=Math.imul(t,0x76F50F34)>>>0;
        swapAcc+=(Math.imul(rol(q),0xC3EFEA97)+q)>>>0;
        t=rol((offsets[i+1]+y)>>>0);q=Math.imul(t,0x1881CE3C)>>>0;
        swapLast=(Math.imul(rol(q),0x35BD1EC9)+q)>>>0;swapAcc=(swapAcc+swapLast)>>>0;
        csState=(Math.imul(csState,keyA)+x)>>>0;
        [0xCF98B111,0x87085B9F,0x12CEB96D,0x257E1D83].forEach(function(k){csState=Math.imul(rol(csState),k)>>>0;});
        acc+=csState;t=(Math.imul(csState,keyB)+y)>>>0;
        t=Math.imul(rol(t),0xA27416F5)>>>0;t=Math.imul(rol(t),0xD38396FF)>>>0;
        csState=Math.imul(rol(Math.imul(rol(t),0x7C932B89)>>>0),0xBFA49F69)>>>0;
        acc=(acc+csState)>>>0;
    }
    function hex(bytes){return bytes.map(function(v){return ('0'+v.toString(16)).slice(-2);}).join('').toUpperCase();}
    var cs=[];
    [(swapLast^csState)>>>0,(swapAcc^acc)>>>0].forEach(function(v){cs.push(v&255,(v>>>8)&255,(v>>>16)&255,v>>>24);});
    return hex(cs)+'-'+hex(digest);
}

```

### 说明

- 时间按 5 分钟窗口取整。
- `BigInt` 保证 Windows 时间刻度计算精确。
- `Math.imul()` 和 `>>> 0` 保证 32 位整数计算与参考实现一致。
- 新版签名包含定制 SHA-256 与 CS64，不能用普通 `CryptoJS.SHA256()` 直接替代。
- 输出格式为 `<16位大写十六进制>-<64位大写十六进制>`。

## 三、修改协议版本号

在 `ensureSocketReady()` 中找到：

```javascript
const Sec_MS_GEC_VERSION = "1-130.0.2849.68";

```

改为：

```javascript
const Sec_MS_GEC_VERSION = "2-143.0.3650.75";

```

修改后的连接部分应保留如下结构：

```javascript
const Sec_MS_GEC = generateSecMsGecToken();
const Sec_MS_GEC_VERSION = "2-143.0.3650.75";

socket = new WebSocket(
    `${SYNTH_URL}&Sec-MS-GEC=${Sec_MS_GEC}&Sec-MS-GEC-Version=${Sec_MS_GEC_VERSION}`
);

```

## 四、保留原公共代理地址

本次修复不需要切换代理。原配置保持：

```javascript
const TRUSTED_CLIENT_TOKEN = "6A5AA1D4EAFF4E9FB37E23D68491D6F4";
const SYNTH_URL = `wss://public.fanqi987.dpdns.org/public/wss/speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1?TrustedClientToken=${TRUSTED_CLIENT_TOKEN}`;

```

这里的 `TRUSTED_CLIENT_TOKEN` 是客户端使用的固定协议常量，不是用户私人 API Key。不要把自建代理的私人访问令牌写进公开教程。

原有的 CryptoJS 加载代码可以保留，不要顺带删除其他依赖。

## 五、保存与检查

1. 保存 `oald.js`，确保文件名和词典原来引用的一致。
2. 如可使用 Node.js，检查语法：

```bash
node --check oald.js

```

1. 完全退出欧路词典并重新打开，避免旧脚本缓存。
2. 找到支持在线 TTS 的例句，分别点击英音与美音喇叭。
3. 再点第二条例句，检查连续请求是否正常。

**无需重新打包 MDX/MDD，也不需要修改 CSS。** 本教程针对词典已从外部加载该 `oald.js` 的部署方式；若使用其他封装方式，需要先确认实际加载的脚本位置。

## 六、本次验证结果与边界

- 签名算法：108 组 Python / JavaScript 时间戳对照结果一致。
- Minis WebKit：实际 OALD10 TTS 函数经原公共代理合成成功。
- 英音 Ryan：返回 31,798 字节音频。
- 美音 Jenny：返回 19,990 字节音频，同一连接复用成功。
- 浏览器测试对 `play()` 使用测试替身，验证了真实联网合成和原音频解析， **不等同于欧路真机已实际发声** 。最终播放效果需在欧路内确认。

## 七、排错与回滚

### 仍无法朗读

- 确认完整替换了函数，而不是只改版本号。
- 确认没有粘贴 Markdown 的三反引号到 JS 文件中。
- 确认欧路加载的是修改后的 `oald.js`，而不是同名旧副本。
- 检查设备日期和时间；签名依赖当前时间。
- 公共代理、网络或微软上游故障也会造成失败，不能仅凭“无法播放”认定签名错误。

### 回滚

用备份的原脚本恢复 `oald.js`，完全退出欧路后重开即可。注意：回滚只撤销修改，不保证旧签名仍能被微软接受。

---

<div class="post-metadata">

作者： ![goodman168](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/g/22d042/32.png) [@goodman168](https://forum.freemdict.com/u/goodman168)\
发布日期： [2026 年10 月 16 日 09:26 UTC](https://forum.freemdict.com/t/topic/42406/62 "2026-10-16T09:26:23Z")

</div>

大神，牛！目前可用。

---

<div class="post-metadata">

作者： ![naisme](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/n/ac91a4/32.png) [@naisme](https://forum.freemdict.com/u/naisme)\
发布日期： [2026 年10 月 16 日 09:29 UTC](https://forum.freemdict.com/t/topic/42406/63 "2026-10-16T09:29:25Z")

</div>

感觉又到折腾没底的模式了，试了这方法，还是没效果。

在原来的js代理换成收费的，其他未变，马上就OK，侧面证明同这个关系不大

[上一页](https://forum.freemdict.com/t/topic/42406.md?page=2)

[下一页](https://forum.freemdict.com/t/topic/42406.md?page=4)
