多邻国拼音选词快捷键简化版(快捷键不包括删除选词)

Enter键:快速学习 或 添加小故事,中文选词快捷键 或 确认消息;ctrl键播放语音,alt慢速播放;Backspace键删除选词;Tab键跳过题目或自动答题;Esc退出学习页面. 参考多邻国选词快捷键https://greasyfork.org/zh-CN/scripts/493966-%E5%A4%9A%E9%82%BB%E5%9B%BD%E9%80%89%E8%AF%8D%E5%BF%AB%E6%8D%B7%E9%94%AE

სკრიპტის ინსტალაცია?
ავტორის შემოთავაზებული სკრიპტი

შეიძლება მოგეწონოს 多邻国拼音选词快捷键.

სკრიპტის ინსტალაცია
  1. // ==UserScript==
  2. // @name 多邻国拼音选词快捷键简化版(快捷键不包括删除选词)
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.39.9
  5. // @description Enter键:快速学习 或 添加小故事,中文选词快捷键 或 确认消息;ctrl键播放语音,alt慢速播放;Backspace键删除选词;Tab键跳过题目或自动答题;Esc退出学习页面. 参考多邻国选词快捷键https://greasyfork.org/zh-CN/scripts/493966-%E5%A4%9A%E9%82%BB%E5%9B%BD%E9%80%89%E8%AF%8D%E5%BF%AB%E6%8D%B7%E9%94%AE
  6. // @author Gelan
  7. // @match https://www.duolingo.com/*
  8. // @match https://www.duolingo.cn/*
  9. // @license MIT
  10. // @icon https://d35aaqx5ub95lt.cloudfront.net/images/super/fb7130289a205fadd2e196b9cc866555.svg
  11. // @require https://unpkg.com/pinyin-pro
  12. // ==/UserScript==
  13.  
  14. ;(function () {
  15. 'use strict'
  16. var { pinyin } = pinyinPro;
  17. var question = { type: -1 , type2: -1 }
  18. var userInput = document.createElement('span')
  19. // 始初化题目数据对象方法
  20. var init_question = function () {
  21. let challengeHeader = document.querySelector('h1[data-test="challenge-header"]');
  22. // 对话
  23. question.el = document.querySelector(
  24. 'div[data-test="challenge challenge-dialogue"]'
  25. )
  26. if (question.el) {
  27. question.type = 10
  28. return
  29. }
  30. // 听写
  31. question.el = document.querySelector(
  32. 'div[data-test="challenge challenge-listen"]'
  33. )
  34. if (question.el) {
  35. question.type = 9
  36. return
  37. }
  38. // 口语
  39. question.el = document.querySelector(
  40. 'div[data-test="challenge challenge-speak"], div[data-test="challenge challenge-listenSpeak"]'
  41. )
  42. if (question.el) {
  43. question.type = 8
  44. return
  45. }
  46. // 补全
  47. question.el = document.querySelector(
  48. 'div[data-test="challenge challenge-tapCloze"]'
  49. )
  50. if (question.el) {
  51. question.type = 7
  52. return
  53. }
  54. // 小故事
  55. question.el = document.getElementsByClassName('kbjat')
  56. if (question.el.length) {
  57. question.el = question.el[0].children
  58. question.type = 6
  59. // 每段数据所在属性名
  60. question.prop_field = Object.keys(question.el[0]).find(p => p.startsWith('__reactFiber'))
  61. return
  62. }
  63. // 听写填空
  64. question.el = document.querySelector(
  65. 'div[data-test="challenge challenge-listenComplete"]'
  66. )
  67. if (question.el) {
  68. question.type = 5
  69. return
  70. }
  71. // 选项听写
  72. question.el = document.querySelector(
  73. 'div[data-test="challenge challenge-listenTap"]'
  74. )
  75. if (question.el) {
  76. question.type = 4
  77. return
  78. }
  79. // 选项填空
  80. question.el = document.querySelector(
  81. 'div[data-test="challenge challenge-tapComplete"]'
  82. )
  83. if (question.el) {
  84. question.type = 3
  85. return
  86. }
  87. // 配对
  88. question.el = document.querySelector(
  89. 'div[data-test="challenge challenge-listenMatch"]'
  90. )
  91. if (question.el) {
  92. question.el = question.el.children[0].children[1].children[0]
  93. question.type = 2
  94. return
  95. }
  96. // 中文组句
  97. question.el = document.querySelector('div[data-test="word-bank"]')
  98. if (question.el) {
  99. let spanElement = challengeHeader.querySelector('span');
  100. if (spanElement.textContent === "用中文写出这句话") {
  101. question.el2 =
  102. question.el.parentElement.previousElementSibling.children[0].children[0].children[1]
  103. question.type = 1
  104. userInput.textContent = ''
  105. challengeHeader.append(userInput)
  106. return
  107. }
  108. }
  109. // 选择
  110. question.el = document.querySelector('div[aria-label="choice"]')
  111. if (question.el) {
  112. question.type = 0
  113. if(challengeHeader) {
  114. let spanElement = challengeHeader.querySelector('span');
  115. if (spanElement.textContent === "阅读并回答") {
  116. question.type2 = 0
  117. }
  118. else if (spanElement.textContent === "你听到了什么?") {
  119. question.type2 = 1
  120. }
  121. else if (spanElement.textContent === "选择听到的内容") {
  122. question.type2 = 2
  123. }
  124. else if (spanElement.textContent === "听音辩词") {
  125. question.type2 = 3
  126. }
  127. return
  128. }
  129. }
  130. // 其他
  131. question.el = null
  132. question.type = -1
  133. }
  134. var process = function () {
  135. if (question.type == 1) {
  136. if (document.querySelector('rt'))
  137. {
  138. return;
  139. }
  140. for (let i = 0; i < question.el.children.length; i++) {
  141. let span = question.el.children[i].querySelector('span[data-test="challenge-tap-token-text"]');
  142. let rt = document.createElement('rt');
  143. rt.style.cssText = 'color: gray; display: flex; flex-direction: row;';
  144. rt.style.fontSize = parseFloat(window.getComputedStyle(span).fontSize) * 0.5 + 'px';
  145. rt.textContent = pinyin(span.textContent, { toneType: 'none' });
  146. rt.textContent = rt.textContent.replace(/ü/g, 'v');
  147.  
  148. span.parentElement.style.cssText = 'display: flex; flex-direction: column;';
  149. span.parentElement.insertBefore(rt, span);
  150. }
  151. }
  152. else if (question.type == 6) {
  153. if (document.querySelector('span.append')) {
  154. return
  155. }
  156. let ul = document.querySelector('ul._13ieZ')
  157. if(!ul) {
  158. return
  159. }
  160. for (let i = 0; i < ul.children.length; i++) {
  161. let li = ul.children[i]
  162. let span = document.createElement('span')
  163. span.className = 'append'
  164. span.textContent = i + 1
  165. li.insertBefore(span,li.querySelector('button[data-test="stories-choice"]'))
  166. }
  167. }
  168. }
  169. var remove = function () {
  170. let rts = document.querySelectorAll('rt')
  171. rts.forEach(function(rt) {
  172. rt.parentElement.removeChild(rt);
  173. })
  174. if (question.type == 1) {
  175. let selects = question.el2.children
  176. try {
  177. selects[0].querySelector('button')
  178. } catch {
  179. return true
  180. }
  181. for (let i = selects.length; i > 0; i--) {
  182. let select = selects[i - 1]
  183. select.querySelector('button').click()
  184. }
  185. return false
  186. }
  187. return true
  188. }
  189. let pinyinIndex = 0; // 匹配拼音按键索引
  190. let matchs = []; // 匹配按钮
  191. let pinyins = []; // 所有拼音按键
  192. let isCombi = false; // 是否为组合键(shift+任意字符)
  193.  
  194. document.addEventListener('keyup', function (event) {
  195. if (!document.querySelector('div.kPqwA')) {
  196. if (event.key == 'Enter') {
  197. if (window.location.pathname == '/learn') {
  198. window.location.href = '/lesson'
  199. }
  200. }
  201. return
  202. }
  203. init_question()
  204. // Esc键,退出练习按钮 或 不,谢谢
  205. if (event.key == 'Escape') {
  206. let quit = document.querySelector('button[data-test="quit-button"]')
  207. let no = document.querySelector('button[data-test="notification-drawer-no-thanks-button"]')
  208. if (no) {
  209. no.click()
  210. }
  211. if (quit) {
  212. quit.click()
  213. }
  214. return
  215. }
  216. // Backspace键, 删除最后一个选词
  217. if (event.key == 'Backspace') {
  218. if (question.el2) {
  219. var selects = question.el2.children
  220. var cnt = selects.length
  221. var last_select = selects[cnt - 1]
  222. last_select.querySelector('button').click()
  223. }
  224. return
  225. }
  226. // Shift键, 在按钮选词和直接输入中切换 或 在减小难度和增大难度中切换
  227. if (!event.shiftKey && event.key == 'Shift') {
  228. if(!isCombi) {
  229. document.querySelector('button[data-test="player-toggle-keyboard"]').click()
  230. }
  231. isCombi = false;
  232. return
  233. }
  234. else if (event.shiftKey && event.key != 'Shift') {
  235. isCombi = true;
  236. }
  237. // Control键, 播放音频
  238. if (event.key == 'Control') {
  239. if (question.type == 0 && question.type2 == 0) {
  240. let el = document.querySelector('button._15600')
  241. el.click()
  242. }
  243. else if (question.type == 0 && question.type2 == 1) {
  244. let el = document.querySelector('button._3U_eC')
  245. el.click()
  246. }
  247. else if (question.type == 0 && question.type2 == 3) {
  248. let el = document.querySelector('div._1j8q_')
  249. el.children[0].click()
  250. }
  251. else if (question.type == 1 || question.type == 8 || question.type == 10) {
  252. let el = document.querySelector('button._1GJVt')
  253. el.click()
  254. }
  255. else if ((question.type == 0 && question.type2 == 2) || question.type == 4) {
  256. let el = document.querySelector('div._3qAs-')
  257. el.children[0].children[0].click()
  258. }
  259. else if (question.type == 5 || question.type == 9) {
  260. let el = document.querySelector('div._1DLP9')
  261. el.children[0].children[0].children[0].click()
  262. }
  263. else if (question.type == 6) {
  264. var last_listen
  265. for (var i = 0; i < question.el.length; i++) {
  266. var el = question.el[i]
  267. var class_list = Array.from(el.classList)
  268. var flag = el[question.prop_field].flags
  269. if (class_list.length == 1) {
  270. continue
  271. }
  272. if (class_list.length == 2) {
  273. last_listen = el
  274. continue
  275. }
  276. if (class_list.length == 3) {
  277. if (flag == 0) {
  278. break
  279. } else {
  280. continue
  281. }
  282. }
  283. if (class_list.length == 4) {
  284. continue
  285. }
  286. }
  287. if (last_listen) {
  288. last_listen.querySelector('div[data-test="audio-button"]').click()
  289. }
  290. }
  291. else {
  292. var els = document.getElementsByClassName('fs-exclude')
  293. if (els) {
  294. els[0].click()
  295. }
  296. }
  297. return
  298. }
  299. // Alt键,慢速播放音频
  300. if (event.key == 'Alt') {
  301. event.preventDefault();
  302. if ((question.type == 0 && question.type2 == 2)|| question.type == 4) {
  303. let el = document.querySelector('div._3qAs-')
  304. el.children[1].children[0].children[0].click()
  305. }
  306. else if (question.type == 0 && question.type2 == 3) {
  307. let el = document.querySelector('div._1j8q_')
  308. el.children[1].click()
  309. }
  310. else if(question.type == 5 || question.type == 9) {
  311. let el = document.querySelector('div._1DLP9')
  312. el.children[1].children[0].children[0].click()
  313. }
  314. return
  315. }
  316. // Tab键,跳过题目或自动答题(需下载Duolingo Pro BETA)
  317. if (event.key == 'Tab') {
  318. event.preventDefault();
  319. let solve = document.querySelector('#solveAllButton')
  320. if (solve) {
  321. if (remove()) {
  322. solve.previousElementSibling.click()
  323. }
  324. }
  325. else {
  326. document.querySelector('button[data-test="player-skip"]').click()
  327. }
  328. return
  329. }
  330. // Enter键,呼出process 或 确认消息
  331. if (event.key == 'Enter') {
  332. let yes = document.querySelector('button[data-test="notification-button"]')
  333. if(yes) {
  334. yes.click()
  335. } else {
  336. process()
  337. }
  338. return
  339. }
  340.  
  341. const keyPressed = event.key;
  342. if (!document.querySelector('rt') && !document.querySelector('span.append')) {
  343. return
  344. }
  345. if (question.type == 1) {
  346. pinyins = document.querySelectorAll('rt');
  347. matchs = [];
  348. userInput.textContent = " 用户输入: " + keyPressed
  349.  
  350. for (let i = 0; i < pinyins.length; i++) {
  351. let pinyin = pinyins[i];
  352. if (pinyin.innerText[pinyinIndex] === keyPressed && pinyin.parentElement.parentElement.getAttribute('aria-disabled') != 'true') {
  353. if (pinyinIndex === 0) {
  354. pinyin.style.color = 'lightblue';
  355. }
  356. else {
  357. if (pinyin.style.color !== 'lightblue') {
  358. continue;
  359. }
  360. }
  361.  
  362. if(pinyin.innerText[pinyinIndex] === ' ')
  363. {
  364. event.preventDefault();
  365. }
  366.  
  367. matchs.push(pinyin);
  368. }
  369. else {
  370. pinyin.style.color = 'gray';
  371. }
  372. }
  373. if (matchs.length === 1) {
  374. matchs[0].parentElement.parentElement.click();
  375. pinyinIndex = 0;
  376. matchs = [];
  377. }
  378. else if (matchs.length > 1) {
  379. let num = 1;
  380. for (let i = 0; i < matchs.length; i++) {
  381. let match = matchs[i]
  382. if (pinyinIndex + 1 === match.textContent.length && !match.textContent.match(/\d+/g)) {
  383. match.textContent += num++;
  384. }
  385. }
  386. pinyinIndex++;
  387. } else {
  388. pinyinIndex = 0;
  389. matchs = [];
  390. }
  391. }
  392. else if (question.type == 6) {
  393. let spans = document.querySelectorAll('span.append')
  394. for(let i = 0 ; i < spans.length; i++)
  395. {
  396. let span = spans[i]
  397. if (keyPressed == span.textContent)
  398. {
  399. span.nextElementSibling.click()
  400. break
  401. }
  402. }
  403. }
  404. })
  405. })()