Duohelper

Monitor Ping and FPS, track session time, and reset password securely.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Duohelper
// @namespace    http://tampermonkey.net/
// @version      1.2.0
// @description  Monitor Ping and FPS, track session time, and reset password securely.
// @author       Your Name
// @match        https://*.duolingo.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// ==/UserScript==

(function() {
    'use strict';

    let basePing = 100; // Basic Ping (ms)
    let baseFps = 60; // Basic FPS

    let ping = basePing; // Current ping value (ms)
    let fps = baseFps; // Current FPS value
    let sessionStartTime = Date.now(); // Session start time

    // Function to check if localStorage is supported
    function isLocalStorageSupported() {
        try {
            const testKey = '__testKey';
            localStorage.setItem(testKey, testKey);
            localStorage.removeItem(testKey);
            return true;
        } catch (error) {
            return false;
        }
    }

    // Check if localStorage is supported
    if (!isLocalStorageSupported()) {
        console.error('LocalStorage is not supported.');
        return;
    }

    // Create and append CSS styles
    const style = document.createElement('style');
    style.textContent = `
        #performanceMonitor {
            position: fixed;
            top: 10px;
            right: 10px;
            padding: 8px;
            border: 5px solid #ddd;
            background-color: #0a0a0a;
            color: white;
            border-radius: 8px;
            font-family: Arial, sans-serif;
            font-size: 14px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
            width: 200px;
            text-align: left;
            overflow: auto;
            cursor: pointer;
            z-index: 9999;
            transition: opacity 0.3s ease-in-out;
        }
        #performanceMonitor button {
            display: block;
            margin-bottom: 5px;
            cursor: pointer;
            background-color: #444;
            color: white;
            border: none;
            border-radius: 4px;
            padding: 4px 8px;
            font-size: 12px;
            transition: background-color 0.3s;
        }
        #performanceMonitor button:hover {
            background-color: #666;
        }
        #performanceContent {
            display: block;
        }
        .modal {
            position: fixed;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            background-color: rgba(0, 0, 0, 0.9);
            color: white;
            border-radius: 8px;
            padding: 20px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
            z-index: 10000;
            display: none;
        }
        .modal h3 {
            margin-bottom: 10px;
        }
        .modal label {
            display: block;
            margin-bottom: 5px;
        }
        .modal input[type="text"], .modal input[type="password"], .modal input[type="email"] {
            width: 100%;
            padding: 8px;
            margin-bottom: 10px;
            border: 1px solid #666;
            border-radius: 4px;
            background-color: #333;
            color: white;
        }
        .modal button {
            margin-top: 10px;
            padding: 8px 16px;
            background-color: #1cb0f6;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            transition: background-color 0.3s;
        }
        .modal button:hover {
            background-color: #0a7bb0;
        }
    `;
    document.head.appendChild(style);

    // Create container for display
    const container = document.createElement('div');
    container.id = 'performanceMonitor';
    container.title = 'Click to hide/show';
    document.body.appendChild(container);

    // Create content wrapper
    const contentWrapper = document.createElement('div');
    contentWrapper.id = 'performanceContentWrapper';
    container.appendChild(contentWrapper);

    // Create content area
    const content = document.createElement('div');
    content.id = 'performanceContent';
    contentWrapper.appendChild(content);

    // Create toggle button
    const toggleButton = document.createElement('button');
    toggleButton.textContent = 'Hide';
    toggleButton.addEventListener('mouseover', () => {
        toggleButton.style.backgroundColor = '#666';
    });
    toggleButton.addEventListener('mouseout', () => {
        toggleButton.style.backgroundColor = '#444';
    });
    toggleButton.addEventListener('click', () => {
        const isVisible = contentWrapper.style.display !== 'none';
        contentWrapper.style.display = isVisible ? 'none' : 'block';
        toggleButton.textContent = isVisible ? 'Show' : 'Hide';
    });
    container.appendChild(toggleButton);

    // Create reload button
    const reloadButton = document.createElement('button');
    reloadButton.textContent = 'Reload Page';
    reloadButton.addEventListener('click', () => {
        location.reload();
    });
    contentWrapper.appendChild(reloadButton);

    // Function to measure ping
    async function measurePing(url) {
        try {
            const start = performance.now();
            const response = await fetch(url, { method: 'HEAD' });
            await response;
            const end = performance.now();
            const pingValue = Math.round(end - start) + ' ms';
            updateDisplay(pingValue);
        } catch (error) {
            console.error('Ping Error:', error);
            updateDisplay('Error');
        }
    }

    // Function to measure FPS
    let lastFrameTime = performance.now();
    let frameCount = 0;

    function measureFPS() {
        const now = performance.now();
        const delta = now - lastFrameTime;
        frameCount++;

        if (delta >= 1000) {
            const fpsValue = Math.round((frameCount * 1000) / delta);
            updateDisplay(null, fpsValue);
            frameCount = 0;
            lastFrameTime = now;
        }

        requestAnimationFrame(measureFPS);
    }

    // Function to update display
    function updateDisplay(pingValue, fpsValue) {
        if (pingValue !== undefined) {
            ping = pingValue;
        }
        if (fpsValue !== undefined) {
            fps = fpsValue;
        }

        const elapsedTime = formatSessionTime(Date.now() - sessionStartTime);

        const display = document.getElementById('performanceContent');
        display.innerHTML = `
            <div><strong>Ping:</strong> ${ping}</div>
            <div><strong>FPS:</strong> ${fps}</div>
            <div><strong>Session Time:</strong> ${elapsedTime}</div>
            <button id="resetPassword" style="margin-top: 5px;">Reset Password</button>
        `;
        document.getElementById('resetPassword').addEventListener('click', showResetPasswordModal);
    }

    // Format session time in HH:mm:ss format
    function formatSessionTime(milliseconds) {
        let seconds = Math.floor(milliseconds / 1000);
        const hours = Math.floor(seconds / 3600);
        seconds %= 3600;
        const minutes = Math.floor(seconds / 60);
        seconds %= 60;
        return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
    }

    // Modal to reset password
    const resetPasswordModal = document.createElement('div');
    resetPasswordModal.className = 'modal';
    resetPasswordModal.innerHTML = `
        <h3>Reset Password</h3>
        <div>
            <label for="resetEmail">Email:</label>
            <input type="email" id="resetEmail" />
        </div>
        <button id="sendResetEmail" style="margin-top: 10px;">Send Reset Email</button>
        <button id="cancelResetPassword" style="margin-top: 10px;">Cancel</button>
    `;
    document.body.appendChild(resetPasswordModal);

    // Show reset password modal function
    function showResetPasswordModal() {
        resetPasswordModal.style.display = 'block';
    }

    // Hide reset password modal function
    function hideResetPasswordModal() {
        resetPasswordModal.style.display = 'none';
    }

    // Cancel reset password modal function
    document.getElementById('cancelResetPassword').addEventListener('click', hideResetPasswordModal);

    // Send reset email function
    document.getElementById('sendResetEmail').addEventListener('click', () => {
        const email = document.getElementById('resetEmail').value;

        if (email && validateEmail(email)) {
            // Simulate sending a reset password email
            console.log('Sending password reset email to:', email);
            alert('A password reset email has been sent to ' + email);
            hideResetPasswordModal();
        } else {
            alert('Please enter a valid email address.');
        }
    });

    // Validate email address
    function validateEmail(email) {
        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        return emailRegex.test(email);
    }

    // Start measuring ping and FPS
    setInterval(() => {
        measurePing('https://www.duolingo.com');
    }, 5000); // Measure ping every 5 seconds

    requestAnimationFrame(measureFPS); // Start measuring FPS

    // Initialize display
    updateDisplay(basePing, baseFps); // Initial display update
})();