您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Auto-refresh GeForce Now page & notifies the user if free capacity is available. Fully optimized for accurate countdown even in the background, with a full range of settings to customize your experience as you'd like.
// ==UserScript== // @name GeForceNOW Smart Refresh Script by Mohi // @name:ar برنامج تحديث صفحة جيفورس ناو تلقائي بواسطة Mohi // @namespace http://tampermonkey.net/ // @version 5.0 // @description Auto-refresh GeForce Now page & notifies the user if free capacity is available. Fully optimized for accurate countdown even in the background, with a full range of settings to customize your experience as you'd like. // @description:ar يقوم بتحديث صفحة GeForce Now تلقائيًا ويقوم بإعلامك إذا كان هناك سعة مجانية متاحة. تم تصميم السكربت لتحسين الأداء مع عدادات دقيقة، حتى عندما تكون الصفحة في الخلفية. يقدم السكربت مجموعة من الإعدادات القابلة للتخصيص، بما في ذلك النقر التلقائي، وإشعارات الصوت، وأساليب الكشف، لتعزيز تجربتك. // @author Mohi // @license GNU GPLv3 // @match https://www.nvidia.com/gfn/product-matrix/* // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_notification // ==/UserScript== (function() { 'use strict'; const defaultSettings = { AUTO_CLICK_BUTTON: true, refreshInterval: 15, freeCapacitySoundURL: 'https://www.myinstants.com/media/sounds/airhorn.mp3', freeCapacitySoundVolume: 0.3, notificationTimeout: 5000, autoReload: true, detectionMethod: 'both' // "button", "text", or "both" }; let AUTO_CLICK_BUTTON = GM_getValue("AUTO_CLICK_BUTTON", defaultSettings.AUTO_CLICK_BUTTON); let refreshInterval = GM_getValue("refreshInterval", defaultSettings.refreshInterval); let freeCapacitySoundURL = GM_getValue("freeCapacitySoundURL", defaultSettings.freeCapacitySoundURL); let freeCapacitySoundVolume = GM_getValue("freeCapacitySoundVolume", defaultSettings.freeCapacitySoundVolume); let notificationTimeout = GM_getValue("notificationTimeout", defaultSettings.notificationTimeout); let autoReload = GM_getValue("autoReload", defaultSettings.autoReload); let detectionMethod = GM_getValue("detectionMethod", defaultSettings.detectionMethod); let countdownTime = refreshInterval; let menuCommandIDs = []; let capacityFound = false; // Web Worker for countdown let countdownWorker; // Handle background/foreground visibility document.addEventListener('visibilitychange', function() { if (document.hidden) { console.log("Page is in the background. Reducing resource usage."); } else { console.log("Page is in the foreground. Restoring full performance."); } }); function playFreeCapacitySound() { if (freeCapacitySoundURL) { const audio = new Audio(freeCapacitySoundURL); audio.volume = freeCapacitySoundVolume; audio.play(); } } function showNotification(title, message) { GM_notification({ text: message, title: title, timeout: notificationTimeout }); } function updateTabTitle() { document.title = !capacityFound ? `Refreshing in ${Math.round(countdownTime)}s | GFN` : "Free Capacity Found | GFN"; } function handleCountdown(data) { if (!capacityFound && autoReload) { countdownTime = data.countdownTime; updateTabTitle(); if (countdownTime <= 0) { triggerReload(); } } } function triggerReload() { checkCapacityMessage(); // Check capacity before deciding to reload if (!capacityFound) { // Only reload if free capacity has not been found countdownTime = refreshInterval; location.reload(); } } function checkCapacityMessage() { const capacityMessage = document.body.innerText.includes("GeForce NOW is currently at capacity."); const playButton = document.querySelector('button[data-qa-id="play-button"]'); if (detectionMethod === 'text' && !capacityMessage && !capacityFound) { capacityFound = true; notifyUser(); } if (detectionMethod === 'button' && playButton && !capacityFound) { capacityFound = true; clickPlayButton(); } if (detectionMethod === 'both' && (!capacityMessage || playButton) && !capacityFound) { capacityFound = true; notifyUser(); if (playButton) clickPlayButton(); } } function notifyUser() { playFreeCapacitySound(); showNotification("GeForce NOW Free Capacity", "Free capacity found on GeForce NOW!"); updateTabTitle(); } function clickPlayButton() { const playButton = document.querySelector('button[data-qa-id="play-button"]'); if (playButton && !capacityFound) { capacityFound = true; playButton.click(); playFreeCapacitySound(); updateTabTitle(); } } // Create Web Worker for countdown function createCountdownWorker() { const blob = new Blob([` let countdownTime = ${refreshInterval}; function countdownStep() { countdownTime -= 1; postMessage({ countdownTime }); if (countdownTime > 0) { setTimeout(countdownStep, 1000); } } countdownStep(); `], { type: 'application/javascript' }); const workerURL = URL.createObjectURL(blob); return new Worker(workerURL); } function startCountdownWorker() { if (countdownWorker) { countdownWorker.terminate(); } countdownWorker = createCountdownWorker(); countdownWorker.onmessage = function(event) { handleCountdown(event.data); }; } // Keep-Alive Ping function keepAlivePing() { fetch('https://example.com/ping', { method: 'GET' }) .catch(err => console.error('Ping failed', err)); setTimeout(keepAlivePing, 30000); // Ping every 30 seconds } function updateMenuCommands() { for (let id of menuCommandIDs) { GM_unregisterMenuCommand(id); } menuCommandIDs = []; // Detection Method Menu menuCommandIDs.push(GM_registerMenuCommand(`Set Detection Method (current: ${detectionMethod})`, setDetectionMethod)); // Refresh Interval menuCommandIDs.push(GM_registerMenuCommand(`Set Refresh Interval (current: ${refreshInterval}s)`, setRefreshInterval)); // Free Capacity Sound URL menuCommandIDs.push(GM_registerMenuCommand(`Set Free Capacity Sound URL (current: ${freeCapacitySoundURL})`, setFreeCapacitySoundURL)); // Free Capacity Sound Volume menuCommandIDs.push(GM_registerMenuCommand(`Set Free Capacity Sound Volume (current: ${freeCapacitySoundVolume * 100}%)`, setFreeCapacitySoundVolume)); // Notification Timeout menuCommandIDs.push(GM_registerMenuCommand(`Set Notification Timeout (current: ${notificationTimeout / 1000}s)`, setNotificationTimeout)); // Auto Click Button (disable if text detection is selected) if (detectionMethod === 'text') { menuCommandIDs.push(GM_registerMenuCommand("Auto Click Button (disabled due to text detection)", () => { alert("Auto Click Button is disabled because detection method is set to 'text'. Change detection method to enable this feature."); })); } else if (AUTO_CLICK_BUTTON) { menuCommandIDs.push(GM_registerMenuCommand("Turn Auto Click Button OFF", () => toggleAutoClickButton(false))); } else { menuCommandIDs.push(GM_registerMenuCommand("Turn Auto Click Button ON", () => toggleAutoClickButton(true))); } menuCommandIDs.push(GM_registerMenuCommand("Reset to Default Settings", resetToDefaultSettings)); } function setDetectionMethod() { const newMethod = prompt("Enter detection method (button, text, both):", detectionMethod); if (newMethod === 'button' || newMethod === 'text' || newMethod === 'both') { detectionMethod = newMethod; GM_setValue("detectionMethod", detectionMethod); updateMenuCommands(); } else { alert("Invalid detection method. Please enter 'button', 'text', or 'both'."); } } function resetToDefaultSettings() { const confirmation = confirm( `Are you sure you want to reset settings to default? \n` + `Default Settings:\n` + `- Auto Click Button: ${defaultSettings.AUTO_CLICK_BUTTON ? "ON" : "OFF"}\n` + `- Refresh Interval: ${defaultSettings.refreshInterval}s\n` + `- Free Capacity Sound URL: ${defaultSettings.freeCapacitySoundURL}\n` + `- Free Capacity Sound Volume: ${defaultSettings.freeCapacitySoundVolume * 100}%\n` + `- Notification Timeout: ${defaultSettings.notificationTimeout / 1000}s\n` + `- Detection Method: ${defaultSettings.detectionMethod}` ); if (confirmation) { AUTO_CLICK_BUTTON = defaultSettings.AUTO_CLICK_BUTTON; refreshInterval = defaultSettings.refreshInterval; freeCapacitySoundURL = defaultSettings.freeCapacitySoundURL; freeCapacitySoundVolume = defaultSettings.freeCapacitySoundVolume; notificationTimeout = defaultSettings.notificationTimeout; detectionMethod = defaultSettings.detectionMethod; GM_setValue("AUTO_CLICK_BUTTON", AUTO_CLICK_BUTTON); GM_setValue("refreshInterval", refreshInterval); GM_setValue("freeCapacitySoundURL", freeCapacitySoundURL); GM_setValue("freeCapacitySoundVolume", freeCapacitySoundVolume); GM_setValue("notificationTimeout", notificationTimeout); GM_setValue("detectionMethod", detectionMethod); countdownTime = refreshInterval; updateMenuCommands(); showNotification("Settings Reset", "All settings have been reset to default values."); } } function setRefreshInterval() { const newInterval = prompt("Enter new refresh interval in seconds:", refreshInterval); if (newInterval !== null) { refreshInterval = parseInt(newInterval); GM_setValue("refreshInterval", refreshInterval); countdownTime = refreshInterval; updateMenuCommands(); } } function setFreeCapacitySoundURL() { const newURL = prompt("Enter new Free Capacity Sound URL:", freeCapacitySoundURL); if (newURL !== null) { freeCapacitySoundURL = newURL; GM_setValue("freeCapacitySoundURL", freeCapacitySoundURL); updateMenuCommands(); } } function setFreeCapacitySoundVolume() { const newVolume = prompt("Enter Free Capacity Sound Volume (0-100):", freeCapacitySoundVolume * 100); if (newVolume !== null) { freeCapacitySoundVolume = parseInt(newVolume) / 100; GM_setValue("freeCapacitySoundVolume", freeCapacitySoundVolume); updateMenuCommands(); } } function setNotificationTimeout() { const newTimeout = prompt("Enter new Notification Timeout in seconds:", notificationTimeout / 1000); if (newTimeout !== null) { notificationTimeout = parseInt(newTimeout) * 1000; GM_setValue("notificationTimeout", notificationTimeout); updateMenuCommands(); } } function toggleAutoClickButton(turnOn) { AUTO_CLICK_BUTTON = turnOn; GM_setValue("AUTO_CLICK_BUTTON", turnOn); showNotification("Auto Click Button Toggled", `Auto Click Button is now ${turnOn ? "ON" : "OFF"}`); updateMenuCommands(); } startCountdownWorker(); keepAlivePing(); updateMenuCommands(); })();