Monitor Ping and FPS, track session time, and reset password securely.
// ==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
})();