[ { "isEnabled": true, "version": 4, "name": "豆包修复版", "pluginId": "doubao.com", "author": "TTS Server", "iconUrl": "https://lf-flow-web-cdn.doubao.com/obj/flow-doubao/doubao/web/logo-icon.png", "code": "let cookie = ttsrv.userVars['cookie']\n\n\nlet req = {}\nvar callback = null\nlet ws = null // Websocket\n\nfunction check() {\n cookie || function () { throw \"未设置变量Cookie\" }()\n}\n\nfunction id() {\n const num1 = Math.floor(1e8 + 9e8 * Math.random());\n const num2 = Math.floor(1e8 + 9e8 * Math.random());\n return String(num1) + String(num2);\n}\n\nvar count = 0\nvar currentId = id()\nfunction commonParams() {\n count++\n if (commonParams > 5) {\n count = 0\n currentId = id()\n }\n return `&mode=0&language=zh&browser_language=zh-CN&device_platform=web&aid=586861&real_aid=586861&pkg_type=release_version&device_id=${currentId}&tea_uuid=${currentId}&web_id=${currentId}&is_new_user=0®ion=CN&sys_region=CN&use-olympus-account=1&samantha_web=1&version=1.20.1&version_code=20800&pc_version=1.20.1`\n}\n\nlet PluginJS = {\n \"name\": \"豆包修复版\",\n \"id\": \"doubao.com\",\n \"author\": \"TTS Server\",\n \"version\": 4,\n 'iconUrl': `https://lf-flow-web-cdn.doubao.com/obj/flow-doubao/doubao/web/logo-icon.png`,\n 'vars': {\n cookie: { label: \"Cookie\", hint: \"完整的请求头Cookie\", loginUrl: 'https://www.doubao.com/chat', binding: 'cookies', ua: \"mobile\" },\n },\n\n \"onStop\": function () {\n if (ws != null) {\n ws.cancel()\n }\n },\n\n\n \"getAudioV2\": function (request, callback2) {\n check()\n\n let rate = (request.rate * 2) - 100\n let pitch = request.pitch - 50\n // let volume = request.volume\n\n callback = callback2\n text = request.text\n speaker = request.voice\n\n req = {\n 'text': text,\n 'speaker': speaker,\n 'rate': rate,\n 'pitch': pitch,\n }\n\n getAudio()\n },\n}\n\nfunction getAudio() {\n if (ws == null) {\n logger.i(\"init Websocket\")\n let url = `wss://ws-samantha.doubao.com/samantha/audio/tts?format=aac&speaker=${req.speaker}&speech_rate=${req.rate}&pitch=${req.pitch}` + commonParams()\n let headers = {\n \"Cookie\": cookie,\n \"Origin\": \"chrome-extension://capohkkfagimodmlpnahjoijgoocdjhd\",\n \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/133.0.0.0\"\n }\n ws = new Websocket(url, headers)\n\n ws.on('close', function (code, reason) {\n ws = null\n if (code == 1000) {\n callback.close()\n } else {\n callback.error(reason)\n }\n })\n\n\n ws.on('error', function (err, resp) {\n ws = null\n console.error(resp.text())\n callback.error(err)\n })\n\n ws.on('binary', function (buffer) {\n // logger.d(buffer)\n callback.write(buffer)\n })\n\n ws.on('text', function (msg) {\n console.log(msg)\n })\n\n ws.on('open', function () {\n logger.d(\"open\")\n getAudio()\n })\n\n return\n }\n\n if (ws.readyState = Websocket.OPEN) {\n sendMessage()\n } else {\n ws = null\n return getAudio()\n }\n function sendMessage() {\n logger.i(\"sendMessage....\")\n send(`{\"event\":\"text\",\"podcast_extra\":{\"role\":\"\"},\"text\":\"${req.text}\"}`)\n send(`{\"event\":\"finish\"}`)\n }\n\n\n function send(msg) {\n let ok = ws.send(msg)\n if (!ok) {\n callback.error(\"send message failed: \" + msg)\n }\n }\n}\n\n\nlet locales = []\nlet voices = []\nlet EditorJS = {\n \"getAudioSampleRate\": function (locale, voice) {\n return 24000\n },\n\n \"getLocales\": function () {\n return locales\n },\n\n \"getVoices\": function (locale) {\n let mm = new Map()\n voices.forEach(v => {\n let tag = v.tag_list.map(t => t.tag_value).join(\"|\")\n mm[v.style_id] = {\n name: v.name + \" \" + tag,\n iconUrl: v.icon.url\n }\n });\n\n\n return mm\n },\n\n // 加载本地或网络数据,运行在IO线程。\n \"onLoadData\": function () {\n check()\n let url = `https://www.doubao.com/alice/user_voice/recommend?language=zh&browser_language=zh-CN&mode=0&language=zh&browser_language=zh-CN&device_platform=web&aid=586861&real_aid=586861&pkg_type=release_version&device_id=${currentId}&tea_uuid=${currentId}&web_id=${currentId}&is_new_user=0®ion=CN&sys_region=CN&use-olympus-account=1&samantha_web=1&version=1.20.1&version_code=20800&pc_version=1.20.1`\n let headers = {\n \"Cookie\": cookie,\n \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/133.0.0.0\"\n }\n\n function load(type, tab) {\n function verify(data) {\n if (data.code != 0) {\n throw '获取失败(请尝试清缓存): ' + data.msg\n }\n }\n\n let filename = `voices_${type}_${tab}.json`\n let data= null \n if (fs.exists(filename)) {\n data = JSON.parse(fs.readText(filename))\n verify(data)\n } else {\n let body = `{\"page_index\":1,\"page_size\":200,\"recommend_type\":${type},\"tab_key\": \"${tab}\"}`\n console.log(body)\n txt = http.post(url, body, headers).text()\n data = JSON.parse(txt)\n verify(data)\n fs.writeFile(filename, txt)\n }\n\n data.data.ugc_voice_list.forEach(v => {\n voices.push(v)\n console.log(voices[voices.length - 1].name)\n\n locales.includes(v.language_code) || locales.push(v.language_code)\n })\n }\n\n\n load(1, \"\")\n load(10, \"female\")\n load(10, \"male\")\n load(10, \"characters\")\n load(10, \"accent\")\n },\n\n \"onLoadUI\": function (ctx, linerLayout) {\n\n },\n\n \"onVoiceChanged\": function (locale, voiceCode) {\n\n }\n\n}", "defVars": { "cookie": { "label": "Cookie", "hint": "完整的请求头Cookie", "loginUrl": "https://www.doubao.com/chat", "binding": "cookies", "ua": "mobile" } }, "order": 47 } ]