NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Auto-Duolingo // @version 1.0.6 // @author DevX // @namespace http://tampermonkey.net/ // @description [Lite Version] Automatically farm experience points, hacking Duolingo is so easy! // @match https://*.duolingo.com/* // @grant none // @license MIT // @icon https://autoduolingo.click/assets/imgs/favicon.ico // ==/UserScript== (() => { const AUTODUOLINGO_STORAGE = "autoDuolingoStorage"; const { isSafeMode, isShowUI, isAnimationOff, exp, time, version, isNewNotify, rmNotifyVersion, rmNotifyContent } = getSession(); const { notifyVersion } = getLocal(); const autoDuoLite = { createSignature: function () { this.signatureElm = document.createElement("div"); Object.assign(this.signatureElm, { className: "signature-listening", innerHTML: ` <div> Auto-Duolingo DevX <div class="autoduo-lite-version"> LITE VERSION </div> </div> `, }); document.body.appendChild(this.signatureElm); }, createContact: function () { this.contactWrapper = document.createElement("div"); Object.assign(this.contactWrapper, { className: "contact-wrapper-listening", innerHTML: `<a class="contact-item-listening" href="https://t.me/imdevx" target="_blank" style="--data-img: url('https://autoduolingo.click/assets/client/tele-icon.ndx')"> <p class="popup">Chat with DevX</p> </a> <a class="contact-item-listening" href="https://t.me/autoduofamily" target="_blank" style="--data-img: url('https://autoduolingo.click/assets/client/tele-gr-icon.ndx')"> <p class="popup">Telegram Community</p> </a> <a class="contact-item-listening" href="https://zalo.me/g/lmhfps187" target="_blank" style="--data-img: url('https://autoduolingo.click/assets/client/zalo-icon.ndx')"> <p class="popup">Zalo Community</p> </a> <a class="contact-item-listening" href="https://www.youtube.com/@autoduofamily" target="_blank" style="--data-img: url('https://autoduolingo.click/assets/client/youtube-icon.ndx')"> <p class="popup">Youtube Channel</p> </a> <a class="contact-item-listening" id="greasyfork" href="https://greasyfork.org/en/scripts/487867-auto-duolingo" target="_blank" style="--data-img: url('https://autoduolingo.click/assets/client/greasyfork-icon.ndx')"> <p class="popup">Greasy Fork</p> </a>`, }); }, createPopup: function () { this.updateGuidePopup = document.createElement("div"); Object.assign(this.updateGuidePopup, { className: "update-guide-popup", innerHTML: ` <div class="guide-popup-main"> <h2 class="guide-popup-title">UPDATE GUIDE</h2> <div class="guide-popup-content"> <p class="guide-popup-text" style="color: rgb(0,159,235)"> The full version unlocks all features and receives priority updates for new features and bug fixes. To upgrade, follow the instructions below: </p> <p class="guide-popup-text"> <b>Step 1:</b> Click the "Go update" button below, then proceed to click the "Update" button in the popup window to confirm the update process. </p> <p class="guide-popup-text"> <b>Step 2</b>: Refresh the Duolingo page to update the interface of the full version of Auto-Duolingo. </p> <div class="guide-popup-btn"> <button class="autoduo-btn popup-btn-close">Close</button> <a class="autoduo-btn btn-green popup-btn-access" href="#">Go Update</a> </div> </div> </div> `, }); const closePopupBtn = this.updateGuidePopup.querySelector(".popup-btn-close"); closePopupBtn.addEventListener("click", () => { document.body.contains(this.updateGuidePopup) && this.updateGuidePopup.remove(); }); }, createBtn: function () { this.autoBtn = document.createElement("button"); Object.assign(this.autoBtn, { className: "autoduo-btn btn-green auto-farm-btn-listening", innerText: "START FARM XP", onclick: () => { this.isAuto ? this.stop() : this.start(); }, }); this.updateBtn = document.createElement("button"); Object.assign(this.updateBtn, { className: "autoduo-btn update-btn-listening", innerText: "Update to the full version", onclick: () => { this.isAuto && this.stop(); document.body.appendChild(this.updateGuidePopup); }, }); this.showHideBtn = document.createElement("button"); Object.assign(this.showHideBtn, { className: "show-hide-listening", style: `--data-version: 'V${this.version}'`, innerHTML: "<i></i>", }); this.showHideBtn.addEventListener("click", () => { this.isShowUI = !this.isShowUI; this.handleShowHideUI(true); }); document.body.append(this.showHideBtn); new Promise((resolve) => { setTimeout( resolve.bind(window, notAvailable("aHR0cHM6Ly9pbnN0YWxsLmF1dG9kdW9saW5nby5jbGljaw==")), 1000 ); }).then((res) => { this.updateGuidePopup.querySelector(".popup-btn-access").href = res; }); }, createBubbles: function () { // Notify bubble this.notifyBubble = document.createElement("button"); this.notifyBubble.className = "bubble-item-listening notify-bubble-listening"; // Super free bubble this.superBubble = document.createElement("a"); Object.assign(this.superBubble, { className: "bubble-item-listening super-bubble-listening", href: "https://t.me/autoduofamily", target: "_blank" }) }, createStatistics: function () { this.statistic = document.createElement("div"); this.keyTypeElm = document.createElement("p"); this.expElm = document.createElement("p"); this.dateElm = document.createElement("p"); const statisticWrapper = document.createElement("div"); Object.assign(this.keyTypeElm, { className: "key-type-listening", style: `--data-name: "Type"`, innerHTML: "<b style='color: #009feb'>Auto-Duolingo Lite</b>", }); this.expElm.className = "total-exp-listening"; this.expElm.innerText = this.exp; this.statistic.className = "statistic-listening"; this.dateElm.className = "time-listening"; statisticWrapper.className = "statistic-wrapper-listening"; statisticWrapper.append(this.expElm, this.dateElm); this.statistic.append(this.keyTypeElm, statisticWrapper); }, createFunctions: function () { this.animationOffWrapper = document.createElement("div"); this.animationOffWrapper.style = `--data-name: "Hide Animation"`; const animationOffInfo = "HIDE ANIMATION MODE:\n" + "- When this mode is enabled, images and animations on the website will be hidden to optimize performance."; this.autoduoCreateSwitch( animationOffInfo, this.animationOffWrapper, 1, this.isAnimationOff, (setSwitch) => { this.isAnimationOff = !this.isAnimationOff; this.handleAnimationOff(true); setSwitch(this.isAnimationOff); } ); this.safeModeWrapper = document.createElement("div"); this.safeModeWrapper.style = `--data-name: "Safe Mode"`; const safeModeInfo = "SAFE MODE:\n" + "- When this mode is enabled, the system will simulate user actions when using auto. The speed will be more relaxed, " + "in exchange for the completion time of lessons and the amount of experience will be the most natural, minimizing " + "the risks of REPORT and account BAN!"; this.autoduoCreateSwitch(safeModeInfo, this.safeModeWrapper, 2, this.isSafeMode, () => { this.isSafeMode ? this.handleSafeModeOff() : this.handleSafeModeOn(); }); this.turboModeWrapper = document.createElement("div"); this.turboModeWrapper.style = `--data-name: "Turbo Mode"`; const turboModeInfo = "TURBO MODE:\n" + "- When enabled, the system will significantly boost the auto speed. It will utilize higher performance and " + "is not recommended for use on low-performance devices.\n- Turn it off and refresh the page if you encounter " + "issues while activating this mode!\n\n- Note: This is an experimental feature and requires a VIP Key to use. " + "Only enable it when you truly require speed and understand its implications!!"; this.autoduoCreateSwitch(turboModeInfo, this.turboModeWrapper, 4, false); this.legendModeWrapper = document.createElement("div"); this.legendModeWrapper.style = `--data-name: "Lesson Pass Mode"`; const legendModeInfo = "LESSON PASS MODE:\n" + "- When activated, the system won't repeat exercises as in the regular mode but will engage in exercises actively selected by the user. " + "This mode is used for legendary exercises, story exercises, and most other similar exercises.\n- You need to enter the lesson you want to " + "pass in, and then the system will automatically complete that lesson for you!\n" + "- When this mode is activated, the basic auto button will be temporarily disabled."; this.autoduoCreateSwitch(legendModeInfo, this.legendModeWrapper, 5, false); this.targetModeWrapper = document.createElement("div"); this.targetModeWrapper.style = `--data-name: "XP Target Mode"`; const targetModeInfo = "EXPERIENCE POINT TARGET MODE:\n" + "- By setting an experience point target, the system will automatically stop auto mode when the total experience points " + "obtained equal or exceed the specified target.\n- This helps you better control the auto function, " + "preventing unintentional accumulation of excess experience points due to forgetting to turn off auto mode!\n\n" + "- Note: The experience point target must be greater than the current amount of experience points obtained through auto mode!"; this.autoduoCreateSwitch(targetModeInfo, this.targetModeWrapper, 6, false); this.passModeWrapper = document.createElement("div"); this.passModeWrapper.style = `--data-name: "Auto Pass Mode"`; const passModeInfo = "AUTO PASS MODE:\n" + "- By setting the number of lessons you wish to pass, the system will automatically pass the corresponding " + "number of new lessons as per the value you've set!\n\n" + "- Note: the lesson value should be within the range of 1 - 1000 (Enter 0 for unlimited auto)!"; this.autoduoCreateSwitch(passModeInfo, this.passModeWrapper, 7, false); this.darkModeWrapper = document.createElement("div"); this.darkModeWrapper.style = `--data-name: "Dark Mode"`; const darkModeInfo = "DARK MODE\n- Enable/disable website dark mode faster!"; this.autoduoCreateSwitch(darkModeInfo, this.darkModeWrapper, 3, this.isDarkMode, (setSwitch) => { this.isDarkMode = !this.isDarkMode; const [theme, value] = this.isDarkMode ? ["dark", "on"] : ["light", "off"]; document.documentElement.setAttribute("data-duo-theme", theme); localStorage.setItem("duo.darkMode", `{"1291358081":"${value}","1313105280":"${value}"}`); setSwitch(this.isDarkMode); }); this.farmingLocationWrapper = document.createElement("div"); this.farmingLocationWrapper.style = `--data-name: "Set XP Farm Location"`; const farmingLocationInfo = "SET XP FARM LOCATION\n" + "- By default, the system can only Farm XP in practice exercises or listening practices. However, with this feature, you can Farm XP " + "in any lesson you want, even in story lessons!\n" + "- Usage: Activate the feature and enter the URL of the lesson you want, then enable the XP Farm mode to start farming.\n" + "- NOTE: The URL to the lesson must be accurate and the lesson must be repeatable. Entering an inaccurate URL may lead " + "to errors or even pose risks to your account!"; this.autoduoCreateSwitch(farmingLocationInfo, this.farmingLocationWrapper, 8, false); this.autoX2Wrapper = document.createElement("div"); this.autoX2Wrapper.style = `--data-name: "Auto Collect x2 XP"`; const autoX2Info = "AUTO COLLECT X2 XP:\n" + '- This is a supplementary feature for "Auto Farm KN", helping to maintain the x2 KN status during farming. When enabled, ' + "it will check and automatically do new lessons to get x2 KN rewards if it detects the current state doesn't have x2. " + "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 " + "consider before enabling it if you have constraints with these lessons."; this.autoduoCreateSwitch(autoX2Info, this.autoX2Wrapper, 8, false); this.functionWrapper = document.createElement("div"); this.functionWrapper.className = "function-wrapper-listening"; this.functionWrapper.append( this.darkModeWrapper, this.animationOffWrapper, this.safeModeWrapper, this.turboModeWrapper ); }, createSetting: function () { this.settingBtn = document.createElement("button"); Object.assign(this.settingBtn, { className: "autoduo-btn setting-btn-listening", innerText: "Other settings", }); this.settingBtn.addEventListener("click", () => { this.controlContainer.contains(this.settingOverlay) || this.controlContainer.appendChild(this.settingOverlay); }); this.closeSettingBtn = document.createElement("button"); Object.assign(this.closeSettingBtn, { className: "autoduo-btn close-setting-btn-listening", innerText: "Close", }); this.closeSettingBtn.addEventListener("click", () => { this.controlContainer.contains(this.settingOverlay) && this.controlContainer.removeChild(this.settingOverlay); }); // Create setting overlay this.settingOverlay = document.createElement("div"); Object.assign(this.settingOverlay, { className: "setting-overlay-listening", innerHTML: ` <h3>Other settings</h3> `, }); // Create setting functions this.settingFunction = document.createElement("div"); this.settingFunction.className = "setting-function-listening"; this.settingFunction.append( this.legendModeWrapper, this.passModeWrapper, this.targetModeWrapper, this.farmingLocationWrapper, this.autoX2Wrapper ); // Append the funtions and the close setting btn to the setting overlay this.settingOverlay.append(this.settingFunction, this.closeSettingBtn); }, createContainer: function () { this.autoContainer = document.createElement("div"); this.autoContainer.className = "auto-container-listening"; this.autoContainer.append( this.statistic, this.functionWrapper, this.settingBtn, this.autoBtn, this.updateBtn ); this.overlayContainer = document.createElement("div"); this.overlayContainer.className = "overlay-listening"; this.controlContainer = document.createElement("div"); this.controlContainer.className = "control-container-listening"; this.controlContainer.append(this.autoContainer, this.contactWrapper); this.bubbleContainer = document.createElement("div"); this.bubbleContainer.className = "bubble-container-listening" this.bubbleContainer.append( this.superBubble, this.notifyBubble ) document.body.append(this.controlContainer, this.bubbleContainer); }, fetchNotify: async function () { try { const res = await ( await fetch("https://api.autoduolingo.click/super/data/notify/?c7f54a73e6340a16176=91bf0d18b83") )?.json(); if (res?.code === 200) { const { notifyVersion: rmVersion, notifyContent: rmContent } = res.data[0]; setDataSession({ isNewNotify: (this.isNewNotify = +rmVersion > this.notifyVersion), rmNotifyVersion: (this.rmNotifyVersion = +rmVersion), rmNotifyContent: (this.rmNotifyContent = rmContent.replaceAll("\\n", "\n")), }); this.setNotify(); } } catch (e) {} }, setNotify: function () { if (!this.rmNotifyVersion) { return; } if (this.isNewNotify) { this.notifyBubble.classList.add("new"); } this.notifyBubble.addEventListener("click", () => { if (this.isNewNotify) { this.notifyBubble.classList.remove("new"); setDataSession("isNewNotify", (this.isNewNotify = false)); setDataLocal("notifyVersion", this.rmNotifyVersion); } window.alert(this.rmNotifyContent); }); }, handleShowHideUI: function (isSave = false) { if (this.isShowUI) { this.showHideBtn.classList.remove("hide"); document.body.append(this.controlContainer, this.signatureElm, this.bubbleContainer); } else { this.showHideBtn.classList.add("hide"); this.controlContainer.remove(); this.signatureElm.remove(); this.bubbleContainer.remove(); } if (isSave) { setDataSession("isShowUI", this.isShowUI); this.controlContainer.classList.contains("autoduo-animate") || this.controlContainer.classList.add("autoduo-animate"); } }, handleAnimationOff: function (isSave = false) { this.isAnimationOff ? document.head.appendChild(this.animationStyle) : document.head.removeChild(this.animationStyle); isSave && setDataSession("isAnimationOff", this.isAnimationOff); }, handleSafeModeOn: function () { this.safeModeWrapper.setAutoduoSwitch(this.setSafeMode(true)); }, handleSafeModeOff: function () { this.safeModeWrapper.setAutoduoSwitch(this.setSafeMode(false)); }, start: function () { if (this.isAuto || this.isAutoRunning) { return; } document.body.appendChild(this.overlayContainer); this.isAuto = true; this.autoBtn.classList.add("running"); this.autoBtn.innerText = "STOP FARM XP"; setDataSession("isBasicAuto", this.isAuto); this.startTm = Date.now(); this.handleLocation(); }, stop: function () { if (!this.isAuto || this.isLegendMode) { return; } document.body.removeChild(this.overlayContainer); this.isAuto = false; this.autoBtn.classList.remove("running"); this.autoBtn.innerText = "START FARM XP"; setDataSession("isBasicAuto", this.isAuto); }, handleLocation: function () { if (!this.isAuto) { return; } const currentPath = window.location.pathname; switch (currentPath) { case this.practiceHubPath: this.goPracticeHubChallenge(); break; case this.listeningPacticePath: this.handlePracticeHubChallenge(); break; default: this.autoduoError( "Inappropriate location: Only enable auto when on the practice page (with the dumbbell icon) of Duolingo Super!" + "\n- Enabling auto on Duolingo Super's practice page will automatically farm listening exercises (20 XP)." + "\n- If you want to auto farm practice exercises without needing Super or automatically complete most other exercises, please update to the full version of Auto-Duolingo!" ); break; } }, goPracticeHubChallenge: function () { if (this.isAuto === false) { return; } const challengeBtn = $( 'img[src="https://d35aaqx5ub95lt.cloudfront.net/images/practiceHub/2ebe830fd55a7f2754d371bcd79faf32.svg"]' ); if (!challengeBtn) { setTimeout(this.goPracticeHubChallenge.bind(this), 1000); return; } challengeBtn.click(); setTimeout(this.handlePracticeHubChallenge.bind(this), 1000); }, handlePracticeHubChallenge: function () { if (window.location.pathname === this.practiceHubPath) { this.goPracticeHubChallenge(); return; } // Flag:BETA const challengeWrapper = $(".wqSzE"); if (challengeWrapper) { this.getDataStateNode(challengeWrapper); this.next(); return; } const nextActiveBtn = $('[data-test="player-next"][aria-disabled="false"]'); if (nextActiveBtn) { this.next(); return; } setTimeout(this.handlePracticeHubChallenge.bind(this), 1000); }, handleChallenge: async function () { if (this.isSafeMode) { await this.sleep(500); } if (!this.isAuto || this.isAutoRunning) { return; } const challengeTypeElm = $('[data-test*="challenge challenge"]'); if (!challengeTypeElm) { return this.autoduoError("Undefined challenge!!"); } const challengeType = challengeTypeElm.dataset.test?.slice(10); this.setAutoRunning(true); switch (challengeType) { case "challenge-listenTap": this.handleChallengeTranslate(); break; case "challenge-gapFill": case "challenge-listenIsolation": case "challenge-assist": case "challenge-selectTranscription": case "challenge-characterIntro": case "challenge-characterSelect": case "challenge-selectPronunciation": case "challenge-dialogue": case "challenge-readComprehension": case "challenge-listenComprehension": case "challenge-select": case "challenge-form": case "challenge-definition": case "challenge-sameDifferent": this.handleChallengeChoice(); break; default: this.autoduoError( "This exercise is not currently supported in this version. Try updating to the full version of Auto-Duolingo and try again!" ); break; } }, handleChallengeTranslate: function () { if (this.isAuto === false) { return; } let data = this.getData("correctTokens"); if (this.isAuto === false) { return; } if (!data?.length) { data = this.getData(["challengeResponseTrackingProperties", "best_solution"])?.split(" "); } if (!data) { return this.autoduoError("Lesson data not found."); } const textArea = $('textarea[data-test="challenge-translate-input"]:not([disabled])'); if (textArea) { const toggleKeyboard = $('[data-test="player-toggle-keyboard"]'); if (toggleKeyboard) { toggleKeyboard.click(); return setTimeout(this.handleChallengeTranslate.bind(this), 500); } const inputEvent = new Event("input", { bubbles: true, }); let answer = ""; const inputCaseHandler = () => { setTimeout(() => { if (data.length === 0) { this.setAutoRunning(false); this.next(true); return; } answer += " " + data.shift(); this.nativeTextareaValueSetter.call(textArea, answer); textArea.dispatchEvent(inputEvent); inputCaseHandler(); }, this.rmSafeDlTm()); }; inputCaseHandler(); return; } // Flag:BETA let options = arr($$('[class="_1v1Bd"] button[data-test*="challenge-tap-token"]')); if (options.length === 0) { return setTimeout(this.handleChallengeTranslate.bind(this), 500); } const getIndexOfOption = (targetData) => { const index = options.findIndex((option) => option.textContent === targetData); return index; }; const selectCaseHandler = () => { setTimeout(() => { if (data.length === 0) { this.setAutoRunning(false); this.next(true); return; } const firstValue = data.shift(); const index = getIndexOfOption(firstValue); if (index === -1) { return this.autoduoLessonError("No suitable option found."); } options[index].click(); options.splice(index, 1); selectCaseHandler(); }, this.rmSafeDlTm()); }; selectCaseHandler(); }, handleChallengeChoice: function () { if (!this.isAuto) { return; } const optionElm = $$('[data-test="challenge-choice"]'); const correctIndex = this.getData("correctIndex"); if (correctIndex === null) { return this.autoduoError("Lesson data not found."); } setTimeout(() => { optionElm[correctIndex].click(); setTimeout(() => { this.setAutoRunning(false); this.next(); }, this.rmSafeDlTm()); }, this.rmSafeDlTm()); }, next: function () { if (!this.isAuto) { return; } // Flag:BETA const expWrapper = $('[class="_1XNQX"]'); if (expWrapper) { const exp = this.getExp(expWrapper); if (exp !== undefined) { this.exp += exp; this.expElm.innerText = this.exp; const timeNow = Date.now(); const finishTime = timeNow - this.startTm; this.totalTime += finishTime; this.startTm = timeNow; this.renderTime(); setDataSession({ exp: this.exp, time: this.totalTime, }); const currentPath = window.location.pathname; if (currentPath === this.listeningPacticePath) { if ((this.totalReloadTime += finishTime) >= this.reloadTm) { window.location.reload(); return; } } } } const nextBtn = $('[data-test="player-next"]'); if (!nextBtn) { setTimeout(this.handleLocation.bind(this), this.goChallengeTm); return; } const isDisable = nextBtn.getAttribute("aria-disabled"); // Flag:BETA const isLoadingBtn = nextBtn.classList.contains("_3whsM"); if (isDisable === "true" && !isLoadingBtn) { boom(this.handleChallenge.bind(this)); return; } !isLoadingBtn && nextBtn.click(); boom(this.next.bind(this)); }, findReactProps: function (wrapperElm) { this.reactProps = Object.keys(wrapperElm).find((key) => key.startsWith("__reactProps")); if (!this.reactProps) { return this.autoduoError("ERROR"); } }, getDataStateNode: function (wrapperElm) { this.reactProps === null && this.findReactProps(wrapperElm); const childrenData = wrapperElm?.[this.reactProps]?.children; if (Array.isArray(childrenData)) { this.dataStateNode = childrenData?.[0]?._owner?.stateNode; } else { this.dataStateNode = childrenData?._owner?.stateNode; } }, getData: function (subGenealogy) { const currentChallenge = this.dataStateNode?.props?.currentChallenge; if (!currentChallenge) { return this.autoduoError("There was an error while loading challenge data!"); } if (Array.isArray(subGenealogy)) { const result = subGenealogy.reduce((acc, currentKey) => { if (acc === null) { return null; } const currentValue = acc[currentKey]; return currentValue || null; }, currentChallenge); if (result === null) { return this.autoduoError("There was an error while getting the data!"); } return Array.isArray(result) ? [...result] : result; } else { const result = currentChallenge[subGenealogy]; return Array.isArray(result) ? [...result] : result; } }, getExp: function (expWrapper) { const keys = Object.keys(expWrapper); const key = keys.find((key) => key.startsWith("__reactProps")); const exp = expWrapper?.[key]?.children?.props?.slide?.xpGoalSessionProgress?.totalXpThisSession; return exp; }, renderTime: function () { const timeString = timeFormat(this.totalTime); this.dateElm.innerText = timeString; }, setAutoRunning: function (isRunning) { this.isAutoRunning = isRunning; }, setSafeMode: function (isSafeMode) { this.isSafeMode = isSafeMode; setDataSession("isSafeMode", isSafeMode); return isSafeMode; }, rmSafeDlTm: function () { if (!this.isSafeMode) { return 0; } return Math.floor(Math.random() * 800 + 100); }, sleep: async function (time) { await new Promise((resolve) => setTimeout(resolve, time)); }, autoduoError: function (message) { this.isAutoRunning && this.setAutoRunning(false); this.isAuto && this.stop(); const tips = "\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!"; alert("ERROR: " + message + tips); }, autoduoLessonError: function (errorText) { // Flag:BETA const settingIcon = $("._2VEsk"); if (settingIcon) { settingIcon.click(); return setTimeout(() => { this.autoduoError( `${errorText}. If you are currently displaying the pronunciation guide, please turn it off first, then reload the page, and finally turn on auto again!` ); }, 800); } return this.autoduoError(errorText); }, autoduoCreateSwitch: function (descriptionText = "", wrapperElm, id, isChecked, handleSwitch) { const infoElm = document.createElement("i"); Object.assign(infoElm, { className: "switch-info-listening", title: "Detail", onclick: () => { alert(descriptionText); }, }); const checkboxElm = document.createElement("input"); Object.assign(checkboxElm, { type: "checkbox", hidden: true, checked: isChecked, }); const setSwitch = (isEnable) => { checkboxElm.checked = isEnable; }; const labelElm = document.createElement("label"); labelElm.addEventListener("click", () => { id > 3 ? notAvailable() : handleSwitch(setSwitch); }); const switchContainer = document.createElement("div"); switchContainer.className = "switch-container-listening"; switchContainer.append(infoElm, checkboxElm, labelElm); wrapperElm.classList.add("switch-wrapper-listening"); if (id > 3) { wrapperElm.classList.add("unavailable"); } wrapperElm.append(switchContainer); wrapperElm.setAutoduoSwitch = setSwitch; }, autoduoCheckUpdate: async function () { let rmVersion = version || (await (await fetch("https://api.autoduolingo.click/lite/version/"))?.json())?.version; if (this.version !== rmVersion) { $("#greasyfork").classList.add("has-update"); $("#greasyfork .popup").innerText = "A new updated version is available!"; } if (!version) { setDataSession("version", rmVersion); } }, createStyle: function () { this.animationStyle = document.createElement("style"); this.animationStyle.innerHTML = ` img, svg, canvas { visibility: hidden !important; } div:not(.autoduo-animate):not(.setting-overlay-listening) { transition: none !important; animation-duration: 0s !important; } .fSJFz { display: none !important; } `; const listenStyle = document.createElement("style"); listenStyle.innerHTML = ` :root{ --autoduo-bg: 255,255,255; --autoduo-color: 75,75,75; --autoduo-h-color: 0,159,235; } :root[data-duo-theme="dark"]{ --autoduo-bg: 19,31,36; --autoduo-color: 241,247,251; --autoduo-h-color: 241,247,251; } .control-container-listening{ position: fixed; z-index: 9999999; left: 20px; bottom: 75px; padding: 12px 10px; border: 2px dotted #00b3c1; border-radius: 20px; box-shadow: rgba(14, 30, 37, 0.12) 0px 2px 4px 0px, rgba(14, 30, 37, 0.32) 0px 2px 16px 0px; background-color: rgba(var(--autoduo-bg), 0.4); backdrop-filter: blur(4px); } .autoduo-animate{ animation: autoduo-control-eff .15s; } .autoduo-animate::after{ animation: autoduo-control-border-eff .35s .12s backwards; } @keyframes autoduo-control-eff { from { transform: scale(.8); opacity: .5; } to { transform: scale(1); opacity: 1; } } @keyframes autoduo-control-border-eff { from { transform: scale(1); opacity: 1; } to { transform: scale(1.15); opacity: 0; } } .control-container-listening::after{ content: ''; position: absolute; z-index: -1; inset: 0; border-radius: inherit; background-color: transparent; box-shadow: rgb(104 149 199 / 50%) 0px 0px 0px 5px; opacity: 0; } .auto-container-listening{ width: 250px !important; } .setting-overlay-listening { position: absolute; inset: 0; display: flex; flex-direction: column; padding: inherit; padding-bottom: 20px; border-radius: inherit; backdrop-filter: inherit; background-color: rgba(var(--autoduo-bg), 0.8); animation: setting-overlay-eff 0.4s; } @keyframes setting-overlay-eff { from { opacity: 0; transform: perspective(450px) rotateY(-90deg); } to { opacity: 1; transform: perspective(450px) rotateY(0deg); } } .setting-overlay-listening h3 { padding: 8px 0 12px 0; text-align: center; text-transform: uppercase; } .setting-function-listening{ flex-grow: 1; } .setting-function-listening .switch-wrapper-listening { margin-bottom: 11px; font-weight: bold; color: #ff4e00; } .close-setting-btn-listening { width: 80%; margin: 0 auto; } .autoduo-btn { display: flex; justify-content: center; align-items: center; position: relative; height: 46px; margin-bottom: 4px; background-color: transparent; color: rgb(var(--autoduo-bg)); border: none; border-radius: 16px; text-transform: uppercase; letter-spacing: 1px; font-weight: bold; font-size: 15px; cursor: pointer; user-select: none; } .autoduo-btn::before { content: ''; position: absolute; inset: 0; z-index: -1; background-color: #1cb0f6; color: rgb(25, 132, 183); border-radius: inherit; box-shadow: 0 4px 0; } .autoduo-btn:hover { filter: brightness(1.1); } .autoduo-btn:active { transform: translateY(4px); } .autoduo-btn:active::before { box-shadow: none; } .btn-green::before { background-color: #58CC02; color: rgb(81, 151, 4); } button.setting-btn-listening { width: 100% !important; margin-top: 10px; } button.setting-btn-listening::before { background-image: url(https://autoduolingo.click/assets/client/setting.svg); background-repeat: no-repeat; background-size: 22px; background-position: 18px; } button.auto-farm-btn-listening{ width: 100% !important; margin-top: 8px; } button.auto-farm-btn-listening::before { background-image: url(https://autoduolingo.click/assets/client/xp.svg); background-repeat: no-repeat; background-size: 32px; background-position: 12px; } button.auto-farm-btn-listening.running::before { background-color: #FF4B4B; color: rgb(234,43,43); } .statistic-listening { color: rgb(var(--autoduo-color)); font-size: 18px; font-weight: bold; } .statistic-listening p{ margin-bottom: 8px; } .statistic-listening > p::before{ display: inline-block; min-width: 60px; } .statistic-wrapper-listening{ display: flex; justify-content: space-between; margin: 16px 0; } .time-listening, .total-exp-listening{ display: flex; align-items: center; margin-bottom: 0 !important; } .time-listening::before, .total-exp-listening::before{ content: ''; width: 21px; height: 21px; margin-right: 4px; background-image: url('https://autoduolingo.click/assets/client/clock.svg'); background-size: cover; } .total-exp-listening::before{ width: 16px; height: 21px; background-image: url('https://autoduolingo.click/assets/client/exp.svg'); } .total-exp-listening::after{ content: 'XP'; margin-left: 4px; } .update-btn-listening{ width: 100%; margin-top: 8px; } .update-btn-listening::before{ background-image: url('https://autoduolingo.click/assets/client/twinkle.ndx'); background-size: 85px auto; } .notify-bubble-listening::before { background-image: url('https://autoduolingo.click/assets/client/notify-icon-lite.png'); } .super-bubble-listening::before { background-image: url('https://autoduolingo.click/assets/client/super-icon.png'); } .bubble-container-listening { position: fixed; z-index: 99999; right: 8px; bottom: 69px; display: flex; flex-direction: column; } .bubble-item-listening + .bubble-item-listening { margin-top: 12px; } .bubble-item-listening { position: relative; width: 48px; height: 48px; border-radius: 50%; border: 1px solid #ccc; background-color: #ffffff40; backdrop-filter: blur(4px); 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; cursor: pointer; } .bubble-item-listening:hover { filter: brightness(0.9); } .bubble-item-listening::before, .bubble-item-listening::after { content: ''; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; } .bubble-item-listening::before { background-size: cover; } .bubble-item-listening::after { display: none; border: 1px solid #009febdb; box-shadow: 2px 2px 5px #ccc, -2px -2px 5px #ccc; animation: notify-border-eff 2s infinite; } .bubble-item-listening.new { animation: notify-eff 2s infinite; } .bubble-item-listening.new::before { animation: notify-bell-eff 2s infinite; } .bubble-item-listening.new::after { display: block; } @keyframes notify-border-eff { 70% { transform: scale(1.6); opacity: 0.1; } 100% { transform: scale(1.6); opacity: 0; } } @keyframes notify-eff { 0%, 75%, 100% { transform: scale(1); } 10% { transform: scale(1.1); } } @keyframes notify-bell-eff { 5%, 15% { transform: rotate(25deg); } 10%, 20% { transform: rotate(-25deg); } 25%, 100% { transform: rotate(0deg); } } .signature-listening{ position: fixed; z-index: 99999999; top: 4px; left: 50%; transform: translateX(-50%); color: rgb(var(--autoduo-h-color)); background-color: rgba(255, 255, 255, .5); font-style: italic; font-size: 15px; font-weight: 700; padding: 2px 8px; border-radius: 8px; width: max-content; display: flex; align-items: center; } .signature-listening::before{ content: ''; width: 50px; height: 50px; background-image: url(https://autoduolingo.click/assets/client/autoduosuperThumb.ndx); background-size: cover; margin: -4px 0; margin-right: 4px; } .autoduo-lite-version{ position: relative; font-size: 13px; font-style: normal; text-align: center; } .key-type-listening::before, .key-expired-listening::before { content: var(--data-name); } .show-hide-listening{ position: fixed; right: 8px; top: 50%; transform: translateY(-50%); z-index: 99999999; padding: 0; width: 50px; height: 50px; border-radius: 50%; color: rgb(var(--autoduo-h-color)); background-color: #00DBDE; background-image: linear-gradient(90deg, #00DBDE 0%, #FC00FF 100%); border: 2px solid currentColor; display: flex; justify-content: center; align-items: center; font-size: 32px; padding-top: 2px; cursor: pointer; } .show-hide-listening.vip::before{ content: ''; position: absolute; inset: 0; background-image: url('https://autoduolingo.click/assets/client/vipCircle.ndx'); background-size: cover; transform: scale(1.2); } .show-hide-listening::after{ content: var(--data-version); position: absolute; left: 50%; bottom: 0; transform: translate(-50%, 130%); font-size: 15px; font-weight: bold; } .show-hide-listening.older::after{ text-decoration: line-through; } .show-hide-listening i { position: relative; flex-shrink: 0; width: 35px; height: 35px; background-image: url('https://autoduolingo.click/assets/client/eye.svg'); background-size: cover; } .show-hide-listening.hide i::after{ content: ''; position: absolute; top: 50%; left: 0; width: 110%; height: 5px; transform: rotate(45deg) translateX(-3px); background-color: #c0efff; border-radius: 7px; } .overlay-listening{ position: fixed; inset: 0; z-index: 9999 } .switch-wrapper-listening{ display: flex; align-items: center; margin-bottom: 8px; } .switch-wrapper-listening::before{ content: var(--data-name); } .switch-wrapper-listening.disable{ opacity: .4; pointer-events: none !important; user-select: none !important; -ms-user-select: none !important; -moz-user-select: none !important; -webkit-user-select: none !important; } .switch-wrapper-listening.unavailable{ color: #808080; } .switch-wrapper-listening.unavailable label{ opacity: .6; } .switch-container-listening{ flex-grow: 1; display: flex; justify-content: space-between; align-items: center; } .switch-info-listening{ width: 18px; height: 18px; margin-left: 4px; margin-right: 8px; border-radius: 50%; background-image: url('https://autoduolingo.click/assets/client/infomation-icon.ndx'); background-size: cover; cursor: pointer; } .switch-info-listening:hover{ filter: brightness(0.8); } .switch-wrapper-listening label{ position: relative; width: 46px; height: 24px; background-color: #bbb; box-shadow: rgb(104 149 199 / 50%) 0px 0px 0px 3px; border-radius: 20px; transition: .2s; } .switch-wrapper-listening label::after{ content: ''; position: absolute; left: 2px; top: 2px; width: 20px; height: 20px; border-radius: 50%; background-color: white; transition: .2s; } .switch-wrapper-listening input:checked + label{ background-color: #1FC2FF; } .switch-wrapper-listening input:checked + label::after { left: 24px; } .function-wrapper-listening{ font-weight: bold; font-size: 18px; color: #ff4e00; } .contact-wrapper-listening{ display: flex; justify-content: center; flex-wrap: wrap; margin: 10px 0 -4px 0; } .contact-item-listening{ position: relative; width: 34px; height: 34px; margin: 2px 4px; border-radius: 50%; background-image: var(--data-img); background-size: cover; transition: .12s; color: rgb(var(--autoduo-color)); } .contact-item-listening:hover{ box-shadow: rgb(104 149 199 / 50%) 0px 0px 0px 3px; transform: scale(1.11); } .contact-item-listening:hover .popup { display: block; } .contact-item-listening .popup { display: none; position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); margin-bottom: 12px; padding: 2px 6px; width: max-content; font-size: 12px; font-weight: bold; border: 1px solid #ccc; border-radius: 6px; background-color: rgb(var(--autoduo-bg)); box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 2px 6px 2px; animation: contact-popup-eff 0.2s; } @keyframes contact-popup-eff { from { opacity: 0; bottom: 50%; } to { opacity: 1; bottom: 100%; } } @keyframes contact-popup-update-eff { 0%, 100% { transform: translateY(3px) } 50% { transform: translateY(-3px) } } @keyframes spin-eff { 0% { transform: scale(var(--scale)) rotate(0deg); } 100% { transform: scale(var(--scale)) rotate(360deg); } } .contact-item-listening .popup::before{ content: ''; position: absolute; top: calc(100% - 2px); left: 50%; transform: translateX(-50%); border: 10px solid transparent; border-top-color: rgb(var(--autoduo-bg)); } .contact-item-listening.has-update { transform: scale(1.11) !important; box-shadow: rgb(117 117 117 / 50%) 0px 0px 0px 3px; } .contact-item-listening.has-update::before { content: ''; --scale: 1.05; position: absolute; inset: 0; border-radius: 50%; border: 2px solid white; border-top-color: transparent; border-bottom-color: transparent; animation: spin-eff 1.1s linear infinite; } .contact-item-listening.has-update .popup{ display: block !important; transform: unset; right: -70%; left: unset; animation: contact-popup-update-eff 1.2s infinite; } .contact-item-listening.has-update .popup::before { left: 75%; transform: unset; } .control-container-listening.vip .contact-item-listening:hover{ box-shadow: rgb(199 138 217 / 50%) 0px 0px 0px 3px; } .update-guide-popup { position: fixed; inset: 0; z-index: 99999999; display: flex; justify-content: center; align-items: center; background-color: rgba(0, 0, 0, 0.4); backdrop-filter: blur(4px); box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px; animation: popup-overlay-eff 0.25s; } .guide-popup-main { display: flex; flex-direction: column; width: 480px; margin: 4px; background-color: #009ee9; border: 2px solid #fff; border-radius: 20px; overflow: hidden; animation: popup-main-eff 0.25s; } .guide-popup-title { text-align: center; padding: 14px 8px 10px 8px; margin: 0; color: white; font-size: 22px; } .guide-popup-content { flex-grow: 1; padding: 20px 16px; text-align: justify; background-color: rgb(var(--autoduo-bg)); border-top-left-radius: 18px; border-top-right-radius: 18px; } ..guide-popup-text { line-height: 24px; color: rgb(var(--autoduo-color)); margin-bottom: 18px; } .guide-popup-btn { display: flex; justify-content: space-between; margin-top: 26px; } .guide-popup-btn .autoduo-btn { z-index: 1; width: calc(50% - 4px); } @keyframes popup-overlay-eff { from { opacity: 0; } to{ opacity: 1; } } @keyframes popup-main-eff { from { transform: scale(0.5); } to{ transform: scale(1); } } @media (max-height: 550px) { .control-container-listening { bottom: 4px; } } @media (max-width: 320px) { .guide-popup-btn .autoduo-btn { width: 100%; margin-top: 4px; } .guide-popup-btn { flex-direction: column-reverse; } } `; document.head.appendChild(listenStyle); const tm = +notAvailable("MjAw"); window.boom = (cb) => { if (Number.isNaN(tm)) return; setTimeout(cb, tm); }; }, setup: function () { this.createStyle(); this.createSignature(); this.createContact(); this.createPopup(); this.createBtn(); this.createBubbles(); this.createStatistics(); this.createFunctions(); this.createSetting(); this.createContainer(); !isShowUI && this.handleShowHideUI(); isAnimationOff && this.handleAnimationOff(); this.renderTime(); getDataSession("isBasicAuto") && this.start(); this.autoduoCheckUpdate(); this.rmNotifyVersion ? this.setNotify() : this.fetchNotify(); }, version: "1.0.6", isAuto: false, isAutoRunning: false, isSafeMode: !!isSafeMode, isAnimationOff: !!isAnimationOff, goChallengeTm: 500, reloadTm: 1800000, startTm: null, isShowUI: isShowUI === undefined || isShowUI, exp: exp || 0, totalTime: time || 0, practiceHubPath: "/practice-hub", listeningPacticePath: "/practice-hub/listening-practice", lessonWrapper: "._3js2_", reactProps: null, dataStateNode: null, nativeTextareaValueSetter: Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value").set, isDarkMode: document.documentElement.getAttribute("data-duo-theme") === "dark", notifyVersion: +notifyVersion || 0, isNewNotify: isNewNotify, rmNotifyVersion: rmNotifyVersion, rmNotifyContent: rmNotifyContent, }; function timeFormat(ms) { const h = String(parseInt(ms / 1000 / 60 / 60)); const m = String(parseInt((ms / 1000 / 60) % 60)); return `${h.padStart(2, "0")}h:${m.padStart(2, "0")}m`; } function notAvailable(str) { try { return str ? atob(str) : window.alert( "The current functionality is not available! To use this feature, please update to the full version of Auto-Duolingo!" ); } catch (e) { autoDuoLite.start = () => {}; } } const $ = document.querySelector.bind(document); const $$ = document.querySelectorAll.bind(document); const arr = (nodeList) => { return Array.from(nodeList); }; function getSession() { const dataStorage = sessionStorage.getItem(AUTODUOLINGO_STORAGE) || "{}"; return JSON.parse(dataStorage); } function setDataSession(key, value) { const dataStorage = getSession(); if (key instanceof Object) { Object.assign(dataStorage, key); } else { dataStorage[key] = value; } sessionStorage.setItem(AUTODUOLINGO_STORAGE, JSON.stringify(dataStorage)); } function getDataSession(key) { const dataStorage = getSession(); return dataStorage[key]; } function getLocal() { const dataStorage = localStorage.getItem(AUTODUOLINGO_STORAGE) || "{}"; try { return JSON.parse(dataStorage); } catch (e) { return {}; } } function setDataLocal(key, value) { const dataStorage = getLocal(); dataStorage[key] = value; localStorage.setItem(AUTODUOLINGO_STORAGE, JSON.stringify(dataStorage)); } // SETUP AUTO autoDuoLite.setup(); })();