Duo_KeepStreak

Automatically maintains the daily streak on Duolingo.

目前為 2025-02-05 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Duo_KeepStreak
// @namespace    HACKER_DUOLINGO_666
// @version      1.0.1
// @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
// ==/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 already maintained your streak today!");

    try {
        const session = await startSession(userData.fromLanguage, userData.learningLanguage, headers);
        await completeSession(session, headers);
        alert("🎉 Streak has been maintained! Reload the page to check.");
    } catch (error) {
        console.error("Streak maintenance error", error);
        alert("⚠️ Error maintaining streak, try again!");
    }
};

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址