您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
封装了一些常用的API,用于方便调用
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/489184/1338830/Lib_MyAPI.js
- // ==UserScript==
- // @name Lib_MyAPI
- // @namespace AC-API
- // @include *
- // @run-at document-start
- // @version 2024.03.07
- // @grant GM_xmlhttpRequest
- // @description 封装了一些常用的API,用于方便调用
- // ==/UserScript==
- // 避免函数污染
- const ACMO = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
- // 不能用unsafeWindow来暴露MyApi,否则会有http的安全问题
- const MyApi = (() => {
- /**
- * @param css CSS的正文内容
- * @param className 被添加的css节点的class,用于onlyOne检测
- * @param isReload 是否自动更新:移除后重新添加
- */
- function addStyle(css, className = '', isReload = false){ // 添加CSS代码,不考虑文本载入时间,带有className
- const tout = setInterval(function() {
- if (document.body != null) {
- clearInterval(tout);
- if (className) {
- // 节点不存在,或者是准备覆盖的时候
- if (isReload === false && document.querySelector("." + className) != null) {
- return;
- }
- // 节点已经存在,并且不准备覆盖
- try {
- document.querySelector("." + className).remove();
- } catch (e) {
- }
- }
- const cssNode = document.createElement("style");
- if (className) {
- cssNode.className = className;
- }
- cssNode.innerHTML = css;
- try {
- document.body.appendChild(cssNode);
- } catch (e) {
- console.log(e.message);
- }
- }
- }, 200);
- }
- function addScript(scriptInner) {
- const scriptNode = document.createElement('script')
- scriptNode.innerText = scriptInner
- document.head.appendChild(scriptNode)
- }
- const safeWaitFunc = function waitForElm(selector, callbackFunc = node => {}, findTick = 200, clearAfterFind = true, timeout = 20000 * 1000) {
- const handle = () => {
- if ((typeof (selector) === "string")) {
- let res = document.querySelectorAll(selector);
- if(res && res.length) {
- callbackFunc(res);
- }
- } else if (typeof (selector) === "function") {
- const res = selector()
- if(res && res.length) {
- callbackFunc(res);
- }
- }
- }
- let lastRunAt = 0 // 最近一次运行的时间
- let onlyTimer;
- const firstRunAt = Date.now()
- // 其他时间增加监听即可
- const watcher = new ACMO(() => {
- // 超过节流时间间隔,立即执行事件处理函数
- if(Date.now() - lastRunAt > findTick) {
- handle()
- if(clearAfterFind) {
- watcher.disconnect();
- }
- lastRunAt = Date.now()
- } else {
- // 未超过节流时间间隔,设置定时器延迟执行事件处理函数
- clearTimeout(timer);
- onlyTimer = setTimeout(() => {
- handle();
- lastRunAt = Date.now()
- }, findTick);
- }
- // 超过最大时限,那么停止监听
- if(Date.now() - firstRunAt > timeout) {
- watcher.disconnect();
- }
- });
- watcher.observe(document.body, {
- childList: true,
- subtree: true
- });
- }
- function getUrlAttribute(attribute, needDecode = true){
- var searchValue = (window.location.search.substr(1) + "").split("&");
- for (var i = 0; i < searchValue.length; i++) {
- var key_value = searchValue[i].split("=");
- var reg = new RegExp("^"+attribute+"$");
- if (reg.test(key_value[0])) {
- var searchWords = key_value[1];
- return needDecode?decodeURIComponent(searchWords):searchWords;
- }
- }
- }
- const http = {
- async get(url) {
- return new Promise((resolve, reject) => {
- GM_xmlhttpRequest({
- url,
- method: 'GET',
- timeout: 10000,
- onload: resp => resolve([null, resp.responseText]),
- onerror: resp => reject([resp, {}])
- })
- })
- },
- async post(url, data) {
- return new Promise((resolve, reject) => {
- GM_xmlhttpRequest({
- url,
- data,
- method: 'POST',
- timeout: 10000,
- onload: resp => resolve([null, resp.responseText]),
- onerror: resp => reject([resp, {}])
- })
- })
- }
- }
- return {
- addStyle,
- addScript,
- safeWaitFunc,
- getUrlAttribute,
- http
- }
- })()