您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
防止屏幕自动休眠。使用Tampermonkey菜单切换悬浮窗,或在无菜单支持时默认显示。
// ==UserScript== // @name Stay Awake! (Modern NoSleep) // @name:zh-CN 保持唤醒!(新防休眠) // @namespace https://github.com/ymhomer/ym_Userscript // @version 0.2.1 // @description Prevents the screen from sleeping. Toggles floating UI with Tampermonkey menu, or shows it by default if unsupported. // @description:zh-CN 防止屏幕自动休眠。使用Tampermonkey菜单切换悬浮窗,或在无菜单支持时默认显示。 // @author ymhomer // @match *://*/* // @grant GM_addStyle // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @run-at document-idle // @license MIT // ==/UserScript== (function() { 'use strict'; class ModernNoSleep { constructor() { this.enabled = false; this._wakeLock = null; this._noSleepVideo = null; this.wakeLockType = 'wakeLock' in navigator ? 'modern' : 'legacy'; if (this.wakeLockType === 'modern') { document.addEventListener('visibilitychange', this._onVisibilityChange.bind(this)); document.addEventListener('fullscreenchange', this._onVisibilityChange.bind(this)); } } async enable() { if (this.enabled) return; try { if (this.wakeLockType === 'modern') { this._wakeLock = await navigator.wakeLock.request('screen'); this._wakeLock.addEventListener('release', () => { if (this.enabled) { this.enabled = false; if(this.onRelease) this.onRelease(); } }); } else { this._createLegacyVideo(); await this._noSleepVideo.play(); } this.enabled = true; } catch (err) { this.enabled = false; throw err; } } disable() { if (!this.enabled) return; if (this.wakeLockType === 'modern' && this._wakeLock) { this._wakeLock.release(); this._wakeLock = null; } else if (this.wakeLockType === 'legacy' && this._noSleepVideo) { this._noSleepVideo.pause(); } this.enabled = false; } get isEnabled() { return this.enabled; } _onVisibilityChange() { if (this.enabled && document.visibilityState === 'visible') { this.enable().catch(() => {}); } } _createLegacyVideo() { if (this._noSleepVideo) return; const minimalMp4 = 'data:video/mp4;base64,AAAAHGZ0eXBNNFYgAAACAGlzb21pc28yYXZjMQAAAAhmcmVlAAAAG21kYXQAAAGzABAHAAABthABGWAAAAABAAA2Z2VzZHMAAAAAAQABAAEAAAA2YXZjMQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAEAAQABAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAc3R0cwAAAAAAAAABAAAAAQABAAABAAAAHHN0c2QAAAAAAAAAAQAAAFhzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAABoc3RzegAAAAAAAAAAAAAAAQAAAAEAAAAUc3RjbwAAAAAAAAABAAAAMAAAAGB1ZHRhAAAAWG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAK2lsc3QAAAAjqXRvbwAAABtkYXRhAAAAAQAAAABMYXZmYzgxLjEyLjEwMA=='; this._noSleepVideo = document.createElement('video'); this._noSleepVideo.setAttribute('title', 'No Sleep'); this._noSleepVideo.setAttribute('playsinline', ''); this._noSleepVideo.setAttribute('loop', ''); this._noSleepVideo.muted = true; const source = document.createElement('source'); source.src = minimalMp4; source.type = 'video/mp4'; this._noSleepVideo.appendChild(source); } } const noSleep = new ModernNoSleep(); const isTampermonkey = typeof GM_registerMenuCommand !== 'undefined'; let menuCommandId = null; let floatingUIVisible = false; function updateFloatingButtonState(enabled) { const toggleButton = document.getElementById('nosleep-toggle-btn'); if (!toggleButton) return; if (enabled) { toggleButton.innerHTML = '☀️'; toggleButton.classList.add('active'); toggleButton.title = 'Screen lock is active. Click to disable.'; } else { toggleButton.innerHTML = '🌙'; toggleButton.classList.remove('active'); toggleButton.title = 'Screen lock is inactive. Click to enable.'; } } function createFloatingButtonUI() { const container = document.createElement('div'); container.id = 'modern-nosleep-widget'; const toggleButton = document.createElement('button'); toggleButton.id = 'nosleep-toggle-btn'; toggleButton.title = 'Toggle Screen Wake Lock'; toggleButton.innerHTML = '🌙'; const hideButton = document.createElement('button'); hideButton.id = 'nosleep-hide-btn'; hideButton.title = 'Hide for this session'; hideButton.innerHTML = '×'; container.appendChild(toggleButton); container.appendChild(hideButton); document.body.appendChild(container); toggleButton.addEventListener('click', async () => { if (noSleep.isEnabled) { noSleep.disable(); updateFloatingButtonState(false); } else { try { await noSleep.enable(); updateFloatingButtonState(true); } catch (err) { updateFloatingButtonState(false); } } }); hideButton.addEventListener('click', () => { container.style.display = 'none'; floatingUIVisible = false; updateMenuCommand(); }); noSleep.onRelease = () => { updateFloatingButtonState(false); }; } function updateMenuCommand() { if (menuCommandId) GM_unregisterMenuCommand(menuCommandId); menuCommandId = GM_registerMenuCommand( floatingUIVisible ? 'Hide Floating Window' : 'Show Floating Window', () => { const container = document.getElementById('modern-nosleep-widget'); if (container) { if (floatingUIVisible) { container.style.display = 'none'; } else { container.style.display = 'flex'; } floatingUIVisible = !floatingUIVisible; } updateMenuCommand(); } ); } GM_addStyle(` #modern-nosleep-widget { position: fixed; bottom: 20px; right: 20px; z-index: 999999; display: flex; gap: 5px; align-items: center; } #modern-nosleep-widget button { background-color: rgba(0, 0, 0, 0.7); color: white; border: 1px solid rgba(255, 255, 255, 0.5); border-radius: 50%; cursor: pointer; box-shadow: 0 2px 10px rgba(0,0,0,0.2); transition: background-color 0.2s, transform 0.2s; font-family: sans-serif; } #modern-nosleep-widget button:hover { background-color: rgba(0, 0, 0, 0.9); transform: scale(1.1); } #nosleep-toggle-btn { width: 48px; height: 48px; font-size: 24px; line-height: 48px; } #nosleep-toggle-btn.active { background-color: #f39c12; } #nosleep-hide-btn { width: 24px; height: 24px; font-size: 16px; line-height: 22px; } `); createFloatingButtonUI(); if (isTampermonkey) { const container = document.getElementById('modern-nosleep-widget'); if (container) { container.style.display = 'none'; } updateMenuCommand(); } else { floatingUIVisible = true; } })();