// ==UserScript== // @name Duo_KeepStreak // @namespace HACKER_DUOLINGO_666 // @version 1.01BETA // @description Automatically maintains the daily streak on Duolingo. // @author HACKER_DUOLINGO_666 // @match https://*.duolingo.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=duolingo.com // @downloadURL none // ==/UserScript== const getToken = () => document.cookie.split('; ').find(row => row.startsWith('jwt_token='))?.split('=')[1] || null; const parseJwt = token => { try { return JSON.parse(atob(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/'))); } catch (e) { console.error("JWT parsing error", e); return null; } }; const getHeaders = token => ({ "Content-Type": "application/json", "Authorization": `Bearer ${token}`, "User-Agent": navigator.userAgent }); const fetchUserData = async (userId, headers) => { const response = await fetch(`https://www.duolingo.com/2017-06-30/users/${userId}?fields=fromLanguage,learningLanguage,streakData`, { headers }); return response.json(); }; const hasStreakToday = data => data.streakData?.currentStreak?.endDate === new Date().toISOString().split('T')[0]; const startSession = async (fromLang, learningLang, headers) => { const payload = { challengeTypes: ["translate", "match", "tapComplete", "reverseAssist", "judge"], fromLanguage: fromLang, learningLanguage: learningLang, type: "GLOBAL_PRACTICE" }; const response = await fetch("https://www.duolingo.com/2017-06-30/sessions", { method: 'POST', headers, body: JSON.stringify(payload) }); return response.json(); }; const completeSession = async (session, headers) => { const payload = { ...session, heartsLeft: 0, failed: false, shouldLearnThings: true }; const response = await fetch(`https://www.duolingo.com/2017-06-30/sessions/${session.id}`, { method: 'PUT', headers, body: JSON.stringify(payload) }); return response.json(); }; const attemptStreak = async () => { const token = getToken(); if (!token) return alert("You are not logged into Duolingo!"); const userId = parseJwt(token)?.sub; if (!userId) return alert("Error retrieving user ID."); const headers = getHeaders(token); const userData = await fetchUserData(userId, headers); if (hasStreakToday(userData)) return alert("You have streak today!Reload the page to enjoy :)))"); try { const session = await startSession(userData.fromLanguage, userData.learningLanguage, headers); await completeSession(session, headers); alert("Streak successfully maintained!"); } catch (error) { console.error("Error maintaining streak", error); alert("Error while maintaining streak, please try again!"); } }; const createUI = () => { const button = document.createElement('button'); button.textContent = 'Get Streak'; button.style = "position:fixed; bottom:20px; right:20px; padding:10px; background:#28a745; color:white; border:none; border-radius:5px; cursor:pointer;"; document.body.appendChild(button); button.onclick = attemptStreak; }; createUI();