Baidu Translate

Baidu translate api support for userscripts. No need for baidu's token.

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greatest.deepsurf.us/scripts/452362/1281581/Baidu%20Translate.js

  1. /* eslint-disable no-multi-spaces */
  2. /* eslint-disable no-return-assign */
  3.  
  4. /* eslint-disable curly */
  5. /* eslint-disable no-sequences */
  6.  
  7. // ==UserScript==
  8. // @name Baidu Translate
  9. // @name:zh-CN 百度翻译
  10. // @name:en Baidu Translate
  11. // @namespace PY-DNG APIS
  12. // @version 0.2.7
  13. // @description Baidu translate api support for userscripts. No need for baidu's token.
  14. // @description:zh-CN 用户脚本版的百度翻译API支持,无需申请token,@require即用
  15. // @description:en Baidu translate api support for userscripts. No need for baidu's token.
  16. // @author PY-DNG
  17. // @license MIT
  18. // @icon data:image/vnd.microsoft.icon;base64,AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPzbt074plC+9Y0e9PWIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1jR70+KZQvvzbuEwAAAAAAAAAAAAAAAD6wYWE9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//rBhYQAAAAA/Nu4TPWIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//zbuEz4plC+9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/+KZQvvaOIPL1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1jh/y9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/2kyr//vDh//vRpP/3okf/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//aRJv////////////7w4f/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/3oET//u/g//7v4P/2lCz/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9o8i/////////////vDh//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//ekS/////////////aWMP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/2jyL////////////96tb/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/96RL////////////9pYw//WIFP/1iBT/96NJ//ecO//2mDP/9pIn//WNHv////////////3q1v/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/3pEv////////////2ljD/9YgU//m5df////////////////////////////////////////v3//3n0P/948j//N/A//zdvf/817H//Nex//ixZP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//ekS/////////////aWMP/1iBT/9o8i//aYM//3n0L/96BD//elTf/4qFT////////////+8ub/+bt4//rAhP/7zJr//Ny5//3r2P/94sb/9Y0d//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/96RL////////////9pYw//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP////////////3s2f/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/3pEv////////////2ljD/9YgU//WIFP/2kCX/+saO//m9ff/5tWz/+Kxc/////////////vLl//aOIP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//ekS/////////////aWMP/1iBT/9YgU//rGjv/+7+D//vfu//748P////////////////////////////////////////////rHkP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/96RL////////////9pYw//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFf////////////727f/3okf/+KtZ//mzav/5tGv/9YgV//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/3pEv////////////2ljD/9po3//rGjv/4qlb/9Y4f//WIFP/1iBT/9YgU/////////////vjx//WIFP/1iBT/9pg0//m3cP/6x5D/9Y0d//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//ekS/////////////aWMP/1iBT/+KdS//3kyv///Pn//N6+//m1bf/2jyP//eXM//rEiv/2mjf/+bl0//3o0v/////////////////82rb/9Y0d//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/817H//Nex//zXsf/817H//OHD////////////9pYw//WIFP/1iBT/9YgU//irWv/969j///////758//6xYz/+bJn//7x5P/////////////////////////////////+7dz/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU///////////////////////////////////////2ljD/9YgU//WIFP/1iBT/9YgU//WKGP/5vHv///r1////////////////////////+fT//N28//rCh//4rFz/9po3//WLGv/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9pgz//aYM//2mDP/9pgz//aYM//2mDP/9pgz//WKGP/1iBT/9YgU//WIFP/1iBT/9YgU//WJF//83r7//////////////////eLF//WMHP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/+8uY///////+7t7//efP////////////+9Km//WJF//1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//irWv//////+9Wr//aOIP/2jiD//eXM////////////+86e//WIFf/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//rDiP/+9+///vfv//m2bv/1iBT/9YgU//WIFP/1jh///vLm//rJlf/1iBX/9YgU//WIFP/2kyn//vPn////////////+sWN//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/+seQ////////////+bl1//WIFP/2kCX//vLm//758////fv//efQ//zhxP/82bP/+9Gk//rJlP/82bT///////////////7//eLF//aXMv/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/6x5D////////////5uXX/9YgU//aYM//4sGL/+LBj//m4cv/5vHr/+sOJ//vLmP/70qb//Nm0//zfwP/+9Or////////////6xo//9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WMHP/2kCT/9pAk//WLGv/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WNHv/837//+r+B//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/2jiDy9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9o4g8vimUL71iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/4plC+/Ny5TPWIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//zbuEwAAAAA+sGFhPWIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/6wYWEAAAAAAAAAAAAAAAA/Nu4TPimUL71jh/y9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WIFP/1iBT/9YgU//WOH/L4plC+/Ny5TAAAAAAAAAAA4AAAB4AAAAGAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAABgAAAAeAAAAc=
  19. // @grant GM_xmlhttpRequest
  20. // @connect fanyi.baidu.com
  21. // ==/UserScript==
  22.  
  23. /* Usage:
  24. ** baidu_translate(details): details = {
  25. text: <string> Text you want to translate.
  26. Required argument, no default value.
  27. callback: <function> Callback function when translation succeed,
  28. e.g. function(result) {console.log(result);}.
  29. Argument `result` will be <string> translate result.
  30. Required argument, no default value.
  31. [src]: <string> Source language; e.g. 'zh' for Chinese, 'en' for English, 'ja' for Japanese, ....
  32. Default: Auto detect.
  33. [dst]: <string> Destination language,
  34. Default: 'zh'.
  35. [split]: <number> Text spliting max length, just leave blank if you don't know what this means.
  36. What it is: Baidu has limited that up to 5000 letters can be translated each single API
  37. request, so the translate function will split text by about every ${split} letters, and
  38. translates each of them with a single API request then concatenate the translate result
  39. together again. Don't worry if any sentence to be splited, actually the translate
  40. function splits text with '\n' first, then concatenate the '\n'-splited strings as long
  41. as possible while keeping its length <= ${split}.
  42. Default: 5000
  43. [onerror]: <function> Callback function when translation failed,
  44. e.g. function(reason) {console.log(reason);}.
  45. Argument: `reason` may be anything that causes its failure, just for debugging and do
  46. not use it in production.
  47. Default: function() {}.
  48. [retry]: <number> Times to retry before onerror function being called or an error being thrown,
  49. Default: 3.
  50. }
  51. ** Or:
  52. ** baidu_translate(text, src, dst, callback, onerror, split, retry)
  53. **
  54. ** Overloads:
  55. ** baidu_translate(text, src, dst, callback, onerror, split)
  56. ** baidu_translate(text, dst, callback, onerror, split)
  57. ** baidu_translate(text, callback, onerror, split)
  58. ** baidu_translate(text, callback, onerror)
  59. ** baidu_translate(text, callback)
  60. */
  61.  
  62. let baidu_translate, bdTransReady;
  63. [baidu_translate, bdTransReady] = (function() {
  64. const BDT = new BaiduTranslateAPI();
  65. return [baidu_translate, bdTransReady];
  66.  
  67. function baidu_translate() {
  68. // Check BDT ready
  69. if (!BDT.gtk || !BDT.token) {
  70. //throw new Error('BaiduTranslateAPI not ready');
  71. return false;
  72. }
  73.  
  74. // Get argument
  75. const [text, src, dst, callback, onerror, split, retry] = parseArgs([...arguments], [
  76. function(args, defaultValues) {
  77. const details = args[0];
  78. const parsed = [...defaultValues];
  79. details.hasOwnProperty('text') && (parsed[0] = details.text);
  80. details.hasOwnProperty('src') && (parsed[1] = details.src);
  81. details.hasOwnProperty('dst') && (parsed[2] = details.dst);
  82. details.hasOwnProperty('callback') && (parsed[3] = details.callback);
  83. details.hasOwnProperty('onerror') && (parsed[4] = details.onerror);
  84. details.hasOwnProperty('split') && (parsed[5] = details.split);
  85. details.hasOwnProperty('retry') && (parsed[6] = details.retry);
  86. return parsed;
  87. },
  88. [1,4],
  89. [1,4,5],
  90. [1,4,5,6],
  91. [1,3,4,5,6],
  92. [1,2,3,4,5,6],
  93. [1,2,3,4,5,6,7]
  94. ], ['', undefined, undefined, function() {}, function() {}, 5000, 3]);
  95.  
  96. // Split lines
  97. const textarr = text.replaceAll('\r\n', '\n').replaceAll('\n\r', '\n').replaceAll('\r', '\n').split('\n');
  98. if (textarr.some((t) => (t.length > split))) {
  99. throw new Error('Some paragraph is longer than given split length (' + split + ')');
  100. }
  101.  
  102. // Prepare
  103. const AM = new AsyncManager();
  104. const result = [];
  105. AM.onfinish = function() {
  106. callback(result.map(re => '\n'.repeat(re.newline_begin) + re.dst + '\n'.repeat(re.newline_end)).join('\n'));
  107. }
  108.  
  109. // Send requests
  110. let index = 0;
  111. while (textarr.length > 0) {
  112. // Join translate api paragraph
  113. let para = '';
  114. while (textarr.length > 0 && para.length + textarr[0].length < split) {
  115. para += '\n' + textarr.shift();
  116. }
  117. para = para.substr(1);
  118.  
  119. // Whether this paragraph contains \n at beginning
  120. const countNewLine = str => str.split('').filter(t => t === '\n').length;
  121. const newline_begin = countNewLine(para.match(/^\s*/) ? para.match(/^\s*/)[0] : '');
  122. const newline_end = countNewLine(para.match(/^\s*/) ? para.match(/\s*$/)[0] : '');
  123. result[index] = {src: para, dst: null, newline_begin, newline_end};
  124.  
  125. // API request
  126. AM.add();
  127. BDT.translate({
  128. text: para,
  129. args: [index],
  130. src: src,
  131. dst: dst,
  132. onerror: onerror,
  133. retry: retry,
  134. callback: function(json, i) {
  135. const temp_result = json.trans_result.data.reduce(function(pre, cur) {
  136. return (pre.push('\n'.repeat(cur.prefixWrap) + cur.dst), pre);
  137. }, []).join('\n');
  138. result[i].dst = temp_result;
  139. AM.finish();
  140. }
  141. });
  142. index++;
  143. }
  144. AM.finishEvent = true;
  145.  
  146. return true;
  147. }
  148.  
  149. function bdTransReady(callback) {
  150. bdTransReady.callbacks = bdTransReady.callbacks || [];
  151. bdTransReady.callbacks.push(callback);
  152. BDT.oninit = dispatchCallback;
  153.  
  154. function dispatchCallback() {
  155. bdTransReady.callbacks.forEach(cb => cb());
  156. bdTransReady.callbacks.splice(0, Infinity);
  157. }
  158. }
  159.  
  160. function BaiduTranslateAPI() {
  161. const BT = this;
  162. BT.gtk = BT.token = null;
  163. BT.inited = false;
  164.  
  165. let oninit=function() {};
  166. Object.defineProperty(BT, 'oninit', {
  167. enumerable: true,
  168. set: (f) => (typeof f === 'function' && (oninit = f) && BT.inited && oninit()),
  169. get: () => (oninit)
  170. });
  171.  
  172. init();
  173.  
  174. BT.calcSign = calcSign;
  175. BT.translate = translate;
  176.  
  177. async function translate(details) {
  178. const callback = details.callback;
  179. const text = details.text;
  180. const src = details.src || await langDetect(text);
  181. const dst = details.dst || 'zh';
  182. const onerror = details.onerror || function() {};
  183. const retry = details.retry || 0;
  184. const args = details.args || [];
  185.  
  186. GM_xmlhttpRequest({
  187. method: 'POST',
  188. url: 'https://fanyi.baidu.com/v2transapi',
  189. headers: {
  190. 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36',
  191. 'Content-Type': 'application/x-www-form-urlencoded'
  192. },
  193. data: toQueryString({
  194. 'from': src,
  195. 'to': dst,
  196. 'query': text,
  197. 'simple_means_flag': 3,
  198. 'sign': calcSign(text),
  199. 'token': BT.token
  200. }),
  201. onload: function(response) {
  202. response.status !== 200 && Err(response);
  203. const json = JSON.parse(response.responseText);
  204. json.error && Err(json);
  205. callback.apply(null, [json].concat(args));
  206.  
  207. function Err(e) {
  208. !_onerror(e) && console.log('Retrying...\nleft: ' + (retry-1).toString());
  209. console.log(e);
  210. throw new Error('Server returned with an error (logged above)');
  211. }
  212. },
  213. onerror: _onerror,
  214. ontimeout: _onerror,
  215. onabort: _onerror,
  216. });
  217.  
  218. // Returns true for error, false for retry
  219. function _onerror(e) {
  220. console.log('sign = ' + calcSign(text));
  221. if (retry > 0) {
  222. setTimeout(retryRequest.bind(null, e), 500);
  223. return false;
  224. }
  225. onerror(e);
  226. return true;
  227. }
  228.  
  229. function retryRequest(e) {
  230. translate({
  231. callback: callback,
  232. text: text,
  233. src: src,
  234. dst: dst,
  235. onerror: onerror,
  236. retry: retry - 1,
  237. args: args
  238. });
  239. }
  240. }
  241.  
  242. function langDetect(text) {
  243. return new Promise((resolve, reject) => {
  244. GM_xmlhttpRequest({
  245. method: 'POST',
  246. url: 'https://fanyi.baidu.com/langdetect',
  247. headers: {
  248. 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36',
  249. 'Content-Type': 'application/x-www-form-urlencoded'
  250. },
  251. data: toQueryString({'query': text}),
  252. onload: function(response) {
  253. const json = JSON.parse(response.responseText);
  254. resolve(json.lan);
  255. },
  256. onerror: function(e) {reject(e)},
  257. ontimeout: function(e) {reject(e)},
  258. onabort: function(e) {reject(e)},
  259. });
  260. });
  261. }
  262.  
  263. // Calc sign based on query-text and gtk
  264. function calcSign(query) {
  265. function e(t, e) {
  266. (null == e || e > t.length) && (e = t.length);
  267. for (var n = 0, r = new Array(e); n < e; n++)
  268. r[n] = t[n];
  269. return r
  270. }
  271. function n(t, e) {
  272. for (var n = 0; n < e.length - 2; n += 3) {
  273. var r = e.charAt(n + 2);
  274. r = "a" <= r ? r.charCodeAt(0) - 87 : Number(r),
  275. r = "+" === e.charAt(n + 1) ? t >>> r : t << r,
  276. t = "+" === e.charAt(n) ? t + r & 4294967295 : t ^ r
  277. }
  278. return t
  279. }
  280. var r = null;
  281. var token = function(t, _gtk) {
  282. var o, i = t.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
  283. if (null === i) {
  284. var a = t.length;
  285. a > 30 && (t = "".concat(t.substr(0, 10)).concat(t.substr(Math.floor(a / 2) - 5, 10)).concat(t.substr(-10, 10)))
  286. } else {
  287. for (var s = t.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), c = 0, u = s.length, l = []; c < u; c++)
  288. "" !== s[c] && l.push.apply(l, function(t) {
  289. if (Array.isArray(t))
  290. return e(t)
  291. }(o = s[c].split("")) || function(t) {
  292. if ("undefined" != typeof Symbol && null != t[Symbol.iterator] || null != t["@@iterator"])
  293. return Array.from(t)
  294. }(o) || function(t, n) {
  295. if (t) {
  296. if ("string" == typeof t)
  297. return e(t, n);
  298. var r = Object.prototype.toString.call(t).slice(8, -1);
  299. return "Object" === r && t.constructor && (r = t.constructor.name),
  300. "Map" === r || "Set" === r ? Array.from(t) : "Arguments" === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r) ? e(t, n) : void 0
  301. }
  302. }(o) || function() {
  303. throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")
  304. }()),
  305. c !== u - 1 && l.push(i[c]);
  306. var p = l.length;
  307. p > 30 && (t = l.slice(0, 10).join("") + l.slice(Math.floor(p / 2) - 5, Math.floor(p / 2) + 5).join("") + l.slice(-10).join(""))
  308. }
  309. for (var h = (_gtk || "").split("."), f = Number(h[0]) || 0, m = Number(h[1]) || 0, g = [], y = 0, v = 0; v < t.length; v++) {
  310. var _ = t.charCodeAt(v);
  311. _ < 128 ? g[y++] = _ : (_ < 2048 ? g[y++] = _ >> 6 | 192 : (55296 == (64512 & _) && v + 1 < t.length && 56320 == (64512 & t.charCodeAt(v + 1)) ? (_ = 65536 + ((1023 & _) << 10) + (1023 & t.charCodeAt(++v)),
  312. g[y++] = _ >> 18 | 240,
  313. g[y++] = _ >> 12 & 63 | 128) : g[y++] = _ >> 12 | 224,
  314. g[y++] = _ >> 6 & 63 | 128),
  315. g[y++] = 63 & _ | 128)
  316. }
  317. for (var b = f, w = '+-a^+6', k = '+-3^+b+-f', x = 0; x < g.length; x++)
  318. b = n(b += g[x], w);
  319. return b = n(b, k),
  320. (b ^= m) < 0 && (b = 2147483648 + (2147483647 & b)),
  321. "".concat((b %= 1e6).toString(), ".").concat(b ^ f)
  322. }
  323.  
  324. return token(query, BT.gtk);
  325. }
  326.  
  327. function toQueryString(obj) {
  328. const USP = new URLSearchParams();
  329. for (const [key, value] of Object.entries(obj)) {
  330. USP.append(key, value);
  331. }
  332. return USP.toString();
  333. }
  334.  
  335. // Request token and gtk
  336. function init() {
  337. // Request twice, make sure gtk is latest,
  338. // or may get 998 error while requesting translate API
  339. requestIndex(requestIndex.bind(null, function(html) {
  340. BT.token = html.match(/token: ["'](.*?)["'],/)[1];
  341. BT.gtk = html.match(/window.gtk = ["'](.*?)["'];/)[1];
  342. BT.inited = true;
  343. oninit();
  344. }));
  345.  
  346. function requestIndex(callback) {
  347. const url = 'https://fanyi.baidu.com';
  348. GM_xmlhttpRequest({
  349. method: 'GET',
  350. headers: {
  351. 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
  352. },
  353. url: url,
  354. onload: function(response) {
  355. callback(response.responseText);
  356. }
  357. });
  358. }
  359. }
  360. }
  361.  
  362. function AsyncManager() {
  363. const AM = this;
  364.  
  365. // Ongoing xhr count
  366. this.taskCount = 0;
  367.  
  368. // Whether generate finish events
  369. let finishEvent = false;
  370. Object.defineProperty(this, 'finishEvent', {
  371. configurable: true,
  372. enumerable: true,
  373. get: () => (finishEvent),
  374. set: (b) => {
  375. finishEvent = b;
  376. b && AM.taskCount === 0 && AM.onfinish && AM.onfinish();
  377. }
  378. });
  379.  
  380. // Add one task
  381. this.add = () => (++AM.taskCount);
  382.  
  383. // Finish one task
  384. this.finish = () => ((--AM.taskCount === 0 && AM.finishEvent && AM.onfinish && AM.onfinish(), AM.taskCount));
  385. }
  386.  
  387. function parseArgs(args, rules, defaultValues=[]) {
  388. // args and rules should be array, but not just iterable (string is also iterable)
  389. if (!Array.isArray(args) || !Array.isArray(rules)) {
  390. throw new TypeError('parseArgs: args and rules should be array')
  391. }
  392.  
  393. // fill rules[0]
  394. (!Array.isArray(rules[0]) || rules[0].length === 1) && rules.splice(0, 0, []);
  395.  
  396. // max arguments length
  397. const count = rules.length - 1;
  398.  
  399. // args.length must <= count
  400. if (args.length > count) {
  401. throw new TypeError(`parseArgs: args has more elements(${args.length}) longer than ruless'(${count})`);
  402. }
  403.  
  404. // rules[i].length should be === i if rules[i] is an array, otherwise it should be a function
  405. for (let i = 1; i <= count; i++) {
  406. const rule = rules[i];
  407. if (Array.isArray(rule)) {
  408. if (rule.length !== i) {
  409. throw new TypeError(`parseArgs: rules[${i}](${rule}) should have ${i} numbers, but given ${rules[i].length}`);
  410. }
  411. if (!rule.every((num) => (typeof num === 'number' && num <= count))) {
  412. throw new TypeError(`parseArgs: rules[${i}](${rule}) should contain numbers smaller than count(${count}) only`);
  413. }
  414. } else if (typeof rule !== 'function') {
  415. throw new TypeError(`parseArgs: rules[${i}](${rule}) should be an array or a function.`)
  416. }
  417. }
  418.  
  419. // Parse
  420. const rule = rules[args.length];
  421. let parsed;
  422. if (Array.isArray(rule)) {
  423. parsed = [...defaultValues];
  424. for (let i = 0; i < rule.length; i++) {
  425. parsed[rule[i]-1] = args[i];
  426. }
  427. } else {
  428. parsed = rule(args, defaultValues);
  429. }
  430. return parsed;
  431. }
  432. }) ();