Progrentis Points Modifier

A new extension

Size

23.2 KB

Version

1.1.5

Created

Mar 25, 2026

Updated

23 days ago

1// ==UserScript==
2// @name		Progrentis Points Modifier
3// @description		A new extension
4// @version		1.1.5
5// @match		https://*.prod.progrentis.com/*
6// @icon		https://prod.progrentis.com/Portals/6/favicon.ico
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    console.log('Progrentis Auto-Complete Extension iniciado');
12
13    // ============================================
14    // CONFIGURACIÓN
15    // ============================================
16    const AUTO_COMPLETE_CONFIG = {
17        pointsPerExercise: 10,
18        progressPerExercise: 10, // 10% por ejercicio
19        autoClickDelay: 2000, // 2 segundos entre acciones
20        maxScore: 100,
21        maxProgress: 100
22    };
23
24    // ============================================
25    // FUNCIONES DE ALMACENAMIENTO
26    // ============================================
27    async function getSavedPoints() {
28        const saved = await GM.getValue('progrentis_points', null);
29        console.log('Puntos guardados recuperados:', saved);
30        return saved;
31    }
32
33    async function savePoints(points) {
34        await GM.setValue('progrentis_points', points);
35        console.log('Puntos guardados:', points);
36    }
37
38    async function getSavedUnit() {
39        const saved = await GM.getValue('progrentis_unit', null);
40        console.log('Unidad guardada recuperada:', saved);
41        return saved;
42    }
43
44    async function saveUnit(unit) {
45        await GM.setValue('progrentis_unit', unit);
46        console.log('Unidad guardada:', unit);
47    }
48
49    async function getSavedUnlockState() {
50        const saved = await GM.getValue('progrentis_unlocked', false);
51        console.log('Estado de desbloqueo recuperado:', saved);
52        return saved;
53    }
54
55    async function saveUnlockState(unlocked) {
56        await GM.setValue('progrentis_unlocked', unlocked);
57        console.log('Estado de desbloqueo guardado:', unlocked);
58    }
59
60    async function getAutoCompleteEnabled() {
61        const enabled = await GM.getValue('progrentis_autocomplete', false);
62        console.log('Auto-completar habilitado:', enabled);
63        return enabled;
64    }
65
66    async function setAutoCompleteEnabled(enabled) {
67        await GM.setValue('progrentis_autocomplete', enabled);
68        console.log('Auto-completar configurado a:', enabled);
69    }
70
71    // ============================================
72    // FUNCIONES DE MODIFICACIÓN DE PROGRESO
73    // ============================================
74    async function modifyScore(newScore) {
75        const scoreElements = document.querySelectorAll('div[data-v-548dd043].progress-bar-x.progress span');
76        
77        for (const element of scoreElements) {
78            const text = element.textContent.trim();
79            // Buscar el elemento que muestra la nota (número sin %)
80            if (!text.includes('%') && !isNaN(parseInt(text))) {
81                element.textContent = newScore.toString();
82                console.log('Nota modificada a:', newScore);
83                await savePoints(newScore);
84                return true;
85            }
86        }
87        return false;
88    }
89
90    async function modifyProgress(newProgress) {
91        const progressElements = document.querySelectorAll('div[data-v-548dd043].progress-bar-x.progress span');
92        
93        for (const element of progressElements) {
94            const text = element.textContent.trim();
95            // Buscar el elemento que muestra el porcentaje
96            if (text.includes('%')) {
97                element.textContent = `${newProgress} %`;
98                console.log('Progreso modificado a:', newProgress + '%');
99                
100                // También modificar la barra visual
101                const progressBar = element.previousElementSibling;
102                if (progressBar && progressBar.classList.contains('inside')) {
103                    progressBar.style.width = `${newProgress}%`;
104                }
105                return true;
106            }
107        }
108        return false;
109    }
110
111    async function incrementScoreAndProgress() {
112        const scoreElements = document.querySelectorAll('div[data-v-548dd043].progress-bar-x.progress span');
113        let currentScore = 0;
114        let currentProgress = 0;
115
116        // Obtener valores actuales
117        for (const element of scoreElements) {
118            const text = element.textContent.trim();
119            if (text.includes('%')) {
120                currentProgress = parseFloat(text.replace('%', '').trim());
121            } else if (!isNaN(parseInt(text))) {
122                currentScore = parseInt(text);
123            }
124        }
125
126        // Calcular nuevos valores
127        const newScore = Math.min(currentScore + AUTO_COMPLETE_CONFIG.pointsPerExercise, AUTO_COMPLETE_CONFIG.maxScore);
128        const newProgress = Math.min(currentProgress + AUTO_COMPLETE_CONFIG.progressPerExercise, AUTO_COMPLETE_CONFIG.maxProgress);
129
130        console.log(`Incrementando - Nota: ${currentScore}${newScore}, Progreso: ${currentProgress}% → ${newProgress}%`);
131
132        // Aplicar cambios
133        await modifyScore(newScore);
134        await modifyProgress(newProgress);
135
136        showSuccessMessage(`✅ +${AUTO_COMPLETE_CONFIG.pointsPerExercise} puntos | +${AUTO_COMPLETE_CONFIG.progressPerExercise}% progreso`);
137
138        return { newScore, newProgress };
139    }
140
141    // ============================================
142    // AUTO-COMPLETAR EJERCICIOS
143    // ============================================
144    async function autoCompleteExercise() {
145        const isEnabled = await getAutoCompleteEnabled();
146        if (!isEnabled) {
147            console.log('Auto-completar deshabilitado');
148            return;
149        }
150
151        console.log('Buscando botones de ejercicio...');
152
153        // Buscar botón "Empezar" o "Continuar"
154        const startButtons = document.querySelectorAll('button[data-v-123be8a0].btn-panel-gamificacion.btn-start-active');
155        
156        if (startButtons.length > 0) {
157            console.log('Botón de inicio encontrado, haciendo clic...');
158            startButtons[0].click();
159            
160            // Esperar y luego incrementar progreso
161            setTimeout(async () => {
162                await incrementScoreAndProgress();
163                
164                // Buscar siguiente ejercicio
165                setTimeout(() => autoCompleteExercise(), AUTO_COMPLETE_CONFIG.autoClickDelay);
166            }, AUTO_COMPLETE_CONFIG.autoClickDelay);
167            
168            return;
169        }
170
171        // Buscar botones de respuesta o siguiente
172        const actionButtons = document.querySelectorAll('button[type="button"]');
173        for (const button of actionButtons) {
174            const buttonText = button.textContent.trim().toLowerCase();
175            if (buttonText.includes('siguiente') || buttonText.includes('continuar') || buttonText.includes('finalizar')) {
176                console.log('Botón de acción encontrado:', buttonText);
177                button.click();
178                
179                setTimeout(async () => {
180                    await incrementScoreAndProgress();
181                    setTimeout(() => autoCompleteExercise(), AUTO_COMPLETE_CONFIG.autoClickDelay);
182                }, AUTO_COMPLETE_CONFIG.autoClickDelay);
183                
184                return;
185            }
186        }
187
188        console.log('No se encontraron más ejercicios para completar');
189    }
190
191    // ============================================
192    // FUNCIONES DE APLICACIÓN DE VALORES GUARDADOS
193    // ============================================
194    async function applyModifiedPoints() {
195        const savedPoints = await getSavedPoints();
196        if (savedPoints !== null) {
197            await modifyScore(savedPoints);
198        }
199    }
200
201    async function applyModifiedUnit() {
202        const savedUnit = await getSavedUnit();
203        if (savedUnit !== null) {
204            const unitDisplay = document.querySelector('div[data-v-28b36b89].unidad span');
205            if (unitDisplay) {
206                unitDisplay.textContent = `Unidad ${savedUnit}`;
207                console.log('Unidad aplicada desde almacenamiento:', savedUnit);
208            }
209        }
210    }
211
212    async function applyUnlockedObjectives() {
213        const isUnlocked = await getSavedUnlockState();
214        if (isUnlocked) {
215            const objectives = document.querySelectorAll('div[data-un-premio][data-disabled="true"]');
216            objectives.forEach((objective) => {
217                objective.removeAttribute('data-disabled');
218                objective.setAttribute('data-disabled', 'false');
219                objective.style.opacity = '1';
220                objective.style.filter = 'none';
221                objective.style.pointerEvents = 'auto';
222                objective.style.cursor = 'pointer';
223            });
224            console.log('Objetivos desbloqueados aplicados desde almacenamiento');
225        }
226    }
227
228    // ============================================
229    // DESBLOQUEAR OBJETIVOS
230    // ============================================
231    async function unlockAllObjectives() {
232        const objectives = document.querySelectorAll('div[data-un-premio][data-disabled="true"]');
233        console.log('Objetivos encontrados:', objectives.length);
234        
235        objectives.forEach((objective) => {
236            objective.removeAttribute('data-disabled');
237            objective.setAttribute('data-disabled', 'false');
238            objective.style.opacity = '1';
239            objective.style.filter = 'none';
240            objective.style.pointerEvents = 'auto';
241            objective.style.cursor = 'pointer';
242        });
243
244        if (objectives.length > 0) {
245            await saveUnlockState(true);
246            showSuccessMessage(`🎉 ${objectives.length} objetivos desbloqueados`);
247        } else {
248            const allObjectives = document.querySelectorAll('div[data-un-premio]');
249            if (allObjectives.length > 0) {
250                await saveUnlockState(true);
251                showSuccessMessage('✅ Todos los objetivos ya están desbloqueados');
252            } else {
253                alert('No se encontraron objetivos');
254            }
255        }
256    }
257
258    // ============================================
259    // OBSERVADORES
260    // ============================================
261    function observeScoreChanges() {
262        const progressSection = document.querySelector('div[data-v-9d32d75b].progresslogros');
263        
264        if (!progressSection) {
265            return;
266        }
267
268        const observer = new MutationObserver(async () => {
269            const savedPoints = await getSavedPoints();
270            if (savedPoints !== null) {
271                await modifyScore(savedPoints);
272            }
273        });
274
275        observer.observe(progressSection, {
276            childList: true,
277            characterData: true,
278            subtree: true
279        });
280
281        console.log('Observer de puntos activado');
282    }
283
284    function observeObjectivesChanges() {
285        const awardsSection = document.querySelector('div[data-seccion-retos-x]');
286        
287        if (!awardsSection) {
288            return;
289        }
290
291        const observer = new MutationObserver(async () => {
292            const isUnlocked = await getSavedUnlockState();
293            if (isUnlocked) {
294                const objectives = document.querySelectorAll('div[data-un-premio][data-disabled="true"]');
295                if (objectives.length > 0) {
296                    console.log('Detectados objetivos bloqueados, desbloqueando...');
297                    objectives.forEach((objective) => {
298                        objective.removeAttribute('data-disabled');
299                        objective.setAttribute('data-disabled', 'false');
300                        objective.style.opacity = '1';
301                        objective.style.filter = 'none';
302                        objective.style.pointerEvents = 'auto';
303                        objective.style.cursor = 'pointer';
304                    });
305                }
306            }
307        });
308
309        observer.observe(awardsSection, {
310            childList: true,
311            subtree: true,
312            attributes: true,
313            attributeFilter: ['data-disabled']
314        });
315
316        console.log('Observer de objetivos activado');
317    }
318
319    // ============================================
320    // INTERFAZ DE USUARIO
321    // ============================================
322    function createControlPanel() {
323        const banner = document.querySelector('div[data-v-f8d4be6e].container_banner');
324        
325        if (!banner) {
326            console.log('No se encontró el banner, reintentando...');
327            return false;
328        }
329
330        if (document.getElementById('progrentis-control-panel')) {
331            console.log('El panel de control ya existe');
332            return true;
333        }
334
335        console.log('Creando panel de control');
336
337        const panel = document.createElement('div');
338        panel.id = 'progrentis-control-panel';
339        panel.style.cssText = `
340            position: fixed;
341            top: 20px;
342            right: 20px;
343            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
344            padding: 20px;
345            border-radius: 15px;
346            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
347            z-index: 10000;
348            min-width: 300px;
349            color: white;
350            font-family: Arial, sans-serif;
351        `;
352
353        const title = document.createElement('div');
354        title.style.cssText = `
355            font-size: 18px;
356            font-weight: bold;
357            margin-bottom: 15px;
358            text-align: center;
359            border-bottom: 2px solid rgba(255, 255, 255, 0.3);
360            padding-bottom: 10px;
361        `;
362        title.textContent = '⚡ Progrentis Turbo';
363
364        const buttonsContainer = document.createElement('div');
365        buttonsContainer.style.cssText = `
366            display: flex;
367            flex-direction: column;
368            gap: 10px;
369        `;
370
371        // Botón Auto-Completar
372        const autoCompleteBtn = document.createElement('button');
373        autoCompleteBtn.id = 'auto-complete-toggle';
374        autoCompleteBtn.textContent = '🚀 Iniciar Auto-Completar';
375        autoCompleteBtn.style.cssText = `
376            background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
377            color: white;
378            border: none;
379            padding: 12px 20px;
380            border-radius: 8px;
381            font-size: 14px;
382            font-weight: bold;
383            cursor: pointer;
384            transition: all 0.3s ease;
385        `;
386
387        autoCompleteBtn.addEventListener('mouseenter', () => {
388            autoCompleteBtn.style.transform = 'scale(1.05)';
389        });
390
391        autoCompleteBtn.addEventListener('mouseleave', () => {
392            autoCompleteBtn.style.transform = 'scale(1)';
393        });
394
395        autoCompleteBtn.addEventListener('click', async () => {
396            const isEnabled = await getAutoCompleteEnabled();
397            await setAutoCompleteEnabled(!isEnabled);
398            
399            if (!isEnabled) {
400                autoCompleteBtn.textContent = '⏸️ Detener Auto-Completar';
401                autoCompleteBtn.style.background = 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)';
402                showSuccessMessage('🚀 Auto-completar ACTIVADO');
403                autoCompleteExercise();
404            } else {
405                autoCompleteBtn.textContent = '🚀 Iniciar Auto-Completar';
406                autoCompleteBtn.style.background = 'linear-gradient(135deg, #11998e 0%, #38ef7d 100%)';
407                showSuccessMessage('⏸️ Auto-completar DESACTIVADO');
408            }
409        });
410
411        // Botón +10 Puntos Manual
412        const addPointsBtn = document.createElement('button');
413        addPointsBtn.textContent = '➕ +10 Puntos';
414        addPointsBtn.style.cssText = `
415            background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
416            color: white;
417            border: none;
418            padding: 12px 20px;
419            border-radius: 8px;
420            font-size: 14px;
421            font-weight: bold;
422            cursor: pointer;
423            transition: all 0.3s ease;
424        `;
425
426        addPointsBtn.addEventListener('mouseenter', () => {
427            addPointsBtn.style.transform = 'scale(1.05)';
428        });
429
430        addPointsBtn.addEventListener('mouseleave', () => {
431            addPointsBtn.style.transform = 'scale(1)';
432        });
433
434        addPointsBtn.addEventListener('click', async () => {
435            await incrementScoreAndProgress();
436        });
437
438        // Botón Modificar Valores
439        const modifyBtn = document.createElement('button');
440        modifyBtn.textContent = '✏️ Modificar Valores';
441        modifyBtn.style.cssText = `
442            background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
443            color: white;
444            border: none;
445            padding: 12px 20px;
446            border-radius: 8px;
447            font-size: 14px;
448            font-weight: bold;
449            cursor: pointer;
450            transition: all 0.3s ease;
451        `;
452
453        modifyBtn.addEventListener('mouseenter', () => {
454            modifyBtn.style.transform = 'scale(1.05)';
455        });
456
457        modifyBtn.addEventListener('mouseleave', () => {
458            modifyBtn.style.transform = 'scale(1)';
459        });
460
461        modifyBtn.addEventListener('click', async () => {
462            const newScore = prompt('¿Qué nota quieres tener? (0-100)', '100');
463            if (newScore !== null) {
464                const score = parseInt(newScore);
465                if (!isNaN(score) && score >= 0 && score <= 100) {
466                    await modifyScore(score);
467                    
468                    const newProgress = prompt('¿Qué progreso quieres tener? (0-100)', '100');
469                    if (newProgress !== null) {
470                        const progress = parseInt(newProgress);
471                        if (!isNaN(progress) && progress >= 0 && progress <= 100) {
472                            await modifyProgress(progress);
473                            showSuccessMessage(`✅ Nota: ${score} | Progreso: ${progress}%`);
474                        }
475                    }
476                } else {
477                    alert('Por favor ingresa un número válido entre 0 y 100');
478                }
479            }
480        });
481
482        // Botón Desbloquear Todo
483        const unlockBtn = document.createElement('button');
484        unlockBtn.textContent = '🏆 Desbloquear Todo';
485        unlockBtn.style.cssText = `
486            background: linear-gradient(135deg, #ffa751 0%, #ffe259 100%);
487            color: white;
488            border: none;
489            padding: 12px 20px;
490            border-radius: 8px;
491            font-size: 14px;
492            font-weight: bold;
493            cursor: pointer;
494            transition: all 0.3s ease;
495        `;
496
497        unlockBtn.addEventListener('mouseenter', () => {
498            unlockBtn.style.transform = 'scale(1.05)';
499        });
500
501        unlockBtn.addEventListener('mouseleave', () => {
502            unlockBtn.style.transform = 'scale(1)';
503        });
504
505        unlockBtn.addEventListener('click', () => {
506            unlockAllObjectives();
507        });
508
509        // Botón Resetear
510        const resetBtn = document.createElement('button');
511        resetBtn.textContent = '🔄 Resetear Todo';
512        resetBtn.style.cssText = `
513            background: linear-gradient(135deg, #868f96 0%, #596164 100%);
514            color: white;
515            border: none;
516            padding: 12px 20px;
517            border-radius: 8px;
518            font-size: 14px;
519            font-weight: bold;
520            cursor: pointer;
521            transition: all 0.3s ease;
522        `;
523
524        resetBtn.addEventListener('mouseenter', () => {
525            resetBtn.style.transform = 'scale(1.05)';
526        });
527
528        resetBtn.addEventListener('mouseleave', () => {
529            resetBtn.style.transform = 'scale(1)';
530        });
531
532        resetBtn.addEventListener('click', async () => {
533            if (confirm('¿Estás seguro de que quieres resetear TODO?')) {
534                await GM.deleteValue('progrentis_points');
535                await GM.deleteValue('progrentis_unit');
536                await GM.deleteValue('progrentis_unlocked');
537                await GM.deleteValue('progrentis_autocomplete');
538                location.reload();
539            }
540        });
541
542        buttonsContainer.appendChild(autoCompleteBtn);
543        buttonsContainer.appendChild(addPointsBtn);
544        buttonsContainer.appendChild(modifyBtn);
545        buttonsContainer.appendChild(unlockBtn);
546        buttonsContainer.appendChild(resetBtn);
547
548        panel.appendChild(title);
549        panel.appendChild(buttonsContainer);
550        document.body.appendChild(panel);
551
552        console.log('Panel de control creado exitosamente');
553        return true;
554    }
555
556    function showSuccessMessage(text) {
557        const message = document.createElement('div');
558        message.style.cssText = `
559            position: fixed;
560            top: 20px;
561            left: 50%;
562            transform: translateX(-50%);
563            background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
564            color: white;
565            padding: 15px 25px;
566            border-radius: 10px;
567            font-weight: bold;
568            box-shadow: 0 4px 15px rgba(17, 153, 142, 0.4);
569            z-index: 10001;
570            animation: slideDown 0.3s ease;
571            font-size: 16px;
572        `;
573        message.textContent = text;
574
575        document.body.appendChild(message);
576
577        setTimeout(() => {
578            message.style.animation = 'slideUp 0.3s ease';
579            setTimeout(() => message.remove(), 300);
580        }, 3000);
581    }
582
583    const style = document.createElement('style');
584    style.textContent = `
585        @keyframes slideDown {
586            from {
587                transform: translateX(-50%) translateY(-100px);
588                opacity: 0;
589            }
590            to {
591                transform: translateX(-50%) translateY(0);
592                opacity: 1;
593            }
594        }
595        @keyframes slideUp {
596            from {
597                transform: translateX(-50%) translateY(0);
598                opacity: 1;
599            }
600            to {
601                transform: translateX(-50%) translateY(-100px);
602                opacity: 0;
603            }
604        }
605    `;
606    document.head.appendChild(style);
607
608    // ============================================
609    // INICIALIZACIÓN
610    // ============================================
611    async function init() {
612        console.log('Iniciando extensión Progrentis Turbo...');
613        
614        await applyModifiedPoints();
615        await applyModifiedUnit();
616        await applyUnlockedObjectives();
617        
618        if (createControlPanel()) {
619            observeScoreChanges();
620            observeObjectivesChanges();
621            return;
622        }
623
624        const observer = new MutationObserver(async (mutations, obs) => {
625            if (createControlPanel()) {
626                await applyModifiedPoints();
627                await applyModifiedUnit();
628                await applyUnlockedObjectives();
629                observeScoreChanges();
630                observeObjectivesChanges();
631                obs.disconnect();
632            }
633        });
634
635        observer.observe(document.body, {
636            childList: true,
637            subtree: true
638        });
639
640        setTimeout(() => {
641            observer.disconnect();
642            createControlPanel();
643            applyModifiedPoints();
644            applyModifiedUnit();
645            applyUnlockedObjectives();
646            observeScoreChanges();
647            observeObjectivesChanges();
648        }, 10000);
649    }
650
651    if (document.readyState === 'loading') {
652        document.addEventListener('DOMContentLoaded', init);
653    } else {
654        init();
655    }
656
657})();