NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// #region UserScript Metadata // ==UserScript== // #region Info // @name akkd-all-sites // @namespace https://openuserjs.org/users/93Akkord // @version 0.0.4 // @description Akkd All Sites // @copyright 2022+, Michael Barros (https://openuserjs.org/users/93Akkord) // @license CC-BY-NC-SA-4.0; https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode // @license GPL-3.0-or-later; https://www.gnu.org/licenses/gpl-3.0.txt // @author 93Akkord // @run-at document-start // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNvyMY98AAA5DSURBVGhDtVr5T1zXGeVviPJDq/bHNq2ZN8MyrGEx4C2JY6tqo+SXRGoVKYqqSlXaqFUjNUlTRXWUWE5iXC/YmNWAjdmXGRgDNruNYciwG4aBYR0wY+x4AWbe1/PdN282PwO21HGO333bfed893zfve85Efx7q6zrpd9UDX32er295bDZ2f6GeVbgdZMT4G1Q2+zwbWfbD6F9SGydvu1s+0GcU3HAh5B2fTgc7QeALLSzGmfbM4GsRuwD+8RWOZaB84y06smW/RUTnx7MMb0kyB860/jT1xrvjO+3LFGWZZmymhcps3kB4C3vL9E+XzsT7UzLImU0LVEGjqVb5gFscVy0cV9a0wKlmucFXjUvUopZ2ed2MpCE/cRwmOYpqWGREoGERmwbcaxxnuJxPN60II7FNywIxKFtNK1Qaq19ZG92608iDtYO5WSBRNa1ZcpgQEQGxDCYNO/vBQTJHZAGpEIckw1HcpMiIBmEkkxLfiSCEBPUQrwpgDiIMjYuUYxpmWLNAO5NLx/PicismZrLsLhE9DMF+TABwN4wolpIw4ikgmTKjgIwCir55xKAyPsEGCGAkVA1MRuRWe9wZzSv+CzyNIRdAC3SwUiFfVJgHy3yDFVAcPS1SAcjOPpxIM8CYnkLEXEQEFcz5Y7IUgXARsLjKnGArbOb6DPYOikgqUWeoWUhLdKM4MirApi8H75RSKix7yxAi6wWhIAw0sF4UQFK9BeUyAcJ4DxIqMYI7K+3uzObXX7iDBH5XZIX3od9tEgzBHGAq08S9lXyuxGgkg8XwO0Y3B9fBQH7ICDDJ2C3CasiDYme6kteLfIMvwAQEsCx5xPA20VBWkWMELAMAWyhBghAFRKR1yC5HRQBin20yDMCApg0C9i9hQICAuQDgIAKhxtVaNK9F+S1CD4LPFmlgdTufL/w3LVfbW8nwCgEzLyoALXmaxNXoQgAOPLPIUAAbVWA6vtQAZwDYgSmnluAv2Q28RJh+wROMgeIP5cAgAUYcSycPCewP4l3OwK7tQ1DjbwgzFuI1CKrBZW4gkDV0RYwqQhI36UAts12FUfF/1uACiEgYwcBXGlEtQmxzdOkVTB5tR1sGy2ywQi3DkOLdDB8AqZ2ELCMycoF8iwCiauuebD/qtlFqajHDEGaI++LfrKPeDLO8Qgkm+boVZBKQvVIwHGxkGNhPtJCBKCQ5y28j+MxAFecuIYlHzAL7yRA+B1E0zFJHb3uoqNtynkeAbFo45nX5KTqmfv0w+ojKpx0UXLDrCiZwXVeRB4l9JOBVbLefUgDdx/RG/UOsfYPnH+WAJDEvTF4L/hL3yIN4l6+/6jJIcizMDGRZWAtxETTEWWOdBomNcUu8/Rep5Mey0SbRPRp7xyi5xTR57qeXDdLI2uPCaepY85FUUUDlFg/I84FC0isX6DjtmXy4rot4LXLt8hYOY3VpM8+PgEKEGGQM6LN5IWIeid9YV0Uz9nEX0eqhshYNYXzeNkRAuocbl7PpGEU0ppgB0EeD4fyCxNruE35tcy4yFDSBxs4QRJvULUzNIyICAFOF0m5PaQrGaSEBuQIHpwMCFJ1c/Q1CPDPAxws7SF98QAZq+/4vK++dYE87BYHESwgxjwHu6CMVjvo84EFkmUvbeFhh8ut4DFEUTXTEIAyml7rcLM1uDSqEH6uddD4+gYJhsD61hal5neQvnQIr34zlIQOhlYf+gXoLnSRruA2RV8aJIwq7aufpfRGPKTGTl/1z4lOPMCB4i4I6KOokn5KqR7DtTOUiWuT6+cFcUY8bJTR6KDfWpy0t2qE/tXH92ME8bAjLOCSjfZcGaPYKyPuiFQI4MkoFTf6yaODd6/N0hMZj8RNMv7y4s/HljGKzMPDy2yUUDFOw34By6Q/30VSwS26MOKkex6Z3F6ZTlqn5JjSH+ir27O4DhEUAjrJUNhLHzQN0+qml9bRwa3V+5RZOYJknaFUiM8bWxV98PXr2I6sPRAC0KQ3Lw+QoXgQAoZJX2LVFpCAhDw94hKPnFt/IPc55mXCEJqmFkm62CmISgU3aWjlR3QrU+fsMkWfa6Fsq528uI5RPmz3Rp+7Lu+52EvHeibFdTwC+ws76L2afnI/AT0Exu5+KB8qaJP1Rf1kuDJEZ8dWxHUcuU3gsdcr9jlQqoCoYivpcG2IABF5QCQhhn3kHicoiFinvMeuDcgIKN19vEnJBbBAQQ9F5naSzXWfA0NdM4t0vGcMyc53EJlGZ7zRZ8xe6WIHRV7spv90T4jrtkDoT9W95EI/TMZ1/0f5SH6rR3+xiyIL+yi1tJ/WNjhTvDSwuCof/G/lVkZ29Vbr9Dx3GyRgkKTwEVAFcPK+Y3HAPmwamf5Y2e19M9dCG2wjJtAE5XndpDvfTkOude6X7m8wITwDD+hyLHhjTpm8ugsdZMB1Ul4PHWMBOIf/aH1DifzKoyf0O5CXzt/AaPaQVHSLPjSNKpbFk/9ce1OWTlso8vQ1+mfrkDiuCtAjz0IF8MTE0cfCK7HBSdlDKFu4YxOkznUOyd/esNH9TcQXHVSMz5H+QjtJOTdo2HVPYeX78UAX2ablyJxWIdKQ30sScKxLGQH/D/c43A8oLbcdOYXrim+LxP779SnRHY/B0bJ20uXewEi30+cdd8RtqgAJ1U4qH0YyswCU0RSUUfY/z5BJSCKb+yFGUYzaU7/5xxuUgI6lnOs0vBwQ8ACjwKI9wD/aRklf2ENRhUquHOtWCPCIPsQIsJWYZOvsKkXhfNQlK2zRTx9fGxfHeb54pwLFIh8lN6+XvujkHFIEHLliJQmFgUdACEiBgGSenCCAZ8K3mh2wC5OXaXzprrdzet7TMb3gsc6tIA0Uj79fP0i6nDayCQEyTbrW5H0ny7Ym7q7jTpnWUF3erkC1KLqJfMEIqAJA4PdFTVv5N0fZjejLS9+hQhlAngW8c7WPNvgp6OWbW1MkIS+kgn46dtMu4sTC3kQZVQQgSEJArd0tpn/YJ75+jk7YlElnCx0dPGP26I5XyhKQ8F29d+0Jz8lEpaNOMpxtoUEIYEkd9gV5z7d19HbhNe/DTXgcKifcP1JKaS9s1OXPAa7j+842yTHf18jWxRXWQI/wnA8tmJiK+siIwjDkWhMjeW/TQ6dQ1U72zdLqI8xH6IAFvHEVFajUBgFjsBIEvFrjcCci+rywiqudxprlEXOkkZV78p7sGvr1KQvtQTL9KtuMMqpMKAsPNsh45poQwKW2bXaJ9KfMpMu20Il2m5dtxOSq7asUndtLxzkHcIAtcCDvOhlON9ORglavSGiInQfBQ1d6hNh3r/TK95BvXDp5xGTctIX5iIsp93u4oh8jgAQun8CkOsgCZhQBsM/euikqGJjyFg9MeP5ad9OrQ4XQ53aRgcscqs77Vb1ykXXSkzcw6dmfd0P+un3YW2S94/mybcgbhZzQc0U53SSf7B7xXMJ1BcDh8pvyH6r75IKBO558XJuc3ylK6x4Ugg9rur3FuKbIOuX5pGVYjobn9+R10eGCZk9J/4Snd8blvYrzH1V0eopwfyHa6aWw1eWxYAEOWMj3RRjrm1isM3TnWlEmQQYPYg9HFcLLXFEuYBI710bS2TYyMGG0BXLacR4Jh4SMhGAujXq+5hy2EC/BGhKukc53wNPoB8mtB6IwexvOtWOL80WwGy8xYCUpF8/F9bqTzbLhdIvvOddxXTdyhf0P+6gCkqodbl4RipUh1iOxdQ4ylo+L5NEjicQMiQQzFN0WFUWX302RIKsTwHyALR/n83ydHlsdCwFRHSch9wHouCJha8BCzoA6rkcp5L6lQvQL6EtwHMlpgL/1l/g4RBbwvXwfAghxhhL4//II6Zjf1Tt8vTsisdoOAYFXPv4Gn9CAlSAWayhTYuXI4AdzpeCaLUgIoHpcwnEug6WDAYCcAYgqsQE/iGOiLyZ9GRNhmQ9oS1hX6QDDZZRFkNNzdbk8inYopCsgLcDRHyd9BQSUQUAS1tQJsI8qIBjGOqdIGAkkWL0gBiIKuA1ygmQo9BzFcDBxkNQzySBwOZTKgwmGgqOtQro6IWBA9PUVkwEB7H8tAQLICz1EcESVIeaIMnFt8gYghDiiKyDIKwKkYAgBiKoGeYEwARx5Ju8XkLyTAMCIty8DD7mPlBZxRjh5cY+IPCMo6oDwMrfZElrEVfjJB4iHCAjPAUbgFS8AI146+MHhAjjpGE8LCCUdTpyhLwN5lERN4oAg7o98KPkQAeo/pG0nIN48T3F1sBMeHC5AFaW2BUT0txOAZBUCQkkHI9j3OwrQJB0E9VuNERUqumyEohFhRihpIMwuKoIjL5J2F4mrZRuByiky4MU+uszmjkjAi3GwAIWo8nUgFPx9RkE8EjsKQ294UQHC99rW2ck2AhCgDwjgEQiNsraAoM98EByDnIjiqvLCAkKJq9jJNgLBAuIr7G7lQxIT931Q2iWi6+ZBCGR4rmCUhdb5ENLCNtsTV8kHl8pQgHiFHQKmIWAaAoYDApgQR3i7j6laMNY78YINYiAvITe0BajkdxP57cj7UAkRVXYIGIWFKibmOPoxjfzNMfDdcdeA9aKR2KJec2V5SsAosLvIP5s8A6SFALQrAVgo5pLVGRF9sTc3FgKYPP/jmSbJnYCciMVkJ10FEV+F4TWNUmmeTV7Ab5tgsloICJCqsV/lwOr0xvmIX/zt2M+ji/sn+csv/6OBMgrPCb6PRcBO+gpE0i9gB/IMLIt3K0ACDLBOFPwfe773zi8/Ov4z8X+svPLBNy8bjtd8GZXbbonJ7+18EURf7OrRn2m16k+1WA3Zptv6E3WD0vfm29KJepv03dPQAZHfY3uywSadbNwWOgGTLTK72Rp9utUifVP571c++OzliIiIiP8B4VfIttF+iOkAAAAASUVORK5CYII= // @updateURL https://openuserjs.org/meta/93Akkord/akkd-all-sites.meta.js // @downloadURL https://openuserjs.org/install/93Akkord/akkd-all-sites.user.js // #endregion Info // #region Matches/Includes/Excludes // @include /^.*$/ // #endregion Matches/Includes/Excludes // #region Grants // @grant GM_addElement // @grant GM_addStyle // @grant GM_addValueChangeListener // @grant GM_deleteValue // @grant GM_download // @grant GM_getResourceText // @grant GM_getResourceURL // @grant GM_getTab // @grant GM_getTabs // @grant GM_getValue // @grant GM_listValues // @grant GM_log // @grant GM_notification // @grant GM_openInTab // @grant GM_registerMenuCommand // @grant GM_removeValueChangeListener // @grant GM_saveTab // @grant GM_setClipboard // @grant GM_setValue // @grant GM_unregisterMenuCommand // @grant GM_xmlhttpRequest // @grant unsafeWindow // @grant window.close // @grant window.focus // @grant window.onurlchange // #endregion Grants // #region Resources // #endregion Resources // #region Requires // @require https://code.jquery.com/jquery-3.2.1.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/arrive/2.4.1/arrive.min.js // @require https://openuserjs.org/src/libs/93Akkord/loglevel.js // @require https://openuserjs.org/src/libs/93Akkord/akkd-common.js // @require https://openuserjs.org/src/libs/sizzle/GM_config.min.js // #endregion Requires // #region Other // noframes // @connect * // #endregion Other // ==/UserScript== // ==OpenUserJS== // @author 93Akkord // ==/OpenUserJS== // #endregion UserScript Metadata // #region Type References /// <reference path='./node_modules/@types/tampermonkey/index.d.ts' /> /// <reference path='./node_modules/@types/jquery/index.d.ts' /> /// <reference path='./node_modules/@types/arrive/index.d.ts' /> // #endregion Type References const logger = getLogger('akkd', { logLevel: log.levels.DEBUG }); function setupConfig(logger) { // demo: http://sizzlemctwizzle.github.io/GM_config/ GM_config.init({ id: `main-${location.host.replace(/\./g, '_')}`, title: 'Akkd All Sites Config', fields: { // test: https://www.codingwithjesse.com/demo/2007-05-16-detect-browser-window-focus/ always_focus: { label: 'Always Focus', type: 'checkbox', default: false, }, }, events: { init: function () { init('loaded', () => alwaysOnFocus(GM_config.get('always_focus'))); }, open: function () { alwaysOnFocus(true); }, save: function () {}, close: function () { alwaysOnFocus(GM_config.get('always_focus')); }, reset: function () {}, }, }); } function registryConfigMenu() { let menuId = GM_registerMenuCommand(`Config`, () => { GM_config.open(); }); } function exposeGlobalVariables() { let variables = [ // libs { name: 'jQuery', value: jQuery }, { name: '$', value: $ }, // functions/variables { name: 'pp', value: pp }, { name: 'pformat', value: pformat }, { name: 'getObjProps', value: getObjProps }, { name: 'getUserDefinedGlobalProps', value: getUserDefinedGlobalProps }, { name: 'getLocalStorageSize', value: getLocalStorageSize }, { name: 'unsafeWindow', value: unsafeWindow }, { name: 'getWindow', value: getWindow }, { name: 'getTopWindow', value: getTopWindow }, { name: 'getStyle', value: getStyle }, { name: 'GM_info', value: GM_info }, { name: 'alwaysOnFocus', value: alwaysOnFocus }, ]; GM_info.script.grant.forEach((grant) => { if (grant.includes('GM_')) { variables.push({ name: grant, value: window[grant], }); } }); variables.forEach((variable, index, variables) => { try { setupWindowProps(getWindow(), variable.name, variable.value); } catch (error) { logger.error(`Unable to expose variable ${variable.name} into the global scope.`); } }); } function startPerformanceMonitor() { // if (getWindow().top != getWindow().self) { // setTimeout(() => { let _window = 'unsafeWindow' in window ? getWindow() : window; class Stats { constructor({ // containerId = 'performance-monitor-container', includeMem = true, includeMemOld = true, includeFps = true, includeMs = true, } = {}) { this.mode = 0; this.container = document.createElement('div'); this.on = false; this.changing = false; this.includeMem = includeMem; this.includeMemOld = includeMemOld; this.includeFps = includeFps; this.includeMs = includeMs; this.container.id = containerId; this.container.style.cssText = 'position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000'; this.container.style.display = 'none'; this.container.addEventListener('click', (ev) => { if (!this.me.moving && !this.me.keyPressed) { ev.preventDefault(); this.showPanel(++this.mode % this.container.children.length); } }); this.beginTime = (performance || Date).now(); this.prevTime = this.beginTime; this.frames = 0; this.memPanel; /** @type {Panel} */ this.memPanelOld; /** @type {Panel} */ this.fpsPanel; /** @type {Panel} */ this.msPanel; if (_window.self.performance && _window.self.performance.memory) { if (this.includeMem) { this.memPanel = new MemoryStats(); this.container.appendChild(this.memPanel.domElement); } if (this.includeMemOld) { this.memPanelOld = this.addPanel(new Panel('MB', '#f08', '#201')); } } if (this.includeFps) { this.fpsPanel = this.addPanel(new Panel('FPS', '#0ff', '#002')); } if (this.includeMs) { this.msPanel = this.addPanel(new Panel('MS', '#0f0', '#020')); } this.showPanel(0); this.REVISION = 16; this.dom = this.container; this.domElement = this.container; this.setMode = this.showPanel; this.me = new MoveableElement(this.container, true); this.me.init(); } showPanel(id) { for (let i = 0; i < this.container.children.length; i++) { this.container.children[i].style.display = i === id ? 'block' : 'none'; } this.mode = id; } addPanel(panel) { this.container.appendChild(panel.dom); return panel; } begin() { this.beginTime = (performance || Date).now(); } end() { let time = (performance || Date).now(); this.frames++; if (this.msPanel) { this.msPanel.update(time - this.beginTime, 200); } if (time >= this.prevTime + 1000) { if (this.fpsPanel) { this.fpsPanel.update((this.frames * 1000) / (time - this.prevTime), 100); } this.prevTime = time; this.frames = 0; if (this.memPanel) { this.memPanel.update(performance.memory.usedJSHeapSize / 1048576, performance.memory.jsHeapSizeLimit / 1048576); } if (this.memPanelOld) { this.memPanelOld.update(performance.memory.usedJSHeapSize / 1048576, performance.memory.jsHeapSizeLimit / 1048576); } } return time; } update() { this.beginTime = this.end(); } start(cb) { if (!this.on) { this.on = true; this.showPanel(this.mode); this.container.style.display = 'block'; this.animate(cb); } } stop() { this.on = false; this.container.style.display = 'none'; } animate(cb) { let _animate = () => { this.begin(); if (cb) { cb(); } this.end(); if (this.on) { requestAnimationFrame(_animate); } }; requestAnimationFrame(_animate); } } class Panel { constructor(name, foreground, background) { this.name = name; this.foreground = foreground; this.background = background; this.min = Infinity; this.max = 0; this.PR = Math.round(_window.devicePixelRatio || 1); this.WIDTH = 80 * this.PR; this.HEIGHT = 48 * this.PR; this.TEXT_X = 3 * this.PR; this.TEXT_Y = 2 * this.PR; this.GRAPH_X = 3 * this.PR; this.GRAPH_Y = 15 * this.PR; this.GRAPH_WIDTH = 74 * this.PR; this.GRAPH_HEIGHT = 30 * this.PR; this.canvas = document.createElement('canvas'); this.canvas.width = this.WIDTH; this.canvas.height = this.HEIGHT; this.canvas.style.cssText = 'width:80px;height:48px;cursor:pointer'; this.context = this.canvas.getContext('2d'); this.context.font = 'bold ' + 9 * this.PR + 'px Helvetica,Arial,sans-serif'; this.context.textBaseline = 'top'; this.context.fillStyle = this.background; this.context.fillRect(0, 0, this.WIDTH, this.HEIGHT); this.context.fillStyle = this.foreground; this.context.fillText(this.name, this.TEXT_X, this.TEXT_Y); this.context.fillRect(this.GRAPH_X, this.GRAPH_Y, this.GRAPH_WIDTH, this.GRAPH_HEIGHT); this.context.fillStyle = this.background; this.context.globalAlpha = 0.9; this.context.fillRect(this.GRAPH_X, this.GRAPH_Y, this.GRAPH_WIDTH, this.GRAPH_HEIGHT); this.dom = this.canvas; } update(value, maxValue) { this.min = Math.min(this.min, value); this.max = Math.max(this.max, value); this.context.fillStyle = this.background; this.context.globalAlpha = 1; this.context.fillRect(0, 0, this.WIDTH, this.GRAPH_Y); this.context.fillStyle = this.foreground; this.context.fillText(Math.round(value) + ' ' + this.name + ' (' + Math.round(this.min) + '-' + Math.round(this.max) + ')', this.TEXT_X, this.TEXT_Y); this.context.drawImage(this.canvas, this.GRAPH_X + this.PR, this.GRAPH_Y, this.GRAPH_WIDTH - this.PR, this.GRAPH_HEIGHT, this.GRAPH_X, this.GRAPH_Y, this.GRAPH_WIDTH - this.PR, this.GRAPH_HEIGHT); this.context.fillRect(this.GRAPH_X + this.GRAPH_WIDTH - this.PR, this.GRAPH_Y, this.PR, this.GRAPH_HEIGHT); this.context.fillStyle = this.background; this.context.globalAlpha = 0.9; this.context.fillRect(this.GRAPH_X + this.GRAPH_WIDTH - this.PR, this.GRAPH_Y, this.PR, Math.round((1 - value / maxValue) * this.GRAPH_HEIGHT)); } } function MemoryStats() { let msMin = 100; let msMax = 0; let GRAPH_HEIGHT = 30; let GRAPH_WIDTH = 74; let redrawMBThreshold = GRAPH_HEIGHT; let container = document.createElement('div'); container.style.display = 'none'; container.id = 'stats'; container.style.cssText = 'width:80px;height:48px;opacity:0.9;cursor:pointer;overflow:hidden;z-index:10000;will-change:transform;'; let msDiv = document.createElement('div'); msDiv.id = 'ms'; msDiv.style.cssText = 'padding:0 0 3px 3px;text-align:left;background-color:#020;'; container.appendChild(msDiv); let msText = document.createElement('div'); msText.id = 'msText'; msText.style.cssText = 'color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px'; msText.innerHTML = 'Memory'; msDiv.appendChild(msText); let msGraph = document.createElement('div'); msGraph.id = 'msGraph'; msGraph.style.cssText = 'position:relative;width:74px;height:' + GRAPH_HEIGHT + 'px;background-color:#0f0'; msDiv.appendChild(msGraph); while (msGraph.children.length < GRAPH_WIDTH) { let bar = document.createElement('span'); bar.style.cssText = 'width:1px;height:' + GRAPH_HEIGHT + 'px;float:left;background-color:#131'; msGraph.appendChild(bar); } let updateGraph = function (dom, height, color) { let child = dom.appendChild(dom.firstChild); child.style.height = height + 'px'; if (color) child.style.backgroundColor = color; }; let redrawGraph = function (dom, oHFactor, hFactor) { [].forEach.call(dom.children, function (c) { let cHeight = c.style.height.substring(0, c.style.height.length - 2); // Convert to MB, change factor let newVal = GRAPH_HEIGHT - ((GRAPH_HEIGHT - cHeight) / oHFactor) * hFactor; c.style.height = newVal + 'px'; }); }; // polyfill usedJSHeapSize if (_window.performance && !performance.memory) { performance.memory = { usedJSHeapSize: 0, totalJSHeapSize: 0 }; } // support of the API? if (performance.memory.totalJSHeapSize === 0) { logger.warn('totalJSHeapSize === 0... performance.memory is only available in Chrome .'); } let sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; let precision; let i; function bytesToSize(bytes, nFractDigit) { if (bytes === 0) return 'n/a'; nFractDigit = nFractDigit !== undefined ? nFractDigit : 0; precision = Math.pow(10, nFractDigit); i = Math.floor(Math.log(bytes) / Math.log(1024)); return Math.round((bytes * precision) / Math.pow(1024, i)) / precision + ' ' + sizes[i]; } // TODO, add a sanity check to see if values are bucketed. // If so, remind user to adopt the --enable-precise-memory-info flag. // open -a "/Applications/Google Chrome.app" --args --enable-precise-memory-info let lastTime = Date.now(); let lastUsedHeap = performance.memory.usedJSHeapSize; let delta = 0; let color = '#131'; let ms = 0; let mbValue = 0; let factor = 0; let newThreshold = 0; return { domElement: container, update: function () { // update at 30fps if (Date.now() - lastTime < 1000 / 30) return; lastTime = Date.now(); delta = performance.memory.usedJSHeapSize - lastUsedHeap; lastUsedHeap = performance.memory.usedJSHeapSize; // if memory has gone down, consider it a GC and draw a red bar. color = delta < 0 ? '#830' : '#131'; ms = lastUsedHeap; msMin = Math.min(msMin, ms); msMax = Math.max(msMax, ms); msText.textContent = 'Mem: ' + bytesToSize(ms, 2); mbValue = ms / (1024 * 1024); if (mbValue > redrawMBThreshold) { factor = (mbValue - (mbValue % GRAPH_HEIGHT)) / GRAPH_HEIGHT; newThreshold = GRAPH_HEIGHT * (factor + 1); redrawGraph(msGraph, GRAPH_HEIGHT / redrawMBThreshold, GRAPH_HEIGHT / newThreshold); redrawMBThreshold = newThreshold; } updateGraph(msGraph, GRAPH_HEIGHT - mbValue * (GRAPH_HEIGHT / redrawMBThreshold), color); }, }; } let stats = new Stats({ includeMemOld: false, // includeFps: false, // includeMs: false, }); function initPerformanceMonitor() { if (!document.body) { setTimeout(() => { initPerformanceMonitor(); }, 250); } else { function setupIFrameEvents() { setTimeout(() => { let iframes = document.querySelectorAll('iframe'); for (let i = 0; i < iframes.length; i++) { try { const iframe = iframes[i]; /** @type {Window} */ let _window = iframe.contentWindow; _window.document.addEventListener('keydown', function (e) { if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() == 'm') { e.cancelBubble = true; e.preventDefault(); e.stopImmediatePropagation(); _window.parent.postMessage('performance-monitor-keybind', '*'); } }); } catch (error) {} } }, 5000); } document.body.appendChild(stats.dom); let changing = false; function startOrStop() { if (!changing) { changing = true; if (!stats.on) { stats.start(); } else { stats.stop(); } setTimeout(() => { changing = false; }, 500); } } document.addEventListener('keydown', function (e) { if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() == 'm') { e.cancelBubble = true; e.preventDefault(); e.stopImmediatePropagation(); startOrStop(); } }); setupIFrameEvents(); /** * * * @author Michael Barros <michaelcbarros@gmail.com> * @param {MessageEvent} ev */ function messageEvent(ev) { if (ev.data === 'performance-monitor-keybind' || ev.message === 'performance-monitor-keybind') { startOrStop(); } } _window.removeEventListener('message', messageEvent); _window.addEventListener('message', messageEvent); } } if (getTopWindow() === getWindow()) { initPerformanceMonitor(); } } function alwaysOnFocusOld() { let on = GM_getValue('always_focus', false); let focusMenuCommandID; /** * * * @author Michael Barros <michaelcbarros@gmail.com> * @param {boolean} [init=false] */ function registerAlwaysFocusMenuCommand(init = false) { if (!init) { on = !on; GM_setValue('always_focus', on); } if (focusMenuCommandID != undefined) { GM_unregisterMenuCommand(focusMenuCommandID); } focusMenuCommandID = GM_registerMenuCommand(`Always Focus: ${on ? 'on' : 'off'}`, () => { registerAlwaysFocusMenuCommand(); }); _alwaysOnFocus(on); } function _alwaysOnFocus(on) { if (!('originalFocusValues' in getWindow())) { getWindow().originalFocusValues = { 'unsafeWindow.onblur': unsafeWindow.onblur, 'unsafeWindow.blurred': unsafeWindow.blurred, 'unsafeWindow.document.hasFocus': unsafeWindow.document.hasFocus, 'unsafeWindow.window.onfocus': unsafeWindow.window.onfocus, 'document.hidden': document.hidden, 'document.mozHidden': document.mozHidden, 'document.msHidden': document.msHidden, 'document.webkitHidden': document.webkitHidden, 'document.visibilityState': document.visibilityState, 'unsafeWindow.document.onvisibilitychange': unsafeWindow.document.onvisibilitychange, }; } if (!('__eventHandler__' in getWindow())) { getWindow().__eventHandler__ = function (event) { event.stopImmediatePropagation(); }; } function getNestedDot(obj, dotStr) { let parts = dotStr.split('.'); while (parts.length > 0) { let part = parts.shift(); obj = obj[part]; } return obj; } if (on) { unsafeWindow.onblur = null; unsafeWindow.blurred = false; unsafeWindow.document.hasFocus = function () { return true; }; unsafeWindow.window.onfocus = function () { return true; }; Object.defineProperty(document, 'hidden', { value: false, configurable: true }); Object.defineProperty(document, 'mozHidden', { value: false, configurable: true }); Object.defineProperty(document, 'msHidden', { value: false, configurable: true }); Object.defineProperty(document, 'webkitHidden', { value: false, configurable: true }); Object.defineProperty(document, 'visibilityState', { get: function () { return 'visible'; }, configurable: true, }); unsafeWindow.document.onvisibilitychange = undefined; let events = [ 'visibilitychange', 'webkitvisibilitychange', 'blur', // may cause issues on some websites 'mozvisibilitychange', 'msvisibilitychange', ]; for (let i = 0; i < events.length; i++) { const event = events[i]; window.addEventListener(event, getWindow().__eventHandler__, true); } } else { let orig = getWindow().originalFocusValues; unsafeWindow.onblur = orig['unsafeWindow.onblur']; unsafeWindow.blurred = orig['unsafeWindow.blurred']; unsafeWindow.document.hasFocus = orig['unsafeWindow.document.hasFocus']; unsafeWindow.window.onfocus = orig['unsafeWindow.window.onfocus']; // Object.defineProperty(document, 'hidden', { value: orig['document.hidden'] }); // Object.defineProperty(document, 'mozHidden', { value: orig['document.mozHidden'] }); // Object.defineProperty(document, 'msHidden', { value: orig['document.msHidden'] }); // Object.defineProperty(document, 'webkitHidden', { value: orig['document.webkitHidden'] }); document.hidden = orig['document.hidden']; document.mozHidden = orig['document.mozHidden']; document.msHidden = orig['document.msHidden']; document.webkitHidden = orig['document.webkitHidden']; document.visibilityState = orig['document.visibilityState']; unsafeWindow.document.onvisibilitychange = orig['unsafeWindow.document.onvisibilitychange']; let events = [ 'visibilitychange', 'webkitvisibilitychange', 'blur', // may cause issues on some websites 'mozvisibilitychange', 'msvisibilitychange', ]; for (let i = 0; i < events.length; i++) { const event = events[i]; window.removeEventListener(event, getWindow().__eventHandler__, true); } } } registerAlwaysFocusMenuCommand(true); } /** * * * @author Michael Barros <michaelcbarros@gmail.com> * @param {boolean} on */ function alwaysOnFocus(on) { if (!('originalFocusValues' in getWindow())) { getWindow().originalFocusValues = { 'unsafeWindow.onblur': unsafeWindow.onblur, 'unsafeWindow.blurred': unsafeWindow.blurred, 'unsafeWindow.document.hasFocus': unsafeWindow.document.hasFocus, 'unsafeWindow.window.onfocus': unsafeWindow.window.onfocus, 'document.hidden': document.hidden, 'document.mozHidden': document.mozHidden, 'document.msHidden': document.msHidden, 'document.webkitHidden': document.webkitHidden, 'document.visibilityState': document.visibilityState, 'unsafeWindow.document.onvisibilitychange': unsafeWindow.document.onvisibilitychange, }; } if (!('__eventHandler__' in getWindow())) { getWindow().__eventHandler__ = function (event) { event.stopImmediatePropagation(); }; } function getNestedDot(obj, dotStr) { let parts = dotStr.split('.'); while (parts.length > 0) { let part = parts.shift(); obj = obj[part]; } return obj; } if (on) { unsafeWindow.onblur = null; unsafeWindow.blurred = false; unsafeWindow.document.hasFocus = function () { return true; }; unsafeWindow.window.onfocus = function () { return true; }; Object.defineProperty(document, 'hidden', { value: false, configurable: true }); Object.defineProperty(document, 'mozHidden', { value: false, configurable: true }); Object.defineProperty(document, 'msHidden', { value: false, configurable: true }); Object.defineProperty(document, 'webkitHidden', { value: false, configurable: true }); Object.defineProperty(document, 'visibilityState', { get: function () { return 'visible'; }, configurable: true, }); unsafeWindow.document.onvisibilitychange = undefined; let events = [ 'visibilitychange', 'webkitvisibilitychange', 'blur', // may cause issues on some websites 'mozvisibilitychange', 'msvisibilitychange', ]; for (let i = 0; i < events.length; i++) { const event = events[i]; window.addEventListener(event, getWindow().__eventHandler__, true); } } else { let orig = getWindow().originalFocusValues; unsafeWindow.onblur = orig['unsafeWindow.onblur']; unsafeWindow.blurred = orig['unsafeWindow.blurred']; unsafeWindow.document.hasFocus = orig['unsafeWindow.document.hasFocus']; unsafeWindow.window.onfocus = orig['unsafeWindow.window.onfocus']; // Object.defineProperty(document, 'hidden', { value: orig['document.hidden'] }); // Object.defineProperty(document, 'mozHidden', { value: orig['document.mozHidden'] }); // Object.defineProperty(document, 'msHidden', { value: orig['document.msHidden'] }); // Object.defineProperty(document, 'webkitHidden', { value: orig['document.webkitHidden'] }); document.hidden = orig['document.hidden']; document.mozHidden = orig['document.mozHidden']; document.msHidden = orig['document.msHidden']; document.webkitHidden = orig['document.webkitHidden']; document.visibilityState = orig['document.visibilityState']; unsafeWindow.document.onvisibilitychange = orig['unsafeWindow.document.onvisibilitychange']; let events = [ 'visibilitychange', 'webkitvisibilitychange', 'blur', // may cause issues on some websites 'mozvisibilitychange', 'msvisibilitychange', ]; for (let i = 0; i < events.length; i++) { const event = events[i]; window.removeEventListener(event, getWindow().__eventHandler__, true); } } } /** * * * @author Michael Barros <michaelcbarros@gmail.com> */ async function init(when) { const DEFAULT_OPTIONS = { use_vanilla: false, }; let options = typeof arguments[1] == 'object' ? arguments[1] : {}; let func = typeof arguments[1] == 'object' ? arguments[2] : arguments[1]; let args = typeof arguments[1] == 'object' ? arguments[3] : arguments[2]; options = Object.assign(DEFAULT_OPTIONS, options); async function runCallback() { if (args && args.length > 0) { await func(...args); } else { await func(); } } if (when == 'start') { await runCallback(); } else if (when == 'ready') { if (!options.use_vanilla) { $(document).ready(async (e) => { await runCallback(); }); } else { document.addEventListener('DOMContentLoaded', async (e) => { await runCallback(); }); } } else if (when == 'loaded') { if (!options.use_vanilla) { $(document).on('readystatechange', async (e) => { if (e.target.readyState == 'complete') { await runCallback(); } }); } else { document.addEventListener('readystatechange', async (e) => { if (e.target.readyState === 'complete') { await runCallback(); } }); } } } (async function () { setupConfig(logger); registryConfigMenu(); GM_getTab((tab) => { tab.title = document.title; GM_saveTab(tab); }); exposeGlobalVariables(); startPerformanceMonitor(); })();