Duo_KeepStreak

Automatically maintains the daily streak on Duolingo.

目前为 2025-02-04 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Duo_KeepStreak
  3. // @namespace HACKER_DUOLINGO_666
  4. // @version 1.01BETA
  5. // @description Automatically maintains the daily streak on Duolingo.
  6. // @author HACKER_DUOLINGO_666
  7. // @match https://*.duolingo.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=duolingo.com
  9. // ==/UserScript==
  10.  
  11. const getToken = () => document.cookie.split('; ').find(row => row.startsWith('jwt_token='))?.split('=')[1] || null;
  12.  
  13. const parseJwt = token => {
  14. try {
  15. return JSON.parse(atob(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/')));
  16. } catch (e) {
  17. console.error("JWT parsing error", e);
  18. return null;
  19. }
  20. };
  21.  
  22. const getHeaders = token => ({
  23. "Content-Type": "application/json",
  24. "Authorization": `Bearer ${token}`,
  25. "User-Agent": navigator.userAgent
  26. });
  27.  
  28. const fetchUserData = async (userId, headers) => {
  29. const response = await fetch(`https://www.duolingo.com/2017-06-30/users/${userId}?fields=fromLanguage,learningLanguage,streakData`, { headers });
  30. return response.json();
  31. };
  32.  
  33. const hasStreakToday = data => data.streakData?.currentStreak?.endDate === new Date().toISOString().split('T')[0];
  34.  
  35. const startSession = async (fromLang, learningLang, headers) => {
  36. const payload = {
  37. challengeTypes: ["translate", "match", "tapComplete", "reverseAssist", "judge"],
  38. fromLanguage: fromLang,
  39. learningLanguage: learningLang,
  40. type: "GLOBAL_PRACTICE"
  41. };
  42. const response = await fetch("https://www.duolingo.com/2017-06-30/sessions", { method: 'POST', headers, body: JSON.stringify(payload) });
  43. return response.json();
  44. };
  45.  
  46. const completeSession = async (session, headers) => {
  47. const payload = { ...session, heartsLeft: 0, failed: false, shouldLearnThings: true };
  48. const response = await fetch(`https://www.duolingo.com/2017-06-30/sessions/${session.id}`, { method: 'PUT', headers, body: JSON.stringify(payload) });
  49. return response.json();
  50. };
  51.  
  52. const attemptStreak = async () => {
  53. const token = getToken();
  54. if (!token) return alert("You are not logged into Duolingo!");
  55.  
  56. const userId = parseJwt(token)?.sub;
  57. if (!userId) return alert("Error retrieving user ID.");
  58.  
  59. const headers = getHeaders(token);
  60. const userData = await fetchUserData(userId, headers);
  61.  
  62. if (hasStreakToday(userData)) return alert("You have streak today!Reload the page to enjoy :)))");
  63.  
  64. try {
  65. const session = await startSession(userData.fromLanguage, userData.learningLanguage, headers);
  66. await completeSession(session, headers);
  67. alert("Streak successfully maintained!");
  68. } catch (error) {
  69. console.error("Error maintaining streak", error);
  70. alert("Error while maintaining streak, please try again!");
  71. }
  72. };
  73.  
  74. const createUI = () => {
  75. const button = document.createElement('button');
  76. button.textContent = 'Get Streak';
  77. button.style = "position:fixed; bottom:20px; right:20px; padding:10px; background:#28a745; color:white; border:none; border-radius:5px; cursor:pointer;";
  78. document.body.appendChild(button);
  79. button.onclick = attemptStreak;
  80. };
  81.  
  82. createUI();

QingJ © 2025

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