Last active
August 3, 2024 17:05
-
-
Save XieJiSS/bbbc561c522e4defe37f354db9026a7a to your computer and use it in GitHub Desktop.
CC98 remove watermark tampermonkey userscript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name No Watermark CC98 | |
// @namespace http://tampermonkey.net/ | |
// @version 1.1 | |
// @description Remove CC98 watermark | |
// @author who cares? | |
// @license WTFPL | |
// @run-at document-start | |
// @match https://www.cc98.org/* | |
// @icon https://www.cc98.org/static/98icon.ico | |
// @grant none | |
// ==/UserScript== | |
// USE AT YOUR OWN RISK. NO WARRANTY IS PROVIDED. | |
(function () { | |
"use strict"; | |
const DEBUG = false; | |
const DEBUG_SHADOW_ROOT = false; | |
function hookAll(window) { | |
if (DEBUG) console.log("hooking window..."); | |
const _setTimeout = window.setTimeout; | |
window.setTimeout = function (...args) { | |
if (DEBUG) console.log("setTimeout", args); | |
return _setTimeout.apply(this, args); | |
}; | |
const _setInterval = window.setInterval; | |
window.setInterval = function (...args) { | |
if (DEBUG) console.log("setInterval", args); | |
return _setInterval.apply(this, args); | |
}; | |
const _requestAnimationFrame = window.requestAnimationFrame; | |
window.requestAnimationFrame = function (...args) { | |
if (DEBUG) console.log("requestAnimationFrame", args); | |
return _requestAnimationFrame.apply(this, args); | |
}; | |
const _requestIdleCallback = window.requestIdleCallback; | |
window.requestIdleCallback = function (...args) { | |
if (DEBUG) console.log("requestIdleCallback", args); | |
return _requestIdleCallback.apply(this, args); | |
}; | |
const shouldIgnoreElementMap = new Map(); | |
const _attachShadow = window.Element.prototype.attachShadow; | |
window.Element.prototype.attachShadow = function (...args) { | |
if (DEBUG || DEBUG_SHADOW_ROOT) console.log("attachShadow", args); | |
const shadowEl = _attachShadow.apply(this, args); | |
// don't use window.ShadowRoot - which is undefined | |
const _shadowRootInnerHTMLGetter = Object.getOwnPropertyDescriptor(ShadowRoot.prototype, "innerHTML").get; | |
const _shadowRootInnerHTMLSetter = Object.getOwnPropertyDescriptor(ShadowRoot.prototype, "innerHTML").set; | |
Object.defineProperty(shadowEl, "innerHTML", { | |
get: _shadowRootInnerHTMLGetter, | |
set (...args) { | |
if (typeof args[0] === "string" && args[0].includes("data:image/svg+xml")) { | |
// we need to specially handle the first assignment to innerHTML | |
if(shouldIgnoreElementMap.get(this)) { | |
// not the first assignment | |
if (DEBUG || DEBUG_SHADOW_ROOT) console.log("auto-ignore: shadow-root.innerHTML setter 1", this, args); | |
// empty slot for consistency | |
_shadowRootInnerHTMLSetter.apply(this, [ "<slot></slot>" ]); | |
return; | |
} | |
// for the first assignment to innerHTML, use display: none to avoid | |
// a randomly happenning issue | |
shouldIgnoreElementMap.set(this, true); | |
if (DEBUG || DEBUG_SHADOW_ROOT) console.log("first-shot: shadow-root.innerHTML setter 1", this, args); | |
args[0] = args[0].replace("<div></div>", '<div style="display: none;"></div>'); | |
} | |
if (DEBUG || DEBUG_SHADOW_ROOT) console.log("shadow-root.innerHTML setter 1", this, args); | |
try { | |
_shadowRootInnerHTMLSetter.apply(this, args); | |
} catch (e) { | |
console.error(this, args, e); | |
} | |
}, | |
}); | |
return shadowEl; | |
}; | |
const _createShadowRoot = window.Element.prototype.createShadowRoot; | |
window.Element.prototype.createShadowRoot = function (...args) { | |
if (DEBUG || DEBUG_SHADOW_ROOT) console.log("createShadowRoot", args); | |
const shadowEl = _createShadowRoot.apply(this, args); | |
// don't use window.ShadowRoot - which is undefined | |
const _shadowRootInnerHTMLGetter = Object.getOwnPropertyDescriptor(ShadowRoot.prototype, "innerHTML").get; | |
const _shadowRootInnerHTMLSetter = Object.getOwnPropertyDescriptor(ShadowRoot.prototype, "innerHTML").set; | |
Object.defineProperty(shadowEl, "innerHTML", { | |
get: _shadowRootInnerHTMLGetter, | |
set (...args) { | |
if (typeof args[0] === "string" && args[0].includes("data:image/svg+xml")) { | |
// we need to specially handle the first assignment to innerHTML | |
if(shouldIgnoreElementMap.get(this)) { | |
// not the first assignment | |
if (DEBUG || DEBUG_SHADOW_ROOT) console.log("auto-ignore: shadow-root.innerHTML setter 2", this, args); | |
// empty slot for consistency | |
_shadowRootInnerHTMLSetter.apply(this, [ "<slot></slot>" ]); | |
return; | |
} | |
// for the first assignment to innerHTML, use display: none to avoid | |
// a randomly happenning issue | |
shouldIgnoreElementMap.set(this, true); | |
if (DEBUG || DEBUG_SHADOW_ROOT) console.log("first-shot: shadow-root.innerHTML setter 2", this, args); | |
args[0] = args[0].replace("<div></div>", '<div style="display: none;"></div>'); | |
} | |
if (DEBUG || DEBUG_SHADOW_ROOT) console.log("shadow-root.innerHTML setter 2", this, args); | |
try { | |
_shadowRootInnerHTMLSetter.apply(this, args); | |
} catch (e) { | |
console.error(this, args, e); | |
} | |
}, | |
}); | |
return shadowEl; | |
}; | |
} | |
const _divInnerHTMLGetter = Object.getOwnPropertyDescriptor(window.Element.prototype, "innerHTML").get; | |
const _divInnerHTMLSetter = Object.getOwnPropertyDescriptor(window.Element.prototype, "innerHTML").set; | |
const _createElement = document.createElement; | |
document.createElement = function (...args) { | |
const el = _createElement.apply(this, args); | |
if (el.nodeName === "DIV") { | |
Object.defineProperty(el, "innerHTML", { | |
get: _divInnerHTMLGetter, | |
set (...args) { | |
if (DEBUG) console.log("div.innerHTML setter", args); | |
_divInnerHTMLSetter.apply(el, args); | |
// hook iframes created by vendor.js | |
if (typeof args[0] === "string" && args[0].includes("iframe")) { | |
Array.from(this.querySelectorAll("iframe")).map((ifr) => { | |
hookAll(ifr.contentWindow); | |
}); | |
} | |
}, | |
}); | |
} | |
return el; | |
}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment