您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
THIS TOOL AUTO FARMED GEMS FOR YOU
// ==UserScript== // @name DUO_FARMEDGEMS // @namespace http://tampermonkey.net/ // @version v1.0BETA // @description THIS TOOL AUTO FARMED GEMS FOR YOU // @author ´꒳`ⓎⒶⓂⒾⓈⒸⓇⒾⓅⓉ×͜× // @match https://www.duolingo.com/learn // @icon https://www.google.com/s2/favicons?sz=64&domain=duolingo.com // @grant none // ==/UserScript== (function () { 'use strict'; const colors = { primary: '#58CC02', secondary: '#1DA462', danger: '#FF4757', background: '#003049', text: '#FFFFFF' }; function createElement(tag, options = {}) { const el = document.createElement(tag); if (options.styles) Object.assign(el.style, options.styles); if (options.content) el.innerHTML = options.content; if (options.events) { for (const [event, handler] of Object.entries(options.events)) { el.addEventListener(event, handler); } } return el; } function createBtn(label, bg, shadow, onClick) { return createElement('button', { styles: { flex: '1 1 120px', padding: '12px 0', fontSize: '16px', fontWeight: '600', background: bg, color: colors.text, border: 'none', borderRadius: '15px', cursor: 'pointer', transition: 'transform 0.3s ease', boxShadow: `0 8px 25px ${shadow}66`, minWidth: '120px' }, content: label, events: { click: onClick, mouseenter: e => e.currentTarget.style.transform = 'translateY(-2px)', mouseleave: e => e.currentTarget.style.transform = 'translateY(0)' } }); } function createSmallBtn(label, bg, shadow, onClick) { return createElement('button', { styles: { padding: '8px 16px', fontSize: '13px', fontWeight: '500', background: bg, color: colors.text, border: 'none', borderRadius: '10px', cursor: 'pointer', transition: 'transform 0.2s ease', boxShadow: `0 5px 15px ${shadow}44`, margin: '5px' }, content: label, events: { click: onClick, mouseenter: e => e.currentTarget.style.transform = 'translateY(-1px)', mouseleave: e => e.currentTarget.style.transform = 'translateY(0)' } }); } const gemBtn = createElement('button', { styles: { position: 'fixed', bottom: '25px', right: '10px', width: '60px', height: '60px', borderRadius: '50%', background: `linear-gradient(135deg, ${colors.primary}, ${colors.secondary})`, color: colors.text, fontSize: '32px', cursor: 'pointer', zIndex: 10000, boxShadow: '0 8px 20px rgba(88, 204, 2, 0.3)', transition: 'transform 0.3s ease', border: 'none', display: 'flex', alignItems: 'center', justifyContent: 'center' }, content: '💎', events: { click: togglePanel } }); const panel = createElement('div', { styles: { position: 'fixed', top: '50%', left: '50%', width: '460px', background: colors.background, borderRadius: '25px', zIndex: 10000, padding: '30px', fontFamily: "'Segoe UI', system-ui", color: colors.text, opacity: '0', transform: 'translate(-50%, -50%) scale(0.9)', pointerEvents: 'none', transition: 'opacity 0.4s ease, transform 0.4s ease', overflow: 'hidden', minHeight: '320px', display: 'flex', flexDirection: 'column' } }); panel.id = 'duoPanel'; const style = document.createElement('style'); style.textContent = ` @keyframes borderAnim { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } } #duoPanel { border: 2px solid transparent; background-origin: border-box; background-clip: padding-box, border-box; background-image: linear-gradient(${colors.background}, ${colors.background}), linear-gradient(270deg, #58CC02, #1DA462, #FF4757, #58CC02); background-size: 400% 400%; background-repeat: no-repeat; animation: borderAnim 10s linear infinite; } #duoPanel.active { opacity: 1 !important; transform: translate(-50%, -50%) scale(1) !important; pointer-events: auto !important; } `; document.head.appendChild(style); function togglePanel() { panel.classList.toggle('active'); gemBtn.style.transform = panel.classList.contains('active') ? 'rotate(360deg)' : 'rotate(0deg)'; } const header = createElement('div', { styles: { textAlign: 'center', marginBottom: '10px' }, content: ` <h1 style="margin: 0 0 10px 0; font-size: 32px; background: linear-gradient(45deg, ${colors.primary}, ${colors.secondary}, ${colors.text}cc); -webkit-background-clip: text; background-clip: text; color: transparent; font-weight: 700; letter-spacing: 1px;"> DUO_FARMEDGEMS</h1> <p style="margin: 0; color: ${colors.text}; font-size: 14px;">MADE BY YAMISCRIPT_DEV</p> <p id="_loginStatus">LOADING...</p> ` }); const usernameGreeting = createElement('div', { styles: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '12px', marginBottom: '20px', fontSize: '18px', color: colors.text }, }); async function fetchUsername() { const userId = getCookie('logged_out_uuid'); const jwt = getCookie('jwt_token'); if (!userId || !jwt) return; try { const res = await fetch(`https://www.duolingo.com/2017-06-30/users/${userId}?fields=username`, { headers: { authorization: `Bearer ${jwt}` } }); const data = await res.json(); if (data.username) { document.getElementById('_loginStatus').innerHTML = ``; usernameGreeting.innerHTML = `<span>👋Welcome, <b style="color: ${colors.primary}">${data.username}</b>!</span>`; } } catch (e) { document.getElementById('_loginStatus').innerText = 'BRUH!'; } } const gemCountDiv = createElement('div', { styles: { textAlign: 'center', margin: '20px 0' }, content: `<div id="gemCount" style="font-size: 42px; font-weight: 700; color: ${colors.primary}; text-shadow: 0 4px 12px rgba(88,204,2,0.2); margin-top: 10px;">0</div>` }); const btnGroup = createElement('div', { styles: { display: 'flex', gap: '15px', justifyContent: 'center', margin: '25px 0', flexWrap: 'wrap' } }); const statusText = createElement('div', { styles: { textAlign: 'center', color: colors.text + '99', fontSize: '14px', marginTop: '5px' }, content: '<span id="statusText">NON-ACTIVE:❌</span>' }); const startBtn = createBtn('START', `linear-gradient(135deg, ${colors.primary}, ${colors.secondary})`, colors.primary, startFarm); const stopBtn = createBtn('STOP', `linear-gradient(135deg, ${colors.danger}, #CC2E3D)`, colors.danger, stopFarm); stopBtn.style.display = 'none'; const discordBtn = createBtn('DISCORD', `linear-gradient(135deg, ${colors.secondary}, ${colors.primary})`, colors.secondary, () => window.open('https://discord.gg/aDD9DMz6', '_blank')); const profileBtn = createBtn('PROFILE', `linear-gradient(135deg, ${colors.primary}, ${colors.secondary})`, colors.primary, () => window.open('https://guns.lol/yamiscript_dev')); const settingBtn = createBtn('SETTING', `linear-gradient(135deg, ${colors.primary}, ${colors.secondary})`, colors.primary, showTokenPanel); const tokenPanel = createElement('div', { styles: { display: 'none', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', padding: '20px', borderRadius: '15px', backgroundColor: '#144d1d', marginTop: '15px', textAlign: 'center', fontSize: '14px', userSelect: 'text' } }); const tokenTextarea = createElement('textarea', { styles: { width: '100%', height: '80px', borderRadius: '10px', border: 'none', resize: 'none', padding: '10px', fontSize: '14px', fontFamily: 'monospace', marginBottom: '12px', backgroundColor: '#0b2e0f', color: '#a6e22e' }, events: { focus: (e) => e.target.select() } }); const copyTokenBtn = createSmallBtn('Copy token', `linear-gradient(135deg, ${colors.primary}, ${colors.secondary})`, colors.primary, () => { tokenTextarea.select(); document.execCommand('copy'); copyTokenBtn.textContent = 'Copied!'; setTimeout(() => copyTokenBtn.textContent = 'Copy token', 2000); }); const closeTokenBtn = createSmallBtn('Close', colors.danger, colors.danger, showMainPanel); tokenPanel.append( createElement('div', { content: '<b>Token JWT of you:</b>', styles: { marginBottom: '10px', fontSize: '10px' } }), tokenTextarea, copyTokenBtn, closeTokenBtn ); btnGroup.append(startBtn, stopBtn, discordBtn, profileBtn, settingBtn); panel.append(header, usernameGreeting, gemCountDiv, btnGroup, statusText, tokenPanel); document.body.append(gemBtn, panel); let farming = false; let gemCount = parseInt(localStorage.getItem('gemsCount')) || 0; let farmInterval; function updateGemCount() { localStorage.setItem('gemsCount', gemCount); document.getElementById('gemCount').textContent = gemCount; } function showTokenPanel() { const token = getCookie('jwt_token') || 'Không tìm thấy token'; tokenTextarea.value = token; btnGroup.style.display = 'none'; statusText.style.display = 'none'; gemCountDiv.style.display = 'none'; tokenPanel.style.display = 'flex'; } function showMainPanel() { tokenPanel.style.display = 'none'; btnGroup.style.display = 'flex'; statusText.style.display = 'block'; gemCountDiv.style.display = 'block'; } function getCookie(name) { const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)')); return match ? match[2] : null; } async function farmGems() { try { const userId = getCookie('logged_out_uuid'); const jwt = getCookie('jwt_token'); const res = await fetch(`https://www.duolingo.com/2017-06-30/users/${userId}/rewards/CAPSTONE_COMPLETION-xxxx-2-GEMS`, { method: 'PATCH', headers: { accept: 'application/json', authorization: 'Bearer ' + jwt, 'content-type': 'application/json' }, body: JSON.stringify({ amount: 0, consumed: true, skillId: 'xxx', type: 'mission' }) }); if (res.status === 200) { for (let i = 1; i <= 15; i++) { setTimeout(() => { gemCount++; updateGemCount(); }, i * 250); } } } catch (err) { console.error('Lỗi farm:', err); } } function startFarm() { if (!farming) { farming = true; startBtn.style.display = 'none'; stopBtn.style.display = 'block'; document.getElementById('statusText').textContent = 'ACTIVE:✅'; farmInterval = setInterval(farmGems, 100); } } function stopFarm() { farming = false; clearInterval(farmInterval); stopBtn.style.display = 'none'; startBtn.style.display = 'block'; document.getElementById('statusText').textContent = 'NON-ACTIVE:❌'; updateGemCount(); } window.addEventListener('load', () => { fetchUsername(); updateGemCount(); }); window.onbeforeunload = () => farming ? 'Đang farm gems - Bạn có chắc chắn muốn thoát?' : null; })();