Auto-Duolingo

[Lite Version] Automatically farm experience points, hacking Duolingo is so easy!

  1. // ==UserScript==
  2. // @name Auto-Duolingo
  3. // @version 1.0.8
  4. // @author DevX
  5. // @namespace http://tampermonkey.net/
  6. // @description [Lite Version] Automatically farm experience points, hacking Duolingo is so easy!
  7. // @match https://*.duolingo.com/*
  8. // @match https://*.duolingo.cn/*
  9. // @grant none
  10. // @license MIT
  11. // @icon https://autoduo.click/assets/imgs/favicon.ico
  12. // ==/UserScript==
  13.  
  14. (() => {
  15. const AUTODUOLINGO_STORAGE = "autoDuolingoStorage";
  16. const { isSafeMode, isShowUI, isAnimationOff, exp, time, version, isNewNotify, rmNotiVer, rmNotiContent } =
  17. getSession();
  18. const { notifyVersion } = getLocal(AUTODUOLINGO_STORAGE);
  19.  
  20. const autoDuoLite = {
  21. initSignature: function () {
  22. this.signatureElm = document.createElement("div");
  23. Object.assign(this.signatureElm, {
  24. className: "signature-listening",
  25. innerHTML: `
  26. <div>
  27. Auto-Duolingo DevX
  28. <div class="autoduo-lite-version">
  29. LITE VERSION <button class="autoduo-upgrade" title="Upgrade version"></button>
  30. </div>
  31. </div>
  32. `,
  33. });
  34. const upgrade = this.signatureElm.querySelector('.autoduo-upgrade')
  35. upgrade.addEventListener('click', () => this.watchTutorial.click())
  36. document.body.appendChild(this.signatureElm);
  37. },
  38.  
  39. initContact: function () {
  40. this.contactWrapper = document.createElement("div");
  41. Object.assign(this.contactWrapper, {
  42. className: "contact-wrapper-listening",
  43. innerHTML: `<a class="contact-item-listening" href="https://t.me/imdevx" target="_blank" style="--data-img: url('https://autoduo.click/assets/client/tele-icon.ndx')">
  44. <p class="popup">Chat with DevX</p>
  45. </a>
  46. <a class="contact-item-listening" href="https://t.me/autoduofamily" target="_blank" style="--data-img: url('https://autoduo.click/assets/client/tele-gr-icon.ndx')">
  47. <p class="popup">Telegram Community</p>
  48. </a>
  49. <a class="contact-item-listening" href="https://zalo.me/g/lmhfps187" target="_blank" style="--data-img: url('https://autoduo.click/assets/client/zalo-icon.ndx')">
  50. <p class="popup">Zalo Community</p>
  51. </a>
  52. <a class="contact-item-listening" href="https://www.youtube.com/@autoduofamily" target="_blank" style="--data-img: url('https://autoduo.click/assets/client/youtube-icon.ndx')">
  53. <p class="popup">Youtube Channel</p>
  54. </a>
  55. <a class="contact-item-listening" href="https://www.facebook.com/groups/autoduofamily" target="_blank" style="--data-img: url('https://autoduo.click/assets/client/facebook-icon.png')">
  56. <p class="popup">Facebook Community</p>
  57. </a>
  58. <a class="contact-item-listening" id="greasyfork" href="https://greatest.deepsurf.us/en/scripts/487867-auto-duolingo" target="_blank" style="--data-img: url('https://autoduo.click/assets/client/greasyfork-icon.ndx')">
  59. <p class="popup">Greasy Fork</p>
  60. </a>`,
  61. });
  62. },
  63. initContactModal: function () {
  64. const admList = [
  65. {
  66. name: 'THUẬN THIÊN',
  67. role: 'Supporter',
  68. avatar: 'thuanthien.jpg',
  69. bio: 'If you have difficulties upgrading versions, obtaining activation keys, or have any questions while using AutoDuo, please contact me for assistance!',
  70. contact: {
  71. fb: 'https://www.facebook.com/share/1B8gdn7DFu/',
  72. tele: 'https://t.me/Thien22092008',
  73. }
  74. },
  75. {
  76. name: 'DEVX',
  77. role: 'Developer',
  78. avatar: 'devx.jpg',
  79. bio: 'If you need to purchase long-term activation keys or upgrade key levels, please contact me!',
  80. contact: {
  81. fb: 'https://www.facebook.com/autoduofamily/',
  82. tele: 'https://t.me/imdevx',
  83. }
  84. },
  85. ]
  86.  
  87. this.contactModal = document.createElement('div')
  88. Object.assign(this.contactModal, {
  89. className: 'contact-modal',
  90. innerHTML: `
  91. <div class="contact-modal-inner">
  92. <header>
  93. <h3><span>CONTACT & SUPPORT</span></h3>
  94. </header>
  95. <div class="body">
  96. ${admList.map(item => `
  97. <div class="adm-item">
  98. <p class="adm-bio">${item.bio}</p>
  99. <img class="adm-avatar" src="https://autoduo.click/assets/imgs/admin/${item.avatar}" />
  100. <h5>${item.name}</h5>
  101. <p class="adm-role">Role: <b>${item.role}</b></p>
  102. <div class="adm-contact contact-wrapper-listening">
  103. <a class="contact-item-listening" href="${item.contact.tele}" target="_blank" style="--data-img: url('https://autoduo.click/assets/client/tele-icon.ndx')"></a>
  104. <a class="contact-item-listening" href="${item.contact.fb}" target="_blank" style="--data-img: url('https://autoduo.click/assets/client/facebook-icon.png')"></a>
  105. </div>
  106. </div>
  107. `).join('')}
  108. </div>
  109. <footer>
  110. <button class="autoduo-btn btn-red close-contact-modal">CLOSE</button>
  111. </footer>
  112. </div>
  113. `
  114. })
  115.  
  116. const closeModalBtn = this.contactModal.querySelector('.close-contact-modal')
  117. closeModalBtn.addEventListener('click', () => {
  118. this.contactModal.remove()
  119. })
  120. },
  121.  
  122. initPopup: function () {
  123. this.updateGuidePopup = document.createElement("div");
  124. Object.assign(this.updateGuidePopup, {
  125. className: "update-guide-popup",
  126. innerHTML: `
  127. <div class="guide-popup-main">
  128. <h2 class="guide-popup-title">AUTO GUIDE</h2>
  129. <div class="guide-popup-content">
  130. <p class="guide-popup-text" style="color: rgb(0,159,235); margin-bottom: 24px">
  131. This is a lite version of AutoDuo with the main feature of automatically farming listening exercises (requires Super Duolingo). To use auto, follow the steps below:
  132. </p>
  133. <p class="guide-popup-text">
  134. <b>Step 1:</b> Go to the Super workout page (with the dumbbell icon).
  135. </p>
  136. <p class="guide-popup-text">
  137. <b>Step 2</b>: Press the "Start Farm XP" button to start the automatic farming process!.
  138. </p>
  139. <i style="font-size: 13px; margin-top: 12px; line-height: 1.3; display: inline-block"><b style="color: #ff5555">Note: </b>Super Duolingo is required to use this version. If you want to auto or use all the other useful features without Super, click to watch the video tutorial!</i>
  140. <div class="guide-popup-btn">
  141. <button class="autoduo-btn popup-btn-close"><span>Close</span></button>
  142. <a class="autoduo-btn btn-green popup-btn-access" href="https://autoduo.click/l/tutorial/" target="_blank">
  143. <span>Watch tutorial</span>
  144. </a>
  145. </div>
  146. </div>
  147. </div>
  148. `,
  149. });
  150.  
  151. const closePopupBtn = this.updateGuidePopup.querySelector(".popup-btn-close");
  152. this.watchTutorial = this.updateGuidePopup.querySelector(".popup-btn-access");
  153. closePopupBtn.addEventListener("click", () => {
  154. document.body.contains(this.updateGuidePopup) && this.updateGuidePopup.remove();
  155. });
  156. },
  157.  
  158. initBtn: function () {
  159. this.autoBtn = document.createElement("button");
  160. Object.assign(this.autoBtn, {
  161. className: "autoduo-btn btn-green auto-farm-btn-listening",
  162. innerText: "START FARM XP",
  163. onclick: () => {
  164. this.isAuto ? this.stop() : this.start();
  165. },
  166. });
  167.  
  168. this.updateBtn = document.createElement("button");
  169. Object.assign(this.updateBtn, {
  170. className: "autoduo-btn guide-btn-listening",
  171. innerText: "Instructions for use",
  172. onclick: () => {
  173. this.isAuto && this.stop();
  174. document.body.appendChild(this.updateGuidePopup);
  175. },
  176. });
  177.  
  178. this.showHideBtn = document.createElement("button");
  179. Object.assign(this.showHideBtn, {
  180. className: "show-hide-listening",
  181. style: `--data-version: 'V${this.version}'`,
  182. innerHTML: "<i></i>",
  183. });
  184.  
  185. this.showHideBtn.addEventListener("click", () => {
  186. this.isShowUI = !this.isShowUI;
  187. this.handleShowHideUI(true);
  188. });
  189. document.body.append(this.showHideBtn);
  190. },
  191.  
  192. initBubbles: function () {
  193. this.notifyBubble = document.createElement("button");
  194. Object.assign(this.notifyBubble, {
  195. className: "bubble-item-listening notify-bubble-listening",
  196. title: "Notification",
  197. });
  198.  
  199. this.superBubble = document.createElement("a");
  200. Object.assign(this.superBubble, {
  201. className: "bubble-item-listening super-bubble-listening",
  202. title: "Duolingo Super Free",
  203. href: "https://t.me/duolingosuperfree",
  204. target: "_blank",
  205. });
  206.  
  207. this.marketerBubble = document.createElement("a");
  208. Object.assign(this.marketerBubble, {
  209. className: "bubble-item-listening full-bubble-listening",
  210. title: "AutoDuo Full Version",
  211. href: "https://autoduo.click/l/upgrade/",
  212. target: "_blank",
  213. });
  214. },
  215.  
  216. initStatistics: function () {
  217. this.statistic = document.createElement("div");
  218. this.keyTypeElm = document.createElement("p");
  219. this.expElm = document.createElement("p");
  220. this.dateElm = document.createElement("p");
  221. const statisticWrapper = document.createElement("div");
  222.  
  223. Object.assign(this.keyTypeElm, {
  224. className: "key-type-listening",
  225. innerHTML: "<b style='color: #009feb'>Auto-Duolingo Lite</b>",
  226. });
  227.  
  228. this.expElm.className = "total-exp-listening";
  229. this.expElm.innerText = this.exp;
  230. this.statistic.className = "statistic-listening";
  231. this.dateElm.className = "time-listening";
  232. statisticWrapper.className = "statistic-wrapper-listening";
  233.  
  234. statisticWrapper.append(this.expElm, this.dateElm);
  235. this.statistic.append(this.keyTypeElm, statisticWrapper);
  236. },
  237.  
  238. initFunctions: function () {
  239. this.animationOffWrapper = document.createElement("div");
  240. this.animationOffWrapper.style = `--data-name: "Hide Animation"`;
  241. const animationOffInfo =
  242. "HIDE ANIMATION MODE:\n" +
  243. "- When this mode is enabled, images and animations on the website will be hidden to optimize performance.\n\n" +
  244. "Suggestion: To achieve the best performance, you should find and disable items related to effects in Duolingo's settings!";
  245. this.autoduoCreateSwitch(
  246. animationOffInfo,
  247. this.animationOffWrapper,
  248. 1,
  249. this.isAnimationOff,
  250. (setSwitch) => {
  251. this.isAnimationOff = !this.isAnimationOff;
  252. this.handleAnimationOff(true);
  253. setSwitch(this.isAnimationOff);
  254. }
  255. );
  256.  
  257. this.safeModeWrapper = document.createElement("div");
  258. this.safeModeWrapper.style = `--data-name: "Safe Mode"`;
  259. const safeModeInfo =
  260. "SAFE MODE:\n" +
  261. "- When this mode is enabled, the system will simulate user actions when using auto. The speed will be more relaxed, " +
  262. "in exchange for the completion time of lessons and the amount of experience will be the most natural, minimizing " +
  263. "the risks of REPORT and account BAN!";
  264. this.autoduoCreateSwitch(safeModeInfo, this.safeModeWrapper, 2, this.isSafeMode, () => {
  265. this.isSafeMode ? this.handleSafeModeOff() : this.handleSafeModeOn();
  266. });
  267.  
  268. this.turboModeWrapper = document.createElement("div");
  269. this.turboModeWrapper.style = `--data-name: "Turbo Mode"`;
  270. const turboModeInfo =
  271. "TURBO MODE:\n" +
  272. "- When enabled, the system will significantly boost the auto speed. It will utilize higher performance and " +
  273. "is not recommended for use on low-performance devices.\n- Turn it off and refresh the page if you encounter " +
  274. "issues while activating this mode!\n\n- Note: This is an experimental feature and requires a VIP Key to use. " +
  275. "Only enable it when you truly require speed and understand its implications!!";
  276. this.autoduoCreateSwitch(turboModeInfo, this.turboModeWrapper, 4, false);
  277.  
  278. this.legendModeWrapper = document.createElement("div");
  279. this.legendModeWrapper.style = `--data-name: "Lesson Pass Mode"`;
  280. const legendModeInfo =
  281. "LESSON PASS MODE:\n" +
  282. "- When activated, the system won't repeat exercises as in the regular mode but will engage in exercises actively selected by the user. " +
  283. "This mode is used for legendary exercises, story exercises, and most other similar exercises.\n- You need to enter the lesson you want to " +
  284. "pass in, and then the system will automatically complete that lesson for you!\n" +
  285. "- When this mode is activated, the basic auto button will be temporarily disabled.";
  286. this.autoduoCreateSwitch(legendModeInfo, this.legendModeWrapper, 5, false);
  287.  
  288. this.targetModeWrapper = document.createElement("div");
  289. this.targetModeWrapper.style = `--data-name: "XP Target Mode"`;
  290. const targetModeInfo =
  291. "EXPERIENCE POINT TARGET MODE:\n" +
  292. "- By setting an experience point target, the system will automatically stop auto mode when the total experience points " +
  293. "obtained equal or exceed the specified target.\n- This helps you better control the auto function, " +
  294. "preventing unintentional accumulation of excess experience points due to forgetting to turn off auto mode!\n\n" +
  295. "- Note: The experience point target must be greater than the current amount of experience points obtained through auto mode!";
  296. this.autoduoCreateSwitch(targetModeInfo, this.targetModeWrapper, 6, false);
  297.  
  298. this.passModeWrapper = document.createElement("div");
  299. this.passModeWrapper.style = `--data-name: "Auto Pass Mode"`;
  300. const passModeInfo =
  301. "AUTO PASS MODE:\n" +
  302. "- By setting the number of lessons you wish to pass, the system will automatically pass the corresponding " +
  303. "number of new lessons as per the value you've set!\n\n" +
  304. "- Note: the lesson value should be within the range of 1 - 1000 (Enter 0 for unlimited auto)!";
  305. this.autoduoCreateSwitch(passModeInfo, this.passModeWrapper, 7, false);
  306.  
  307. this.darkModeWrapper = document.createElement("div");
  308. this.darkModeWrapper.style = `--data-name: "Dark Mode"`;
  309. const darkModeInfo = "DARK MODE\n- Enable/disable website dark mode faster!";
  310. this.autoduoCreateSwitch(darkModeInfo, this.darkModeWrapper, 3, this.isDarkMode, (setSwitch) => {
  311. this.isDarkMode = !this.isDarkMode;
  312. const [theme, value, css] = this.isDarkMode
  313. ? ["dark", "on", "--app-offset: 0px; --color-snow: 19, 31, 36; --color-snow-always-light: 255, 255, 255; --color-snow-always-dark: 19, 31, 36; --color-polar: 32, 47, 54; --color-swan: 55, 70, 79; --color-swan-always-light: 229, 229, 229; --color-swan-always-dark: 55, 70, 79; --color-hare: 82, 101, 109; --color-hare-always-light: 175, 175, 175; --color-wolf: 220, 230, 236; --color-eel: 241, 247, 251; --color-squid: 235, 227, 227; --color-walking-fish: 32, 47, 54; --color-flamingo: 148, 81, 81; --color-pig: 245, 164, 164; --color-crab: 255, 120, 120; --color-cardinal: 238, 85, 85; --color-fire-ant: 216, 72, 72; --color-canary: 32, 47, 54; --color-duck: 251, 229, 109; --color-bee: 255, 199, 0; --color-bee-always-dark: 255, 199, 0; --color-lion: 255, 177, 0; --color-fox: 255, 171, 51; --color-cheetah: 32, 47, 54; --color-monkey: 229, 162, 89; --color-camel: 231, 166, 1; --color-guinea-pig: 215, 148, 51; --color-grizzly: 187, 113, 73; --color-sea-sponge: 32, 47, 54; --color-turtle: 95, 132, 40; --color-owl: 147, 211, 51; --color-tree-frog: 121, 185, 51; --color-peacock: 0, 205, 156; --color-iguana: 32, 47, 54; --color-anchovy: 210, 228, 232; --color-beluga: 187, 242, 255; --color-moon-jelly: 122, 240, 242; --color-blue-jay: 63, 133, 167; --color-macaw: 73, 192, 248; --color-whale: 24, 153, 214; --color-humpback: 43, 112, 201; --color-narwhal: 20, 83, 163; --color-manta-ray: 4, 44, 96; --color-starfish: 255, 134, 208; --color-beetle: 206, 130, 255; --color-betta: 144, 105, 205; --color-butterfly: 111, 78, 161; --color-dragon: 204, 52, 141; --color-starling: 92, 108, 252; --color-martin: 71, 85, 223; --color-grackle: 167, 160, 255; --color-honeycreeper: 193, 187, 255; --color-deep-starling: 34, 33, 81; --color-deep-martin: 16, 15, 62; --color-legendary-foreground: 140, 65, 3; --color-stardust: 199, 255, 254; --color-cosmos: 60, 77, 255; --color-nebula: 63, 34, 236; --color-nova: 207, 23, 200; --color-gamma: 38, 246, 99; --color-starlight: 38, 138, 255; --color-quasar: 252, 85, 255; --color-celestia: 255, 255, 255; --color-eclipse: 0, 4, 55; --color-black: 0, 0, 0; --color-aqua: 43, 164, 176; --color-aqua-always-light: 56, 238, 255; --color-ocean: 56, 238, 255; --color-seafoam: 30, 89, 97; --color-ice: 23, 52, 58; --color-max-shadow: 20, 208, 225; --color-black-white: 255, 255, 255; --color-diamond-stat: 86, 219, 226; --color-mask-green: 144, 220, 72; --color-pearl-stat: 255, 170, 222; --color-snow-dark-swan: 55, 70, 79; --color-black-text: 241, 247, 251; --color-blue-space: 11, 62, 113; --color-juicy-blue-space: 10, 74, 130; --color-juicy-blue-space-light: 35, 83, 144; --color-gold: 250, 169, 25; --color-gray-text: 220, 230, 236; --color-orange: 255, 157, 0; --color-diamond-highlight: 231, 251, 251; --color-diamond: 56, 208, 208; --color-banana: 255, 176, 32; --color-cloud: 207, 207, 207; --color-cloud-light: 221, 221, 221; --color-cloud-lightest: 240, 240, 240; --color-kiwi: 122, 199, 12; --color-kiwi-dark: 93, 151, 9; --color-kiwi-light: 142, 224, 0; --color-facebook: 59, 89, 152; --color-facebook-dark: 45, 67, 115; --color-google: 66, 133, 244; --color-twitter: 29, 161, 242; --color-hv-light-peach: 241, 218, 179; --color-hv-peach: 219, 186, 131; --color-hv-light-orange: 255, 177, 64; --color-hv-orange: 204, 121, 0; --color-hv-brown: 140, 90, 17; --color-streak-panel-extended-background: 205, 121, 0; --color-streak-panel-frozen-background: 43, 112, 201; --color-streak-panel-frozen-flair-background: 73, 192, 248; --color-streak-panel-frozen-subtitle: 255, 255, 255; --color-streak-panel-frozen-text: 255, 255, 255; --color-streak-panel-frozen-topbar-text: 255, 255, 255; --color-streak-panel-streak-society-background: 215, 148, 51; --color-streak-panel-streak-society-text: 255, 255, 255; --color-streak-panel-unextended-heading-text: 82, 101, 109; --color-streak-panel-unextended-heading-background: 32, 47, 54; --color-streak-panel-unextended-topbar-text: 255, 255, 255; --color-streak-panel-milestone-gradient-start: 255, 147, 58; --color-streak-panel-milestone-gradient-end: 255, 200, 0; --color-streak-society-dark-orange: 255, 151, 1; --color-streak-society-light-orange: 255, 179, 1; --color-friends-quest-own-incomplete: 111, 139, 157; --color-friends-quest-friend-incomplete: 79, 100, 113; --color-black-text-always-light: 60, 60, 60; --color-cardinal-always-light: 255, 75, 75; --color-cowbird: 174, 104, 2; --color-eel-always-light: 75, 75, 75; --color-fox-always-light: 255, 150, 0; --color-fire-ant-always-light: 234, 43, 43; --color-grizzly-lite: 220, 143, 71; --color-guinea-pig-always-light: 205, 121, 0; --color-iguana-always-light: 221, 244, 255; --color-macaw-always-light: 28, 176, 246; --color-owl-always-light: 88, 204, 2; --color-polar-always-light: 247, 247, 247; --color-sea-sponge-always-light: 215, 255, 184; --color-tree-frog-always-light: 88, 167, 0; --color-turtle-always-light: 165, 237, 110; --color-walking-fish-always-light: 255, 223, 224; --color-wolf-always-light: 119, 119, 119; --color-cardinal-always-dark: 238, 85, 85; --color-eel-always-dark: 241, 247, 251; --color-hare-always-dark: 82, 101, 109; --color-macaw-always-dark: 73, 192, 248; --color-owl-always-dark: 147, 211, 51; --color-polar-always-dark: 32, 47, 54; --color-wolf-always-dark: 220, 230, 236; --color-rookie: 0, 175, 133; --color-explorer: 255, 100, 191; --color-traveler: 255, 145, 83; --color-trailblazer: 154, 143, 232; --color-adventurer: 96, 12, 199; --color-discoverer: 111, 44, 57; --color-daredevil: 46, 83, 138; --color-navigator: 9, 47, 119; --color-champion: 255, 110, 53; --color-daily_refresh: 0, 148, 255; --color-dark-mode-locked-path-section-text-color: 82, 101, 109; --color-rookie-progress-bar: 0, 198, 150; --color-explorer-progress-bar: 255, 138, 207; --color-traveler-progress-bar: 255, 167, 106; --color-trailblazer-progress-bar: 169, 157, 254; --color-adventurer-progress-bar: 122, 13, 199; --color-discoverer-progress-bar: 131, 50, 65; --color-daredevil-progress-bar: 54, 98, 165; --color-navigator-progress-bar: 12, 57, 141; --color-champion-progress-bar: 255, 129, 80; --color-daily_refresh-progress-bar: 28, 160, 255; --color-course-complete-cta: 120, 219, 224; --color-course-complete-cta-border: 94, 201, 204; --color-bea-secondary: 24, 153, 214; --color-eddy-secondary: 234, 43, 43; --color-gilded-secondary: 231, 166, 1; --color-lily-secondary: 165, 104, 204; --color-vikram-secondary: 163, 42, 113; --color-zari-secondary: 204, 107, 166; --color-oscar-secondary: 0, 164, 125; --color-falstaff-secondary: 150, 90, 58; --color-bea-radio: 20, 123, 172; --color-duo-radio: 62, 143, 1; --color-eddy-radio: 179, 53, 53; --color-falstaff-radio: 131, 79, 51; --color-lin-lucy-radio: 179, 105, 0; --color-lily-radio: 144, 91, 179; --color-vikram-radio: 143, 36, 99; --color-zari-radio: 179, 94, 146; --color-oscar-radio: 0, 144, 109; --color-bea-junior-shine: 67, 190, 248; --color-duo-shine: 114, 214, 39; --color-eddy-shine: 255, 105, 105; --color-falstaff-shine: 227, 165, 108; --color-lily-shine: 214, 150, 255; --color-lin-lucy-shine: 255, 168, 44; --color-oscar-shine: 63, 217, 181; --color-vikram-shine: 214, 90, 162; --color-zari-shine: 255, 158, 217; --color-super-background-secondary: 26, 30, 76; --color-super-gradient-background: 12, 47, 113; --color-super-gradient-top-halo: 12, 76, 70; --color-super-gradient-bottom-halo: 76, 29, 115; --color-gold-shine: 255, 231, 0; --color-legendary-dark-background: 24, 24, 24; --color-roseate: 223, 75, 162; --color-rosefinch: 180, 28, 117; --color-bluebird: 3, 144, 211; --color-cotinga: 121, 58, 227; --color-sabrewing: 165, 112, 255; --color-blueberry: 17, 82, 167; --color-ether: 60, 89, 141; --color-diamond-tournament-purple: 161, 161, 238; --color-diamond-tournament-reaction: 118, 163, 231; --color-yir-page0: 221, 244, 255; --color-yir-page1: 227, 255, 235; --color-yir-page1-shadow: 19, 31, 36; --color-yir-page3-shadow: 187, 172, 252; --color-yir-page4-shadow: 143, 219, 255; --color-yir-page5-shadow: 255, 183, 80; --color-super-gradient-green-variant1: 38, 255, 85; --color-super-gradient-blue-variant1: 38, 139, 255; --color-super-gradient-pink-variant1: 252, 85, 255; --color-super-gradient-purple-variant1: 17, 34, 181; --color-unknown-001e2d: 0, 30, 45; --color-unknown-0047a4: 0, 71, 164; --color-unknown-0087d0: 0, 135, 208; --color-unknown-00aff9: 0, 175, 249; --color-unknown-013047: 1, 48, 71; --color-unknown-048fd1: 4, 143, 209; --color-unknown-0e0f10: 14, 15, 16; --color-unknown-0e3d79: 14, 61, 121; --color-unknown-172071: 23, 32, 113; --color-unknown-280378: 40, 3, 120; --color-unknown-3ebbf6: 62, 187, 246; --color-unknown-655ebb: 101, 94, 187; --color-unknown-696cee: 105, 108, 238; --color-unknown-7c0000: 124, 0, 0; --color-unknown-89e219: 137, 226, 25; --color-unknown-935051: 147, 80, 81; --color-unknown-959595: 149, 149, 149; --color-unknown-a2a2a2: 162, 162, 162; --color-unknown-a3dbeb: 163, 219, 235; --color-unknown-a4dffb: 164, 223, 251; --color-unknown-aaa: 170, 170, 170; --color-unknown-d087ff: 208, 135, 255; --color-unknown-d9d9d9: 217, 217, 217; --color-unknown-ddd: 221, 221, 221; --color-unknown-de8029: 222, 128, 41; --color-unknown-e3e3e3: 227, 227, 227; --color-unknown-e4ffff: 228, 255, 255; --color-unknown-ed8c01: 237, 140, 1; --color-unknown-f3484e: 243, 72, 78; --color-unknown-f4fafe: 244, 250, 254; --color-unknown-fbdec5: 251, 222, 197; --color-unknown-ffc700: 255, 199, 0; --color-unknown-fff2aa: 255, 242, 170; --color-unknown-fffbef: 255, 251, 239;"]
  314. : ["light", "off", "--app-offset: 0px; --color-snow: 255, 255, 255; --color-snow-always-light: 255, 255, 255; --color-snow-always-dark: 19, 31, 36; --color-polar: 247, 247, 247; --color-swan: 229, 229, 229; --color-swan-always-light: 229, 229, 229; --color-swan-always-dark: 55, 70, 79; --color-hare: 175, 175, 175; --color-hare-always-light: 175, 175, 175; --color-wolf: 119, 119, 119; --color-eel: 75, 75, 75; --color-squid: 235, 227, 227; --color-walking-fish: 255, 223, 224; --color-flamingo: 255, 178, 178; --color-pig: 245, 164, 164; --color-crab: 255, 120, 120; --color-cardinal: 255, 75, 75; --color-fire-ant: 234, 43, 43; --color-canary: 255, 245, 211; --color-duck: 251, 229, 109; --color-bee: 255, 200, 0; --color-bee-always-dark: 255, 199, 0; --color-lion: 255, 177, 0; --color-fox: 255, 150, 0; --color-cheetah: 255, 206, 142; --color-monkey: 229, 162, 89; --color-camel: 231, 166, 1; --color-guinea-pig: 205, 121, 0; --color-grizzly: 187, 113, 73; --color-sea-sponge: 215, 255, 184; --color-turtle: 165, 237, 110; --color-owl: 88, 204, 2; --color-tree-frog: 88, 167, 0; --color-peacock: 0, 205, 156; --color-iguana: 221, 244, 255; --color-anchovy: 210, 228, 232; --color-beluga: 187, 242, 255; --color-moon-jelly: 122, 240, 242; --color-blue-jay: 132, 216, 255; --color-macaw: 28, 176, 246; --color-whale: 24, 153, 214; --color-humpback: 43, 112, 201; --color-narwhal: 20, 83, 163; --color-manta-ray: 4, 44, 96; --color-starfish: 255, 134, 208; --color-beetle: 206, 130, 255; --color-betta: 144, 105, 205; --color-butterfly: 111, 78, 161; --color-dragon: 204, 52, 141; --color-starling: 92, 108, 252; --color-martin: 71, 85, 223; --color-grackle: 167, 160, 255; --color-honeycreeper: 193, 187, 255; --color-deep-starling: 34, 33, 81; --color-deep-martin: 16, 15, 62; --color-legendary-foreground: 140, 65, 3; --color-stardust: 199, 255, 254; --color-cosmos: 60, 77, 255; --color-nebula: 63, 34, 236; --color-nova: 207, 23, 200; --color-gamma: 38, 246, 99; --color-starlight: 38, 138, 255; --color-quasar: 252, 85, 255; --color-celestia: 255, 255, 255; --color-eclipse: 0, 4, 55; --color-black: 0, 0, 0; --color-aqua: 56, 238, 255; --color-aqua-always-light: 56, 238, 255; --color-ocean: 0, 124, 143; --color-seafoam: 158, 224, 233; --color-ice: 225, 253, 255; --color-max-shadow: 20, 208, 225; --color-black-white: 0, 0, 0; --color-diamond-stat: 86, 219, 226; --color-mask-green: 137, 226, 25; --color-pearl-stat: 255, 170, 222; --color-snow-dark-swan: 255, 255, 255; --color-black-text: 60, 60, 60; --color-blue-space: 11, 62, 113; --color-juicy-blue-space: 10, 74, 130; --color-juicy-blue-space-light: 35, 83, 144; --color-gold: 250, 169, 25; --color-gray-text: 153, 153, 153; --color-orange: 255, 157, 0; --color-diamond-highlight: 231, 251, 251; --color-diamond: 56, 208, 208; --color-banana: 255, 176, 32; --color-cloud: 207, 207, 207; --color-cloud-light: 221, 221, 221; --color-cloud-lightest: 240, 240, 240; --color-kiwi: 122, 199, 12; --color-kiwi-dark: 93, 151, 9; --color-kiwi-light: 142, 224, 0; --color-facebook: 59, 89, 152; --color-facebook-dark: 45, 67, 115; --color-google: 66, 133, 244; --color-twitter: 29, 161, 242; --color-hv-light-peach: 241, 218, 179; --color-hv-peach: 219, 186, 131; --color-hv-light-orange: 255, 177, 64; --color-hv-orange: 204, 121, 0; --color-hv-brown: 140, 90, 17; --color-streak-panel-extended-background: 255, 150, 0; --color-streak-panel-frozen-background: 221, 244, 255; --color-streak-panel-frozen-flair-background: 132, 216, 255; --color-streak-panel-frozen-subtitle: 28, 176, 246; --color-streak-panel-frozen-text: 132, 216, 255; --color-streak-panel-frozen-topbar-text: 24, 153, 214; --color-streak-panel-streak-society-background: 255, 200, 0; --color-streak-panel-streak-society-text: 205, 121, 0; --color-streak-panel-unextended-heading-text: 235, 195, 127; --color-streak-panel-unextended-heading-background: 255, 245, 211; --color-streak-panel-unextended-topbar-text: 235, 195, 127; --color-streak-panel-milestone-gradient-start: 255, 147, 58; --color-streak-panel-milestone-gradient-end: 255, 200, 0; --color-streak-society-dark-orange: 255, 151, 1; --color-streak-society-light-orange: 255, 179, 1; --color-friends-quest-own-incomplete: 175, 175, 175; --color-friends-quest-friend-incomplete: 145, 145, 145; --color-black-text-always-light: 60, 60, 60; --color-cardinal-always-light: 255, 75, 75; --color-cowbird: 174, 104, 2; --color-eel-always-light: 75, 75, 75; --color-fox-always-light: 255, 150, 0; --color-fire-ant-always-light: 234, 43, 43; --color-grizzly-lite: 220, 143, 71; --color-guinea-pig-always-light: 205, 121, 0; --color-iguana-always-light: 221, 244, 255; --color-macaw-always-light: 28, 176, 246; --color-owl-always-light: 88, 204, 2; --color-polar-always-light: 247, 247, 247; --color-sea-sponge-always-light: 215, 255, 184; --color-tree-frog-always-light: 88, 167, 0; --color-turtle-always-light: 165, 237, 110; --color-walking-fish-always-light: 255, 223, 224; --color-wolf-always-light: 119, 119, 119; --color-cardinal-always-dark: 238, 85, 85; --color-eel-always-dark: 241, 247, 251; --color-hare-always-dark: 82, 101, 109; --color-macaw-always-dark: 73, 192, 248; --color-owl-always-dark: 147, 211, 51; --color-polar-always-dark: 32, 47, 54; --color-wolf-always-dark: 220, 230, 236; --color-rookie: 0, 175, 133; --color-explorer: 255, 100, 191; --color-traveler: 255, 145, 83; --color-trailblazer: 154, 143, 232; --color-adventurer: 96, 12, 199; --color-discoverer: 111, 44, 57; --color-daredevil: 46, 83, 138; --color-navigator: 9, 47, 119; --color-champion: 255, 110, 53; --color-daily_refresh: 0, 148, 255; --color-dark-mode-locked-path-section-text-color: 82, 101, 109; --color-rookie-progress-bar: 0, 198, 150; --color-explorer-progress-bar: 255, 138, 207; --color-traveler-progress-bar: 255, 167, 106; --color-trailblazer-progress-bar: 169, 157, 254; --color-adventurer-progress-bar: 122, 13, 199; --color-discoverer-progress-bar: 131, 50, 65; --color-daredevil-progress-bar: 54, 98, 165; --color-navigator-progress-bar: 12, 57, 141; --color-champion-progress-bar: 255, 129, 80; --color-daily_refresh-progress-bar: 28, 160, 255; --color-course-complete-cta: 120, 219, 224; --color-course-complete-cta-border: 94, 201, 204; --color-bea-secondary: 24, 153, 214; --color-eddy-secondary: 234, 43, 43; --color-gilded-secondary: 231, 166, 1; --color-lily-secondary: 165, 104, 204; --color-vikram-secondary: 163, 42, 113; --color-zari-secondary: 204, 107, 166; --color-oscar-secondary: 0, 164, 125; --color-falstaff-secondary: 150, 90, 58; --color-bea-radio: 20, 123, 172; --color-duo-radio: 62, 143, 1; --color-eddy-radio: 179, 53, 53; --color-falstaff-radio: 131, 79, 51; --color-lin-lucy-radio: 179, 105, 0; --color-lily-radio: 144, 91, 179; --color-vikram-radio: 143, 36, 99; --color-zari-radio: 179, 94, 146; --color-oscar-radio: 0, 144, 109; --color-bea-junior-shine: 67, 190, 248; --color-duo-shine: 114, 214, 39; --color-eddy-shine: 255, 105, 105; --color-falstaff-shine: 227, 165, 108; --color-lily-shine: 214, 150, 255; --color-lin-lucy-shine: 255, 168, 44; --color-oscar-shine: 63, 217, 181; --color-vikram-shine: 214, 90, 162; --color-zari-shine: 255, 158, 217; --color-super-background-secondary: 26, 30, 76; --color-super-gradient-background: 12, 47, 113; --color-super-gradient-top-halo: 12, 76, 70; --color-super-gradient-bottom-halo: 76, 29, 115; --color-gold-shine: 255, 231, 0; --color-legendary-dark-background: 24, 24, 24; --color-roseate: 223, 75, 162; --color-rosefinch: 180, 28, 117; --color-bluebird: 3, 144, 211; --color-cotinga: 121, 58, 227; --color-sabrewing: 165, 112, 255; --color-blueberry: 17, 82, 167; --color-ether: 60, 89, 141; --color-diamond-tournament-purple: 161, 161, 238; --color-diamond-tournament-reaction: 118, 163, 231; --color-yir-page0: 221, 244, 255; --color-yir-page1: 227, 255, 235; --color-yir-page1-shadow: 19, 31, 36; --color-yir-page3-shadow: 187, 172, 252; --color-yir-page4-shadow: 143, 219, 255; --color-yir-page5-shadow: 255, 183, 80; --color-super-gradient-green-variant1: 38, 255, 85; --color-super-gradient-blue-variant1: 38, 139, 255; --color-super-gradient-pink-variant1: 252, 85, 255; --color-super-gradient-purple-variant1: 17, 34, 181; --color-unknown-001e2d: 0, 30, 45; --color-unknown-0047a4: 0, 71, 164; --color-unknown-0087d0: 0, 135, 208; --color-unknown-00aff9: 0, 175, 249; --color-unknown-013047: 1, 48, 71; --color-unknown-048fd1: 4, 143, 209; --color-unknown-0e0f10: 14, 15, 16; --color-unknown-0e3d79: 14, 61, 121; --color-unknown-172071: 23, 32, 113; --color-unknown-280378: 40, 3, 120; --color-unknown-3ebbf6: 62, 187, 246; --color-unknown-655ebb: 101, 94, 187; --color-unknown-696cee: 105, 108, 238; --color-unknown-7c0000: 124, 0, 0; --color-unknown-89e219: 137, 226, 25; --color-unknown-935051: 147, 80, 81; --color-unknown-959595: 149, 149, 149; --color-unknown-a2a2a2: 162, 162, 162; --color-unknown-a3dbeb: 163, 219, 235; --color-unknown-a4dffb: 164, 223, 251; --color-unknown-aaa: 170, 170, 170; --color-unknown-d087ff: 208, 135, 255; --color-unknown-d9d9d9: 217, 217, 217; --color-unknown-ddd: 221, 221, 221; --color-unknown-de8029: 222, 128, 41; --color-unknown-e3e3e3: 227, 227, 227; --color-unknown-e4ffff: 228, 255, 255; --color-unknown-ed8c01: 237, 140, 1; --color-unknown-f3484e: 243, 72, 78; --color-unknown-f4fafe: 244, 250, 254; --color-unknown-fbdec5: 251, 222, 197; --color-unknown-ffc700: 255, 199, 0; --color-unknown-fff2aa: 255, 242, 170; --color-unknown-fffbef: 255, 251, 239;"];
  315.  
  316. document.documentElement.setAttribute("data-duo-theme", theme);
  317. document.documentElement.setAttribute("style", css);
  318.  
  319. const darkModeDataLocal = getLocal("duo.darkMode")
  320. for(const key in darkModeDataLocal){
  321. darkModeDataLocal[key] = value
  322. }
  323.  
  324. localStorage.setItem("duo.darkMode", JSON.stringify(darkModeDataLocal));
  325. setSwitch(this.isDarkMode);
  326. });
  327.  
  328. this.farmingLocationWrapper = document.createElement("div");
  329. this.farmingLocationWrapper.style = `--data-name: "Set XP Farm Location"`;
  330. const farmingLocationInfo =
  331. "SET XP FARM LOCATION\n" +
  332. "- By default, the system can only Farm XP in practice exercises or listening practices. However, with this feature, you can Farm XP " +
  333. "in any lesson you want, even in story lessons!\n" +
  334. "- Usage: Activate the feature and enter the URL of the lesson you want, then enable the XP Farm mode to start farming.\n" +
  335. "- NOTE: The URL to the lesson must be accurate and the lesson must be repeatable. Entering an inaccurate URL may lead " +
  336. "to errors or even pose risks to your account!";
  337. this.autoduoCreateSwitch(farmingLocationInfo, this.farmingLocationWrapper, 8, false);
  338.  
  339. this.autoX2Wrapper = document.createElement("div");
  340. this.autoX2Wrapper.style = `--data-name: "Auto Collect x2 XP"`;
  341. const autoX2Info =
  342. "AUTO COLLECT X2 XP:\n" +
  343. '- This is a supplementary feature for "Auto Farm KN", helping to maintain the x2 KN status during farming. When enabled, ' +
  344. "it will check and automatically do new lessons to get x2 KN rewards if it detects the current state doesn't have x2. " +
  345. "This will help you farm more KN points than usual. \n\n- NOTE: This feature will do new lessons to maintain the x2 status, so " +
  346. "consider before enabling it if you have constraints with these lessons.";
  347. this.autoduoCreateSwitch(autoX2Info, this.autoX2Wrapper, 8, false);
  348.  
  349. this.functionWrapper = document.createElement("div");
  350. this.functionWrapper.className = "function-wrapper-listening";
  351. this.functionWrapper.append(
  352. this.darkModeWrapper,
  353. this.animationOffWrapper,
  354. this.safeModeWrapper,
  355. this.turboModeWrapper
  356. );
  357. },
  358.  
  359. initSetting: function () {
  360. this.settingBtn = document.createElement("button");
  361. Object.assign(this.settingBtn, {
  362. className: "autoduo-btn setting-btn-listening",
  363. innerText: "Other settings",
  364. });
  365. this.settingBtn.addEventListener("click", () => {
  366. this.controlContainer.contains(this.settingOverlay) ||
  367. this.controlContainer.appendChild(this.settingOverlay);
  368. });
  369.  
  370. this.closeSettingBtn = document.createElement("button");
  371. Object.assign(this.closeSettingBtn, {
  372. className: "autoduo-btn close-setting-btn-listening",
  373. innerText: "Close",
  374. });
  375. this.closeSettingBtn.addEventListener("click", () => {
  376. this.controlContainer.contains(this.settingOverlay) &&
  377. this.controlContainer.removeChild(this.settingOverlay);
  378. });
  379.  
  380. this.settingOverlay = document.createElement("div");
  381. Object.assign(this.settingOverlay, {
  382. className: "setting-overlay-listening",
  383. innerHTML: `
  384. <h3>Other settings</h3>
  385. `,
  386. });
  387.  
  388. this.settingFunction = document.createElement("div");
  389. this.settingFunction.className = "setting-function-listening";
  390. this.settingFunction.append(
  391. this.legendModeWrapper,
  392. this.passModeWrapper,
  393. this.targetModeWrapper,
  394. this.farmingLocationWrapper,
  395. this.autoX2Wrapper
  396. );
  397.  
  398. this.settingOverlay.append(this.settingFunction, this.closeSettingBtn);
  399. },
  400.  
  401. initContainer: function () {
  402. this.footerContainer = document.createElement('div')
  403. this.footerContainer.className = 'footer-container'
  404. this.autoduoPowered = document.createElement('div')
  405. Object.assign(this.autoduoPowered, {
  406. className: 'autoduo-powered',
  407. innerHTML: `Powered by <a href="https://autoduo.click" target="_blank">🔥autoduo.click</a>`
  408. })
  409. this.contactBtn = document.createElement('button')
  410. this.contactBtn.className = 'contact-btn'
  411. this.contactBtn.innerHTML = '<img src="https://autoduo.click/assets/client/headphone.png" style="margin: -4px 4px 0 0; width: 16px" /> SUPPORT'
  412. this.contactBtn.addEventListener('click', () => {
  413. document.body.appendChild(this.contactModal)
  414. })
  415. this.footerContainer.append(this.autoduoPowered, this.contactBtn)
  416.  
  417. this.autoContainer = document.createElement("div");
  418. this.autoContainer.className = "auto-container-listening";
  419. this.autoContainer.append(
  420. this.statistic,
  421. this.functionWrapper,
  422. this.settingBtn,
  423. this.autoBtn,
  424. this.updateBtn
  425. );
  426.  
  427. this.overlayContainer = document.createElement("div");
  428. this.overlayContainer.className = "overlay-listening";
  429.  
  430. this.controlContainer = document.createElement("div");
  431. this.controlContainer.className = "control-container-listening";
  432. this.controlContainer.append(this.autoContainer, this.contactWrapper, this.footerContainer);
  433.  
  434. this.bubbleContainer = document.createElement("div");
  435. this.bubbleContainer.className = "bubble-container-listening";
  436. this.bubbleContainer.append(this.marketerBubble, this.superBubble, this.notifyBubble);
  437.  
  438. document.body.append(this.controlContainer, this.bubbleContainer);
  439. },
  440.  
  441. fetchNoti: async function () {
  442. try {
  443. const res = await (
  444. await fetch("https://api.autoduo.click/super/data/notify/?c7f54a73e6340a16176=91bf0d18b83")
  445. )?.json();
  446. if (res?.code === 200) {
  447. const { notifyVersion: rmVersion, notifyContent: rmContent } = res.data[0];
  448. setDataSession({
  449. isNewNotify: (this.isNewNotify = +rmVersion > this.notifyVersion),
  450. rmNotiVer: (this.rmNotiVer = +rmVersion),
  451. rmNotiContent: (this.rmNotiContent = rmContent.replaceAll("\\n", "\n")),
  452. });
  453. this.setNoti();
  454. }
  455. } catch (e) {}
  456. },
  457.  
  458. setNoti: function () {
  459. if (!this.rmNotiVer) {
  460. return;
  461. }
  462. if (this.isNewNotify) {
  463. this.notifyBubble.classList.add("new");
  464. }
  465. this.notifyBubble.addEventListener("click", () => {
  466. if (this.isNewNotify) {
  467. this.notifyBubble.classList.remove("new");
  468. setDataSession("isNewNotify", (this.isNewNotify = false));
  469. setDataLocal("notifyVersion", this.rmNotiVer);
  470. }
  471. window.alert(this.rmNotiContent);
  472. });
  473. },
  474.  
  475. handleShowHideUI: function (isSave = false) {
  476. if (this.isShowUI) {
  477. this.showHideBtn.classList.remove("hide");
  478. document.body.append(this.controlContainer, this.signatureElm, this.bubbleContainer);
  479. } else {
  480. this.showHideBtn.classList.add("hide");
  481. this.controlContainer.remove();
  482. this.signatureElm.remove();
  483. this.bubbleContainer.remove();
  484. }
  485.  
  486. if (isSave) {
  487. setDataSession("isShowUI", this.isShowUI);
  488. this.controlContainer.classList.contains("autoduo-animate") ||
  489. this.controlContainer.classList.add("autoduo-animate");
  490. }
  491. },
  492.  
  493. handleAnimationOff: function (isSave = false) {
  494. this.isAnimationOff
  495. ? document.head.appendChild(this.animationStyle)
  496. : document.head.removeChild(this.animationStyle);
  497. isSave && setDataSession("isAnimationOff", this.isAnimationOff);
  498. },
  499.  
  500. handleSafeModeOn: function () {
  501. this.safeModeWrapper.setAutoduoSwitch(this.setSafeMode(true));
  502. },
  503.  
  504. handleSafeModeOff: function () {
  505. this.safeModeWrapper.setAutoduoSwitch(this.setSafeMode(false));
  506. },
  507.  
  508. start: function () {
  509. if (this.isAuto || this.isAutoRunning) {
  510. return;
  511. }
  512.  
  513. document.body.appendChild(this.overlayContainer);
  514. this.isAuto = true;
  515. this.autoBtn.classList.add("running");
  516. this.autoBtn.innerText = "STOP FARM XP";
  517. setDataSession("isBasicAuto", this.isAuto);
  518. this.startTm = Date.now();
  519. this.handleLocation();
  520. },
  521.  
  522. stop: function () {
  523. if (!this.isAuto || this.isLegendMode) {
  524. return;
  525. }
  526. document.body.removeChild(this.overlayContainer);
  527. this.isAuto = false;
  528. this.autoBtn.classList.remove("running");
  529. this.autoBtn.innerText = "START FARM XP";
  530. setDataSession("isBasicAuto", this.isAuto);
  531. },
  532.  
  533. handleLocation: function () {
  534. if (!this.isAuto) {
  535. return;
  536. }
  537.  
  538. const currentPath = window.location.pathname;
  539.  
  540. switch (currentPath) {
  541. case this.practiceHubPath:
  542. this.goPracticeHubChallenge();
  543. break;
  544.  
  545. case this.listeningPacticePath:
  546. this.handlePracticeHubChallenge();
  547. break;
  548.  
  549. default:
  550. this.autoduoError(
  551. "[Inappropriate location]: Only enable auto when on the practice page (with the dumbbell icon) of Duolingo Super!" +
  552. "\n- Enabling auto on Duolingo Super's practice page will automatically farm listening exercises (20 XP)." +
  553. "\n- Upgrade to the full version of Auto-Duolingo to use auto farming and many other useful features without needing Super Duolingo!"
  554. , true);
  555. break;
  556. }
  557. },
  558.  
  559. goPracticeHubChallenge: function () {
  560. if (this.isAuto === false) {
  561. return;
  562. }
  563. const challengeBtn = $(
  564. 'img[src="https://d35aaqx5ub95lt.cloudfront.net/images/practiceHub/2ebe830fd55a7f2754d371bcd79faf32.svg"]'
  565. );
  566.  
  567. if (!challengeBtn) {
  568. setTimeout(this.goPracticeHubChallenge.bind(this), 1000);
  569. return;
  570. }
  571.  
  572. challengeBtn.click();
  573. setTimeout(this.handlePracticeHubChallenge.bind(this), 1000);
  574. },
  575.  
  576. handlePracticeHubChallenge: function () {
  577. if (window.location.pathname === this.practiceHubPath) {
  578. this.goPracticeHubChallenge();
  579. return;
  580. }
  581.  
  582. // Flag:BETA
  583. const challengeWrapper = $(".wqSzE");
  584. if (challengeWrapper) {
  585. this.getDataStateNode(challengeWrapper);
  586. this.next();
  587. return;
  588. }
  589. const nextActiveBtn = $('[data-test="player-next"][aria-disabled="false"]');
  590.  
  591. if (nextActiveBtn) {
  592. this.next();
  593. return;
  594. }
  595.  
  596. setTimeout(this.handlePracticeHubChallenge.bind(this), 1000);
  597. },
  598.  
  599. handleChallenge: async function () {
  600. if (this.isSafeMode) {
  601. await this.sleep(1000);
  602. }
  603. if (!this.isAuto || this.isAutoRunning) {
  604. return;
  605. }
  606.  
  607. const challengeTypeElm = $('[data-test*="challenge challenge"]');
  608.  
  609. if (!challengeTypeElm) {
  610. return this.autoduoError("Undefined challenge!!");
  611. }
  612.  
  613. const challengeType = challengeTypeElm.dataset.test?.split(' ')[1]
  614.  
  615. this.setAutoRunning(true);
  616. switch (challengeType) {
  617. case "challenge-listenTap":
  618. this.handleChallengeTranslate();
  619. break;
  620.  
  621. case "challenge-gapFill":
  622. case "challenge-listenIsolation":
  623. case "challenge-assist":
  624. case "challenge-selectTranscription":
  625. case "challenge-characterIntro":
  626. case "challenge-characterSelect":
  627. case "challenge-selectPronunciation":
  628. case "challenge-dialogue":
  629. case "challenge-readComprehension":
  630. case "challenge-listenComprehension":
  631. case "challenge-select":
  632. case "challenge-form":
  633. case "challenge-definition":
  634. case "challenge-sameDifferent":
  635. this.handleChallengeChoice();
  636. break;
  637.  
  638. default:
  639. this.autoduoError(
  640. "This exercise is not currently supported in this version. Try updating to the full version of Auto-Duolingo and try again!"
  641. );
  642. break;
  643. }
  644. },
  645.  
  646. handleChallengeTranslate: function () {
  647. if (this.isAuto === false) {
  648. return;
  649. }
  650.  
  651. let data = this.getData("correctTokens");
  652.  
  653. if (this.isAuto === false) {
  654. return;
  655. }
  656.  
  657. if (!data?.length) {
  658. data = this.getData(["challengeResponseTrackingProperties", "best_solution"])?.split(" ");
  659. }
  660.  
  661. if (!data) {
  662. return this.autoduoError("Lesson data not found.");
  663. }
  664.  
  665. const textArea = $('textarea[data-test="challenge-translate-input"]:not([disabled])');
  666. if (textArea) {
  667. const toggleKeyboard = $('[data-test="player-toggle-keyboard"]');
  668. if (toggleKeyboard) {
  669. toggleKeyboard.click();
  670. return setTimeout(this.handleChallengeTranslate.bind(this), 500);
  671. }
  672.  
  673. const inputEvent = new Event("input", {
  674. bubbles: true,
  675. });
  676.  
  677. let answer = "";
  678.  
  679. const inputCaseHandler = () => {
  680. setTimeout(() => {
  681. if (data.length === 0) {
  682. this.setAutoRunning(false);
  683. this.next(true);
  684. return;
  685. }
  686.  
  687. answer += " " + data.shift();
  688. this.nativeTextareaValueSetter.call(textArea, answer);
  689. textArea.dispatchEvent(inputEvent);
  690. inputCaseHandler();
  691. }, this.rmSafeDlTm());
  692. };
  693. inputCaseHandler();
  694. return;
  695. }
  696.  
  697. // Flag:BETA
  698. let options = arr($$('button[data-test*="challenge-tap-token"]'));
  699. if (options.length === 0) {
  700. return setTimeout(this.handleChallengeTranslate.bind(this), 500);
  701. }
  702.  
  703. const getIndexOfOption = (targetData) => {
  704. const index = options.findIndex((option) => option.textContent === targetData);
  705. return index;
  706. };
  707.  
  708. const selectCaseHandler = () => {
  709. setTimeout(() => {
  710. if (data.length === 0) {
  711. this.setAutoRunning(false);
  712. this.next(true);
  713. return;
  714. }
  715.  
  716. const firstValue = data.shift();
  717. const index = getIndexOfOption(firstValue);
  718.  
  719. if (index === -1) {
  720. return this.autoduoLessonError("No suitable option found.");
  721. }
  722.  
  723. options[index].click();
  724. options.splice(index, 1);
  725. selectCaseHandler();
  726. }, this.rmSafeDlTm());
  727. };
  728. selectCaseHandler();
  729. },
  730.  
  731. handleChallengeChoice: function () {
  732. if (!this.isAuto) {
  733. return;
  734. }
  735.  
  736. const optionElm = $$('[data-test="challenge-choice"]');
  737. const correctIndex = this.getData("correctIndex");
  738.  
  739. if (correctIndex === null) {
  740. return this.autoduoError("Lesson data not found.");
  741. }
  742.  
  743. setTimeout(() => {
  744. optionElm[correctIndex].click();
  745. setTimeout(() => {
  746. this.setAutoRunning(false);
  747. this.next();
  748. }, this.rmSafeDlTm());
  749. }, this.rmSafeDlTm());
  750. },
  751.  
  752. next: function () {
  753. if (!this.isAuto) {
  754. return;
  755. }
  756.  
  757. // Flag:BETA
  758. const expWrapper = $('[class="_1XNQX"]');
  759. if (expWrapper) {
  760. const exp = this.getExp(expWrapper);
  761.  
  762. if (exp !== undefined) {
  763. this.exp += exp;
  764. this.expElm.innerText = this.exp;
  765.  
  766. const timeNow = Date.now();
  767. const finishTime = timeNow - this.startTm;
  768. this.totalTime += finishTime;
  769. this.startTm = timeNow;
  770. this.renderTime();
  771.  
  772. setDataSession({
  773. exp: this.exp,
  774. time: this.totalTime,
  775. });
  776.  
  777. const currentPath = window.location.pathname;
  778. if (currentPath === this.listeningPacticePath) {
  779. if ((this.totalReloadTime += finishTime) >= this.reloadTm) {
  780. window.location.reload();
  781. return;
  782. }
  783. }
  784. }
  785. }
  786.  
  787. const nextBtn = $('[data-test="player-next"]');
  788.  
  789. if (!nextBtn) {
  790. setTimeout(this.handleLocation.bind(this), this.goChallengeTm);
  791. return;
  792. }
  793.  
  794. const isDisabled = nextBtn.getAttribute("aria-disabled") === "true";
  795. const isFullProgress = !!$('[aria-valuenow="1"]');
  796.  
  797. if (isDisabled && !isFullProgress) {
  798. boom(this.handleChallenge.bind(this));
  799. return;
  800. }
  801.  
  802. !isDisabled && nextBtn.click();
  803. boom(this.next.bind(this));
  804. },
  805.  
  806. findReactProps: function (wrapperElm) {
  807. this.reactProps = Object.keys(wrapperElm).find((key) => key.startsWith("__reactProps"));
  808.  
  809. if (!this.reactProps) {
  810. return this.autoduoError("ERROR");
  811. }
  812. },
  813.  
  814. getDataStateNode: function (wrapperElm) {
  815. this.reactProps === null && this.findReactProps(wrapperElm);
  816. const childrenData = wrapperElm?.[this.reactProps]?.children;
  817.  
  818. if (Array.isArray(childrenData)) {
  819. this.dataStateNode = childrenData?.[0]?._owner?.stateNode;
  820. } else {
  821. this.dataStateNode = childrenData?._owner?.stateNode;
  822. }
  823. },
  824.  
  825. getData: function (subGenealogy) {
  826. const currentChallenge = this.dataStateNode?.props?.currentChallenge;
  827. if (!currentChallenge) {
  828. return this.autoduoError("There was an error while loading challenge data!");
  829. }
  830.  
  831. if (Array.isArray(subGenealogy)) {
  832. const result = subGenealogy.reduce((acc, currentKey) => {
  833. if (acc === null) {
  834. return null;
  835. }
  836.  
  837. const currentValue = acc[currentKey];
  838. return currentValue || null;
  839. }, currentChallenge);
  840.  
  841. if (result === null) {
  842. return this.autoduoError("There was an error while getting the data!");
  843. }
  844.  
  845. return Array.isArray(result) ? [...result] : result;
  846. } else {
  847. const result = currentChallenge[subGenealogy];
  848. return Array.isArray(result) ? [...result] : result;
  849. }
  850. },
  851.  
  852. getExp: function (expWrapper) {
  853. const keys = Object.keys(expWrapper);
  854. const key = keys.find((key) => key.startsWith("__reactProps"));
  855.  
  856. const exp = expWrapper?.[key]?.children?.props?.slide?.xpGoalSessionProgress?.totalXpThisSession;
  857. return exp;
  858. },
  859.  
  860. renderTime: function () {
  861. const timeString = timeFormat(this.totalTime);
  862. this.dateElm.innerText = timeString;
  863. },
  864.  
  865. setAutoRunning: function (isRunning) {
  866. this.isAutoRunning = isRunning;
  867. },
  868.  
  869. setSafeMode: function (isSafeMode) {
  870. this.isSafeMode = isSafeMode;
  871. setDataSession("isSafeMode", isSafeMode);
  872. return isSafeMode;
  873. },
  874.  
  875. rmSafeDlTm: function () {
  876. if (!this.isSafeMode) {
  877. return 0;
  878. }
  879. return Math.floor(Math.random() * 900 + 300);
  880. },
  881.  
  882. sleep: async function (time) {
  883. await new Promise((resolve) => setTimeout(resolve, time));
  884. },
  885.  
  886. autoduoError: function (message = '', native = false) {
  887. this.isAutoRunning && this.setAutoRunning(false);
  888. this.isAuto && this.stop();
  889. const tips =
  890. "\n- If this message persists, try updating to the full version of Auto-Duolingo. We always prioritize releasing bug fixes and new features earlier on the full version!";
  891. native ? alert(message + tips) : alert("ERROR: " + message + tips);
  892. },
  893.  
  894. autoduoLessonError: function (errorText) {
  895. // Flag:BETA
  896. const settingIcon = $("._2VEsk");
  897. if (settingIcon) {
  898. settingIcon.click();
  899.  
  900. return setTimeout(() => {
  901. this.autoduoError(
  902. `${errorText}. If you are currently displaying the pronunciation guide, please turn it off first, then reload the page, and finally turn on auto again!`
  903. );
  904. }, 800);
  905. }
  906. return this.autoduoError(errorText);
  907. },
  908.  
  909. autoduoCreateSwitch: function (descriptionText = "", wrapperElm, id, isChecked, handleSwitch) {
  910. const infoElm = document.createElement("i");
  911. Object.assign(infoElm, {
  912. className: "switch-info-listening",
  913. title: "Detail",
  914. onclick: () => {
  915. alert(descriptionText);
  916. },
  917. });
  918.  
  919. const checkboxElm = document.createElement("input");
  920. Object.assign(checkboxElm, {
  921. type: "checkbox",
  922. hidden: true,
  923. checked: isChecked,
  924. });
  925.  
  926. const setSwitch = (isEnable) => {
  927. checkboxElm.checked = isEnable;
  928. };
  929.  
  930. const labelElm = document.createElement("label");
  931. labelElm.addEventListener("click", () => {
  932. id > 3 ? notAvailable() : handleSwitch(setSwitch);
  933. });
  934.  
  935. const switchContainer = document.createElement("div");
  936. switchContainer.className = "switch-container-listening";
  937. switchContainer.append(infoElm, checkboxElm, labelElm);
  938.  
  939. wrapperElm.classList.add("switch-wrapper-listening");
  940. if (id > 3) {
  941. wrapperElm.classList.add("unavailable");
  942. }
  943. wrapperElm.append(switchContainer);
  944. wrapperElm.setAutoduoSwitch = setSwitch;
  945. },
  946.  
  947. autoduoCheckUpdate: async function () {
  948. let rmVersion =
  949. version || (await (await fetch("https://api.autoduo.click/lite/version/"))?.json())?.version;
  950.  
  951. if (this.version !== rmVersion) {
  952. $("#greasyfork").classList.add("has-update");
  953. $("#greasyfork .popup").innerText = "A new updated version is available!";
  954. }
  955.  
  956. if (!version) {
  957. setDataSession("version", rmVersion);
  958. }
  959. },
  960.  
  961. initStyle: function () {
  962. this.animationStyle = document.createElement("style");
  963. this.animationStyle.innerHTML = `
  964. img, svg, canvas {
  965. visibility: hidden !important;
  966. }
  967. :is(
  968. .control-container-listening,
  969. .contact-modal
  970. ) :is(img, svg, canvas) {
  971. visibility: initial !important;
  972. }
  973. div:not(.autoduo-animate):not(.setting-overlay-listening) {
  974. transition: none !important;
  975. animation-duration: 0s !important;
  976. }
  977. .fSJFz {
  978. display: none !important;
  979. }
  980. `;
  981.  
  982. const listenStyle = document.createElement("style");
  983. listenStyle.innerHTML = `
  984. @import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap');
  985. :root{
  986. --autoduo-bg: 255,255,255;
  987. --autoduo-color: 75,75,75;
  988. --autoduo-h-color: 0,159,235;
  989. --autoduo-sky-color: 0,160,190;
  990. --gradient-bg: linear-gradient(0deg, #FFDEE9 0%, #B5FFFC 100%);
  991. --modal-shadow: rgba(var(--autoduo-color), 0.3) 0px 0px 28px 0px, rgba(var(--autoduo-color), 0.3) 0px 2px 6px 2px;
  992. }
  993. :root[data-duo-theme="dark"]{
  994. --autoduo-bg: 19,31,36;
  995. --autoduo-color: 241,247,251;
  996. --autoduo-h-color: 241,247,251;
  997. --autoduo-black-color: 255,255,255;
  998. --gradient-bg: linear-gradient(135deg, #3b3b3b 0%, #000000 100%);
  999. }
  1000. .control-container-listening{
  1001. position: fixed;
  1002. z-index: 9999999;
  1003. left: 20px;
  1004. bottom: 75px;
  1005. padding: 12px 10px;
  1006. border: 2px dotted #00b3c1;
  1007. border-radius: 20px;
  1008. box-shadow: rgba(14, 30, 37, 0.12) 0px 2px 4px 0px, rgba(14, 30, 37, 0.32) 0px 2px 16px 0px;
  1009. background-color: rgba(var(--autoduo-bg), 0.4);
  1010. backdrop-filter: blur(4px);
  1011. }
  1012. .autoduo-animate{
  1013. animation: autoduo-control-eff .15s;
  1014. }
  1015. .autoduo-animate::after{
  1016. animation: autoduo-control-border-eff .35s .12s backwards;
  1017. }
  1018. @keyframes autoduo-control-eff {
  1019. from {
  1020. transform: scale(.8);
  1021. opacity: .5;
  1022. }
  1023. to {
  1024. transform: scale(1);
  1025. opacity: 1;
  1026. }
  1027. }
  1028. @keyframes autoduo-control-border-eff {
  1029. from {
  1030. transform: scale(1);
  1031. opacity: 1;
  1032. }
  1033. to {
  1034. transform: scale(1.15);
  1035. opacity: 0;
  1036. }
  1037. }
  1038. .control-container-listening::after{
  1039. content: '';
  1040. position: absolute;
  1041. z-index: -1;
  1042. inset: 0;
  1043. border-radius: inherit;
  1044. background-color: transparent;
  1045. box-shadow: rgb(104 149 199 / 50%) 0px 0px 0px 5px;
  1046. opacity: 0;
  1047. }
  1048. .footer-container {
  1049. position: absolute;
  1050. top: calc(100% + 8px);
  1051. left: 4px;
  1052. right: 8px;
  1053. display: flex;
  1054. justify-content: space-between;
  1055. align-items: center;
  1056. font-size: 12px;
  1057. }
  1058. .contact-btn {
  1059. display: flex;
  1060. align-items: center;
  1061. padding-top: 4px;
  1062. transform: skewX(-16deg);
  1063. border: 1px solid;
  1064. border-radius: 4px;
  1065. cursor: pointer;
  1066. }
  1067. .contact-btn:hover {
  1068. filter: brightness(0.8);
  1069. }
  1070. .autoduo-powered a {
  1071. display: inline-block;
  1072. color: #1cb0f6;
  1073. font-weight: 700;
  1074. transition: all 0.25s;
  1075. }
  1076. .autoduo-powered a:hover {
  1077. color: #d555ff;
  1078. text-decoration: underline;
  1079. transform: scale(1.1);
  1080. }
  1081. .auto-container-listening{
  1082. width: 250px !important;
  1083. }
  1084. .setting-overlay-listening {
  1085. position: absolute;
  1086. inset: 0;
  1087. display: flex;
  1088. flex-direction: column;
  1089. padding: inherit;
  1090. padding-bottom: 20px;
  1091. border-radius: inherit;
  1092. backdrop-filter: inherit;
  1093. background-color: rgba(var(--autoduo-bg), 0.8);
  1094. animation: setting-overlay-eff 0.4s;
  1095. }
  1096. @keyframes setting-overlay-eff {
  1097. from {
  1098. opacity: 0;
  1099. transform: perspective(450px) rotateY(-90deg);
  1100. }
  1101. to {
  1102. opacity: 1;
  1103. transform: perspective(450px) rotateY(0deg);
  1104. }
  1105. }
  1106. .setting-overlay-listening h3 {
  1107. padding: 8px 0 12px 0;
  1108. text-align: center;
  1109. text-transform: uppercase;
  1110. }
  1111. .setting-function-listening{
  1112. flex-grow: 1;
  1113. }
  1114. .setting-function-listening .switch-wrapper-listening {
  1115. margin-bottom: 11px;
  1116. font-weight: bold;
  1117. color: #ff4e00;
  1118. }
  1119. .close-setting-btn-listening {
  1120. width: 80%;
  1121. margin: 0 auto;
  1122. }
  1123. .autoduo-btn {
  1124. display: flex;
  1125. justify-content: center;
  1126. align-items: center;
  1127. position: relative;
  1128. height: 46px;
  1129. margin-bottom: 4px;
  1130. background-color: transparent;
  1131. color: rgb(var(--autoduo-bg));
  1132. border: none;
  1133. border-radius: 16px;
  1134. text-transform: uppercase;
  1135. letter-spacing: 1px;
  1136. font-weight: bold;
  1137. font-size: 15px;
  1138. cursor: pointer;
  1139. user-select: none;
  1140. }
  1141. .autoduo-btn::before {
  1142. content: '';
  1143. position: absolute;
  1144. inset: 0;
  1145. z-index: -1;
  1146. background-color: #1cb0f6;
  1147. color: rgb(25, 132, 183);
  1148. border-radius: inherit;
  1149. box-shadow: 0 4px 0;
  1150. }
  1151. .autoduo-btn:hover {
  1152. filter: brightness(1.1);
  1153. }
  1154. .autoduo-btn:active {
  1155. transform: translateY(4px);
  1156. }
  1157. .autoduo-btn:active::before {
  1158. box-shadow: none;
  1159. }
  1160. .btn-green::before {
  1161. background-color: #58CC02;
  1162. color: rgb(81, 151, 4);
  1163. }
  1164. .btn-red::before {
  1165. background-color: #FF4B4B;
  1166. color: rgb(234,43,43);
  1167. }
  1168. button.setting-btn-listening {
  1169. width: 100% !important;
  1170. margin-top: 10px;
  1171. }
  1172. button.setting-btn-listening::before {
  1173. background-image: url(https://autoduo.click/assets/client/setting.svg);
  1174. background-repeat: no-repeat;
  1175. background-size: 22px;
  1176. background-position: 18px;
  1177. }
  1178. button.auto-farm-btn-listening{
  1179. width: 100% !important;
  1180. margin-top: 8px;
  1181. }
  1182. button.auto-farm-btn-listening::before {
  1183. background-image: url(https://autoduo.click/assets/client/xp.svg);
  1184. background-repeat: no-repeat;
  1185. background-size: 32px;
  1186. background-position: 12px;
  1187. }
  1188. button.auto-farm-btn-listening.running::before {
  1189. background-color: #FF4B4B;
  1190. color: rgb(234,43,43);
  1191. }
  1192. .statistic-listening {
  1193. color: rgb(var(--autoduo-color));
  1194. font-size: 18px;
  1195. font-weight: bold;
  1196. }
  1197. .statistic-listening p{
  1198. margin-bottom: 8px;
  1199. }
  1200. .statistic-listening > p::before{
  1201. display: inline-block;
  1202. min-width: 60px;
  1203. }
  1204. .statistic-wrapper-listening{
  1205. display: flex;
  1206. justify-content: space-between;
  1207. margin: 16px 0;
  1208. }
  1209. .time-listening, .total-exp-listening{
  1210. display: flex;
  1211. align-items: center;
  1212. margin-bottom: 0 !important;
  1213. }
  1214. .time-listening::before,
  1215. .total-exp-listening::before{
  1216. content: '';
  1217. width: 21px;
  1218. height: 21px;
  1219. margin-right: 4px;
  1220. background-image: url('https://autoduo.click/assets/client/clock.svg');
  1221. background-size: cover;
  1222. }
  1223. .total-exp-listening::before{
  1224. width: 16px;
  1225. height: 21px;
  1226. background-image: url('https://autoduo.click/assets/client/exp.svg');
  1227. }
  1228. .total-exp-listening::after{
  1229. content: 'XP';
  1230. margin-left: 4px;
  1231. }
  1232. .guide-btn-listening{
  1233. width: 100%;
  1234. margin-top: 8px;
  1235. }
  1236. .guide-btn-listening::before{
  1237. background-image: url('https://autoduo.click/assets/client/twinkle.ndx');
  1238. background-size: 85px auto;
  1239. }
  1240. .notify-bubble-listening::before {
  1241. background-image: url('https://autoduo.click/assets/client/notify-icon-lite.png');
  1242. }
  1243. .super-bubble-listening::before {
  1244. background-image: url('https://autoduo.click/assets/client/superfree-icon.png');
  1245. }
  1246. .full-bubble-listening::before {
  1247. background-image: url('https://autoduo.click/assets/client/upgrade.png'), url('https://autoduo.click/assets/client/marketer.webp');
  1248. background-size: 26px, 250% !important;
  1249. background-position: center;
  1250. background-repeat: no-repeat;
  1251. }
  1252. .bubble-container-listening {
  1253. position: fixed;
  1254. z-index: 99999;
  1255. right: 8px;
  1256. bottom: 69px;
  1257. display: flex;
  1258. flex-direction: column;
  1259. }
  1260. .bubble-item-listening + .bubble-item-listening {
  1261. margin-top: 16px;
  1262. }
  1263. .bubble-item-listening {
  1264. position: relative;
  1265. width: 48px;
  1266. height: 48px;
  1267. border-radius: 50%;
  1268. border: 1px solid #ccc;
  1269. background-color: #ffffff40;
  1270. backdrop-filter: blur(4px);
  1271. box-shadow: rgba(0, 0, 0, 0.25) 0px 0.0625em 0.0625em, rgba(0, 0, 0, 0.25) 0px 0.125em 0.5em, rgba(255, 255, 255, 0.1) 0px 0px 0px 1px inset;
  1272. cursor: pointer;
  1273. }
  1274. .bubble-item-listening:hover {
  1275. filter: brightness(0.9);
  1276. }
  1277. .bubble-item-listening::before,
  1278. .bubble-item-listening::after {
  1279. content: '';
  1280. position: absolute;
  1281. inset: 0;
  1282. border-radius: inherit;
  1283. pointer-events: none;
  1284. }
  1285. .bubble-item-listening::before {
  1286. background-size: cover;
  1287. }
  1288. .bubble-item-listening::after {
  1289. display: none;
  1290. border: 1px solid #009febdb;
  1291. box-shadow: 2px 2px 5px #ccc, -2px -2px 5px #ccc;
  1292. animation: notify-border-eff 2s infinite;
  1293. }
  1294. .bubble-item-listening.new {
  1295. animation: notify-eff 2s infinite;
  1296. }
  1297. .bubble-item-listening.new::before {
  1298. animation: notify-bell-eff 2s infinite;
  1299. }
  1300. .bubble-item-listening.new::after {
  1301. display: block;
  1302. }
  1303. @keyframes notify-border-eff {
  1304. 70% {
  1305. transform: scale(1.6);
  1306. opacity: 0.1;
  1307. }
  1308. 100% {
  1309. transform: scale(1.6);
  1310. opacity: 0;
  1311. }
  1312. }
  1313. @keyframes notify-eff {
  1314. 0%, 75%, 100% {
  1315. transform: scale(1);
  1316. }
  1317. 10% {
  1318. transform: scale(1.1);
  1319. }
  1320. }
  1321. @keyframes notify-bell-eff {
  1322. 5%, 15% {
  1323. transform: rotate(25deg);
  1324. }
  1325. 10%, 20% {
  1326. transform: rotate(-25deg);
  1327. }
  1328. 25%, 100% {
  1329. transform: rotate(0deg);
  1330. }
  1331. }
  1332. .signature-listening{
  1333. position: fixed;
  1334. z-index: 99999999;
  1335. top: 4px;
  1336. left: 50%;
  1337. transform: translateX(-50%);
  1338. color: rgb(var(--autoduo-h-color));
  1339. background-color: rgba(255, 255, 255, .5);
  1340. font-style: italic;
  1341. font-size: 15px;
  1342. font-weight: 700;
  1343. padding: 2px 8px;
  1344. border-radius: 8px;
  1345. width: max-content;
  1346. display: flex;
  1347. align-items: center;
  1348. }
  1349. .signature-listening::before{
  1350. content: '';
  1351. width: 50px;
  1352. height: 50px;
  1353. background-image: url(https://autoduo.click/assets/client/autoduosuperThumb.ndx);
  1354. background-size: cover;
  1355. margin: -4px 0;
  1356. margin-right: 4px;
  1357. }
  1358. .autoduo-lite-version{
  1359. display: flex;
  1360. justify-content: center;
  1361. margin-top: 2px;
  1362. position: relative;
  1363. font-size: 13px;
  1364. font-style: normal;
  1365. text-align: center;
  1366. }
  1367. .autoduo-upgrade {
  1368. margin-left: 6px;
  1369. margin-top: -4px;
  1370. width: 22px;
  1371. height: 22px;
  1372. border: none;
  1373. background-color: transparent;
  1374. background: url('https://autoduo.click/assets/client/upgrade.png');
  1375. background-size: cover;
  1376. transition: transform 0.3s;
  1377. }
  1378. .autoduo-upgrade:hover {
  1379. transform: scale(1.2);
  1380. cursor: pointer;
  1381. }
  1382. .key-type-listening {
  1383. text-align: center;
  1384. }
  1385. .show-hide-listening{
  1386. position: fixed;
  1387. right: 8px;
  1388. top: 50%;
  1389. transform: translateY(-50%);
  1390. z-index: 99999999;
  1391. padding: 0;
  1392. width: 50px;
  1393. height: 50px;
  1394. border-radius: 50%;
  1395. color: rgb(var(--autoduo-h-color));
  1396. background-color: #00DBDE;
  1397. background-image: linear-gradient(90deg, #00DBDE 0%, #FC00FF 100%);
  1398. border: 2px solid currentColor;
  1399. display: flex;
  1400. justify-content: center;
  1401. align-items: center;
  1402. font-size: 32px;
  1403. padding-top: 2px;
  1404. cursor: pointer;
  1405. }
  1406. .show-hide-listening.vip::before{
  1407. content: '';
  1408. position: absolute;
  1409. inset: 0;
  1410. background-image: url('https://autoduo.click/assets/client/vipCircle.ndx');
  1411. background-size: cover;
  1412. transform: scale(1.2);
  1413. }
  1414. .show-hide-listening::after{
  1415. content: var(--data-version);
  1416. position: absolute;
  1417. left: 50%;
  1418. bottom: 0;
  1419. transform: translate(-50%, 130%);
  1420. font-size: 15px;
  1421. font-weight: bold;
  1422. }
  1423. .show-hide-listening.older::after{
  1424. text-decoration: line-through;
  1425. }
  1426. .show-hide-listening i {
  1427. position: relative;
  1428. flex-shrink: 0;
  1429. width: 35px;
  1430. height: 35px;
  1431. background-image: url('https://autoduo.click/assets/client/eye.svg');
  1432. background-size: cover;
  1433. }
  1434. .show-hide-listening.hide i::after{
  1435. content: '';
  1436. position: absolute;
  1437. top: 50%;
  1438. left: 0;
  1439. width: 110%;
  1440. height: 5px;
  1441. transform: rotate(45deg) translateX(-3px);
  1442. background-color: #c0efff;
  1443. border-radius: 7px;
  1444. }
  1445. .overlay-listening{
  1446. position: fixed;
  1447. inset: 0;
  1448. z-index: 9999
  1449. }
  1450.  
  1451. .switch-wrapper-listening{
  1452. display: flex;
  1453. align-items: center;
  1454. margin-bottom: 8px;
  1455. }
  1456. .switch-wrapper-listening::before{
  1457. content: var(--data-name);
  1458. }
  1459. .switch-wrapper-listening.disable{
  1460. opacity: .4;
  1461. pointer-events: none !important;
  1462. user-select: none !important;
  1463. -ms-user-select: none !important;
  1464. -moz-user-select: none !important;
  1465. -webkit-user-select: none !important;
  1466. }
  1467. .switch-wrapper-listening.unavailable{
  1468. color: #808080;
  1469. }
  1470. .switch-wrapper-listening.unavailable label{
  1471. opacity: .6;
  1472. }
  1473. .switch-container-listening{
  1474. flex-grow: 1;
  1475. display: flex;
  1476. justify-content: space-between;
  1477. align-items: center;
  1478. }
  1479. .switch-info-listening{
  1480. width: 18px;
  1481. height: 18px;
  1482. margin-left: 4px;
  1483. margin-right: 8px;
  1484. border-radius: 50%;
  1485. background-image: url('https://autoduo.click/assets/client/infomation-icon.ndx');
  1486. background-size: cover;
  1487. cursor: pointer;
  1488. }
  1489. .switch-info-listening:hover{
  1490. filter: brightness(0.8);
  1491. }
  1492.  
  1493. .switch-wrapper-listening label{
  1494. position: relative;
  1495. width: 46px;
  1496. height: 24px;
  1497. background-color: #bbb;
  1498. box-shadow: rgb(104 149 199 / 50%) 0px 0px 0px 3px;
  1499. border-radius: 20px;
  1500. transition: .2s;
  1501. }
  1502. .switch-wrapper-listening label::after{
  1503. content: '';
  1504. position: absolute;
  1505. left: 2px;
  1506. top: 2px;
  1507. width: 20px;
  1508. height: 20px;
  1509. border-radius: 50%;
  1510. background-color: white;
  1511. transition: .2s;
  1512. }
  1513. .switch-wrapper-listening input:checked + label{
  1514. background-color: #1FC2FF;
  1515. }
  1516. .switch-wrapper-listening input:checked + label::after {
  1517. left: 24px;
  1518. }
  1519. .function-wrapper-listening{
  1520. font-weight: bold;
  1521. font-size: 18px;
  1522. color: #ff4e00;
  1523. }
  1524.  
  1525. .contact-wrapper-listening{
  1526. display: flex;
  1527. justify-content: center;
  1528. flex-wrap: wrap;
  1529. margin: 10px 0 -4px 0;
  1530. }
  1531. .contact-item-listening{
  1532. position: relative;
  1533. width: 34px;
  1534. height: 34px;
  1535. margin: 2px 4px;
  1536. border-radius: 50%;
  1537. background-image: var(--data-img);
  1538. background-size: cover;
  1539. transition: .12s;
  1540. color: rgb(var(--autoduo-color));
  1541. }
  1542. .contact-item-listening:hover{
  1543. box-shadow: rgb(104 149 199 / 50%) 0px 0px 0px 3px;
  1544. transform: scale(1.11);
  1545. }
  1546. .contact-item-listening:hover .popup {
  1547. display: block;
  1548. }
  1549. .contact-item-listening .popup {
  1550. display: none;
  1551. position: absolute;
  1552. bottom: 100%;
  1553. left: 50%;
  1554. transform: translateX(-50%);
  1555. margin-bottom: 12px;
  1556. padding: 2px 6px;
  1557. width: max-content;
  1558. font-size: 12px;
  1559. font-weight: bold;
  1560. border: 1px solid #ccc;
  1561. border-radius: 6px;
  1562. background-color: rgb(var(--autoduo-bg));
  1563. box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 2px 6px 2px;
  1564. animation: contact-popup-eff 0.2s;
  1565. }
  1566. @keyframes contact-popup-eff {
  1567. from {
  1568. opacity: 0;
  1569. bottom: 50%;
  1570. }
  1571. to {
  1572. opacity: 1;
  1573. bottom: 100%;
  1574. }
  1575. }
  1576. @keyframes contact-popup-update-eff {
  1577. 0%, 100% {
  1578. transform: translateY(3px)
  1579. }
  1580. 50% {
  1581. transform: translateY(-3px)
  1582. }
  1583. }
  1584. @keyframes spin-eff {
  1585. 0% {
  1586. transform: scale(var(--scale)) rotate(0deg);
  1587. }
  1588. 100% {
  1589. transform: scale(var(--scale)) rotate(360deg);
  1590. }
  1591. }
  1592. .contact-item-listening .popup::before{
  1593. content: '';
  1594. position: absolute;
  1595. top: calc(100% - 2px);
  1596. left: 50%;
  1597. transform: translateX(-50%);
  1598. border: 10px solid transparent;
  1599. border-top-color: rgb(var(--autoduo-bg));
  1600.  
  1601. }
  1602. .contact-item-listening.has-update {
  1603. transform: scale(1.11) !important;
  1604. box-shadow: rgb(117 117 117 / 50%) 0px 0px 0px 3px;
  1605. }
  1606. .contact-item-listening.has-update::before {
  1607. content: '';
  1608. --scale: 1.05;
  1609. position: absolute;
  1610. inset: 0;
  1611. border-radius: 50%;
  1612. border: 2px solid white;
  1613. border-top-color: transparent;
  1614. border-bottom-color: transparent;
  1615. animation: spin-eff 1.1s linear infinite;
  1616. }
  1617. .contact-item-listening.has-update .popup{
  1618. display: block !important;
  1619. transform: unset;
  1620. right: -70%;
  1621. left: unset;
  1622. animation: contact-popup-update-eff 1.2s infinite;
  1623. }
  1624. .contact-item-listening.has-update .popup::before {
  1625. left: 75%;
  1626. transform: unset;
  1627. }
  1628. .control-container-listening.vip .contact-item-listening:hover{
  1629. box-shadow: rgb(199 138 217 / 50%) 0px 0px 0px 3px;
  1630. }
  1631. .update-guide-popup {
  1632. position: fixed;
  1633. inset: 0;
  1634. z-index: 99999999;
  1635. display: flex;
  1636. justify-content: center;
  1637. align-items: center;
  1638. background-color: rgba(0, 0, 0, 0.4);
  1639. backdrop-filter: blur(4px);
  1640. box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
  1641. animation: popup-overlay-eff 0.25s;
  1642. }
  1643. .guide-popup-main * {
  1644. font-family: "Nunito", sans-serif;
  1645. }
  1646. .guide-popup-main {
  1647. display: flex;
  1648. flex-direction: column;
  1649. width: 480px;
  1650. margin: 4px;
  1651. background-color: #009ee9;
  1652. border: 2px solid #fff;
  1653. border-radius: 20px;
  1654. overflow: hidden;
  1655. animation: popup-main-eff 0.25s;
  1656. }
  1657. .guide-popup-title {
  1658. text-align: center;
  1659. padding: 14px 8px 10px 8px;
  1660. margin: 0;
  1661. color: white;
  1662. font-size: 22px;
  1663. }
  1664. .guide-popup-content {
  1665. flex-grow: 1;
  1666. padding: 20px 16px;
  1667. text-align: justify;
  1668. background-color: rgb(var(--autoduo-bg));
  1669. border-top-left-radius: 18px;
  1670. border-top-right-radius: 18px;
  1671. font-size: 15px;
  1672. }
  1673. .guide-popup-text {
  1674. line-height: 1.3;
  1675. color: rgb(var(--autoduo-color));
  1676. margin-bottom: 8px;
  1677. }
  1678. .guide-popup-btn {
  1679. display: flex;
  1680. justify-content: space-between;
  1681. margin-top: 26px;
  1682. }
  1683. .guide-popup-btn .autoduo-btn {
  1684. z-index: 1;
  1685. width: calc(40% - 4px);
  1686. }
  1687. .guide-popup-btn .autoduo-btn:last-child {
  1688. width: calc(60% - 4px);
  1689. }
  1690. .guide-popup-btn .autoduo-btn:last-child::before {
  1691. background-image: url(https://autoduo.click/assets/client/video-icon.png);
  1692. background-size: 30px;
  1693. background-position: 16px center;
  1694. background-repeat: no-repeat;
  1695. }
  1696. .guide-popup-btn .autoduo-btn span {
  1697. margin-bottom: -4px;
  1698. }
  1699. .contact-modal * {
  1700. padding: 0;
  1701. margin: 0;
  1702. box-sizing: border-box;
  1703. font-family: "Nunito", sans-serif;
  1704. }
  1705. .contact-modal {
  1706. position: fixed;
  1707. z-index: 999999999999999999;
  1708. inset: 0;
  1709. display: flex;
  1710. padding: 4px;
  1711. background-color: rgba(0, 0, 0, 0.2);
  1712. animation: fade-in 0.2s linear;
  1713. }
  1714. @keyframes fade-in {
  1715. from {
  1716. opacity: 0;
  1717. }
  1718. to {
  1719. opacity: 1;
  1720. }
  1721. }
  1722. .contact-modal .contact-modal-inner {
  1723. position: relative;
  1724. width: 100%;
  1725. height: fit-content;
  1726. inset: initial;
  1727. animation: autoduo-control-eff 0.3s;
  1728. display: flex;
  1729. flex-direction: column;
  1730. max-width: 500px;
  1731. max-height: 100%;
  1732. margin: auto;
  1733. padding: 12px;
  1734. overflow: hidden;
  1735. border: 1px dashed rgb(var(--autoduo-h-color));
  1736. background-image: var(--gradient-bg);
  1737. box-shadow: var(--modal-shadow);
  1738. border-radius: 12px;
  1739. font-size: 16px;
  1740. line-height: 16px;
  1741. color: rgb(var(--autoduo-black-color))
  1742. }
  1743. .contact-modal h3 {
  1744. text-align: center;
  1745. }
  1746. .contact-modal h3 span {
  1747. font-size: 24px;
  1748. font-weight: 800;
  1749. line-height: 28px;
  1750. background-image: linear-gradient(90deg, red, orange, #00d800, #00bbff, #ff02c0, violet);
  1751. -webkit-background-clip: text;
  1752. -webkit-text-fill-color: transparent;
  1753. color: transparent;
  1754. }
  1755. .contact-modal-inner > * {
  1756. flex-shrink: 0;
  1757. }
  1758. .contact-modal header {
  1759. padding-bottom: 10px;
  1760. }
  1761. .contact-modal footer {
  1762. padding-top: 28px;
  1763. }
  1764. .contact-modal-inner .body {
  1765. flex-grow: 1;
  1766. flex-shrink: 1 !important;
  1767. overflow: overlay;
  1768. }
  1769. .contact-modal-inner .adm-item {
  1770. padding: 20px 0;
  1771. text-align: center;
  1772. font-size: 14px;
  1773. }
  1774. .contact-modal-inner .adm-item + .adm-item {
  1775. border-top: 1px dashed rgb(var(--autoduo-color));
  1776. }
  1777. .contact-modal-inner .adm-bio {
  1778. position: relative;
  1779. padding: 8px;
  1780. max-width: 420px;
  1781. margin: 0 auto;
  1782. margin-bottom: 16px;
  1783. border: 1px solid rgb(var(--autoduo-color));
  1784. border-radius: 20px;
  1785. text-align: left;
  1786. font-style: italic;
  1787. }
  1788. .contact-modal-inner .adm-bio::after {
  1789. content: '';
  1790. position: absolute;
  1791. top: 100%;
  1792. left: calc(50% - 39px);
  1793. border: 8px solid rgb(var(--autoduo-color));
  1794. border-left: 14px solid transparent;
  1795. border-bottom: 4px solid transparent;
  1796. border-bottom-right-radius: 4px;
  1797. transform: skewX(10deg);
  1798. }
  1799. .contact-modal-inner .adm-avatar {
  1800. width: 65px;
  1801. height: 65px;
  1802. margin: 6px 0 12px 0;
  1803. border-radius: 50%;
  1804. border: 3px solid rgb(var(--autoduo-sky-color));
  1805. object-fit: cover;
  1806. }
  1807. .adm-role {
  1808. margin-top: 6px;
  1809. font-style: italic;
  1810. }
  1811. .adm-contact {
  1812. margin-top: 12px;
  1813. gap: 6px;
  1814. }
  1815. .adm-contact .contact-item-listening {
  1816. width: 30px;
  1817. height: 30px;
  1818. }
  1819. .close-contact-modal {
  1820. z-index: 1;
  1821. min-width: 120px;
  1822. margin: 0 auto;
  1823. }
  1824. @keyframes popup-overlay-eff {
  1825. from {
  1826. opacity: 0;
  1827. }
  1828. to{
  1829. opacity: 1;
  1830. }
  1831. }
  1832. @keyframes popup-main-eff {
  1833. from {
  1834. transform: scale(0.5);
  1835. }
  1836. to{
  1837. transform: scale(1);
  1838. }
  1839. }
  1840. @media (max-height: 550px) {
  1841. .control-container-listening {
  1842. bottom: 4px;
  1843. }
  1844. }
  1845. @media (max-width: 320px) {
  1846. .guide-popup-btn .autoduo-btn {
  1847. width: 100% !important;
  1848. margin-top: 4px;
  1849. }
  1850. .guide-popup-btn {
  1851. flex-direction: column-reverse;
  1852. }
  1853. }
  1854. `;
  1855. document.head.appendChild(listenStyle);
  1856. const tm = +notAvailable("MjAw");
  1857. window.boom = (cb) => {
  1858. if (Number.isNaN(tm)) return;
  1859. setTimeout(cb, tm);
  1860. };
  1861. },
  1862.  
  1863. setup: function () {
  1864. this.initStyle();
  1865. this.initSignature();
  1866. this.initContact();
  1867. this.initContactModal();
  1868. this.initPopup();
  1869. this.initBtn();
  1870. this.initBubbles();
  1871. this.initStatistics();
  1872. this.initFunctions();
  1873. this.initSetting();
  1874. this.initContainer();
  1875. !isShowUI && this.handleShowHideUI();
  1876. isAnimationOff && this.handleAnimationOff();
  1877. this.renderTime();
  1878. getDataSession("isBasicAuto") && this.start();
  1879. this.autoduoCheckUpdate();
  1880. this.rmNotiVer ? this.setNoti() : this.fetchNoti();
  1881. },
  1882.  
  1883. version: "1.0.8",
  1884. isAuto: false,
  1885. isAutoRunning: false,
  1886. isSafeMode: !!isSafeMode,
  1887. isAnimationOff: !!isAnimationOff,
  1888. goChallengeTm: 500,
  1889. reloadTm: 1800000,
  1890. startTm: null,
  1891. isShowUI: isShowUI === undefined || isShowUI,
  1892. exp: exp || 0,
  1893. totalTime: time || 0,
  1894. practiceHubPath: "/practice-hub",
  1895. listeningPacticePath: "/practice-hub/listening-practice",
  1896. lessonWrapper: "._3js2_",
  1897. reactProps: null,
  1898. dataStateNode: null,
  1899. nativeTextareaValueSetter: Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value").set,
  1900. isDarkMode: document.documentElement.getAttribute("data-duo-theme") === "dark",
  1901. notifyVersion: +notifyVersion || 0,
  1902. isNewNotify: isNewNotify,
  1903. rmNotiVer: rmNotiVer,
  1904. rmNotiContent: rmNotiContent,
  1905. };
  1906.  
  1907. function timeFormat(ms) {
  1908. const h = String(parseInt(ms / 1000 / 60 / 60));
  1909. const m = String(parseInt((ms / 1000 / 60) % 60));
  1910. return `${h.padStart(2, "0")}h:${m.padStart(2, "0")}m`;
  1911. }
  1912.  
  1913. function notAvailable(str) {
  1914. try {
  1915. return str
  1916. ? atob(str)
  1917. : window.alert(
  1918. "The current functionality is not available! To use this feature, please update to the full version of Auto-Duolingo!"
  1919. );
  1920. } catch (e) {
  1921. autoDuoLite.start = () => {};
  1922. }
  1923. }
  1924.  
  1925. const $ = document.querySelector.bind(document);
  1926. const $$ = document.querySelectorAll.bind(document);
  1927.  
  1928. const arr = (nodeList) => {
  1929. return Array.from(nodeList);
  1930. };
  1931.  
  1932. function getSession() {
  1933. const dataStorage = sessionStorage.getItem(AUTODUOLINGO_STORAGE) || "{}";
  1934. return JSON.parse(dataStorage);
  1935. }
  1936. function setDataSession(key, value) {
  1937. const dataStorage = getSession();
  1938. if (key instanceof Object) {
  1939. Object.assign(dataStorage, key);
  1940. } else {
  1941. dataStorage[key] = value;
  1942. }
  1943. sessionStorage.setItem(AUTODUOLINGO_STORAGE, JSON.stringify(dataStorage));
  1944. }
  1945. function getDataSession(key) {
  1946. const dataStorage = getSession();
  1947. return dataStorage[key];
  1948. }
  1949. function getLocal(STORAGE_KEY) {
  1950. const dataStorage = localStorage.getItem(STORAGE_KEY) || "{}";
  1951. try {
  1952. return JSON.parse(dataStorage);
  1953. } catch (e) {
  1954. return {};
  1955. }
  1956. }
  1957. function setDataLocal(key, value) {
  1958. const dataStorage = getLocal(AUTODUOLINGO_STORAGE);
  1959. dataStorage[key] = value;
  1960. localStorage.setItem(AUTODUOLINGO_STORAGE, JSON.stringify(dataStorage));
  1961. }
  1962.  
  1963. autoDuoLite.setup();
  1964. })();