Greasy Fork镜像 支持简体中文。

youdaodict

Translate any text selected into a tooltip

  1. // ==UserScript==
  2. // @id youdaodict-greasemonkey-reverland-2015-09-26
  3. // @name youdaodict
  4. // @name:zh-CN 有道取词
  5. // @version 2.0
  6. // @namespace https://github.com/HalfdogStudio/youdaodict
  7. // @author Liu Yuyang(sa@linuxer.me)
  8. // @description Translate any text selected into a tooltip
  9. // @description:zh-cn 一个可以在浏览器中自由使用的屏幕取词脚本
  10. // @include *
  11. // @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
  12. // @grant GM_xmlhttpRequest
  13. // @grant GM.xmlHttpRequest
  14. // ==/UserScript==
  15.  
  16. window.document.body.addEventListener("mouseup", translate, false);
  17. window.document.body.addEventListener("keyup", toggleYoudao, false);
  18. var toggle = true;
  19.  
  20. function toggleYoudao(e) {
  21. if (e.which == 81 && e.altKey && e.ctrlKey) {
  22. if (toggle) {
  23. window.document.body.removeEventListener("mouseup", translate, false);
  24. toggle = false;
  25. } else {
  26. window.document.body.addEventListener("mouseup", translate, false);
  27. toggle = true;
  28. }
  29. }
  30. }
  31.  
  32. function translate(e) {
  33. // remove previous .youdaoPopup if exists
  34. var previous = document.querySelector(".youdaoPopup");
  35. if (previous) {
  36. document.body.removeChild(previous);
  37. }
  38. //console.log("translate start");
  39. var selectObj = document.getSelection();
  40.  
  41. // if #text node
  42. if (selectObj.anchorNode && selectObj.anchorNode.nodeType == 3) {
  43. //GM_log(selectObj.anchorNode.nodeType.toString());
  44. var word = selectObj.toString();
  45. if (word == "") {
  46. return;
  47. }
  48. // linebreak wordwrap, optimize for pdf.js
  49. word = word.replace('-\n','');
  50. // multiline selection, optimize for pdf.js
  51. word = word.replace('\n', ' ');
  52. //console.log("word:", word);
  53. var ts = new Date().getTime();
  54. //console.log("time: ", ts);
  55. var mx = e.clientX;
  56. var my = e.clientY;
  57. translate(word, ts);
  58.  
  59. }
  60.  
  61. function popup(mx, my, result) {
  62. //console.log(mx)
  63. //console.log(my)
  64. //console.log("popup window!")
  65. var youdaoWindow = document.createElement('div');
  66. youdaoWindow.classList.toggle("youdaoPopup");
  67. // parse
  68. var dictJSON = JSON.parse(result);
  69. console.log(dictJSON);
  70. var query = dictJSON['query'];
  71. var errorCode = dictJSON['errorCode'];
  72. if (dictJSON['basic']) {
  73. word();
  74. } else {
  75. sentence();
  76. }
  77. // main window
  78. // first insert into dom then there is offsetHeight!IMPORTANT!
  79. document.body.appendChild(youdaoWindow);
  80. youdaoWindow.style.color = "black";
  81. youdaoWindow.style.textAlign = "left";
  82. youdaoWindow.style.display = "block";
  83. youdaoWindow.style.position = "fixed";
  84. youdaoWindow.style.background = "lightblue";
  85. youdaoWindow.style.borderRadius = "5px";
  86. youdaoWindow.style.boxShadow = "0 0 5px 0";
  87. youdaoWindow.style.opacity = "0.9";
  88. youdaoWindow.style.width = "200px";
  89. youdaoWindow.style.wordWrap = "break-word";
  90. youdaoWindow.style.left = mx + 10 + "px";
  91. if (mx + 200 + 30 >= window.innerWidth) {
  92. youdaoWindow.style.left = parseInt(youdaoWindow.style.left) - 200 + "px";
  93. }
  94. if (my + youdaoWindow.offsetHeight + 30 >= window.innerHeight) {
  95. youdaoWindow.style.bottom = "20px";
  96. } else {
  97. youdaoWindow.style.top = my + 10 + "px";
  98. }
  99. youdaoWindow.style.padding = "5px";
  100. youdaoWindow.style.zIndex = '999999';
  101.  
  102. function word() {
  103.  
  104. function play(word) {
  105. //console.log("[DEBUG] PLAYOUND")
  106.  
  107. function playSound(buffer) {
  108. var source = context.createBufferSource();
  109. source.buffer = buffer;
  110. source.connect(context.destination);
  111. source.start(0);
  112. }
  113.  
  114. var context = new AudioContext();
  115. var soundUrl = `https://dict.youdao.com/dictvoice?type=2&audio=${word}`;
  116. var p = new Promise(function(resolve, reject) {
  117. var ret = GM.xmlHttpRequest({
  118. method: "GET",
  119. url: soundUrl,
  120. responseType: 'arraybuffer',
  121. onload: function(res) {
  122. try {
  123. context.decodeAudioData(res.response, function(buffer) {
  124. resolve(buffer);
  125. });
  126. } catch(e) {
  127. reject(e);
  128. }
  129. }
  130. });
  131. });
  132. p.then(playSound, function(e) {
  133. console.log(e);
  134. });
  135. }
  136.  
  137. var basic = dictJSON['basic'];
  138. var header = document.createElement('p');
  139. // header
  140. var span = document.createElement('span');
  141. span.innerHTML = query;
  142. header.appendChild(span);
  143. // phonetic if there is
  144. var phonetic = basic['phonetic'];
  145. if (phonetic) {
  146. var phoneticNode = document.createElement('span');
  147. phoneticNode.innerHTML = '[' + phonetic + ']';
  148. phoneticNode.style.cursor = "pointer";
  149. header.appendChild(phoneticNode);
  150. var playLogo = document.createElement('span');
  151. header.appendChild(phoneticNode);
  152. phoneticNode.addEventListener('mouseup', function(e){
  153. if (e.target === phoneticNode) {
  154. e.stopPropagation();
  155. play(query);
  156. }
  157. }, false);
  158. }
  159. header.style.color = "darkBlue";
  160. header.style.margin = "0";
  161. header.style.padding = "0";
  162. span.style.fontweight = "900";
  163. span.style.color = "black";
  164.  
  165. youdaoWindow.appendChild(header);
  166. var hr = document.createElement('hr');
  167. hr.style.margin = "0";
  168. hr.style.padding = "0";
  169. hr.style.height = "1px";
  170. hr.style.borderTop = "dashed 1px black";
  171. youdaoWindow.appendChild(hr);
  172. var ul = document.createElement('ul');
  173. // ul style
  174. ul.style.margin = "0";
  175. ul.style.padding = "0";
  176. basic['explains'].map(function(trans) {
  177. var li = document.createElement('li');
  178. li.style.listStyle = "none";
  179. li.style.margin = "0";
  180. li.style.padding = "0";
  181. li.style.background = "none";
  182. li.style.color = "inherit";
  183. li.appendChild(document.createTextNode(trans));
  184. ul.appendChild(li);
  185. });
  186. youdaoWindow.appendChild(ul);
  187.  
  188. }
  189.  
  190. function sentence() {
  191. var ul = document.createElement('ul');
  192. // ul style
  193. ul.style.margin = "0";
  194. ul.style.padding = "0";
  195. dictJSON['translation'].map(function(trans) {
  196. var li = document.createElement('li');
  197. li.style.listStyle = "none";
  198. li.style.margin = "0";
  199. li.style.padding = "0";
  200. li.style.background = "none";
  201. li.style.color = "inherit";
  202. li.appendChild(document.createTextNode(trans));
  203. ul.appendChild(li);
  204. });
  205. youdaoWindow.appendChild(ul);
  206. }
  207. }
  208.  
  209.  
  210. function translate(word, ts) {
  211. var reqUrl = `http://fanyi.youdao.com/openapi.do?type=data&doctype=json&version=1.1&relatedUrl=http%3A%2F%2Ffanyi.youdao.com%2F%23&keyfrom=fanyiweb&key=null&translate=on&q=${word}&ts=${ts}`;
  212. //console.log("request url: ", reqUrl);
  213. var ret = GM.xmlHttpRequest({
  214. method: "GET",
  215. url: reqUrl,
  216. headers: {"Accept": "application/json"}, // can be omitted...
  217. onreadystatechange: function(res) {
  218. //console.log("Request state changed to: " + res.readyState);
  219. },
  220. onload: function(res) {
  221. var retContent = res.response;
  222. //console.log(retContent)
  223. popup(mx, my, retContent);
  224. },
  225. onerror: function(res) {
  226. console.log("error");
  227. }
  228. });
  229. }
  230. }
  231.  

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址