Skip to content

Instantly share code, notes, and snippets.

@XieJiSS
Last active August 3, 2024 17:05
Show Gist options
  • Save XieJiSS/bbbc561c522e4defe37f354db9026a7a to your computer and use it in GitHub Desktop.
Save XieJiSS/bbbc561c522e4defe37f354db9026a7a to your computer and use it in GitHub Desktop.
CC98 remove watermark tampermonkey userscript
// ==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