Size
389.9 KB
Version
3.1BETA.03
Created
Nov 29, 2025
Updated
3 months ago
1// ==UserScript==
2// @name Duolingo PRO
3// @namespace https://duolingopro.net
4// @version 3.1BETA.03
5// @description The fastest Duolingo XP gainer, working as of November 2025.
6// @author anonymousHackerIV
7// @match https://*.duolingo.com/*
8// @match https://*.duolingo.cn/*
9// @icon https://www.duolingopro.net/static/favicons/duo/128/light/primary.png
10// @grant GM_log
11// @antifeature payment
12// @downloadURL https://update.greasyfork.org/scripts/473310/Duolingo%20PRO.user.js
13// @updateURL https://update.greasyfork.org/scripts/473310/Duolingo%20PRO.meta.js
14// ==/UserScript==
15
16let storageLocal;
17let storageSession;
18let versionNumber = "05";
19let storageLocalVersion = "05";
20let storageSessionVersion = "05";
21let versionName = "BETA.03";
22let versionFull = "3.1BETA.03";
23let versionFormal = "3.1 BETA.03";
24let serverURL = "https://www.duolingopro.net";
25let apiURL = "https://api.duolingopro.net";
26let greasyfork = true;
27let alpha = false;
28
29let hidden = false;
30let lastPage;
31let currentPage = 1;
32let windowBlurState = true;
33
34let solvingIntervalId;
35let isAutoMode;
36let findReactMainElementClass = '_3yE3H';
37let reactTraverseUp = 1;
38
39const debug = false;
40const flag01 = false;
41const flag02 = false;
42const flag03 = false;
43
44// USAGE OR MODIFICATION OF THIS SCRIPT IMPLIES YOU AGREE TO THE TERMS AND CONDITIONS PRESENTED IN THE SCRIPT. IF YOU DO NOT AGREE, DO NOT USE OR MODIFY THIS SCRIPT.
45
46(function buildOrMigrateStorageLocal() {
47 let tempRandom16 = Array.from({ length: 16 }, () => 'abcdefghijklmnopqrstuvwxyz0123456789'[Math.floor(Math.random() * 36)]).join('');
48 let tempTimestamp = Date.now();
49
50 const DEFAULTS = {
51 version: versionNumber,
52 terms: "00",
53 random16: tempRandom16,
54 pins: {
55 home: ["DLP_Get_XP_1_ID", "DLP_Get_GEM_1_ID"],
56 legacy: ["DLP_Get_PATH_1_ID", "DLP_Get_PRACTICE_1_ID"]
57 },
58 settings: {
59 autoUpdate: !greasyfork,
60 showSolveButtons: true,
61 showAutoServerButton: alpha,
62 muteLessons: false,
63 anonymousUsageData: alpha,
64 solveSpeed: 0.9
65 },
66 stats: {
67 modern: {
68 xp: 0,
69 gem: 0,
70 streak: 0,
71 super: 0,
72 heart_refill: 0,
73 streak_freeze: 0,
74 double_xp_boost: 0
75 },
76 legacy: {
77 path: {
78 lessons: 0,
79 questions: 0
80 },
81 practice: {
82 lessons: 0,
83 questions: 0
84 },
85 listen: {
86 lessons: 0,
87 questions: 0
88 },
89 lesson: {
90 lessons: 0,
91 questions: 0
92 }
93 },
94 tracking_since: tempTimestamp
95 },
96 chats: [],
97 notifications: [{ id: "0000" }],
98 tips: { seeMore1: false },
99 languagePackVersion: "00",
100 onboarding: false,
101 storageVersion: storageLocalVersion
102 };
103
104 function isPlainObject(v) {
105 return Object.prototype.toString.call(v) === "[object Object]";
106 }
107 function safeParse(json) {
108 try {
109 const v = JSON.parse(json);
110 return isPlainObject(v) ? v : null;
111 } catch {
112 return null;
113 }
114 }
115
116 function mergeWithPrune(existing, defaults) {
117 const result = Array.isArray(defaults) ? [] : {};
118 for (const key of Object.keys(defaults)) {
119 const defVal = defaults[key];
120 const hasExisting = existing && Object.prototype.hasOwnProperty.call(existing, key);
121 const exVal = hasExisting ? existing[key] : undefined;
122
123 if (isPlainObject(defVal)) {
124 if (isPlainObject(exVal)) {
125 result[key] = mergeWithPrune(exVal, defVal);
126 } else {
127 result[key] = mergeWithPrune({}, defVal); // take full default subtree
128 }
129 } else if (Array.isArray(defVal)) {
130 result[key] = Array.isArray(exVal) ? exVal : defVal.slice();
131 } else {
132 // primitives / everything else: keep existing if present, else default
133 result[key] = hasExisting ? exVal : defVal;
134 }
135 }
136 // Unknown keys in `existing` are intentionally NOT copied (pruned)
137 return result;
138 }
139
140 const raw = localStorage.getItem("DLP_Local_Storage");
141 const existing = safeParse(raw);
142
143 // Migrate: replace old "DLP_Get_GEMS_1_ID" pin with new "DLP_Get_GEM_1_ID"
144 if (existing && existing.pins && Array.isArray(existing.pins.home)) {
145 const legacyIndex = existing.pins.home.indexOf("DLP_Get_GEMS_1_ID");
146 if (legacyIndex !== -1) {
147 existing.pins.home[legacyIndex] = "DLP_Get_GEM_1_ID";
148 }
149 }
150
151 // Fresh write if missing or unparsable
152 if (!existing) {
153 const fresh = { ...DEFAULTS, storageVersion: storageLocalVersion };
154 localStorage.setItem("DLP_Local_Storage", JSON.stringify(fresh));
155 storageLocal = fresh;
156 return;
157 }
158
159 // Up-to-date -> just use it
160 if (existing.storageVersion === storageLocalVersion) {
161 storageLocal = existing;
162 return;
163 }
164
165 // Migrate: keep existing values where keys match, add missing defaults, drop extras
166 const migrated = mergeWithPrune(existing, DEFAULTS);
167
168 // Ensure we actually bump the version so we don't re-migrate on next load
169 migrated.storageVersion = storageLocalVersion;
170
171 localStorage.setItem("DLP_Local_Storage", JSON.stringify(migrated));
172 storageLocal = migrated;
173})();
174function saveStorageLocal() {
175 localStorage.setItem("DLP_Local_Storage", JSON.stringify(storageLocal));
176}
177
178if (sessionStorage.getItem("DLP_Session_Storage") == null || JSON.parse(sessionStorage.getItem("DLP_Session_Storage")).storageVersion !== storageSessionVersion) {
179 sessionStorage.setItem("DLP_Session_Storage", JSON.stringify({
180 "legacy": {
181 "page": 0,
182 "status": false,
183 "path": {
184 "type": "lesson",
185 "amount": 0
186 },
187 "practice": {
188 "type": "lesson",
189 "amount": 0
190 },
191 "listen": {
192 "type": "lesson",
193 "amount": 0
194 },
195 "lesson": {
196 "section": 1,
197 "unit": 1,
198 "level": 1,
199 "type": "lesson",
200 "amount": 0
201 }
202 },
203 "notifications": [
204 {
205 "id": "0001"
206 }
207 ],
208 "storageVersion": storageSessionVersion
209 }));
210 storageSession = JSON.parse(sessionStorage.getItem("DLP_Session_Storage"));
211} else {
212 storageSession = JSON.parse(sessionStorage.getItem("DLP_Session_Storage"));
213}
214function saveStorageSession() {
215 sessionStorage.setItem("DLP_Session_Storage", JSON.stringify(storageSession));
216}
217
218if (alpha) apiURL = "https://api.duolingopro.net/alpha";
219
220let systemLanguage = document.cookie.split('; ').find(row => row.startsWith('lang=')).split('=')[1];
221let systemText = {
222 en: {
223 1: "Switch to Legacy",
224 2: "Show",
225 3: "Connecting",
226 4: "Donate",
227 5: "Support",
228 6: "Settings",
229 7: "What's New",
230 8: "How much XP would you like to gain?",
231 9: "GET",
232 10: "How many Gems would you like to gain?",
233 12: "Would you like to redeem 3 days of Super Duolingo?",
234 13: "REDEEM",
235 14: "Terms & Conditions",
236 15: "See More",
237 16: "Back",
238 17: "How many lessons would you like to solve on the path?",
239 18: "START",
240 19: "How many practices would you like to solve?",
241 21: "How many listening practices would you like to solve? (Requires Super Duolingo)",
242 23: "Which and how many lessons would you like to repeat?",
243 25: "Please read and accept the Terms & Conditions to use Duolingo PRO 3.1.",
244 26: "These are the Terms & Conditions you agreed to use Duolingo PRO 3.1.",
245 27: "LOADING TERMS & CONDITIONS<br><br>YOU CANNOT USE THIS SOFTWARE UNTIL TERMS & CONDITIONS ARE LOADED",
246 28: "DECLINE",
247 29: "ACCEPT",
248 30: "Without accepting the Terms & Conditions, you cannot use Duolingo PRO 3.1.",
249 31: "BACK",
250 32: "Settings",
251 34: "Automatic Updates",
252 35: "Duolingo PRO 3.1 will automatically update itself when there's a new version available.",
253 37: "SAVE",
254 38: "Feedback",
255 39: "Help us make Duolingo PRO 3.1 better.",
256 40: "Write here as much as you can with as many details as possible.",
257 41: "Feedback Type: ",
258 42: "BUG REPORT",
259 43: "SUGGESTION",
260 44: "Add Attachment: (Optional)",
261 45: "UPLOAD",
262 47: "SEND",
263 48: "What's New",
264 51: "LEARN MORE",
265 52: "Welcome to",
266 53: "The next generation of Duolingo PRO is here, with Instant XP, Magnet UI, all powerful than ever. ",
267 54: "START",
268 100: "SOLVE",
269 101: "SOLVE ALL",
270 102: "PAUSE SOLVE",
271 103: "Hide",
272 104: "Show",
273 105: "Switch to 3.1",
274 106: "Switch to Legacy",
275 107: "STOP",
276 108: "Connected",
277 109: "Error",
278 110: "SEND",
279 111: "SENDING",
280 112: "SENT",
281 113: "LOADING",
282 114: "DONE",
283 115: "FAILED",
284 116: "SAVING AND APPLYING",
285 200: "Under Construction",
286 201: "The Gems function is currently under construction. We plan to make it accessible to everyone soon.",
287 202: "Update Available",
288 203: "You are using an outdated version of Duolingo PRO.<br><br>Please <a href='https://www.duolingopro.net/greasyfork' target='_blank' style='font-family: Duolingo PRO Rounded; color: #007AFF; text-decoration: underline;'>update Duolingo PRO</a> or turn on automatic updates.",
289 204: "Feedback Sent",
290 205: "Your feedback was successfully sent, and our developers will look over it. Keep in mind, we cannot respond back to your feedback.",
291 206: "Error Sending Feedback",
292 207: "Your feedback was not sent. This might be because you are using an outdated or a modified version of Duolingo PRO.",
293 208: "Unknown Error",
294 209: "Please try again later. An unknown error occurred. Number: ",
295 210: "hour",
296 211: "hours",
297 212: "minute",
298 213: "minutes",
299 214: "and",
300 215: "{hours} {hourUnit}",
301 216: "{minutes} {minuteUnit}",
302 217: "{hourPhrase} {conjunction} {minutePhrase}",
303 218: "XP Successfully Received",
304 219: "You received {amount} XP. You can request up to {remainingXP} XP before your limit resets back to {totalLimit} XP in {timeMessage}. To boost your limits, <a href='https://duolingopro.net/donate' target='_blank' style='font-family: Duolingo PRO Rounded; text-decoration: underline; color: #007AFF;'>donate</a>.",
305 220: "Super Duolingo Successfully Redeemed",
306 221: "You redeemed a 3 day Super Duolingo trial. You can request another 3 day Super Duolingo trial in {timeMessage}.",
307 222: "Limit Warning",
308 223: "You can only request up to {limitAmount} XP before your limit resets back to {totalLimitAmount} XP in {timeMessage}. To boost your limits, <a href='https://duolingopro.net/donate' target='_blank' style='font-family: Duolingo PRO Rounded; text-decoration: underline; color: #007AFF;'>donate</a>.",
309 224: "Limit Reached",
310 225: "You reached your XP limit for the next {timeMessage}. To boost your limits, <a href='https://duolingopro.net/donate' target='_blank' style='font-family: Duolingo PRO Rounded; text-decoration: underline; color: #007AFF;'>donate</a>.",
311 227: "You already redeemed a 3 day Super Duolingo trial. You can request another 3 day Super Duolingo trial in {timeMessage}.",
312 229: "REFILL",
313 230: "GEMS testing",
314 231: "Error Connecting",
315 232: "Duolingo PRO was unable to connect to our servers. This may be because our servers are temporarily unavailable or you are using an outdated version. Check for <a href='https://status.duolingopro.net' target='_blank' style='font-family: Duolingo PRO Rounded; text-decoration: underline; color: #007AFF;'>server status</a> or <a href='https://duolingopro.net/greasyfork' target='_blank' style='font-family: Duolingo PRO Rounded; text-decoration: underline; color: #007AFF;'>updates</a>.",
316 233: "Update Duolingo PRO",
317 234: "You are using an outdated version of Duolingo PRO. Please <a href='https://www.duolingopro.net/greasyfork' target='_blank' style='font-family: Duolingo PRO Rounded; color: #007AFF; text-decoration: underline;'>update Duolingo PRO</a>."
318 },
319};
320
321let CSS1;
322let HTML2;
323let CSS2;
324let HTML3;
325let HTML4;
326let HTML5;
327let CSS5;
328let HTML6;
329let CSS6;
330let HTML7;
331let CSS7;
332
333function Two() {
334CSS1 = `
335@font-face {
336 font-family: 'Duolingo PRO Rounded';
337 src: url(${serverURL}/static/fonts/V7R100DB1/Duolingo-PRO-Rounded-Semibold.woff2) format('woff2');
338 font-weight: 600;
339}
340
341:root {
342 --DLP-red-hex: #ff3b30;
343 --DLP-orange-hex: #ff9500;
344 --DLP-yellow-hex: #ffcc00;
345 --DLP-green-hex: #34c759;
346 --DLP-teal-hex: #00c7be;
347 --DLP-cyan-hex: #5ac8fa;
348 --DLP-blue-hex: #007aff;
349 --DLP-indigo-hex: #5856d6;
350 --DLP-purple-hex: #af52de;
351 --DLP-pink-hex: #ff2d55;
352
353 --DLP-red-rgb: rgb(255, 59, 48);
354 --DLP-orange-rgb: rgb(255, 149, 0);
355 --DLP-yellow-rgb: rgb(255, 204, 0);
356 --DLP-green-rgb: rgb(52, 199, 89);
357 --DLP-teal-rgb: rgb(0, 199, 190);
358 --DLP-cyan-rgb: rgb(90, 200, 250);
359 --DLP-blue-rgb: rgb(0, 122, 255);
360 --DLP-indigo-rgb: rgb(88, 86, 214);
361 --DLP-purple-rgb: rgb(175, 82, 222);
362 --DLP-pink-rgb: rgb(255, 45, 85);
363
364 --DLP-red: 255, 59, 48;
365 --DLP-orange: 255, 149, 0;
366 --DLP-yellow: 255, 204, 0;
367 --DLP-green: 52, 199, 89;
368 --DLP-teal: 0, 199, 190;
369 --DLP-cyan: 90, 200, 250;
370 --DLP-blue: 0, 122, 255;
371 --DLP-indigo: 88, 86, 214;
372 --DLP-purple: 175, 82, 222;
373 --DLP-pink: 255, 45, 85;
374}
375@media (prefers-color-scheme: dark) {
376 :root {
377 --DLP-red-hex: #ff453a;
378 --DLP-orange-hex: #ff9f0a;
379 --DLP-yellow-hex: #ffd60a;
380 --DLP-green-hex: #30d158;
381 --DLP-teal-hex: #63e6e2;
382 --DLP-cyan-hex: #64d2ff;
383 --DLP-blue-hex: #0a84ff;
384 --DLP-indigo-hex: #5e5ce6;
385 --DLP-purple-hex: #bf5af2;
386 --DLP-pink-hex: #ff375f;
387
388 --DLP-red-rgb: rgb(255, 69, 58);
389 --DLP-orange-rgb: rgb(255, 159, 10);
390 --DLP-yellow-rgb: rgb(255, 214, 10);
391 --DLP-green-rgb: rgb(48, 209, 88);
392 --DLP-teal-rgb: rgb(99, 230, 226);
393 --DLP-cyan-rgb: rgb(100, 210, 255);
394 --DLP-blue-rgb: rgb(10, 132, 255);
395 --DLP-indigo-rgb: rgb(94, 92, 230);
396 --DLP-purple-rgb: rgb(191, 90, 242);
397 --DLP-pink-rgb: rgb(255, 55, 95);
398
399 --DLP-red: 255, 69, 58;
400 --DLP-orange: 255, 159, 10;
401 --DLP-yellow: 255, 214, 10;
402 --DLP-green: 48, 209, 88;
403 --DLP-teal: 99, 230, 226;
404 --DLP-cyan: 100, 210, 255;
405 --DLP-blue: 10, 132, 255;
406 --DLP-indigo: 94, 92, 230;
407 --DLP-purple: 191, 90, 242;
408 --DLP-pink: 255, 55, 95;
409
410 --DLP-background: var(--color-snow);
411 }
412}
413`;
414
415HTML2 = `
416<canvas style="position: fixed; top: 0; left: 0; bottom: 0; right: 0; width: 100%; height: 100vh; z-index: 211; pointer-events: none;" id="DLP_Confetti_Canvas"></canvas>
417<div class="DLP_Notification_Main"></div>
418<div class="DLP_Main">
419 <div class="DLP_HStack_8" style="align-self: flex-end;">
420 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Switch_Legacy_Button_1_ID" style="outline: 2px solid rgba(var(--DLP-blue), 0.20); outline-offset: -2px; background: linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80); backdrop-filter: blur(16px);">
421 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: rgb(var(--DLP-blue));"></p>
422 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: rgb(var(--DLP-blue)); white-space: nowrap;">${systemText[systemLanguage][1]}</p>
423 </div>
424 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Hide_Button_1_ID" style="outline: 2px solid rgba(var(--DLP-blue), 0.20); outline-offset: -2px; background: rgba(var(--DLP-blue), 0.10); flex: none; backdrop-filter: blur(16px);">
425 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: rgb(var(--DLP-blue));"></p>
426 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: rgb(var(--DLP-blue));">${systemText[systemLanguage][2]}</p>
427 </div>
428 </div>
429 <div class="DLP_Main_Box">
430 <div class="DLP_Main_Box_Divider" id="DLP_Main_Box_Divider_1_ID" style="display: block;">
431 <div class="DLP_VStack_8">
432 <div class="DLP_VStack_8">
433 <div class="DLP_HStack_8">
434 <div id="DLP_Main_1_Server_Connection_Button_1_ID" class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" style="outline: 2px solid rgb(var(--color-eel), 0.20); outline-offset: -2px; background: rgb(var(--color-eel), 0.10); transition: opacity 0.8s cubic-bezier(0.16, 1, 0.32, 1), background 0.8s cubic-bezier(0.16, 1, 0.32, 1), outline 0.8s cubic-bezier(0.16, 1, 0.32, 1), filter 0.4s cubic-bezier(0.16, 1, 0.32, 1), transform 0.4s cubic-bezier(0.16, 1, 0.32, 1); padding: 10px 0px 10px 10px;">
435 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: rgb(var(--color-eel));"></p>
436 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: rgb(var(--color-eel));">${systemText[systemLanguage][3]}</p>
437 </div>
438 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Main_Donate_Button_1_ID" onclick="window.open('https://duolingopro.net/donate', '_blank');" style="outline: 2px solid rgba(0, 0, 0, 0.20); outline-offset: -2px; background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 50% / cover no-repeat; padding: 10px 0px 10px 10px;">
439 <svg width="17" height="19" viewBox="0 0 17 19" fill="#FFF" xmlns="http://www.w3.org/2000/svg">
440 <path d="M16.5 5.90755C16.4968 3.60922 14.6997 1.72555 12.5913 1.04588C9.97298 0.201877 6.51973 0.324211 4.01956 1.49921C0.989301 2.92355 0.0373889 6.04355 0.00191597 9.15522C-0.0271986 11.7136 0.229143 18.4517 4.04482 18.4997C6.87998 18.5356 7.30214 14.8967 8.61397 13.1442C9.5473 11.8974 10.749 11.5452 12.2284 11.1806C14.7709 10.5537 16.5037 8.55506 16.5 5.90755Z"/>
441 </svg>
442 <p class="DLP_Text_Style_1" style="color: #FFF;">${systemText[systemLanguage][4]}</p>
443 </div>
444 </div>
445 <div class="DLP_HStack_8">
446 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Main_Feedback_1_Button_1_ID" style="outline: 2px solid rgba(var(--DLP-blue), 0.20); outline-offset: -2px; background: linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80); backdrop-filter: blur(16px);">
447 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: rgb(var(--DLP-blue));"></p>
448 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: rgb(var(--DLP-blue));">${systemText[systemLanguage][5]}</p>
449 </div>
450 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Main_Settings_1_Button_1_ID" style="outline: 2px solid rgba(var(--DLP-blue), 0.20); outline-offset: -2px; background: linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80); backdrop-filter: blur(16px);">
451 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: rgb(var(--DLP-blue));"></p>
452 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: rgb(var(--DLP-blue));">${systemText[systemLanguage][6]}</p>
453 </div>
454 </div>
455 <div class="DLP_HStack_8">
456 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Secondary_Earn_Button_1_ID" style="outline: 2px solid rgba(0, 0, 0, 0.20); outline-offset: -2px; background: url(${serverURL}/static/images/flow/secondary/512/light.png) lightgray 50% / cover no-repeat; padding: 10px 0px 10px 10px;">
457 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
458 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">Boost</p>
459 </div>
460 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Main_YouTube_Button_1_ID" onclick="window.open('https://duolingopro.net/youtube', '_blank');" style="justify-content: center; flex: none; width: 40px; padding: 10px; outline: 2px solid rgba(0, 0, 0, 0.20); outline-offset: -2px; background: rgb(var(--DLP-pink));">
461 <svg width="22" height="16" viewBox="0 0 22 16" fill="#FFF" xmlns="http://www.w3.org/2000/svg">
462 <path fill-rule="evenodd" clip-rule="evenodd" d="M19.2043 1.0885C20.1084 1.33051 20.8189 2.041 21.0609 2.9451C21.4982 4.58216 21.5 7.99976 21.5 7.99976C21.5 7.99976 21.5 11.4174 21.0609 13.0544C20.8189 13.9585 20.1084 14.669 19.2043 14.911C17.5673 15.3501 11 15.3501 11 15.3501C11 15.3501 4.43274 15.3501 2.79568 14.911C1.89159 14.669 1.1811 13.9585 0.939084 13.0544C0.5 11.4174 0.5 7.99976 0.5 7.99976C0.5 7.99976 0.5 4.58216 0.939084 2.9451C1.1811 2.041 1.89159 1.33051 2.79568 1.0885C4.43274 0.649414 11 0.649414 11 0.649414C11 0.649414 17.5673 0.649414 19.2043 1.0885ZM14.3541 8.00005L8.89834 11.1497V4.85038L14.3541 8.00005Z"/>
463 </svg>
464 </div>
465 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Main_Discord_Button_1_ID" onclick="window.open('https://duolingopro.net/discord', '_blank');" style="justify-content: center; flex: none; width: 40px; padding: 10px; outline: 2px solid rgba(0, 0, 0, 0.20); outline-offset: -2px; background: rgb(var(--DLP-indigo));">
466 <svg width="22" height="16" viewBox="0 0 22 16" fill="#FFF" xmlns="http://www.w3.org/2000/svg">
467 <path d="M18.289 1.34C16.9296 0.714 15.4761 0.259052 13.9565 0C13.7699 0.332095 13.5519 0.77877 13.4016 1.1341C11.7862 0.894993 10.1857 0.894993 8.60001 1.1341C8.44972 0.77877 8.22674 0.332095 8.03844 0C6.51721 0.259052 5.06204 0.715671 3.70267 1.34331C0.960812 5.42136 0.21754 9.39811 0.589177 13.3184C2.40772 14.655 4.17011 15.467 5.90275 15.9984C6.33055 15.4189 6.71209 14.8028 7.04078 14.1536C6.41478 13.9195 5.81521 13.6306 5.24869 13.2952C5.39898 13.1856 5.546 13.071 5.68803 12.9531C9.14342 14.5438 12.8978 14.5438 16.3119 12.9531C16.4556 13.071 16.6026 13.1856 16.7512 13.2952C16.183 13.6322 15.5818 13.9211 14.9558 14.1553C15.2845 14.8028 15.6644 15.4205 16.0939 16C17.8282 15.4687 19.5922 14.6567 21.4107 13.3184C21.8468 8.77378 20.6658 4.83355 18.289 1.34ZM7.51153 10.9075C6.47426 10.9075 5.62361 9.95435 5.62361 8.7937C5.62361 7.63305 6.45609 6.67831 7.51153 6.67831C8.56699 6.67831 9.41761 7.63138 9.39945 8.7937C9.40109 9.95435 8.56699 10.9075 7.51153 10.9075ZM14.4884 10.9075C13.4511 10.9075 12.6005 9.95435 12.6005 8.7937C12.6005 7.63305 13.4329 6.67831 14.4884 6.67831C15.5438 6.67831 16.3945 7.63138 16.3763 8.7937C16.3763 9.95435 15.5438 10.9075 14.4884 10.9075Z"/>
468 </svg>
469 </div>
470 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Main_GitHub_Button_1_ID" onclick="window.open('https://duolingopro.net/github', '_blank');" style="justify-content: center; flex: none; width: 40px; padding: 10px; outline: 2px solid rgba(255, 255, 255, 0.20); outline-offset: -2px; background: #333333;">
471 <svg width="22" height="22" viewBox="0 0 22 22" fill="#FFF" xmlns="http://www.w3.org/2000/svg">
472 <path fill-rule="evenodd" clip-rule="evenodd" d="M11.0087 0.5C5.19766 0.5 0.5 5.3125 0.5 11.2662C0.5 16.0253 3.50995 20.0538 7.68555 21.4797C8.2076 21.5868 8.39883 21.248 8.39883 20.963C8.39883 20.7134 8.38162 19.8578 8.38162 18.9664C5.45836 19.6082 4.84962 17.683 4.84962 17.683C4.37983 16.4353 3.68375 16.1146 3.68375 16.1146C2.72697 15.4551 3.75345 15.4551 3.75345 15.4551C4.81477 15.5264 5.37167 16.5602 5.37167 16.5602C6.31103 18.1999 7.82472 17.7366 8.43368 17.4514C8.52058 16.7562 8.79914 16.2749 9.09491 16.0076C6.7634 15.758 4.31035 14.8312 4.31035 10.6957C4.31035 9.51928 4.72765 8.55678 5.38888 7.80822C5.28456 7.54091 4.9191 6.43556 5.49342 4.95616C5.49342 4.95616 6.38073 4.67091 8.38141 6.06128C9.23797 5.82561 10.1213 5.70573 11.0087 5.70472C11.896 5.70472 12.8005 5.82963 13.6358 6.06128C15.6367 4.67091 16.524 4.95616 16.524 4.95616C17.0983 6.43556 16.7326 7.54091 16.6283 7.80822C17.3069 8.55678 17.707 9.51928 17.707 10.6957C17.707 14.8312 15.254 15.7401 12.905 16.0076C13.2879 16.3463 13.6183 16.9878 13.6183 18.0039C13.6183 19.4477 13.6011 20.6064 13.6011 20.9627C13.6011 21.248 13.7926 21.5868 14.3144 21.4799C18.49 20.0536 21.5 16.0253 21.5 11.2662C21.5172 5.3125 16.8023 0.5 11.0087 0.5Z"/>
473 </svg>
474 </div>
475 </div>
476 </div>
477 <div class="DLP_HStack_Auto_Top DLP_NoSelect">
478 <div class="DLP_HStack_4">
479 <p class="DLP_Text_Style_2">Duolingo</p>
480 <p class="DLP_Text_Style_2" style="background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">PRO 3.1</p>
481 </div>
482 <p class="DLP_Text_Style_1" style="margin-top: 2px; font-size: 14px; background: url(${serverURL}/static/images/flow/secondary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${versionName}</p>
483 </div>
484 <p id="DLP_Main_Warning_1_ID" class="DLP_Text_Style_1" style="transition: 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); text-align: center; opacity: 0.5; display: none;"></p>
485 <div class="DLP_VStack_8" id="DLP_Main_Inputs_1_Divider_1_ID" style="opacity: 0.5; pointer-events: none; transition: 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);">
486 <div class="DLP_VStack_8" id="DLP_Get_XP_1_ID" style="flex: 1 0 0;">
487 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][8]}</p>
488 <div class="DLP_HStack_8">
489 <div class="DLP_Input_Style_1_Active">
490 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
491 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1">
492 </div>
493 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID">
494 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][9]}</p>
495 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
496 </div>
497 </div>
498 </div>
499 <div class="DLP_VStack_8" id="DLP_Get_GEM_1_ID" style="flex: 1 0 0; align-self: stretch;">
500 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][10]}</p>
501 <div class="DLP_HStack_8">
502 <div class="DLP_Input_Style_1_Active" style="position: relative; overflow: hidden;">
503 <svg width="120" height="48" viewBox="0 0 120 48" fill="none" xmlns="http://www.w3.org/2000/svg" style="position: absolute; pointer-events: none; transform: translateX(-150px); animation: slideRight 4s ease-in-out forwards infinite; animation-delay: 2s;">
504 <path opacity="0.5" d="M72 0H96L72 48H48L72 0Z" fill="rgb(var(--DLP-blue))"/>
505 <path opacity="0.5" d="M24 0H60L36 48H0L24 0Z" fill="rgb(var(--DLP-blue))"/>
506 <path opacity="0.5" d="M108 0H120L96 48H84L108 0Z" fill="rgb(var(--DLP-blue))"/>
507 </svg>
508 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
509 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1">
510 </div>
511 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID">
512 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][9]}</p>
513 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
514 </div>
515 </div>
516 </div>
517 <div class="DLP_VStack_8" id="DLP_Get_SUPER_1_ID" style="display: none;">
518 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][12]}</p>
519 <div class="DLP_HStack_8">
520 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID" style="flex: 1 0 0;">
521 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][13]}</p>
522 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
523 </div>
524 </div>
525 </div>
526 <div class="DLP_VStack_8" id="DLP_Get_DOUBLE_XP_BOOST_1_ID" style="display: none;">
527 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">Would you like to redeem an XP Boost?</p>
528 <div class="DLP_HStack_8">
529 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID" style="flex: 1 0 0;">
530 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][13]}</p>
531 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
532 </div>
533 </div>
534 </div>
535 <div class="DLP_VStack_8" id="DLP_Get_Streak_Freeze_1_ID" style="display: none;">
536 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">How many Streak Freezes would you like to get?</p>
537 <div class="DLP_HStack_8">
538 <div class="DLP_Input_Style_1_Active">
539 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
540 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1">
541 </div>
542 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID">
543 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][9]}</p>
544 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
545 </div>
546 </div>
547 </div>
548 <div class="DLP_VStack_8" id="DLP_Get_Streak_1_ID" style="display: none;">
549 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">How many days would you like to increase your Streak by?</p>
550 <div class="DLP_HStack_8">
551 <div class="DLP_Input_Style_1_Active">
552 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
553 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1">
554 </div>
555 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID">
556 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][9]}</p>
557 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
558 </div>
559 </div>
560 </div>
561 <div class="DLP_VStack_8" id="DLP_Get_Heart_Refill_1_ID" style="display: none;">
562 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">Would you like to refill your Hearts to full?</p>
563 <div class="DLP_HStack_8">
564 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID" style="flex: 1 0 0;">
565 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][229]}</p>
566 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
567 </div>
568 </div>
569 </div>
570 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Main_See_More_1_Button_1_ID" style="outline: rgba(var(--DLP-blue), 0.2) solid 2px; outline-offset: -2px; background: linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80); backdrop-filter: blur(16px); transform: translate(0px, 0px) scale(1); align-self: stretch; justify-content: space-between;">
571 <p class="DLP_Text_Style_1" style="color: rgb(var(--DLP-blue));">${systemText[systemLanguage][15]}</p>
572 <p class="DLP_Text_Style_1" style="color: rgb(var(--DLP-blue));"></p>
573 </div>
574 </div>
575 <div class="DLP_HStack_Auto" style="padding-top: 4px;">
576 <div class="DLP_HStack_4 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Main_Terms_1_Button_1_ID" style="align-items: center;">
577 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);">${systemText[systemLanguage][14]}</p>
578 </div>
579 <div class="DLP_HStack_4 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Main_Whats_New_1_Button_1_ID" style="align-items: center;">
580 <p class="DLP_Text_Style_1" style="color: rgb(var(--DLP-blue));">${systemText[systemLanguage][7]}</p>
581 </div>
582 </div>
583 </div>
584 </div>
585
586
587 <div class="DLP_Main_Box_Divider" id="DLP_Main_Box_Divider_2_ID" style="display: none;">
588 <div class="DLP_VStack_8">
589 <div class="DLP_HStack_Auto_Top DLP_NoSelect">
590 <div class="DLP_HStack_4 DLP_Hover_1" id="DLP_Universal_Back_1_Button_1_ID">
591 <p class="DLP_Text_Style_2" style="font-size: 20px;"></p>
592 <p class="DLP_Text_Style_2">Duolingo</p>
593 <p class="DLP_Text_Style_2" style="background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">PRO 3.1</p>
594 </div>
595 <p class="DLP_Text_Style_1" style="font-size: 14px; background: url(${serverURL}/static/images/flow/secondary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${versionName}</p>
596 </div>
597 <div class="DLP_VStack_8" id="DLP_Main_Inputs_1_Divider_1_ID">
598 <div class="DLP_HStack_8">
599 <div class="DLP_VStack_8" id="DLP_Get_XP_2_ID" style="flex: 1 0 0;">
600 <div class="DLP_HStack_8" style="align-items: center;">
601 <p class="DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Inset_Icon_1_ID" style="color: rgba(var(--color-eel), 0.50);"></p>
602 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][8]}</p>
603 </div>
604 <div class="DLP_HStack_8">
605 <div class="DLP_Input_Style_1_Active">
606 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
607 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1">
608 </div>
609 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID">
610 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][9]}</p>
611 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
612 </div>
613 </div>
614 </div>
615 <div class="DLP_VStack_8" id="DLP_Get_GEM_2_ID" style="flex: 1 0 0; align-self: stretch;">
616 <div class="DLP_HStack_8" style="align-items: center;">
617 <p class="DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Inset_Icon_1_ID" style="color: rgba(var(--color-eel), 0.50);"></p>
618 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][10]}</p>
619 </div>
620 <div class="DLP_HStack_8">
621 <div class="DLP_Input_Style_1_Active" style="position: relative; overflow: hidden;">
622 <svg width="120" height="48" viewBox="0 0 120 48" fill="none" xmlns="http://www.w3.org/2000/svg" style="position: absolute; pointer-events: none; transform: translateX(-150px); animation: slideRight 4s ease-in-out forwards infinite; animation-delay: 2s;">
623 <path opacity="0.5" d="M72 0H96L72 48H48L72 0Z" fill="rgb(var(--DLP-blue))"/>
624 <path opacity="0.5" d="M24 0H60L36 48H0L24 0Z" fill="rgb(var(--DLP-blue))"/>
625 <path opacity="0.5" d="M108 0H120L96 48H84L108 0Z" fill="rgb(var(--DLP-blue))"/>
626 </svg>
627 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
628 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1">
629 </div>
630 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID">
631 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][9]}</p>
632 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
633 </div>
634 </div>
635 </div>
636 </div>
637 <div class="DLP_HStack_8">
638 <div class="DLP_VStack_8" id="DLP_Get_SUPER_2_ID" style="flex: 1 0 0;">
639 <div class="DLP_HStack_8" style="align-items: center;">
640 <p class="DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Inset_Icon_1_ID" style="color: rgba(var(--color-eel), 0.50);"></p>
641 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][12]}</p>
642 </div>
643 <div class="DLP_HStack_8">
644 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID" style="flex: 1 0 0;">
645 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][13]}</p>
646 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
647 </div>
648 </div>
649 </div>
650 <div class="DLP_VStack_8" id="DLP_Get_DOUBLE_XP_BOOST_2_ID" style="flex: 1 0 0;">
651 <div class="DLP_HStack_8" style="align-items: center;">
652 <p class="DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Inset_Icon_1_ID" style="color: rgba(var(--color-eel), 0.50);"></p>
653 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">Would you like to redeem an XP Boost?</p>
654 </div>
655 <div class="DLP_HStack_8">
656 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID" style="flex: 1 0 0;">
657 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][13]}</p>
658 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
659 </div>
660 </div>
661 </div>
662 </div>
663 <div class="DLP_HStack_8">
664 <div class="DLP_VStack_8" id="DLP_Get_Streak_Freeze_2_ID" style="flex: 1 0 0;">
665 <div class="DLP_HStack_8" style="align-items: center;">
666 <p class="DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Inset_Icon_1_ID" style="color: rgba(var(--color-eel), 0.50);"></p>
667 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">How many Streak Freezes would you like to get?</p>
668 </div>
669 <div class="DLP_HStack_8">
670 <div class="DLP_Input_Style_1_Active">
671 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
672 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1">
673 </div>
674 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID">
675 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][9]}</p>
676 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
677 </div>
678 </div>
679 </div>
680 <div class="DLP_VStack_8" id="DLP_Get_Streak_2_ID" style="flex: 1 0 0;">
681 <div class="DLP_HStack_8" style="align-items: center;">
682 <p class="DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Inset_Icon_1_ID" style="color: rgba(var(--color-eel), 0.50);"></p>
683 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">How many days would you like to increase your Streak by?</p>
684 </div>
685 <div class="DLP_HStack_8">
686 <div class="DLP_Input_Style_1_Active">
687 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
688 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1">
689 </div>
690 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID">
691 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][9]}</p>
692 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
693 </div>
694 </div>
695 </div>
696 </div>
697 <div class="DLP_HStack_8">
698 <div class="DLP_VStack_8" id="DLP_Get_Heart_Refill_2_ID" style="flex: 1 0 0;">
699 <div class="DLP_HStack_8" style="align-items: center;">
700 <p class="DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Inset_Icon_1_ID" style="color: rgba(var(--color-eel), 0.50);"></p>
701 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">Would you like to refill your Hearts to full?</p>
702 </div>
703 <div class="DLP_HStack_8">
704 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID" style="flex: 1 0 0;">
705 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][229]}</p>
706 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
707 </div>
708 </div>
709 </div>
710 <div style="flex: 1 0 0; align-self: stretch; opacity: 0; pointer-events: none;"></div>
711 </div>
712 </div>
713 </div>
714 </div>
715
716
717 <div class="DLP_Main_Box_Divider" id="DLP_Main_Box_Divider_3_ID" style="display: none;">
718 <div class="DLP_VStack_8">
719 <div class="DLP_VStack_8">
720 <div class="DLP_HStack_8">
721 <div id="DLP_Secondary_1_Server_Connection_Button_1_ID" class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" style="outline: 2px solid rgb(var(--color-eel), 0.20); outline-offset: -2px; background: rgb(var(--color-eel), 0.10); transition: opacity 0.8s cubic-bezier(0.16, 1, 0.32, 1), background 0.8s cubic-bezier(0.16, 1, 0.32, 1), outline 0.8s cubic-bezier(0.16, 1, 0.32, 1), filter 0.4s cubic-bezier(0.16, 1, 0.32, 1), transform 0.4s cubic-bezier(0.16, 1, 0.32, 1); padding: 10px 0px 10px 10px; opacity: 0.25; pointer-events: none;">
722 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: rgb(var(--DLP-blue));"></p>
723 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #000; transition: 0.4s;">${systemText[systemLanguage][3]}</p>
724 </div>
725 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Secondary_Donate_Button_1_ID" onclick="window.open('https://duolingopro.net/donate', '_blank');" style="outline: 2px solid rgba(0, 0, 0, 0.20); outline-offset: -2px; background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 50% / cover no-repeat; padding: 10px 0px 10px 10px;">
726 <svg width="17" height="19" viewBox="0 0 17 19" fill="#FFF" xmlns="http://www.w3.org/2000/svg">
727 <path d="M16.5 5.90755C16.4968 3.60922 14.6997 1.72555 12.5913 1.04588C9.97298 0.201877 6.51973 0.324211 4.01956 1.49921C0.989301 2.92355 0.0373889 6.04355 0.00191597 9.15522C-0.0271986 11.7136 0.229143 18.4517 4.04482 18.4997C6.87998 18.5356 7.30214 14.8967 8.61397 13.1442C9.5473 11.8974 10.749 11.5452 12.2284 11.1806C14.7709 10.5537 16.5037 8.55506 16.5 5.90755Z"/>
728 </svg>
729 <p class="DLP_Text_Style_1" style="color: #FFF;">${systemText[systemLanguage][4]}</p>
730 </div>
731 </div>
732 <div class="DLP_HStack_8">
733 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Secondary_Feedback_1_Button_1_ID" style="outline: 2px solid rgba(var(--DLP-blue), 0.20); outline-offset: -2px; background: linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80); backdrop-filter: blur(16px);">
734 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: rgb(var(--DLP-blue));"></p>
735 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: rgb(var(--DLP-blue));">${systemText[systemLanguage][5]}</p>
736 </div>
737 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Secondary_Settings_1_Button_1_ID" style="outline: 2px solid rgba(var(--DLP-blue), 0.20); outline-offset: -2px; background: linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80); backdrop-filter: blur(16px);">
738 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: rgb(var(--DLP-blue));"></p>
739 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: rgb(var(--DLP-blue));">${systemText[systemLanguage][6]}</p>
740 </div>
741 </div>
742 <div class="DLP_HStack_8">
743 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Main_Earn_Button_1_ID" style="outline: 2px solid rgba(0, 0, 0, 0.20); outline-offset: -2px; background: url(${serverURL}/static/images/flow/secondary/512/light.png) lightgray 50% / cover no-repeat; padding: 10px 0px 10px 10px;">
744 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
745 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">Boost</p>
746 </div>
747 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Secondary_YouTube_Button_1_ID" onclick="window.open('https://duolingopro.net/youtube', '_blank');" style="justify-content: center; flex: none; width: 40px; padding: 10px; outline: 2px solid rgba(0, 0, 0, 0.20); outline-offset: -2px; background: rgb(var(--DLP-pink));">
748 <svg width="22" height="16" viewBox="0 0 22 16" fill="#FFF" xmlns="http://www.w3.org/2000/svg">
749 <path fill-rule="evenodd" clip-rule="evenodd" d="M19.2043 1.0885C20.1084 1.33051 20.8189 2.041 21.0609 2.9451C21.4982 4.58216 21.5 7.99976 21.5 7.99976C21.5 7.99976 21.5 11.4174 21.0609 13.0544C20.8189 13.9585 20.1084 14.669 19.2043 14.911C17.5673 15.3501 11 15.3501 11 15.3501C11 15.3501 4.43274 15.3501 2.79568 14.911C1.89159 14.669 1.1811 13.9585 0.939084 13.0544C0.5 11.4174 0.5 7.99976 0.5 7.99976C0.5 7.99976 0.5 4.58216 0.939084 2.9451C1.1811 2.041 1.89159 1.33051 2.79568 1.0885C4.43274 0.649414 11 0.649414 11 0.649414C11 0.649414 17.5673 0.649414 19.2043 1.0885ZM14.3541 8.00005L8.89834 11.1497V4.85038L14.3541 8.00005Z"/>
750 </svg>
751 </div>
752 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Secondary_Discord_Button_1_ID" onclick="window.open('https://duolingopro.net/discord', '_blank');" style="justify-content: center; flex: none; width: 40px; padding: 10px; outline: 2px solid rgba(0, 0, 0, 0.20); outline-offset: -2px; background: rgb(var(--DLP-indigo));">
753 <svg width="22" height="16" viewBox="0 0 22 16" fill="#FFF" xmlns="http://www.w3.org/2000/svg">
754 <path d="M18.289 1.34C16.9296 0.714 15.4761 0.259052 13.9565 0C13.7699 0.332095 13.5519 0.77877 13.4016 1.1341C11.7862 0.894993 10.1857 0.894993 8.60001 1.1341C8.44972 0.77877 8.22674 0.332095 8.03844 0C6.51721 0.259052 5.06204 0.715671 3.70267 1.34331C0.960812 5.42136 0.21754 9.39811 0.589177 13.3184C2.40772 14.655 4.17011 15.467 5.90275 15.9984C6.33055 15.4189 6.71209 14.8028 7.04078 14.1536C6.41478 13.9195 5.81521 13.6306 5.24869 13.2952C5.39898 13.1856 5.546 13.071 5.68803 12.9531C9.14342 14.5438 12.8978 14.5438 16.3119 12.9531C16.4556 13.071 16.6026 13.1856 16.7512 13.2952C16.183 13.6322 15.5818 13.9211 14.9558 14.1553C15.2845 14.8028 15.6644 15.4205 16.0939 16C17.8282 15.4687 19.5922 14.6567 21.4107 13.3184C21.8468 8.77378 20.6658 4.83355 18.289 1.34ZM7.51153 10.9075C6.47426 10.9075 5.62361 9.95435 5.62361 8.7937C5.62361 7.63305 6.45609 6.67831 7.51153 6.67831C8.56699 6.67831 9.41761 7.63138 9.39945 8.7937C9.40109 9.95435 8.56699 10.9075 7.51153 10.9075ZM14.4884 10.9075C13.4511 10.9075 12.6005 9.95435 12.6005 8.7937C12.6005 7.63305 13.4329 6.67831 14.4884 6.67831C15.5438 6.67831 16.3945 7.63138 16.3763 8.7937C16.3763 9.95435 15.5438 10.9075 14.4884 10.9075Z"/>
755 </svg>
756 </div>
757 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Secondary_GitHub_Button_1_ID" onclick="window.open('https://duolingopro.net/github', '_blank');" style="justify-content: center; flex: none; width: 40px; padding: 10px; outline: 2px solid rgba(255, 255, 255, 0.20); outline-offset: -2px; background: #333333;">
758 <svg width="22" height="22" viewBox="0 0 22 22" fill="#FFF" xmlns="http://www.w3.org/2000/svg">
759 <path fill-rule="evenodd" clip-rule="evenodd" d="M11.0087 0.5C5.19766 0.5 0.5 5.3125 0.5 11.2662C0.5 16.0253 3.50995 20.0538 7.68555 21.4797C8.2076 21.5868 8.39883 21.248 8.39883 20.963C8.39883 20.7134 8.38162 19.8578 8.38162 18.9664C5.45836 19.6082 4.84962 17.683 4.84962 17.683C4.37983 16.4353 3.68375 16.1146 3.68375 16.1146C2.72697 15.4551 3.75345 15.4551 3.75345 15.4551C4.81477 15.5264 5.37167 16.5602 5.37167 16.5602C6.31103 18.1999 7.82472 17.7366 8.43368 17.4514C8.52058 16.7562 8.79914 16.2749 9.09491 16.0076C6.7634 15.758 4.31035 14.8312 4.31035 10.6957C4.31035 9.51928 4.72765 8.55678 5.38888 7.80822C5.28456 7.54091 4.9191 6.43556 5.49342 4.95616C5.49342 4.95616 6.38073 4.67091 8.38141 6.06128C9.23797 5.82561 10.1213 5.70573 11.0087 5.70472C11.896 5.70472 12.8005 5.82963 13.6358 6.06128C15.6367 4.67091 16.524 4.95616 16.524 4.95616C17.0983 6.43556 16.7326 7.54091 16.6283 7.80822C17.3069 8.55678 17.707 9.51928 17.707 10.6957C17.707 14.8312 15.254 15.7401 12.905 16.0076C13.2879 16.3463 13.6183 16.9878 13.6183 18.0039C13.6183 19.4477 13.6011 20.6064 13.6011 20.9627C13.6011 21.248 13.7926 21.5868 14.3144 21.4799C18.49 20.0536 21.5 16.0253 21.5 11.2662C21.5172 5.3125 16.8023 0.5 11.0087 0.5Z"/>
760 </svg>
761 </div>
762 </div>
763 </div>
764 <div class="DLP_HStack_Auto_Top DLP_NoSelect">
765 <div class="DLP_HStack_4">
766 <p class="DLP_Text_Style_2">Duolingo</p>
767 <p class="DLP_Text_Style_2" style="background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">PRO LE</p>
768 </div>
769 <p class="DLP_Text_Style_1" style="font-size: 14px; background: url(${serverURL}/static/images/flow/secondary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${versionName}</p>
770 </div>
771 <p class="DLP_Text_Style_1" style="display: none; transition: 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); opacity: 0; filter: blur(4px);">You are using an outdated version of Duolingo PRO. <br><br>Please update Duolingo PRO or turn on automatic updates. </p>
772 <p class="DLP_Text_Style_1" style="display: none; transition: 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); opacity: 0; filter: blur(4px);">Duolingo PRO failed to connect. This might be happening because of an issue on our system or your device. <br><br>Try updating Duolingo PRO. If the issue persists afterwards, join our Discord Server to get support. </p>
773 <p class="DLP_Text_Style_1" style="display: none; transition: 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); opacity: 0; filter: blur(4px);">We are currently unable to receive new requests due to high demand. Join our Discord Server to learn more. <br><br>You can help us handle more demand by donating on Patreon while getting exclusive features and higher limits. </p>
774 <div class="DLP_VStack_8" id="DLP_Main_Inputs_2_Divider_1_ID">
775 <div class="DLP_VStack_8" id="DLP_Get_PATH_1_ID">
776 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][17]}</p>
777 <div class="DLP_HStack_8">
778 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_2_ID" style="width: 48px; padding: 0;">
779 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
780 </div>
781 <div class="DLP_Input_Style_1_Active">
782 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1">
783 </div>
784 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID">
785 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][18]}</p>
786 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
787 </div>
788 </div>
789 </div>
790 <div class="DLP_VStack_8" id="DLP_Get_PRACTICE_1_ID">
791 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][19]}</p>
792 <div class="DLP_HStack_8">
793 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_2_ID" style="width: 48px; padding: 0;">
794 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
795 </div>
796 <div class="DLP_Input_Style_1_Active">
797 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1">
798 </div>
799 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID">
800 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][18]}</p>
801 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
802 </div>
803 </div>
804 </div>
805 <div class="DLP_VStack_8" id="DLP_Get_LISTEN_1_ID" style="display: none;">
806 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][21]}</p>
807 <div class="DLP_HStack_8">
808 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_2_ID" style="width: 48px; padding: 0;">
809 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
810 </div>
811 <div class="DLP_Input_Style_1_Active">
812 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1">
813 </div>
814 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID">
815 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][18]}</p>
816 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
817 </div>
818 </div>
819 </div>
820 <div class="DLP_VStack_8" id="DLP_Get_LESSON_1_ID" style="display: none;">
821 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][23]}</p>
822 <div class="DLP_HStack_8">
823 <div class="DLP_Input_Style_1_Active">
824 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
825 <div style="display: flex; align-items: center; gap: 8px; width: 100%; justify-content: flex-end;">
826 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: rgba(var(--DLP-blue), 0.5);">Unit:</p>
827 <input type="text" value="1" placeholder="1" id="DLP_Inset_Input_3_ID" class="DLP_Input_Input_Style_1" style="width: 30px;">
828 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: rgba(var(--DLP-blue), 0.5);">Lesson:</p>
829 <input type="text" value="1" placeholder="1" id="DLP_Inset_Input_4_ID" class="DLP_Input_Input_Style_1" style="width: 30px;">
830 </div>
831 </div>
832 </div>
833 <div class="DLP_HStack_8">
834 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_2_ID" style="width: 48px; padding: 0;">
835 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
836 </div>
837 <div class="DLP_Input_Style_1_Active">
838 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1">
839 </div>
840 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID">
841 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][18]}</p>
842 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
843 </div>
844 </div>
845 </div>
846 <div class="DLP_Button_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Secondary_See_More_1_Button_1_ID" style="outline: rgba(var(--DLP-blue), 0.2) solid 2px; outline-offset: -2px; background: linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80); backdrop-filter: blur(16px); transform: translate(0px, 0px) scale(1); align-self: stretch; justify-content: space-between;">
847 <p class="DLP_Text_Style_1" style="color: rgb(var(--DLP-blue));">${systemText[systemLanguage][15]}</p>
848 <p class="DLP_Text_Style_1" style="color: rgb(var(--DLP-blue));"></p>
849 </div>
850 <div class="DLP_HStack_Auto" style="padding-top: 4px;">
851 <div class="DLP_HStack_4 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Secondary_Terms_1_Button_1_ID" style="align-items: center;">
852 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);">${systemText[systemLanguage][14]}</p>
853 </div>
854 <div class="DLP_HStack_4 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Secondary_Whats_New_1_Button_1_ID" style="align-items: center;">
855 <p class="DLP_Text_Style_1" style="color: rgb(var(--DLP-blue));">${systemText[systemLanguage][7]}</p>
856 </div>
857 </div>
858 </div>
859 </div>
860 </div>
861
862
863 <div class="DLP_Main_Box_Divider" id="DLP_Main_Box_Divider_4_ID" style="display: none;">
864 <div class="DLP_VStack_8">
865 <div class="DLP_HStack_Auto_Top DLP_NoSelect">
866 <div class="DLP_HStack_4 DLP_Hover_1" id="DLP_Universal_Back_1_Button_1_ID">
867 <p class="DLP_Text_Style_2" style="font-size: 20px;"></p>
868 <p class="DLP_Text_Style_2">Duolingo</p>
869 <p class="DLP_Text_Style_2" style="background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">PRO LE</p>
870 </div>
871 <p class="DLP_Text_Style_1" style="font-size: 14px; background: url(${serverURL}/static/images/flow/secondary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${versionName}</p>
872 </div>
873 <div class="DLP_VStack_8" id="DLP_Main_Inputs_1_Divider_1_ID">
874 <div class="DLP_VStack_8" id="DLP_Get_PATH_2_ID">
875 <div class="DLP_HStack_8" style="align-items: center;">
876 <p class="DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Inset_Icon_1_ID" style="color: rgba(var(--color-eel), 0.50);"></p>
877 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][17]}</p>
878 </div>
879 <div class="DLP_HStack_8">
880 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_2_ID" style="width: 48px; padding: 0;">
881 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
882 </div>
883 <div class="DLP_Input_Style_1_Active">
884 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1">
885 </div>
886 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID">
887 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][18]}</p>
888 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
889 </div>
890 </div>
891 </div>
892 <div class="DLP_VStack_8" id="DLP_Get_PRACTICE_2_ID">
893 <div class="DLP_HStack_8" style="align-items: center;">
894 <p class="DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Inset_Icon_1_ID" style="color: rgba(var(--color-eel), 0.50);"></p>
895 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][19]}</p>
896 </div>
897 <div class="DLP_HStack_8">
898 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_2_ID" style="width: 48px; padding: 0;">
899 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
900 </div>
901 <div class="DLP_Input_Style_1_Active">
902 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1">
903 </div>
904 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID">
905 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][18]}</p>
906 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
907 </div>
908 </div>
909 </div>
910 <div class="DLP_VStack_8" id="DLP_Get_LISTEN_2_ID">
911 <div class="DLP_HStack_8" style="align-items: center;">
912 <p class="DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Inset_Icon_1_ID" style="color: rgba(var(--color-eel), 0.50);"></p>
913 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][21]}</p>
914 </div>
915 <div class="DLP_HStack_8">
916 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_2_ID" style="width: 48px; padding: 0;">
917 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
918 </div>
919 <div class="DLP_Input_Style_1_Active">
920 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1">
921 </div>
922 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID">
923 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][18]}</p>
924 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
925 </div>
926 </div>
927 </div>
928 <div class="DLP_VStack_8" id="DLP_Get_LESSON_2_ID">
929 <div class="DLP_HStack_8" style="align-items: center;">
930 <p class="DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Inset_Icon_1_ID" style="color: rgba(var(--color-eel), 0.50);"></p>
931 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][23]}</p>
932 </div>
933 <div class="DLP_HStack_8">
934 <div class="DLP_Input_Style_1_Active">
935 <div style="display: flex; align-items: center; gap: 8px; width: 100%; justify-content: flex-end;">
936 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: rgba(var(--DLP-blue), 0.5);">Unit:</p>
937 <input type="text" value="1" placeholder="1" id="DLP_Inset_Input_3_ID" class="DLP_Input_Input_Style_1" style="width: 30px;">
938 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: rgba(var(--DLP-blue), 0.5);">Lesson:</p>
939 <input type="text" value="1" placeholder="1" id="DLP_Inset_Input_4_ID" class="DLP_Input_Input_Style_1" style="width: 30px;">
940 </div>
941 </div>
942 </div>
943 <div class="DLP_HStack_8">
944 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_2_ID" style="width: 48px; padding: 0;">
945 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
946 </div>
947 <div class="DLP_Input_Style_1_Active">
948 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1">
949 </div>
950 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_1_ID">
951 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][18]}</p>
952 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
953 </div>
954 </div>
955 </div>
956 </div>
957 </div>
958 </div>
959
960
961 <div class="DLP_Main_Box_Divider" id="DLP_Main_Box_Divider_5_ID" style="display: none;">
962 <div class="DLP_VStack_8">
963 <div class="DLP_HStack_Auto_Top DLP_NoSelect">
964 <div class="DLP_HStack_4">
965 <p class="DLP_Text_Style_2">Duolingo</p>
966 <p class="DLP_Text_Style_2" style="background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">PRO 3.1</p>
967 </div>
968 <p class="DLP_Text_Style_1" style="font-size: 14px; background: url(${serverURL}/static/images/flow/secondary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${versionName}</p>
969 </div>
970 <p class="DLP_Text_Style_1 DLP_NoSelect" id="DLP_Terms_1_Text_1_ID">${systemText[systemLanguage][25]}</p>
971 <p class="DLP_Text_Style_1 DLP_NoSelect" id="DLP_Terms_1_Text_2_ID" style="display: none; align-self: stretch;">${systemText[systemLanguage][26]}</p>
972 <div class="DLP_Scroll_Box_Style_1">
973 <p id="DLP_Terms_Main_Text_1_ID" class="DLP_Scroll_Box_Text_Style_1">${systemText[systemLanguage][27]}</p>
974 </div>
975 <div class="DLP_HStack_8" id="DLP_Terms_1_Button_1_ID">
976 <div id="DLP_Terms_Decline_Button_1_ID" class="DLP_Button_Style_2 DLP_Magnetic_Hover_1 DLP_NoSelect" style="outline: 2px solid rgba(var(--DLP-blue), 0.20); outline-offset: -2px; background: rgba(var(--DLP-blue), 0.10);">
977 <p class="DLP_Text_Style_1" style="color: rgb(var(--DLP-blue));"></p>
978 <p class="DLP_Text_Style_1" style="color: rgb(var(--DLP-blue));">${systemText[systemLanguage][28]}</p>
979 </div>
980 <div id="DLP_Terms_Accept_Button_1_ID" class="DLP_Button_Style_2 DLP_Magnetic_Hover_1 DLP_NoSelect" style="outline: 2px solid rgba(0, 0, 0, 0.20); outline-offset: -2px; background: rgb(var(--DLP-blue));">
981 <p class="DLP_Text_Style_1" style="color: #FFF;">ACCEPT</p>
982 <p class="DLP_Text_Style_1" style="color: #FFF;"></p>
983 </div>
984 </div>
985 <div class="DLP_HStack_8" id="DLP_Terms_1_Button_2_ID" style="display: none;">
986 <div class="DLP_Button_Style_2 DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Terms_Back_Button_1_ID" style="outline: 2px solid rgba(var(--DLP-blue), 0.20); outline-offset: -2px; background: rgba(var(--DLP-blue), 0.10);">
987 <p class="DLP_Text_Style_1" style="color: rgb(var(--DLP-blue));"></p>
988 <p class="DLP_Text_Style_1" style="color: rgb(var(--DLP-blue));">${systemText[systemLanguage][29]}</p>
989 </div>
990 </div>
991 </div>
992 </div>
993
994
995 <div class="DLP_Main_Box_Divider" id="DLP_Main_Box_Divider_6_ID" style="display: none;">
996 <div class="DLP_VStack_8">
997 <div class="DLP_HStack_Auto_Top DLP_NoSelect">
998 <div class="DLP_HStack_4">
999 <p class="DLP_Text_Style_2">Duolingo</p>
1000 <p class="DLP_Text_Style_2" style="background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">PRO 3.1</p>
1001 </div>
1002 <p class="DLP_Text_Style_1" style="font-size: 14px; background: url(${serverURL}/static/images/flow/secondary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${versionName}</p>
1003 </div>
1004 <p class="DLP_Text_Style_1 DLP_NoSelect" style="opacity: 0.5;">${systemText[systemLanguage][30]}</p>
1005 <div class="DLP_HStack_8">
1006 <div id="DLP_Terms_Declined_Back_Button_1_ID" class="DLP_Button_Style_2 DLP_Magnetic_Hover_1 DLP_NoSelect" style="outline: 2px solid rgba(var(--DLP-blue), 0.20); outline-offset: -2px; background: rgba(var(--DLP-blue), 0.10);">
1007 <p class="DLP_Text_Style_1" style="color: rgb(var(--DLP-blue));"></p>
1008 <p class="DLP_Text_Style_1" style="color: rgb(var(--DLP-blue));">${systemText[systemLanguage][31]}</p>
1009 </div>
1010 </div>
1011 </div>
1012 </div>
1013
1014
1015 <div class="DLP_Main_Box_Divider" id="DLP_Main_Box_Divider_7_ID" style="display: none;">
1016 <div class="DLP_VStack_8">
1017 <div class="DLP_HStack_Auto_Top DLP_NoSelect">
1018 <div id="DLP_Universal_Back_1_Button_1_ID" class="DLP_HStack_4 DLP_Hover_1">
1019 <p class="DLP_Text_Style_2" style="font-size: 20px; background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 0% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;"></p>
1020 <p class="DLP_Text_Style_2" style="background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${systemText[systemLanguage][32]}</p>
1021 </div>
1022 <p class="DLP_Text_Style_1" style="font-size: 14px; background: url(${serverURL}/static/images/flow/secondary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${versionName}</p>
1023 </div>
1024 <div style="max-height: 320px; overflow-y: auto;">
1025 <div class="DLP_VStack_8">
1026 <div id="DLP_Settings_Show_Solve_Buttons_1_ID" class="DLP_HStack_8" style="justify-content: center; align-items: center;">
1027 <div class="DLP_VStack_0" style="align-items: flex-start; flex: 1 0 0;">
1028 <p class="DLP_Text_Style_1">Show Solve Buttons</p>
1029 <p class="DLP_Text_Style_1" style="opacity: 0.5;">In lessons and practices, see the solve and solve all buttons.</p>
1030 </div>
1031 <div id="DLP_Inset_Toggle_1_ID" class="DLP_Toggle_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect">
1032 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
1033 </div>
1034 </div>
1035 <div id="DLP_Settings_Show_AutoServer_Button_1_ID" class="DLP_HStack_8" style="justify-content: center; align-items: center;">
1036 <div class="DLP_VStack_0" style="align-items: flex-start; flex: 1 0 0;">
1037 <p class="DLP_Text_Style_1">Show AutoServer Button</p>
1038 <p class="DLP_Text_Style_1" style="opacity: 0.5;">See the AutoServer by Duolingo PRO button in your Duolingo menubar.</p>
1039 </div>
1040 <div id="DLP_Inset_Toggle_1_ID" class="DLP_Toggle_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect">
1041 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
1042 </div>
1043 </div>
1044 <div id="DLP_Settings_Legacy_Solve_Speed_1_ID" class="DLP_HStack_8" style="justify-content: center; align-items: center;">
1045 <div class="DLP_VStack_0" style="align-items: flex-start; flex: 1 0 0;">
1046 <p class="DLP_Text_Style_1">Legacy Solve Speed</p>
1047 <p class="DLP_Text_Style_1" style="opacity: 0.5;">Legacy will solve each question every this amount of seconds. The lower speed you set, the more mistakes Legacy can make.</p>
1048 </div>
1049 <div class="DLP_Input_Style_1_Active" style="flex: none; width: 72px;">
1050 <input type="text" placeholder="0" id="DLP_Inset_Input_1_ID" class="DLP_Input_Input_Style_1" style="text-align: center;">
1051 </div>
1052 </div>
1053 <div id="DLP_Settings_Help_Us_Make_Better_Button_1_ID" class="DLP_HStack_8" style="justify-content: center; align-items: center;${alpha ? ' opacity: 0.5; pointer-events: none;' : ''}">
1054 <div class="DLP_VStack_0" style="align-items: flex-start; flex: 1 0 0;">
1055 <p class="DLP_Text_Style_1">Help Us Make Duolingo PRO Better</p>
1056 <p class="DLP_Text_Style_1" style="opacity: 0.5;">Allow Duolingo PRO to collect anonymous usage data for us to improve the script.</p>
1057 </div>
1058 <div id="DLP_Inset_Toggle_1_ID" class="DLP_Toggle_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect">
1059 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
1060 </div>
1061 </div>
1062 <div id="DLP_Settings_Auto_Update_Toggle_1_ID" class="DLP_HStack_8" style="justify-content: center; align-items: center; opacity: 0.5; pointer-events: none; cursor: not-allowed;">
1063 <div class="DLP_VStack_0" style="align-items: flex-start; flex: 1 0 0;">
1064 <p class="DLP_Text_Style_1">${systemText[systemLanguage][34]}</p>
1065 <p class="DLP_Text_Style_1" style="opacity: 0.5;">${systemText[systemLanguage][35]}</p>
1066 </div>
1067 <div id="DLP_Inset_Toggle_1_ID" class="DLP_Toggle_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect">
1068 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
1069 </div>
1070 </div>
1071 <div id="DLP_Settings_Modern_Stats_Main_Box_1_ID" class="DLP_VStack_6" style="background: rgba(var(--DLP-blue), 0.10); outline: 2px solid rgba(var(--DLP-blue), 0.20); outline-offset: -2px; padding: 16px; border-radius: 8px;">
1072 <div style="display: flex; align-self: stretch; justify-content: space-between; align-items: center;">
1073 <p class="DLP_Text_Style_1" style="color: rgb(var(--DLP-blue));">3.1 Stats</p>
1074 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
1075 </div>
1076 <div style="display: flex; align-self: stretch; justify-content: space-between; align-items: center;">
1077 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);">XP Gained:</p>
1078 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
1079 </div>
1080 <div style="display: flex; align-self: stretch; justify-content: space-between; align-items: center;">
1081 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);">Gems Gained:</p>
1082 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
1083 </div>
1084 <div style="display: flex; align-self: stretch; justify-content: space-between; align-items: center;">
1085 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);">Streak Gained:</p>
1086 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
1087 </div>
1088 <div style="display: flex; align-self: stretch; justify-content: space-between; align-items: center;">
1089 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);">Heart Refills Requested:</p>
1090 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
1091 </div>
1092 </div>
1093 <div id="DLP_Settings_Legacy_Stats_Main_Box_1_ID" class="DLP_VStack_6" style="background: rgba(var(--DLP-blue), 0.10); outline: 2px solid rgba(var(--DLP-blue), 0.20); outline-offset: -2px; padding: 16px; border-radius: 8px;">
1094 <div style="display: flex; align-self: stretch; justify-content: space-between; align-items: center;">
1095 <p class="DLP_Text_Style_1" style="color: rgb(var(--DLP-blue));">Legacy Mode Stats</p>
1096 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
1097 </div>
1098 <div style="display: flex; align-self: stretch; justify-content: space-between; align-items: center;">
1099 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);">Lessons Solved:</p>
1100 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
1101 </div>
1102 <div style="display: flex; align-self: stretch; justify-content: space-between; align-items: center;">
1103 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);">Questions Solved:</p>
1104 <p class="DLP_Text_Style_1" style="color: rgba(var(--DLP-blue), 0.5);"></p>
1105 </div>
1106 </div>
1107 </div>
1108 </div>
1109 <div class="DLP_HStack_8">
1110 <div id="DLP_Settings_Save_Button_1_ID" class="DLP_Button_Style_2 DLP_Magnetic_Hover_1 DLP_NoSelect" style="outline: 2px solid rgba(0, 0, 0, 0.20); outline-offset: -2px; background: rgb(var(--DLP-blue));">
1111 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][37]}</p>
1112 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
1113 </div>
1114 </div>
1115 </div>
1116 </div>
1117
1118
1119 <div clas="DLP_Main_Box_Divider" id="DLP_Main_Box_Divider_8_ID" style="display: none;">
1120 <div class="DLP_VStack_8">
1121 <div class="DLP_HStack_Auto_Top DLP_NoSelect">
1122 <div id="DLP_Universal_Back_1_Button_1_ID" class="DLP_HStack_4 DLP_Hover_1">
1123 <p class="DLP_Text_Style_2" style="font-size: 20px; background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 0% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;"></p>
1124 <p class="DLP_Text_Style_2" style="background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${systemText[systemLanguage][38]}</p>
1125 </div>
1126 <p class="DLP_Text_Style_1" style="font-size: 14px; background: url(${serverURL}/static/images/flow/secondary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${versionName}</p>
1127 </div>
1128 <div class="DLP_VStack_4" style="padding: 16px; border-radius: 8px; outline: 2px solid rgba(var(--DLP-blue), 0.20); outline-offset: -2px; background: rgba(var(--DLP-blue), 0.10); box-sizing: border-box;">
1129 <div class="DLP_HStack_4">
1130 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: rgb(var(--DLP-blue));"></p>
1131 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch; color: rgb(var(--DLP-blue));">Need Support?</p>
1132 </div>
1133 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch; color: rgba(var(--DLP-blue), 0.5);">Get help from our <a href='https://www.duolingopro.net/faq' target='_blank' style='font-family: Duolingo PRO Rounded; color: rgb(var(--DLP-blue)); text-decoration: underline;'>FAQ page</a>, enhanced with AI, or join our <a href='https://www.duolingopro.net/discord' target='_blank' style='font-family: Duolingo PRO Rounded; color: rgb(var(--DLP-blue)); text-decoration: underline;'>Discord server</a> and talk with the devs.</p>
1134 </div>
1135 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][39]}</p>
1136 <textarea id="DLP_Feedback_Text_Input_1_ID" class="DLP_Large_Input_Box_Style_1" style="height: 128px; max-height: 256px;" placeholder="${systemText[systemLanguage][40]}"/></textarea>
1137 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][41]}</p>
1138 <div class="DLP_HStack_8">
1139 <div id="DLP_Feedback_Type_Bug_Report_Button_1_ID" class="DLP_Button_Style_2 DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Feedback_Type_Button_Style_1_OFF" style="transition: background 0.4s, outline 0.4s, filter 0.4s cubic-bezier(0.16, 1, 0.32, 1), transform 0.4s cubic-bezier(0.16, 1, 0.32, 1);">
1140 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="transition: 0.4s;"></p>
1141 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="transition: 0.4s;">${systemText[systemLanguage][42]}</p>
1142 </div>
1143 <div id="DLP_Feedback_Type_Suggestion_Button_1_ID" class="DLP_Button_Style_2 DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Feedback_Type_Button_Style_2_ON" style="transition: background 0.4s, outline 0.4s, filter 0.4s cubic-bezier(0.16, 1, 0.32, 1), transform 0.4s cubic-bezier(0.16, 1, 0.32, 1);">
1144 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="transition: 0.4s;"></p>
1145 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="transition: 0.4s;">${systemText[systemLanguage][43]}</p>
1146 </div>
1147 </div>
1148 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch;">${systemText[systemLanguage][44]}</p>
1149 <div class="DLP_HStack_8">
1150 <div id="DLP_Feedback_Attachment_Upload_Button_1_ID" class="DLP_Button_Style_2 DLP_Magnetic_Hover_1 DLP_NoSelect" style="outline: 2px solid rgba(var(--DLP-blue), 0.20); outline-offset: -2px; background: rgba(var(--DLP-blue), 0.10); transition: background 0.4s, outline 0.4s, filter 0.4s cubic-bezier(0.16, 1, 0.32, 1), transform 0.4s cubic-bezier(0.16, 1, 0.32, 1);">
1151 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: rgb(var(--DLP-blue)); transition: 0.4s;">${systemText[systemLanguage][45]}</p>
1152 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: rgb(var(--DLP-blue));"></p>
1153 </div>
1154 </div>
1155 <input type="file" accept="image/png, image/jpg, image/jpeg, video/mp4, image/gif, video/mov, video/webm" id="DLP_Feedback_Attachment_Input_Hidden_1_ID" style="display: none;"/>
1156 <div class="DLP_HStack_8">
1157 <div id="DLP_Feedback_Send_Button_1_ID" class="DLP_Button_Style_2 DLP_Magnetic_Hover_1 DLP_NoSelect" style="outline: 2px solid rgba(0, 0, 0, 0.20); outline-offset: -2px; background: rgb(var(--DLP-blue));">
1158 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: #FFF;">${systemText[systemLanguage][47]}</p>
1159 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
1160 </div>
1161 </div>
1162 </div>
1163 </div>
1164
1165
1166 <div class="DLP_Main_Box_Divider" id="DLP_Main_Box_Divider_9_ID" style="display: none;">
1167 <div class="DLP_VStack_8">
1168 <div class="DLP_HStack_Auto_Top DLP_NoSelect">
1169 <div id="DLP_Universal_Back_1_Button_1_ID" class="DLP_HStack_4 DLP_Hover_1">
1170 <p class="DLP_Text_Style_2" style="font-size: 20px; background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 0% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;"></p>
1171 <p class="DLP_Text_Style_2" style="background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${systemText[systemLanguage][48]}</p>
1172 </div>
1173 <p class="DLP_Text_Style_1" style="font-size: 14px; background: url(${serverURL}/static/images/flow/secondary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${versionName}</p>
1174 </div>
1175 <div class="DLP_VStack_8" id="DLP_Release_Notes_List_1_ID" style="height: 256px; padding: 0 16px;"></div>
1176 <div id="DLP_Release_Notes_Controls" class="DLP_NoSelect" style="display: flex; align-items: center; gap: 8px; margin: 8px;">
1177 <p class="DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_Inset_Icon_1_ID" style="color: rgb(var(--DLP-blue));"></p>
1178 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="color: rgb(var(--DLP-blue));"></p>
1179 <p class="DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_Inset_Icon_2_ID" style="color: rgb(var(--DLP-blue));"></p>
1180 </div>
1181 </div>
1182 </div>
1183
1184
1185 <div class="DLP_Main_Box_Divider" id="DLP_Main_Box_Divider_10_ID" style="display: none;">
1186 <div class="DLP_VStack_8">
1187 <div class="DLP_VStack_8" style="padding: 8px 0;">
1188 <div class="DLP_VStack_0">
1189 <p class="DLP_Text_Style_1" style="font-size: 14px; background: url(${serverURL}/static/images/flow/secondary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${systemText[systemLanguage][52]}</p>
1190 <div class="DLP_HStack_4" style="align-self: auto;">
1191 <p class="DLP_Text_Style_2">Duolingo</p>
1192 <p class="DLP_Text_Style_2" style="background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">PRO 3.1</p>
1193 </div>
1194 </div>
1195 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch; text-align: center;">${systemText[systemLanguage][53]}</p>
1196 </div>
1197 <div class="DLP_HStack_8">
1198 <div id="DLP_Onboarding_Start_Button_1_ID" class="DLP_Button_Style_2 DLP_Magnetic_Hover_1 DLP_NoSelect" style="outline: 2px solid rgba(0, 0, 0, 0.20); outline-offset: -2px; background: rgb(var(--DLP-blue));">
1199 <p class="DLP_Text_Style_1" style="color: #FFF;">${systemText[systemLanguage][54]}</p>
1200 <p class="DLP_Text_Style_1" style="color: #FFF;"></p>
1201 </div>
1202 </div>
1203 </div>
1204 </div>
1205
1206
1207 <div class="DLP_Main_Box_Divider" id="DLP_Main_Box_Divider_11_ID" style="display: none;">
1208 <div class="DLP_VStack_8">
1209 <div class="DLP_HStack_Auto_Top DLP_NoSelect">
1210 <div id="DLP_Universal_Back_1_Button_1_ID" class="DLP_HStack_4 DLP_Hover_1">
1211 <p class="DLP_Text_Style_2" style="font-size: 20px; background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 0% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;"></p>
1212 <p class="DLP_Text_Style_2" style="background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">Support</p>
1213 </div>
1214 <p class="DLP_Text_Style_1" style="font-size: 14px; background: url(${serverURL}/static/images/flow/secondary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${versionName}</p>
1215 </div>
1216
1217 <div class="DLP_VStack_8" style="height: 500px;">
1218 <div id="DLP_Inset_Card_1" style="display: flex; padding: 16px; flex-direction: column; justify-content: flex-start; align-items: flex-start; gap: 4px; align-self: stretch; border-radius: 8px; outline: 2px solid rgba(var(--DLP-blue), 0.20); outline-offset: -2px; background: rgba(var(--DLP-blue), 0.10); overflow: hidden; transition: all 0.4s cubic-bezier(0.16, 1, 0.32, 1);">
1219 <div class="DLP_HStack_6">
1220 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: rgb(var(--DLP-blue));"></p>
1221 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: rgb(var(--DLP-blue)); flex: 1 0 0;">Response Times</p>
1222 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: rgb(var(--DLP-blue));"></p>
1223 </div>
1224 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch; color: rgba(var(--DLP-blue), 0.5); display: none; opacity: 0; filter: blur(4px); height: 0px; transition: 0.4s cubic-bezier(0.16, 1, 0.32, 1);">It may take a few hours for a developer to respond to you. You will be notified in Duolingo PRO when there's a reply.</p>
1225 </div>
1226
1227 <div class="DLP_Chat_Box_1_ID_1" style="display: flex; flex-direction: column; align-items: center; gap: 8px; flex: 1 0 0; align-self: stretch; overflow-y: auto; display: none;">
1228
1229 </div>
1230
1231 <div class="DLP_VStack_8" id="DLP_Inset_Group_3" style="padding: 0px 32px; flex: 1 0 0;">
1232 <p class="DLP_Text_Style_1 DLP_NoSelect" style="background: url(https://www.duolingopro.net/static/images/flow/primary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-size: 24px;"></p>
1233 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch; text-align: center;">Send a message to start talking with a support member.</p>
1234 </div>
1235
1236 <div class="DLP_VStack_8" id="DLP_Inset_Group_2" style="display: none;">
1237 <div id="DLP_Inset_Card_2" style="display: flex; padding: 16px; flex-direction: column; justify-content: flex-start; align-items: flex-start; gap: 4px; align-self: stretch; border-radius: 8px; outline: 2px solid rgba(var(--DLP-blue), 0.20); outline-offset: -2px; background: rgba(var(--DLP-blue), 0.10); overflow: hidden; transition: all 0.4s cubic-bezier(0.16, 1, 0.32, 1);">
1238 <div class="DLP_HStack_6">
1239 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: rgb(var(--DLP-blue));"></p>
1240 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: rgb(var(--DLP-blue)); flex: 1 0 0;">This chat was closed.</p>
1241 </div>
1242 <p class="DLP_Text_Style_1 DLP_NoSelect" style="align-self: stretch; color: rgba(var(--DLP-blue), 0.5);">We hope to have solved your issue. If not, you can start a new chat.</p>
1243 </div>
1244
1245 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_3_ID" style="width: 100%;">
1246 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: #FFF;">Start a New Chat</p>
1247 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: #FFF;"></p>
1248 </div>
1249 </div>
1250
1251 <div class="DLP_VStack_8" id="DLP_Inset_Group_1">
1252 <div id="DLP_Attachment_Preview_Parent" class="DLP_Row DLP_Left DLP_Gap_8" style="width: 100%; overflow-y: scroll; display: none;">
1253 <div class="DLP_Attachment_Box_Drop_1 DLP_Fill_Col" style="height: 96px; display: none;">
1254 <div class="DLP_Row DLP_Gap_6" style="opacity: 0.5;">
1255 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: rgb(var(--DLP-blue));"></p>
1256 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: rgb(var(--DLP-blue));">Drop here to attach</p>
1257 </div>
1258 </div>
1259 </div>
1260
1261 <div class="DLP_HStack_8" style="align-items: flex-end;">
1262 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Hide_Scrollbar" id="DLP_Inset_Button_1_ID" style="width: 48px; background: rgba(var(--DLP-blue), 0.10); outline-offset: -2px; outline: 2px solid rgba(var(--DLP-blue), 0.20);">
1263 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: rgb(var(--DLP-blue));"></p>
1264 <input type="file" id="DLP_Attachment_Input_1" accept="image/*, video/*" multiple style="display: none;">
1265 </div>
1266 <div class="DLP_Input_Style_1_Active" style="padding: 0;">
1267 <textarea type="text" placeholder="Type here..." id="DLP_Inset_Input_1_ID" class="DLP_Input_Style_1 DLP_Hide_Scrollbar" style="padding: 16px; box-sizing: content-box; overflow: scroll;"></textarea>
1268 </div>
1269 <div class="DLP_Input_Button_Style_1_Active DLP_Magnetic_Hover_1 DLP_NoSelect" id="DLP_Inset_Button_2_ID" style="width: 48px;">
1270 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: #FFF;"></p>
1271 </div>
1272 </div>
1273 </div>
1274 </div>
1275
1276 </div>
1277 </div>
1278
1279 </div>
1280</div>
1281`;
1282CSS2 = `
1283.DLP_NoSelect {
1284 -webkit-touch-callout: none;
1285 -webkit-user-select: none;
1286 -khtml-user-select: none;
1287 -moz-user-select: none;
1288 -ms-user-select: none;
1289 user-select: none;
1290}
1291.DLP_Text_Style_1 {
1292 font-family: "Duolingo PRO Rounded";
1293 font-size: 16px;
1294 font-style: normal;
1295 font-weight: 500;
1296 line-height: normal;
1297
1298 color: rgb(var(--color-wolf), 0.8);
1299
1300 margin: 0;
1301 -webkit-font-smoothing: antialiased;
1302}
1303.DLP_Text_Style_2 {
1304 font-family: "Duolingo PRO Rounded";
1305 font-size: 24px;
1306 font-style: normal;
1307 font-weight: 500;
1308 line-height: normal;
1309
1310 margin: 0;
1311 -webkit-font-smoothing: antialiased;
1312}
1313.DLP_Magnetic_Hover_1 {
1314 transition: filter 0.4s cubic-bezier(0.16, 1, 0.32, 1), transform 0.4s cubic-bezier(0.16, 1, 0.32, 1);
1315 cursor: pointer;
1316}
1317.DLP_Magnetic_Hover_1:hover {
1318 filter: brightness(0.9);
1319 transform: scale(1.05);
1320}
1321.DLP_Magnetic_Hover_1:active {
1322 filter: brightness(0.9);
1323 transform: scale(0.9);
1324}
1325
1326.DLP_Hover_1 {
1327 transition: filter 0.4s cubic-bezier(0.16, 1, 0.32, 1);
1328 cursor: pointer;
1329}
1330.DLP_Hover_1:hover {
1331 filter: brightness(0.9);
1332}
1333.DLP_Hover_1:active {
1334 filter: brightness(0.9);
1335}
1336
1337
1338
1339.DLP_Row {
1340 display: flex;
1341 flex-direction: row;
1342}
1343.DLP_Col {
1344 display: flex;
1345 flex-direction: column;
1346}
1347
1348.DLP_Auto {
1349 justify-content: space-between;
1350}
1351.DLP_Hug {
1352 justify-content: center;
1353}
1354.DLP_Fill_Row {
1355 align-self: stretch;
1356}
1357.DLP_Fill_Col {
1358 flex: 1 0 0;
1359}
1360
1361.DLP_Left {
1362 justify-content: flex-start;
1363}
1364.DLP_Right {
1365 justify-content: flex-end;
1366}
1367
1368.DLP_Top {
1369 align-items: flex-start;
1370}
1371.DLP_Center {
1372 align-items: center;
1373}
1374.DLP_Bottom {
1375 align-items: flex-end;
1376}
1377
1378.DLP_Gap_0 {
1379 gap: 0px;
1380}
1381.DLP_Gap_2 {
1382 gap: 2px;
1383}
1384.DLP_Gap_4 {
1385 gap: 4px;
1386}
1387.DLP_Gap_6 {
1388 gap: 6px;
1389}
1390.DLP_Gap_8 {
1391 gap: 8px;
1392}
1393.DLP_Gap_12 {
1394 gap: 12px;
1395}
1396.DLP_Gap_16 {
1397 gap: 16px;
1398}
1399.DLP_Gap_24 {
1400 gap: 24px;
1401}
1402.DLP_Gap_32 {
1403 gap: 32px;
1404}
1405
1406
1407
1408.DLP_Main {
1409 display: inline-flex;
1410 flex-direction: column;
1411 justify-content: flex-end;
1412 align-items: flex-end;
1413 gap: 8px;
1414
1415 position: fixed;
1416 right: 16px;
1417 bottom: 16px;
1418 z-index: 2;
1419}
1420@media (max-width: 699px) {
1421 .DLP_Main {
1422 display: inline-flex;
1423 flex-direction: column;
1424 justify-content: flex-end;
1425 align-items: flex-end;
1426 gap: 8px;
1427
1428 position: fixed;
1429 right: 16px;
1430 bottom: 16px;
1431 z-index: 2;
1432 margin-bottom: 80px;
1433 }
1434}
1435.DLP_Main_Box {
1436 display: flex;
1437 width: 312px;
1438 padding: 16px;
1439 box-sizing: border-box;
1440 flex-direction: column;
1441 justify-content: center;
1442 align-items: center;
1443 gap: 8px;
1444 overflow: hidden;
1445
1446 border-radius: 20px;
1447 outline: 2px solid rgb(var(--color-eel), 0.10);
1448 outline-offset: -2px;
1449 background: rgb(var(--color-snow), 0.90);
1450 backdrop-filter: blur(16px);
1451}
1452.DLP_Main_Box_Divider {
1453 display: flex;
1454 box-sizing: border-box;
1455 flex-direction: column;
1456 justify-content: center;
1457 align-items: center;
1458 gap: 8px;
1459
1460 width: 100%;
1461}
1462svg {
1463 flex-shrink: 0;
1464}
1465.DLP_HStack_Auto {
1466 display: flex;
1467 align-items: center;
1468 justify-content: space-between;
1469 align-self: stretch;
1470}
1471.DLP_HStack_Auto_Top {
1472 display: flex;
1473 align-items: flex-start;
1474 justify-content: space-between;
1475 align-self: stretch;
1476}
1477.DLP_HStack_0 {
1478 display: flex;
1479 align-items: center;
1480 gap: 0;
1481 align-self: stretch;
1482}
1483.DLP_HStack_4 {
1484 display: flex;
1485 align-items: center;
1486 gap: 4px;
1487 align-self: stretch;
1488}
1489.DLP_HStack_6 {
1490 display: flex;
1491 align-items: center;
1492 gap: 6px;
1493 align-self: stretch;
1494}
1495.DLP_HStack_8 {
1496 display: flex;
1497 align-items: center;
1498 gap: 8px;
1499 align-self: stretch;
1500}
1501.DLP_VStack_0 {
1502 display: flex;
1503 flex-direction: column;
1504 justify-content: center;
1505 align-items: center;
1506 gap: 0;
1507 align-self: stretch;
1508}
1509.DLP_VStack_4 {
1510 display: flex;
1511 flex-direction: column;
1512 justify-content: center;
1513 align-items: center;
1514 gap: 4px;
1515 align-self: stretch;
1516}
1517.DLP_VStack_6 {
1518 display: flex;
1519 flex-direction: column;
1520 justify-content: center;
1521 align-items: center;
1522 gap: 6px;
1523 align-self: stretch;
1524}
1525.DLP_VStack_8 {
1526 display: flex;
1527 flex-direction: column;
1528 justify-content: center;
1529 align-items: center;
1530 gap: 8px;
1531 align-self: stretch;
1532}
1533.DLP_VStack_12 {
1534 display: flex;
1535 flex-direction: column;
1536 justify-content: center;
1537 align-items: center;
1538 gap: 12px;
1539 align-self: stretch;
1540}
1541.DLP_Hide_Scrollbar {
1542 scrollbar-width: none;
1543 -ms-overflow-style: none;
1544}
1545.DLP_Hide_Scrollbar::-webkit-scrollbar {
1546 display: none;
1547}
1548.DLP_Button_Style_1 {
1549 display: flex;
1550 height: 40px;
1551 padding: 10px 12px 10px 10px;
1552 box-sizing: border-box;
1553 align-items: center;
1554 gap: 6px;
1555 flex: 1 0 0;
1556
1557 border-radius: 8px;
1558}
1559.DLP_Input_Style_1 {
1560 border: none;
1561 outline: none;
1562 background: none;
1563
1564 font-family: "Duolingo PRO Rounded";
1565 font-size: 16px;
1566 font-style: normal;
1567 font-weight: 500;
1568 line-height: normal;
1569 color: rgb(var(--DLP-blue));
1570
1571 width: 100%;
1572
1573 width: 100%; /* Full width */
1574 height: auto; /* Let the height be controlled dynamically */
1575 min-height: 1.2em; /* Set minimum height for one line */
1576 max-height: calc(1.2em * 5); /* Limit to 5 lines */
1577 line-height: 1.2em; /* Adjust the line height */
1578 overflow-y: hidden; /* Hide vertical scrollbar */
1579 resize: none; /* Prevent manual resizing */
1580 padding: 0; /* Remove padding to eliminate extra space */
1581 margin: 0; /* Remove margin to eliminate extra space */
1582 box-sizing: border-box; /* Include padding in height calculation */
1583
1584}
1585.DLP_Input_Style_1::placeholder {
1586 color: rgba(var(--DLP-blue), 0.50);
1587}
1588.DLP_Input_Input_Style_1 {
1589 border: none;
1590 outline: none;
1591 background: none;
1592 text-align: right;
1593
1594 font-family: "Duolingo PRO Rounded";
1595 font-size: 16px;
1596 font-style: normal;
1597 font-weight: 500;
1598 line-height: normal;
1599 color: rgb(var(--DLP-blue));
1600
1601 width: 100%;
1602}
1603.DLP_Input_Input_Style_1::placeholder {
1604 color: rgba(var(--DLP-blue), 0.50);
1605}
1606.DLP_Input_Style_1_Active {
1607 display: flex;
1608 height: 48px;
1609 padding: 16px;
1610 box-sizing: border-box;
1611 align-items: center;
1612 flex: 1 0 0;
1613 gap: 6px;
1614
1615 border-radius: 8px;
1616 outline: 2px solid rgba(var(--DLP-blue), 0.20);
1617 outline-offset: -2px;
1618 background: rgba(var(--DLP-blue), 0.10);
1619}
1620.DLP_Input_Button_Style_1_Active {
1621 display: flex;
1622 height: 48px;
1623 padding: 12px 12px 12px 14px;
1624 box-sizing: border-box;
1625 justify-content: center;
1626 align-items: center;
1627 gap: 6px;
1628
1629 border-radius: 8px;
1630 outline: 2px solid rgba(0, 0, 0, 0.20);
1631 outline-offset: -2px;
1632 background: rgb(var(--DLP-blue));
1633}
1634@keyframes DLP_Rotate_360_Animation_1 {
1635 from {
1636 transform: rotate(0deg);
1637 }
1638 to {
1639 transform: rotate(360deg);
1640 }
1641}
1642@keyframes DLP_Pulse_Opacity_Animation_1 {
1643 0% {
1644 opacity: 1;
1645 }
1646 16.66666666% {
1647 opacity: 0.75;
1648 }
1649 33.33333333% {
1650 opacity: 1;
1651 }
1652 100% {
1653 opacity: 1;
1654 }
1655}
1656@keyframes DLP_Pulse_Opacity_Animation_2 {
1657 0% {
1658 opacity: 0.75;
1659 }
1660 50% {
1661 opacity: 0.5;
1662 }
1663 100% {
1664 opacity: 0.75;
1665 }
1666}
1667.DLP_Scroll_Box_Style_1 {
1668 display: flex;
1669 height: 200px;
1670 padding: 14px 16px;
1671 box-sizing: border-box;
1672 justify-content: center;
1673 align-items: flex-start;
1674 gap: 8px;
1675 align-self: stretch;
1676
1677 border-radius: 8px;
1678 outline: 2px solid rgb(var(--color-eel), 0.10);
1679 outline-offset: -2px;
1680 background: rgb(var(--color-snow), 0.90);
1681
1682 position: relative;
1683}
1684.DLP_Scroll_Box_Text_Style_1 {
1685 font-family: "Duolingo PRO Rounded";
1686 font-size: 16px;
1687 font-style: normal;
1688 font-weight: 500;
1689 line-height: normal;
1690 color: rgb(var(--color-wolf));
1691 margin: 0;
1692
1693 overflow-y: scroll;
1694 overflow-x: hidden;
1695 position: absolute;
1696 top: 0;
1697 bottom: 0;
1698 right: 16px;
1699 left: 16px;
1700 padding-top: 16px;
1701 padding-bottom: 16px;
1702}
1703.DLP_Scroll_Box_Text_Style_1::-webkit-scrollbar {
1704 transform: translateX(16px);
1705}
1706.DLP_Button_Style_2 {
1707 display: flex;
1708 height: 48px;
1709 box-sizing: border-box;
1710 justify-content: center;
1711 align-items: center;
1712 gap: 6px;
1713 flex: 1 0 0;
1714
1715 border-radius: 8px;
1716}
1717.DLP_Toggle_Style_1 {
1718 display: flex;
1719 width: 48px;
1720 height: 48px;
1721 padding: 16px;
1722 box-sizing: border-box;
1723 justify-content: center;
1724 align-items: center;
1725 gap: 6px;
1726
1727 border-radius: 8px;
1728 transition: background 0.8s cubic-bezier(0.16, 1, 0.32, 1), filter 0.4s cubic-bezier(0.16, 1, 0.32, 1), transform 0.4s cubic-bezier(0.16, 1, 0.32, 1);
1729}
1730.DLP_Toggle_Style_1_ON {
1731 outline: 2px solid rgba(0, 0, 0, 0.20);
1732 outline-offset: -2px;
1733 background: rgb(var(--DLP-green));
1734}
1735.DLP_Toggle_Style_1_OFF {
1736 outline: 2px solid rgba(0, 0, 0, 0.20);
1737 outline-offset: -2px;
1738 background: rgb(var(--DLP-pink));
1739}
1740.DLP_Large_Input_Box_Style_1 {
1741 display: flex;
1742 padding: 16px;
1743 box-sizing: border-box;
1744 justify-content: center;
1745 align-items: flex-start;
1746 align-self: stretch;
1747
1748 border-radius: 8px;
1749 border: none;
1750 outline: 2px solid rgb(var(--color-eel), 0.10);
1751 outline-offset: -2px;
1752 background: rgb(var(--color-snow), 0.90);
1753
1754 color: rgb(var(--color-eel), 0.50);
1755 font-size: 16px;
1756 font-weight: 500;
1757 font-family: Duolingo PRO Rounded, 'din-round' !important;
1758
1759 resize: vertical;
1760 transition: .2s;
1761}
1762.DLP_Large_Input_Box_Style_1::placeholder {
1763 font-weight: 500;
1764 color: rgb(var(--color-eel), 0.25);
1765}
1766.DLP_Large_Input_Box_Style_1:focus {
1767 outline: 2px solid rgb(var(--DLP-blue));
1768}
1769.DLP_Feedback_Type_Button_Style_1_ON {
1770 outline: 2px solid rgba(0, 0, 0, 0.20);
1771 outline-offset: -2px;
1772 background: rgb(var(--DLP-pink));
1773}
1774.DLP_Feedback_Type_Button_Style_1_ON .DLP_Text_Style_1 {
1775 color: #FFF;
1776}
1777.DLP_Feedback_Type_Button_Style_1_OFF {
1778 outline: 2px solid rgba(255, 45, 85, 0.20);
1779 outline-offset: -2px;
1780 background: rgba(255, 45, 85, 0.10);
1781}
1782.DLP_Feedback_Type_Button_Style_1_OFF .DLP_Text_Style_1 {
1783 color: rgb(var(--DLP-pink));
1784}
1785.DLP_Feedback_Type_Button_Style_2_ON {
1786 outline: 2px solid rgba(0, 0, 0, 0.20);
1787 outline-offset: -2px;
1788 background: rgb(var(--DLP-green));
1789}
1790.DLP_Feedback_Type_Button_Style_2_ON .DLP_Text_Style_1 {
1791 color: #FFF;
1792}
1793.DLP_Feedback_Type_Button_Style_2_OFF {
1794 outline: 2px solid rgba(52, 199, 89, 0.20);
1795 outline-offset: -2px;
1796 background: rgba(52, 199, 89, 0.10);
1797}
1798.DLP_Feedback_Type_Button_Style_2_OFF .DLP_Text_Style_1 {
1799 color: rgb(var(--DLP-green));
1800}
1801
1802.DLP_Notification_Main {
1803 display: flex;
1804 justify-content: center;
1805 align-items: center;
1806
1807 transition: 0.8s cubic-bezier(0.16, 1, 0.32, 1);
1808 width: 300px;
1809 position: fixed;
1810 left: calc(50% - (300px / 2));
1811 z-index: 210;
1812 bottom: 16px;
1813 border-radius: 16px;
1814}
1815.DLP_Notification_Box {
1816 display: flex;
1817 width: 300px;
1818 padding: 16px;
1819 box-sizing: border-box;
1820 flex-direction: column;
1821 justify-content: flex-start;
1822 align-items: center;
1823 gap: 4px;
1824
1825 border-radius: 16px;
1826 outline: 2px solid rgb(var(--color-eel), 0.10);
1827 outline-offset: -2px;
1828 background: rgb(var(--color-snow), 0.90);
1829 backdrop-filter: blur(16px);
1830
1831 transition: 0.8s cubic-bezier(0.16, 1, 0.32, 1);
1832 filter: blur(16px);
1833 opacity: 0;
1834}
1835._2V6ug._1ursp._7jW2t._2hkLC._1wiIJ {
1836 width: 36px !important;
1837 height: 38px !important;
1838}
1839._2V6ug._1ursp._7jW2t._2hkLC._1wiIJ::before {
1840 border-radius: 20px !important;
1841}
1842.DLP_Tooltip {
1843 position: fixed;
1844 display: inline-flex;
1845 height: 40px;
1846 padding: 10px 14px;
1847 box-sizing: border-box;
1848 margin: 0;
1849 align-items: center;
1850 gap: 6px;
1851 flex-shrink: 0;
1852
1853 border-radius: 24px;
1854 outline: 2px solid rgb(var(--color-eel), 0.10);
1855 outline-offset: -2px;
1856 background: rgb(var(--color-snow), 0.90);
1857 backdrop-filter: blur(4px);
1858 filter: blur(8px);
1859
1860 font-family: Duolingo PRO Rounded;
1861 z-index: 10;
1862 opacity: 0;
1863 transition: opacity 0.5s ease-in-out, filter 0.5s ease-in-out;
1864 white-space: nowrap;
1865 pointer-events: none;
1866}
1867.DLP_Tooltip.DLP_Tooltip_Visible {
1868 opacity: 1;
1869 filter: blur(0px);
1870}
1871.DLP_Attachment_Box_1 {
1872 width: 96px;
1873 height: 96px;
1874 aspect-ratio: 1/1;
1875 object-fit: cover;
1876 overflow: hidden;
1877 position: relative;
1878
1879 border-radius: 8px;
1880 outline: 2px solid rgba(var(--color-black-white), 0.20);
1881 outline-offset: -2px;
1882 background: rgba(var(--color-black-text), 0.20); /* Gotta change */
1883}
1884.DLP_Attachment_Box_1_Content {
1885 width: 100%;
1886 height: 100%;
1887 aspect-ratio: 1/1;
1888 object-fit: cover;
1889}
1890.DLP_Attachment_Box_1_Hover {
1891 display: flex;
1892 width: 100%;
1893 height: 100%;
1894 position: absolute;
1895 top: 0;
1896 left: 0;
1897 right: 0;
1898 bottom: 0;
1899
1900 flex-direction: column;
1901 justify-content: center;
1902 align-items: center;
1903 flex-shrink: 0;
1904
1905 background: rgba(var(--color-snow), 0.50);
1906 backdrop-filter: blur(8px);
1907 outline: inherit;
1908 outline-offset: inherit;
1909 border-radius: inherit;
1910}
1911.DLP_Attachment_Box_Large_View_1 {
1912 display: flex;
1913 position: fixed;
1914 inset: 0;
1915 width: 100%;
1916 height: 100vh;
1917 justify-content: center;
1918 align-items: center;
1919 flex-shrink: 0;
1920
1921 background: rgba(var(--color-snow), 0.00);
1922 backdrop-filter: blur(0px);
1923 z-index: 211;
1924 transition: 0.4s cubic-bezier(0.16, 1, 0.32, 1);
1925}
1926.DLP_Attachment_Box_Drop_1 {
1927 display: flex;
1928 height: 48px;
1929 padding: 16px;
1930 justify-content: center;
1931 align-items: center;
1932 gap: 6px;
1933
1934 border-radius: 8px;
1935 /* outline: 2px dashed rgba(var(--DLP-blue), 0.20); */
1936 outline: 2px solid rgba(var(--DLP-blue), 0.20);
1937 outline-offset: -2px;
1938 background: linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.90);
1939}
1940
1941@keyframes slideRight {
1942 0% {
1943 transform: translateX(-150px);
1944 }
1945 20% {
1946 transform: translateX(200px);
1947 }
1948 100% {
1949 transform: translateX(200px);
1950 }
1951}
1952
1953`;
1954
1955HTML3 = `
1956<div class="DLP_Notification_Box" style="position: fixed;">
1957 <div class="DLP_HStack_4" style="align-items: center;">
1958 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID DLP_NoSelect"></p>
1959 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID" style="flex: 1 0 0;"></p>
1960 <p class="DLP_Text_Style_1 DLP_Inset_Icon_2_ID DLP_Magnetic_Hover_1 DLP_NoSelect" style="align-self: stretch;"></p>
1961 </div>
1962 <p class="DLP_Text_Style_1 DLP_Inset_Text_2_ID" style="opacity: 0.5; align-self: stretch; overflow-wrap: break-word;"></p>
1963</div>
1964`;
1965
1966HTML4 = `
1967.solving-btn {
1968 position: relative;
1969 min-width: 150px;
1970 font-size: 17px;
1971 border: none;
1972 border-bottom: 4px solid #2b70c9;
1973 border-radius: 16px;
1974 padding: 13px 16px;
1975 transition: filter .0s;
1976 font-weight: 700;
1977 letter-spacing: .8px;
1978 background: #1cb0f6;
1979 color: rgb(var(--color-snow));
1980 cursor: pointer;
1981}
1982.solve-btn {
1983 position: relative;
1984 min-width: 100px;
1985 font-size: 17px;
1986 border: none;
1987 border-bottom: 4px solid #ff9600;
1988 border-radius: 16px;
1989 padding: 13px 16px;
1990 transition: filter .0s;
1991 font-weight: 700;
1992 letter-spacing: .8px;
1993 background: #ffc800;
1994 color: rgb(var(--color-snow));
1995 cursor: pointer;
1996}
1997.auto-solver-btn:hover {
1998 filter: brightness(1.1);
1999}
2000.auto-solver-btn:active {
2001 border-bottom: 0px;
2002 margin-bottom: 4px;
2003 top: 4px;
2004}
2005`;
2006
2007HTML5 = `
2008<div class="DLP_AutoServer_Mother_Box" style="display: none; opacity: 0; filter: blur(8px);">
2009 <div class="DLP_AutoServer_Box DLP_Hide_Scrollbar">
2010 <div class="DLP_AutoServer_Menu_Bar">
2011 <div style="display: flex; justify-content: center; align-items: center; gap: 6px; opacity: 0.5;">
2012 <p id="DLP_AutoServer_Close_Button_1_ID" class="DLP_AutoServer_Text_Style_1 DLP_Magnetic_Hover_1" style="color: rgb(var(--color-black-text));"></p>
2013 </div>
2014 <div class="DLP_NoSelect" style="display: flex; justify-content: center; align-items: center; gap: 6px; opacity: 0.5;">
2015 <p class="DLP_AutoServer_Text_Style_1 DLP_Inset_Text_1_ID" style="color: rgb(var(--color-black-text));">Unavailable</p>
2016 <p class="DLP_AutoServer_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: rgb(var(--color-black-text));"></p>
2017 </div>
2018 </div>
2019 <div class="DLP_AutoServer_Scroll_Box">
2020
2021 <div style="display: flex; justify-content: space-between; align-items: center; align-self: stretch;">
2022 <div style="display: flex; align-items: flex-end; gap: 4px;">
2023 <p class="DLP_AutoServer_Text_Style_2 DLP_NoSelect">AutoServer</p>
2024 <div class="DLP_HStack_4" style="align-items: center; padding-top: 6px;">
2025 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="opacity: 0.5;">by Duolingo</p>
2026 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="background: url(${serverURL}/static/images/flow/primary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">PRO</p>
2027 </div>
2028 </div>
2029 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="font-size: 14px; background: url(${serverURL}/static/images/flow/secondary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${versionName}</p>
2030 </div>
2031
2032 <div class="DLP_AutoServer_Default_Box" style="background: linear-gradient(rgba(var(--color-snow), 0.8), rgba(var(--color-snow), 0.8)), url(${serverURL}/static/images/flow/primary/512/light.png); background-position: center; background-size: cover; background-repeat: no-repeat;">
2033 <div style="display: flex; display: none; flex-direction: column; align-items: flex-start; gap: 6px; align-self: stretch; width: 100%;">
2034 <div class="DLP_HStack_Auto">
2035 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect">Settings</p>
2036 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect"></p>
2037 </div>
2038 <div class="DLP_HStack_Auto">
2039 <div class="DLP_HStack_4" style="align-items: center;">
2040 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect"></p>
2041 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect">Timezone</p>
2042 </div>
2043 <p class="DLP_AutoServer_Text_Style_1">America/NewYork - 11:45 PM</p>
2044 </div>
2045 </div>
2046 <div style="display: flex; flex-direction: column; align-items: flex-start; gap: 6px; align-self: stretch; width: 100%;">
2047 <div class="DLP_HStack_Auto" style="align-items: center; width: 100%;">
2048 <p class="DLP_AutoServer_Text_Style_1">Under Construction</p>
2049 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect"></p>
2050 </div>
2051 <p class="DLP_AutoServer_Text_Style_1" style="opacity: 0.5;">AutoServer is currently under construction and unavailable. We appreciate your patience and will provide updates as progress continues.</p>
2052 </div>
2053 </div>
2054
2055 <div class="DLP_AutoServer_Default_Box" style="height: 256px; background: linear-gradient(rgba(var(--color-snow), 0), rgba(var(--color-snow), 0)), url(${serverURL}/static/images/flow/primary/512/light.png); background-position: center; background-size: cover; background-repeat: no-repeat;">
2056 <div style="display: flex; width: 168px; flex-direction: column; justify-content: space-between; align-items: flex-start; align-self: stretch;">
2057 <div class="DLP_VStack_6">
2058 <div class="DLP_HStack_Auto">
2059 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF;"></p>
2060 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF;">Streak Protector</p>
2061 </div>
2062 <div class="DLP_HStack_Auto">
2063 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF; opacity: 0;">BETA</p>
2064 <div class="DLP_HStack_4 DLP_Magnetic_Hover_1">
2065 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF;">Active</p>
2066 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
2067 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect DLP_Inset_Icon_1_ID" style="color: #FFF; display: none;"></p>
2068 </div>
2069 </div>
2070 </div>
2071 <div class="DLP_VStack_12">
2072 <div class="DLP_VStack_6">
2073 <div class="DLP_HStack_Auto">
2074 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF; opacity: 0.5;">Protecting:</p>
2075 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF; opacity: 0;">BETA</p>
2076 </div>
2077 <div class="DLP_HStack_Auto">
2078 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect DLP_Magnetic_Hover_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
2079 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF;">2 Days</p>
2080 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect DLP_Magnetic_Hover_1 DLP_Inset_Icon_2_ID" style="color: #FFF;"></p>
2081 </div>
2082 </div>
2083 <div class="DLP_VStack_6">
2084 <div class="DLP_HStack_Auto">
2085 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF; opacity: 0.5;">Protecting Time:</p>
2086 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF; opacity: 0;">BETA</p>
2087 </div>
2088 <div class="DLP_HStack_Auto">
2089 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect DLP_Magnetic_Hover_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
2090 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF;">Morning</p>
2091 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect DLP_Magnetic_Hover_1 DLP_Inset_Icon_2_ID" style="color: #FFF;"></p>
2092 </div>
2093 </div>
2094 </div>
2095 </div>
2096 <div style="display: flex; flex-direction: column; align-items: flex-start; gap: 6px; flex: 1 0 0; align-self: stretch;">
2097 <div class="DLP_VStack_6" style="height: 100%; justify-content: flex-start;">
2098 <div class="DLP_HStack_Auto">
2099 <div class="DLP_HStack_4">
2100 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF;"></p>
2101 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF;">Info</p>
2102 </div>
2103 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF; opacity: 0.5;">This function is in BETA</p>
2104 </div>
2105 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF; opacity: 0.5;">Streak Protector extends your streak by completing a lesson in our servers.</p>
2106 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF; opacity: 0.5;">You can only protect your streak for up to 7 days. Donate to protect longer.</p>
2107 <div style="display: flex; justify-content: flex-end; align-items: flex-end; gap: 6px; flex: 1 0 0; align-self: stretch;">
2108 <p class="DLP_AutoServer_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" style="color: #FFF; opacity: 0.5;">Learn More</p>
2109 </div>
2110 </div>
2111 </div>
2112 </div>
2113
2114 <div class="DLP_AutoServer_Default_Box" style="height: 256px; background: linear-gradient(rgba(var(--color-snow), 0), rgba(var(--color-snow), 0)), url(${serverURL}/static/images/flow/secondary/512/light.png); background-position: center; background-size: cover; background-repeat: no-repeat;">
2115 <div style="display: flex; width: 168px; flex-direction: column; justify-content: space-between; align-items: flex-start; align-self: stretch;">
2116 <div class="DLP_VStack_6">
2117 <div class="DLP_HStack_Auto">
2118 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF;"></p>
2119 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF;">League Protector</p>
2120 </div>
2121 <div class="DLP_HStack_Auto">
2122 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF; opacity: 0;">BETA</p>
2123 <div class="DLP_HStack_4 DLP_Magnetic_Hover_1">
2124 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF;">Active</p>
2125 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
2126 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect DLP_Inset_Icon_1_ID" style="color: #FFF; display: none;"></p>
2127 </div>
2128 </div>
2129 </div>
2130 <div class="DLP_VStack_12">
2131 <div class="DLP_VStack_6">
2132 <div class="DLP_HStack_Auto">
2133 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF; opacity: 0.5;">Protecting:</p>
2134 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF; opacity: 0;">BETA</p>
2135 </div>
2136 <div class="DLP_HStack_Auto">
2137 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect DLP_Magnetic_Hover_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
2138 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF;">5 Days</p>
2139 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect DLP_Magnetic_Hover_1 DLP_Inset_Icon_2_ID" style="color: #FFF;"></p>
2140 </div>
2141 </div>
2142 <div class="DLP_VStack_6">
2143 <div class="DLP_HStack_Auto">
2144 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF; opacity: 0.5;">Protecting Mode:</p>
2145 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF; opacity: 0;">BETA</p>
2146 </div>
2147 <div class="DLP_HStack_Auto">
2148 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect DLP_Magnetic_Hover_1 DLP_Inset_Icon_1_ID" style="color: #FFF;"></p>
2149 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF;">Chill</p>
2150 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect DLP_Magnetic_Hover_1 DLP_Inset_Icon_2_ID" style="color: #FFF;"></p>
2151 </div>
2152 </div>
2153 </div>
2154 </div>
2155 <div style="display: flex; flex-direction: column; align-items: flex-start; gap: 6px; flex: 1 0 0; align-self: stretch;">
2156 <div class="DLP_VStack_6" style="height: 100%; justify-content: flex-start;">
2157 <div class="DLP_HStack_Auto">
2158 <div class="DLP_HStack_4">
2159 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF;"></p>
2160 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF;">Info</p>
2161 </div>
2162 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF; opacity: 0.5;">This function is in BETA</p>
2163 </div>
2164 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF; opacity: 0.5;">League Protector protects your league position by completing lessons in our servers.</p>
2165 <p class="DLP_AutoServer_Text_Style_1 DLP_NoSelect" style="color: #FFF; opacity: 0.5;">You only have access to Chill and Standard Mode with up to 7 days of protection. Donate to get access to Aggressive Mode and longer protection.</p>
2166 <div style="display: flex; justify-content: flex-end; align-items: flex-end; gap: 6px; flex: 1 0 0; align-self: stretch;">
2167 <p class="DLP_AutoServer_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect" style="color: #FFF; opacity: 0.5;">Learn More</p>
2168 </div>
2169 </div>
2170 </div>
2171 </div>
2172
2173 </div>
2174 </div>
2175</div>
2176`;
2177CSS5 = `
2178.DLP_AutoServer_Text_Style_1 {
2179 font-family: "Duolingo PRO Rounded";
2180 font-size: 16px;
2181 font-style: normal;
2182 font-weight: 500;
2183 line-height: normal;
2184
2185 margin: 0;
2186 -webkit-font-smoothing: antialiased;
2187}
2188.DLP_AutoServer_Text_Style_2 {
2189 font-family: "Duolingo PRO Rounded";
2190 font-size: 24px;
2191 font-style: normal;
2192 font-weight: 500;
2193 line-height: normal;
2194
2195 margin: 0;
2196 -webkit-font-smoothing: antialiased;
2197}
2198.DLP_AutoServer_Mother_Box {
2199 position: fixed;
2200 top: 0;
2201 bottom: 0;
2202 right: 0;
2203 left: 0;
2204 display: flex;
2205 width: 100%;
2206 height: 100vh;
2207 justify-content: center;
2208 align-items: center;
2209 flex-shrink: 0;
2210 z-index: 210;
2211 transition: filter 0.4s cubic-bezier(0.16, 1, 0.32, 1), opacity 0.4s cubic-bezier(0.16, 1, 0.32, 1);
2212
2213 background: rgba(var(--color-snow), 0.50);
2214 backdrop-filter: blur(16px);
2215}
2216
2217.DLP_AutoServer_Box {
2218 display: flex;
2219 width: 512px;
2220 height: 512px;
2221 flex-direction: column;
2222 align-items: center;
2223 flex-shrink: 0;
2224 overflow-y: scroll;
2225 overflow-x: hidden;
2226 scrollbar-width: none;
2227 -ms-overflow-style: none;
2228
2229 border-radius: 20px;
2230 border: 2px solid rgba(var(--color-eel), 0.10);
2231 background: rgba(var(--color-snow), 0.90);
2232 backdrop-filter: blur(16px);
2233 box-sizing: border-box;
2234}
2235
2236.DLP_AutoServer_Menu_Bar {
2237 display: flex;
2238 width: 100%;
2239 height: 64px;
2240 padding: 16px;
2241 justify-content: space-between;
2242 align-items: center;
2243
2244 position: sticky;
2245 top: 0;
2246 right: 0;
2247 left: 0;
2248
2249 background: rgba(var(--color-snow), 0.80);
2250 backdrop-filter: blur(8px);
2251 z-index: 2;
2252}
2253
2254.DLP_AutoServer_Scroll_Box {
2255 display: flex;
2256 padding: 0 16px 16px 16px;
2257 flex-direction: column;
2258 justify-content: center;
2259 align-items: center;
2260 gap: 8px;
2261 align-self: stretch;
2262}
2263
2264.DLP_AutoServer_Default_Box {
2265 display: flex;
2266 padding: 16px;
2267 justify-content: center;
2268 align-items: center;
2269 gap: 16px;
2270 align-self: stretch;
2271
2272 border-radius: 8px;
2273 outline: 2px solid rgba(0, 0, 0, 0.10);
2274 outline-offset: -2px;
2275}
2276`;
2277
2278HTML6 = `
2279<div class="DPAutoServerButtonMainMenu">
2280 <svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
2281 <g clip-path="url(#clip0_952_270)">
2282 <rect width="30" height="30" rx="15" fill="rgb(var(--DLP-blue))"/>
2283 <path d="M19.9424 20.5947H10.4404C7.96582 20.5947 6.04492 18.7764 6.04492 16.582C6.04492 14.8115 7.02246 13.3623 8.61523 13.0342C8.73145 11.0859 10.5361 9.77344 12.3545 10.1904C13.2773 8.88477 14.7061 8.02344 16.4766 8.02344C19.4502 8.02344 21.7334 10.2998 21.7402 13.458C23.1279 14.0322 23.9551 15.3926 23.9551 16.876C23.9551 18.9404 22.1777 20.5947 19.9424 20.5947ZM10.6318 16.1445C10.2285 16.6504 10.6934 17.1904 11.2539 16.9102L13.4688 15.7549L16.1006 17.2109C16.2578 17.2998 16.4082 17.3477 16.5586 17.3477C16.7705 17.3477 16.9688 17.2383 17.1465 17.0195L19.3818 14.1963C19.7646 13.7109 19.3203 13.1641 18.7598 13.4443L16.5312 14.5928L13.9062 13.1436C13.7422 13.0547 13.5986 13.0068 13.4414 13.0068C13.2363 13.0068 13.0381 13.1094 12.8535 13.335L10.6318 16.1445Z" fill="white"/>
2284 </g>
2285 <defs>
2286 <clipPath id="clip0_952_270">
2287 <rect width="30" height="30" rx="15" fill="#FFF"/>
2288 </clipPath>
2289 </defs>
2290 </svg>
2291 <p class="DPAutoServerElementsMenu DLP_NoSelect" style="flex: 1 0 0; color: rgb(var(--DLP-blue)); font-size: 16px; font-style: normal; font-weight: 700; line-height: normal; margin: 0px;">AUTOSERVER</p>
2292 <svg class="DPAutoServerElementsMenu" style="opacity: 0;" width="9" height="16" viewBox="0 0 9 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2293 <path d="M8.57031 7.85938C8.57031 8.24219 8.4375 8.5625 8.10938 8.875L2.20312 14.6641C1.96875 14.8984 1.67969 15.0156 1.33594 15.0156C0.648438 15.0156 0.0859375 14.4609 0.0859375 13.7734C0.0859375 13.4219 0.226562 13.1094 0.484375 12.8516L5.63281 7.85156L0.484375 2.85938C0.226562 2.60938 0.0859375 2.28906 0.0859375 1.94531C0.0859375 1.26562 0.648438 0.703125 1.33594 0.703125C1.67969 0.703125 1.96875 0.820312 2.20312 1.05469L8.10938 6.84375C8.42969 7.14844 8.57031 7.46875 8.57031 7.85938Z" fill="rgb(var(--DLP-blue))"/>
2294 </svg>
2295</div>
2296`;
2297CSS6 = `
2298.DPAutoServerButtonMainMenu {
2299 display: flex;
2300 box-sizing: border-box;
2301 justify-content: center;
2302 align-items: center;
2303 gap: 16px;
2304 flex-shrink: 0;
2305
2306 border-radius: 12px;
2307
2308 cursor: pointer;
2309}
2310.DPAutoServerButtonMainMenu:hover {
2311 background: rgba(var(--DLP-blue), 0.10);
2312}
2313.DPAutoServerButtonMainMenu:active {
2314 filter: brightness(.9);
2315
2316}
2317
2318.DPAutoServerButtonMainMenu:hover .DPAutoServerElementsMenu {
2319 opacity: 1 !important;
2320}
2321
2322.DPAutoServerButtonMainMenuMedium {
2323 width: 56px;
2324 height: 52px;
2325 padding: 8px;
2326}
2327
2328.DPAutoServerButtonMainMenuLarge {
2329 width: 222px;
2330 height: 52px;
2331 padding: 16px 17px;
2332}
2333`;
2334HTML7 = `
2335<div id="DLP_The_Bar_Thing_Box" class="DuolingoProCounterBoxOneClass" style="display: inline-flex; justify-content: center; flex-direction: row-reverse; align-items: center; gap: 4px;">
2336 <div class="vCIrKKxykXwXyUza DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Inset_Button_1_ID">
2337 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: rgb(var(--color-eel)); display: none;"></p>
2338 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID"></p>
2339 </div>
2340 <div class="vCIrKKxykXwXyUza DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Inset_Button_2_ID">
2341 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: rgb(var(--color-eel));"></p>
2342 <p class="DLP_Text_Style_1 DLP_Inset_Text_1_ID">Mute</p>
2343 </div>
2344 <div class="vCIrKKxykXwXyUza DLP_Magnetic_Hover_1 DLP_NoSelect DLP_Inset_Button_3_ID" style="width: 40px; padding: 0;">
2345 <p class="DLP_Text_Style_1 DLP_Inset_Icon_1_ID" style="color: rgb(var(--color-eel)); transition: all 0.8s cubic-bezier(0.16, 1, 0.32, 1);"></p>
2346 </div>
2347</div>
2348`;
2349CSS7 = `
2350.vCIrKKxykXwXyUza {
2351 outline: 2px solid rgb(var(--color-swan));
2352 outline-offset: -2px;
2353 height: 40px;
2354 width: auto;
2355 padding: 0 16px;
2356 gap: 6px;
2357 display: inline-flex;
2358 justify-content: center;
2359 align-items: center;
2360 flex-wrap: nowrap;
2361 flex-shrink: 0;
2362
2363 border-radius: 32px;
2364 background: rgb(var(--color-snow), 0.84);
2365 backdrop-filter: blur(16px);
2366 overflow: hidden;
2367
2368 transition: all 0.4s cubic-bezier(0.16, 1, 0.32, 1);
2369 cursor: pointer;
2370}
2371.vCIrKKxykXwXyUza p {
2372 white-space: nowrap;
2373}
2374.vCIrKKxykXwXyUza svg {
2375 flex-shrink: 0;
2376}
2377`;
2378}
2379
2380function One() {
2381 Two();
2382
2383 document.head.appendChild(Object.assign(document.createElement('style'), { type: 'text/css', textContent: CSS1 }));
2384 document.body.insertAdjacentHTML('beforeend', HTML2);
2385 document.head.appendChild(Object.assign(document.createElement('style'), { type: 'text/css', textContent: CSS2 }));
2386
2387 document.body.insertAdjacentHTML('beforeend', HTML5);
2388 document.head.appendChild(Object.assign(document.createElement('style'), { type: 'text/css', textContent: CSS5 }));
2389
2390 let DPAutoServerButtonMainMenuElement = null;
2391 let DPAutoServerButtonMainMenuStyle = null;
2392
2393 function DPAutoServerButtonMainMenuFunction() {
2394 try {
2395 if (storageLocal.settings.showAutoServerButton && alpha) {
2396 let targetElement = document.querySelector('._2uLXp');
2397 if (!targetElement || document.querySelector('.DPAutoServerButtonMainMenu')) return;
2398
2399 DPAutoServerButtonMainMenuStyle = document.createElement('style');
2400 DPAutoServerButtonMainMenuStyle.type = 'text/css';
2401 DPAutoServerButtonMainMenuStyle.innerHTML = CSS6;
2402 document.head.appendChild(DPAutoServerButtonMainMenuStyle);
2403
2404 let targetDivLast = document.querySelector('[data-test="profile-tab"]');
2405
2406 if (targetElement && targetDivLast) {
2407 targetElement.lastChild.insertAdjacentHTML('beforebegin', HTML6);
2408
2409 let otherTargetDiv = document.querySelector('.DPAutoServerButtonMainMenu');
2410 otherTargetDiv.addEventListener('click', () => {
2411 manageAutoServerWindowVisibility(true);
2412 });
2413
2414 let lastWidth = targetElement.offsetWidth;
2415 const resizeObserver = new ResizeObserver(entries => {
2416 for (let entry of entries) {
2417 if (entry.target.offsetWidth !== lastWidth) {
2418 otherTargetDiv.remove();
2419 DPAutoServerButtonMainMenuFunction();
2420 lastWidth = entry.target.offsetWidth;
2421 }
2422 }
2423 });
2424 resizeObserver.observe(targetElement);
2425
2426 if (targetElement.offsetWidth < 100) {
2427 otherTargetDiv.classList.add('DPAutoServerButtonMainMenuMedium');
2428 document.querySelectorAll('.DPAutoServerElementsMenu').forEach(function(element) {
2429 element.remove();
2430 });
2431 } else {
2432 otherTargetDiv.classList.add('DPAutoServerButtonMainMenuLarge');
2433 }
2434 }
2435 }
2436 } catch(error) {}
2437 }
2438 setInterval(DPAutoServerButtonMainMenuFunction, 500);
2439
2440 document.querySelector('.DLP_AutoServer_Mother_Box').querySelector('#DLP_AutoServer_Close_Button_1_ID').addEventListener('click', () => {
2441 manageAutoServerWindowVisibility(false);
2442 });
2443 document.querySelector('.DLP_AutoServer_Mother_Box').addEventListener('click', (event) => {
2444 if (event.target === event.currentTarget) {
2445 manageAutoServerWindowVisibility(false);
2446 }
2447 });
2448 function manageAutoServerWindowVisibility(state) {
2449 if (state) {
2450 document.querySelector('.DLP_AutoServer_Mother_Box').style.display = "";
2451 document.querySelector('.DLP_AutoServer_Mother_Box').offsetHeight;
2452 document.querySelector('.DLP_AutoServer_Mother_Box').style.opacity = "1";
2453 document.querySelector('.DLP_AutoServer_Mother_Box').style.filter = "blur(0px)";
2454 } else {
2455 document.querySelector('.DLP_AutoServer_Mother_Box').style.opacity = "0";
2456 document.querySelector('.DLP_AutoServer_Mother_Box').style.filter = "blur(8px)";
2457 setTimeout(() => {
2458 document.querySelector('.DLP_AutoServer_Mother_Box').style.display = "none";
2459 }, 400);
2460 }
2461 }
2462
2463 let counterPaused = false;
2464 function DuolingoProCounterOneFunction() {
2465 function handleMuteTab(value) {
2466 if (isBusySwitchingPages) return;
2467 isBusySwitchingPages = true;
2468 muteTab(value);
2469 let button = document.querySelector('#DLP_Inset_Button_2_ID');
2470 if (value) {
2471 setButtonState(button, {button: 'rgb(var(--color-snow), 0.84)', outline: 'rgb(var(--color-swan))', text: 'rgb(var(--color-black-text))', icon: 'rgb(var(--color-black-text))'}, {text: 'Muted', icon: ''}, {text: '', icon: ' '}, () => {
2472 setTimeout(() => {
2473 isBusySwitchingPages = false;
2474 }, 400);
2475 });
2476 } else {
2477 setButtonState(button, {button: 'rgb(var(--color-snow), 0.84)', outline: 'rgb(var(--color-swan))', text: 'rgb(var(--color-black-text))', icon: 'rgb(var(--color-black-text))'}, {text: 'Mute', icon: ''}, {text: '', icon: ' '}, () => {
2478 setTimeout(() => {
2479 isBusySwitchingPages = false;
2480 }, 400);
2481 });
2482 }
2483 }
2484
2485 if ((window.location.pathname.includes('/lesson') || window.location.pathname.includes('/practice')) && storageSession.legacy.status) {
2486 let theBarThing = document.querySelector('#DLP_The_Bar_Thing_Box');
2487 if (!theBarThing) {
2488 document.head.appendChild(Object.assign(document.createElement('style'), { type: 'text/css', textContent: CSS7 }));
2489 //const targetElement1 = document.querySelector('.I-Avc._1zcW8');
2490 const targetElement1 = document.querySelector('._1zcW8');
2491 const targetElement2 = document.querySelector('.mAxZF');
2492 if (targetElement1) {
2493 targetElement1.insertAdjacentHTML('beforeend', HTML7);
2494 theBarThing = document.querySelector('#DLP_The_Bar_Thing_Box');
2495 targetElement1.style.display = "flex";
2496 document.querySelector('[role="progressbar"]').style.width = "100%";
2497 } else if (targetElement2) {
2498 targetElement2.insertAdjacentHTML('beforeend', HTML7);
2499 theBarThing = document.querySelector('#DLP_The_Bar_Thing_Box');
2500 theBarThing.style.marginLeft = '24px';
2501 document.querySelector('._15ch1').style.pointerEvents = 'all';
2502 }
2503 else if (debug) console.log('Element with class ._1zcW8 or .mAxZF not found');
2504
2505 let muteButton = theBarThing.querySelector('.DLP_Inset_Button_2_ID');
2506 let expandButton = theBarThing.querySelector('.DLP_Inset_Button_3_ID');
2507 let expandButtonIcon = expandButton.querySelector('.DLP_Inset_Icon_1_ID');
2508 let theBarThingExtended = false;
2509 function theBarThingExtend(button, visibility, noAnimation) {
2510 if (visibility) {
2511 button.style.display = "";
2512 button.style.width = "";
2513 button.style.padding = "";
2514 button.style.transition = '';
2515 let remember0010 = button.offsetWidth;
2516 button.style.width = "0px";
2517 requestAnimationFrame(() => {
2518 button.style.width = remember0010 + "px";
2519 button.style.padding = "";
2520 button.style.filter = "blur(0px)";
2521 button.style.opacity = "1";
2522 button.style.margin = "";
2523 });
2524 } else {
2525 button.style.transition = '';
2526 button.style.width = button.offsetWidth + "px";
2527 requestAnimationFrame(() => {
2528 button.style.width = "4px";
2529 button.style.padding = "0";
2530 button.style.filter = "blur(8px)";
2531 button.style.margin = "0 -4px";
2532 button.style.opacity = "0";
2533 });
2534 if (!noAnimation) {
2535 setTimeout(function() {
2536 button.style.display = "none";
2537 }, 400);
2538 } else {
2539 button.style.display = "none";
2540 }
2541 }
2542 }
2543 theBarThingExtend(muteButton, false, true);
2544 expandButton.addEventListener('click', () => {
2545 if (theBarThingExtended) {
2546 expandButtonIcon.style.transform = "rotate(0deg)";
2547 theBarThingExtended = false;
2548 theBarThingExtend(muteButton, false);
2549 } else {
2550 expandButtonIcon.style.transform = "rotate(180deg)";
2551 theBarThingExtended = true;
2552 theBarThingExtend(muteButton, true);
2553 }
2554 });
2555
2556 let counterButton = theBarThing.querySelector('.DLP_Inset_Button_1_ID');
2557 counterButton.addEventListener('click', () => {
2558 if (isBusySwitchingPages) return;
2559 isBusySwitchingPages = true;
2560 if (theBarThing.querySelector('#DLP_Inset_Button_1_ID').querySelector('#DLP_Inset_Text_1_ID').innerHTML === 'Click Again to Stop Legacy') {
2561 setButtonState(counterButton, {button: 'rgb(var(--color-snow), 0.84)', outline: 'rgb(var(--color-swan))', text: 'rgb(var(--color-black-text))', icon: 'rgb(var(--color-black-text))'}, {text: 'Stopping', icon: undefined}, {text: '', icon: ''}, () => {
2562 storageSession.legacy.status = false;
2563 saveStorageSession();
2564 setTimeout(() => {
2565 isBusySwitchingPages = false;
2566 window.location.href = "https://duolingo.com";
2567 }, 400);
2568 });
2569 } else {
2570 counterPaused = true;
2571 setButtonState(counterButton, {button: 'rgb(var(--color-snow), 0.84)', outline: 'rgb(var(--color-swan))', text: 'rgb(var(--color-black-text))', icon: 'rgb(var(--color-black-text))'}, {text: 'Click Again to Stop', icon: undefined}, {text: '', icon: ''}, () => {
2572 setTimeout(() => {
2573 isBusySwitchingPages = false;
2574 setTimeout(() => {
2575 if (storageSession.legacy.status) counterPaused = false;
2576 }, 4000);
2577 }, 400);
2578 });
2579 }
2580 });
2581
2582 if (storageLocal.settings.muteLessons) {
2583 handleMuteTab(true);
2584 }
2585
2586 document.querySelector('#DLP_Inset_Button_2_ID').addEventListener('click', () => {
2587 storageLocal.settings.muteLessons = !storageLocal.settings.muteLessons;
2588 saveStorageLocal();
2589 handleMuteTab(storageLocal.settings.muteLessons);
2590 });
2591 }
2592
2593 function updateCounter() {
2594 let button = theBarThing.querySelector('.DLP_Inset_Button_1_ID');
2595 let text = button.querySelector('.DLP_Inset_Text_1_ID');
2596
2597 if (storageSession.legacy[storageSession.legacy.status].type === 'infinity' && text.textContent !== 'Infinity') {
2598 isBusySwitchingPages = true;
2599 setButtonState(button, {button: 'rgb(var(--color-snow), 0.84)', outline: 'rgb(var(--color-swan))', text: 'rgb(var(--color-black-text))', icon: 'rgb(var(--color-black-text))'}, {text: 'Infinity', icon: ''}, {text: '', icon: ''}, () => {
2600 setTimeout(() => {
2601 isBusySwitchingPages = false;
2602 }, 400);
2603 });
2604 } else if (storageSession.legacy[storageSession.legacy.status].type === 'xp' && text.textContent !== String(storageSession.legacy[storageSession.legacy.status].amount + ' XP Left')) {
2605 isBusySwitchingPages = true;
2606 setButtonState(button, {button: 'rgb(var(--color-snow), 0.84)', outline: 'rgb(var(--color-swan))', text: 'rgb(var(--color-black-text))', icon: 'rgb(var(--color-black-text))'}, {text: String(storageSession.legacy[storageSession.legacy.status].amount + ' XP Left'), icon: ''}, {text: '', icon: ''}, () => {
2607 setTimeout(() => {
2608 isBusySwitchingPages = false;
2609 }, 400);
2610 });
2611 } else if (window.location.pathname === '/practice') {
2612 if (storageSession.legacy[storageSession.legacy.status].amount === 1 && text.textContent !== 'Last Practice') {
2613 isBusySwitchingPages = true;
2614 setButtonState(button, {button: 'rgb(var(--color-snow), 0.84)', outline: 'rgb(var(--color-swan))', text: 'rgb(var(--color-black-text))', icon: 'rgb(var(--color-black-text))'}, {text: 'Last Practice', icon: ''}, {text: '', icon: ''}, () => {
2615 setTimeout(() => {
2616 isBusySwitchingPages = false;
2617 }, 400);
2618 });
2619 } else if (storageSession.legacy[storageSession.legacy.status].amount === 0 && text.textContent !== 'Finishing Up') {
2620 isBusySwitchingPages = true;
2621 setButtonState(button, {button: 'rgb(var(--color-snow), 0.84)', outline: 'rgb(var(--color-swan))', text: 'rgb(var(--color-black-text))', icon: 'rgb(var(--color-black-text))'}, {text: 'Finishing Up', icon: ''}, {text: '', icon: ''}, () => {
2622 setTimeout(() => {
2623 isBusySwitchingPages = false;
2624 }, 400);
2625 });
2626 } else if (storageSession.legacy[storageSession.legacy.status].amount > 1 && text.textContent !== String(storageSession.legacy[storageSession.legacy.status].amount + ' Practices Left')) {
2627 isBusySwitchingPages = true;
2628 setButtonState(button, {button: 'rgb(var(--color-snow), 0.84)', outline: 'rgb(var(--color-swan))', text: 'rgb(var(--color-black-text))', icon: 'rgb(var(--color-black-text))'}, {text: String(storageSession.legacy[storageSession.legacy.status].amount + ' Practices Left'), icon: ''}, {text: '', icon: ''}, () => {
2629 setTimeout(() => {
2630 isBusySwitchingPages = false;
2631 }, 400);
2632 });
2633 }
2634 } else if (storageSession.legacy[storageSession.legacy.status].type === 'lesson') {
2635 if (storageSession.legacy[storageSession.legacy.status].amount === 1 && text.textContent !== 'Last Lesson') {
2636 isBusySwitchingPages = true;
2637 setButtonState(button, {button: 'rgb(var(--color-snow), 0.84)', outline: 'rgb(var(--color-swan))', text: 'rgb(var(--color-black-text))', icon: 'rgb(var(--color-black-text))'}, {text: 'Last Lesson', icon: ''}, {text: '', icon: ''}, () => {
2638 setTimeout(() => {
2639 isBusySwitchingPages = false;
2640 }, 400);
2641 });
2642 } else if (storageSession.legacy[storageSession.legacy.status].amount === 0 && text.textContent !== 'Finishing Up') {
2643 isBusySwitchingPages = true;
2644 setButtonState(button, {button: 'rgb(var(--color-snow), 0.84)', outline: 'rgb(var(--color-swan))', text: 'rgb(var(--color-black-text))', icon: 'rgb(var(--color-black-text))'}, {text: 'Finishing Up', icon: ''}, {text: '', icon: ''}, () => {
2645 setTimeout(() => {
2646 isBusySwitchingPages = false;
2647 }, 400);
2648 });
2649 } else if (storageSession.legacy[storageSession.legacy.status].amount > 1 && text.textContent !== String(storageSession.legacy[storageSession.legacy.status].amount + ' Lessons Left')) {
2650 isBusySwitchingPages = true;
2651 setButtonState(button, {button: 'rgb(var(--color-snow), 0.84)', outline: 'rgb(var(--color-swan))', text: 'rgb(var(--color-black-text))', icon: 'rgb(var(--color-black-text))'}, {text: String(storageSession.legacy[storageSession.legacy.status].amount + ' Lessons Left'), icon: ''}, {text: '', icon: ''}, () => {
2652 setTimeout(() => {
2653 isBusySwitchingPages = false;
2654 }, 400);
2655 });
2656 }
2657 }
2658 }
2659
2660 if (!counterPaused) updateCounter();
2661 }
2662 }
2663 setInterval(DuolingoProCounterOneFunction, 500);
2664
2665
2666 window.onfocus = () => {
2667 windowBlurState = true;
2668 };
2669 window.onblur = () => {
2670 windowBlurState = false;
2671 };
2672
2673 function addButtons() {
2674 if (!storageLocal.settings.showSolveButtons) return;
2675 if (window.location.pathname === '/learn' && document.querySelector('a[data-test="global-practice"]')) return;
2676 if (document.querySelector("#solveAllButton")) return;
2677
2678 document.querySelector('[data-test="quit-button"]')?.addEventListener('click', function() {
2679 solving("stop");
2680 //storageSession.legacy.status = false;
2681 //saveStorageSession();
2682 });
2683
2684 function createButton(id, text, styleClass, eventHandlers) {
2685 const button = document.createElement('button');
2686 button.id = id;
2687 button.innerText = text;
2688 button.className = styleClass;
2689 Object.keys(eventHandlers).forEach(event => {
2690 button.addEventListener(event, eventHandlers[event]);
2691 });
2692 return button;
2693 }
2694
2695 const nextButton = document.querySelector('[data-test="player-next"]');
2696 const storiesContinueButton = document.querySelector('[data-test="stories-player-continue"]');
2697 const storiesDoneButton = document.querySelector('[data-test="stories-player-done"]');
2698 const target = nextButton || storiesContinueButton || storiesDoneButton;
2699
2700 if (document.querySelector('[data-test="story-start"]') && storageSession.legacy.status) {
2701 document.querySelector('[data-test="story-start"]').click();
2702 }
2703 if (!target) {
2704 const startButton = document.querySelector('[data-test="start-button"]');
2705 if (!startButton) {
2706 return;
2707 }
2708 const solveAllButton = createButton("solveAllButton", "COMPLETE SKILL", "solve-all-btn", {
2709 'click': () => {
2710 solving(true);
2711 setInterval(() => {
2712 const startButton = document.querySelector('[data-test="start-button"]');
2713 if (startButton && startButton.innerText.startsWith("START")) {
2714 startButton.click();
2715 }
2716 }, 1000);
2717 startButton.click();
2718 }
2719 });
2720 startButton.parentNode.appendChild(solveAllButton);
2721 } else {
2722 if (document.querySelector('.MYehf') !== null) {
2723 document.querySelector('.MYehf').style.display = "flex";
2724 document.querySelector('.MYehf').style.gap = "20px";
2725 } else if (document.querySelector(".FmlUF") !== null) { // Story
2726 findReactMainElementClass = '_3TJzR';
2727 reactTraverseUp = 0;
2728 document.querySelector('._3TJzR').style.display = "flex";
2729 document.querySelector('._3TJzR').style.gap = "20px";
2730 }
2731
2732 const buttonsCSS = document.createElement('style');
2733 buttonsCSS.innerHTML = HTML4;
2734 document.head.appendChild(buttonsCSS);
2735
2736 const solveCopy = createButton('solveAllButton', systemText[systemLanguage][101], 'auto-solver-btn solving-btn', { click: solving });
2737 const pauseCopy = createButton('', systemText[systemLanguage][100], 'auto-solver-btn solve-btn', { click: solve });
2738
2739 target.parentElement.appendChild(pauseCopy);
2740 target.parentElement.appendChild(solveCopy);
2741
2742 if (storageSession.legacy.status) {
2743 solving("start");
2744 }
2745 }
2746 }
2747 setInterval(addButtons, 500);
2748
2749
2750
2751 let notificationCount = 0;
2752 let currentNotification = [];
2753 let notificationsHovered = false;
2754
2755 const notificationMain = document.querySelector('.DLP_Notification_Main');
2756 notificationMain.addEventListener('mouseenter', () => {
2757 notificationsHovered = true;
2758 });
2759 notificationMain.addEventListener('mouseleave', () => {
2760 notificationsHovered = false;
2761 });
2762
2763 function showNotification(icon, head, body, time = 0) {
2764 notificationCount++;
2765 let notificationID = notificationCount;
2766 currentNotification.push(notificationID);
2767
2768 let element = new DOMParser().parseFromString(HTML3, 'text/html').body.firstChild;
2769 element.id = 'DLP_Notification_Box_' + notificationID + '_ID';
2770 notificationMain.appendChild(element);
2771 initializeMagneticHover(element.querySelector('.DLP_Inset_Icon_2_ID'));
2772
2773 let iconElement = element.querySelector('.DLP_Inset_Icon_1_ID');
2774 if (icon === "") {
2775 iconElement.style.display = 'none';
2776 playHaptic();
2777 } else if (icon === "checkmark") {
2778 iconElement.style.color = "rgb(var(--DLP-green))";
2779 iconElement.textContent = "";
2780 playHaptic("success");
2781 } else if (icon === "warning") {
2782 iconElement.style.color = "rgb(var(--DLP-orange))";
2783 iconElement.textContent = "";
2784 playHaptic("warning");
2785 } else if (icon === "error") {
2786 iconElement.style.color = "rgb(var(--DLP-pink))";
2787 iconElement.textContent = "";
2788 playHaptic("error");
2789 } else {
2790 iconElement.style.color = icon.color;
2791 iconElement.textContent = icon.icon;
2792 playHaptic();
2793 }
2794
2795 element.querySelector('.DLP_Inset_Text_1_ID').innerHTML = head;
2796 if (body && body !== "") {
2797 element.querySelector('.DLP_Inset_Text_2_ID').innerHTML = body;
2798 } else {
2799 element.querySelector('.DLP_Inset_Text_2_ID').style.display = "none";
2800 }
2801
2802 let notification = document.querySelector(
2803 '#DLP_Notification_Box_' + notificationID + '_ID'
2804 );
2805 let notificationHeight = notification.offsetHeight;
2806 notification.style.bottom = '-' + notificationHeight + 'px';
2807
2808 setTimeout(() => {
2809 requestAnimationFrame(() => {
2810 notification.style.bottom = "16px";
2811 notification.style.filter = "blur(0px)";
2812 notification.style.opacity = "1";
2813 });
2814 }, 50);
2815
2816 let isBusyDisappearing = false;
2817
2818 let timerData = null;
2819 if (time !== 0) {
2820 timerData = {
2821 remaining: time * 1000,
2822 lastTimestamp: Date.now(),
2823 timeoutHandle: null,
2824 paused: false,
2825 };
2826 timerData.timeoutHandle = setTimeout(internalDisappear, timerData.remaining);
2827 }
2828
2829 let repeatInterval = setInterval(() => {
2830 if (document.body.offsetWidth <= 963) {
2831 requestAnimationFrame(() => {
2832 notificationMain.style.width = "300px";
2833 notificationMain.style.position = "fixed";
2834 notificationMain.style.left = "16px";
2835 });
2836 } else {
2837 requestAnimationFrame(() => {
2838 notificationMain.style.width = "";
2839 notificationMain.style.position = "";
2840 notificationMain.style.left = "";
2841 });
2842 }
2843
2844 if (isBusyDisappearing) return;
2845
2846 if (timerData) {
2847 if (notificationsHovered && !timerData.paused) {
2848 clearTimeout(timerData.timeoutHandle);
2849 let elapsed = Date.now() - timerData.lastTimestamp;
2850 timerData.remaining -= elapsed;
2851 timerData.paused = true;
2852 }
2853 if (!notificationsHovered && timerData.paused) {
2854 timerData.paused = false;
2855 timerData.lastTimestamp = Date.now();
2856 timerData.timeoutHandle = setTimeout(internalDisappear, timerData.remaining);
2857 }
2858 }
2859
2860 if (notificationsHovered) {
2861 let allIDs = currentNotification.slice();
2862 let bottoms = {};
2863 let currentBottom = 16;
2864 for (let i = allIDs.length - 1; i >= 0; i--) {
2865 let notifEl = document.querySelector(
2866 '#DLP_Notification_Box_' + allIDs[i] + '_ID'
2867 );
2868 if (!notifEl) continue;
2869 notifEl.style.width = "";
2870 notifEl.style.height = "";
2871 notifEl.style.transform = "";
2872 bottoms[allIDs[i]] = currentBottom;
2873 currentBottom += notifEl.offsetHeight + 8;
2874 }
2875 notification.style.bottom = bottoms[notificationID] + "px";
2876
2877 let totalHeight = 0;
2878 for (let i = 0; i < allIDs.length; i++) {
2879 let notifEl = document.querySelector(
2880 '#DLP_Notification_Box_' + allIDs[i] + '_ID'
2881 );
2882 if (notifEl) {
2883 totalHeight += notifEl.offsetHeight;
2884 }
2885 }
2886 if (allIDs.length > 1) {
2887 totalHeight += (allIDs.length - 1) * 8;
2888 }
2889 notificationMain.style.height = totalHeight + "px";
2890 } else {
2891 notificationMain.style.height = '';
2892 notification.style.bottom = "16px";
2893 if (currentNotification[currentNotification.length - 1] !== notificationID) {
2894 notification.style.height = notificationHeight + 'px';
2895 requestAnimationFrame(() => {
2896 let latestNotif = document.querySelector(
2897 '#DLP_Notification_Box_' +
2898 String(currentNotification[currentNotification.length - 1]) +
2899 '_ID'
2900 );
2901 if (latestNotif) {
2902 notification.style.height = latestNotif.offsetHeight + 'px';
2903 }
2904 notification.style.width = "284px";
2905 notification.style.transform = "translateY(-8px)";
2906 });
2907 } else {
2908 requestAnimationFrame(() => {
2909 notification.style.height = notificationHeight + "px";
2910 notification.style.width = "";
2911 notification.style.transform = "";
2912 });
2913 }
2914 }
2915 }, 20);
2916
2917 function internalDisappear() {
2918 if (timerData && timerData.timeoutHandle) {
2919 clearTimeout(timerData.timeoutHandle);
2920 }
2921 if (isBusyDisappearing) return;
2922 isBusyDisappearing = true;
2923 currentNotification.splice(currentNotification.indexOf(notificationID), 1);
2924
2925 requestAnimationFrame(() => {
2926 notification.style.bottom = "-" + notificationHeight + "px";
2927 notification.style.filter = "blur(16px)";
2928 notification.style.opacity = "0";
2929 });
2930 clearInterval(repeatInterval);
2931 setTimeout(() => {
2932 notification.remove();
2933 if (currentNotification.length === 0) {
2934 notificationMain.style.height = '';
2935 }
2936 }, 800);
2937 }
2938
2939 function disappear() {
2940 internalDisappear();
2941 }
2942
2943 notification.querySelector('.DLP_Inset_Icon_2_ID').addEventListener("click", disappear);
2944
2945 return {
2946 close: disappear
2947 };
2948 }
2949
2950
2951 let isBusySwitchingPages = false;
2952 let pages = {
2953 "DLP_Onboarding_Start_Button_1_ID": [5],
2954 "DLP_Switch_Legacy_Button_1_ID": [3],
2955
2956 "DLP_Universal_Back_1_Button_1_ID": [1],
2957
2958 "DLP_Main_Settings_1_Button_1_ID": [7],
2959 //"DLP_Main_Feedback_1_Button_1_ID": [8],
2960
2961 "DLP_Main_Feedback_1_Button_1_ID": [11],
2962
2963 "DLP_Main_Whats_New_1_Button_1_ID": [9],
2964 "DLP_Main_See_More_1_Button_1_ID": [2],
2965 "DLP_Main_Terms_1_Button_1_ID": [5],
2966
2967 "DLP_Secondary_Settings_1_Button_1_ID": [7],
2968 "DLP_Secondary_Feedback_1_Button_1_ID": [8],
2969 "DLP_Secondary_Whats_New_1_Button_1_ID": [9],
2970 "DLP_Secondary_See_More_1_Button_1_ID": [4],
2971 "DLP_Secondary_Terms_1_Button_1_ID": [5],
2972
2973 "DLP_Terms_Back_Button_1_ID": [1],
2974 "DLP_Terms_Accept_Button_1_ID": [1],
2975 "DLP_Terms_Decline_Button_1_ID": [6],
2976 "DLP_Terms_Declined_Back_Button_1_ID": [5]
2977 };
2978 function goToPage(to, buttonID) {
2979 if (isBusySwitchingPages) return;
2980 isBusySwitchingPages = true;
2981
2982 let mainBox = document.querySelector(`.DLP_Main_Box`);
2983 let toNumber = to;
2984 let fromPage = document.querySelector(`#DLP_Main_Box_Divider_${currentPage}_ID`);
2985 let toPage = document.querySelector(`#DLP_Main_Box_Divider_${toNumber}_ID`);
2986
2987 let mainBoxNewToBeWidth = mainBox.offsetWidth;
2988
2989 if (buttonID === 'DLP_Main_Terms_1_Button_1_ID' || buttonID === 'DLP_Secondary_Terms_1_Button_1_ID') {
2990 document.querySelector(`#DLP_Terms_1_Text_1_ID`).style.display = 'none';
2991 document.querySelector(`#DLP_Terms_1_Button_1_ID`).style.display = 'none';
2992 document.querySelector(`#DLP_Terms_1_Text_2_ID`).style.display = 'block';
2993 document.querySelector(`#DLP_Terms_1_Button_2_ID`).style.display = 'block';
2994 } else if (buttonID === 'DLP_Terms_Back_Button_1_ID') {
2995 toNumber = lastPage;
2996 toPage = document.querySelector(`#DLP_Main_Box_Divider_${toNumber}_ID`);
2997 setTimeout(() => {
2998 document.querySelector(`#DLP_Terms_1_Text_1_ID`).style.display = 'block';
2999 document.querySelector(`#DLP_Terms_1_Button_1_ID`).style.display = 'block';
3000 document.querySelector(`#DLP_Terms_1_Text_2_ID`).style.display = 'none';
3001 document.querySelector(`#DLP_Terms_1_Button_2_ID`).style.display = 'none';
3002 }, 400);
3003 } else if (buttonID === 'DLP_Universal_Back_1_Button_1_ID' || to === -1) {
3004 toNumber = lastPage;
3005 toPage = document.querySelector(`#DLP_Main_Box_Divider_${toNumber}_ID`);
3006 } else if (buttonID === 'DLP_Switch_Legacy_Button_1_ID') {
3007 let button = document.querySelector('#DLP_Switch_Legacy_Button_1_ID');
3008 console.log(storageSession.legacy.page);
3009 if (storageSession.legacy.page !== 0) {
3010 toNumber = 1;
3011 toPage = document.querySelector(`#DLP_Main_Box_Divider_${toNumber}_ID`);
3012 setButtonState(button, {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][106], icon: ''}, {text: '', icon: ''});
3013 storageSession.legacy.page = 0;
3014 saveStorageSession();
3015 } else {
3016 toNumber = 3;
3017 toPage = document.querySelector(`#DLP_Main_Box_Divider_${toNumber}_ID`);
3018 setButtonState(button, {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][105], icon: ''}, {text: '', icon: ''});
3019 storageSession.legacy.page = 1;
3020 saveStorageSession();
3021 }
3022 } else if (buttonID === 'DLP_Terms_Accept_Button_1_ID') {
3023 storageLocal.terms = newTermID;
3024 saveStorageLocal();
3025 connectToServer();
3026 } else if (buttonID === 'DLP_Onboarding_Start_Button_1_ID') {
3027 storageLocal.onboarding = true;
3028 saveStorageLocal();
3029 goToPage(1);
3030 } else if (buttonID === 'DLP_Main_Feedback_1_Button_1_ID') {
3031 setTimeout(() => {
3032 const chatBox = document.querySelector('#DLP_Main_Box_Divider_11_ID')?.querySelector('.DLP_Chat_Box_1_ID_1');
3033 chatBox.scrollTop = chatBox.scrollHeight;
3034 }, 420);
3035 } else if (toNumber === 7) {
3036 const trackingSinceDateString = new Date(storageLocal.stats.tracking_since).toLocaleDateString(systemLanguage, { month: 'short', day: 'numeric', year: 'numeric' });
3037
3038 let modernStatsBox = document.querySelector('#DLP_Main_Box_Divider_7_ID').querySelector('#DLP_Settings_Modern_Stats_Main_Box_1_ID');
3039 modernStatsBox.children[0].lastElementChild.innerHTML = "since " + trackingSinceDateString;
3040 modernStatsBox.children[1].lastElementChild.innerHTML = storageLocal.stats.modern.xp;
3041 modernStatsBox.children[2].lastElementChild.innerHTML = storageLocal.stats.modern.gem;
3042 modernStatsBox.children[3].lastElementChild.innerHTML = storageLocal.stats.modern.streak;
3043 modernStatsBox.children[4].lastElementChild.innerHTML = storageLocal.stats.modern.heart_refill;
3044
3045 let legacyStatsBox = document.querySelector('#DLP_Main_Box_Divider_7_ID').querySelector('#DLP_Settings_Legacy_Stats_Main_Box_1_ID');
3046 legacyStatsBox.children[0].lastElementChild.innerHTML = "since " + trackingSinceDateString;
3047 legacyStatsBox.children[1].lastElementChild.innerHTML = (storageLocal.stats.legacy.listen.lessons + storageLocal.stats.legacy.path.lessons + storageLocal.stats.legacy.practice.lessons + storageLocal.stats.legacy.lesson.lessons);
3048 legacyStatsBox.children[2].lastElementChild.innerHTML = (storageLocal.stats.legacy.listen.questions + storageLocal.stats.legacy.path.questions + storageLocal.stats.legacy.practice.questions + storageLocal.stats.legacy.lesson.questions);
3049 }
3050
3051 if (toNumber === 11) {
3052 if (newReplyButtonActive) {
3053 newReplyButtonActive = false;
3054 updateConnetionButtonStyles(document.getElementById("DLP_Main_Feedback_1_Button_1_ID"), {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][5], icon: ''}, {text: '', icon: ''});
3055 }
3056 }
3057
3058 if (toNumber === 2) mainBoxNewToBeWidth = "600";
3059 else if (toNumber === 5) mainBoxNewToBeWidth = "400";
3060 else if (toNumber === 7) mainBoxNewToBeWidth = "400";
3061 else if (toNumber === 8) mainBoxNewToBeWidth = "400";
3062 else if (toNumber === 9) mainBoxNewToBeWidth = "400";
3063 else if (toNumber === 11) mainBoxNewToBeWidth = "400";
3064 else mainBoxNewToBeWidth = "312";
3065
3066 if ([1, 2, 3, 4].includes(toNumber)) legacyButtonVisibility(true);
3067 else legacyButtonVisibility(false);
3068
3069 if (toNumber === 3) {
3070 storageSession.legacy.page = 1;
3071 saveStorageSession();
3072 } else if (toNumber === 4) {
3073 storageSession.legacy.page = 2;
3074 saveStorageSession();
3075 }
3076
3077 let mainBoxOldWidth = mainBox.offsetWidth;
3078 let mainBoxOldHeight = mainBox.offsetHeight;
3079 let fromBoxOldWidth = fromPage.offsetWidth;
3080 let fromBoxOldHeight = fromPage.offsetHeight;
3081 console.log(fromBoxOldWidth, fromBoxOldHeight);
3082 mainBox.style.transition = "";
3083 fromPage.style.display = "none";
3084 toPage.style.display = "block";
3085 mainBox.offsetHeight;
3086 mainBox.style.width = `${mainBoxNewToBeWidth}px`;
3087 let mainBoxNewWidth = mainBoxNewToBeWidth;
3088 let mainBoxNewHeight = mainBox.offsetHeight;
3089 let toBoxOldWidth = toPage.offsetWidth;
3090 let toBoxOldHeight = toPage.offsetHeight;
3091 console.log(toBoxOldWidth, toBoxOldHeight);
3092 fromPage.style.display = "block";
3093 toPage.style.display = "none";
3094 mainBox.style.width = `${mainBoxOldWidth}px`;
3095 mainBox.style.height = `${mainBoxOldHeight}px`;
3096 mainBox.offsetHeight;
3097
3098 if (flag02) mainBox.style.transition = "0.8s linear(0.00, -0.130, 0.164, 0.450, 0.687, 0.861, 0.973, 1.04, 1.06, 1.07, 1.06, 1.04, 1.03, 1.02, 1.01, 1.00, 0.999, 0.997, 0.997, 0.997, 0.998, 0.998, 0.999, 0.999, 1.00)";
3099 else mainBox.style.transition = "0.8s cubic-bezier(0.16, 1, 0.32, 1)";
3100
3101 mainBox.offsetHeight;
3102 mainBox.style.width = `${mainBoxNewToBeWidth}px`;
3103 mainBox.style.height = `${mainBoxNewHeight}px`;
3104
3105 fromPage.style.transform = `scaleX(1) scaleY(1)`;
3106 fromPage.style.width = `${fromBoxOldWidth}px`;
3107 fromPage.style.height = `${fromBoxOldHeight}px`;
3108
3109 if (flag02) fromPage.style.transition = "opacity 0.4s cubic-bezier(0.16, 1, 0.32, 1), filter 0.4s cubic-bezier(0.16, 1, 0.32, 1), transform 1.5s linear(0.00, -0.130, 0.164, 0.450, 0.687, 0.861, 0.973, 1.04, 1.06, 1.07, 1.06, 1.04, 1.03, 1.02, 1.01, 1.00, 0.999, 0.997, 0.997, 0.997, 0.998, 0.998, 0.999, 0.999, 1.00)";
3110 else fromPage.style.transition = "opacity 0.4s cubic-bezier(0.16, 1, 0.32, 1), filter 0.4s cubic-bezier(0.16, 1, 0.32, 1), transform 0.8s cubic-bezier(0.16, 1, 0.32, 1)";
3111
3112 fromPage.offsetHeight;
3113 fromPage.style.opacity = "0";
3114 fromPage.style.filter = "blur(4px)";
3115 fromPage.style.transform = `scaleX(${toBoxOldWidth / fromBoxOldWidth}) scaleY(${toBoxOldHeight / fromBoxOldHeight})`;
3116
3117 toPage.style.width = `${toBoxOldWidth}px`;
3118 toPage.style.height = `${toBoxOldHeight}px`;
3119 toPage.style.opacity = "0";
3120 toPage.style.filter = "blur(4px)";
3121 toPage.style.transform = `scaleX(${fromBoxOldWidth / toBoxOldWidth}) scaleY(${fromBoxOldHeight / toBoxOldHeight})`;
3122
3123 if (flag02) toPage.style.transition = "opacity 0.4s cubic-bezier(0.16, 1, 0.32, 1), filter 0.4s cubic-bezier(0.16, 1, 0.32, 1), transform 1.5s linear(0.00, -0.130, 0.164, 0.450, 0.687, 0.861, 0.973, 1.04, 1.06, 1.07, 1.06, 1.04, 1.03, 1.02, 1.01, 1.00, 0.999, 0.997, 0.997, 0.997, 0.998, 0.998, 0.999, 0.999, 1.00)";
3124 else toPage.style.transition = "opacity 0.4s cubic-bezier(0.16, 1, 0.32, 1), filter 0.4s cubic-bezier(0.16, 1, 0.32, 1), transform 0.8s cubic-bezier(0.16, 1, 0.32, 1)";
3125
3126 toPage.offsetHeight;
3127 toPage.style.transform = `scaleX(1) scaleY(1)`;
3128
3129 setTimeout(() => {
3130 fromPage.style.display = "none";
3131
3132 fromPage.style.width = ``;
3133 fromPage.style.height = ``;
3134 fromPage.style.transform = ``;
3135
3136 toPage.style.display = "block";
3137 toPage.offsetHeight;
3138 toPage.style.opacity = "1";
3139 toPage.style.filter = "blur(0px)";
3140 setTimeout(() => {
3141 toPage.style.opacity = "";
3142 toPage.style.filter = "";
3143 toPage.style.transition = "";
3144
3145 fromPage.style.transition = "";
3146 toPage.style.opacity = "";
3147 toPage.style.filter = "";
3148
3149 mainBox.style.height = "";
3150
3151 toPage.style.width = ``;
3152 toPage.style.height = ``;
3153 toPage.style.transform = ``;
3154
3155 lastPage = currentPage;
3156 currentPage = toNumber;
3157 isBusySwitchingPages = false;
3158 }, 400);
3159 }, 400);
3160 }
3161 Object.keys(pages).forEach(function (key) {
3162 document.querySelectorAll(`#${key}`).forEach(element => {
3163 element.addEventListener("click", function () {
3164 if (isBusySwitchingPages || isGetButtonsBusy) return;
3165 goToPage(pages[key][0], key);
3166 });
3167 });
3168 });
3169 document.getElementById('DLP_Hide_Button_1_ID').addEventListener("click", function () {
3170 if (isBusySwitchingPages) return;
3171 hidden = !hidden;
3172 hide(hidden);
3173 });
3174 function hide(value) {
3175 if (isBusySwitchingPages) return;
3176 isBusySwitchingPages = true;
3177 let button = document.querySelector(`#DLP_Hide_Button_1_ID`);
3178 let main = document.querySelector(`.DLP_Main`);
3179 let mainBox = document.querySelector(`.DLP_Main_Box`);
3180
3181 let mainBoxHeight = mainBox.offsetHeight;
3182
3183 main.style.transition = "0.8s cubic-bezier(0.16, 1, 0.32, 1)";
3184 mainBox.style.transition = "0.8s cubic-bezier(0.16, 1, 0.32, 1)";
3185 if (value) {
3186 setButtonState(button, {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][104], icon: ''}, {text: '', icon: ''});
3187 main.style.bottom = `-${mainBoxHeight - 8}px`;
3188 legacyButtonVisibility(false);
3189 mainBox.style.filter = "blur(8px)";
3190 mainBox.style.opacity = "0";
3191 } else {
3192 setButtonState(button, {button: 'rgb(var(--DLP-blue)', outline: 'rgba(0, 0, 0, 0.20)', text: '#FFF', icon: '#FFF'}, {text: systemText[systemLanguage][103], icon: ''}, {text: '', icon: ''});
3193 main.style.bottom = "16px";
3194 if (currentPage === 1 || currentPage === 3) legacyButtonVisibility(true);
3195 mainBox.style.filter = "";
3196 mainBox.style.opacity = "";
3197 }
3198 setTimeout(() => {
3199 main.style.transition = "";
3200 mainBox.style.transition = "";
3201 isBusySwitchingPages = false;
3202 }, 800);
3203 }
3204 document.querySelector(`.DLP_Main`).style.bottom = `-${document.querySelector(`.DLP_Main_Box`).offsetHeight - 8}px`;
3205 document.querySelector(`.DLP_Main_Box`).style.opacity = "0";
3206 document.querySelector(`.DLP_Main_Box`).style.filter = "blur(8px)";
3207 document.querySelector(`#DLP_Switch_Legacy_Button_1_ID`).style.filter = "blur(8px)";
3208 document.querySelector(`#DLP_Switch_Legacy_Button_1_ID`).style.opacity = "0";
3209 document.querySelector(`#DLP_Switch_Legacy_Button_1_ID`).style.display = "none";
3210 hide(false, false);
3211 function legacyButtonVisibility(value) {
3212 let legacyButton = document.querySelector(`#DLP_Switch_Legacy_Button_1_ID`);
3213 legacyButton.style.transition = 'width 0.8s cubic-bezier(0.77,0,0.18,1), opacity 0.8s cubic-bezier(0.16, 1, 0.32, 1), filter 0.8s cubic-bezier(0.16, 1, 0.32, 1), transform 0.4s cubic-bezier(0.16, 1, 0.32, 1)';
3214 if (value) {
3215 legacyButton.style.display = "";
3216 legacyButton.offsetWidth;
3217 legacyButton.style.filter = "";
3218 legacyButton.style.opacity = "";
3219 } else {
3220 legacyButton.style.filter = "blur(8px)";
3221 legacyButton.style.opacity = "0";
3222 setTimeout(() => {
3223 legacyButton.style.display = "none";
3224 }, 800);
3225 }
3226 }
3227 function handleVisibility() {
3228 if (document.querySelector('.MYehf') !== null || window.location.pathname.includes('/lesson') || window.location.pathname === '/practice') {
3229 document.querySelector('.DLP_Main').style.display = 'none';
3230 } else {
3231 document.querySelector('.DLP_Main').style.display = '';
3232 }
3233 }
3234 setInterval(handleVisibility, 200);
3235
3236 let isGetButtonsBusy = false;
3237 function setButtonState(button, color, content, animation, callback) {
3238 try {
3239 let textElement = button.querySelector('.DLP_Inset_Text_1_ID');
3240 let iconElement = button.querySelector('.DLP_Inset_Icon_1_ID');
3241
3242 let previousText = textElement.textContent;
3243 let previousIcon = undefined;
3244 if (iconElement.style.display !== 'none') {
3245 previousIcon = {
3246 icon: iconElement.textContent,
3247 color: iconElement.style.color
3248 };
3249 }
3250 textElement.textContent = content.text;
3251 if (content.icon !== '') {
3252 if (content.icon !== undefined) iconElement.textContent = content.icon;
3253 } else {
3254 iconElement.style.display = 'none';
3255 }
3256 let buttonNewWidth = button.offsetWidth;
3257 textElement.textContent = previousText;
3258 if (previousIcon !== undefined) {
3259 iconElement.textContent = previousIcon.icon;
3260 iconElement.style.color = previousIcon.color;
3261 iconElement.style.display = '';
3262 }
3263
3264 button.style.transition = 'width 0.8s cubic-bezier(0.77,0,0.18,1), background 0.8s cubic-bezier(0.16, 1, 0.32, 1), outline 0.8s cubic-bezier(0.16, 1, 0.32, 1), filter 0.4s cubic-bezier(0.16, 1, 0.32, 1), transform 0.4s cubic-bezier(0.16, 1, 0.32, 1)';
3265 button.style.width = `${button.offsetWidth}px`;
3266
3267 requestAnimationFrame(() => {
3268 textElement.style.transition = '0.4s';
3269 if (previousIcon !== undefined) iconElement.style.transition = '0.4s';
3270
3271 textElement.style.filter = 'blur(4px)';
3272 if (previousIcon !== undefined) iconElement.style.filter = 'blur(4px)';
3273 textElement.style.opacity = '0';
3274 if (previousIcon !== undefined) iconElement.style.opacity = '0';
3275 button.style.width = `${buttonNewWidth}px`;
3276
3277 button.style.background = color.button;
3278 button.style.outline = `solid 2px ${color.outline}`;
3279 });
3280
3281 setTimeout(() => {
3282 textElement.style.animation = '';
3283 if (content.icon !== '') iconElement.style.animation = '';
3284
3285 textElement.style.transition = '0s';
3286 if (content.icon !== '') iconElement.style.transition = '0s';
3287 textElement.style.color = color.text;
3288 if (content.icon !== '') iconElement.style.color = color.icon;
3289 void textElement.offsetWidth;
3290 textElement.style.transition = '0.4s';
3291 if (content.icon !== '') iconElement.style.transition = '0.4s';
3292
3293 textElement.textContent = content.text;
3294 if (content.icon !== '') {
3295 if (content.icon !== undefined) iconElement.textContent = content.icon;
3296 } else {
3297 iconElement.style.display = 'none';
3298 }
3299
3300 requestAnimationFrame(() => {
3301 textElement.style.filter = 'blur(0px)';
3302 if (content.icon !== '') iconElement.style.filter = 'blur(0px)';
3303 textElement.style.opacity = '1';
3304 if (content.icon !== '') iconElement.style.opacity = '1';
3305 });
3306
3307 setTimeout(() => {
3308 textElement.style.animation = animation.text;
3309 if (content.icon !== '') iconElement.style.animation = animation.icon;
3310
3311 button.style.width = '';
3312 }, 400);
3313
3314 if (callback) callback();
3315 }, 400);
3316 } catch (e) {
3317 console.log('setButton error', e);
3318 }
3319 }
3320
3321 const tooltipObserver = new MutationObserver((mutationsList) => {
3322 mutationsList.forEach(mutation => {
3323 if (mutation.type === 'attributes' && mutation.attributeName === 'data-dlp-tooltip') {
3324 tooltipCreate(mutation.target);
3325 console.log('Attribute changed: registered');
3326 } else if (mutation.type === 'childList') {
3327 mutation.addedNodes.forEach(node => {
3328 if (node.nodeType === Node.ELEMENT_NODE && node.hasAttribute('data-dlp-tooltip')) {
3329 tooltipCreate(node);
3330 console.log('New element with attribute: registered');
3331 }
3332 });
3333 }
3334 });
3335 });
3336
3337 tooltipObserver.observe(document.body, {
3338 childList: true,
3339 subtree: true,
3340 attributes: true,
3341 attributeFilter: ['data-dlp-tooltip']
3342 });
3343
3344 const tooltipData = new WeakMap(); // Store tooltip data associated with elements
3345
3346 function tooltipCreate(element) {
3347 if (!flag01) return;
3348 // Check if there's an existing tooltip for this element and hide it
3349 if (tooltipData.has(element)) {
3350 hideTooltip(element);
3351 }
3352
3353 let timeoutId = null;
3354 let currentTooltip = null; // Use a local variable here
3355
3356 const showTooltipForElement = (event) => { // Pass event to showTooltipForElement
3357 timeoutId = setTimeout(() => {
3358 currentTooltip = showTooltip(element, event); // Pass event to showTooltip
3359 tooltipData.set(element, { tooltip: currentTooltip, timeoutId: timeoutId }); // Store data
3360 }, 1000);
3361 };
3362
3363 const hideTooltipForElement = () => {
3364 clearTimeout(timeoutId);
3365 hideTooltip(element);
3366 };
3367
3368 const positionTooltipForElement = (event) => { // Pass event to positionTooltipForElement
3369 if(!currentTooltip) return; // Use the local currentTooltip
3370 positionTooltip(currentTooltip, event); // Pass tooltip and event to positionTooltip
3371 };
3372
3373 element.addEventListener('mouseenter', showTooltipForElement);
3374 element.addEventListener('mouseleave', hideTooltipForElement);
3375 element.addEventListener('mousemove', positionTooltipForElement);
3376
3377 // Store the listeners so we can remove them later if needed (though not explicitly required by the prompt, good practice)
3378 tooltipData.set(element, {
3379 timeoutId: null,
3380 tooltip: null,
3381 listeners: {
3382 mouseenter: showTooltipForElement,
3383 mouseleave: hideTooltipForElement,
3384 mousemove: positionTooltipForElement
3385 }
3386 });
3387
3388 console.log('Tooltip listeners attached to element');
3389
3390 // Immediately show tooltip if mouse is already over and attribute is just added/changed
3391 if (element.matches(':hover')) {
3392 // Simulate mousemove event to position tooltip correctly on initial hover if attribute is added dynamically
3393 const mockEvent = new MouseEvent('mousemove', {
3394 clientX: element.getBoundingClientRect().left, // Or any reasonable default cursor position
3395 clientY: element.getBoundingClientRect().top
3396 });
3397 showTooltipForElement(mockEvent);
3398 }
3399 };
3400
3401 function showTooltip(element, event) { // Accept event in showTooltip
3402 const tooltipText = element.dataset.dlpTooltip;
3403 let tooltip = document.createElement('div'); // Create a new tooltip each time
3404 tooltip.classList.add('DLP_Tooltip');
3405 document.body.appendChild(tooltip);
3406
3407 tooltip.textContent = tooltipText;
3408 tooltip.offsetHeight; // Trigger reflow for transition
3409 tooltip.classList.add('DLP_Tooltip_Visible');
3410
3411 positionTooltip(tooltip, event); // Pass tooltip and event to positionTooltip
3412 console.log('created tooltip');
3413 return tooltip; // Return the created tooltip
3414 }
3415
3416 function positionTooltip(tooltip, event){ // Accept tooltip and event in positionTooltip
3417 if (!tooltip || !event) return; // Exit if tooltip or event is null
3418
3419 const tooltipRect = tooltip.getBoundingClientRect();
3420 const viewportWidth = window.innerWidth;
3421 const viewportHeight = window.innerHeight;
3422
3423 const cursorX = event.clientX;
3424 const cursorY = event.clientY;
3425
3426 const tooltipWidth = tooltipRect.width;
3427 const tooltipHeight = tooltipRect.height;
3428
3429 const offsetX = 10; // Horizontal offset from cursor
3430 const offsetY = 10; // Vertical offset from cursor
3431
3432 let preferredPosition = 'bottom-right'; // Default position
3433 let tooltipLeft, tooltipTop, tooltipBottom, tooltipRight;
3434
3435 // Check bottom-right position
3436 tooltipLeft = cursorX + offsetX;
3437 tooltipTop = cursorY + offsetY;
3438 if (tooltipLeft + tooltipWidth <= viewportWidth && tooltipTop + tooltipHeight <= viewportHeight) {
3439 preferredPosition = 'bottom-right';
3440 } else if (cursorX - offsetX - tooltipWidth >= 0 && tooltipTop + tooltipHeight <= viewportHeight) { // Check bottom-left
3441 tooltipLeft = cursorX - offsetX - tooltipWidth;
3442 tooltipTop = cursorY + offsetY;
3443 preferredPosition = 'bottom-left';
3444 } else if (tooltipLeft + tooltipWidth <= viewportWidth && cursorY - offsetY - tooltipHeight >= 0) { // Check top-right
3445 tooltipLeft = cursorX + offsetX;
3446 tooltipTop = cursorY - offsetY - tooltipHeight;
3447 preferredPosition = 'top-right';
3448 } else if (cursorX - offsetX - tooltipWidth >= 0 && cursorY - offsetY - tooltipHeight >= 0) { // Check top-left
3449 tooltipLeft = cursorX - offsetX - tooltipWidth;
3450 tooltipTop = cursorY - offsetY - tooltipHeight;
3451 preferredPosition = 'top-left';
3452 } else { // Fallback to bottom-right if none fit (might go off-screen)
3453 tooltipLeft = cursorX + offsetX;
3454 tooltipTop = cursorY + offsetY;
3455 preferredPosition = 'bottom-right';
3456 }
3457
3458 tooltip.style.left = tooltipLeft + 'px';
3459 tooltip.style.top = tooltipTop + 'px';
3460 tooltip.style.bottom = 'auto'; // Ensure bottom is not overriding top
3461 tooltip.style.right = 'auto'; // Ensure right is not overriding left
3462 }
3463
3464 function hideTooltip(element) {
3465 if (!tooltipData.has(element)) return; // Exit if no tooltip data for this element
3466
3467 const data = tooltipData.get(element);
3468 const tooltip = data.tooltip;
3469 if (tooltip) {
3470 tooltip.classList.remove('DLP_Tooltip_Visible');
3471 setTimeout(() => {
3472 if (tooltip && tooltip.parentNode) {
3473 tooltip.parentNode.removeChild(tooltip);
3474 }
3475 tooltipData.delete(element); // Clear tooltip data when hidden
3476 console.log('tooltip removed');
3477 }, 500);
3478 } else {
3479 tooltipData.delete(element); // Clear data even if no tooltip element (to avoid memory leak)
3480 }
3481 }
3482
3483
3484
3485
3486 const DLP_Get_PATH_1_ID = document.getElementById("DLP_Get_PATH_1_ID");
3487 const DLP_Get_PATH_2_ID = document.getElementById("DLP_Get_PATH_2_ID");
3488 const DLP_Get_PRACTICE_1_ID = document.getElementById("DLP_Get_PRACTICE_1_ID");
3489 const DLP_Get_PRACTICE_2_ID = document.getElementById("DLP_Get_PRACTICE_2_ID");
3490 const DLP_Get_LISTEN_1_ID = document.getElementById("DLP_Get_LISTEN_1_ID");
3491 const DLP_Get_LISTEN_2_ID = document.getElementById("DLP_Get_LISTEN_2_ID");
3492 const DLP_Get_LESSON_1_ID = document.getElementById("DLP_Get_LESSON_1_ID");
3493 const DLP_Get_LESSON_2_ID = document.getElementById("DLP_Get_LESSON_2_ID");
3494
3495 function inputCheck2() {
3496 const ids = {
3497 "DLP_Get_PATH_1_ID": ["path"],
3498 "DLP_Get_PATH_2_ID": ["path"],
3499 "DLP_Get_PRACTICE_1_ID": ["practice"],
3500 "DLP_Get_PRACTICE_2_ID": ["practice"],
3501 "DLP_Get_LISTEN_1_ID": ["listen"],
3502 "DLP_Get_LISTEN_2_ID": ["listen"],
3503 "DLP_Get_LESSON_1_ID": ["lesson"],
3504 "DLP_Get_LESSON_2_ID": ["lesson"]
3505 };
3506
3507 Object.keys(ids).forEach(id => {
3508 const element = document.getElementById(id);
3509 if (!element) return;
3510 const input = element.querySelector('#DLP_Inset_Input_1_ID');
3511 const button = element.querySelector('#DLP_Inset_Button_1_ID');
3512 if (!input || !button) return;
3513 function updateButtonState() {
3514 const isEmpty = input.value.length === 0;
3515 button.style.opacity = isEmpty ? '0.5' : '';
3516 button.style.pointerEvents = isEmpty ? 'none' : '';
3517 };
3518 const category = ids[id][0];
3519 input.addEventListener("input", function () {
3520 this.value = this.value.replace(/[^0-9]/g, "");
3521 if (this.value.length === 1 && this.value[0] === '0') this.value = this.value.slice(1);
3522 if (this.value.length > 6) this.value = this.value.slice(0, 6);
3523 updateButtonState();
3524 //if (!storageSession.legacy[category]) storageSession.legacy[category] = [];
3525 storageSession.legacy[category].amount = Number(this.value);
3526 saveStorageSession();
3527 });
3528 if (['DLP_Get_LESSON_1_ID', 'DLP_Get_LESSON_2_ID'].includes(id)) {
3529 const input3 = element.querySelector('#DLP_Inset_Input_3_ID');
3530 const input4 = element.querySelector('#DLP_Inset_Input_4_ID');
3531
3532 input3.addEventListener("input", function () {
3533 this.value = this.value.replace(/[^0-9]/g, "");
3534 if (this.value.length === 1 && this.value[0] === '0') this.value = this.value.slice(1);
3535 if (this.value.length > 2) this.value = this.value.slice(0, 2);
3536 //if (!storageSession.legacy[category]) storageSession.legacy[category] = [];
3537 storageSession.legacy[category].unit = Number(this.value);
3538 saveStorageSession();
3539 });
3540 input3.addEventListener("blur", function () {
3541 if (this.value.trim() === "") {
3542 this.value = "1";
3543 storageSession.legacy[category].unit = 1;
3544 saveStorageSession();
3545 }
3546 });
3547
3548 input4.addEventListener("input", function () {
3549 this.value = this.value.replace(/[^0-9]/g, "");
3550 if (this.value.length === 1 && this.value[0] === '0') this.value = this.value.slice(1);
3551 if (this.value.length > 2) this.value = this.value.slice(0, 2);
3552 //if (!storageSession.legacy[category]) storageSession.legacy[category] = [];
3553 storageSession.legacy[category].level = Number(this.value);
3554 saveStorageSession();
3555 });
3556 input4.addEventListener("blur", function () {
3557 if (this.value.trim() === "") {
3558 this.value = "1";
3559 storageSession.legacy[category].level = 1;
3560 saveStorageSession();
3561 }
3562 });
3563 }
3564 if (storageSession.legacy[category].amount !== 0) input.value = storageSession.legacy[category].amount; updateButtonState();
3565 });
3566
3567 Object.keys(ids).forEach(id => {
3568 const element = document.getElementById(id);
3569 if (!element) return;
3570 const input = element.querySelector('#DLP_Inset_Input_1_ID');
3571 const button = element.querySelector('#DLP_Inset_Button_1_ID');
3572 if (!input || !button) return;
3573 function updateButtonState() {
3574 const isEmpty = input.value.length === 0;
3575 button.style.opacity = isEmpty ? '0.5' : '';
3576 button.style.pointerEvents = isEmpty ? 'none' : '';
3577 };
3578 const category = ids[id][0];
3579 input.addEventListener("input", function () {
3580 this.value = this.value.replace(/[^0-9]/g, "");
3581 if (this.value.length === 1 && this.value[0] === '0') this.value = this.value.slice(1);
3582 if (this.value.length > 6) this.value = this.value.slice(0, 6);
3583 updateButtonState();
3584 if (!storageSession.legacy[category]) storageSession.legacy[category] = [];
3585 storageSession.legacy[category].amount = Number(this.value);
3586 saveStorageSession();
3587 });
3588 if (storageSession.legacy[category].amount !== 0) input.value = storageSession.legacy[category].amount; updateButtonState();
3589 });
3590
3591 function updatePinnedItems() {
3592 const pinnedIds = storageLocal.pins.legacy || [];
3593 for (const id in ids) {
3594 if (id.endsWith("1_ID")) {
3595 const element = document.getElementById(id);
3596 if (element) {
3597 if (pinnedIds.includes(id)) {
3598 element.style.display = 'flex';
3599 } else {
3600 element.style.display = 'none';
3601 }
3602 }
3603 }
3604 }
3605 };
3606 updatePinnedItems();
3607
3608 Object.keys(ids).forEach(id => {
3609 if (id.endsWith("2_ID")) {
3610 const pinIcon = document.querySelector(`#${id} > .DLP_HStack_8 > .DLP_Inset_Icon_1_ID`);
3611 const modifiedId = id.replace("2_ID", "1_ID");
3612
3613 function updatePinViews() {
3614 if (storageLocal.pins.legacy.includes(modifiedId)) {
3615 pinIcon.textContent = "";
3616 pinIcon.style.color = "rgb(var(--DLP-blue))";
3617 } else {
3618 pinIcon.textContent = "";
3619 pinIcon.style.color = "rgba(var(--color-eel), 0.50)";
3620 }
3621 }
3622 updatePinViews();
3623
3624 function updatePins(isAdding) {
3625 const index = storageLocal.pins.legacy.indexOf(modifiedId);
3626 if (isAdding && index === -1) {
3627 if (storageLocal.pins.legacy.length > Math.floor(((window.innerHeight) / 200) - 1)) {
3628 showNotification("warning", "Pin Limit Reached", "You've pinned too many functions. Please unpin one to continue.", 15);
3629 } else {
3630 storageLocal.pins.legacy.push(modifiedId);
3631 }
3632 } else if (!isAdding && index !== -1) {
3633 storageLocal.pins.legacy.splice(index, 1);
3634 } else {
3635 console.log("Something unexpected happened: djr9234.");
3636 }
3637 updatePinViews();
3638 saveStorageLocal();
3639 updatePinnedItems();
3640 }
3641
3642 pinIcon.addEventListener('click', () => {
3643 updatePins(!storageLocal.pins.legacy.includes(modifiedId));
3644 });
3645 }
3646 });
3647 }
3648
3649 inputCheck2();
3650
3651 function setupButton1Events(baseId, page, type) {
3652 const button1 = document.querySelector(`#${baseId}_ID`).querySelector('#DLP_Inset_Button_1_ID');
3653 const input1 = document.querySelector(`#${baseId}_ID`).querySelector('#DLP_Inset_Input_1_ID');
3654
3655 function clickHandler() {
3656 if (isGetButtonsBusy) return;
3657 isGetButtonsBusy = true;
3658
3659 const buttonElement = document.querySelector(`#${baseId}_ID`).querySelector('#DLP_Inset_Button_1_ID');
3660
3661 if (!storageSession.legacy.status && storageSession.legacy[type].amount > 0) {
3662 setButtonState(buttonElement, {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][107], icon: ''}, {text: '', icon: ''});
3663 storageSession.legacy.page = page;
3664 storageSession.legacy.status = type;
3665 saveStorageSession();
3666 } else if (storageSession.legacy.status === type) {
3667 setButtonState(buttonElement, {button: 'rgb(var(--DLP-blue))', outline: 'rgba(0, 0, 0, 0.20)', text: '#FFF', icon: '#FFF'}, {text: systemText[systemLanguage][18], icon: ''}, {text: '', icon: ''});
3668 storageSession.legacy.status = false;
3669 saveStorageSession();
3670 }
3671 setTimeout(() => {
3672 isGetButtonsBusy = false;
3673 }, 800);
3674 };
3675
3676 button1.addEventListener('click', clickHandler);
3677
3678 input1.onkeyup = function (event) {
3679 if (event.keyCode === 13) {
3680 if (isGetButtonsBusy) return;
3681 isGetButtonsBusy = true;
3682
3683 const buttonElement = document.querySelector(`#${baseId}_ID`).querySelector('#DLP_Inset_Button_1_ID');
3684
3685 if (!storageSession.legacy.status && storageSession.legacy[type].amount > 0) {
3686 setButtonState(buttonElement, {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][107], icon: ''}, {text: '', icon: ''});
3687 storageSession.legacy.page = page;
3688 storageSession.legacy.status = type;
3689 saveStorageSession();
3690 }
3691 setTimeout(() => {
3692 isGetButtonsBusy = false;
3693 }, 800);
3694 }
3695 };
3696 }
3697
3698 function setupButton2Events(baseId, type) {
3699 const button2 = document.querySelector(`#${baseId}_ID`).querySelector('#DLP_Inset_Button_2_ID');
3700
3701 function clickHandler() {
3702 const icon = button2.querySelector('.DLP_Inset_Icon_1_ID');
3703 const input = button2.parentElement.querySelector('#DLP_Inset_Input_1_ID');
3704 const button1 = button2.parentElement.querySelector('#DLP_Inset_Button_1_ID');
3705
3706 function animateElement(element, visibility, duration = 400) {
3707 if (visibility) {
3708 element.style.display = 'block';
3709 element.style.filter = 'blur(4px)';
3710 element.style.opacity = '0';
3711 element.style.transition = '0.4s';
3712
3713 requestAnimationFrame(() => {
3714 element.style.filter = 'blur(0px)';
3715 element.style.opacity = '1';
3716 });
3717
3718 setTimeout(() => {
3719 element.style.filter = '';
3720 element.style.opacity = '';
3721
3722 element.style.transition = '';
3723 }, duration);
3724 } else {
3725 element.style.display = 'block';
3726 element.style.filter = 'blur(0px)';
3727 element.style.opacity = '1';
3728 element.style.transition = '0.4s';
3729
3730 requestAnimationFrame(() => {
3731 element.style.filter = 'blur(4px)';
3732 element.style.opacity = '0';
3733 });
3734
3735 setTimeout(() => {
3736 element.style.display = 'none';
3737 element.style.filter = '';
3738 element.style.opacity = '';
3739 element.style.transition = '';
3740 }, duration);
3741 }
3742 }
3743
3744 function syncGetButtonState(mode) {
3745 if (!button1) return;
3746 if (mode === 'infinity') {
3747 button1.style.opacity = '';
3748 button1.style.pointerEvents = '';
3749 } else {
3750 const isEmpty = input && input.value.length === 0;
3751 button1.style.opacity = isEmpty ? '0.5' : '';
3752 button1.style.pointerEvents = isEmpty ? 'none' : '';
3753 }
3754 }
3755
3756 if (storageSession.legacy[type].type === 'lesson') {
3757 let inputTo;
3758 button2.setAttribute("data-dlp-tooltip", "Lesson Mode");
3759
3760 if (input.style.display === 'none') inputTo = 'show';
3761
3762 syncGetButtonState('lesson');
3763
3764 animateElement(icon, false);
3765 setTimeout(() => {
3766 icon.textContent = '';
3767 animateElement(icon, true);
3768 }, 400);
3769 if (inputTo === 'show') setTimeout(() => animateElement(input, true), 400);
3770
3771 } else if (storageSession.legacy[type].type === 'xp') {
3772 let inputTo;
3773 button2.setAttribute("data-dlp-tooltip", "XP Mode");
3774
3775 if (input.style.display === 'none') inputTo = 'show';
3776
3777 syncGetButtonState('xp');
3778
3779 animateElement(icon, false);
3780 setTimeout(() => {
3781 icon.textContent = 'XP';
3782 animateElement(icon, true);
3783 }, 400);
3784 if (inputTo === 'show') setTimeout(() => animateElement(input, true), 400);
3785
3786 } else if (storageSession.legacy[type].type === 'infinity') {
3787 let inputTo;
3788 button2.setAttribute("data-dlp-tooltip", "Infinity Mode");
3789
3790 if (input.style.display !== 'none') inputTo = 'hide';
3791
3792 syncGetButtonState('infinity');
3793
3794 animateElement(icon, false);
3795 setTimeout(() => {
3796 icon.textContent = '';
3797 animateElement(icon, true);
3798 }, 400);
3799 if (inputTo === 'hide') animateElement(input, false);
3800
3801 }
3802 };
3803 clickHandler();
3804
3805 button2.addEventListener('click', () => {
3806 if (isGetButtonsBusy) return;
3807 isGetButtonsBusy = true;
3808 if (storageSession.legacy[type].type === 'lesson') {
3809 storageSession.legacy[type].type = 'xp';
3810 saveStorageSession();
3811 } else if (storageSession.legacy[type].type === 'xp') {
3812 storageSession.legacy[type].type = 'infinity';
3813 saveStorageSession();
3814 } else if (storageSession.legacy[type].type === 'infinity') {
3815 storageSession.legacy[type].type = 'lesson';
3816 saveStorageSession();
3817 }
3818 clickHandler();
3819 setTimeout(() => {
3820 isGetButtonsBusy = false;
3821 }, 800);
3822 });
3823 }
3824
3825 for (const type of ['PATH', 'PRACTICE', 'LISTEN', 'LESSON']) {
3826 for (let i = 1; i <= 2; i++) {
3827 const baseId = `DLP_Get_${type}_${i}`;
3828 setupButton1Events(baseId, i, type.toLowerCase());
3829 setupButton2Events(baseId, type.toLowerCase());
3830 }
3831 }
3832
3833 if (storageSession.legacy.status === 'path' && storageSession.legacy.path.amount > 0) {
3834 if (storageSession.legacy.page === 1) {
3835 setButtonState(DLP_Get_PATH_1_ID.querySelector('#DLP_Inset_Button_1_ID'), {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][107], icon: ''}, {text: '', icon: ''});
3836 } else if (storageSession.legacy.page === 2) {
3837 setButtonState(DLP_Get_PATH_2_ID.querySelector('#DLP_Inset_Button_1_ID'), {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][107], icon: ''}, {text: '', icon: ''});
3838 }
3839 } else if (storageSession.legacy.status === 'practice' && storageSession.legacy.practice.amount > 0) {
3840 if (storageSession.legacy.page === 1) {
3841 setButtonState(DLP_Get_PRACTICE_1_ID.querySelector('#DLP_Inset_Button_1_ID'), {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][107], icon: ''}, {text: '', icon: ''});
3842 } else if (storageSession.legacy.page === 2) {
3843 setButtonState(DLP_Get_PRACTICE_2_ID.querySelector('#DLP_Inset_Button_1_ID'), {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][107], icon: ''}, {text: '', icon: ''});
3844 }
3845 } else if (storageSession.legacy.status === 'listen' && storageSession.legacy.listen.amount > 0) {
3846 if (storageSession.legacy.page === 1) {
3847 setButtonState(DLP_Get_LISTEN_1_ID.querySelector('#DLP_Inset_Button_1_ID'), {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][107], icon: ''}, {text: '', icon: ''});
3848 } else if (storageSession.legacy.page === 2) {
3849 setButtonState(DLP_Get_LISTEN_2_ID.querySelector('#DLP_Inset_Button_1_ID'), {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][107], icon: ''}, {text: '', icon: ''});
3850 }
3851 } else if (storageSession.legacy.status === 'lesson' && storageSession.legacy.lesson.amount > 0) {
3852 if (storageSession.legacy.page === 1) {
3853 setButtonState(DLP_Get_LESSON_1_ID.querySelector('#DLP_Inset_Button_1_ID'), {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][107], icon: ''}, {text: '', icon: ''});
3854 } else if (storageSession.legacy.page === 2) {
3855 setButtonState(DLP_Get_LESSON_2_ID.querySelector('#DLP_Inset_Button_1_ID'), {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][107], icon: ''}, {text: '', icon: ''});
3856 }
3857 }
3858
3859 let pageSwitching = false;
3860 function process1() {
3861 if (window.location.href.includes('/lesson') || window.location.href.includes('/practice') || window.location.href.includes('/practice-hub/listening-practice')) return;
3862 if (storageSession.legacy.status && storageSession.legacy[storageSession.legacy.status].amount > 0) {
3863 if (pageSwitching) return;
3864 pageSwitching = true;
3865 setTimeout(() => {
3866 checkChest();
3867 }, 2000);
3868 } else {
3869 pageSwitching = false;
3870 }
3871 }
3872 setInterval(process1, 500);
3873 function process2() {
3874 if (storageSession.legacy.status && storageSession.legacy[storageSession.legacy.status].amount > 0) {
3875 if (storageSession.legacy.status === 'path') {
3876 window.location.href = "https://duolingo.com/lesson";
3877 } else if (storageSession.legacy.status === 'practice') {
3878 window.location.href = "https://duolingo.com/practice";
3879 } else if (storageSession.legacy.status === 'listen') {
3880 window.location.href = "https://duolingo.com/practice-hub/listening-practice";
3881 } else if (storageSession.legacy.status === 'lesson') {
3882 //storageSession.legacy[storageSession.legacy.status].section
3883 window.location.href = `https://duolingo.com/lesson/unit/${storageSession.legacy[storageSession.legacy.status].unit}/level/${storageSession.legacy[storageSession.legacy.status].level}`;
3884 }
3885 } else {
3886 pageSwitching = false;
3887 }
3888 }
3889 let checkChestCount = 0;
3890 function checkChest() {
3891 try {
3892 if (document.readyState === 'complete') {
3893 const imageUrl = 'https://d35aaqx5ub95lt.cloudfront.net/images/path/09f977a3e299d1418fde0fd053de0beb.svg';
3894 const images = document.querySelectorAll('.TI9Is');
3895 if (!images.length) {
3896 setTimeout(function () {
3897 process2();
3898 }, 2000);
3899 } else {
3900 let imagesProcessed = 0;
3901 let chestFound = false;
3902 images.forEach(image => {
3903 if (image.src === imageUrl) {
3904 image.click();
3905 chestFound = true;
3906 setTimeout(function () {
3907 process2();
3908 }, 2000);
3909 }
3910 imagesProcessed++;
3911 if (imagesProcessed >= images.length && !chestFound) {
3912 process2();
3913 }
3914 });
3915 }
3916 } else {
3917 setTimeout(function () {
3918 checkChestCount++;
3919 checkChest();
3920 }, 100);
3921 }
3922 } catch (error) {
3923 setTimeout(function () {
3924 process2();
3925 }, 2000);
3926 }
3927 };
3928
3929 if (storageSession.legacy.page === 1) {
3930 document.querySelector(`#DLP_Main_Box_Divider_${currentPage}_ID`).style.display = 'none';
3931 document.querySelector(`#DLP_Main_Box_Divider_3_ID`).style.display = 'block';
3932 currentPage = 3;
3933 let button = document.querySelector('#DLP_Switch_Legacy_Button_1_ID');
3934 setButtonState(button, {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][105], icon: ''}, {text: '', icon: ''});
3935 } else if (storageSession.legacy.page === 2) {
3936 document.querySelector(`#DLP_Main_Box_Divider_${currentPage}_ID`).style.display = 'none';
3937 document.querySelector(`#DLP_Main_Box_Divider_4_ID`).style.display = 'block';
3938 lastPage = 3;
3939 currentPage = 4;
3940 let button = document.querySelector('#DLP_Switch_Legacy_Button_1_ID');
3941 setButtonState(button, {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][105], icon: ''}, {text: '', icon: ''});
3942 }
3943
3944
3945
3946
3947
3948
3949
3950 if (storageLocal.pins.home.includes("DLP_Get_XP_1_ID")) {
3951 document.querySelector("#DLP_Get_Heart_Refill_2_ID > .DLP_HStack_8 > #DLP_Inset_Icon_1_ID");
3952 }
3953
3954 function inputCheck1() {
3955 const ids = {
3956 "DLP_Get_XP_1_ID": ["xp"],
3957 "DLP_Get_XP_2_ID": ["xp"],
3958 "DLP_Get_GEM_1_ID": ["gem"],
3959 "DLP_Get_GEM_2_ID": ["gem"],
3960 "DLP_Get_SUPER_1_ID": ["super"],
3961 "DLP_Get_SUPER_2_ID": ["super"],
3962 "DLP_Get_DOUBLE_XP_BOOST_1_ID": ["double_xp_boost"],
3963 "DLP_Get_DOUBLE_XP_BOOST_2_ID": ["double_xp_boost"],
3964 "DLP_Get_Streak_Freeze_1_ID": ["streak_freeze"],
3965 "DLP_Get_Streak_Freeze_2_ID": ["streak_freeze"],
3966 "DLP_Get_Heart_Refill_1_ID": ["heart_refill"],
3967 "DLP_Get_Heart_Refill_2_ID": ["heart_refill"],
3968 "DLP_Get_Streak_1_ID": ["streak"],
3969 "DLP_Get_Streak_2_ID": ["streak"]
3970 };
3971
3972 Object.keys(ids).forEach(id => {
3973 const element = document.getElementById(id);
3974 if (!element) return;
3975 const input = element.querySelector('#DLP_Inset_Input_1_ID');
3976 const button = element.querySelector('#DLP_Inset_Button_1_ID');
3977 if (!input || !button) return;
3978 function updateButtonState() {
3979 const isEmpty = input.value.length === 0;
3980 button.style.opacity = isEmpty ? '0.5' : '';
3981 button.style.pointerEvents = isEmpty ? 'none' : '';
3982 };
3983 const category = ids[id][0];
3984 input.addEventListener("input", function () {
3985 this.value = this.value.replace(/[^0-9]/g, "");
3986 if (this.value.length === 1 && this.value[0] === '0') this.value = this.value.slice(1);
3987 if (this.value.length > 9) this.value = this.value.slice(0, 9);
3988 updateButtonState();
3989 });
3990 if (!input.value) updateButtonState();
3991 });
3992
3993 function updatePinnedItems() {
3994 const pinnedIds = storageLocal.pins.home || [];
3995 for (const id in ids) {
3996 if (id.endsWith("1_ID")) {
3997 const element = document.getElementById(id);
3998 if (element) {
3999 if (pinnedIds.includes(id)) {
4000 element.style.display = 'flex';
4001 } else {
4002 element.style.display = 'none';
4003 }
4004 }
4005 }
4006 }
4007 };
4008 updatePinnedItems();
4009
4010 Object.keys(ids).forEach(id => {
4011 if (id.endsWith("2_ID")) {
4012 const pinIcon = document.querySelector(`#${id} > .DLP_HStack_8 > .DLP_Inset_Icon_1_ID`);
4013 const modifiedId = id.replace("2_ID", "1_ID");
4014
4015 function updatePinViews() {
4016 if (storageLocal.pins.home.includes(modifiedId)) {
4017 pinIcon.textContent = "";
4018 pinIcon.style.color = "rgb(var(--DLP-blue))";
4019 } else {
4020 pinIcon.textContent = "";
4021 pinIcon.style.color = "rgba(var(--color-eel), 0.50)";
4022 }
4023 }
4024 updatePinViews();
4025
4026 function updatePins(isAdding) {
4027 const index = storageLocal.pins.home.indexOf(modifiedId);
4028 if (isAdding && index === -1) {
4029 if (storageLocal.pins.home.length > Math.floor(((window.innerHeight) / 200) - 1)) {
4030 showNotification("warning", "Pin Limit Reached", "You've pinned too many functions. Please unpin one to continue.", 15);
4031 } else {
4032 storageLocal.pins.home.push(modifiedId);
4033 }
4034 } else if (!isAdding && index !== -1) {
4035 storageLocal.pins.home.splice(index, 1);
4036 } else {
4037 console.log("Something unexpected happened: djr9234.");
4038 }
4039 updatePinViews();
4040 saveStorageLocal();
4041 updatePinnedItems();
4042 }
4043
4044 pinIcon.addEventListener('click', () => {
4045 updatePins(!storageLocal.pins.home.includes(modifiedId));
4046 });
4047 }
4048 });
4049 }
4050 inputCheck1();
4051
4052
4053 function initializeMagneticHover(element) {
4054 let mouseDown = false;
4055 let originalZIndex = null;
4056 element.addEventListener('pointermove', (e) => {
4057 const rect = element.getBoundingClientRect();
4058 const x = e.clientX - rect.left - rect.width / 2;
4059 const y = e.clientY - rect.top - rect.height / 2;
4060 if (mouseDown) {
4061 element.style.transform = `translate(${x * 0.1}px, ${y * 0.1}px) scale(0.9)`;
4062 } else {
4063 element.style.transform = `translate(${x * 0.1}px, ${y * 0.1}px) scale(1.1)`;
4064 }
4065 if (!originalZIndex) {
4066 if (element.style.zIndex) originalZIndex = parseInt(element.style.zIndex);
4067 else originalZIndex = 0;
4068 }
4069 element.style.zIndex = originalZIndex + 1;
4070 });
4071 element.addEventListener('pointerleave', () => {
4072 element.style.transform = 'translate(0, 0) scale(1)';
4073 element.style.zIndex = originalZIndex;
4074 mouseDown = false;
4075 });
4076 element.addEventListener('pointerdown', (e) => {
4077 mouseDown = true;
4078 const rect = element.getBoundingClientRect();
4079 const x = e.clientX - rect.left - rect.width / 2;
4080 const y = e.clientY - rect.top - rect.height / 2;
4081 if (mouseDown) {
4082 element.style.transform = `translate(${x * 0.1}px, ${y * 0.1}px) scale(0.9)`;
4083 } else {
4084 element.style.transform = `translate(${x * 0.1}px, ${y * 0.1}px) scale(1.1)`;
4085 }
4086 });
4087 element.addEventListener('pointerup', (e) => {
4088 mouseDown = false;
4089 const rect = element.getBoundingClientRect();
4090 const x = e.clientX - rect.left - rect.width / 2;
4091 const y = e.clientY - rect.top - rect.height / 2;
4092
4093 const isPointerWithinElement = e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom;
4094 if (isPointerWithinElement) {
4095 playHaptic();
4096 }
4097
4098 if (mouseDown) {
4099 element.style.transform = `translate(${x * 0.1}px, ${y * 0.1}px) scale(0.9)`;
4100 } else {
4101 element.style.transform = `translate(${x * 0.1}px, ${y * 0.1}px) scale(1.1)`;
4102 }
4103 });
4104 }
4105 document.querySelectorAll('.DLP_Magnetic_Hover_1').forEach(element => {
4106 initializeMagneticHover(element);
4107 });
4108
4109 function initializeDefaultHover(element) {
4110 element.addEventListener('pointerup', (e) => {
4111 const rect = element.getBoundingClientRect();
4112 const isPointerWithinElement = e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom;
4113 if (isPointerWithinElement) {
4114 playHaptic();
4115 }
4116 });
4117 }
4118 document.querySelectorAll('.DLP_Hover_1').forEach(element => {
4119 initializeDefaultHover(element);
4120 });
4121
4122
4123 let DLP_Server_Connection_Button = document.getElementById("DLP_Main_1_Server_Connection_Button_1_ID");
4124 let DLP_Server_Connection_Button_2 = document.getElementById("DLP_Secondary_1_Server_Connection_Button_1_ID");
4125 DLP_Server_Connection_Button.addEventListener('click', () => {
4126 if (DLP_Server_Connection_Button.getAttribute("data-dlp-connection-status") === "outdated") {
4127 window.open("https://duolingopro.net/update/userscript", "_blank");
4128 } else if (DLP_Server_Connection_Button.getAttribute("data-dlp-connection-status") === "error") {
4129 window.open("https://status.duolingopro.net", "_blank");
4130 }
4131 });
4132 function updateConnetionButtonStyles(button, color, content, animation) {
4133 let iconToChange = button.querySelector(".DLP_Inset_Icon_1_ID");
4134 let textToChange = button.querySelector(".DLP_Inset_Text_1_ID");
4135 textToChange.style.animation = '';
4136 iconToChange.style.animation = '';
4137 void button.offsetWidth;
4138 requestAnimationFrame(() => {
4139 textToChange.style.filter = 'blur(4px)';
4140 textToChange.style.opacity = '0';
4141 iconToChange.style.filter = 'blur(4px)';
4142 iconToChange.style.opacity = '0';
4143 button.style.background = color.button;
4144 button.style.outline = `2px solid ${color.outline}`;
4145 });
4146 setTimeout(() => {
4147 textToChange.style.animation = 'none';
4148 iconToChange.style.animation = 'none';
4149 requestAnimationFrame(() => {
4150 textToChange.style.transition = '0s';
4151 iconToChange.style.transition = '0s';
4152 textToChange.textContent = content.text;
4153 iconToChange.textContent = content.icon;
4154 textToChange.style.color = color.text;
4155 iconToChange.style.color = color.icon;
4156 void button.offsetWidth;
4157 textToChange.style.transition = '0.4s';
4158 iconToChange.style.transition = '0.4s';
4159 void button.offsetWidth;
4160 textToChange.style.filter = 'blur(0px)';
4161 iconToChange.style.filter = 'blur(0px)';
4162 textToChange.style.opacity = '1';
4163 iconToChange.style.opacity = '1';
4164 setTimeout(() => {
4165 textToChange.style.animation = animation.text;
4166 iconToChange.style.animation = animation.icon;
4167 }, 400);
4168 });
4169 }, 400);
4170 }
4171 let serverConnectedBefore = 'no';
4172 let serverConnectedBeforeNotification;
4173 let newTermID;
4174 let chatMemory = [];
4175 let chatTempSendList = [];
4176 const pendingTempMessages = new Map();
4177 let chatMemoryFingerprints = [];
4178 let chatMessageLookup = new Map();
4179
4180 function normalizeMessageValue(value) {
4181 if (Array.isArray(value)) {
4182 return value.map(normalizeMessageValue);
4183 }
4184 if (value && typeof value === 'object') {
4185 const sortedKeys = Object.keys(value).sort();
4186 const normalizedObject = {};
4187 sortedKeys.forEach(key => {
4188 normalizedObject[key] = normalizeMessageValue(value[key]);
4189 });
4190 return normalizedObject;
4191 }
4192 if (value === undefined || Number.isNaN(value)) {
4193 return null;
4194 }
4195 return value;
4196 }
4197
4198 function computeMessageFingerprint(message) {
4199 const relevantData = {
4200 accent: message?.accent ?? '',
4201 author: message?.author ?? '',
4202 deleted: message?.deleted ?? false,
4203 edited: message?.edited ?? false,
4204 files: Array.isArray(message?.files) ? message.files.slice() : [],
4205 message_id: message?.message_id ?? null,
4206 message: message?.message ?? '',
4207 profile_picture: message?.profile_picture ?? '',
4208 role: message?.role ?? '',
4209 send_time: message?.send_time ?? null,
4210 status: message?.status ?? '',
4211 reply_to: message?.reply_to ?? null
4212 };
4213
4214 try {
4215 return JSON.stringify(normalizeMessageValue(relevantData));
4216 } catch (error) {
4217 console.error('Failed to compute message fingerprint', error);
4218 return JSON.stringify({
4219 message_id: message?.message_id ?? null,
4220 send_time: message?.send_time ?? null
4221 });
4222 }
4223 }
4224
4225 function resolveMessageKey(msg) {
4226 if (!msg || typeof msg !== 'object') return null;
4227 if (msg?.message_id !== undefined && msg?.message_id !== null) {
4228 return String(msg.message_id);
4229 }
4230 if (msg?.send_time !== undefined && msg?.send_time !== null) {
4231 return String(msg.send_time);
4232 }
4233 return null;
4234 }
4235
4236 function areArraysEqual(arrayA = [], arrayB = []) {
4237 if (arrayA.length !== arrayB.length) return false;
4238 for (let i = 0; i < arrayA.length; i++) {
4239 if (arrayA[i] !== arrayB[i]) return false;
4240 }
4241 return true;
4242 }
4243 let newReplyButtonActive = false;
4244 let userBioData = false;
4245 let kqjzvmbt = false;
4246 function connectToServer() {
4247 let mainInputsDiv1 = document.getElementById('DLP_Main_Inputs_1_Divider_1_ID');
4248
4249 const chatKeyValue = storageLocal?.chatKey?.[0] ?? false;
4250
4251 //fetch(apiURL + '/server', {
4252 fetch('https://api.duolingopro.net/server', {
4253 method: 'POST',
4254 headers: {
4255 'Content-Type': 'application/json'
4256 },
4257 body: JSON.stringify({
4258 version: versionFormal,
4259 key: storageLocal.random16,
4260 ...(chatKeyValue && { chat_key: chatKeyValue })
4261 })
4262 })
4263 .then(response => response.json())
4264 .then(data => {
4265 if (data.global || data.versions) {
4266 console.log(data.chats);
4267
4268 if (!userBioData && !fetchingUserBioData) {
4269 fetchUserBioData();
4270 }
4271
4272 if (chatKeyValue) {
4273 if (!data.chats) {
4274 if (kqjzvmbt) {
4275 storageLocal.chatKey.shift();
4276 saveStorageLocal();
4277 }
4278 kqjzvmbt = true;
4279 } else {
4280 buildChat(data);
4281 }
4282 }
4283
4284 function buildChat(data) {
4285 const chatParent = document.querySelector('#DLP_Main_Box_Divider_11_ID').lastElementChild;
4286 const chatBox = chatParent?.querySelector('.DLP_Chat_Box_1_ID_1');
4287 if (!chatBox) return;
4288
4289 if (typeof data === 'undefined' || typeof data.chats === 'undefined' || !Array.isArray(data.chats.messages)) return;
4290 if (chatParent?.querySelector('#DLP_Inset_Group_3')?.style.display !== 'none') chatParent.querySelector('#DLP_Inset_Group_3').style.display = 'none';
4291 if (chatBox?.style.display === 'none') chatBox.style.display = 'flex';
4292
4293 if (data.chats.solved) {
4294 chatParent.querySelector('#DLP_Inset_Group_1').style.display = 'none';
4295 chatParent.querySelector('#DLP_Inset_Group_2').style.display = '';
4296 }
4297
4298 const incomingMessages = data.chats.messages.filter(msg => !msg?.deleted && msg?.status !== 'deleted');
4299 const nextFingerprints = incomingMessages.map(computeMessageFingerprint);
4300 const hasChanges = nextFingerprints.length !== chatMemoryFingerprints.length || nextFingerprints.some((fingerprint, index) => fingerprint !== chatMemoryFingerprints[index]);
4301
4302 if (hasChanges) {
4303 const previousLength = chatMemory.length;
4304 const wasAtBottom = Math.abs(chatBox.scrollHeight - (chatBox.scrollTop + chatBox.clientHeight)) < 5;
4305 const scrollOffsetFromBottom = chatBox.scrollHeight - chatBox.scrollTop;
4306
4307 chatBox.innerHTML = '';
4308 const combinedMessages = [];
4309 let sequenceCounter = 0;
4310 const resolveTimestamp = (msg) => {
4311 const rawTimestamp = msg?.send_time;
4312 if (rawTimestamp === undefined || rawTimestamp === null) {
4313 return Number.MAX_SAFE_INTEGER;
4314 }
4315 const numericTimestamp = Number(rawTimestamp);
4316 if (!Number.isFinite(numericTimestamp)) {
4317 return Number.MAX_SAFE_INTEGER;
4318 }
4319 return numericTimestamp < 1e12 ? numericTimestamp * 1000 : numericTimestamp;
4320 };
4321
4322 incomingMessages.forEach(message => {
4323 combinedMessages.push({
4324 message,
4325 tempId: false,
4326 sequence: sequenceCounter++
4327 });
4328 });
4329 pendingTempMessages.forEach((tempMessage, tempId) => {
4330 combinedMessages.push({
4331 message: tempMessage,
4332 tempId,
4333 sequence: sequenceCounter++
4334 });
4335 });
4336
4337 combinedMessages.sort((a, b) => {
4338 const timeA = resolveTimestamp(a.message);
4339 const timeB = resolveTimestamp(b.message);
4340 if (timeA === timeB) {
4341 return a.sequence - b.sequence;
4342 }
4343 return timeA - timeB;
4344 });
4345
4346 chatMessageLookup.clear();
4347 incomingMessages.forEach(msg => {
4348 const key = resolveMessageKey(msg);
4349 if (key) {
4350 chatMessageLookup.set(key, msg);
4351 }
4352 if (msg?.send_time !== undefined && msg?.send_time !== null) {
4353 const sendKey = String(msg.send_time);
4354 if (sendKey && sendKey !== key) {
4355 chatMessageLookup.set(sendKey, msg);
4356 }
4357 }
4358 });
4359
4360 combinedMessages.forEach(({ message, tempId }) => {
4361 createMessage(message, false, tempId || false);
4362 });
4363
4364 const hasNewMessages = incomingMessages.length > previousLength;
4365 if (hasNewMessages || wasAtBottom) {
4366 chatBox.scrollTop = chatBox.scrollHeight;
4367 } else {
4368 const newScrollTop = chatBox.scrollHeight - scrollOffsetFromBottom;
4369 chatBox.scrollTop = newScrollTop < 0 ? 0 : newScrollTop;
4370 }
4371 }
4372
4373 chatMemory = incomingMessages.map(message => ({ ...message }));
4374 chatMemoryFingerprints = nextFingerprints;
4375
4376 const knownMessageIds = (storageLocal.chats ?? []).map(id => (id === null || id === undefined) ? id : String(id));
4377
4378 if (currentPage === 11) {
4379 const newMessageIds = chatMemory.map(resolveMessageKey);
4380 if (!areArraysEqual(knownMessageIds, newMessageIds)) {
4381 storageLocal.chats = newMessageIds;
4382 saveStorageLocal();
4383 }
4384 } else {
4385 incomingMessages.forEach(msg => {
4386 const messageKey = resolveMessageKey(msg);
4387 const sendTimeKey = (msg?.send_time !== undefined && msg?.send_time !== null) ? String(msg.send_time) : null;
4388 const alreadyKnown = (messageKey && knownMessageIds.includes(messageKey)) || (sendTimeKey && knownMessageIds.includes(sendTimeKey));
4389 if (!alreadyKnown && !newReplyButtonActive) {
4390 newReplyButtonActive = true;
4391 updateConnetionButtonStyles(document.getElementById("DLP_Main_Feedback_1_Button_1_ID"), {button: 'rgb(var(--DLP-blue))', outline: 'rgba(0, 0, 0, 0.20)', text: '#FFF', icon: '#FFF'}, {text: 'New Reply', icon: ''}, {text: 'DLP_Pulse_Opacity_Animation_1 6s ease-in-out infinite', icon: 'DLP_Pulse_Opacity_Animation_1 6s ease-in-out infinite'});
4392 showNotification({icon: "", color: "rgb(var(--DLP-blue))"}, "Support Team Response", "You have a new message from our support team.", 30);
4393 }
4394 });
4395 }
4396 }
4397
4398
4399 const globalData = data.global;
4400 const versionData = data.versions[versionFull];
4401 const warnings = versionData.warnings || [];
4402
4403 const termsText = Object.entries(globalData.terms)[0][1];
4404 newTermID = Object.entries(globalData.terms)[0][0];
4405
4406 //console.log('Global Warning:', globalData.warning);
4407 //console.log('Notifications:', globalData.notifications);
4408
4409 document.querySelector(`#DLP_Terms_Main_Text_1_ID`).innerHTML = termsText;
4410
4411 if (versionData.status === 'latest') {
4412 if (storageLocal.terms === newTermID) {
4413 if (serverConnectedBefore !== 'yes') {
4414 updateReleaseNotes(warnings);
4415 mainInputsDiv1.style.opacity = '1';
4416 mainInputsDiv1.style.pointerEvents = 'auto';
4417 updateConnetionButtonStyles(DLP_Server_Connection_Button, {button: 'rgb(var(--DLP-green))', outline: 'rgba(0, 0, 0, 0.20)', text: '#FFF', icon: '#FFF'}, {text: systemText[systemLanguage][108], icon: ''}, {text: 'DLP_Pulse_Opacity_Animation_1 6s ease-in-out infinite', icon: 'DLP_Pulse_Opacity_Animation_1 6s ease-in-out infinite'});
4418 updateConnetionButtonStyles(DLP_Server_Connection_Button_2, {button: 'rgb(var(--DLP-green))', outline: 'rgba(0, 0, 0, 0.20)', text: '#FFF', icon: '#FFF'}, {text: systemText[systemLanguage][108], icon: ''}, {text: 'DLP_Pulse_Opacity_Animation_1 6s ease-in-out infinite', icon: 'DLP_Pulse_Opacity_Animation_1 6s ease-in-out infinite'});
4419 DLP_Server_Connection_Button.setAttribute("data-dlp-connection-status", "connected");
4420 DLP_Server_Connection_Button_2.setAttribute("data-dlp-connection-status", "connected");
4421 if (serverConnectedBefore === 'error' || serverConnectedBeforeNotification) {
4422 serverConnectedBeforeNotification.close();
4423 serverConnectedBeforeNotification = false;
4424 }
4425 serverConnectedBefore = 'yes';
4426 }
4427 } else {
4428 if (storageLocal.onboarding) {
4429 if (currentPage !== 5 && currentPage !== 6) goToPage(5);
4430 document.querySelector(`#DLP_Main_Box_Divider_5_ID`).querySelector(`#DLP_Terms_1_Text_1_ID`).innerHTML = "We have updated our Terms & Conditions. Please read them carefully and accept to continue using Duolingo PRO 3.1.";
4431 } else {
4432 if (currentPage !== 10) goToPage(10);
4433 }
4434 }
4435 } else if (serverConnectedBefore !== 'outdated') {
4436 updateConnetionButtonStyles(DLP_Server_Connection_Button, {button: 'rgb(var(--DLP-orange))', outline: 'rgba(0, 0, 0, 0.20)', text: '#FFF', icon: '#FFF'}, {text: 'Outdated', icon: ''}, {text: 'DLP_Pulse_Opacity_Animation_1 6s ease-in-out infinite', icon: 'DLP_Pulse_Opacity_Animation_1 6s ease-in-out infinite'});
4437 updateConnetionButtonStyles(DLP_Server_Connection_Button_2, {button: 'rgb(var(--DLP-orange))', outline: 'rgba(0, 0, 0, 0.20)', text: '#FFF', icon: '#FFF'}, {text: 'Outdated', icon: ''}, {text: 'DLP_Pulse_Opacity_Animation_1 6s ease-in-out infinite', icon: 'DLP_Pulse_Opacity_Animation_1 6s ease-in-out infinite'});
4438 DLP_Server_Connection_Button.setAttribute("data-dlp-connection-status", "outdated");
4439 DLP_Server_Connection_Button_2.setAttribute("data-dlp-connection-status", "outdated");
4440 if (serverConnectedBefore === 'no') {
4441 mainInputsDiv1.style.opacity = '0.5';
4442 mainInputsDiv1.style.pointerEvents = 'none';
4443 showNotification("warning", systemText[systemLanguage][233], systemText[systemLanguage][234], 0);
4444 } else if (serverConnectedBefore === 'error' || serverConnectedBeforeNotification) {
4445 serverConnectedBeforeNotification.close();
4446 serverConnectedBeforeNotification = false;
4447 }
4448 serverConnectedBefore = 'outdated';
4449 }
4450
4451 //if (storageLocal.languagePackVersion !== versionData.languagePackVersion) {
4452 // fetch(serverURL + "/static/3.0/resources/language_pack.json")
4453 // .then(response => response.json())
4454 // .then(data => {
4455 // if (data[versionFull]) {
4456 // storageLocal.languagePack = data[versionFull];
4457 // console.log(data[versionFull]);
4458 // storageLocal.languagePackVersion = versionData.languagePackVersion;
4459 // saveStorageLocal();
4460 // }
4461 // })
4462 // .catch(error => console.error('Error fetching systemText:', error));
4463 //}
4464 } else {
4465 console.error(`Version ${versionFull} not found in the data`);
4466 }
4467 })
4468 .catch(error => {
4469 console.error('Error fetching data:', error);
4470 if (serverConnectedBefore !== 'error') {
4471 mainInputsDiv1.style.opacity = '0.5';
4472 mainInputsDiv1.style.pointerEvents = 'none';
4473 updateConnetionButtonStyles(DLP_Server_Connection_Button, {button: 'rgb(var(--DLP-pink))', outline: 'rgba(0, 0, 0, 0.20)', text: '#FFF', icon: '#FFF'}, {text: systemText[systemLanguage][109], icon: ''}, {text: 'DLP_Pulse_Opacity_Animation_1 6s ease-in-out infinite', icon: 'DLP_Pulse_Opacity_Animation_1 6s ease-in-out infinite'});
4474 updateConnetionButtonStyles(DLP_Server_Connection_Button_2, {button: 'rgb(var(--DLP-pink))', outline: 'rgba(0, 0, 0, 0.20)', text: '#FFF', icon: '#FFF'}, {text: systemText[systemLanguage][109], icon: ''}, {text: 'DLP_Pulse_Opacity_Animation_1 6s ease-in-out infinite', icon: 'DLP_Pulse_Opacity_Animation_1 6s ease-in-out infinite'});
4475 DLP_Server_Connection_Button.setAttribute("data-dlp-connection-status", "error");
4476 DLP_Server_Connection_Button_2.setAttribute("data-dlp-connection-status", "error");
4477 serverConnectedBeforeNotification = showNotification("error", systemText[systemLanguage][231], systemText[systemLanguage][232], 0);
4478 serverConnectedBefore = 'error';
4479 }
4480 });
4481 }
4482 connectToServer();
4483 setTimeout(() => {
4484 connectToServer();
4485 }, 1000);
4486 setInterval(() => {
4487 //if (windowBlurState) connectToServer();
4488 if (document.visibilityState === "visible" || isAutoMode) connectToServer();
4489 }, 4000);
4490
4491 let fetchingUserBioData = false;
4492 async function fetchUserBioData() {
4493 fetchingUserBioData = true;
4494 console.log('FETHCING FOR YOU YOUR HONOR');
4495 const userResponse = await fetch('https://www.duolingo.com/2017-06-30/users/' + JSON.parse(atob(document.cookie.split(';').find(cookie => cookie.includes('jwt_token')).split('=')[1].split('.')[1])).sub + '?fields=name,username,picture');
4496 if (!userResponse.ok) {
4497 fetchingUserBioData = false;
4498 return;
4499 }
4500 const userData = await userResponse.json();
4501 console.log(userData);
4502 userBioData = {
4503 username: (userData.name && userData.name.trim().length > 0) ? userData.name : userData.username,
4504 profile_picture: "https:" + userData.picture + "/xlarge"
4505 };
4506 fetchingUserBioData = false;
4507 }
4508
4509 function createMessage(message, isBefore=false, isTemp=false) {
4510 function formatTimeAgo(timestamp) {
4511 // If the timestamp is in seconds (10 digits), convert to ms
4512 if (timestamp < 1e12) {
4513 timestamp = timestamp * 1000;
4514 }
4515 const now = Date.now();
4516 const diff = now - timestamp; // Difference in milliseconds
4517
4518 const seconds = Math.floor(diff / 1000);
4519 const minutes = Math.floor(seconds / 60);
4520 const hours = Math.floor(minutes / 60);
4521 const days = Math.floor(hours / 24);
4522 const weeks = Math.floor(days / 7);
4523 const months = Math.floor(days / 30);
4524 const years = Math.floor(days / 365);
4525
4526 if (seconds < 60) {
4527 return "now";
4528 } else if (minutes < 60) {
4529 return `${minutes}m ago`;
4530 } else if (hours < 24) {
4531 return `${hours}h ago`;
4532 } else if (days < 7) {
4533 return `${days}d ago`;
4534 } else if (weeks < 4) {
4535 return `${weeks}w ago`;
4536 } else if (months < 12) {
4537 return `${months}m ago`;
4538 } else {
4539 return `${years}y ago`;
4540 }
4541 }
4542 function toMilliseconds(ts) {
4543 return ts < 1e12 ? ts * 1000 : ts;
4544 }
4545 function updateTimeAgo(element, timestamp) {
4546 function update() {
4547 if (!document.contains(element)) {
4548 clearInterval(intervalId);
4549 return;
4550 }
4551 const newText = formatTimeAgo(timestamp);
4552 if (element.textContent !== newText) {
4553 element.textContent = newText;
4554 }
4555 }
4556
4557 update();
4558 const intervalId = setInterval(update, 1000);
4559 }
4560
4561 const chatBox = document.querySelector('#DLP_Main_Box_Divider_11_ID')?.querySelector('.DLP_Chat_Box_1_ID_1');
4562
4563 const messageKey = (() => {
4564 if (message?.message_id !== undefined && message?.message_id !== null) {
4565 return String(message.message_id);
4566 }
4567 if (message?.send_time !== undefined && message?.send_time !== null) {
4568 return String(message.send_time);
4569 }
4570 if (isTemp) {
4571 return `temp-${isTemp}`;
4572 }
4573 return '';
4574 })();
4575
4576 let lastChatChild = chatBox.lastElementChild;
4577 if (isBefore) lastChatChild = isBefore.previousElementSibling;
4578
4579 const tempState = isTemp ? pendingTempMessages.get(isTemp) : null;
4580 const failedTemp = Boolean(tempState?.sendFailed);
4581
4582 function getReplyKey(message) {
4583 const rawReplyTo = message?.reply_to;
4584 if (typeof rawReplyTo === 'number' && Number.isFinite(rawReplyTo)) {
4585 return String(rawReplyTo);
4586 }
4587 if (typeof rawReplyTo === 'string') {
4588 const trimmed = rawReplyTo.trim();
4589 if (/^\d+$/.test(trimmed)) {
4590 return trimmed;
4591 }
4592 }
4593 if (typeof rawReplyTo === 'bigint') {
4594 return rawReplyTo.toString();
4595 }
4596 return null;
4597 }
4598
4599 function hasNumericReply(message) {
4600 return Boolean(getReplyKey(message));
4601 }
4602
4603 function createReplyPreview(message) {
4604 const replyKey = getReplyKey(message);
4605 if (!replyKey) {
4606 return null;
4607 }
4608
4609 function deriveTargetFromDom(key) {
4610 if (!chatBox) return null;
4611
4612 const messageNodes = chatBox.querySelectorAll('[data-message-id]');
4613 let matchedNode = null;
4614 for (const node of messageNodes) {
4615 if (node.getAttribute('data-message-id') === key) {
4616 matchedNode = node;
4617 break;
4618 }
4619 }
4620
4621 if (!matchedNode) {
4622 const groupCandidate = chatBox.querySelector(`[data-group-id="${key}"]`);
4623 if (groupCandidate) {
4624 matchedNode = groupCandidate.querySelector('[data-message-id]');
4625 }
4626 }
4627
4628 if (!matchedNode) return null;
4629
4630 const result = {
4631 message_id: key,
4632 message: (matchedNode.textContent || '').trim()
4633 };
4634
4635 const sendAttr = matchedNode.getAttribute('data-message-sent');
4636 if (sendAttr && sendAttr !== '') {
4637 const numericSend = Number(sendAttr);
4638 result.send_time = Number.isFinite(numericSend) ? numericSend : sendAttr;
4639 }
4640
4641 const groupNode = matchedNode.closest('[data-group-id]');
4642 if (groupNode) {
4643 if (!result.message) {
4644 const fallbackNode = groupNode.querySelector('[data-message-id]');
4645 if (fallbackNode && fallbackNode !== matchedNode) {
4646 const fallbackText = (fallbackNode.textContent || '').trim();
4647 if (fallbackText) {
4648 result.message = fallbackText;
4649 }
4650 }
4651 }
4652
4653 const authorNameAttr = groupNode.getAttribute('data-author-name');
4654 if (authorNameAttr) {
4655 result.author = authorNameAttr;
4656 }
4657
4658 const headerNode = groupNode.querySelector('[data-chat-header="true"]');
4659 if (headerNode) {
4660 const authorElement = headerNode.querySelector('.DLP_HStack_6 p.DLP_Text_Style_1');
4661 if (authorElement) {
4662 const authorText = authorElement.textContent || '';
4663 if (authorText.trim()) {
4664 result.author = authorText.trim();
4665 }
4666 let accentColor = authorElement.style?.color?.trim();
4667 if ((!accentColor || accentColor === '') && typeof window !== 'undefined' && document.contains(authorElement)) {
4668 try {
4669 accentColor = window.getComputedStyle(authorElement).color;
4670 } catch (error) {
4671 console.error('Failed to compute accent color for reply preview', error);
4672 }
4673 }
4674 if (accentColor) {
4675 result.accent = accentColor;
4676 }
4677 }
4678
4679 const avatarElement = headerNode.querySelector('div[style*="background"]');
4680 if (avatarElement) {
4681 const styleAttr = avatarElement.getAttribute('style') || '';
4682 const urlMatch = styleAttr.match(/url\((['"]?)(.*?)\1\)/);
4683 if (urlMatch && urlMatch[2]) {
4684 result.profile_picture = urlMatch[2];
4685 }
4686 }
4687 }
4688 }
4689
4690 if ((!result.message || result.message === '') && matchedNode.classList?.contains('DLP_Hide_Scrollbar')) {
4691 result.message = 'Attachment';
4692 }
4693
4694 return result;
4695 }
4696
4697 let targetMessage = chatMessageLookup.get(replyKey);
4698 if (!targetMessage && chatMemory.length) {
4699 targetMessage = chatMemory.find(existing => resolveMessageKey(existing) === replyKey);
4700 }
4701
4702 function isMeaningful(value, type) {
4703 if (value === undefined || value === null) return false;
4704 const trimmed = String(value).trim();
4705 if (!trimmed) return false;
4706 if (type === 'author' && trimmed === 'The User Who Was Replied') return false;
4707 if (type === 'message' && trimmed === 'Reply content') return false;
4708 return true;
4709 }
4710
4711 const domMessage = deriveTargetFromDom(replyKey);
4712 if (domMessage) {
4713 const merged = targetMessage ? { ...targetMessage } : {};
4714
4715 if (isMeaningful(domMessage.author, 'author')) {
4716 merged.author = domMessage.author;
4717 }
4718 if (isMeaningful(domMessage.profile_picture)) {
4719 merged.profile_picture = domMessage.profile_picture;
4720 }
4721 if (isMeaningful(domMessage.accent)) {
4722 merged.accent = domMessage.accent;
4723 }
4724
4725 if (isMeaningful(domMessage.message, 'message')) {
4726 if (!isMeaningful(merged.message, 'message') || domMessage.message !== 'Attachment') {
4727 merged.message = domMessage.message;
4728 }
4729 } else if (!isMeaningful(merged.message, 'message') && domMessage.message) {
4730 merged.message = domMessage.message;
4731 }
4732
4733 if (domMessage.send_time !== undefined && domMessage.send_time !== null && (merged.send_time === undefined || merged.send_time === null || merged.send_time === '')) {
4734 merged.send_time = domMessage.send_time;
4735 }
4736 if (!isMeaningful(merged.message_id)) {
4737 merged.message_id = replyKey;
4738 }
4739
4740 targetMessage = merged;
4741 chatMessageLookup.set(replyKey, targetMessage);
4742 const derivedSendKey = targetMessage?.send_time;
4743 if (derivedSendKey !== undefined && derivedSendKey !== null) {
4744 const sendKey = String(derivedSendKey);
4745 if (sendKey && sendKey !== replyKey) {
4746 chatMessageLookup.set(sendKey, targetMessage);
4747 }
4748 }
4749 }
4750
4751 const previewWrapper = document.createElement('div');
4752 const targetKey = resolveMessageKey(targetMessage) ?? replyKey;
4753 const targetSendTime = targetMessage?.send_time ?? '';
4754 const previewAccent = targetMessage?.accent && targetMessage.accent !== '' ? targetMessage.accent : (message?.accent || 'rgb(var(--DLP-blue))');
4755 const previewAuthor = targetMessage?.author ?? message?.author ?? 'Unknown user';
4756 const previewAvatar = targetMessage?.profile_picture ?? message?.profile_picture ?? '';
4757 const avatarBackground = previewAvatar ? `background: url(${previewAvatar}) 50% center / cover no-repeat white;` : 'background: rgba(var(--color-snow), 1);';
4758 const previewMessage = (targetMessage?.message && targetMessage.message.trim() !== '') ? targetMessage.message : 'Original message unavailable';
4759
4760 previewWrapper.innerHTML = `
4761 <div class="DLP_HStack_8" data-reply-preview="true" style="padding-left: 24px; position: relative;">
4762 <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" style="position: absolute; left: 9px; top: 9px; z-index: -1;">
4763 <path d="M17 1H11C5.47715 1 1 5.47715 1 11V17" stroke="rgb(var(--color-eel), 0.20)" stroke-width="2" stroke-linecap="round"/>
4764 </svg>
4765 <div class="DLP_HStack_6">
4766 <div style="width: 20px; height: 20px; border-radius: 16px; outline: rgba(0, 0, 0, 0.2) solid 2px; outline-offset: -2px; ${avatarBackground}"></div>
4767 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: ${previewAccent}; white-space: pre;">${previewAuthor}</p>
4768 </div>
4769 <p class="DLP_Text_Style_1" data-message-id="${targetKey}" data-message-sent="${targetSendTime}" style="align-self: stretch; white-space: nowrap; overflow-wrap: anywhere; word-break: break-word; text-overflow: ellipsis; -webkit-line-clamp: 1; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical;">${previewMessage}</p>
4770 </div>
4771 `;
4772
4773 return previewWrapper.firstElementChild;
4774 }
4775
4776 function ensureReplyPreview(container, message) {
4777 if (!container) return;
4778 const replyKey = getReplyKey(message);
4779 const existingPreview = container.querySelector('[data-reply-preview="true"]');
4780
4781 if (!replyKey) {
4782 if (existingPreview) existingPreview.remove();
4783 return;
4784 }
4785
4786 const headerElement = container.querySelector('[data-chat-header="true"]');
4787 if (!headerElement) {
4788 if (existingPreview) existingPreview.remove();
4789 return;
4790 }
4791
4792 if (existingPreview) {
4793 existingPreview.remove();
4794 }
4795
4796 const previewElement = createReplyPreview(message);
4797 if (previewElement) {
4798 container.insertBefore(previewElement, headerElement);
4799 }
4800 }
4801
4802 function createStartersMessage(message) {
4803 const temp = document.createElement('div');
4804 temp.innerHTML = `
4805 <div class="DLP_VStack_4" data-group-id="${messageKey}" data-group-sent="${message.send_time ?? ''}" data-author-name="${message.author}">
4806 <div data-chat-header="true" style="display: flex; justify-content: space-between; align-items: center; align-self: stretch;">
4807 <div class="DLP_HStack_6">
4808 <div style="width: 20px; height: 20px; border-radius: 16px; outline: rgba(0, 0, 0, 0.2) solid 2px; outline-offset: -2px; background: url(${message.profile_picture}) 50% center / cover no-repeat white;"></div>
4809 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: ${message.accent};">${message.author}</p>
4810 </div>
4811 <div class="DLP_HStack_6">
4812 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: ${message.accent};">${message.role}</p>
4813 <p class="DLP_Text_Style_1 DLP_NoSelect" style="color: ${message.accent}; font-size: 4px;"></p>
4814 <p class="DLP_Text_Style_1 DLP_NoSelect" data-time-element="true" style="color: ${message.accent};">${formatTimeAgo(message.send_time)}</p>
4815 </div>
4816 </div>
4817 </div>
4818 `;
4819 const newElement = temp.firstElementChild;
4820 chatBox.appendChild(newElement);
4821 lastChatChild = newElement;
4822
4823 ensureReplyPreview(lastChatChild, message);
4824
4825 const timeElement = lastChatChild.querySelector('[data-time-element="true"]');
4826 if (timeElement) {
4827 updateTimeAgo(timeElement, message.send_time);
4828 }
4829
4830 createContinuationMessage(message, true);
4831 }
4832
4833 function createContinuationMessage(message, skipGroupChecks = false) {
4834 const firstMessageTimestampAttr = lastChatChild.getAttribute('data-group-sent') ?? lastChatChild.getAttribute('data-group-timestamp');
4835 const firstMessageTimestamp = firstMessageTimestampAttr ? parseInt(firstMessageTimestampAttr) : 0;
4836 const replyKey = getReplyKey(message);
4837
4838 if (!skipGroupChecks) {
4839 if (replyKey) {
4840 createStartersMessage(message);
4841 return;
4842 }
4843 if (toMilliseconds(message.send_time) - toMilliseconds(firstMessageTimestamp) > 900000) { // 15 minutes, 900,000 milliseconds
4844 createStartersMessage(message);
4845 return;
4846 }
4847 }
4848
4849 if (replyKey) {
4850 ensureReplyPreview(lastChatChild, message);
4851 }
4852
4853 if (message.message !== "") {
4854 const continuationStyles = [
4855 'align-self: stretch',
4856 'white-space: pre-line',
4857 'overflow-wrap: anywhere',
4858 'word-break: break-word'
4859 ];
4860 if (isTemp && !failedTemp) {
4861 continuationStyles.push('animation: DLP_Pulse_Opacity_Animation_2 2s ease-in-out infinite');
4862 }
4863 if (failedTemp) {
4864 continuationStyles.push('color: rgba(var(--DLP-pink))');
4865 }
4866 const continuationStyleAttr = continuationStyles.join('; ') + ';';
4867 const temp = document.createElement('div');
4868 temp.innerHTML = `
4869 <p class="DLP_Text_Style_1" data-message-id="${messageKey}" data-message-sent="${message.send_time ?? ''}"${isTemp ? ` data-is-temp="${isTemp}"` : ''} style="${continuationStyleAttr}">${message.message}</p>
4870 `;
4871 const newElement = temp.firstElementChild;
4872 lastChatChild.appendChild(newElement);
4873 }
4874 createAttachmentMessage(message);
4875 }
4876
4877 function expandAttachment(lastAttachment) {
4878 let expanded = false;
4879
4880 function getElementPosition(element) {
4881 if (!element || !(element instanceof Element)) {
4882 return false;
4883 }
4884 const rect = element.getBoundingClientRect();
4885 return {
4886 top: rect.top,
4887 right: rect.right,
4888 bottom: rect.bottom,
4889 left: rect.left,
4890 width: rect.width,
4891 height: rect.height
4892 };
4893 }
4894
4895 async function getElementDimensions(element) {
4896 return new Promise((resolve, reject) => {
4897 if (!(element instanceof HTMLImageElement) && !(element instanceof HTMLVideoElement)) {
4898 return reject(new Error('Element must be an image or video'));
4899 }
4900
4901 if (element instanceof HTMLImageElement) {
4902 if (element.complete) {
4903 return resolve({ width: element.naturalWidth, height: element.naturalHeight });
4904 }
4905 element.addEventListener('load', () => {
4906 resolve({ width: element.naturalWidth, height: element.naturalHeight });
4907 }, { once: true });
4908 element.addEventListener('error', () => {
4909 reject(new Error('Failed to load image'));
4910 }, { once: true });
4911 } else if (element instanceof HTMLVideoElement) {
4912 if (element.readyState >= 1) {
4913 return resolve({ width: element.videoWidth, height: element.videoHeight });
4914 }
4915 element.addEventListener('loadedmetadata', () => {
4916 resolve({ width: element.videoWidth, height: element.videoHeight });
4917 }, { once: true });
4918 element.addEventListener('error', () => {
4919 reject(new Error('Failed to load video'));
4920 }, { once: true });
4921 }
4922 });
4923 }
4924
4925 function getMaxDimensions(element) {
4926 const computedStyle = window.getComputedStyle(element);
4927 const maxWidth = computedStyle.maxWidth;
4928 const maxHeight = computedStyle.maxHeight;
4929
4930 const result = { width: null, height: null };
4931
4932 function parseCalcOrPixel(value, dimension) {
4933 // If value is in pixels, return it
4934 if (value.endsWith('px')) {
4935 return parseFloat(value);
4936 }
4937
4938 // Handle calc(100% - Npx)
4939 if (value.includes('calc')) {
4940 const match = value.match(/calc\(100% - (\d+\.?\d*?)px\)/);
4941 if (match) {
4942 const subtractedPx = parseFloat(match[1]);
4943 const parent = element.parentElement;
4944 if (dimension === 'width') {
4945 return parent ? parent.getBoundingClientRect().width - subtractedPx : window.innerWidth - subtractedPx;
4946 } else if (dimension === 'height') {
4947 return parent ? parent.getBoundingClientRect().height - subtractedPx : window.innerHeight - subtractedPx;
4948 }
4949 }
4950 }
4951
4952 return false; // Fallback
4953 }
4954
4955 // Calculate max-width and max-height in pixels
4956 result.width = parseCalcOrPixel(maxWidth, 'width');
4957 result.height = parseCalcOrPixel(maxHeight, 'height');
4958
4959 return result;
4960 }
4961
4962 async function fitToWindow() {
4963 const max = getMaxDimensions(lastAttachment);
4964 const lastAttachmentContent = lastAttachment.querySelector('.DLP_Attachment_Box_1_Content');
4965 const orig = await getElementDimensions(lastAttachmentContent);
4966 const scale = Math.min(max.width / orig.width, max.height / orig.height);
4967
4968 const w = Math.floor(orig.width * scale);
4969 const h = Math.floor(orig.height * scale);
4970 lastAttachment.style.width = `${w}px`;
4971 lastAttachment.style.height = `${h}px`;
4972 }
4973
4974 lastAttachment.addEventListener('mouseenter', () => {
4975 if (expanded) return;
4976 lastAttachment.querySelector('.DLP_Attachment_Box_1_Hover').style.display = '';
4977 });
4978 lastAttachment.addEventListener('mouseleave', () => {
4979 if (expanded) return;
4980 lastAttachment.querySelector('.DLP_Attachment_Box_1_Hover').style.display = 'none';
4981 });
4982 lastAttachment.querySelector('.DLP_Attachment_Box_1_Hover p').addEventListener('click', async () => {
4983 expanded = true;
4984 lastAttachment.querySelector('.DLP_Attachment_Box_1_Hover').style.display = 'none';
4985
4986 let pos = getElementPosition(lastAttachment);
4987 const tempHover = document.createElement('div');
4988 tempHover.style.width = pos.width + 'px';
4989 tempHover.style.height = pos.height + 'px';
4990 tempHover.style.opacity = '0';
4991
4992 // append tempHover right before lastAttachment
4993 lastAttachment.parentNode.insertBefore(tempHover, lastAttachment);
4994
4995 const largeViewMotherBox = document.createElement('div');
4996 largeViewMotherBox.className = 'DLP_Attachment_Box_Large_View_1';
4997 document.body.appendChild(largeViewMotherBox);
4998
4999 let closeBtn = `
5000 <div style="display: flex; padding: 2px; justify-content: center; align-items: center; gap: 6px; opacity: 0.5; position: absolute; bottom: 24px; pointer-events: none;">
5001 <p class="DLP_Text_Style_1 DLP_NoSelect"></p>
5002 <p class="DLP_Text_Style_1 DLP_NoSelect">Close</p>
5003 </div>
5004 `;
5005 largeViewMotherBox.insertAdjacentHTML('beforeend', closeBtn);
5006
5007 function getTransformToMatchPosition(element) {
5008 const parentRect = largeViewMotherBox.getBoundingClientRect();
5009 const centerX = parentRect.width / 2;
5010 const centerY = parentRect.height / 2;
5011 const elementRect = element.getBoundingClientRect();
5012 const elementCenterX = elementRect.width / 2;
5013 const elementCenterY = elementRect.height / 2;
5014 const shiftX = pos.left + elementCenterX - centerX;
5015 const shiftY = pos.top + elementCenterY - centerY;
5016 return { translateX: shiftX, translateY: shiftY };
5017 }
5018
5019 largeViewMotherBox.appendChild(lastAttachment);
5020
5021 translate = getTransformToMatchPosition(lastAttachment);
5022
5023 lastAttachment.style.transform = `translate(${translate.translateX}px, ${translate.translateY}px)`;
5024 void lastAttachment.offsetHeight;
5025
5026 lastAttachment.style.transition = '0.4s cubic-bezier(0.16, 1, 0.32, 1)';
5027
5028 void lastAttachment.offsetHeight;
5029
5030 lastAttachment.style.transform = 'translate(0px, 0px)';
5031
5032 largeViewMotherBox.style.background = 'rgba(var(--color-snow), 0.50)';
5033 largeViewMotherBox.style.backdropFilter = 'blur(16px)';
5034
5035 lastAttachment.style.aspectRatio = 'unset';
5036
5037 let lastAttachmentContent = lastAttachment.querySelector('.DLP_Attachment_Box_1_Content');
5038
5039 lastAttachmentContent.style.aspectRatio = 'unset';
5040 lastAttachmentContent.style.maxWidth = '100%';
5041 lastAttachmentContent.style.maxHeight = '100%';
5042 lastAttachmentContent.style.width = 'auto';
5043 lastAttachmentContent.style.height = 'auto';
5044
5045 lastAttachment.style.maxWidth = 'calc(100% - 32px)';
5046 lastAttachment.style.maxHeight = 'calc(100% - 142px)';
5047
5048 lastAttachment.style.display = 'inline-flex';
5049
5050 lastAttachment.style.width = 'auto';
5051 lastAttachment.style.height = 'auto';
5052
5053 void lastAttachment.offsetHeight;
5054
5055 const maxDimensions = getMaxDimensions(lastAttachment);
5056 const elementDimensions = await getElementDimensions(lastAttachmentContent);
5057
5058 // compute uniform scale to fit within maxDimensions
5059 const scale = Math.min(maxDimensions.width / elementDimensions.width, maxDimensions.height / elementDimensions.height);
5060
5061 // calculate final pixel dimensions
5062 let newWidth = Math.floor(elementDimensions.width * scale);
5063 let newHeight = Math.floor(elementDimensions.height * scale);
5064
5065 //let newWidth = lastAttachmentContent.offsetWidth;
5066 //let newHeight = lastAttachmentContent.offsetHeight;
5067
5068 lastAttachment.style.width = '';
5069 lastAttachment.style.height = '';
5070
5071 void lastAttachment.offsetHeight;
5072
5073 lastAttachment.style.width = newWidth + 'px';
5074 lastAttachment.style.height = newHeight + 'px';
5075
5076 lastAttachmentContent.style.width = '100%';
5077 lastAttachmentContent.style.height = '100%';
5078
5079 if (lastAttachmentContent.tagName.toLowerCase() === 'video') {
5080 lastAttachmentContent.controls = true;
5081 lastAttachmentContent.autoplay = false;
5082 lastAttachmentContent.muted = false;
5083 lastAttachmentContent.currentTime = 0;
5084 lastAttachmentContent.play();
5085 }
5086
5087 window.addEventListener('resize', fitToWindow);
5088
5089 largeViewMotherBox.addEventListener('click', (event) => {
5090 if (largeViewMotherBox === event.target && lastAttachment !== event.target) {
5091 window.removeEventListener('resize', fitToWindow);
5092
5093 if (lastAttachmentContent.tagName.toLowerCase() === 'video') {
5094 lastAttachmentContent.controls = false;
5095 lastAttachmentContent.autoplay = true;
5096 lastAttachmentContent.muted = true;
5097 lastAttachmentContent.play();
5098 }
5099
5100 lastAttachment.style.transform = `translate(${translate.translateX}px, ${translate.translateY}px)`;
5101 lastAttachment.style.width = pos.width + 'px';
5102 lastAttachment.style.height = pos.height + 'px';
5103
5104 largeViewMotherBox.style.background = 'rgba(var(--color-snow), 0.00)';
5105 largeViewMotherBox.style.backdropFilter = 'blur(0px)';
5106
5107 setTimeout(() => {
5108 tempHover.parentNode.insertBefore(lastAttachment, tempHover);
5109 lastAttachment.style.transform = '';
5110 tempHover.remove();
5111 largeViewMotherBox.remove();
5112
5113 lastAttachment.style.aspectRatio = '';
5114 lastAttachment.querySelector('.DLP_Attachment_Box_1_Content').style.aspectRatio = '';
5115 lastAttachment.querySelector('.DLP_Attachment_Box_1_Content').style.maxWidth = '';
5116 lastAttachment.querySelector('.DLP_Attachment_Box_1_Content').style.maxHeight = '';
5117 lastAttachment.querySelector('.DLP_Attachment_Box_1_Content').style.width = '';
5118 lastAttachment.querySelector('.DLP_Attachment_Box_1_Content').style.height = '';
5119
5120 lastAttachment.style.maxWidth = '';
5121 lastAttachment.style.maxHeight = '';
5122
5123 lastAttachment.style.display = '';
5124
5125 lastAttachment.style.transition = '';
5126 void lastAttachment.offsetHeight;
5127
5128 expanded = false;
5129 }, 400);
5130 }
5131 });
5132 });
5133 }
5134
5135 async function createAttachmentMessage(message) {
5136 async function contentType(url) {
5137 const imageExts = ['jpg','jpeg','png','gif','webp','bmp','svg'];
5138 const videoExts = ['mp4','webm','ogg','mov','m4v'];
5139
5140 let ft = '';
5141 try {
5142 const u = new URL(url);
5143 ft = (u.searchParams.get('filetype') || '').toLowerCase();
5144 } catch (e) {
5145 const qs = url.split('?')[1] || '';
5146 const match = qs.match(/(?:^|&)filetype=([^&]+)/i);
5147 ft = match ? decodeURIComponent(match[1]).toLowerCase() : '';
5148 }
5149 if (imageExts.includes(ft)) return 'image';
5150 if (videoExts.includes(ft)) return 'video';
5151
5152 // 3) give up
5153 return 'other';
5154 }
5155
5156 if (message.files.length > 0) {
5157 const temp2 = document.createElement('div');
5158 temp2.innerHTML = `
5159 <div data-message-id="${messageKey}" data-message-sent="${message.send_time ?? ''}"${isTemp ? ` data-is-temp="${isTemp}"` : ''} class="DLP_Hide_Scrollbar" style="display: flex; align-items: center; gap: 8px; align-self: stretch; width: 100%; overflow-y: scroll; opacity: 1; filter: blur(0px); margin-top: 0px; transition: 0.4s cubic-bezier(0.16, 1, 0.32, 1);${failedTemp ? ' color: rgba(var(--DLP-pink));' : ''}"></div>
5160 `;
5161 const newElement2 = temp2.firstElementChild;
5162 lastChatChild.appendChild(newElement2);
5163 let attachmentParent = lastChatChild.lastElementChild;
5164 for (let i = 0; i < message.files.length; i++) {
5165 const file = message.files[i];
5166 const temp = document.createElement('div');
5167 let extensionType = await contentType(file);
5168 if (extensionType === 'image') {
5169 temp.innerHTML = `
5170 <div class="DLP_Attachment_Box_1" data-preview-src="${file}">
5171 <img class="DLP_Attachment_Box_1_Content" src="${file}">
5172 <div class="DLP_Attachment_Box_1_Hover" style="display: none;">
5173 <p class="DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect"></p>
5174 </div>
5175 </div>
5176 `;
5177 } else if (extensionType === 'video') {
5178 temp.innerHTML = `
5179 <div class="DLP_Attachment_Box_1" data-preview-src="${file}">
5180 <video class="DLP_Attachment_Box_1_Content" src="${file}" muted autoplay loop></video>
5181 <div class="DLP_Attachment_Box_1_Hover" style="display: none;">
5182 <p class="DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect"></p>
5183 </div>
5184 </div>
5185 `;
5186 } else {
5187 temp.innerHTML = `
5188 <div class="DLP_Attachment_Box_1" data-preview-src="${file}">
5189 <div style="display: flex; width: 100%; height: 100%; padding-top: 6px; flex-direction: column; justify-content: center; align-items: center; gap: 6px; flex-shrink: 0;">
5190 <p class="DLP_Text_Style_1 DLP_NoSelect" style="font-size: 24px;"></p>
5191 <p class="DLP_Text_Style_1 DLP_NoSelect">File</p>
5192 </div>
5193 <div class="DLP_Attachment_Box_1_Hover" style="display: none;">
5194 <p class="DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect"></p>
5195 </div>
5196 </div>
5197 `;
5198 }
5199 const newElement = temp.firstElementChild;
5200 attachmentParent.appendChild(newElement);
5201
5202 expandAttachment(newElement);
5203 }
5204 }
5205 }
5206
5207 const sameAuthor = lastChatChild !== null && message.author === lastChatChild.getAttribute('data-author-name');
5208 const messageHasReply = hasNumericReply(message);
5209
5210 if (sameAuthor && !messageHasReply) {
5211 createContinuationMessage(message);
5212 } else {
5213 createStartersMessage(message);
5214 }
5215 }
5216
5217 async function intelligentLeaderboardBasedWarningLimit() {
5218 const defaultBoardId = "7d9f5dd1-8423-491a-91f2-2532052038ce";
5219 const tournamentBoardId = "4b668ba6-288d-4b78-81a3-7b213175ae2c";
5220 const baseUrl = "https://duolingo-leaderboards-prod.duolingo.com/leaderboards/";
5221
5222 function getDuolingoUserIdFromJwt(token) {
5223 try {
5224 const p = token.split('.')[1];
5225 const decoded = decodeURIComponent(atob(p.replace(/-/g, '+').replace(/_/g, '/').padEnd(p.length + (4 - p.length % 4) % 4, '=')).split('').map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join(''));
5226 return JSON.parse(decoded).sub;
5227 } catch (e) {
5228 console.error("Failed to decode JWT:", e);
5229 return null;
5230 }
5231 }
5232
5233 function processLeaderboardData(data, userId) {
5234 if (!data || !data.active || !data.active.cohort || !data.active.cohort.rankings) {
5235 console.log("Chosen leaderboard data is invalid or inactive.");
5236 return null;
5237 }
5238
5239 const rankings = data.active.cohort.rankings;
5240 const topN = 5;
5241 const topScores = [...rankings].sort((a, b) => b.score - a.score).slice(0, topN).map(user => user.score);
5242
5243 const userRanking = rankings.find(u => u.user_id === userId);
5244 const userScore = userRanking ? userRanking.score : 0;
5245 const avgTopScore = topScores.length ? Math.round(topScores.reduce((sum, val) => sum + val, 0) / topScores.length) : 0;
5246
5247 const intelligentAmount = Math.max(0, avgTopScore - userScore);
5248
5249 console.log(`Using leaderboard: ${data.active.contest.contest_id}`);
5250 console.log(`Average top ${topN} score:`, avgTopScore);
5251 console.log(`Your score:`, userScore);
5252 console.log(`Calculated intelligent warning limit:`, intelligentAmount);
5253
5254 return intelligentAmount;
5255 }
5256
5257 const jwtToken = document.cookie.split('; ').find(cookie => cookie.startsWith('jwt_token='))?.split('=')[1];
5258 if (!jwtToken) {
5259 console.error("JWT token not found. Cannot proceed.");
5260 return null;
5261 }
5262
5263 const userID = getDuolingoUserIdFromJwt(jwtToken);
5264 if (!userID) {
5265 console.error("Could not extract User ID from JWT.");
5266 return null;
5267 }
5268
5269 const spedTimestamp = Date.now();
5270 const fetchOptions = {
5271 method: 'GET',
5272 headers: {
5273 'Content-Type': 'application/json',
5274 'Authorization': `Bearer ${jwtToken}`,
5275 },
5276 };
5277
5278 try {
5279 const [tournamentResult, defaultResult] = await Promise.allSettled([
5280 fetch(`${baseUrl}${tournamentBoardId}/users/${userID}?_=${spedTimestamp}`, fetchOptions).then(res => res.json()),
5281 fetch(`${baseUrl}${defaultBoardId}/users/${userID}?_=${spedTimestamp}`, fetchOptions).then(res => res.json()),
5282 ]);
5283
5284 let selectedData = null;
5285
5286 if (tournamentResult.status === 'fulfilled' && tournamentResult.value.active) {
5287 console.log("Tournament leaderboard is active. Using it for calculation.");
5288 selectedData = tournamentResult.value;
5289 } else if (defaultResult.status === 'fulfilled' && defaultResult.value.active) {
5290 console.log("Default leaderboard is active. Using it for calculation.");
5291 selectedData = defaultResult.value;
5292 } else {
5293 console.log("No active leaderboards found (neither tournament nor default).");
5294 if (tournamentResult.status === 'rejected') console.error("Tournament fetch failed:", tournamentResult.reason);
5295 if (defaultResult.status === 'rejected') console.error("Default fetch failed:", defaultResult.reason);
5296 return null;
5297 }
5298
5299 const intelligentAmount = processLeaderboardData(selectedData, userID);
5300 // return intelligentAmount ?? null;
5301 return 20;
5302 } catch (error) {
5303 console.error("An unexpected error occurred during the fetch process:", error);
5304 return null;
5305 }
5306 }
5307
5308 function updateReleaseNotes(warnings) {
5309 const releaseNotesContainer = document.getElementById('DLP_Release_Notes_List_1_ID');
5310 const controlsContainer = document.getElementById('DLP_Release_Notes_Controls');
5311 const warningCounterDisplay = controlsContainer.querySelector('.DLP_Inset_Text_1_ID');
5312 const prevButton = controlsContainer.querySelector('.DLP_Inset_Icon_1_ID');
5313 const nextButton = controlsContainer.querySelector('.DLP_Inset_Icon_2_ID');
5314
5315 releaseNotesContainer.innerHTML = '';
5316
5317 let currentWarningIndex = 0;
5318 const totalWarnings = warnings.length;
5319
5320 function updateCounterDisplay(current, total, displayElement) {
5321 displayElement.textContent = `${current}/${total}`;
5322 }
5323
5324 function updateButtonOpacity(current, total, prevButton, nextButton) {
5325 if (current === 0) {
5326 prevButton.style.opacity = '0.5';
5327 prevButton.style.pointerEvents = 'none';
5328 } else {
5329 prevButton.style.opacity = '1';
5330 prevButton.style.pointerEvents = 'auto';
5331 }
5332
5333 if (current === total - 1) {
5334 nextButton.style.opacity = '0.5';
5335 nextButton.style.pointerEvents = 'none';
5336 } else {
5337 nextButton.style.opacity = '1';
5338 nextButton.style.pointerEvents = 'auto';
5339 }
5340 }
5341
5342 warnings.forEach((warning, index) => {
5343 if (warning.head && warning.body && warning.icon) {
5344 const warningHTML = `
5345 <div id="warning-${index}" style="display: ${index === 0 ? 'flex' : 'none'}; flex-direction: column; justify-content: center; align-items: center; gap: 8px; align-self: stretch; transition: filter 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94), opacity 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);">
5346 <div style="display: flex; flex-direction: column; align-items: center; gap: 4px;">
5347 ${warning.icon}
5348 <p class="DLP_Text_Style_2">${warning.head}</p>
5349 <p class="DLP_Text_Style_1" style="background: url(${serverURL}/static/images/flow/secondary/512/light.png) lightgray 50% / cover no-repeat; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${warning.tag}</p>
5350 </div>
5351 <p class="DLP_Text_Style_1" style="text-align: center;">${warning.body}</p>
5352 </div>
5353 `;
5354 releaseNotesContainer.insertAdjacentHTML('beforeend', warningHTML);
5355 }
5356 });
5357
5358 updateCounterDisplay(currentWarningIndex + 1, totalWarnings, warningCounterDisplay);
5359 updateButtonOpacity(currentWarningIndex, totalWarnings, prevButton, nextButton);
5360
5361 prevButton.addEventListener('click', () => {
5362 if (isBusySwitchingPages) return;
5363 isBusySwitchingPages = true;
5364 if (currentWarningIndex > 0) {
5365 const oldWarning = document.getElementById(`warning-${currentWarningIndex}`);
5366 const newWarning = document.getElementById(`warning-${currentWarningIndex - 1}`);
5367
5368 oldWarning.style.filter = 'blur(16px)';
5369 oldWarning.style.opacity = '0';
5370 newWarning.style.filter = 'blur(16px)';
5371 newWarning.style.opacity = '0';
5372
5373 setTimeout(() => {
5374 oldWarning.style.display = 'none';
5375 newWarning.style.display = 'flex';
5376 newWarning.offsetHeight;
5377 newWarning.style.filter = 'blur(0px)';
5378 newWarning.style.opacity = '1';
5379 currentWarningIndex--;
5380 updateCounterDisplay(currentWarningIndex + 1, totalWarnings, warningCounterDisplay);
5381 updateButtonOpacity(currentWarningIndex, totalWarnings, prevButton, nextButton);
5382 setTimeout(() => {
5383 isBusySwitchingPages = false;
5384 }, 400);
5385 }, 400);
5386 }
5387 });
5388
5389 nextButton.addEventListener('click', () => {
5390 if (isBusySwitchingPages) return;
5391 isBusySwitchingPages = true;
5392 if (currentWarningIndex < totalWarnings - 1) {
5393 const oldWarning = document.getElementById(`warning-${currentWarningIndex}`);
5394 const newWarning = document.getElementById(`warning-${currentWarningIndex + 1}`);
5395 oldWarning.style.filter = 'blur(16px)';
5396 oldWarning.style.opacity = '0';
5397 newWarning.style.filter = 'blur(16px)';
5398 newWarning.style.opacity = '0';
5399
5400 setTimeout(() => {
5401 oldWarning.style.display = 'none';
5402 newWarning.style.display = 'flex';
5403 newWarning.offsetHeight;
5404 newWarning.style.filter = 'blur(0px)';
5405 newWarning.style.opacity = '1';
5406 currentWarningIndex++;
5407 updateCounterDisplay(currentWarningIndex + 1, totalWarnings, warningCounterDisplay);
5408 updateButtonOpacity(currentWarningIndex, totalWarnings, prevButton, nextButton);
5409 setTimeout(() => {
5410 isBusySwitchingPages = false;
5411 }, 400);
5412 }, 400);
5413 }
5414 });
5415 }
5416
5417 let DLP_Feedback_Text_Input_1_ID = document.getElementById("DLP_Feedback_Text_Input_1_ID");
5418 let DLP_Feedback_Type_Bug_Report_Button_1_ID = document.getElementById("DLP_Feedback_Type_Bug_Report_Button_1_ID");
5419 let DLP_Feedback_Type_Suggestion_Button_1_ID = document.getElementById("DLP_Feedback_Type_Suggestion_Button_1_ID");
5420 let DLP_Feedback_Attachment_Upload_Button_1_ID = document.getElementById("DLP_Feedback_Attachment_Upload_Button_1_ID");
5421 let DLP_Feedback_Attachment_Input_Hidden_1_ID = document.getElementById("DLP_Feedback_Attachment_Input_Hidden_1_ID");
5422 let DLP_Feedback_Send_Button_1_ID = document.getElementById("DLP_Feedback_Send_Button_1_ID");
5423
5424 let sendFeedbackStatus = '';
5425 DLP_Feedback_Send_Button_1_ID.addEventListener('click', () => {
5426 if (sendFeedbackStatus !== '') return;
5427 let FeedbackText = DLP_Feedback_Text_Input_1_ID.value;
5428 sendFeedbackServer(feedbackType, FeedbackText);
5429
5430 setButtonState(DLP_Feedback_Send_Button_1_ID, {button: 'linear-gradient(0deg, rgba(var(--DLP-blue), 0.10) 0%, rgba(var(--DLP-blue), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))'}, {text: systemText[systemLanguage][111], icon: ''}, {text: '', icon: 'DLP_Rotate_360_Animation_1 4s ease-in-out infinite'}, () => {
5431 function f() {
5432 if (sendFeedbackStatus === 'sent') {
5433 setButtonState(DLP_Feedback_Send_Button_1_ID, {button: 'linear-gradient(0deg, rgba(var(--DLP-green), 0.10) 0%, rgba(var(--DLP-green), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-green), 0.20)', text: 'rgb(var(--DLP-green))', icon: 'rgb(var(--DLP-green))'}, {text: systemText[systemLanguage][112], icon: ''}, {text: '', icon: ' '}, () => {
5434 confetti();
5435 });
5436 } else if (sendFeedbackStatus === 'error') {
5437 setButtonState(DLP_Feedback_Send_Button_1_ID, {button: 'linear-gradient(0deg, rgba(var(--DLP-pink), 0.10) 0%, rgba(var(--DLP-pink), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-pink), 0.20)', text: 'rgb(var(--DLP-pink))', icon: 'rgb(var(--DLP-pink))'}, {text: systemText[systemLanguage][115], icon: ''}, {text: '', icon: ' '}, () => {
5438 });
5439 } else if (sendFeedbackStatus === 'sending') {
5440 setTimeout(() => { f(); }, 800);
5441 }
5442 }
5443 f();
5444 });
5445 });
5446
5447 let feedbackType = 'Suggestion';
5448 DLP_Feedback_Type_Bug_Report_Button_1_ID.addEventListener('click', () => {
5449 feedbackType = 'Bug Report';
5450 DLP_Feedback_Type_Bug_Report_Button_1_ID.classList.add('DLP_Feedback_Type_Button_Style_1_ON');
5451 DLP_Feedback_Type_Bug_Report_Button_1_ID.classList.remove('DLP_Feedback_Type_Button_Style_1_OFF');
5452 DLP_Feedback_Type_Suggestion_Button_1_ID.classList.add('DLP_Feedback_Type_Button_Style_2_OFF');
5453 DLP_Feedback_Type_Suggestion_Button_1_ID.classList.remove('DLP_Feedback_Type_Button_Style_2_ON');
5454 });
5455 DLP_Feedback_Type_Suggestion_Button_1_ID.addEventListener('click', () => {
5456 feedbackType = 'Suggestion';
5457 DLP_Feedback_Type_Bug_Report_Button_1_ID.classList.add('DLP_Feedback_Type_Button_Style_1_OFF');
5458 DLP_Feedback_Type_Bug_Report_Button_1_ID.classList.remove('DLP_Feedback_Type_Button_Style_1_ON');
5459 DLP_Feedback_Type_Suggestion_Button_1_ID.classList.add('DLP_Feedback_Type_Button_Style_2_ON');
5460 DLP_Feedback_Type_Suggestion_Button_1_ID.classList.remove('DLP_Feedback_Type_Button_Style_2_OFF');
5461 });
5462 let currentFileName = '';
5463 setInterval(() => {
5464 if (DLP_Feedback_Attachment_Input_Hidden_1_ID.files.length > 0) {
5465 let fileName = DLP_Feedback_Attachment_Input_Hidden_1_ID.files[0].name;
5466 if (currentFileName === fileName) return;
5467 currentFileName = fileName;
5468 DLP_Feedback_Attachment_Upload_Button_1_ID.querySelector('.DLP_Inset_Text_1_ID').style.filter = 'blur(4px)';
5469 DLP_Feedback_Attachment_Upload_Button_1_ID.querySelector('.DLP_Inset_Text_1_ID').style.opacity = '0';
5470 DLP_Feedback_Attachment_Upload_Button_1_ID.querySelector('.DLP_Inset_Icon_1_ID').style.filter = 'blur(4px)';
5471 DLP_Feedback_Attachment_Upload_Button_1_ID.querySelector('.DLP_Inset_Icon_1_ID').style.opacity = '0';
5472 DLP_Feedback_Attachment_Upload_Button_1_ID.style.background = 'rgb(var(--DLP-blue))';
5473 DLP_Feedback_Attachment_Upload_Button_1_ID.style.outline = '2px solid rgba(0, 0, 0, 0.20)';
5474 setTimeout(() => {
5475 DLP_Feedback_Attachment_Upload_Button_1_ID.querySelector('.DLP_Inset_Icon_1_ID').style.display = 'none';
5476 DLP_Feedback_Attachment_Upload_Button_1_ID.querySelector('.DLP_Inset_Text_1_ID').textContent = fileName;
5477 DLP_Feedback_Attachment_Upload_Button_1_ID.querySelector('.DLP_Inset_Text_1_ID').style.color = '#FFF';
5478 DLP_Feedback_Attachment_Upload_Button_1_ID.querySelector('.DLP_Inset_Text_1_ID').style.filter = '';
5479 DLP_Feedback_Attachment_Upload_Button_1_ID.querySelector('.DLP_Inset_Text_1_ID').style.opacity = '';
5480 }, 400);
5481 }
5482 }, 1000);
5483 DLP_Feedback_Attachment_Upload_Button_1_ID.addEventListener('click', () => {
5484 DLP_Feedback_Attachment_Input_Hidden_1_ID.click();
5485 });
5486
5487 DLP_Feedback_Send_Button_1_ID.style.pointerEvents = 'none';
5488 DLP_Feedback_Send_Button_1_ID.style.opacity = '0.5';
5489 DLP_Feedback_Text_Input_1_ID.addEventListener("input", function () {
5490 if (DLP_Feedback_Text_Input_1_ID.value.replace(/\s/g, "").length <= 16) {
5491 DLP_Feedback_Send_Button_1_ID.style.pointerEvents = 'none';
5492 DLP_Feedback_Send_Button_1_ID.style.opacity = '0.5';
5493 } else {
5494 DLP_Feedback_Send_Button_1_ID.style.pointerEvents = '';
5495 DLP_Feedback_Send_Button_1_ID.style.opacity = '';
5496 }
5497 });
5498 async function sendFeedbackServer(head, body) {
5499 try {
5500 sendFeedbackStatus = 'sending';
5501
5502 let payload = {
5503 head: head,
5504 body: body,
5505 version: versionFormal
5506 };
5507
5508 if (DLP_Feedback_Attachment_Input_Hidden_1_ID.files.length > 0) {
5509 const file = DLP_Feedback_Attachment_Input_Hidden_1_ID.files[0];
5510 const base64File = await new Promise((resolve) => {
5511 const reader = new FileReader();
5512 reader.onloadend = () => {
5513 resolve(reader.result);
5514 };
5515 reader.readAsDataURL(file);
5516 });
5517 payload.file = base64File;
5518 }
5519
5520 const response = await fetch(apiURL + "/feedback", {
5521 method: 'POST',
5522 headers: {
5523 'Content-Type': 'application/json',
5524 'Authorization': `Bearer ${document.cookie.split(';').find(cookie => cookie.includes('jwt_token')).split('=')[1]}`
5525 },
5526 body: JSON.stringify(payload)
5527 });
5528
5529 const responseData = await response.json();
5530
5531 if (responseData.status) sendFeedbackStatus = 'sent';
5532 else sendFeedbackStatus = 'error';
5533
5534 showNotification(responseData.notification.icon, responseData.notification.head, responseData.notification.body, responseData.notification.duration);
5535 } catch (error) {
5536 console.error('Error:', error);
5537 sendFeedbackStatus = 'error';
5538 showNotification("error", systemText[systemLanguage][206], systemText[systemLanguage][207], 30);
5539 }
5540 }
5541
5542
5543 async function handleClick(button, id, amount) {
5544 const ANIM_MS = 820;
5545 let status = 'loading';
5546
5547 const loadingStart = Date.now();
5548 setButtonState(
5549 button,
5550 { button: 'rgba(var(--DLP-blue), 0.10)', outline: 'rgba(var(--DLP-blue), 0.20)', text: 'rgb(var(--DLP-blue))', icon: 'rgb(var(--DLP-blue))' },
5551 { text: systemText[systemLanguage][113], icon: '' },
5552 { text: '', icon: 'DLP_Rotate_360_Animation_1 4s ease-in-out infinite' }
5553 );
5554 let nextAnimationEndsAt = loadingStart + ANIM_MS;
5555
5556 setTimeout(() => { f(); }, Math.max(0, nextAnimationEndsAt - Date.now()));
5557
5558 try {
5559 if (flag03) {
5560 const intelligentAmount = await intelligentLeaderboardBasedWarningLimit();
5561 console.log(`Intelligent amount: ${intelligentAmount}`);
5562
5563 const overrideXp = button.dataset.overrideXp === 'true';
5564 if (id === 'xp' && amount > intelligentAmount && !overrideXp) {
5565 button.dataset.overrideXp = 'true';
5566
5567 showNotification(
5568 'warning',
5569 'That is a lot of XP...',
5570 `You're about to gain more XP than recommended. Click CONFIRM to continue.`,
5571 10
5572 );
5573
5574 const elapsed = Date.now() - loadingStart;
5575 const delay = Math.max(0, ANIM_MS - elapsed);
5576 setTimeout(() => {
5577 setButtonState(
5578 button,
5579 { button: 'rgb(var(--DLP-blue))', outline: 'rgba(0, 0, 0, 0.20)', text: '#FFF', icon: '#FFF' },
5580 { text: 'CONFIRM', icon: '' },
5581 { text: '', icon: '' }
5582 );
5583 nextAnimationEndsAt = Date.now() + ANIM_MS;
5584 }, delay);
5585
5586 // Keep status 'loading' so the poller waits until the user confirms or cancels
5587 return;
5588 }
5589
5590 // Reset the override flag when actually proceeding
5591 button.dataset.overrideXp = 'false';
5592 }
5593
5594 const response = await fetch(apiURL + '/request', {
5595 method: 'POST',
5596 headers: {
5597 'Content-Type': 'application/json',
5598 'Authorization': `Bearer ${document.cookie.split(';').find(cookie => cookie.includes('jwt_token')).split('=')[1]}`
5599 },
5600 body: JSON.stringify({ type: id, amount, version: versionFull })
5601 });
5602
5603 if (!response.ok) throw new Error('Request failed with status ' + response.status);
5604
5605 const reader = response.body.getReader();
5606 const decoder = new TextDecoder();
5607 let done = false;
5608 let buffer = '';
5609
5610 while (!done) {
5611 const { value, done: doneReading } = await reader.read();
5612 done = doneReading;
5613 buffer += decoder.decode(value, { stream: true });
5614
5615 let openBraces = 0;
5616 let start = 0;
5617
5618 for (let i = 0; i < buffer.length; i++) {
5619 const ch = buffer[i];
5620
5621 if (ch === '{') {
5622 openBraces++;
5623 } else if (ch === '}') {
5624 openBraces--;
5625
5626 if (openBraces === 0) {
5627 const jsonStr = buffer.substring(start, i + 1).trim();
5628
5629 try {
5630 const data = JSON.parse(jsonStr);
5631
5632 if (data.status === 'completed') {
5633 status = 'done';
5634 done = true;
5635 showNotification(data.notification.icon, data.notification.head, data.notification.body, data.notification.duration);
5636
5637 if (storageLocal.stats.tracking_since === 0) storageLocal.stats.tracking_since = Date.now();
5638 storageLocal.stats.modern[id] += amount;
5639 saveStorageLocal();
5640
5641 const input = button.parentElement.querySelector('#DLP_Inset_Input_1_ID');
5642 if (input) {
5643 input.value = '';
5644 setTimeout(() => input.dispatchEvent(new Event('input')), 2400);
5645 }
5646 } else if (data.status == 'failed') {
5647 status = 'error';
5648 done = true;
5649 showNotification(data.notification.icon, data.notification.head, data.notification.body, data.notification.duration);
5650 console.log(data);
5651 } else if (data.status === 'rejected') {
5652 status = 'rejected';
5653 done = true;
5654 showNotification(data.notification.icon, data.notification.head, data.notification.body, data.notification.duration);
5655
5656 const input = button.parentElement.querySelector('#DLP_Inset_Input_1_ID');
5657 if (data.max_amount && input) {
5658 input.value = data.max_amount;
5659 setTimeout(() => input.dispatchEvent(new Event('input')), 2400);
5660 }
5661 } else {
5662 console.log(`Percentage: ${data.percentage}%`);
5663 button.querySelector('.DLP_Inset_Text_1_ID').innerHTML = data.percentage + '%';
5664 }
5665
5666 // Trim processed chunk and reset counters
5667 buffer = buffer.substring(i + 1);
5668 i = -1;
5669 start = 0;
5670 openBraces = 0;
5671 } catch (e) {
5672 // ignore and continue streaming
5673 }
5674 }
5675 } else if (openBraces === 0 && buffer[i].trim() !== '') {
5676 start = i;
5677 }
5678 }
5679 }
5680 } catch (error) {
5681 console.error('Error during request:', error);
5682 status = 'error';
5683 }
5684
5685 function f() {
5686 const now = Date.now();
5687
5688 // If an animation is still running, wait precisely until it ends
5689 if (now < nextAnimationEndsAt) {
5690 setTimeout(() => { f(); }, nextAnimationEndsAt - now);
5691 return;
5692 }
5693
5694 if (status === 'done') {
5695 setButtonState(
5696 button,
5697 { button: 'rgba(var(--DLP-green), 0.10)', outline: 'rgba(var(--DLP-green), 0.20)', text: 'rgb(var(--DLP-green))', icon: 'rgb(var(--DLP-green))' },
5698 { text: systemText[systemLanguage][114], icon: '' },
5699 { text: '', icon: '' }
5700 );
5701 nextAnimationEndsAt = Date.now() + ANIM_MS;
5702
5703 confetti();
5704 setTimeout(() => {
5705 let buttonContentText = systemText[systemLanguage][9];
5706 if (id === 'super' || id === 'double_xp_boost') buttonContentText = systemText[systemLanguage][13];
5707 else if (id === 'heart_refill') buttonContentText = systemText[systemLanguage][229];
5708 setButtonState(
5709 button,
5710 { button: 'rgb(var(--DLP-blue))', outline: 'rgba(0, 0, 0, 0.20)', text: '#FFF', icon: '#FFF' },
5711 { text: buttonContentText, icon: '' },
5712 { text: '', icon: '' }
5713 );
5714 nextAnimationEndsAt = Date.now() + ANIM_MS;
5715
5716 setTimeout(() => { isGetButtonsBusy = false; }, ANIM_MS);
5717 }, (ANIM_MS * 2));
5718
5719 } else if (status === 'error') {
5720 setButtonState(
5721 button,
5722 { button: 'rgb(var(--DLP-pink))', outline: 'rgba(0, 0, 0, 0.20)', text: '#FFF', icon: '#FFF' },
5723 { text: systemText[systemLanguage][115], icon: '' },
5724 { text: '', icon: '' }
5725 );
5726 nextAnimationEndsAt = Date.now() + ANIM_MS;
5727
5728 setTimeout(() => {
5729 setButtonState(
5730 button,
5731 { button: 'rgb(var(--DLP-blue))', outline: 'rgba(0, 0, 0, 0.20)', text: '#FFF', icon: '#FFF' },
5732 { text: systemText[systemLanguage][9], icon: '' },
5733 { text: '', icon: '' }
5734 );
5735 nextAnimationEndsAt = Date.now() + ANIM_MS;
5736
5737 setTimeout(() => { isGetButtonsBusy = false; }, ANIM_MS);
5738 }, (ANIM_MS * 2));
5739
5740 } else if (status === 'rejected') {
5741 setButtonState(
5742 button,
5743 { button: 'rgb(var(--DLP-blue))', outline: 'rgba(0, 0, 0, 0.20)', text: '#FFF', icon: '#FFF' },
5744 { text: systemText[systemLanguage][9], icon: '' },
5745 { text: '', icon: '' }
5746 );
5747 nextAnimationEndsAt = Date.now() + ANIM_MS;
5748
5749 setTimeout(() => { isGetButtonsBusy = false; }, ANIM_MS);
5750
5751 } else {
5752 // Still waiting for async work or user confirmation; check again after any new animation
5753 setTimeout(() => { f(); }, ANIM_MS);
5754 }
5755 }
5756 }
5757
5758 const getButtonsList1 = [
5759 { base: 'DLP_Get_XP', type: 'xp', input: true },
5760 { base: 'DLP_Get_GEM', type: 'gem', input: true },
5761 { base: 'DLP_Get_Streak', type: 'streak', input: true },
5762 { base: 'DLP_Get_SUPER', type: 'super' },
5763 { base: 'DLP_Get_DOUBLE_XP_BOOST', type: 'double_xp_boost' },
5764 { base: 'DLP_Get_Streak_Freeze', type: 'streak_freeze', input: true },
5765 { base: 'DLP_Get_Heart_Refill', type: 'heart_refill' }
5766 ];
5767 function setupGetButtons(base, type, hasInput) {
5768 [1, 2].forEach(n => {
5769 const parent = document.getElementById(`${base}_${n}_ID`);
5770 if (!parent) return;
5771
5772 const button = parent.querySelector('#DLP_Inset_Button_1_ID');
5773 const handler = () => {
5774 if (isGetButtonsBusy && !(type === 'xp' && button.dataset.overrideXp === 'true')) return;
5775 isGetButtonsBusy = true;
5776 handleClick(button, type, hasInput ? Number(parent.querySelector('#DLP_Inset_Input_1_ID').value) : 1);
5777 };
5778
5779 button.addEventListener('click', handler);
5780
5781 if (hasInput) {
5782 const input = parent.querySelector('#DLP_Inset_Input_1_ID');
5783 input.onkeyup = e => e.keyCode === 13 && handler();
5784 }
5785 });
5786 };
5787 getButtonsList1.forEach(({ base, type, input }) => setupGetButtons(base, type, input));
5788
5789
5790 let DLP_Settings_Save_Button_1_ID = document.getElementById("DLP_Settings_Save_Button_1_ID");
5791 DLP_Settings_Save_Button_1_ID.addEventListener('click', () => {
5792 if (isBusySwitchingPages) return;
5793 isBusySwitchingPages = true;
5794 storageLocal.settings.autoUpdate = DLP_Settings_Var.autoUpdate;
5795 storageLocal.settings.showAutoServerButton = DLP_Settings_Var.showAutoServerButton;
5796 storageLocal.settings.showSolveButtons = DLP_Settings_Var.showSolveButtons;
5797 storageLocal.settings.anonymousUsageData = DLP_Settings_Var.anonymousUsageData;
5798 storageLocal.settings.solveSpeed = Number(settingsLegacySolveSpeedInputSanitizeValue(DLP_Settings_Legacy_Solve_Speed_1_ID.querySelector('#DLP_Inset_Input_1_ID').value, true));
5799 saveStorageLocal();
5800 setButtonState(DLP_Settings_Save_Button_1_ID, {button: 'linear-gradient(0deg, rgba(var(--DLP-green), 0.10) 0%, rgba(var(--DLP-green), 0.10) 100%), rgba(var(--color-snow), 0.80)', outline: 'rgba(var(--DLP-green), 0.20)', text: 'rgb(var(--DLP-green))', icon: 'rgb(var(--DLP-green))'}, {text: systemText[systemLanguage][116], icon: ''}, {text: '', icon: ' '}, () => {
5801 //confetti();
5802 setTimeout(() => {
5803 //goToPage(-1);
5804 location.reload();
5805 }, 1600);
5806 //setTimeout(() => {
5807 // setButtonState(DLP_Settings_Save_Button_1_ID, systemText[systemLanguage][37], DLP_Settings_Save_Button_1_ID.querySelector('#DLP_Inset_Icon_1_ID'), DLP_Settings_Save_Button_1_ID.querySelector('#DLP_Inset_Icon_3_ID'), 'rgb(var(--DLP-blue))', '2px solid rgba(0, 0, 0, 0.20)', '#FFF', 400);
5808 // isBusySwitchingPages = false;
5809 //}, 2400);
5810 });
5811 });
5812
5813 let DLP_Settings_Var = {
5814 autoUpdate: storageLocal.settings.autoUpdate,
5815 showAutoServerButton: storageLocal.settings.showAutoServerButton,
5816 showSolveButtons: storageLocal.settings.showSolveButtons,
5817 solveSpeed: storageLocal.settings.solveSpeed,
5818 anonymousUsageData: storageLocal.settings.anonymousUsageData
5819 };
5820 let DLP_Settings_Toggle_Busy = false;
5821 let DLP_Settings_Show_Solve_Buttons_1_ID = document.getElementById("DLP_Settings_Show_Solve_Buttons_1_ID");
5822 let DLP_Settings_Show_AutoServer_Button_1_ID = document.getElementById("DLP_Settings_Show_AutoServer_Button_1_ID");
5823 let DLP_Settings_Legacy_Solve_Speed_1_ID = document.getElementById("DLP_Settings_Legacy_Solve_Speed_1_ID");
5824 let DLP_Settings_Help_Us_Make_Better_Button_1_ID = document.getElementById("DLP_Settings_Help_Us_Make_Better_Button_1_ID");
5825 let DLP_Settings_Auto_Update_Toggle_1_ID = document.getElementById("DLP_Settings_Auto_Update_Toggle_1_ID");
5826
5827 handleToggleClick(DLP_Settings_Show_Solve_Buttons_1_ID.querySelector('#DLP_Inset_Toggle_1_ID'), DLP_Settings_Var.showSolveButtons);
5828 if (alpha) handleToggleClick(DLP_Settings_Show_AutoServer_Button_1_ID.querySelector('#DLP_Inset_Toggle_1_ID'), DLP_Settings_Var.showAutoServerButton);
5829 else DLP_Settings_Show_AutoServer_Button_1_ID.remove();
5830 handleToggleClick(DLP_Settings_Auto_Update_Toggle_1_ID.querySelector('#DLP_Inset_Toggle_1_ID'), DLP_Settings_Var.autoUpdate);
5831 handleToggleClick(DLP_Settings_Help_Us_Make_Better_Button_1_ID.querySelector('#DLP_Inset_Toggle_1_ID'), DLP_Settings_Var.anonymousUsageData);
5832 DLP_Settings_Legacy_Solve_Speed_1_ID.querySelector('#DLP_Inset_Input_1_ID').value = DLP_Settings_Var.solveSpeed;
5833
5834 DLP_Settings_Legacy_Solve_Speed_1_ID.querySelector('#DLP_Inset_Input_1_ID').addEventListener("input", function () {
5835 this.value = settingsLegacySolveSpeedInputSanitizeValue(this.value, false);
5836 });
5837 DLP_Settings_Legacy_Solve_Speed_1_ID.querySelector('#DLP_Inset_Input_1_ID').addEventListener("blur", function () {
5838 this.value = settingsLegacySolveSpeedInputSanitizeValue(this.value, true);
5839 DLP_Settings_Var.solveSpeed = Number(this.value);
5840 });
5841
5842 function settingsLegacySolveSpeedInputSanitizeValue(value, completeSanitization) {
5843 value = value.replace(/[^0-9.,]/g, '');
5844 let match = value.match(/[.,]/g);
5845 if (match && match.length > 1) {
5846 value = value.slice(0, value.lastIndexOf(match[match.length - 1]));
5847 }
5848 let decimalIndex = value.indexOf('.');
5849 if (decimalIndex !== -1) {
5850 value = value.slice(0, decimalIndex + 3);
5851 }
5852 let digitCount = value.replace(/[^0-9]/g, '').length;
5853 if (digitCount > 3) {
5854 value = value.replace(/(\d{3})\d+/, '$1');
5855 }
5856 if (/^0\d/.test(value) && !value.startsWith("0.")) {
5857 value = value.replace(/^0+/, '0');
5858 }
5859
5860 if (!completeSanitization) return value;
5861
5862 value = value.replace(',', '.');
5863 value = parseFloat(value);
5864 if (!isNaN(value)) {
5865 if (value < 0.6) value = 0.6;
5866 } else {
5867 value = 0.8;
5868 }
5869 return value;
5870 }
5871
5872
5873 function handleToggleClick(button, state) {
5874 try {
5875 let iconToChange = button.querySelector(".DLP_Inset_Icon_1_ID");
5876 iconToChange.style.transition = '0.4s';
5877
5878 void button.offsetWidth;
5879 iconToChange.style.filter = 'blur(4px)';
5880 iconToChange.style.opacity = '0';
5881
5882 if (state) {
5883 button.classList.add('DLP_Toggle_Style_1_ON');
5884 button.classList.remove('DLP_Toggle_Style_1_OFF');
5885 } else {
5886 button.classList.add('DLP_Toggle_Style_1_OFF');
5887 button.classList.remove('DLP_Toggle_Style_1_ON');
5888 }
5889
5890 setTimeout(() => {
5891 iconToChange.textContent = state ? '' : '';
5892
5893 void button.offsetWidth;
5894 iconToChange.style.filter = 'blur(0px)';
5895 iconToChange.style.opacity = '1';
5896 }, 400);
5897 } catch (e) {
5898 console.error(e);
5899 }
5900 }
5901 DLP_Settings_Auto_Update_Toggle_1_ID.querySelector('#DLP_Inset_Toggle_1_ID').addEventListener('click', () => {
5902 if (DLP_Settings_Toggle_Busy) return;
5903 if (!greasyfork) {
5904 DLP_Settings_Var.autoUpdate = !DLP_Settings_Var.autoUpdate;
5905 DLP_Settings_Toggle_Busy = true;
5906 handleToggleClick(DLP_Settings_Auto_Update_Toggle_1_ID.querySelector('#DLP_Inset_Toggle_1_ID'), DLP_Settings_Var.autoUpdate);
5907 setTimeout(() => {
5908 DLP_Settings_Toggle_Busy = false;
5909 }, 800);
5910 }
5911 });
5912 DLP_Settings_Show_Solve_Buttons_1_ID.querySelector('#DLP_Inset_Toggle_1_ID').addEventListener('click', () => {
5913 if (DLP_Settings_Toggle_Busy) return;
5914 DLP_Settings_Var.showSolveButtons = !DLP_Settings_Var.showSolveButtons;
5915 DLP_Settings_Toggle_Busy = true;
5916 handleToggleClick(DLP_Settings_Show_Solve_Buttons_1_ID.querySelector('#DLP_Inset_Toggle_1_ID'), DLP_Settings_Var.showSolveButtons);
5917 setTimeout(() => {
5918 DLP_Settings_Toggle_Busy = false;
5919 }, 800);
5920 });
5921 DLP_Settings_Show_AutoServer_Button_1_ID.querySelector('#DLP_Inset_Toggle_1_ID').addEventListener('click', () => {
5922 if (DLP_Settings_Toggle_Busy) return;
5923 DLP_Settings_Var.showAutoServerButton = !DLP_Settings_Var.showAutoServerButton;
5924 DLP_Settings_Toggle_Busy = true;
5925 handleToggleClick(DLP_Settings_Show_AutoServer_Button_1_ID.querySelector('#DLP_Inset_Toggle_1_ID'), DLP_Settings_Var.showAutoServerButton);
5926 setTimeout(() => {
5927 DLP_Settings_Toggle_Busy = false;
5928 }, 800);
5929 });
5930 DLP_Settings_Help_Us_Make_Better_Button_1_ID.querySelector('#DLP_Inset_Toggle_1_ID').addEventListener('click', () => {
5931 if (DLP_Settings_Toggle_Busy) return;
5932 if (alpha) return;
5933 DLP_Settings_Var.anonymousUsageData = !DLP_Settings_Var.anonymousUsageData;
5934 DLP_Settings_Toggle_Busy = true;
5935 handleToggleClick(DLP_Settings_Help_Us_Make_Better_Button_1_ID.querySelector('#DLP_Inset_Toggle_1_ID'), DLP_Settings_Var.anonymousUsageData);
5936 setTimeout(() => {
5937 DLP_Settings_Toggle_Busy = false;
5938 }, 800);
5939 });
5940
5941
5942 function confetti() {
5943 let canvas = document.getElementById("DLP_Confetti_Canvas");
5944 if (!canvas.confettiInitialized) {
5945 let ctx = canvas.getContext("2d");
5946 canvas.width = window.innerWidth;
5947 canvas.height = window.innerHeight;
5948 let cx = ctx.canvas.width / 2;
5949 let cy = ctx.canvas.height / 2;
5950
5951 canvas.ctx = ctx;
5952 canvas.cx = cx;
5953 canvas.cy = cy;
5954 canvas.confetti = [];
5955 canvas.animationId = null;
5956 canvas.confettiInitialized = true;
5957
5958 let resizeCanvas = () => {
5959 canvas.width = window.innerWidth;
5960 canvas.height = window.innerHeight;
5961 canvas.cx = canvas.ctx.canvas.width / 2;
5962 canvas.cy = canvas.ctx.canvas.height / 2;
5963 };
5964
5965 const resizeObserver = new ResizeObserver(() => {
5966 resizeCanvas();
5967 });
5968 resizeObserver.observe(canvas);
5969
5970 let render = () => {
5971 canvas.ctx.clearRect(0, 0, canvas.width, canvas.height);
5972 canvas.confetti.forEach((confetto, index) => {
5973 let width = confetto.dimensions.x * confetto.scale.x;
5974 let height = confetto.dimensions.y * confetto.scale.y;
5975 canvas.ctx.translate(confetto.position.x, confetto.position.y);
5976 canvas.ctx.rotate(confetto.rotation);
5977
5978 confetto.velocity.x -= confetto.velocity.x * drag;
5979 confetto.velocity.y = Math.min(
5980 confetto.velocity.y + gravity,
5981 terminalVelocity,
5982 );
5983 confetto.velocity.x +=
5984 Math.random() > 0.5 ? Math.random() : -Math.random();
5985
5986 confetto.position.x += confetto.velocity.x;
5987 confetto.position.y += confetto.velocity.y;
5988
5989 if (confetto.position.y >= canvas.height) canvas.confetti.splice(index, 1);
5990
5991 if (confetto.position.x > canvas.width) confetto.position.x = 0;
5992 if (confetto.position.x < 0) confetto.position.x = canvas.width;
5993
5994 canvas.ctx.fillStyle = confetto.color.front;
5995 canvas.ctx.fillRect(-width / 2, -height / 2, width, height);
5996 canvas.ctx.setTransform(1, 0, 0, 1, 0, 0);
5997 });
5998 canvas.animationId = window.requestAnimationFrame(render);
5999 };
6000 render();
6001 }
6002
6003 const gravity = 0.5;
6004 const terminalVelocity = 10;
6005 const drag = 0.01;
6006 const colors = [
6007 { front: "#FF2D55", back: "#FF2D55" },
6008 { front: "#FF9500", back: "#FF9500" },
6009 { front: "#FFCC00", back: "#FFCC00" },
6010 { front: "#34C759", back: "#34C759" },
6011 { front: "#5AC8FA", back: "#5AC8FA" },
6012 { front: "#007AFF", back: "#007AFF" },
6013 { front: "#5856D6", back: "#5856D6" },
6014 { front: "#AF52DE", back: "#AF52DE" },
6015 ];
6016
6017 const confettiSizeRange = {
6018 min: 5,
6019 max: 15
6020 };
6021
6022 let randomRange = (min, max) => Math.random() * (max - min) + min;
6023
6024 const confettiCount = 400;
6025 for (let i = 0; i < confettiCount; i++) {
6026 canvas.confetti.push({
6027 color: colors[Math.floor(randomRange(0, colors.length))],
6028 dimensions: {
6029 x: randomRange(confettiSizeRange.min, confettiSizeRange.max),
6030 y: randomRange(confettiSizeRange.min, confettiSizeRange.max),
6031 },
6032 position: {
6033 x: randomRange(0, canvas.width),
6034 y: canvas.height - 1,
6035 },
6036 rotation: randomRange(0, 2 * Math.PI),
6037 scale: {
6038 x: 1,
6039 y: 1,
6040 },
6041 velocity: {
6042 x: randomRange(-25, 25),
6043 y: randomRange(0, -50),
6044 },
6045 });
6046 }
6047 }
6048
6049 function playHaptic(type) {
6050 function isIPhone() {
6051 return (/iPhone/.test(navigator.userAgent) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1));
6052 }
6053 function isAndroid() {
6054 return /Android/.test(navigator.userAgent) && 'vibrate' in navigator;
6055 }
6056
6057 // iOS haptic trick
6058 function iosHaptic() {
6059 try {
6060 const label = document.createElement("label");
6061 label.ariaHidden = "true";
6062 label.style.display = "none";
6063 const input = document.createElement("input");
6064 input.type = "checkbox";
6065 input.setAttribute("switch", "");
6066 label.appendChild(input);
6067 document.head.appendChild(label);
6068 label.click();
6069 document.head.removeChild(label);
6070 } catch {
6071 console.log("iOS haptic error");
6072 }
6073 }
6074
6075 // Android/Browser Vibration API
6076 function androidHaptic(pattern) {
6077 try {
6078 if (navigator.vibrate) {
6079 navigator.vibrate(pattern);
6080 }
6081 } catch {
6082 console.log("Android haptic error");
6083 }
6084 }
6085
6086 if (isIPhone()) {
6087 if (type === "success") {
6088 iosHaptic();
6089 setTimeout(iosHaptic, 80);
6090 } else if (type === "warning" || type === "error") {
6091 iosHaptic();
6092 setTimeout(iosHaptic, 100);
6093 setTimeout(iosHaptic, 200);
6094 setTimeout(iosHaptic, 280);
6095 } else {
6096 iosHaptic();
6097 }
6098 } else if (isAndroid()) {
6099 if (type === "success") {
6100 androidHaptic([30, 40, 30]);
6101 } else if (type === "fail" || type === "error") {
6102 androidHaptic([30, 40, 30, 40, 30]);
6103 } else {
6104 androidHaptic(30);
6105 }
6106 } else if (navigator.vibrate) {
6107 // fallback for other platforms supporting Vibration API
6108 if (type === "success") {
6109 navigator.vibrate([30, 40, 30]);
6110 } else if (type === "fail" || type === "error") {
6111 navigator.vibrate([30, 40, 30, 40, 30]);
6112 } else {
6113 navigator.vibrate(30);
6114 }
6115 }
6116 // else: no-op
6117 }
6118
6119
6120
6121 async function generateEarnKey() {
6122 const endpoint = `https://api.duolingopro.net/earn/connect/generate`;
6123
6124 try {
6125 const response = await fetch(endpoint, {
6126 method: 'GET',
6127 headers: {
6128 'Content-Type': 'application/json',
6129 'Authorization': `Bearer ${document.cookie.split(';').find(cookie => cookie.includes('jwt_token')).split('=')[1]}`
6130 },
6131 });
6132
6133 if (response.ok) {
6134 const data = await response.json();
6135 if (data.earn_key) {
6136 console.log('Earn Key:', data.earn_key);
6137 return data.earn_key;
6138 } else {
6139 throw new Error('Earn key not found in the response.');
6140 }
6141 } else if (response.status === 401) {
6142 throw new Error('Unauthorized: Invalid or missing authentication token.');
6143 } else if (response.status === 429) {
6144 throw new Error('Rate limit exceeded: Please try again later.');
6145 } else if (response.status === 500) {
6146 const errorData = await response.json();
6147 throw new Error(`Server Error: ${errorData.detail || 'An unexpected error occurred.'}`);
6148 } else {
6149 const errorData = await response.json();
6150 throw new Error(`Error ${response.status}: ${errorData.detail || 'An unexpected error occurred.'}`);
6151 }
6152 } catch (error) {
6153 console.error('Error generating earn key:', error.message);
6154 throw error;
6155 }
6156 }
6157
6158 let earnButtonAssignedLink = false;
6159 document.querySelectorAll("#DLP_Main_Earn_Button_1_ID, #DLP_Secondary_Earn_Button_1_ID").forEach(button => {
6160 button.addEventListener('click', () => {
6161 button.style.opacity = '0.5';
6162 button.style.pointerEvents = 'none';
6163
6164 generateEarnKey()
6165 .then(earnKey => {
6166 console.log('Successfully retrieved earn key:', earnKey);
6167 button.setAttribute("onclick", `window.open('${serverURL}/earn/connect/link/${earnKey}', '_blank');`);
6168 if (!earnButtonAssignedLink) {
6169 earnButtonAssignedLink = true;
6170 window.open(serverURL + "/earn/connect/link/" + earnKey, "_blank");
6171 }
6172 })
6173 .catch(error => {
6174 console.error('Failed to retrieve earn key:', error.message);
6175 })
6176 .finally(() => {
6177 button.style.opacity = '';
6178 button.style.pointerEvents = '';
6179 });
6180 });
6181 });
6182
6183
6184
6185
6186 let currentChatId = 1;
6187 let allTexts = {}; // { [chatId]: text }
6188 let allAttachments = {}; // { [chatId]: [ {id, file}, … ] }
6189
6190 function setupSupportPage() {
6191 const container = document.getElementById("DLP_Main_Box_Divider_11_ID");
6192 const chatBox = container.querySelector('.DLP_Chat_Box_1_ID_1');
6193 const attachmentVisualButton = container.querySelector('#DLP_Inset_Button_1_ID');
6194 const sendButton = container.querySelector("#DLP_Inset_Button_2_ID");
6195 const attachmentInput = container.querySelector("#DLP_Attachment_Input_1");
6196 const messageInput = container.querySelector("#DLP_Inset_Input_1_ID");
6197 const activeContainer = container.querySelector('.DLP_Input_Style_1_Active');
6198 let messageSendInProgress = false;
6199
6200 function resetMessageInputState() {
6201 messageInput.value = '';
6202 messageInput.style.height = '1.2em';
6203 if (activeContainer) activeContainer.style.height = '48px';
6204 messageInput.scrollTop = 0;
6205 checkSendButton();
6206 }
6207
6208 function setupCard() {
6209 let card = document.getElementById("DLP_Main_Box_Divider_11_ID").querySelector("#DLP_Inset_Card_1");
6210 let cardExpanded = false;
6211 let cardAnimating = false;
6212
6213 let descriptionText = card.querySelectorAll(':scope > .DLP_Text_Style_1');
6214
6215 card.addEventListener('click', () => {
6216 if (cardAnimating) return;
6217 cardAnimating = true;
6218 if (!cardExpanded) {
6219 let cardHeight = card.offsetHeight;
6220 let textHeight = false;
6221 if (descriptionText.length > 0) {
6222 textHeight = Array.from(descriptionText).map(() => "0");
6223 descriptionText.forEach(element => {
6224 element.style.display = 'block';
6225 element.style.height = 'auto';
6226 });
6227 }
6228 void card.offsetHeight;
6229 let newCardHeight = card.offsetHeight;
6230 let newTextHeight = false;
6231 if (descriptionText.length > 0) {
6232 newTextHeight = Array.from(descriptionText).map(element => element.offsetHeight);
6233 }
6234 if (descriptionText.length > 0) {
6235 descriptionText.forEach(element => {
6236 element.style.height = '0px';
6237 });
6238 }
6239 card.style.height = `${cardHeight}px`;
6240 void card.offsetHeight;
6241 if (descriptionText.length > 0) {
6242 descriptionText.forEach(element => {
6243 element.style.filter = 'blur(0px)';
6244 element.style.opacity = '1';
6245 });
6246 }
6247 card.style.height = `${newCardHeight}px`;
6248 if (descriptionText.length > 0) {
6249 descriptionText.forEach(element => {
6250 element.style.height = `${newTextHeight[Array.from(descriptionText).indexOf(element)]}px`;
6251 });
6252 }
6253 card.querySelector('.DLP_HStack_6').style.opacity = '0.5';
6254 card.querySelector('.DLP_HStack_6').lastElementChild.style.transition = 'all 0.4s cubic-bezier(0.16, 1, 0.32, 1)';
6255 card.querySelector('.DLP_HStack_6').lastElementChild.style.transform = 'rotate(90deg)';
6256 setTimeout(() => {
6257 card.style.height = 'auto';
6258 if (descriptionText.length > 0) {
6259 descriptionText.forEach(element => {
6260 element.style.height = 'auto';
6261 });
6262 }
6263 cardExpanded = true;
6264 cardAnimating = false;
6265 }, 400);
6266 } else {
6267 let cardHeight = card.offsetHeight;
6268 let textHeight = false;
6269 if (descriptionText.length > 0) {
6270 textHeight = Array.from(descriptionText).map(element => element.offsetHeight);
6271 descriptionText.forEach(element => {
6272 element.style.display = 'none';
6273 });
6274 }
6275 void card.offsetHeight;
6276 let newCardHeight = card.offsetHeight;
6277 let newTextHeight = false;
6278 if (descriptionText.length > 0) {
6279 newTextHeight = Array.from(descriptionText).map(() => "0");
6280 descriptionText.forEach(element => {
6281 element.style.display = 'block';
6282 element.style.height = `${textHeight[Array.from(descriptionText).indexOf(element)]}px`;
6283 });
6284 }
6285 card.style.height = `${cardHeight}px`;
6286 void card.offsetHeight;
6287
6288 if (descriptionText.length > 0) {
6289 descriptionText.forEach(element => {
6290 element.style.filter = 'blur(4px)';
6291 element.style.opacity = '0';
6292 });
6293 }
6294 card.style.height = `${newCardHeight}px`;
6295 if (descriptionText.length > 0) {
6296 descriptionText.forEach(element => {
6297 element.style.height = '0px';
6298 });
6299 }
6300 card.querySelector('.DLP_HStack_6').style.opacity = '1';
6301 card.querySelector('.DLP_HStack_6').lastElementChild.style.transition = 'all 0.4s cubic-bezier(0.16, 1, 0.32, 1)';
6302 card.querySelector('.DLP_HStack_6').lastElementChild.style.transform = 'rotate(0deg)';
6303 setTimeout(() => {
6304 card.style.height = 'auto';
6305 if (descriptionText.length > 0) {
6306 descriptionText.forEach(element => {
6307 element.style.display = 'none';
6308 });
6309 }
6310 cardExpanded = false;
6311 cardAnimating = false;
6312 }, 400);
6313 }
6314 });
6315 }
6316 setupCard();
6317
6318 function markTempMessageFailed(tempId) {
6319 const tempState = pendingTempMessages.get(tempId);
6320 if (tempState) {
6321 tempState.sendFailed = true;
6322 }
6323 const tempElements = chatBox.querySelectorAll(`[data-is-temp="${tempId}"]`);
6324 tempElements.forEach(element => {
6325 element.style.animation = '';
6326 element.style.color = 'rgba(var(--DLP-pink))';
6327 });
6328 }
6329
6330 function setupSendButton() {
6331 sendButton.addEventListener('click', async () => {
6332 if (messageSendInProgress) return;
6333 if (!storageLocal.chatKey || storageLocal.chatKey.length === 0) {
6334 if (container?.querySelector('#DLP_Inset_Group_3')?.style.display !== 'none') container.querySelector('#DLP_Inset_Group_3').style.display = 'none';
6335 if (chatBox?.style.display === 'none') chatBox.style.display = 'flex';
6336
6337 try {
6338 let response = await fetch(apiURL + "/chats/create", {
6339 method: "GET",
6340 headers: {
6341 "Authorization": `Bearer ${document.cookie.split(';').find(cookie => cookie.includes('jwt_token')).split('=')[1]}`
6342 }
6343 });
6344
6345 let data = await response.json();
6346 console.log("Server Response:", data);
6347 storageLocal.chatKey = [data.chat_key];
6348 saveStorageLocal();
6349 } catch (error) {
6350 console.error("Fetch error:", error);
6351 }
6352 }
6353
6354 let formData = new FormData();
6355 formData.append("message", messageInput.value);
6356
6357 let fileUrls = [];
6358 for (const attachment of allAttachments[currentChatId] ?? []) {
6359 const file = attachment.file;
6360 console.log("attaching", file);
6361 formData.append("files", file);
6362 const url = URL.createObjectURL(file);
6363 console.log("url", url);
6364 fileUrls.push(url);
6365 }
6366
6367 let chatTempSendNumber = chatTempSendList.length ? chatTempSendList[chatTempSendList.length - 1] + 1 : 1;
6368 const tempMessageId = `temp-${chatTempSendNumber}`;
6369 let tempData = {
6370 "accent": '#007AFF',
6371 "author": userBioData.username,
6372 "edited": false,
6373 "files": fileUrls,
6374 "message": messageInput.value,
6375 "profile_picture": userBioData.profile_picture,
6376 "role": "You",
6377 "send_time": Number(Date.now()),
6378 "message_id": tempMessageId
6379 };
6380 createMessage(tempData, false, chatTempSendNumber);
6381 pendingTempMessages.set(chatTempSendNumber, {
6382 ...tempData,
6383 files: [...tempData.files]
6384 });
6385
6386 chatTempSendList.push(chatTempSendNumber);
6387
6388 chatBox.scrollTop = chatBox.scrollHeight;
6389 allAttachments[currentChatId] = [];
6390 renderAttachmentsPreview();
6391 messageSendInProgress = true;
6392 checkSendButton();
6393 resetMessageInputState();
6394
6395 try {
6396 let response = await fetch(apiURL + "/chats/send_message", {
6397 method: "POST",
6398 headers: alpha
6399 ? {
6400 'Authorization': `Bearer ${document.cookie.split(';').find(cookie => cookie.includes('jwt_token')).split('=')[1]}`,
6401 'X-Chat-Key': `${storageLocal.chatKey[0]}`
6402 }
6403 : {
6404 'X-Chat-Key': `${storageLocal.chatKey[0]}`
6405 },
6406 body: formData
6407 });
6408
6409 let responseData = await response.json();
6410 console.log("Server Response:", responseData);
6411
6412 const isNewMessageFormat = response.ok && responseData && typeof responseData === 'object' && Object.prototype.hasOwnProperty.call(responseData, 'message_id');
6413 if (isNewMessageFormat) {
6414 const wasAtBottom = Math.abs(chatBox.scrollHeight - (chatBox.scrollTop + chatBox.clientHeight)) < 5;
6415 chatBox.querySelectorAll(`[data-is-temp="${chatTempSendNumber}"]`).forEach(element => {
6416 element.remove();
6417 });
6418 createMessage(responseData);
6419 const tempIndex = chatTempSendList.indexOf(chatTempSendNumber);
6420 if (tempIndex !== -1) {
6421 chatTempSendList.splice(tempIndex, 1);
6422 }
6423 pendingTempMessages.delete(chatTempSendNumber);
6424 if (wasAtBottom) {
6425 chatBox.scrollTop = chatBox.scrollHeight;
6426 }
6427 } else {
6428 if (responseData?.status === false && responseData?.notification) {
6429 showNotification(responseData.notification.icon, responseData.notification.head, responseData.notification.body, responseData.notification.duration);
6430 } else {
6431 showNotification("error", "Send Failed", "We could not verify that your message was delivered. Please try again.", 8);
6432 }
6433 markTempMessageFailed(chatTempSendNumber);
6434 }
6435
6436 } catch (error) {
6437 console.error("Fetch error:", error);
6438 markTempMessageFailed(chatTempSendNumber);
6439 } finally {
6440 messageSendInProgress = false;
6441 checkSendButton();
6442 }
6443 });
6444 }
6445 setupSendButton();
6446
6447 function setupTextInput() {
6448 const sendButton = container.querySelector("#DLP_Inset_Button_2_ID");
6449 resetMessageInputState();
6450
6451 messageInput.addEventListener('input', function () {
6452 messageInput.style.height = '1.2em';
6453
6454 const lineHeight = parseInt(getComputedStyle(messageInput).lineHeight);
6455 const maxRows = 5;
6456 const maxHeight = lineHeight * maxRows;
6457
6458 const newHeight = Math.min((messageInput.scrollHeight - 32), maxHeight);
6459
6460 messageInput.style.height = newHeight + 'px';
6461
6462 if (newHeight < 20) {
6463 activeContainer.style.height = '48px';
6464 } else {
6465 activeContainer.style.height = (newHeight + 32) + 'px';
6466 }
6467
6468 checkSendButton();
6469 });
6470
6471 messageInput.addEventListener('keydown', function (event) {
6472 if (event.key === 'Enter' && !event.shiftKey) {
6473 event.preventDefault();
6474 if (sendButton.style.pointerEvents !== 'none') {
6475 sendButton.click();
6476 }
6477 }
6478 });
6479 }
6480 setupTextInput();
6481
6482 let nextAttachmentId = 0;
6483 let attachmentDropBoxExpanded = false;
6484
6485 const MAX_ATTACHMENT_FILE_SIZE = 50 * 1024 * 1024; // 50 MB
6486 const MAX_ATTACHMENT_FILE_COUNT = 3;
6487
6488 function setupAttachmentsInput() {
6489 const attachmentBox = container.querySelector('#DLP_Attachment_Preview_Parent');
6490 const attachmentBoxDrop = attachmentBox.querySelector('.DLP_Attachment_Box_Drop_1');
6491
6492 attachmentBoxDrop.addEventListener('dragenter', event => {
6493 event.preventDefault();
6494 //attachmentBoxDrop.style.outline = '2px solid rgba(var(--DLP-blue), 0.20)';
6495 attachmentBoxDrop.firstElementChild.style.opacity = '1';
6496 });
6497
6498 attachmentBoxDrop.addEventListener('dragleave', event => {
6499 event.preventDefault();
6500 if (attachmentBoxDrop.contains(event.relatedTarget)) return;
6501 //attachmentBoxDrop.style.outline = '2px dashed rgba(var(--DLP-blue), 0.20)';
6502 attachmentBoxDrop.firstElementChild.style.opacity = '0.5';
6503 });
6504
6505 window.addEventListener('dragover', (event) => {
6506 event.preventDefault();
6507 if (attachmentInput.disabled) return;
6508 if (event.dataTransfer && event.dataTransfer.types.includes('Files')) {
6509 if (attachmentBox.style.display === 'none') {
6510 attachmentBox.style.display = '';
6511 }
6512 [...attachmentBox.children].forEach(child => {
6513 if (child !== attachmentBoxDrop) {
6514 child.style.display = 'none';
6515 }
6516 });
6517 attachmentBoxDrop.style.display = '';
6518 }
6519 });
6520
6521 window.addEventListener('dragleave', (event) => {
6522 if (event.clientX <= 0 || event.clientY <= 0 || event.clientX >= window.innerWidth || event.clientY >= window.innerHeight) {
6523 if (attachmentBox.children.length === 1 && attachmentBox.children[0] === attachmentBoxDrop) {
6524 attachmentBox.style.display = 'none';
6525 }
6526 [...attachmentBox.children].forEach(child => {
6527 if (child !== attachmentBoxDrop) {
6528 child.style.display = '';
6529 }
6530 });
6531 attachmentBoxDrop.style.display = 'none';
6532 //attachmentBoxDrop.style.outline = '2px dashed a(var(--DLP-blue), 0.20)';
6533 attachmentBoxDrop.firstElementChild.style.opacity = '0.5';
6534 }
6535 });
6536
6537 window.addEventListener('drop', (event) => {
6538 event.preventDefault();
6539 [...attachmentBox.children].forEach(child => {
6540 if (child !== attachmentBoxDrop) {
6541 child.style.display = '';
6542 }
6543 });
6544 attachmentBoxDrop.style.display = 'none';
6545 //attachmentBoxDrop.style.outline = '2px dashed rgba(var(--DLP-blue), 0.20)';
6546 attachmentBoxDrop.firstElementChild.style.opacity = '0.5';
6547 });
6548
6549 attachmentBoxDrop.addEventListener('drop', (event) => {
6550 event.preventDefault();
6551 attachmentBoxDrop.style.display = 'none';
6552
6553 const selectedFiles = Array.from(event.dataTransfer.files);
6554 triggerInputAttachments(selectedFiles);
6555 });
6556
6557 attachmentVisualButton.addEventListener('click', () => attachmentInput.click());
6558
6559 attachmentInput.addEventListener('change', (event) => {
6560 const selectedFiles = Array.from(event.target.files);
6561 triggerInputAttachments(selectedFiles);
6562 });
6563 }
6564 setupAttachmentsInput();
6565
6566 function triggerInputAttachments(selectedFiles) {
6567 if (!allAttachments[currentChatId]) {
6568 allAttachments[currentChatId] = [];
6569 }
6570 const validFiles = [];
6571
6572 selectedFiles.forEach(file => {
6573 if (file.size > MAX_ATTACHMENT_FILE_SIZE) {
6574 showNotification("warning", "File Too Large", `${file.name} is over 10 MB, please choose a smaller file.`, 10);
6575 } else {
6576 validFiles.push(file);
6577 }
6578 });
6579
6580 const remainingSlots = MAX_ATTACHMENT_FILE_COUNT - allAttachments[currentChatId]?.length;
6581 if (validFiles.length > remainingSlots) {
6582 showNotification("warning", "Too Many Files", `You can only attach up to ${MAX_ATTACHMENT_FILE_COUNT} files at once.`, 10);
6583 validFiles.length = remainingSlots;
6584 }
6585
6586 validFiles.forEach(file => {
6587 allAttachments[currentChatId]?.push({ id: String(nextAttachmentId++), file }); // wrap each in an {id, file} and append
6588 });
6589
6590 updateAttachmentsInput();
6591 renderAttachmentsPreview();
6592 checkSendButton();
6593 attachmentInput.value = '';
6594 }
6595
6596 function updateAttachmentsInput() {
6597 const dt = new DataTransfer();
6598 allAttachments[currentChatId]?.forEach(a => dt.items.add(a.file));
6599 attachmentInput.files = dt.files;
6600 }
6601
6602 function removeAttachmentById(id) {
6603 allAttachments[currentChatId] = allAttachments[currentChatId]?.filter(a => a.id !== id);
6604 updateAttachmentsInput();
6605 renderAttachmentsPreview();
6606 checkSendButton();
6607 }
6608
6609 function renderAttachmentsPreview() {
6610 const attachmentBox = container.querySelector('#DLP_Attachment_Preview_Parent');
6611 const attachmentBoxDrop = attachmentBox.querySelector('.DLP_Attachment_Box_Drop_1');
6612
6613 const currentIds = new Set(allAttachments[currentChatId]?.map(a => a.id));
6614
6615 // 1) remove deleted attachments from the DOM
6616 Array.from(attachmentBox.children).forEach(child => {
6617 const childId = child.getAttribute('data-id');
6618 if (!currentIds.has(childId) && child !== attachmentBoxDrop) {
6619 attachmentBox.removeChild(child);
6620 }
6621 });
6622
6623 // 2) add new attachments to the DOM
6624 allAttachments[currentChatId]?.forEach(({ id, file }) => {
6625 if (attachmentBox.querySelector(`[data-id="${id}"]`)) return;
6626
6627 const url = URL.createObjectURL(file);
6628 const box = document.createElement('div');
6629 box.className = 'DLP_Attachment_Box_1';
6630 box.setAttribute('data-id', id);
6631 box.style.position = 'relative';
6632
6633 let media;
6634 if (file.type.startsWith('image/')) {
6635 media = document.createElement('img');
6636 media.src = url;
6637 media.className = 'DLP_Attachment_Box_1_Content';
6638 } else if (file.type.startsWith('video/')) {
6639 media = document.createElement('video');
6640 media.src = url;
6641 media.autoplay = true;
6642 media.muted = true;
6643 media.loop = true;
6644 media.className = 'DLP_Attachment_Box_1_Content';
6645 } else {
6646 media = document.createElement('div');
6647 media.style.display = 'flex';
6648 media.style.width = '100%';
6649 media.style.height = '100%';
6650 media.style.paddingTop = '6px';
6651 media.style.flexDirection = 'column';
6652 media.style.justifyContent = 'center';
6653 media.style.alignItems = 'center';
6654 media.style.gap = '6px';
6655 media.style.flexShrink = '0';
6656
6657 mediaChild1 = document.createElement('p');
6658 mediaChild1.className = 'DLP_Text_Style_1 DLP_NoSelect';
6659 mediaChild1.style.fontSize = '24px';
6660 mediaChild1.textContent = '';
6661 media.appendChild(mediaChild1);
6662
6663 mediaChild2 = document.createElement('p');
6664 mediaChild2.className = 'DLP_Text_Style_1 DLP_NoSelect';
6665 mediaChild2.style.opacity = '0.5';
6666 mediaChild2.textContent = 'File';
6667 //mediaChild2.textContent = file.name;
6668 media.appendChild(mediaChild2);
6669 }
6670
6671 // Create and append delete button
6672 const hover = document.createElement('div');
6673 hover.className = 'DLP_Attachment_Box_1_Hover';
6674 hover.style.display = 'none';
6675 box.addEventListener('mouseenter', () => {
6676 hover.style.display = '';
6677 });
6678 box.addEventListener('mouseleave', () => {
6679 hover.style.display = 'none';
6680 });
6681 const btn = document.createElement('p');
6682 btn.className = 'DLP_Text_Style_1 DLP_Magnetic_Hover_1 DLP_NoSelect';
6683 if ((file.type.startsWith('image/') || file.type.startsWith('video/'))) btn.textContent = '';
6684 else btn.textContent = '';
6685 btn.addEventListener('click', () => removeAttachmentById(id));
6686 hover.appendChild(btn);
6687
6688 box.appendChild(media);
6689 box.appendChild(hover);
6690 attachmentBox.appendChild(box);
6691
6692 if (false) {
6693 if (file.type.startsWith('image/')) {
6694 media.addEventListener('load', () => updateContrast(box));
6695 if (media.complete) updateContrast(box);
6696 } else if (file.type.startsWith('video/')) {
6697 media.addEventListener('loadeddata', () => {
6698 const iv = setInterval(() => {
6699 if (!document.contains(media)) {
6700 clearInterval(iv);
6701 } else {
6702 updateContrast(box);
6703 }
6704 }, 250);
6705 updateContrast(box);
6706 });
6707 } else {
6708 updateContrast(box);
6709 }
6710 }
6711 });
6712
6713 // Show or hide the attachmentBox and adjust padding/navigation
6714 if ((allAttachments[currentChatId]?.length ?? 0) === 0 && attachmentDropBoxExpanded) {
6715 attachmentBox.style.display = 'none';
6716 attachmentDropBoxExpanded = false;
6717 chatBox.scrollTop = chatBox.scrollHeight;
6718 //const nav = document.querySelector('#DLP_Main_Navigation_Box_5_ID .DLP_Col.DLP_Fill_Col.DLP_Fill_Row.DLP_Gap_8');
6719 //nav.style.paddingBottom = `${parseFloat(getComputedStyle(nav).paddingBottom) - 104}px`;
6720 } else if (allAttachments[currentChatId]?.length > 0 && !attachmentDropBoxExpanded) {
6721 attachmentBox.style.display = '';
6722 attachmentDropBoxExpanded = true;
6723 chatBox.scrollTop = chatBox.scrollHeight;
6724 //const nav = document.querySelector('#DLP_Main_Navigation_Box_5_ID .DLP_Col.DLP_Fill_Col.DLP_Fill_Row.DLP_Gap_8');
6725 //nav.style.paddingBottom = `${parseFloat(getComputedStyle(nav).paddingBottom) + 104}px`;
6726 //void container.offsetHeight;
6727 //document.querySelector('#DLP_Main_Navigation_Box_5_ID').scrollTop += 104;
6728 }
6729
6730 // Disable input if there are too many files
6731 if (allAttachments[currentChatId]?.length >= MAX_ATTACHMENT_FILE_COUNT) {
6732 attachmentInput.disabled = true;
6733 attachmentVisualButton.style.opacity = '0.5';
6734 attachmentVisualButton.style.pointerEvents = 'none';
6735 } else {
6736 attachmentInput.disabled = false;
6737 attachmentVisualButton.style.opacity = '';
6738 attachmentVisualButton.style.pointerEvents = '';
6739 }
6740
6741 }
6742
6743 function setupCreateNewChatButton() {
6744 let theButton = container.querySelector('#DLP_Inset_Group_2').querySelector('#DLP_Inset_Button_3_ID');
6745 theButton.addEventListener('click', async () => {
6746 theButton.style.opacity = "0.5";
6747 theButton.style.pointerEvents = "none";
6748 try {
6749 let response = await fetch(apiURL + "/chats/create", {
6750 method: "GET",
6751 headers: {
6752 "Authorization": `Bearer ${document.cookie.split(';').find(cookie => cookie.includes('jwt_token')).split('=')[1]}`
6753 }
6754 });
6755
6756 let data = await response.json();
6757 console.log("Server Response:", data);
6758 storageLocal.chatKey = [data.chat_key];
6759 saveStorageLocal();
6760
6761 chatBox.innerHTML = '';
6762
6763 container.querySelector('#DLP_Inset_Group_1').style.display = "";
6764 container.querySelector('#DLP_Inset_Group_2').style.display = "none";
6765
6766 theButton.style.opacity = "";
6767 theButton.style.pointerEvents = "";
6768 } catch (error) {
6769 console.error("Fetch error:", error);
6770 theButton.style.opacity = "";
6771 theButton.style.pointerEvents = "";
6772 }
6773 });
6774 }
6775 setupCreateNewChatButton();
6776
6777 function checkSendButton() {
6778 if (messageSendInProgress) {
6779 sendButton.style.opacity = "0.5";
6780 sendButton.style.pointerEvents = "none";
6781 return;
6782 }
6783 if (messageInput.value.trim() !== "" || (allAttachments[currentChatId]?.length ?? 0) > 0) {
6784 sendButton.style.opacity = "";
6785 sendButton.style.pointerEvents = "";
6786 } else {
6787 sendButton.style.opacity = "0.5";
6788 sendButton.style.pointerEvents = "none";
6789 }
6790 }
6791 checkSendButton();
6792 }
6793 setupSupportPage();
6794
6795
6796
6797
6798
6799
6800
6801
6802
6803
6804 const originalPlay = HTMLAudioElement.prototype.play;
6805 function muteTab(value) {
6806 HTMLAudioElement.prototype.play = function () {
6807 if (value) {
6808 this.muted = true;
6809 } else {
6810 this.muted = false;
6811 }
6812 return originalPlay.apply(this, arguments);
6813 };
6814 }
6815
6816 document.addEventListener('keydown', function(event) {
6817 if ((event.ctrlKey || event.metaKey) && event.key === 'Enter') {
6818 if (event.shiftKey) {
6819 solving();
6820 } else {
6821 solve();
6822 }
6823 }
6824 });
6825
6826 let currentQuestionId = null;
6827 let hasLoggedForCurrent = false;
6828
6829 async function logOnce(flag, sol, dom) {
6830 // flag: 1 = solved, 2 = wrong, 3 = stuck
6831 if (!hasLoggedForCurrent) {
6832 if (alpha) {
6833 console.log(flag);
6834 //console.log(sol);
6835 //console.log(dom);
6836 console.log(sol.challengeGeneratorIdentifier.generatorId);
6837 }
6838 hasLoggedForCurrent = true;
6839
6840 if (storageLocal.settings.anonymousUsageData) {
6841 if (flag === 2) showNotification("error", "Legacy Solved Incorrectly", "Legacy has detected that it solved a question incorrectly. A report has been made under ID: " + sol.challengeGeneratorIdentifier.generatorId, 10);
6842 else if (flag === 3) showNotification("error", "Legacy is Stuck", "Legacy has detected that it is stuck on a question. A report has been made under ID: " + sol.challengeGeneratorIdentifier.generatorId, 10);
6843
6844 const payload = {
6845 version: versionFormal,
6846 random: storageLocal.random16,
6847 flag: flag,
6848 sol: sol,
6849 dom: dom.outerHTML
6850 };
6851
6852 console.log(sol);
6853
6854 const response = await fetch("https://api.duolingopro.net/analytics/legacy", {
6855 method: 'POST',
6856 headers: {
6857 'Content-Type': 'application/json'
6858 },
6859 body: JSON.stringify(payload)
6860 });
6861 } else {
6862 if (flag === 2) showNotification("error", "Legacy Solved Incorrectly", "Legacy has detected that it solved a question incorrectly. Turn on share anonymous usage data in settings to help us fix this bug.", 10);
6863 else if (flag === 3) showNotification("error", "Legacy is Stuck", "Legacy has detected that it is stuck on a question. Turn on share anonymous usage data in settings to help us fix this bug.", 10);
6864 }
6865 }
6866 }
6867
6868 function updateSolveButtonText(text) {
6869 document.getElementById("solveAllButton").innerText = text;
6870 }
6871
6872 function solving(value) {
6873 if (value === "start") isAutoMode = true;
6874 else if (value === "stop") isAutoMode = false;
6875 else isAutoMode = !isAutoMode;
6876 updateSolveButtonText(isAutoMode ? systemText[systemLanguage][102] : systemText[systemLanguage][101]);
6877 solvingIntervalId = isAutoMode ? (function() {
6878 let initialUrl = window.location.href;
6879 return setInterval(function() {
6880 if (window.location.href !== initialUrl) {
6881 isAutoMode = false;
6882 clearInterval(solvingIntervalId);
6883 updateSolveButtonText(isAutoMode ? systemText[systemLanguage][102] : systemText[systemLanguage][101]);
6884 return;
6885 } else {
6886 solve();
6887 }
6888 }, storageLocal.settings.solveSpeed * 1000);
6889 })() : clearInterval(solvingIntervalId);
6890 }
6891
6892 let hcwNIIOdaQqCZRDL = false;
6893 function solve() {
6894 const practiceAgain = document.querySelector('[data-test="player-practice-again"]');
6895 const sessionCompleteSlide = document.querySelector('[data-test="session-complete-slide"]');
6896
6897 const selectorsForSkip = [
6898 '[data-test="practice-hub-ad-no-thanks-button"]',
6899 '.vpDIE',
6900 '[data-test="plus-no-thanks"]',
6901 '._1N-oo._36Vd3._16r-S._1ZBYz._23KDq._1S2uf.HakPM',
6902 '._8AMBh._2vfJy._3Qy5R._28UWu._3h0lA._1S2uf._1E9sc',
6903 '._1Qh5D._36g4N._2YF0P._28UWu._3h0lA._1S2uf._1E9sc',
6904 '[data-test="story-start"]',
6905 '._3bBpU._1x5JY._1M9iF._36g4N._2YF0P.T7I0c._2EnxW.MYehf',
6906 '._2V6ug._1ursp._7jW2t._28UWu._3h0lA._1S2uf._1E9sc', // No Thanks Legendary Button
6907 '._1rcV8._1VYyp._1ursp._7jW2t._1gKir', // Language Score
6908 '._2V6ug._1ursp._7jW2t._3zgLG' // Create Profile Later
6909 ];
6910 selectorsForSkip.forEach(selector => {
6911 const element = document.querySelector(selector);
6912 if (element) element.click();
6913 });
6914
6915
6916 const status = storageSession.legacy.status;
6917 const type = status ? storageSession.legacy[status]?.type : null;
6918 let amount;
6919
6920 if (sessionCompleteSlide !== null && isAutoMode && storageSession.legacy.status) {
6921 if (!hcwNIIOdaQqCZRDL) {
6922 hcwNIIOdaQqCZRDL = true;
6923 if (type === 'lesson') {
6924 storageSession.legacy[status].amount -= 1;
6925 saveStorageSession();
6926 (((storageLocal.stats ??= {}).legacy ??= {})[status] ??= { lessons: 0 }).lessons++;
6927 saveStorageLocal();
6928 amount = status ? storageSession.legacy[status]?.amount : null;
6929 if (amount > 0) {
6930 if (practiceAgain !== null) {
6931 practiceAgain.click();
6932 return;
6933 } else {
6934 location.reload();
6935 }
6936 } else {
6937 storageSession.legacy[status].amount = 0;
6938 storageSession.legacy.status = false;
6939 saveStorageSession();
6940 window.location.href = "https://duolingo.com";
6941 return;
6942 }
6943 } else if (type === 'xp') {
6944 storageSession.legacy[status].amount -= findSubReact(document.getElementsByClassName("_1XNQX")[0]).xpGoalSessionProgress.totalXpThisSession;
6945 saveStorageSession();
6946 (((storageLocal.stats ??= {}).legacy ??= {})[status] ??= { lessons: 0 }).lessons++;
6947 saveStorageLocal();
6948 amount = status ? storageSession.legacy[status]?.amount : null;
6949 if (amount > 0) {
6950 if (practiceAgain !== null) {
6951 practiceAgain.click();
6952 return;
6953 } else {
6954 location.reload();
6955 }
6956 } else {
6957 storageSession.legacy[status].amount = 0;
6958 storageSession.legacy.status = false;
6959 saveStorageSession();
6960 window.location.href = "https://duolingo.com";
6961 return;
6962 }
6963 } else if (type === 'infinity') {
6964 (((storageLocal.stats ??= {}).legacy ??= {})[status] ??= { lessons: 0 }).lessons++;
6965 saveStorageLocal();
6966 if (practiceAgain !== null) {
6967 practiceAgain.click();
6968 return;
6969 } else {
6970 location.reload();
6971 }
6972 }
6973 }
6974 }
6975
6976 try {
6977 window.sol = findReact(document.getElementsByClassName(findReactMainElementClass)[0]).props.currentChallenge;
6978 } catch (error) {
6979 console.log(error);
6980 //let next = document.querySelector('[data-test="player-next"]');
6981 //if (next) {
6982 // next.click();
6983 //}
6984 //return;
6985 }
6986 //if (!window.sol) {
6987 // return;
6988 //}
6989
6990 let challengeType;
6991 if (window.sol) {
6992 challengeType = determineChallengeType();
6993 } else {
6994 challengeType = 'error';
6995 nextClickFunc();
6996 }
6997
6998 let questionKey;
6999 if (window.sol && window.sol.id) {
7000 questionKey = window.sol.id;
7001 } else if (window.sol) {
7002 // Fallback if no 'id' property: use type + prompt
7003 questionKey = JSON.stringify({
7004 type: window.sol.type,
7005 prompt: window.sol.prompt || ''
7006 });
7007 } else {
7008 questionKey = null;
7009 }
7010
7011 if (questionKey !== currentQuestionId) {
7012 currentQuestionId = questionKey;
7013 hasLoggedForCurrent = false;
7014 }
7015
7016 if (challengeType === 'error') {
7017 nextClickFunc();
7018 } else if (challengeType) {
7019 if (debug) document.getElementById("solveAllButton").innerText = challengeType;
7020 handleChallenge(challengeType);
7021 nextClickFunc();
7022 } else {
7023 nextClickFunc();
7024 }
7025 }
7026
7027
7028
7029 function nextClickFunc() {
7030 setTimeout(function () {
7031 try {
7032 let nextButtonNormal = document.querySelector('[data-test="player-next"]');
7033 let storiesContinueButton = document.querySelector('[data-test="stories-player-continue"]');
7034 let storiesDoneButton = document.querySelector('[data-test="stories-player-done"]');
7035
7036 let nextButtonAriaValueNormal = nextButtonNormal ? nextButtonNormal.getAttribute('aria-disabled') : null;
7037 let nextButtonAriaValueStoriesContinue = storiesContinueButton ? storiesContinueButton.disabled : null;
7038
7039 let nextButton = nextButtonNormal || storiesContinueButton || storiesDoneButton;
7040 let nextButtonAriaValue = nextButtonAriaValueNormal || nextButtonAriaValueStoriesContinue || storiesDoneButton;
7041
7042 if (nextButton) {
7043 if (nextButtonAriaValue === 'true' || nextButtonAriaValue === true) {
7044 requestAnimationFrame(() => {
7045 if (document.querySelectorAll('._35QY2._3jIlr.f2zGP._18W4a.xtPuL').length > 0) {
7046 } else {
7047 if (nextButtonAriaValue === 'true') {
7048 //console.log('The next button is disabled.');
7049 logOnce(3, window.sol, document.querySelector('.RMEuZ._1GVfY'));
7050 }
7051 }
7052 });
7053 } else if (nextButtonAriaValue === 'false' || nextButtonAriaValue === false) {
7054 nextButton.click();
7055 requestAnimationFrame(() => {
7056 if (document.querySelector('[data-test="player-next"]').classList.contains('_2oGJR')) { // _1rcV8 _1VYyp _1ursp _7jW2t _3DbUj _2VWgj _3S8jJ
7057 logOnce(1, window.sol, document.querySelector('.RMEuZ._1GVfY'));
7058 const status = storageSession.legacy.status;
7059 (((storageLocal.stats ??= {}).legacy ??= {})[status] ??= { questions: 0 }).questions++;
7060 saveStorageLocal();
7061 //mainSolveStatistics('question', 1);
7062 if (isAutoMode) {
7063 setTimeout(function () {
7064 nextButton.click();
7065 }, 100);
7066 }
7067 } else if (document.querySelector('[data-test="player-next"]').classList.contains('_3S8jJ')) {
7068 logOnce(2, window.sol, document.querySelector('.RMEuZ._1GVfY'));
7069 //if (solveSpeed < 0.6) {
7070 // solveSpeed = 0.6;
7071 // localStorage.setItem('duopro.autoSolveDelay', solveSpeed);
7072 //}
7073 } else {
7074 console.log('The element does not have the class ._9C_ii or .NAidc or the element is not found.');
7075 }
7076 });
7077 } else {
7078 console.log('The aria-disabled attribute is not set or has an unexpected value.');
7079 //notificationCall("what", "Idk");
7080 nextButton.click();
7081 }
7082 } else {
7083 console.log('Element with data-test="player-next" or data-test="stories-player-continue" not found.');
7084 }
7085 } catch (error) { }
7086 }, 100);
7087 }
7088
7089
7090 function LhEqEHHc() {
7091 const randomImageValue = Math.random().toString(36).substring(2, 15);
7092 //questionErrorLogs(findReact(document.getElementsByClassName(findReactMainElementClass)[0]).props.currentChallenge, document.body.innerHTML, randomImageValue);
7093 //const challengeAssistElement = document.querySelector('[data-test="challenge challenge-assist"]');
7094 const challengeAssistElement = document.querySelector('._3x0ok');
7095 if (challengeAssistElement) {
7096 } else {
7097 console.log('Element not found');
7098 }
7099 }
7100 function determineChallengeType() {
7101 try {
7102 //console.log(window.sol);
7103 if (document.getElementsByClassName("FmlUF").length > 0) {
7104 // Story
7105 if (window.sol.type === "arrange") {
7106 return "Story Arrange"
7107 } else if (window.sol.type === "multiple-choice" || window.sol.type === "select-phrases") {
7108 return "Story Multiple Choice"
7109 } else if (window.sol.type === "point-to-phrase") {
7110 return "Story Point to Phrase"
7111 } else if (window.sol.type === "match") {
7112 return "Story Pairs"
7113 }
7114 } else {
7115 // Lesson
7116 if (document.querySelectorAll('[data-test*="challenge-speak"]').length > 0) {
7117 hcwNIIOdaQqCZRDL = false;
7118 return 'Challenge Speak';
7119 } else if (window.sol.type === 'tapCompleteTable') {
7120 return 'Tap Complete Table';
7121 } else if (window.sol.type === 'typeCloze') {
7122 return 'Type Cloze';
7123 } else if (window.sol.type === 'typeClozeTable') {
7124 return 'Type Cloze Table';
7125 } else if (window.sol.type === 'tapClozeTable') {
7126 return 'Tap Cloze Table';
7127 } else if (window.sol.type === 'typeCompleteTable') {
7128 return 'Type Complete Table';
7129 } else if (window.sol.type === 'patternTapComplete') {
7130 return 'Pattern Tap Complete';
7131 } else if (document.querySelectorAll('[data-test*="challenge-name"]').length > 0 && document.querySelectorAll('[data-test="challenge-choice"]').length > 0) {
7132 hcwNIIOdaQqCZRDL = false;
7133 return 'Challenge Name';
7134 } else if (window.sol.type === 'listenMatch') {
7135 hcwNIIOdaQqCZRDL = false;
7136 return 'Listen Match';
7137 } else if (document.querySelectorAll('[data-test="challenge challenge-listenSpeak"]').length > 0) {
7138 hcwNIIOdaQqCZRDL = false;
7139 return 'Listen Speak';
7140 } else if (document.querySelectorAll('[data-test="challenge-choice"]').length > 0) {
7141 hcwNIIOdaQqCZRDL = false;
7142 if (document.querySelectorAll('[data-test="challenge-text-input"]').length > 0) {
7143 return 'Challenge Choice with Text Input';
7144 } else {
7145 return 'Challenge Choice'
7146 }
7147 } else if (document.querySelectorAll('[data-test$="challenge-tap-token"]').length > 0) {
7148 hcwNIIOdaQqCZRDL = false;
7149 if (window.sol.pairs !== undefined) {
7150 return 'Pairs';
7151 } else if (window.sol.correctTokens !== undefined) {
7152 return 'Tokens Run';
7153 } else if (window.sol.correctIndices !== undefined) {
7154 return 'Indices Run';
7155 }
7156 } else if (document.querySelectorAll('[data-test="challenge-tap-token-text"]').length > 0) {
7157 hcwNIIOdaQqCZRDL = false;
7158 return 'Fill in the Gap';
7159 } else if (document.querySelectorAll('[data-test="challenge-text-input"]').length > 0) {
7160 hcwNIIOdaQqCZRDL = false;
7161 return 'Challenge Text Input';
7162 } else if (document.querySelectorAll('[data-test*="challenge-partialReverseTranslate"]').length > 0) {
7163 hcwNIIOdaQqCZRDL = false;
7164 return 'Partial Reverse';
7165 } else if (document.querySelectorAll('textarea[data-test="challenge-translate-input"]').length > 0) {
7166 hcwNIIOdaQqCZRDL = false;
7167 return 'Challenge Translate Input';
7168 } else if (document.querySelectorAll('[data-test="session-complete-slide"]').length > 0) {
7169 return 'Session Complete';
7170 } else if (document.querySelectorAll('[data-test="daily-quest-progress-slide"]').length > 0) {
7171 return 'Daily Quest Progress';
7172 } else if (document.querySelectorAll('[data-test="streak-slide"]').length > 0) {
7173 return 'Streak';
7174 } else if (document.querySelectorAll('[data-test="leaderboard-slide"]').length > 0) { // needs maintainance
7175 return 'Leaderboard';
7176 } else {
7177 return false;
7178 }
7179 }
7180 } catch (error) {
7181 console.log(error);
7182 return 'error';
7183 }
7184 }
7185
7186 function handleChallenge(challengeType) {
7187 // Implement logic to handle different challenge types
7188 // This function should encapsulate the logic for each challenge type
7189 if (challengeType === 'Challenge Speak' || challengeType === 'Listen Match' || challengeType === 'Listen Speak') {
7190 const buttonSkip = document.querySelector('button[data-test="player-skip"]');
7191 buttonSkip?.click();
7192 } else if (challengeType === 'Challenge Choice' || challengeType === 'Challenge Choice with Text Input') {
7193 // Text input
7194 if (challengeType === 'Challenge Choice with Text Input') {
7195 let elm = document.querySelectorAll('[data-test="challenge-text-input"]')[0];
7196 let nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
7197 nativeInputValueSetter.call(elm, window.sol.correctSolutions ? window.sol.correctSolutions[0].split(/(?<=^\S+)\s/)[1] : (window.sol.displayTokens ? window.sol.displayTokens.find(t => t.isBlank).text : window.sol.prompt));
7198 let inputEvent = new Event('input', {
7199 bubbles: true
7200 });
7201
7202 elm.dispatchEvent(inputEvent);
7203 } else if (challengeType === 'Challenge Choice') {
7204 document.querySelectorAll("[data-test='challenge-choice']")[window.sol.correctIndex].click();
7205 }
7206
7207 } else if (challengeType === 'Pairs') {
7208 let nl = document.querySelectorAll('[data-test*="challenge-tap-token"]:not(span)');
7209 if (document.querySelectorAll('[data-test="challenge-tap-token-text"]').length === nl.length) {
7210 window.sol.pairs?.forEach((pair) => {
7211 for (let i = 0; i < nl.length; i++) {
7212 const nlInnerText = nl[i].querySelector('[data-test="challenge-tap-token-text"]').innerText.toLowerCase().trim();
7213
7214 try {
7215 if (
7216 (
7217 nlInnerText === pair.transliteration.toLowerCase().trim() ||
7218 nlInnerText === pair.character.toLowerCase().trim()
7219 )
7220 && !nl[i].disabled
7221 ) {
7222 nl[i].click()
7223 }
7224 } catch (TypeError) {
7225 if (
7226 (
7227 nlInnerText === pair.learningToken.toLowerCase().trim() ||
7228 nlInnerText === pair.fromToken.toLowerCase().trim()
7229 )
7230 && !nl[i].disabled
7231 ) {
7232 nl[i].click()
7233 }
7234 }
7235 }
7236 })
7237 }
7238
7239 } else if (challengeType === 'Story Pairs') {
7240 const nl = document.querySelectorAll('[data-test*="challenge-tap-token"]:not(span)');
7241 const textElements = document.querySelectorAll('[data-test="challenge-tap-token-text"]');
7242
7243 const textToElementMap = new Map();
7244 for (let i = 0; i < nl.length; i++) {
7245 const text = textElements[i].innerText.toLowerCase().trim();
7246 textToElementMap.set(text, nl[i]);
7247 }
7248
7249 for (const key in window.sol.dictionary) {
7250 if (window.sol.dictionary.hasOwnProperty(key)) {
7251 const value = window.sol.dictionary[key];
7252 const keyPart = key.split(":")[1].toLowerCase().trim();
7253 const normalizedValue = value.toLowerCase().trim();
7254
7255 const element1 = textToElementMap.get(keyPart);
7256 const element2 = textToElementMap.get(normalizedValue);
7257
7258 if (element1 && !element1.disabled) element1.click();
7259 if (element2 && !element2.disabled) element2.click();
7260 }
7261 }
7262
7263 } else if (challengeType === 'Tap Complete Table') {
7264 solveTapCompleteTable();
7265
7266 } else if (challengeType === 'Tokens Run') {
7267 correctTokensRun();
7268
7269 } else if (challengeType === 'Indices Run') {
7270 correctIndicesRun();
7271
7272 } else if (challengeType === 'Fill in the Gap') {
7273 correctIndicesRun();
7274
7275 } else if (challengeType === 'Challenge Text Input') {
7276 let elm = document.querySelectorAll('[data-test="challenge-text-input"]')[0];
7277 let nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
7278 nativeInputValueSetter.call(elm, window.sol.correctSolutions ? window.sol.correctSolutions[0] : (window.sol.displayTokens ? window.sol.displayTokens.find(t => t.isBlank).text : window.sol.prompt));
7279 let inputEvent = new Event('input', {
7280 bubbles: true
7281 });
7282
7283 elm.dispatchEvent(inputEvent);
7284
7285 } else if (challengeType === 'Partial Reverse') {
7286 let elm = document.querySelector('[data-test*="challenge-partialReverseTranslate"]')?.querySelector("span[contenteditable]");
7287 let nativeInputNodeTextSetter = Object.getOwnPropertyDescriptor(Node.prototype, "textContent").set
7288 nativeInputNodeTextSetter.call(elm, window.sol?.displayTokens?.filter(t => t.isBlank)?.map(t => t.text)?.join()?.replaceAll(',', ''));
7289 let inputEvent = new Event('input', {
7290 bubbles: true
7291 });
7292
7293 elm.dispatchEvent(inputEvent);
7294
7295 } else if (challengeType === 'Challenge Translate Input') {
7296 const elm = document.querySelector('textarea[data-test="challenge-translate-input"]');
7297 const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value").set;
7298 nativeInputValueSetter.call(elm, window.sol.correctSolutions ? window.sol.correctSolutions[0] : window.sol.prompt);
7299
7300 let inputEvent = new Event('input', {
7301 bubbles: true
7302 });
7303
7304 elm.dispatchEvent(inputEvent);
7305 } else if (challengeType === 'Challenge Name') {
7306
7307 let articles = findReact(document.getElementsByClassName(findReactMainElementClass)[0]).props.currentChallenge.articles;
7308 let correctSolutions = findReact(document.getElementsByClassName(findReactMainElementClass)[0]).props.currentChallenge.correctSolutions[0];
7309
7310 let matchingArticle = articles.find(article => correctSolutions.startsWith(article));
7311 let matchingIndex = matchingArticle !== undefined ? articles.indexOf(matchingArticle) : null;
7312 let remainingValue = correctSolutions.substring(matchingArticle.length);
7313
7314 let selectedElement = document.querySelector(`[data-test="challenge-choice"]:nth-child(${matchingIndex + 1})`);
7315 if (selectedElement) {
7316 selectedElement.click();
7317 }
7318
7319 let elm = document.querySelector('[data-test="challenge-text-input"]');
7320 let nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
7321 nativeInputValueSetter.call(elm, remainingValue);
7322 let inputEvent = new Event('input', {
7323 bubbles: true
7324 });
7325
7326 elm.dispatchEvent(inputEvent);
7327 } else if (challengeType === 'Type Cloze') {
7328 const input = document.querySelector('input[type="text"].b4jqk');
7329 if (!input) return;
7330
7331 let targetToken = window.sol.displayTokens.find(t => t.damageStart !== undefined);
7332 let correctWord = targetToken?.text || "";
7333
7334 let correctEnding = "";
7335 if (typeof targetToken?.damageStart === "number") {
7336 correctEnding = correctWord.slice(targetToken.damageStart);
7337 }
7338
7339 const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
7340 nativeInputValueSetter.call(input, correctEnding);
7341
7342 input.dispatchEvent(new Event("input", { bubbles: true }));
7343 input.dispatchEvent(new Event("change", { bubbles: true }));
7344 } else if (challengeType === 'Type Cloze Table') {
7345 const tableRows = document.querySelectorAll('tbody tr');
7346
7347 window.sol.displayTableTokens.slice(1).forEach((rowTokens, i) => {
7348 const answerCell = rowTokens[1]?.find(t => typeof t.damageStart === "number");
7349
7350 if (answerCell && tableRows[i]) {
7351 const input = tableRows[i].querySelector('input[type="text"].b4jqk');
7352 if (!input) return;
7353
7354 const correctWord = answerCell.text;
7355 const correctEnding = correctWord.slice(answerCell.damageStart);
7356
7357 const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
7358 nativeInputValueSetter.call(input, correctEnding);
7359
7360 input.dispatchEvent(new Event("input", { bubbles: true }));
7361 input.dispatchEvent(new Event("change", { bubbles: true }));
7362 }
7363 });
7364 } else if (challengeType === 'Tap Cloze Table') {
7365 const tableRows = document.querySelectorAll('tbody tr');
7366
7367 window.sol.displayTableTokens.slice(1).forEach((rowTokens, i) => {
7368 const answerCell = rowTokens[1]?.find(t => typeof t.damageStart === "number");
7369 if (!answerCell || !tableRows[i]) return;
7370
7371 const wordBank = document.querySelector('[data-test="word-bank"], .eSgkc');
7372 const wordButtons = wordBank ? Array.from(wordBank.querySelectorAll('button[data-test*="challenge-tap-token"]:not([aria-disabled="true"])')) : [];
7373
7374 const correctWord = answerCell.text;
7375 const correctEnding = correctWord.slice(answerCell.damageStart);
7376
7377 let endingMatched = "";
7378 let used = new Set();
7379 for (let btn of wordButtons) {
7380 if (!correctEnding.startsWith(endingMatched + btn.innerText)) continue;
7381 btn.click();
7382 endingMatched += btn.innerText;
7383 used.add(btn);
7384 if (endingMatched === correctEnding) break;
7385 }
7386 });
7387 } else if (challengeType === 'Type Complete Table') {
7388 const tableRows = document.querySelectorAll('tbody tr');
7389
7390 window.sol.displayTableTokens.slice(1).forEach((rowTokens, i) => {
7391 const answerCell = rowTokens[1]?.find(t => t.isBlank);
7392 if (!answerCell || !tableRows[i]) return;
7393
7394 const input = tableRows[i].querySelector('input[type="text"].b4jqk');
7395 if (!input) return;
7396
7397 const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
7398 nativeInputValueSetter.call(input, answerCell.text);
7399
7400 input.dispatchEvent(new Event("input", { bubbles: true }));
7401 input.dispatchEvent(new Event("change", { bubbles: true }));
7402 });
7403 } else if (challengeType === 'Pattern Tap Complete') {
7404 const wordBank = document.querySelector('[data-test="word-bank"], .eSgkc');
7405 if (!wordBank) return;
7406
7407 const choices = window.sol.choices;
7408 const correctIndex = window.sol.correctIndex ?? 0;
7409 const correctText = choices[correctIndex];
7410
7411 const buttons = Array.from(wordBank.querySelectorAll('button[data-test*="challenge-tap-token"]:not([aria-disabled="true"])'));
7412 const targetButton = buttons.find(btn => btn.innerText.trim() === correctText);
7413
7414 if (targetButton) {
7415 targetButton.click();
7416 }
7417 } else if (challengeType === 'Session Complete') {
7418 } else if (challengeType === 'Story Arrange') {
7419 let choices = document.querySelectorAll('[data-test*="challenge-tap-token"]:not(span)');
7420 for (let i = 0; i < window.sol.phraseOrder.length; i++) {
7421 choices[window.sol.phraseOrder[i]].click();
7422 }
7423 } else if (challengeType === 'Story Multiple Choice') {
7424 let choices = document.querySelectorAll('[data-test="stories-choice"]');
7425 choices[window.sol.correctAnswerIndex].click();
7426 } else if (challengeType === 'Story Point to Phrase') {
7427 let choices = document.querySelectorAll('[data-test="challenge-tap-token-text"]');
7428 var correctIndex = -1;
7429 for (let i = 0; i < window.sol.parts.length; i++) {
7430 if (window.sol.parts[i].selectable === true) {
7431 correctIndex += 1;
7432 if (window.sol.correctAnswerIndex === i) {
7433 choices[correctIndex].parentElement.click();
7434 }
7435 }
7436 }
7437 }
7438 }
7439
7440 function correctTokensRun() {
7441 const all_tokens = document.querySelectorAll('[data-test$="challenge-tap-token"]');
7442 const correct_tokens = window.sol.correctTokens;
7443 const clicked_tokens = [];
7444
7445 correct_tokens.forEach(correct_token => {
7446 const matching_elements = Array.from(all_tokens).filter(element => element.textContent.trim() === correct_token.trim());
7447 if (matching_elements.length > 0) {
7448 const match_index = clicked_tokens.filter(token => token.textContent.trim() === correct_token.trim()).length;
7449 if (match_index < matching_elements.length) {
7450 matching_elements[match_index].click();
7451 clicked_tokens.push(matching_elements[match_index]);
7452 } else {
7453 clicked_tokens.push(matching_elements[0]);
7454 }
7455 }
7456 });
7457 }
7458
7459
7460 function correctIndicesRun() {
7461 if (window.sol.correctIndices) {
7462 window.sol.correctIndices?.forEach(index => {
7463 document.querySelectorAll('div[data-test="word-bank"] [data-test*="challenge-tap-token"]:not(span)')[index].click();
7464 });
7465 }
7466 }
7467
7468 function solveTapCompleteTable() {
7469 const solutionRows = window.sol.displayTableTokens.slice(1);
7470
7471 const tableRowElements = document.querySelectorAll('tbody tr');
7472
7473 const wordBank = document.querySelector('div[data-test="word-bank"]');
7474 const wordBankButtons = wordBank ? wordBank.querySelectorAll('button[data-test*="-challenge-tap-token"]') : [];
7475
7476 const usedWordBankIndexes = new Set();
7477
7478 solutionRows.forEach((solutionRow, rowIndex) => {
7479 const answerCellData = solutionRow[1];
7480
7481 const correctToken = answerCellData.find(token => token.isBlank);
7482
7483 if (correctToken) {
7484 const correctAnswerText = correctToken.text;
7485 const currentRowElement = tableRowElements[rowIndex];
7486
7487 let buttons = currentRowElement.querySelectorAll('button[data-test*="-challenge-tap-token"]');
7488 let clicked = false;
7489
7490 if (buttons.length > 0) {
7491 for (let button of buttons) {
7492 const buttonTextElm = button.querySelector('[data-test="challenge-tap-token-text"]');
7493 if (buttonTextElm && buttonTextElm.innerText.trim() === correctAnswerText && !button.disabled) {
7494 button.click();
7495 clicked = true;
7496 break;
7497 }
7498 }
7499 }
7500
7501 if (!clicked && wordBankButtons.length > 0) {
7502 for (let i = 0; i < wordBankButtons.length; i++) {
7503 if (usedWordBankIndexes.has(i)) continue;
7504
7505 const button = wordBankButtons[i];
7506 const buttonTextElm = button.querySelector('[data-test="challenge-tap-token-text"]');
7507 if (buttonTextElm && buttonTextElm.innerText.trim() === correctAnswerText && !button.disabled) {
7508 button.click();
7509 usedWordBankIndexes.add(i);
7510 break;
7511 }
7512 }
7513 }
7514 }
7515 });
7516 }
7517
7518 function findSubReact(dom, traverseUp = reactTraverseUp) {
7519 const key = Object.keys(dom).find(key => key.startsWith("__reactProps"));
7520 return dom?.[key]?.children?.props?.slide;
7521 }
7522
7523 function findReact(dom, traverseUp = reactTraverseUp) {
7524 const key = Object.keys(dom).find(key => {
7525 return key.startsWith("__reactFiber$") // react 17+
7526 || key.startsWith("__reactInternalInstance$"); // react <17
7527 });
7528 const domFiber = dom[key];
7529 if (domFiber == null) return null;
7530 // react <16
7531 if (domFiber._currentElement) {
7532 let compFiber = domFiber._currentElement._owner;
7533 for (let i = 0; i < traverseUp; i++) {
7534 compFiber = compFiber._currentElement._owner;
7535 }
7536 return compFiber._instance;
7537 }
7538 // react 16+
7539 const GetCompFiber = fiber => {
7540 //return fiber._debugOwner; // this also works, but is __DEV__ only
7541 let parentFiber = fiber.return;
7542 while (typeof parentFiber.type == "string") {
7543 parentFiber = parentFiber.return;
7544 }
7545 return parentFiber;
7546 };
7547 let compFiber = GetCompFiber(domFiber);
7548 for (let i = 0; i < traverseUp; i++) {
7549 compFiber = GetCompFiber(compFiber);
7550 }
7551 return compFiber.stateNode;
7552 }
7553
7554 window.findReact = findReact;
7555 window.findSubReact = findSubReact;
7556 window.ss = solving;
7557}
7558
7559try {
7560 if (false) {
7561 if (storageLocal.languagePackVersion !== "00") {
7562 if (!storageLocal.languagePack.hasOwnProperty(systemLanguage)) systemLanguage = "en";
7563 systemText = storageLocal.languagePack;
7564 One();
7565 } else {
7566 systemLanguage = "en";
7567 One();
7568 }
7569 } else {
7570 systemLanguage = "en";
7571 One();
7572 }
7573} catch (error) {
7574 console.log(error);
7575 One();
7576}
7577