您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A script that observes the pages via MutationObserver and quickly captures and activates the button to extend the session and not be signed off.
// ==UserScript== // @name Keep MillenniumBCP Session Active // @namespace http://tampermonkey.net/ // @version 1.0 // @description A script that observes the pages via MutationObserver and quickly captures and activates the button to extend the session and not be signed off. // @author JoaoWorkspace // @icon https://ptpimg.me/hy2wdn.png // @grant none // @match https://corp.millenniumbcp.pt/* // @license MIT // ==/UserScript== (function() { 'use strict'; // Updated number revealing how many times the session has been extended. let revivalCount = 0; /*______________*/ /* Common tools */ /*______________*/ // The number of times the mutation observer executes (meaning also, how many mutations detected), variable to be incremented by the code. let executionCount = 0; const debug = false; async function incrementExecutionNumber(mutations){ executionCount ++; if(executionCount > 999){ observer.disconnect(); logWithTimestamp(`Execution Count: ${executionCount} has reached a huge number. Stopping program...`); } // This formats number 1 to 001 and 23 to 023. // It predicts the execution count (meaning number of mutations) in the same page doesn't surpass 999 executions. // A very realistic number, safe for edge cases, like videogames. const formattedNumber = executionCount.toString().padStart(3, '0'); console.log('####################################################'); console.log(`############### Execution Number ${formattedNumber} ###############`); console.log('####################################################'); if (mutations) { // Count each type of mutation const mutationCounts = mutations.reduce( (counts, mutation) => { counts[mutation.type] = (counts[mutation.type] || 0) + 1; return counts; }, { attributes: 0, characterData: 0, childList: 0 } ); console.log('################## Mutation Stats ##################'); console.log(`# Attribute Mutations: ${mutationCounts.attributes}`); console.log(`# Character Data Mutations: ${mutationCounts.characterData}`); console.log(`# Child List Mutations: ${mutationCounts.childList}`); } console.log('####################################################'); } async function giveStatusUpdate(section){ const formattedNumber = executionCount.toString().padStart(3, '0'); const formattedTimestamp = new Date() .toISOString() .replace('T', ' ') .replace(/\.\d+/, match => match.substring(0, 2)) // Keep only the first decimal of milliseconds .replace('Z', ''); // Remove trailing 'Z' console.log('####################################################'); console.log(`############### Execution ${formattedNumber} Result ###############`); console.log(`############### ${formattedTimestamp} ##############`); console.log('####################################################'); console.log(`# Section ${section} complete...`); console.log('####################################################'); console.log(`# Session Revivals: ${revivalCount}`); console.log('####################################################'); } // Utility function for logging with a timestamp function logWithTimestamp(message, ...optionalParams) { const formattedTimestamp = new Date() .toISOString() .replace('T', ' ') .replace(/\.\d+/, match => match.substring(0, 2)) // Keep only the first decimal of milliseconds .replace('Z', ''); // Remove trailing 'Z' console.log(`${formattedTimestamp} | ${message}`, ...optionalParams); } // Debug function for adding varied listeners to the target element async function injectEventListeners(targetElement) { targetElement.addEventListener('focus', (e) => logWithTimestamp('Focused!', e)); targetElement.addEventListener('click', (e) => logWithTimestamp('Clicked!', e)); targetElement.addEventListener('blur', (e) => logWithTimestamp('Blurred!', e)); targetElement.addEventListener('change', (e) => logWithTimestamp('Changed!', e)); targetElement.addEventListener('input', (e) => logWithTimestamp('Received Input!', e)); targetElement.addEventListener('keyup', (e) => logWithTimestamp('Key Up!', e)); targetElement.addEventListener('keydown', (e) => logWithTimestamp('Key Down!', e)); targetElement.addEventListener('keypress', (e) => logWithTimestamp('Key Pressed!', e)); targetElement.addEventListener('mousedown', (e) => logWithTimestamp('Mouse Down!', e)); targetElement.addEventListener('mouseup', (e) => logWithTimestamp('Mouse Up!', e)); } // Waits for a single element matching the selector async function waitForElement(selector, source, timeout = 5000) { return new Promise((resolve, reject) => { const interval = setInterval(() => { const element = source.querySelector(selector); if (element) { clearInterval(interval); resolve(element); } }, 100); setTimeout(() => { clearInterval(interval); if(debug) logWithTimestamp(`Element with selector \"${selector}\" not found within timeout.`); resolve(null); }, timeout); }); } // Waits for at least a single element matching the selector async function waitForElements(selector, source, timeout = 5000) { return new Promise((resolve, reject) => { const interval = setInterval(() => { const elements = source.querySelectorAll(selector); if (elements) { clearInterval(interval); resolve(elements); } }, 100); setTimeout(() => { clearInterval(interval); if(debug) logWithTimestamp(`Elements with selector \"${selector}\" not found within timeout.`); resolve(null); }, timeout); }); } // Sets the value of the input element and ensures changes are registered async function setInputValue(inputElement, value) { if (inputElement) { const valueSetter = Object.getOwnPropertyDescriptor( Object.getPrototypeOf(inputElement), 'value' )?.set; if (valueSetter) { valueSetter.call(inputElement, value); } else { inputElement.value = value; } dispatchInputChange(inputElement); } else { logWithTimestamp("Input element is null or undefined.", "warn"); } } // Dispatches input and change events for the input element async function dispatchInputChange(inputElement) { logWithTimestamp(`Dispatching Change Event to ${inputElement.name}`); if (inputElement) { ['change', 'input'].forEach((eventType) => { const event = new Event(eventType, { bubbles: true }); inputElement.dispatchEvent(event); }); } } // Finds and clicks the submit button async function findAndClickButton(submitButton) { if (submitButton) { if (submitButton.getAttribute('aria-disabled') === 'true') { logWithTimestamp("Submit button is disabled. Removing disabled attribute."); } submitButton.removeAttribute('aria-disabled'); submitButton.click(); logWithTimestamp("Submit button clicked."); } else { logWithTimestamp("Submit button not found.", "warn"); } } // To control debounce timing let debounceTimeout = null; // The DEBOUNCE_DELAY prevents the script from executing actions too frequently by grouping mutation events within a set interval (1 second by default). const DEBOUNCE_DELAY = 1000; /* * Use MutationObserver with Debounce and log the many times it gets triggered * Guarantees that when there's a rapid successive number of mutations on the page, it ignores it * Only "processes mutations" after at least 1 second without mutations occurs. */ const observer = new MutationObserver((mutations) => { if(debug) logWithTimestamp(`Observer Triggered... Clearing timeout of ${debounceTimeout} ms`); if (debounceTimeout) clearTimeout(debounceTimeout); // Clear the previous timeout if(debug) logWithTimestamp(`Setting a timeout of ${DEBOUNCE_DELAY} ms`); debounceTimeout = setTimeout(() => processMutations(mutations), DEBOUNCE_DELAY); }); /*_____________________*/ /* End of Common Tools */ /*_____________________*/ async function processMutations(mutations) { console.clear(); if(debug) logWithTimestamp(`Found the following mutations`,mutations); await incrementExecutionNumber(mutations); if(await locateKeepAliveAndExtendSession()){ revivalCount++; } giveStatusUpdate("Keep-Alive"); } // Define a function to locate the Keep-Alive button and press it to extend it async function locateKeepAliveAndExtendSession() { const sessionButtons = await waitForElements('button.cf-button', document); for (const button of sessionButtons) { // Check if the button's text content is "Sim" if (button.textContent.trim() === 'Sim') { logWithTimestamp('Session keep-alive button found:', button); await findAndClickButton(button); // Your existing function to click the button return true; // Indicate success } } logWithTimestamp('Session keep-alive button not found!') return false; // Indicate failure } console.log(`JoaoWorkspace's Userscript injected! Starting observer on this page's document: ${window.location.href}`); // Start observing only after the entire page is fully loaded window.addEventListener('load', () => { observer.observe(document.body, { childList: true, subtree: true }); console.log('Observer started after window load.'); }); })();