您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
释放 YouTube 用过的 IndexDBs 让后台页面能进入休眠
当前为
// ==UserScript== // @name YouTube Unhold IndexedDB // @name:en YouTube Unhold IndexedDB // @name:ja YouTube Unhold IndexedDB // @name:zh-TW YouTube Unhold IndexedDB // @name:zh-CN YouTube Unhold IndexedDB // @namespace http://tampermonkey.net/ // @version 2022.12.27 // @license MIT License // @description Release YouTube's used IndexDBs to make background tabs able to sleep // @description:en Release YouTube's used IndexDBs to make background tabs able to sleep // @description:ja YouTube の 使用済みIndexDB を解放して、バックグラウンドページを休止状態になるように // @description:zh-TW 釋放 YouTube 用過的 IndexDBs 讓後台頁面能進入休眠 // @description:zh-CN 释放 YouTube 用过的 IndexDBs 让后台页面能进入休眠 // @author CY Fung // @match https://www.youtube.com/* // @match https://www.youtube.com/embed/* // @match https://www.youtube-nocookie.com/embed/* // @match https://www.youtube.com/live_chat* // @match https://www.youtube.com/live_chat_replay* // @match https://music.youtube.com/* // @exclude /^https?://\S+\.(txt|png|jpg|jpeg|gif|xml|svg|manifest|log|ini)[^\/]*$/ // @icon https://raw.githubusercontent.com/cyfung1031/userscript-supports/main/icons/youtube-unlock-indexedDB.png // @supportURL https://github.com/cyfung1031/userscript-supports // @run-at document-start // @grant none // @unwrap // @allFrames // @inject-into page // ==/UserScript== /* jshint esversion:8 */ const DEBUG_LOG = false; const DB_NAME_FOR_TESTING = 'testdb-Q4IOpq0p' let runCount = 0; const isSupported = (function (console, consoleX) { 'use strict'; let [window] = new Function('return [window];')(); // real window object const isSupported = (((window || 0).indexedDB || 0).constructor || 0).name === 'IDBFactory' && typeof requestIdleCallback === 'function' if (isSupported) { const addEventListenerKey = Symbol(); const removeEventListenerKey = Symbol(); const openKey = Symbol(); const funcHooks = new WeakMap(); let openCount = 0; const msgStore = []; const message = (message) => { msgStore.push(message); if (openCount === 0 && msgStore.length > 0) { setTimeout(() => { if (openCount === 0 && msgStore.length > 0) { let messages = [...msgStore] msgStore.length = 0 messages.sort((a, b) => a.databaseId.localeCompare(b.databaseId) || a.time - b.time) consoleX.dir(messages) } }, 300) } }; const mTime = Date.now() function releaseOnIdle(db, databaseId, eventType, event_type) { setTimeout(() => { requestIdleCallback(() => { Promise.resolve(db).then((db) => { DEBUG_LOG && console.log(db, databaseId, eventType, event_type) db.close(); db = null; openCount-- message({ databaseId: databaseId, action: 'close', time: Date.now() }) runCount++ if (runCount > 1e9) runCount = 0 }).catch(consoleX.warn) db = null }, { timeout: 300 }) }, 300) } function makeHandler(handler, databaseId, eventType) { return function (event) { DEBUG_LOG && console.log(32, 'addEventListener', databaseId, eventType, event.type) handler.call(this, arguments) releaseOnIdle(event.target.result, databaseId, eventType, event.type) DEBUG_LOG && console.log(441, 'addEventListener', databaseId, eventType, event.type) } } function makeAddEventListener(databaseId) { return function (eventType, handler) { const addEventListener = this[addEventListenerKey] if (arguments.length !== 2) return addEventListener.call(this, ...arguments) if (eventType === 'error' || eventType === 'success') { DEBUG_LOG && console.log(31, databaseId, eventType) let gx = funcHooks.get(handler) if (!gx) { gx = makeHandler(handler, databaseId, eventType) // databaseId and eventType are just for logging; not reliable funcHooks.set(handler, gx) } return addEventListener.call(this, eventType, gx) } return addEventListener.call(this, ...arguments) } } function makeRemoveEventListener(databaseId) { return function (eventType, handler) { const removeEventListener = this[removeEventListenerKey] if (arguments.length !== 2) return removeEventListener.call(this, ...arguments) if (eventType === 'error' || eventType === 'success') { let gx = funcHooks.get(handler) DEBUG_LOG && console.log(30, 'removeEventListener', databaseId, eventType) let ret = removeEventListener.call(this, eventType, gx || handler) DEBUG_LOG && console.log(442, 'removeEventListener', databaseId, eventType) return ret } return removeEventListener.call(this, ...arguments); } } function makeOpen() { return function (databaseId) { let request = this[openKey](databaseId); // IDBRequest request[addEventListenerKey] = request.addEventListener; request.addEventListener = makeAddEventListener(databaseId); request[removeEventListenerKey] = request.removeEventListener; request.removeEventListener = makeRemoveEventListener(databaseId); openCount++ message({ databaseId: databaseId, action: 'open', time: Date.now() }) return request; } } window.indexedDB.constructor.prototype[openKey] = window.indexedDB.constructor.prototype.open; window.indexedDB.constructor.prototype.open = makeOpen(); } console.log(22) return isSupported })(DEBUG_LOG ? console : Object.assign({}, console, { log: function () { } }), console); isSupported && (function () { let request = indexedDB.open(DB_NAME_FOR_TESTING); let mi = 0; let px = function () { mi += 1000; }; request.addEventListener('success', px); request.addEventListener('success', function () { mi += 101; }); request.addEventListener('error', px); request.addEventListener('error', function () { mi += 201; }); request.removeEventListener('success', px); request.removeEventListener('error', px); indexedDB.deleteDatabase(DB_NAME_FOR_TESTING); setTimeout(() => { requestIdleCallback(() => { setTimeout(() => { Promise.resolve(0).then(() => { if ((mi === 101 || mi === 201) && runCount >= 1) { console.log(`%cYouTube Unhold IndexDB - %cInjection Success ${mi} ${runCount}`, 'background: #222; color: #fff', 'background: #222; color: #bada55'); } else { console.log(`%cYouTube Unhold IndexDB - %cInjection Failure ${mi} ${runCount}`, 'background: #222; color: #fff', 'background: #222; color: #da5a2f'); } }).catch(console.warn) }, 100) }, { timeout: 300 }) }, 300) })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址