├── README.md ├── donate.png └── ncm.js /README.md: -------------------------------------------------------------------------------- 1 | # Some-js-scripts-for-FB2K 2 | 3 | ## ncm.js 4 | 5 | FB2K ESLyric 下的能获取网易云音乐歌词并进行一些处理的脚本 6 | 7 | - 2020-08-13 8 | - [x] 修复了无法找到部分同名歌曲的问题 9 | - 2020-08-27 10 | - [x] 更新了曲名后缀去除内容 11 | - [x] 更改了艺术家字段匹配方式(多人) 12 | - [x] 加了点注释 13 | - 2020-08-28 14 | - [x] 修复了「Cover」改「翻自」搜不到的问题 15 | - [x] 简化部分结构 16 | - 2020-09-04 17 | - [x] 增加了时长匹配功能 18 | - 2020-09-05 19 | - [x] 重构了 lrc 解析方式,解决多种时间戳格式混用导致的问题 20 | - [x] 重构了合并方式,并(可能)修复了一些问题 21 | - 2020-09-06 22 | - [x] 修复了第一个匹配到的歌曲没有歌词(就不继续找)的问题 23 | - [x] 修复了模糊搜索结果可能无法显示的问题 24 | - [x] 修复了 ` ` (`\xa0`) 影响匹配度的的问题 25 | - 2020-09-09 26 | - [x] 更新了曲名后缀去除内容 27 | - [x] 修复了 ESLyric 自动去掉歌名里括号部分,从而影响匹配度的的问题 28 | - [x] 支持选择多个歌曲版本 29 | - [x] 优化了部分情况下歌词标题的形式 30 | - [x] 由于 0.3.6 版本的 ESLyric 支持 JSON,所以去除 polyfill 31 | - [x] 替换简繁转换方法 32 | - [x] 简化部分结构 33 | 34 | 使用说明: 35 | 36 | 先放个[别人的教程](https://elia-is-me.github.io/2016/02-18-an-introduction-to-eslyric/)吧,有空再写。 37 | 38 | 用户设置的参数可以微调。 39 | 40 | ### 一些问题解答 41 | 42 | 1. 目前网易云 VIP 歌曲是能获取到歌词的;变灰的歌没有歌词,可能是因为搜索结果被放在了最后从而没有匹配到。 43 | 44 | 2. 重构的并排合并卡拉 OK 模式 `same_line_k` 没有测试在其他(软件/插件)歌词显示的效果。 45 | 46 | 3. 当曲名有较大的变动时,可能需要将 ESLyric 设置里的歌词匹配度(Lyric Matching Level)适当降低。 47 | 48 | - 明明有歌词却无法匹配的话,可以开个 issue。 49 | 50 | ## cover.js 51 | 52 | 有空重写一下下。 53 | 54 | ## 打赏嘛 55 | 56 | ![](https://raw.githubusercontent.com/xiaopc/Some-js-script-for-FB2K/master/donate.png) 57 | -------------------------------------------------------------------------------- /donate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaopc/Some-js-script-for-FB2K/29f92436c8ffedce50468c9321408bfaa346c9cb/donate.png -------------------------------------------------------------------------------- /ncm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by cimoc on 2016/12/23 3 | * Modified by xiaopc on 2020/08/27 4 | * Netease Cloud Music Lyric Source For ESLyric 5 | * version : 0.1.3 6 | * 感谢 ChowDPa02K,Jeannela\Elia, 不知名的的api提供者 7 | * 页面 : https://github.com/cimoc-sokka/Some-js-script-for-FB2K 8 | * 下载 : https://github.com/cimoc-sokka/Some-js-script-for-FB2K/releases 9 | * cimoc的邮箱 : cimoc@sokka.cn 10 | */ 11 | 12 | /** 13 | * 用户设置部分 14 | */ 15 | 16 | // - 歌词显示 17 | 18 | // 歌词输出顺序,删除即不获取 19 | // same_line: 并排合并歌词 20 | // new_line: 翻译在下一行,仿网易云 21 | // tran: 翻译 22 | // origin: 原文 23 | // same_line_k: 并排合并歌词,在卡拉OK模式下仅高亮原语言歌词(其他模式会出现显示问题) 24 | // 不推荐使用,仅能即时获取歌词即时使用,不能保存 25 | var lrc_order = [ 26 | "new_line", 27 | "same_line", 28 | "same_line_k", 29 | "origin", 30 | "tran", 31 | ]; 32 | 33 | // new_line 翻译滚动时长 以及 same_line_k 翻译时间轴滞后时长 34 | // (秒),设为 0 则取消,如果翻译歌词跳得快,酌情设为 0.4-1.0 35 | var savefix = 0.01; 36 | 37 | // new_line 最后一句时长(秒) 38 | var new_line_last = 10; 39 | 40 | // 翻译外括号,可以为空 41 | // 括号示例:〔 〕〈 〉《 》「 」『 』〖 〗【 】( ) [ ] { } 42 | // 如果都为空的话,same_line 下原文与翻译没有间隔 43 | var bracket = [ 44 | ' ', // 左括号 45 | '' // 右括号 46 | ]; 47 | 48 | // 要从翻译中删除的括号 49 | var bracket_rm = /(〔|〕|〈|〉|《|》|「|」|『|』|〖|〗|【|】|{|}|\/)/g; 50 | 51 | // 去除空行 52 | // 在 new_line 时,若空行时间不准确,空行会导致歌词提前消失 53 | var rm_empty = false; 54 | 55 | // - 搜索 56 | 57 | // 搜索请求返回的最多结果数,如果经常搜不到试着改小或改大 58 | var limit = 5; 59 | 60 | // 去除标题附加内容 61 | var rm_suffix = [ 62 | "feat.", 63 | "Featuring", 64 | "(Cover", 65 | "(cover", 66 | "(翻自", 67 | ] 68 | 69 | // 开启简繁转换 70 | // 由于 ESLyric 会将繁体歌曲信息转为简体去搜索,这会导致匹配不上等问题 71 | // 「本程式使用了繁化姬的 API 服務」,「繁化姬商用必須付費」。https://zhconvert.org/ 72 | // 由于连接速度等问题,开启后可能会降低歌词搜索速度,酌情开启 73 | var trad_to_simp = false; 74 | 75 | // 与网易云标题对比时,去除半角括号/全角括号中的内容 76 | // 分别为半角和全角的开关,若不需要可改为 false 77 | // ESLyric 在搜索时好像会去除本地曲名中半角括号的部分,这会导致匹配度计算出现问题 78 | // 去除全角括号仅对网易云添加了()内容的曲名有帮助,酌情开启 79 | var title_bracket = [true, true]; 80 | 81 | // 最小准确匹配度,分别为标题和艺术家字段 82 | var min_exact_matching = [85, 70]; 83 | 84 | // 最小模糊匹配度 85 | // 模糊匹配:不考虑艺术家字段 86 | var min_fuzzy_matching = 80; 87 | 88 | // 匹配曲目时长误差率 89 | // 如本地曲目时长 3 分钟,误差率为 10%,则仅匹配时长在 3 分 ± 18s 的在线曲目 90 | // 小于 0 则不使用这条规则 91 | var length_error_rate = 15; 92 | 93 | // 输出调试信息 94 | var debug = true; 95 | 96 | /** 97 | * 插件定义部分 98 | */ 99 | 100 | var xmlHttp = new ActiveXObject("WinHttp.WinHttpRequest.5.1"); 101 | 102 | var headers = { 103 | "Origin": "https://music.163.com", 104 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) (KHTML, like Gecko) Chrome/55.0.2919.83 Safari/537.36", 105 | "Referer": "https://music.163.com/search/" 106 | } 107 | // "Content-Type": "application/x-www-form-urlencoded", 108 | 109 | function get_my_name() { 110 | return "网易云音乐"; 111 | } 112 | 113 | function get_version() { 114 | return "0.1.3"; 115 | } 116 | 117 | function get_author() { 118 | return "cimoc & wwh1004"; 119 | } 120 | 121 | /** 122 | * 面向 ESLyric 的搜索实现 123 | * @param Object info 歌曲信息,Title& Artist 124 | * @param {*} callback 回调函数 125 | */ 126 | 127 | function start_search(info, callback) { 128 | debug && console( 129 | "info.Title: " + info.Title + "\n" + 130 | "info.Artist: " + info.Artist + "\n" + 131 | "info.Length:" + info.Length); 132 | // 删除冗余内容 133 | var title = del(info.Title, rm_suffix); 134 | var artist = del(info.Artist, rm_suffix); 135 | debug && console("search_title: " + title + "\n" + "search_artist: " + artist); 136 | // 搜索语句 137 | var s = title + " " + (artist ? artist : ""); 138 | // searchURL = "http://music.163.com/api/search/get/web?csrf_token=";//如果下面的没用,试试改成这句 139 | var searchURL = "https://music.163.com/api/search/get/"; 140 | var post_data = 'hlpretag=&hlposttag=&s=' + encodeURIComponent(s) + '&type=1&offset=0&total=true&limit=' + limit; 141 | ncm_back = request("POST", searchURL, headers, post_data); 142 | // 先转简体 143 | if (trad_to_simp) ncm_back = zhconvert(ncm_back, "Simplified"); 144 | // parse 返回 json 145 | var ncm_back = json(ncm_back); 146 | var result = ncm_back.result; 147 | if (ncm_back.code != 200 || !result || !result.songs.length) { 148 | debug && console("get info failed"); 149 | return; 150 | } 151 | // 筛选曲名及艺术家 152 | var songs = result.songs; 153 | var times = 0; // 第一遍精确搜索,第二遍模糊搜索 154 | var songid = -1; 155 | var fetchlyric = [null, null]; 156 | var p0, p1; 157 | var found_action = function () { 158 | // 处理歌曲基础信息 159 | var res_name = info.Title; // 必须要完整包括搜索的曲名才能添加? 160 | if (info.Title != songs[songid].name) res_name += songs[songid].name.replace(title, ""); 161 | var res_album = songs[songid].album.name; 162 | var res_artist; 163 | if (times > 0) res_artist = info.Artist + '(原) - ' + songs[songid].artist_combine; // 必须要完整包括搜索的艺术家才能添加? 164 | else if (times == 0 && p1 > 99) res_artist = info.Artist; // 顺序相反可能导致无法添加 165 | else res_artist = songs[songid].artist_combine; 166 | debug && console("selected #" + songs[songid].id + ": " + res_name + "-" + res_artist); 167 | insert_lyric(callback, fetchlyric, [res_name, res_artist, res_album]); 168 | }; 169 | // 获取匹配歌曲,先精确后模糊 170 | while (times < 2 && songid < 0) { 171 | for (var k in songs) { 172 | var ncm_name = songs[k].name; 173 | // 去除曲名中的后缀 174 | cmp_name = del(ncm_name, rm_suffix); 175 | cmp_name = cmp_name.replace(/\xa0/g, ' '); 176 | // 如果搜索关键词不含括号,而搜索结果含,则去除括号部分 177 | if (title_bracket[0] && title.indexOf('(') < 0 && cmp_name.indexOf('(') >= 0) 178 | cmp_name = cmp_name.replace(/\(.*\)/g, ''); 179 | if (title_bracket[1] && title.indexOf('(') < 0 && cmp_name.indexOf('(') >= 0) 180 | cmp_name = cmp_name.replace(/(.*)/g, ''); 181 | // 匹配曲名 182 | p0 = compare(title, cmp_name); 183 | debug && console("ncm_title: " + ncm_name + " match: " + p0); 184 | // 匹配时长 185 | var length_diff = Math.abs(songs[k].duration / 1000 - info.Length) / info.Length; 186 | debug && console("duration: " + songs[k].duration / 1000 + "s, delta: " + length_diff); 187 | if (length_error_rate > 0 && length_diff > length_error_rate / 100) 188 | continue; 189 | // 模糊匹配 190 | if (times > 0) { 191 | if (p0 >= min_fuzzy_matching && (fetchlyric = get_lyric_from_id(songs[k].id))[0] != null) { // 同时获取歌曲对应歌词 192 | songid = k; 193 | found_action(); 194 | } 195 | continue; 196 | } 197 | // 精确匹配之匹配艺术家 198 | var artist_combine = []; 199 | // 合并艺术家信息 200 | for (var key in songs[k].artists) { 201 | artist_combine.push(songs[k].artists[key].name); 202 | } 203 | songs[k].artist_combine = artist_combine.join("/"); 204 | // 匹配艺术家 205 | p1 = compare(artist, songs[k].artist_combine); 206 | debug && console("ncm_artist: " + songs[k].artist_combine + " match: " + p1); 207 | if (p0 >= min_exact_matching[0] && p1 >= min_exact_matching[1] && (fetchlyric = get_lyric_from_id(songs[k].id))[0] != null) { 208 | songid = k; 209 | found_action(); 210 | } 211 | } 212 | times++; 213 | debug && console(times + "# search finished"); 214 | } 215 | } 216 | 217 | /** 218 | * 插入歌词 219 | * @param {*} callback 220 | * @param Array fetchlyric [string | null, string | null] 221 | * @param Array info [res_name, res_artist, res_album] 222 | */ 223 | 224 | function insert_lyric(callback, fetchlyric, info) { 225 | var newLyric = callback.CreateLyric(); 226 | // 顺序默认值 227 | lrc_order = lrc_order || ["same_line_k", "new_line", "origin", "tran"]; 228 | for (var key in lrc_order) { 229 | newLyric.Title = info[0]; 230 | newLyric.Artist = info[1]; 231 | newLyric.Album = info[2]; 232 | switch (lrc_order[key]) { 233 | case "origin": 234 | if (fetchlyric[0]) { 235 | newLyric.LyricText = fetchlyric[0]; 236 | newLyric.Source = "(原词)" + get_my_name(); 237 | callback.AddLyric(newLyric); 238 | } 239 | break; 240 | case "tran": 241 | if (fetchlyric[1]) { 242 | newLyric.LyricText = fetchlyric[1]; 243 | newLyric.Source = "(翻译)" + get_my_name(); 244 | callback.AddLyric(newLyric); 245 | } 246 | break; 247 | case "same_line_k": 248 | if (fetchlyric[0] && fetchlyric[1]) { 249 | newLyric.LyricText = lrc_merge_same_line_k(fetchlyric[0], fetchlyric[1]); 250 | newLyric.Source = "(并排β)" + get_my_name(); 251 | callback.AddLyric(newLyric); 252 | } 253 | break; 254 | case "new_line": 255 | if (fetchlyric[0] && fetchlyric[1]) { 256 | newLyric.LyricText = lrc_merge_new_line(fetchlyric[0], fetchlyric[1]); 257 | newLyric.Source = "(并列)" + get_my_name(); 258 | callback.AddLyric(newLyric); 259 | } 260 | break; 261 | case "same_line": 262 | if (fetchlyric[0] && fetchlyric[1]) { 263 | newLyric.LyricText = lrc_merge_same_line(fetchlyric[0], fetchlyric[1]); 264 | newLyric.Source = "(并排)" + get_my_name(); 265 | callback.AddLyric(newLyric); 266 | } 267 | break; 268 | } 269 | } 270 | newLyric.Dispose(); 271 | } 272 | 273 | /** 274 | * 获取歌曲对应歌词 275 | * @param Number id 276 | */ 277 | function get_lyric_from_id(id) { 278 | var lyricURL = "https://music.163.com/api/song/lyric?os=pc&id=" + id + "&lv=-1&kv=-1&tv=-1"; 279 | var ncm_lrc = json(request("GET", lyricURL, { "Cookie": "appver=1.5.0.75771" })); 280 | // (原语言)歌词 281 | var lyric = null; 282 | if (ncm_lrc.lrc && ncm_lrc.lrc.lyric) 283 | lyric = ncm_lrc.lrc.lyric; 284 | else 285 | debug && console("no (original) lyric"); 286 | // 翻译歌词 287 | var translrc = null; 288 | if (ncm_lrc.tlyric && ncm_lrc.tlyric.lyric) { 289 | translrc = ncm_lrc.tlyric.lyric; 290 | translrc = translrc.replace(bracket_rm, ""); 291 | } else debug && console("no translation"); 292 | return [lyric, translrc]; 293 | } 294 | 295 | /** 296 | * 歌词处理 297 | */ 298 | 299 | /** 300 | * 分析时间轴并重排,返回 [ {time: string, time_ms: [毫秒, ...], text: ...}, ] 301 | * @param String lrc 302 | */ 303 | 304 | function lrc_timeline(lrc) { 305 | // TODO: by 这些标记信息(好像网易云现在都没这部分? 306 | lines = lrc.split("\n"); 307 | objs = [] 308 | for (var i in lines) { 309 | // 分别为: 全部内容,所有时间戳,正文 310 | var parts = /((?:\[(?:\d|\.|\:)*\])+)(.*)/g.exec(lines[i]); 311 | if (parts == null || parts.length < 3) continue; 312 | var times = timestamp_parser(parts[1]); 313 | // 处理非时间戳情况 314 | if (times.length == 0) { 315 | // TODO 316 | continue; 317 | } 318 | for (var j in times) { 319 | objs.push({ time: times[j][0], time_ms: timestamp_to_ms(times[j]), text: parts[2] }); 320 | } 321 | } 322 | var cmp = function (a, b) { 323 | return a.time_ms - b.time_ms; 324 | } 325 | return objs.sort(cmp); 326 | } 327 | 328 | /** 329 | * 将(可含多个)时间戳 string 转为 [[原串, mm, ss, (毫秒)], ...] 330 | * @param String str 331 | */ 332 | 333 | function timestamp_parser(str) { 334 | var regex = /\[(\d{2}):(\d{2})(\.\d{2,3})?\]/g; 335 | var lis = [], find = null; 336 | while ((find = regex.exec(str)) != null) lis.push(find); 337 | return lis; 338 | } 339 | 340 | /** 341 | * 将 [原串, mm, ss, (毫秒)] 转为毫秒数 342 | * @param Array arr 343 | */ 344 | 345 | function timestamp_to_ms(arr) { 346 | return Number(arr[1]) * 60000 + Number(arr[2]) * 1000 + (arr.length > 3 ? Number(arr[3].substr(1)) * Math.pow(10, (4 - arr[3].length)) : 0); 347 | } 348 | 349 | function num_pad(num, length) { 350 | length = length || 2; 351 | return (Array(length).join("0") + Math.floor(num)).slice(-length); 352 | } 353 | 354 | function timestamp_to_str(t) { 355 | return '[' + num_pad(t / 60000) + ':' + num_pad(t % 60000 / 1000) + '.' + num_pad(t % 1000 / 10) + ']'; 356 | } 357 | 358 | /** 359 | * same_line 同行合并 360 | * @param String olrc 361 | * @param String tlrc 362 | */ 363 | 364 | function lrc_merge_same_line(olrc, tlrc) { 365 | var olrc = lrc_timeline(olrc), tlrc = lrc_timeline(tlrc), lrc = []; 366 | var i = 0, j = 0; 367 | while (i < olrc.length && j < tlrc.length) { 368 | var cmp = olrc[i].time_ms - tlrc[j].time_ms; 369 | if (cmp == 0) { 370 | if (!rm_empty || olrc[i].text != '') 371 | lrc.push(olrc[i].time + olrc[i].text + bracket[0] + tlrc[j].text + bracket[1]); 372 | i++; j++; 373 | } else if (cmp < 0) { 374 | if (!rm_empty || olrc[i].text != '') 375 | lrc.push(olrc[i].time + olrc[i].text); 376 | i++; 377 | } else { 378 | j++; 379 | debug && console('unsynced translation:' + tlrc[j].time + tlrc[j].text); 380 | } 381 | } 382 | return lrc.join("\n"); 383 | } 384 | 385 | /** 386 | * new_line 将翻译添加到下一句原文前 savefix 时长处 387 | * @param String olrc 388 | * @param String tlrc 389 | */ 390 | 391 | function lrc_merge_new_line(olrc, tlrc) { 392 | var olrc = lrc_timeline(olrc), tlrc = lrc_timeline(tlrc), lrc = []; 393 | var i = 0, j = 0; 394 | while (i < olrc.length && j < tlrc.length) { 395 | var t_time = timestamp_to_str((i + 1 < olrc.length) ? olrc[i + 1].time_ms - savefix * 1000 : olrc[i].time_ms + new_line_last * 1000); 396 | var cmp = olrc[i].time_ms - tlrc[j].time_ms; 397 | if (cmp <= 0) { 398 | if (!rm_empty || olrc[i].text != '') { 399 | lrc.push(timestamp_to_str(olrc[i].time_ms) + olrc[i].text); 400 | lrc.push(t_time + ((cmp == 0) ? bracket[0] + tlrc[j].text + bracket[1] : '')); 401 | } 402 | i++; (cmp == 0) && j++; 403 | } else { 404 | j++; 405 | debug && console('unsynced translation:' + tlrc[j].time + tlrc[j].text); 406 | } 407 | } 408 | return lrc.join("\n"); 409 | } 410 | 411 | /** 412 | * same_line_k 将翻译带时间轴添加到原文后面(同一行) 413 | * @param String olrc 414 | * @param String tlrc 415 | */ 416 | 417 | function lrc_merge_same_line_k(olrc, tlrc) { 418 | var olrc = lrc_timeline(olrc), tlrc = lrc_timeline(tlrc), lrc = []; 419 | var i = 0, j = 0; 420 | while (i < olrc.length && j < tlrc.length) { 421 | var t_time = timestamp_to_str((i + 1 < olrc.length) ? olrc[i + 1].time_ms - savefix * 1000 : olrc[i].time_ms + new_line_last * 1000); 422 | var cmp = olrc[i].time_ms - tlrc[j].time_ms; 423 | if (cmp == 0) { 424 | if (!rm_empty || olrc[i].text != '') 425 | lrc.push(timestamp_to_str(olrc[i].time_ms) + olrc[i].text + ' ' + t_time + bracket[0] + tlrc[j].text + bracket[1]); 426 | i++; j++; 427 | } else if (cmp < 0) { 428 | if (!rm_empty || olrc[i].text != '') 429 | lrc.push(timestamp_to_str(olrc[i].time_ms) + olrc[i].text); 430 | i++; 431 | } else { 432 | j++; 433 | debug && console('unsynced translation:' + tlrc[j].time + tlrc[j].text); 434 | } 435 | } 436 | return lrc.join("\n"); 437 | } 438 | 439 | /** 440 | * 辅助函数, 库或 polyfills 441 | */ 442 | 443 | /** 444 | * 输出控制台 445 | * @param String s 内容 446 | */ 447 | 448 | function console(s) { 449 | fb.trace("* lyric-js: " + s); 450 | } 451 | 452 | /** 453 | * 去除分隔符之后内容 454 | * @param String str 455 | * @param String del_arr 456 | */ 457 | 458 | function del(str, del_arr) { 459 | for (var i = 0; i < del_arr.length; i++) { 460 | str = str.split(del_arr[i])[0]; 461 | } 462 | return str 463 | } 464 | 465 | /** 466 | * 字符串匹配度,0-1 467 | * @param String x 468 | * @param String y 469 | */ 470 | 471 | function compare(x, y) { 472 | x = x.split(""); 473 | y = y.split(""); 474 | var z = 0; 475 | var s = x.length + y.length; 476 | 477 | x.sort(); 478 | y.sort(); 479 | var a = x.shift(); 480 | var b = y.shift(); 481 | 482 | while (a !== undefined && b !== undefined) { 483 | if (a === b) { 484 | z++; 485 | a = x.shift(); 486 | b = y.shift(); 487 | } else if (a < b) { 488 | a = x.shift(); 489 | } else if (a > b) { 490 | b = y.shift(); 491 | } 492 | } 493 | return z / s * 200; 494 | } 495 | 496 | /** 497 | * JSON 解析包装 498 | * @param {*} text 499 | */ 500 | 501 | function json(text) { 502 | try { 503 | var data = JSON.parse(text); 504 | return data; 505 | } catch (e) { 506 | return false; 507 | } 508 | } 509 | 510 | /** 511 | * xmlHttp 包装 512 | * @param String method “GET” “POST” 513 | * @param String url 514 | * @param {*} headers 515 | * @param String data 516 | */ 517 | 518 | function request(method, url, headers, data) { 519 | try { 520 | xmlHttp.Open(method, url, false); 521 | add_headers(headers, xmlHttp); 522 | if (method == "POST") { 523 | add_headers({ "Content-Type": "application/x-www-form-urlencoded" }, xmlHttp); 524 | xmlHttp.Send(data); 525 | } else { 526 | xmlHttp.Send(); 527 | } 528 | if (xmlHttp.Status != 200) throw 'HTTP.Status=' + xmlHttp.Status; 529 | } catch (e) { 530 | debug && console("request " + url + " failed: " + e); 531 | return; 532 | } 533 | return xmlHttp.responseText; 534 | } 535 | 536 | /** 537 | * 给 xmlhttp 加 header 538 | * @param {*} header 539 | * @param Object client 540 | */ 541 | 542 | function add_headers(header, client) { 543 | for (var i in header) { 544 | client.SetRequestHeader(i, header[i]); 545 | } 546 | } 547 | 548 | /** 549 | * 由「繁化姬」提供的转换服务,API 文档:https://docs.zhconvert.org/api/convert/ 550 | * @param String text 551 | * @param String converter: ‘Simplified’ 简体化,‘Traditional’ 繁体化 552 | */ 553 | 554 | function zhconvert(text, converter) { 555 | var post_data = 'converter=' + converter + '&text=' + encodeURIComponent(text); 556 | var response = json(request("POST", "https://api.zhconvert.org/convert", {}, post_data)); 557 | if (response.code != 0) { 558 | debug && console("zhconvert api: " + response.msg); 559 | return; 560 | } 561 | return response.data.text; 562 | } 563 | --------------------------------------------------------------------------------