您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Some useful utilities for userscript development
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/391648/744266/US_Utils.js
// US Utils library // // Some useful utilities for userscript development. // // https://greasyfork.org/scripts/******-us-utils // Copyright (C) 2019, Guido Villa // // For information/instructions on user scripts, see: // https://greasyfork.org/help/installing-user-scripts // // To use this library in a userscript you must add to script header: // @require https://greasyfork.org/scripts/******-us-utils/code/US_Utils.js // @grant GM_xmlhttpRequest (only if using UU.GM_xhR) // // -------------------------------------------------------------------- // // ==UserScript== // @namespace https://greasyfork.org/users/373199-guido-villa // @exclude * // // ==UserLibrary== // @name US_Utils // @description Some useful utilities for userscript development // @version 0.1 // @author guidovilla // @date 26.10.2019 // @copyright 2019, Guido Villa (https://greasyfork.org/users/373199-guido-villa) // @license GPL-3.0-or-later // @homepageURL https://greasyfork.org/scripts/******-us-utils // @supportURL https://gitlab.com/gv-browser/userscripts/issues // @contributionURL https://tinyurl.com/gv-donate-ed // @attribution Trevor Dixon (https://stackoverflow.com/users/711902/trevor-dixon) // ==/UserScript== // // ==/UserLibrary== // // -------------------------------------------------------------------- // // To-do (priority: [H]igh, [M]edium, [L]ow): // - [H] GM_xhR: remove workaround responseXML2 and make responseXML work // - [M] add other functions // // Changelog: // ---------- // 2019.10.26 [0.1] First test version, private use only // /* jshint esversion: 6, laxbreak: true, -W008, supernew: true */ /* exported UU, Library_Version_US_UTILS */ const Library_Version_US_UTILS = '0.1'; /* How to use the library This library instantitates an UU object with utility variables and methods: - me: script name as returned by GM_info - isUndef(p): check if p is undefined - le(...args): like ocnsole.error, prepending the script name - lw(...args): like ocnsole.warn, prepending the script name - li(...args): like ocnsole.info, prepending the script name - ld(...args): like ocnsole.debug, prepending the script name - checkProperty(object, property, type, optional) Check if object "object" has property "property" of type "type". If property is "optional" (default false), it is only checked for type Used to test if object "implements" a specific interface - parseCSV(csv): simple CSV parsing function, by Trevor Dixon (see below) Take a CSV string as input and return an array of rows, each containing an array of fields. NOTE: it is not strict in RFC 4180 compliance as it handles unquoted double quotes inside a field (this is not allowed in the RFC specifications). - wait(waitTime, result) return a Promise to wait for "waitTime" ms, then resolve with value "result" - thenWait(waitTime) like wait(), to be used inside a Promise.then(). Passes through the received fulfillment value. - GM_xhR(method, url, purpose, opts): GM_xmlhttpRequest wrapped in a Promise. Return a Promise resolving with the GM_xmlhttpRequest response, or failing with an error message (which is also logged). Arguments: - mathod: HTTP method (GET, POST, ...) - url: URL to call - purpose: string describing XHR call (for error logging and reporting) - opts: details to be passed to GM_xmlhttpRequest; the following properties will be ignored: - method, url: overwritten by function arguments - onload: overwritten to resolve the Promise - onabort, onerror, ontimeout: overwritten to reject the Promise if no context is specified, purpose is passed as context */ window.UU = new (function() { 'use strict'; var self = this; // the name of the running script this.me = GM_info.script.name; // check if parameter is undefined this.isUndef = function(p) { return (typeof p === 'undefined'); }; // logging var bracketMe = '[' + this.me + ']'; this.le = function(...args) { console.error(bracketMe, ...args); }; this.lw = function(...args) { console.warn (bracketMe, ...args); }; this.li = function(...args) { console.info (bracketMe, ...args); }; this.ld = function(...args) { console.debug(bracketMe, ...args); }; // Check if "object" has "property" of "type" // used to test if object "implements" a specific interface this.checkProperty = function(object, property, type, optional = false) { if (self.isUndef(object[property])) { if (optional) return true; self.le('Invalid object: missing property "' + property + '" of type "' + type + '"'); return false; } if (typeof object[property] !== type) { self.le('Invalid object: ' + (optional ? 'optional ' : '') + 'property "' + property + '" must be of type "' + type + '"'); return false; } return true; }; // Simple CSV parsing function, by Trevor Dixon: // https://stackoverflow.com/a/14991797 // take a CSV as input and returns an array of arrays (rows, fields) /* eslint-disable max-statements, max-statements-per-line, max-len */ this.parseCSV = function(csv) { var arr = []; var quote = false; // true means we're inside a quoted field // iterate over each character, keep track of current row and column (of the returned array) var row, col, c; for (row = col = c = 0; c < csv.length; c++) { var cc = csv[c], nc = csv[c+1]; // current character, next character arr[row] = arr[row] || []; // create a new row if necessary arr[row][col] = arr[row][col] || ''; // create a new column (start with empty string) if necessary // If the current character is a quotation mark, and we're inside a // quoted field, and the next character is also a quotation mark, // add a quotation mark to the current column and skip the next character if (cc == '"' && quote && nc == '"') { arr[row][col] += cc; ++c; continue; } // If it's just one quotation mark, begin/end quoted field if (cc == '"') { quote = !quote; continue; } // If it's a comma and we're not in a quoted field, move on to the next column if (cc == ',' && !quote) { ++col; continue; } // If it's a newline (CRLF) and we're not in a quoted field, skip the next character // and move on to the next row and move to column 0 of that new row if (cc == '\r' && nc == '\n' && !quote) { ++row; col = 0; ++c; continue; } // If it's a newline (LF or CR) and we're not in a quoted field, // move on to the next row and move to column 0 of that new row if (cc == '\n' && !quote) { ++row; col = 0; continue; } if (cc == '\r' && !quote) { ++row; col = 0; continue; } // Otherwise, append the current character to the current column arr[row][col] += cc; } return arr; }; /* eslint-enable max-statements, max-statements-per-line, max-len */ // setTimeout wrapped in a Promise this.wait = function(waitTime, result) { return new Promise(function(resolve, _I_reject) { setTimeout(resolve, waitTime, result); }); }; // setTimeout wrapped in a Promise, if called iside "then" this.thenWait = function(waitTime) { return (function(result) { return self.wait(waitTime, result); }); }; // handle download error in a Promise-enhanced GM_xmlhttpRequest function xhrError(rejectFunc, response, method, url, purpose, reason) { var m = purpose + ' - HTTP ' + method + ' error' + (reason ? ' (' + reason + ')' : '') + ': ' + response.status + (response.statusText ? ' - ' + response.statusText : ''); self.le(m, 'URL: ' + url, 'Response:', response); rejectFunc(m); } function xhrErrorFunc(rejectFunc, method, url, purpose, reason) { return (function(resp) { xhrError(rejectFunc, resp, method, url, purpose, reason); }); } // wrap GM_xmlhttpRequest in a Promise // returns a Promise resolving with the GM_xmlhttpRequest response this.GM_xhR = function(method, url, purpose, opts) { return new Promise(function(resolve, reject) { var details = opts || {}; details.method = method; details.url = url; details.onload = function(response) { if (response.status !== 200) xhrError(reject, response, method, url, purpose); // else resolve(response); else { if (details.responseType === 'document') { try { const d = document.implementation.createHTMLDocument().documentElement; d.innerHTML = response.responseText; response.responseXML2 = d; } catch(e) { xhrError(reject, response, method, url, purpose, e); } } resolve(response); } }; details.onabort = xhrErrorFunc(reject, method, url, purpose, 'abort'); details.onerror = xhrErrorFunc(reject, method, url, purpose, 'error'); details.ontimeout = xhrErrorFunc(reject, method, url, purpose, 'timeout'); if (self.isUndef(details.synchronous)) details.synchronous = false; if (self.isUndef(details.context)) details.context = purpose; GM_xmlhttpRequest(details); }); }; })();