DuohackerMAX v3

Real server-based XP, streak, gems, and perfect lesson manipulation for Duolingo

  1. // ==UserScript==
  2. // @name DuohackerMAX v3
  3. // @namespace https://duohackermax.net
  4. // @version 3.0
  5. // @description Real server-based XP, streak, gems, and perfect lesson manipulation for Duolingo
  6. // @author misbisshi & ChatGPT
  7. // @match https://www.duolingo.com/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. // Basic UI
  15. const panel = document.createElement('div');
  16. panel.innerHTML = `
  17. <div style="position:fixed;top:20px;right:20px;z-index:9999;background:#58cc02;padding:15px;border-radius:10px;color:white;font-family:sans-serif;">
  18. <h3>DuohackerMAX v3</h3>
  19. <input id="xp_input" type="number" placeholder="XP (예: 10000)" style="width:90%;margin:5px;"><br>
  20. <input id="streak_input" type="number" placeholder="스트릭 (예: 600)" style="width:90%;margin:5px;"><br>
  21. <input id="gems_input" type="number" placeholder="보석 (예: 9999)" style="width:90%;margin:5px;"><br>
  22. <input id="lesson_input" type="number" placeholder="레슨 수 (퍼펙트)" style="width:90%;margin:5px;"><br>
  23. <button id="duo_claim" style="width:95%;margin-top:8px;background:#ffcc00;border:none;padding:8px;border-radius:6px;">콱콱 적용</button>
  24. <div id="duo_status" style="margin-top:10px;font-size:0.9em;"></div>
  25. </div>
  26. `;
  27. document.body.appendChild(panel);
  28.  
  29. const getJWT = () => {
  30. const match = document.cookie.match(/jwt_token=([^;]+)/);
  31. return match ? match[1] : null;
  32. };
  33.  
  34. const sendSession = (data, jwt) => {
  35. return fetch("https://www.duolingo.com/2017-06-30/sessions", {
  36. method: "POST",
  37. headers: {
  38. "Content-Type": "application/json",
  39. "Authorization": `Bearer ${jwt}`
  40. },
  41. body: JSON.stringify(data)
  42. });
  43. };
  44.  
  45. document.getElementById("duo_claim").onclick = async function() {
  46. const xp = parseInt(document.getElementById("xp_input").value) || 0;
  47. const streak = parseInt(document.getElementById("streak_input").value) || 0;
  48. const gems = parseInt(document.getElementById("gems_input").value) || 0;
  49. const lessons = parseInt(document.getElementById("lesson_input").value) || 0;
  50. const jwt = getJWT();
  51. const status = document.getElementById("duo_status");
  52.  
  53. if (!jwt) {
  54. status.innerHTML = "JWT 토큰을 찾을 수 없습니다. 로그인 상태를 확인하세요.";
  55. return;
  56. }
  57.  
  58. // XP 조작
  59. if (xp > 0) {
  60. await sendSession({
  61. xpGain: xp,
  62. skillId: "global",
  63. fromLanguage: "en",
  64. isFinalLevel: true,
  65. type: "practice",
  66. startTime: new Date().toISOString(),
  67. endTime: new Date().toISOString()
  68. }, jwt);
  69. }
  70.  
  71. // 스트릭 조작
  72. for (let i = 0; i < streak; i++) {
  73. const date = new Date();
  74. date.setDate(date.getDate() - i);
  75. await sendSession({
  76. xpGain: 10,
  77. skillId: "streak",
  78. fromLanguage: "en",
  79. type: "practice",
  80. startTime: date.toISOString(),
  81. endTime: date.toISOString()
  82. }, jwt);
  83. }
  84.  
  85. // 퍼펙트 레슨 조작
  86. for (let i = 0; i < lessons; i++) {
  87. await sendSession({
  88. xpGain: 20,
  89. perfect: true,
  90. lessonCompleted: true,
  91. fromLanguage: "en",
  92. skillId: "perfect",
  93. type: "lesson",
  94. startTime: new Date().toISOString(),
  95. endTime: new Date().toISOString()
  96. }, jwt);
  97. }
  98.  
  99. status.innerHTML = `적용 완료! XP: ${xp}, 스트릭: ${streak}일, 퍼펙트 레슨: ${lessons}`;
  100. };
  101. })();