A library by CKylinMC combined all usually-used script segments.
This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greasyfork.org/scripts/429720/1082330/CKTools.js
// ==UserScript== // @name CKTools // @namespace ckylin-script-lib-combined-tools // @version 1.6.1 // @match http://* // @match https://* // @author CKylinMC // @license GPLv3 License // ==/UserScript== (function () { const VERSION = 1.6; if ('CKTools' in window) { if (!window.CKTools.ver) console.warn('Unrecognized version of CKTools is already loaded, overwriting...'); else if (window.CKTools.ver > VERSION) throw new Error("You have newer version CKTools loaded. Aborting loading version " + VERSION); else console.warn(`You have older version of CKTools (${window.CKTools.ver}) was loaded, and now upgrading to newer version ${VERSION}.`); } class CKTools { static ver = VERSION static get(q, base = document) { return base.querySelector(q); } static getAll(q, base = document) { return [...base.querySelectorAll(q)]; } static domHelper(options = {}, compatibleParm2 = {}) { let tagName = 'div'; if (typeof (options) == 'string') { /* Migrate from version 1 */ tagName = options; /* Migrate from makeDom */ if (compatibleParm2.constructor.name == 'Object') options = compatibleParm2; else if (compatibleParm2.constructor.name == 'AsyncFunction') options = { initAsync: compatibleParm2 }; else if (compatibleParm2.constructor.name == 'Function') options = { init: compatibleParm2 }; else options = {}; } if (options.listeners) { /* Migrate from version 1 */ if (!options.on) options.on = {}; Object.assign(options.on, options.listeners); } if (options.classnames) { /* Migrate from version 1 */ if (!options.classList) options.classList = []; options.classList.concat(options.classnames); } if (options.tag) tagName = options.tag; let el; if (options.from) { if (options.from instanceof HTMLElement) { el = options.from; } else if (typeof (options.from) == "string") { els = domHelper(tagName, { html: options.from }); if (els.childElementCount === 0) { el = document.createElement(tagName); } else if (els.childElementCount === 1) { el = els.firstElementChild; } else { el = els; } } } else if (options.query) { const query = document.querySelector(options.query); if (query) el = query; else return null; } else el = document.createElement(tagName); if (options.id) el.id = options.id; if (options.html) el.innerHTML = options.html; if (options.text) el.innerText = options.text; if (options.attr) { for (const ak of Object.keys(options.attr)) { el.setAttribute(ak, options.attr[ak]); } } if (options.cssText) el.style.cssText = options.cssText; if (options.style) Object.assign(el.style, options.style); if (options.css) Object.assign(el.style, options.css); if (options.childs) { if (options.childs instanceof Array) options.childs.filter(el => !!el).forEach(child => { if (child instanceof HTMLElement) el.appendChild(child); else if (child.hasOwnProperty('type') && child.hasOwnProperty('content')) { switch (child.type) { case 'html': { arguments.callee('span', { from: child.content, append: el }); } break; case 'style': { const scoped = child.hasOwnProperty('scoped') && !!child.scoped; arguments.callee('style', { html: child.content, append: el, attr: { scoped } }); } break; default: el.appendChild(arguments.callee(child.type, child.content)); } } else el.appendChild(document.createTextNode(child)); }); else if (options.childs instanceof HTMLElement) el.appendChild(options.childs); else el.appendChild(document.createTextNode(options.childs)); } if (options.classlist) { if (options.classlist instanceof Array) options.classlist.forEach(classname => { el.classList.add(classname); }); else el.classList.add(...options.classlist.split(" ")); } if (options.classList) { if (options.classList instanceof Array) options.classList.forEach(classname => { el.classList.add(classname); }); else el.classList.add(...options.classList.split(" ")); } if (options.on) { for (let listenerName of Object.keys(options.on)) { el.addEventListener(listenerName, options.on[listenerName]); } } if (options.off) { for (let listenerName of Object.keys(options.of)) { el.removeEventListener(listenerName, options.off[listenerName]); } } if (options.bind) { const serverName = "$bindingserver" + Math.floor(Math.random() * 100000); const bindings = CKTools.deepClone(options.bind); const unbindProperty = (prop) => bindings[prop] = undefined; const unbindAllProperties = () => el[serverName].disconnect(); el[serverName] = new MutationObserver(mutations => { for (const mutation in mutations) { if (bindings.hasOwnProperty(mutation.attributeName)) { try { bindings[mutation.attributeName]({ target: mutation.target, attributeName: mutation.attributeName, attributeNamespace: mutation.attributeNamespace, oldValue: mutation.oldValue, newValue: mutation.target.getAttribute(mutation.attributeName) || undefined, unbind: () => unbindProperty(mutation.attributeName), stopListen: () => (unbindAllProperties(), el[serverName] = undefined) }); } catch (e) {} } } }); el.addEventListener('DOMNodeRemoved', () => (unbindAllProperties(), el[serverName] = undefined)); el[serverName].observe(el, { attributes: true, attributeOldValue: true }); } if (options.append && options.append instanceof HTMLElement) options.append.appendChild(el); if (options.insertBefore && insertBefore instanceof HTMLElement) options.insertBefore.parentNode.insertBefore(el, options.insertBefore); if (options.insertAfter && insertAfter instanceof HTMLElement) options.insertAfter.parentNode.insertAfter(el, options.insertAfter); if (options.init && options.init instanceof Function) options.init(el); if (options.initAsync && options.initAsync instanceof Function) { return options.initAsync(el).then(() => el); } return el; } static makeDom() { console.warn('"makeDom" has been deprecated. Redirecting to "domHelper"...'); return CKTools.domHelper(...arguments); } static addDom(item) { const make = (tag = 'div') => document.createElement(tag); const txt = (it = '') => document.createTextNode(it); class DOMItem { constructor(it = '') { this.setItem(it); } setItem(it = '') { if (typeof it === 'string' || it instanceof String) { this.el = txt(it); } else if (it instanceof HTMLElement) { this.el = it; } else this.el = txt(it.toString()); if (!this.target) this.target = document.body; this.mode = 'child'; return this; } inside(q = document.body) { this.mode = 'child'; if (q instanceof HTMLElement) { this.target = q; } else if (typeof q === 'string' || q instanceof String) { const ql = this.target.querySelector(q); if (ql) this.target = ql; } return this; } after(a = null) { this.mode = 'child-after'; if (a instanceof HTMLElement) { this.after = a; } else if (typeof a === 'string' || a instanceof String) { const al = this.target.querySelector(a); if (al) this.after = al; } return this; } before(a = null) { this.mode = 'child-before'; if (a instanceof HTMLElement) { this.before = a; } else if (typeof a === 'string' || a instanceof String) { const al = this.target.querySelector(a); if (al) this.before = al; } return this; } done() { switch (this.mode) { case "child": { if (this.el && this.target) this.target.appendChild(this.el); } break; case "child-before": { if (this.el && this.target && this.before) this.target.insertBefore(this.el, this.before); } break; case "child-after": { if (this.el && this.target && this.after) this.target.insertBefore(this.el, this.after.nextSibling); } break; } } } return new DOMItem(item); } static deepClone(obj) { let newObject = {}; if (Array.isArray(obj)) { newObject = []; for (let i = 0; i < obj.length; i++) { newObject.push(CKTools.deepClone(obj[i])); } return newObject; } Object.keys(obj).map(key => { if (typeof obj[key] === 'object') { newObject[key] = CKTools.deepClone(obj[key]); } else { newObject[key] = obj[key]; } }); return newObject; } static getCookie(name) { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop().split(';').shift(); } static clearAllCookies() { return document.cookie.split(';').forEach(cookie => document.cookie = cookie.replace(/^ +/, '').replace(/=.*/, `=;expires=${new Date(0).toUTCString()};path=/`)); } static getUrlParam(key) { return (new URL(location.href)).searchParams.get(key); } static wait(ms) { return new Promise(r => setTimeout(r, ms)); } static async waitForDom(query, domparent = document, maxRetries = 20, gagms = 200) { let i = maxRetries; while (--i > 0) { if (domparent.querySelector(query)) return true; await CKTools.wait(gagms); } return false; } static async waitForAttribute(q, attr) { let i = 50; let value; while (--i >= 0) { if ((attr in q) && q[attr] != null) { value = q[attr]; break; } await wait(100); } return value; } static async waitForPageVisible() { if (document.hidden) return true; return new Promise(r => { const handler = () => { r(true); document.removeEventListener('visibilitychange', handler); }; document.addEventListener("visibilitychange", handler) }); } static clearStyles(className = "injectedStyle") { let dom = document.querySelectorAll("style." + className); if (dom)[...dom].forEach(e => e.remove()); } static addStyle(s, className = "injectedStyle", mode = "append", injectBase = document.head) { switch (mode) { default: case "append": break; case "unique": if (document.querySelector("style." + className)) return; break; case "update": CKTools.clearStyles(className); break; } let style = document.createElement("style"); style.classList.add(className); style.innerHTML = s; injectBase.appendChild(style); } // stackoverflow static debounce(func, timeout = 300) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => { func.apply(this, args); }, timeout); }; } static throttle(callback, limit) { var waiting = false; return function () { if (!waiting) { callback.apply(this, arguments); waiting = true; setTimeout(function () { waiting = false; }, limit); } } } static domContains(selector, text) { var elements = document.querySelectorAll(selector); return [].filter.call(elements, function (element) { return RegExp(text).test(element.textContent); }); } static mapReplace(str, map) { //reference: https://segmentfault.com/q/1010000023489916 answer-2 const replace = ({ str, reg, replacer }) => str.replace(new RegExp(reg, 'g'), replacer); return Object.keys(map).reduce((str, reg) => replace({ str, reg, replacer: map[reg] }), str); } static padStart(num, count = 2) { return (('' + Math.pow(10, count)).substr(1) + num).slice(-1 * Math.max(count, ('' + num).length)); } static fixNum(num, fix = 0) { return Math.floor(num * (Math.pow(10, fix))) / (Math.pow(10, fix)); } static random = class { static hex() { return `#${Math.floor(Math.random() * 0xffffff).toString(16).padEnd(6, "0")}`; } static shuffleArray(arr) { return arr.sort(() => 0.5 - Math.random()); } static num(min, max) { return Math.random() * (max - min) + min; } static fromArray(arr = []) { return arr[Math.floor(CKTools.random.num(0, arr.length))]; } static from(...args) { return CKTools.random.fromArray(args); } } static is = class { static str(s) { return (s != null && (typeof s === "string" || s instanceof String)); } static elementInViewport(el) { var rect = el.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); } static asyncFn(fn) { return fn.constructor.name === "AsyncFunction"; } static darkMode() { return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; } } static modal = class { static openModal(title = '', content) { CKTools.modal.blockWindow(); let modal = CKTools.get("#CKTOOLS-modal"); if (!modal) modal = CKTools.modal.initModal(); modal.setTitle(title); modal.setContent(content); modal.show(); } static isModalShowing() { let modal = CKTools.get("#CKTOOLS-modal"); if (modal) return modal.classList.contains("show"); else return false; } static hideModal() { CKTools.modal.blockWindow(false); let modal = CKTools.get("#CKTOOLS-modal"); if (modal) modal.hide(); } static initModal() { CKTools.addStyle(` #CKTOOLS-modal{ position: fixed; z-index: 99010; top: 50%; left: 50%; width: 300px; width: 30vw; /*height: 300px; height: 50vh;*/ background: white; border-radius: 8px; padding: 12px; transform: translate(-50%,-50%); transition: all .3s; box-shadow: 0 2px 8px grey; } #CKTOOLS-modal.show{ opacity: 1; transform: translate(-50%,-50%) scale(1); } #CKTOOLS-modal.hide{ opacity: 0; pointer-events: none; transform: translate(-50%,-50%) scale(0.9); } .CKTOOLS-modal-title{ font-size: large; } .CKTOOLS-modal-content{ font-size: medium; } .CKTOOLS-modal-content>div{ display: flex; margin: 6px 10px; flex-wrap: wrap; flex-direction: column; align-content: space-around; justify-content: space-between; align-items: center; } .CKTOOLS-toolbar-btns{ flex: 1; border: none; background: #2196f3; border-radius: 3px; margin: 0 6px; padding: 3px; color: white; box-shadow: 0 2px 3px grey; min-width: 60px; } .CKTOOLS-toolbar-btns:hover{ filter: brightness(0.85); } `, "CKTOOLS-modal-css", "unique"); const modal = document.createElement("div"); modal.id = "CKTOOLS-modal"; modal.className = "hide"; const header = document.createElement("h2"); header.className = "CKTOOLS-modal-title" modal.appendChild(header); modal.setTitle = (t = '') => { header.innerHTML = t; } const contents = document.createElement("div"); contents.className = "CKTOOLS-modal-content"; modal.appendChild(contents); modal.setContent = async (c) => { let ct = c; if (ct instanceof Function) { ct = await ct(); } if (ct instanceof HTMLElement) { contents.innerHTML = ''; contents.appendChild(ct); return; } if (typeof (ct) === "string") { contents.innerHTML = ct; return; } console.log("unknown: ", ct); } modal.addContent = async (c) => { let ct = c; if (ct instanceof Function) { ct = await ct(); } if (ct instanceof HTMLElement) { contents.appendChild(ct); return; } if (ct instanceof String) { contents.innerHTML += ct; return; } console.log("unknown: ", ct); } modal.close = CKTools.modal.closeModal; modal.open = CKTools.modal.openModal; modal.show = () => { modal.className = "show"; } modal.hide = () => { modal.className = "hide"; } document.body.appendChild(modal); return modal; } static closeModal() { CKTools.modal.blockWindow(false); let modal = CKTools.get("#CKTOOLS-modal"); if (modal) modal.remove(); } static async alertModal(title = "", content = "", okbtn = null) { if (CKTools.modal.isModalShowing()) { CKTools.modal.hideModal(); await CKTools.wait(200); } CKTools.modal.openModal(title, await CKTools.domHelper("div", async container => { container.appendChild(await CKTools.domHelper("div", tip => { tip.innerHTML = content; })) if (okbtn !== null) container.appendChild(await CKTools.domHelper("div", async btns => { btns.style.display = "flex"; btns.appendChild(await CKTools.domHelper("button", btn => { btn.className = "CKTOOLS-toolbar-btns"; btn.innerHTML = okbtn; btn.onclick = e => CKTools.modal.hideModal(); })) })) })) await CKTools.wait(300); } static blockWindow(block = true) { CKTools.addStyle(` #CKTOOLS-blockWindow{ z-index: 99005; display: block; background: #00000080; opacity: 0; transition: all .3s; position: fixed; left: 0; top: 0; width: 100vw; height: 100vh; } #CKTOOLS-blockWindow.hide{ pointer-events: none; opacity: 0; } #CKTOOLS-blockWindow.show{ opacity: 1; } `, "CKTOOLS-blockWindow-css", "unique"); let dom = CKTools.get("#CKTOOLS-blockWindow"); if (!dom) { dom = document.createElement("div"); dom.id = "CKTOOLS-blockWindow"; dom.className = "hide"; document.body.appendChild(dom); } if (block) { dom.className = "show"; } else { dom.className = "hide"; } } } static bili = class { static getCSRFToken() { return CKTools.getCookie("bili_jct"); } static async playerReady() { let i = 50; while (--i >= 0) { await CKTools.wait(100); if (!('player' in window)) continue; if (!('isInitialized' in window.player)) continue; if (!window.player.isInitialized()) continue; } if (i < 0) return false; await CKTools.waitForPageVisible(); while (1) { await CKTools.wait(200); if (document.querySelector(".bilibili-player-video-control-wrap, .bpx-player-control-wrap")) return true; } } static getTotalTime() { return waitForAttribute(CKTools.get('video, bwp-video'), 'duration')||unsafeWindow.player?.getDuration(); } static getCurrentTime() { return CKTools.get('video, bwp-video').currentTime||unsafeWindow.player?.getCurrentTime(); } static setTime(t) { return window.player.seek(t); } static play() { return window.player.play(); } static pause() { return window.player.pause(); } static getInfoByBvid(bvid) { return fetch('https://api.bilibili.com/x/web-interface/view?bvid=' + bvid).then(raw => raw.json()); } static getInfoByAid(aid) { return fetch('https://api.bilibili.com/x/web-interface/view?aid=' + aid).then(raw => raw.json()); } } static EventEmitter = class { handlers = {}; on(name, func) { if (!(func instanceof Function)) throw "Param must be func!"; if (!(name in this.handlers)) { this.handlers[name] = []; } this.handlers[name].push(func); } off(name, func) { if (!(func instanceof Function)) throw "Param must be func!"; if (name in this.handlers) { for (let i = 0; i < this.handlers[name].length; i++) { if (this.handlers[name][i] === func) { this.handlers[name].splice(i, 1); i--; } } } } clean(name) { if (name in this.handlers) { this.handlers[name] = []; } } emit(name, ...args) { if (name in this.handlers) { for (let func of this.handlers[name]) { try { func(...args); } catch (e) { console.error('ERROR:', e); } } } } } static HoldClick = class { dom; emitter = new CKTools.EventEmitter; downTime = 0; holdingTime = 250; mouseDown = false; constructor(dom, holdingTime = 250) { this.bind(dom); this.holdingTime = holdingTime; } bind(dom) { if (this.dom) { this.unregListeners(); } if (dom instanceof HTMLElement) { this.dom = dom; this.initListener(); } } onclick(func) { this.emitter.on("click", func); return this; } onhold(func) { this.emitter.on("hold", func); return this; } onup(func) { this.emitter.on("up", func); return this; } offclick(func) { this.emitter.off("click", func); return this; } offhold(func) { this.emitter.off("hold", func); return this; } offup(func) { this.emitter.off("up", func); return this; } resetCallback(name = "all") { const allEv = ["click", "hold", "up"]; if (name === "all") { allEv.forEach(e => this.emitter.clean(e)); } else if (allEv.includes(name)) { this.emitter.clean(name); } } unregListeners() { this.dom.removeEventListener("mouseup", this.handleMouseUp.bind(this)); this.dom.removeEventListener("mousedown", this.handleMouseDown.bind(this)); this.dom.removeEventListener("mouseout", this.handleMouseOut.bind(this)); } uninstall() { this.resetCallback(); this.unregListeners(); } handleMouseDown(e) { if (e.button !== 0 && e.button !== 1) return; e.preventDefault(); this.mouseDown = true; this.downTime = (new Date()).getTime(); setTimeout(() => { if (this.mouseDown) { console.log(this); this.mouseDown = false; this.downTime = 0; this.emitter.emit("hold", e); } }, this.holdingTime) } handleMouseUp(e) { if (e.button !== 0 && e.button !== 1) return; e.preventDefault(); if (this.mouseDown) { this.mouseDown = false; const currTime = (new Date).getTime(); if ((currTime - this.downTime) >= this.holdingTime) { this.emitter.emit("hold", e); } else { this.emitter.emit("click", e); } this.downTime = 0; } this.emitter.emit("up", e); } handleMouseOut(e) { e.preventDefault(); if (this.mouseDown) { this.mouseDown = false; this.downTime = 0; this.emitter.emit("hold", e); } } initListener() { this.dom.addEventListener("mouseup", this.handleMouseUp.bind(this)) this.dom.addEventListener("mousedown", this.handleMouseDown.bind(this)) this.dom.addEventListener("mouseout", this.handleMouseOut.bind(this)) } } static dragger = class { static defaultHandler(val) { return console.log("DRAG:", val); } static async waitForDragger(waitStatus = true) { while (CKTools.dragger.dragging !== waitStatus) await CKTools.wait(10); return CKTools.dragger; } static async regHandler(func) { if (!(func instanceof Function)) throw "Param must be a func!"; await CKTools.dragger.waitForDragger(false); CKTools.dragger.handler = func; return CKTools.dragger; } static handler() {} static dragging = false; static initialDragData = { x: 0, y: 0 } static lastDragData = { x: 0, y: 0 } static startDrag(e) { if (CKTools.dragger.dragging) return; CKTools.dragger.dragging = true; console.log(CKTools.dragger.initialDragData); CKTools.dragger.initialDragData.x = e.screenX; CKTools.dragger.initialDragData.y = e.screenY; CKTools.dragger.lastDragData.x = e.screenX; CKTools.dragger.lastDragData.y = e.screenY; document.body.addEventListener("mouseup", CKTools.dragger.stopDrag); document.body.addEventListener("mousemove", CKTools.dragger.handleDrag); console.info("DRAG:", "Start Drag"); return CKTools.dragger; } static handleDrag(e) { const currPos = { x: e.screenX, y: e.screenY }; const initPos = CKTools.dragger.initialDragData; const delta = { x: initPos.x - currPos.x, y: initPos.y - currPos.y } const lastdelta = { x: CKTools.dragger.lastDragData.x - currPos.x, y: CKTools.dragger.lastDragData.y - currPos.y } CKTools.dragger.lastDragData = currPos; CKTools.dragger.handler(delta, lastdelta); } static stopDrag() { document.body.removeEventListener("mouseup", CKTools.dragger.stopDrag); document.body.removeEventListener("mousemove", CKTools.dragger.handleDrag); CKTools.dragger.handler = CKTools.dragger.defaultHandler; console.info("DRAG:", "Stop Drag"); CKTools.dragger.dragging = false; return CKTools.dragger; } } static GUID = class { static S4() { return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); } static get() { let S4 = CKTools.GUID.S4; return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4()); } static getShort() { let S4 = CKTools.GUID.S4; return (S4() + S4() + S4() + S4()); } } } window.CKTools = CKTools; })();