个人辅助
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/511562/1822902/zenyBoost2.js
// ==UserScript==
// @name zenyBoost2
// @namespace http://tampermonkey.net/
// @namespace https://coderschool.cn
// @version 0.2
// @description 个人辅助
// @author yuexiaojun
// @icon https://www.google.com/s2/favicons?sz=64&domain=huaban.com
// @include *
// @grant unsafeWindow
// @grant GM_setClipboard
// @grant GM_download
// @grant GM_addStyle
// @grant GM_notification
// @connect 192.168.1.2
// @connect 192.168.1.2:8093
// ==/UserScript==
let log = console.log;
let noLog = function(args){};
//字符串增强
String.prototype.format = function(...args) {
if (args.length == 1 && typeof args[0] == 'object') {
let k = '', v = ''
return this.replace(/{[A-Za-z]+}/g, (it, i) => {
k = it.slice(1, -1)
v = args[0][k]
return typeof v != 'undefined' ? v : '';
})
}
return this.replace(/{(\d+)}/g, (it, i) => {
return typeof args[i] != 'undefined' ? args[i] : '';
});
};
//打开新窗口
function openNewWindowWithText(s) {
// 打开一个新的窗口
const newWindow = window.open('', '_blank', 'width=400,height=300');
// 检查窗口是否成功打开
if (newWindow) {
// 向窗口的文档写入内容
newWindow.document.write(s);
newWindow.document.title = 'My New Window';
// 关闭文档流,确保所有资源被正确加载
newWindow.document.close();
return newWindow;
} else {
// 如果窗口没有成功打开(可能由于浏览器阻止弹窗)
alert('Window could not be opened. Please check your popup settings.');
}
}
// 将 GM_xmlhttpRequest 封装成返回 Promise 的函数,该 Promise 解析为布尔值
function checkUrl(url) {
return new Promise((resolve) => {
GM_xmlhttpRequest({
method: "GET",
url: url,
onload: function(response) {
if (response.status >= 200 && response.status < 300) {
console.log("URL is accessible:", url);
resolve(true); // 成功访问,返回 true
} else {
console.log("URL is not accessible:", url, "Status code:", response.status);
resolve(false); // 状态码不是 2xx,返回 false
}
},
onerror: function() {
console.log("Error accessing URL:", url);
resolve(false); // 有错误发生,返回 false
}
});
});
}
async function atHome(){
return await checkUrl("http://192.168.1.2:8093/");
}
/**
* DOM节点定位器 - 可复用的节点查找库
*
* 支持三种使用方式:
* 1. 简洁操作符: '^^>0>div:1' (推荐,最简洁)
* 2. 路径字符串: 'parent/parent/child:0/find:div:1'
* 3. 链式调用: .parent().parent().child(0).find('div', 1)
*/
class DOMLocator {
/**
* 调试模式开关
* 设置为 true 启用调试日志输出
*/
static debugMode = false;
/**
* 设置调试模式
* @param {boolean} enabled - 是否启用调试
*/
static setDebug(enabled) {
this.debugMode = enabled;
if (enabled) {
console.log('%c[DOMLocator] 调试模式已启用', 'color: #0066cc; font-weight: bold');
}
}
/**
* 使用简洁操作符定位节点
* @param {HTMLElement} startNode - 起始节点
* @param {string} pattern - 定位模式,例如: '^^>0>div:1'
* @param {boolean} debug - 是否输出调试信息(可选,默认使用全局设置)
* @returns {HTMLElement|null} 目标节点
*
* 操作符说明:
* ^ - 父节点 (parent)
* > - 子节点索引 (child at index)
* >tag:idx - 特定标签的第idx个子节点 (find specific tag)
* < - 上一个兄弟节点 (previous sibling)
* <tag:idx - 向上找第N个特定标签的兄弟节点
*
* 示例:
* '^^' - 父节点的父节点
* '>0' - 第一个子节点
* '>div:1' - 第2个div子节点
* '<' - 上一个兄弟节点
* '<div:1' - 向上第2个div兄弟节点
* '^^<<>0' - 父节点 -> 父节点 -> 上一个兄弟 -> 第1个子节点
*/
static locate(startNode, pattern, debug = this.debugMode) {
if (!startNode || !pattern) return null;
const operations = this._parseOperatorPattern(pattern);
return this._execute(startNode, operations, debug);
}
/**
* 使用路径字符串定位节点
* @param {HTMLElement} startNode - 起始节点
* @param {string} path - 路径,例如: 'parent/parent/child:0/find:div:1'
* @param {boolean} debug - 是否输出调试信息(可选,默认使用全局设置)
* @returns {HTMLElement|null} 目标节点
*/
static locateByPath(startNode, path, debug = this.debugMode) {
if (!startNode || !path) return null;
const operations = this._parsePath(path);
return this._execute(startNode, operations, debug);
}
/**
* 创建链式调用构建器
* @param {HTMLElement} startNode - 起始节点
* @returns {LocatorBuilder} 链式调用构建器
*/
static chain(startNode) {
return new LocatorBuilder(startNode);
}
/**
* 解析简洁操作符模式
* @private
*/
static _parseOperatorPattern(pattern) {
const operations = [];
// 正则匹配: ^(父节点) | <(上一个兄弟) | >(子节点) | >tag:idx(特定标签) | <tag:idx(特定标签兄弟)
const regex = /(\^+)|(<+)|(>(\w+)?(?::(\d+))?)/g;
let match;
while ((match = regex.exec(pattern)) !== null) {
if (match[1]) {
// 父节点操作符 ^^^^
operations.push({
type: 'parent',
count: match[1].length
});
} else if (match[2]) {
// 上一个兄弟节点操作符 <<<
operations.push({
type: 'previous',
count: match[2].length
});
} else if (match[3]) {
// 子节点操作符 >0 或 >div:1
const tag = match[4]; // 标签名 (可选)
const index = match[5] ? parseInt(match[5]) : 0; // 索引
if (tag) {
operations.push({
type: 'find',
tag: tag,
index: index
});
} else {
operations.push({
type: 'child',
index: index
});
}
}
}
return operations;
}
/**
* 解析路径字符串
* @private
*/
static _parsePath(path) {
const operations = [];
const parts = path.split('/').filter(p => p);
for (const part of parts) {
const [type, ...args] = part.split(':');
switch (type) {
case 'parent':
operations.push({ type: 'parent', count: args[0] ? parseInt(args[0]) : 1 });
break;
case 'child':
operations.push({ type: 'child', index: args[0] ? parseInt(args[0]) : 0 });
break;
case 'previous':
operations.push({ type: 'previous', count: args[0] ? parseInt(args[0]) : 1 });
break;
case 'find':
operations.push({ type: 'find', tag: args[0], index: args[1] ? parseInt(args[1]) : 0 });
break;
}
}
return operations;
}
/**
* 执行操作序列
* @private
*/
static _execute(startNode, operations, debug = false) {
let currentNode = startNode;
if (debug) {
console.group('%c[DOMLocator] 开始执行定位', 'color: #0066cc; font-weight: bold');
console.log('起始节点:', currentNode);
console.log('操作序列:', operations);
}
for (let i = 0; i < operations.length; i++) {
const op = operations[i];
let opName = '';
let opDesc = '';
try {
switch (op.type) {
case 'parent':
opName = '↑ parent';
opDesc = `向上 ${op.count} 层`;
if (debug) {
console.log(`%c[步骤 ${i + 1}] ${opName}`, 'color: #666', opDesc);
}
for (let j = 0; j < op.count; j++) {
if (currentNode && currentNode.parentElement) {
currentNode = currentNode.parentElement;
if (debug && j < op.count - 1) {
console.log(` → 中间节点:`, currentNode);
}
} else {
if (debug) {
console.error(`❌ 失败: 找不到父节点 (第 ${j + 1}/${op.count} 层)`);
}
console.groupEnd();
return null;
}
}
break;
case 'previous':
opName = '← previous';
opDesc = `向前 ${op.count} 个兄弟节点`;
if (debug) {
console.log(`%c[步骤 ${i + 1}] ${opName}`, 'color: #666', opDesc);
}
for (let j = 0; j < op.count; j++) {
if (currentNode && currentNode.previousElementSibling) {
currentNode = currentNode.previousElementSibling;
if (debug && j < op.count - 1) {
console.log(` → 中间节点:`, currentNode);
}
} else {
if (debug) {
console.error(`❌ 失败: 找不到前面的兄弟节点 (第 ${j + 1}/${op.count} 个)`);
}
console.groupEnd();
return null;
}
}
break;
case 'child':
opName = '↓ child';
opDesc = `向下找第 ${op.index + 1} 个子节点`;
if (debug) {
console.log(`%c[步骤 ${i + 1}] ${opName}`, 'color: #666', opDesc);
console.log(' 可用子节点:', currentNode?.children?.length || 0);
}
if (currentNode && currentNode.children && currentNode.children[op.index]) {
currentNode = currentNode.children[op.index];
} else {
if (debug) {
console.error(`❌ 失败: 找不到第 ${op.index + 1} 个子节点`);
}
console.groupEnd();
return null;
}
break;
case 'find':
opName = '↓ find';
opDesc = `向下找第 ${op.index + 1}个 <${op.tag}>`;
if (debug) {
console.log(`%c[步骤 ${i + 1}] ${opName}`, 'color: #666', opDesc);
}
const matchingChildren = Array.from(currentNode.children || [])
.filter(el => el.tagName.toLowerCase() === op.tag.toLowerCase());
if (debug) {
console.log(` 找到 ${matchingChildren.length} 个 <${op.tag}> 子节点`);
}
if (matchingChildren[op.index]) {
currentNode = matchingChildren[op.index];
} else {
if (debug) {
console.error(`❌ 失败: 找不到第 ${op.index + 1} 个 <${op.tag}> 子节点`);
}
console.groupEnd();
return null;
}
break;
}
if (debug) {
console.log(`%c → 当前节点:`, 'color: #009933', currentNode);
console.log(` 标签: ${currentNode?.tagName}, 类名: "${currentNode?.className}"`);
}
} catch (e) {
if (debug) {
console.error(`❌ 操作失败:`, e);
}
console.error('DOM定位失败:', e);
console.groupEnd();
return null;
}
}
if (debug) {
console.log('%c✅ 定位成功!', 'color: #009933; font-weight: bold; font-size: 14px');
console.log('最终节点:', currentNode);
console.groupEnd();
}
return currentNode;
}
}
/**
* 链式调用构建器
*/
class LocatorBuilder {
constructor(startNode) {
this.currentNode = startNode;
this.operations = [];
this.debug = DOMLocator.debugMode;
}
/**
* 设置调试模式
* @param {boolean} enabled - 是否启用调试
* @returns {LocatorBuilder} 返回自身,支持链式调用
*/
setDebug(enabled) {
this.debug = enabled;
return this;
}
/**
* 向上查找父节点
* @param {number} count - 父节点层级,默认1
*/
parent(count = 1) {
this.operations.push({ type: 'parent', count });
return this;
}
/**
* 向前查找上一个兄弟节点
* @param {number} count - 向前数几个兄弟节点,默认1
*/
previous(count = 1) {
this.operations.push({ type: 'previous', count });
return this;
}
/**
* 向下查找第N个子节点
* @param {number} index - 子节点索引,从0开始
*/
child(index) {
this.operations.push({ type: 'child', index });
return this;
}
/**
* 查找第N个特定标签的子节点
* @param {string} tag - 标签名
* @param {number} index - 该标签子节点的索引,从0开始
*/
find(tag, index = 0) {
this.operations.push({ type: 'find', tag, index });
return this;
}
/**
* 执行查找并返回结果
* @param {boolean} debug - 是否输出调试信息(可选,默认使用实例设置)
* @returns {HTMLElement|null}
*/
exec(debug = this.debug) {
return DOMLocator._execute(this.currentNode, this.operations, debug);
}
/**
* 转换为简洁操作符字符串
* @returns {string}
*/
toOperatorPattern() {
return this.operations.map(op => {
switch (op.type) {
case 'parent': return '^'.repeat(op.count);
case 'previous': return '<'.repeat(op.count);
case 'child': return `>${op.index}`;
case 'find': return `>${op.tag}:${op.index}`;
}
}).join('');
}
/**
* 转换为路径字符串
* @returns {string}
*/
toPath() {
return this.operations.map(op => {
switch (op.type) {
case 'parent': return `parent:${op.count}`;
case 'previous': return `previous:${op.count}`;
case 'child': return `child:${op.index}`;
case 'find': return `find:${op.tag}:${op.index}`;
}
}).join('/');
}
}
// 导出(适配不同环境)
/*
if (typeof module !== 'undefined' && module.exports) {
module.exports = { DOMLocator, LocatorBuilder };
}
*/