您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
[Demo] Auto Farm XP, streak, gem hack – so easy!
// ==UserScript== // @name Duolingo SM // @version 2.3.0 // @author MeowWoof // @namespace http://tampermonkey.net/ // @description [Demo] Auto Farm XP, streak, gem hack – so easy! // @match https://*.duolingo.com/* // @grant none // @license MIT // @icon https://d35aaqx5ub95lt.cloudfront.net/vendor/a0ee30fa22ca3d00e9e5db913b1965b5.svg // ==/UserScript== (function() { 'use strict'; // đừng đọc mà con cạc const sessionUrl = "https://www.duolingo.com/2017-06-30/sessions"; let isFarming = false, isVisible = true; let currentLanguage = "en"; const getJwtToken = () => document.cookie.split(';').find(c => c.trim().startsWith('jwt_token='))?.split('=')[1] || null; const decodeJwtToken = token => JSON.parse(atob(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/'))); const formatHeaders = jwtToken => ({ "Content-Type": "application/json", "Authorization": `Bearer ${jwtToken}`, "User-Agent": navigator.userAgent }); const getUserInfo = async (sub, headers) => (await fetch(`https://www.duolingo.com/2017-06-30/users/${sub}?fields=username,fromLanguage,learningLanguage`, { headers })).json(); const farmXp = async (headers, sessionPayload, updateSessionPayload) => { while (isFarming) { try { const session = await (await fetch(sessionUrl, { method: 'POST', headers, body: JSON.stringify(sessionPayload) })).json(); const updatedSession = await (await fetch(`${sessionUrl}/${session.id}`, { method: 'PUT', headers, body: JSON.stringify({ ...session, ...updateSessionPayload }) })).json(); document.getElementById("_xpAmount").innerText = parseInt(document.getElementById("_xpAmount").innerText) + updatedSession.xpGain; } catch (error) { alert(currentLanguage === "en" ? "An error occurred while farming XP. Please try again!" : "Đã xảy ra lỗi khi farm XP. Vui lòng thử lại!"); await new Promise(resolve => setTimeout(resolve, 5000)); } } }; const translations = { en: { title: "Duolingo SM", welcome: "Welcome to Duolingo SM!", notLoggedIn: "You are not logged in! (if you are logged in, please refresh the page)", hello: "Hello", farmXp: "FARM XP", farmGems: "FARM GEMS", upgrade: "UPGRADE", start: "Start Farming", stop: "Stop Farming", xpGained: "XP Gained", warning: "Please use this tool responsibly.", loading: "Processing...", switchLang: "Tiếng Việt", status: "Status", active: "Active", inactive: "Inactive" }, vi: { title: "Super-Duo", welcome: "Chào mừng đến với Duolingo SM!", notLoggedIn: "Bạn chưa đăng nhập! (nếu bạn đã đăng nhập, vui lòng tải lại trang)", hello: "Xin chào", farmXp: "FARM XP", farmGems: "FARM GEMS", upgrade: "NÂNG CẤP", start: "Bắt đầu Farm", stop: "Dừng Farm", xpGained: "XP Đã Nhận", warning: "Vui lòng sử dụng công cụ này 1 cách tự nhiên", loading: "Đang xử lý...", switchLang: "English", status: "Trạng thái", active: "Hoạt động", inactive: "Không hoạt động" } }; const initSuperDuolingo = async () => { const style = document.createElement('style'); style.innerHTML = ` :root { /* Light theme colors */ --primary-bg: #ffffff; --secondary-bg: #f8fafc; --accent-bg: #f1f5f9; --surface: #e2e8f0; --surface-light: #f8fafc; --primary-color: #0ea5e9; --secondary-color: #6366f1; --accent-color: #8b5cf6; --success-color: #10b981; --warning-color: #f59e0b; --error-color: #ef4444; --text-primary: #1e293b; --text-secondary: #475569; --text-muted: #64748b; --gradient-primary: linear-gradient(135deg, #0ea5e9 0%, #3b82f6 100%); --gradient-success: linear-gradient(135deg, #10b981 0%, #059669 100%); --gradient-secondary: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05); --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07); --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1); --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.1); --border-radius: 8px; --border-radius-lg: 12px; --transition: all 0.2s ease; } ._sd_container { position: fixed; right: 16px; top: 50%; transform: translateY(-50%); width: 280px; background: var(--primary-bg); border-radius: var(--border-radius-lg); box-shadow: var(--shadow-xl); z-index: 9999; overflow: hidden; transition: var(--transition); border: 1px solid var(--surface); } ._sd_container.hidden { transform: translateY(-50%) translateX(100%); opacity: 0; } ._sd_header { background: var(--gradient-primary); padding: 16px; text-align: center; } ._sd_title { font-size: 1.1rem; font-weight: 700; color: white; margin: 0 0 8px 0; } ._sd_language_switcher { background: rgba(255, 255, 255, 0.2); border: 1px solid rgba(255, 255, 255, 0.3); border-radius: var(--border-radius); padding: 4px 12px; font-size: 0.75rem; color: white; cursor: pointer; transition: var(--transition); font-weight: 500; } ._sd_language_switcher:hover { background: rgba(255, 255, 255, 0.3); } ._sd_body { padding: 16px; background: var(--primary-bg); } ._sd_welcome { font-size: 0.85rem; color: var(--text-secondary); margin-bottom: 16px; padding: 12px; background: var(--surface-light); border-radius: var(--border-radius); border-left: 3px solid var(--primary-color); } ._sd_status_indicator { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; padding: 8px 12px; background: var(--surface-light); border-radius: var(--border-radius); font-size: 0.8rem; } ._sd_status_dot { width: 6px; height: 6px; border-radius: 50%; background: var(--error-color); transition: var(--transition); } ._sd_status_dot.active { background: var(--success-color); } ._sd_status_text { color: var(--text-muted); font-weight: 500; } ._sd_xp_counter { display: flex; align-items: center; justify-content: center; gap: 6px; padding: 10px; background: var(--surface-light); border-radius: var(--border-radius); margin-bottom: 16px; border: 1px solid var(--surface); } ._sd_xp_counter_label { font-size: 0.8rem; color: var(--text-muted); font-weight: 500; } ._sd_xp_counter_value { font-size: 1rem; color: var(--primary-color); font-weight: 700; } ._sd_tabs { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; } ._sd_tab { padding: 10px 12px; border-radius: var(--border-radius); background: var(--surface-light); color: var(--text-secondary); cursor: pointer; transition: var(--transition); font-weight: 500; font-size: 0.85rem; display: flex; align-items: center; justify-content: space-between; border: 1px solid var(--surface); } ._sd_tab:hover { background: var(--accent-bg); color: var(--text-primary); border-color: var(--primary-color); } ._sd_tab.active { background: var(--primary-color); color: white; border-color: var(--primary-color); } ._sd_tab_icon { font-size: 1rem; } ._sd_start_btn { padding: 12px 20px; background: var(--gradient-success); border: none; border-radius: var(--border-radius); color: white; font-weight: 600; cursor: pointer; transition: var(--transition); width: 100%; font-size: 0.9rem; box-shadow: var(--shadow-sm); } ._sd_start_btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-md); } ._sd_start_btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; } ._sd_toggle_btn { position: fixed; left: 16px; bottom: 20px; width: 44px; height: 44px; border-radius: 50%; background: var(--gradient-primary); border: none; display: flex; justify-content: center; align-items: center; cursor: pointer; z-index: 10000; transition: var(--transition); color: white; font-weight: bold; font-size: 1.2rem; box-shadow: var(--shadow-lg); } ._sd_toggle_btn:hover { transform: scale(1.05); box-shadow: var(--shadow-xl); } ._sd_overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); display: none; align-items: center; justify-content: center; z-index: 9999; } ._sd_modal { background: var(--primary-bg); border-radius: var(--border-radius-lg); padding: 24px; width: 90%; max-width: 320px; box-shadow: var(--shadow-xl); border: 1px solid var(--surface); text-align: center; } ._sd_modal_title { font-size: 1.2rem; font-weight: 700; margin-bottom: 16px; color: var(--text-primary); } ._sd_spinner { display: inline-block; width: 40px; height: 40px; margin: 16px auto; } ._sd_spinner:after { content: " "; display: block; width: 32px; height: 32px; margin: 4px; border-radius: 50%; border: 3px solid var(--surface); border-top: 3px solid var(--primary-color); animation: _sd_spin 1s linear infinite; } ._sd_xp_info { font-size: 1rem; color: var(--primary-color); margin: 16px 0; font-weight: 600; padding: 12px; background: var(--surface-light); border-radius: var(--border-radius); border: 1px solid var(--surface); } ._sd_warning { font-size: 0.8rem; color: var(--text-secondary); margin-bottom: 16px; line-height: 1.4; padding: 12px; background: #fef3c7; border-radius: var(--border-radius); border: 1px solid #fbbf24; } ._sd_stop_btn { padding: 10px 20px; background: var(--gradient-secondary); border: none; border-radius: var(--border-radius); color: white; font-weight: 600; cursor: pointer; transition: var(--transition); font-size: 0.85rem; box-shadow: var(--shadow-sm); } ._sd_stop_btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-md); } @keyframes _sd_spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } /* Responsive */ @media (max-width: 768px) { ._sd_container { width: 260px; right: 12px; } ._sd_toggle_btn { left: 12px; bottom: 16px; width: 40px; height: 40px; font-size: 1.1rem; } ._sd_modal { margin: 16px; padding: 20px; } } /* Focus states */ ._sd_tab:focus, ._sd_start_btn:focus, ._sd_stop_btn:focus, ._sd_language_switcher:focus, ._sd_toggle_btn:focus { outline: 2px solid var(--primary-color); outline-offset: 2px; } `; document.head.appendChild(style); const containerHTML = ` <div class="_sd_container" id="_sd_container"> <div class="_sd_header"> <h2 class="_sd_title" id="_sd_title">${translations[currentLanguage].title}</h2> <button class="_sd_language_switcher" id="_sd_language_switcher"> ${translations[currentLanguage].switchLang} </button> </div> <div class="_sd_body"> <div class="_sd_welcome" id="_sd_welcome"> ${translations[currentLanguage].welcome} </div> <div class="_sd_status_indicator"> <div class="_sd_status_dot" id="_sd_status_dot"></div> <span class="_sd_status_text" id="_sd_status_text"> ${translations[currentLanguage].status}: ${translations[currentLanguage].inactive} </span> </div> <div class="_sd_xp_counter"> <span class="_sd_xp_counter_label" id="_sd_xp_label">${translations[currentLanguage].xpGained}:</span> <span class="_sd_xp_counter_value" id="_xpAmount">0</span> <span class="_sd_xp_counter_label">XP</span> </div> <div class="_sd_tabs"> <div class="_sd_tab active" id="_sd_tab_farm_xp"> <span>${translations[currentLanguage].farmXp}</span> <span class="_sd_tab_icon">⚡</span> </div> <div class="_sd_tab" id="_sd_tab_farm_gems"> <span>${translations[currentLanguage].farmGems}</span> <span class="_sd_tab_icon">💎</span> </div> <div class="_sd_tab" id="_sd_tab_upgrade"> <span>${translations[currentLanguage].upgrade}</span> <span class="_sd_tab_icon">👑</span> </div> </div> <div class="_sd_farm_controls"> <button class="_sd_start_btn" id="_sd_start_btn"> ${translations[currentLanguage].start} </button> </div> </div> </div> <button class="_sd_toggle_btn" id="_sd_toggle_btn">→</button> <div class="_sd_overlay" id="_sd_overlay"> <div class="_sd_modal"> <h2 class="_sd_modal_title" id="_sd_modal_title"> ${translations[currentLanguage].title} </h2> <p id="_sd_loading_message"> ${translations[currentLanguage].loading} </p> <div class="_sd_spinner" id="_sd_spinner"></div> <div class="_sd_warning" id="_sd_warning"> ${translations[currentLanguage].warning} </div> <div class="_sd_xp_info"> <span id="_sd_xp_label_modal">${translations[currentLanguage].xpGained}:</span> <span id="_xpAmount_modal">0</span> XP </div> <button id="_sd_stop_btn" class="_sd_stop_btn"> ${translations[currentLanguage].stop} </button> </div> </div> `; document.body.insertAdjacentHTML('beforeend', containerHTML); const JWT = getJwtToken(); if (!JWT) { document.getElementById("_sd_start_btn").disabled = true; document.getElementById("_sd_welcome").innerText = translations[currentLanguage].notLoggedIn; return; } const HEADERS = formatHeaders(JWT); try { const { username, fromLanguage, learningLanguage } = await getUserInfo( decodeJwtToken(JWT).sub, HEADERS ); document.getElementById("_sd_welcome").innerHTML = `${translations[currentLanguage].hello} <strong>${username}</strong>! 🎉`; const sessionPayload = { challengeTypes: [ "assist", "characterIntro", "characterMatch", "characterPuzzle", "characterSelect", "characterTrace", "characterWrite", "completeReverseTranslation", "definition", "dialogue", "extendedMatch", "extendedListenMatch", "form", "freeResponse", "gapFill", "judge", "listen", "listenComplete", "listenMatch", "match", "name", "listenComprehension", "listenIsolation", "listenSpeak", "listenTap", "orderTapComplete", "partialListen", "partialReverseTranslate", "patternTapComplete", "radioBinary", "radioImageSelect", "radioListenMatch", "radioListenRecognize", "radioSelect", "readComprehension", "reverseAssist", "sameDifferent", "select", "selectPronunciation", "selectTranscription", "svgPuzzle", "syllableTap", "syllableListenTap", "speak", "tapCloze", "tapClozeTable", "tapComplete", "tapCompleteTable", "tapDescribe", "translate", "transliterate", "transliterationAssist", "typeCloze", "typeClozeTable", "typeComplete", "typeCompleteTable", "writeComprehension" ], fromLanguage, learningLanguage, type: "GLOBAL_PRACTICE" }; const updateSessionPayload = { heartsLeft: 0, startTime: Math.floor(Date.now() / 1000), enableBonusPoints: false, endTime: Math.floor(Date.now() / 1000) + 112, failed: false, maxInLessonStreak: 9, shouldLearnThings: true }; document.getElementById("_sd_toggle_btn").addEventListener("click", () => { isVisible = !isVisible; document.getElementById("_sd_container").classList.toggle("hidden", !isVisible); document.getElementById("_sd_toggle_btn").innerHTML = isVisible ? "→" : "←"; }); document.getElementById("_sd_start_btn").addEventListener("click", () => { document.getElementById("_sd_overlay").style.display = "flex"; document.getElementById("_sd_status_dot").classList.add("active"); document.getElementById("_sd_status_text").innerText = `${translations[currentLanguage].status}: ${translations[currentLanguage].active}`; isFarming = true; const syncXpCounters = () => { const mainXp = document.getElementById("_xpAmount").innerText; document.getElementById("_xpAmount_modal").innerText = mainXp; }; const observer = new MutationObserver(syncXpCounters); observer.observe(document.getElementById("_xpAmount"), { childList: true, subtree: true }); farmXp(HEADERS, sessionPayload, updateSessionPayload); }); document.getElementById("_sd_stop_btn").addEventListener("click", () => { document.getElementById("_sd_overlay").style.display = "none"; document.getElementById("_sd_status_dot").classList.remove("active"); document.getElementById("_sd_status_text").innerText = `${translations[currentLanguage].status}: ${translations[currentLanguage].inactive}`; isFarming = false; const startBtn = document.getElementById("_sd_start_btn"); startBtn.disabled = true; startBtn.innerText = "..."; setTimeout(() => { startBtn.disabled = false; startBtn.innerText = translations[currentLanguage].start; }, 2000); }); document.getElementById("_sd_language_switcher").addEventListener("click", () => { currentLanguage = currentLanguage === "en" ? "vi" : "en"; updateLanguage(); }); document.getElementById("_sd_tab_farm_gems").addEventListener("click", () => { window.open("https://discord.gg/ufBrcGemBH", "_blank"); }); document.getElementById("_sd_tab_upgrade").addEventListener("click", () => { window.open("https://duolingo.click", "_blank"); }); } catch (error) { console.error("Error initializing SuperDuolingo:", error); document.getElementById("_sd_start_btn").disabled = true; document.getElementById("_sd_welcome").innerText = translations[currentLanguage].notLoggedIn; } }; const updateLanguage = () => { const elements = { "_sd_title": translations[currentLanguage].title, "_sd_welcome": translations[currentLanguage].welcome, "_sd_language_switcher": translations[currentLanguage].switchLang, "_sd_start_btn": translations[currentLanguage].start, "_sd_xp_label": translations[currentLanguage].xpGained, "_sd_xp_label_modal": translations[currentLanguage].xpGained, "_sd_modal_title": translations[currentLanguage].title, "_sd_loading_message": translations[currentLanguage].loading, "_sd_warning": translations[currentLanguage].warning, "_sd_stop_btn": translations[currentLanguage].stop }; Object.entries(elements).forEach(([id, text]) => { const element = document.getElementById(id); if (element) element.innerText = text; }); document.querySelector("#_sd_tab_farm_xp span").innerText = translations[currentLanguage].farmXp; document.querySelector("#_sd_tab_farm_gems span").innerText = translations[currentLanguage].farmGems; document.querySelector("#_sd_tab_upgrade span").innerText = translations[currentLanguage].upgrade; const statusDot = document.getElementById("_sd_status_dot"); const statusText = document.getElementById("_sd_status_text"); const isActive = statusDot.classList.contains("active"); statusText.innerText = `${translations[currentLanguage].status}: ${isActive ? translations[currentLanguage].active : translations[currentLanguage].inactive}`; }; const addTabClickEvents = () => { document.querySelectorAll("._sd_tab").forEach(tab => { tab.addEventListener("click", () => { document.querySelectorAll("._sd_tab").forEach(t => t.classList.remove("active")); tab.classList.add("active"); }); }); }; const addKeyboardShortcuts = () => { document.addEventListener("keydown", (e) => { if (e.ctrlKey && e.shiftKey && e.key === 'D') { e.preventDefault(); document.getElementById("_sd_toggle_btn").click(); } if (e.key === 'Escape' && document.getElementById("_sd_overlay").style.display === "flex") { document.getElementById("_sd_stop_btn").click(); } }); }; const addSoundEffects = () => { const playSound = (frequency, duration) => { if (typeof AudioContext !== 'undefined' || typeof webkitAudioContext !== 'undefined') { const audioContext = new (window.AudioContext || window.webkitAudioContext)(); const oscillator = audioContext.createOscillator(); const gainNode = audioContext.createGain(); oscillator.connect(gainNode); gainNode.connect(audioContext.destination); oscillator.frequency.value = frequency; oscillator.type = 'sine'; gainNode.gain.setValueAtTime(0.1, audioContext.currentTime); gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + duration); oscillator.start(audioContext.currentTime); oscillator.stop(audioContext.currentTime + duration); } }; const originalXpElement = document.getElementById("_xpAmount"); if (originalXpElement) { const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.type === 'childList' || mutation.type === 'characterData') { const newValue = parseInt(mutation.target.textContent || mutation.target.innerText); if (newValue > 0 && isFarming) { playSound(800, 0.2); } } }); }); observer.observe(originalXpElement, { childList: true, subtree: true, characterData: true }); } }; const addAnimations = () => { const xpCounter = document.getElementById("_xpAmount"); if (xpCounter) { const observer = new MutationObserver(() => { xpCounter.style.transform = "scale(1.2)"; xpCounter.style.color = "var(--success-color)"; setTimeout(() => { xpCounter.style.transform = "scale(1)"; xpCounter.style.color = "var(--primary-color)"; }, 300); }); observer.observe(xpCounter, { childList: true, subtree: true }); } }; const addTooltips = () => { const tooltips = { "_sd_tab_farm_xp": "Farm XP automatically to level up faster", "_sd_tab_farm_gems": "Join our Discord community for gem farming", "_sd_tab_upgrade": "Upgrade to Pro version for more features", "_sd_toggle_btn": "Toggle SuperDuolingo panel (Ctrl+Shift+D)" }; Object.entries(tooltips).forEach(([id, text]) => { const element = document.getElementById(id); if (element) { element.title = text; } }); }; const init = () => { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initSuperDuolingo); } else { initSuperDuolingo(); } setTimeout(() => { addTabClickEvents(); addKeyboardShortcuts(); addSoundEffects(); addAnimations(); addTooltips(); const xpElement = document.getElementById("_xpAmount"); if (xpElement) { const observer = new MutationObserver(() => { const currentXp = parseInt(xpElement.innerText) || 0; }); observer.observe(xpElement, { childList: true, subtree: true }); } }, 1000); }; let inactivityTimer; const resetInactivityTimer = () => { clearTimeout(inactivityTimer); inactivityTimer = setTimeout(() => { if (!isFarming && isVisible) { document.getElementById("_sd_toggle_btn").click(); } }, 300000); }; ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart'].forEach(event => { document.addEventListener(event, resetInactivityTimer, true); }); const logError = (error, context) => { console.error(`[SuperDuolingo] Error in ${context}:`, error); }; if (typeof module !== 'undefined' && module.exports) { module.exports = { initSuperDuolingo, updateLanguage, farmXp, getJwtToken, formatHeaders }; } init(); })();