// ==UserScript== // @name 【移动端】MT论坛优化 // @namespace https://greasyfork.org/zh-CN/scripts/401359 // @version 2024.12.17 // @author WhiteSevs // @description MT论坛效果增强,如自动签到、自动展开帖子、滚动加载评论、显示UID、自定义屏蔽、手机版小黑屋、编辑器优化、在线用户查看、便捷式图床、自定义用户标签、积分商城商品上架提醒等 // @license GPL-3.0-only // @icon data:image/png;base64,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 // @supportURL https://github.com/WhiteSevs/TamperMonkeyScript/issues // @match *://bbs.binmt.cc/* // @exclude /^http(s|)://bbs.binmt.cc/uc_server.*$/ // @require https://update.greasyfork.org/scripts/494167/1413255/CoverUMD.js // @require https://update.greasyfork.org/scripts/452322/1470429/js-watermark.js // @require https://fastly.jsdelivr.net/npm/@whitesev/utils@2.5.5/dist/index.umd.js // @require https://fastly.jsdelivr.net/npm/@whitesev/domutils@1.4.8/dist/index.umd.js // @require https://fastly.jsdelivr.net/npm/@whitesev/pops@1.9.5/dist/index.umd.js // @require https://fastly.jsdelivr.net/npm/qmsg@1.2.8/dist/index.umd.js // @require https://fastly.jsdelivr.net/npm/viewerjs@1.11.7/dist/viewer.min.js // @require https://fastly.jsdelivr.net/npm/@highlightjs/cdn-assets@11.11.0/highlight.min.js // @resource HljsCSS https://fastly.jsdelivr.net/npm/highlight.js@11.11.0/styles/github-dark.min.css // @resource ViewerCSS https://fastly.jsdelivr.net/npm/viewerjs@1.11.7/dist/viewer.min.css // @connect * // @connect * // @connect helloimg.com // @connect z4a.net // @connect kggzs.cn // @connect woozooo.com // @grant GM_deleteValue // @grant GM_getResourceText // @grant GM_getValue // @grant GM_info // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_unregisterMenuCommand // @grant GM_xmlhttpRequest // @grant unsafeWindow // @run-at document-start // ==/UserScript== (function (Qmsg, DOMUtils, Utils, pops, Viewer, hljs) { 'use strict'; var __defProp = Object.defineProperty; var __getOwnPropNames = Object.getOwnPropertyNames; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); var require_entrance_001 = __commonJS({ "entrance-CZ8XgvVO.js"(exports, module) { var _a; var _GM_deleteValue = /* @__PURE__ */ (() => typeof GM_deleteValue != "undefined" ? GM_deleteValue : void 0)(); var _GM_getResourceText = /* @__PURE__ */ (() => typeof GM_getResourceText != "undefined" ? GM_getResourceText : void 0)(); var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)(); var _GM_info = /* @__PURE__ */ (() => typeof GM_info != "undefined" ? GM_info : void 0)(); var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)(); var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)(); var _GM_unregisterMenuCommand = /* @__PURE__ */ (() => typeof GM_unregisterMenuCommand != "undefined" ? GM_unregisterMenuCommand : void 0)(); var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)(); var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)(); var _monkeyWindow = /* @__PURE__ */ (() => window)(); const HttpxCookieManager = { $data: { /** 是否启用 */ get enable() { return PopsPanel.getValue("httpx-use-cookie-enable"); }, /** 是否使用document.cookie */ get useDocumentCookie() { return PopsPanel.getValue("httpx-use-document-cookie"); }, cookieRule: [ { key: "httpx-cookie-bbs.binmt.cc", hostname: /bbs.binmt.cc/g } ] }, /** * 补充cookie末尾分号 */ fixCookieSplit(str) { if (utils.isNotNull(str) && !str.trim().endsWith(";")) { str += ";"; } return str; }, /** * 合并两个cookie */ concatCookie(targetCookie, newCookie) { if (utils.isNull(targetCookie)) { return newCookie; } targetCookie = targetCookie.trim(); newCookie = newCookie.trim(); targetCookie = this.fixCookieSplit(targetCookie); if (newCookie.startsWith(";")) { newCookie = newCookie.substring(1); } return targetCookie.concat(newCookie); }, /** * 处理cookie * @param details * @returns */ handle(details) { if (details.fetch) { return; } if (!this.$data.enable) { return; } let ownCookie = ""; let url = details.url; if (url.startsWith("//")) { url = window.location.protocol + url; } let urlObj = new URL(url); if (this.$data.useDocumentCookie && urlObj.hostname.endsWith( window.location.hostname.split(".").slice(-2).join(".") )) { ownCookie = this.concatCookie(ownCookie, document.cookie.trim()); } for (let index = 0; index < this.$data.cookieRule.length; index++) { let rule = this.$data.cookieRule[index]; if (urlObj.hostname.match(rule.hostname)) { let cookie = PopsPanel.getValue(rule.key); if (utils.isNull(cookie)) { break; } ownCookie = this.concatCookie(ownCookie, cookie); } } if (utils.isNotNull(ownCookie)) { if (details.headers && details.headers["Cookie"]) { details.headers.Cookie = this.concatCookie( details.headers.Cookie, ownCookie ); } else { details.headers["Cookie"] = ownCookie; } log.info(["Httpx => 设置cookie:", details]); } if (details.headers && details.headers.Cookie != null && utils.isNull(details.headers.Cookie)) { delete details.headers.Cookie; } } }; const GM_RESOURCE_MAPPING = { ElementPlus: { keyName: "ElementPlusResourceCSS", url: "https://fastly.jsdelivr.net/npm/element-plus@latest/dist/index.min.css" }, Viewer: { keyName: "ViewerCSS", url: "https://fastly.jsdelivr.net/npm/viewerjs@latest/dist/viewer.min.css" }, Hljs: { keyName: "HljsCSS", url: "https://fastly.jsdelivr.net/npm/highlight.js@latest/styles/github-dark.min.css" } }; (function(global, factory) { if (typeof exports === "object" && typeof module !== "undefined") { module.exports = factory(); } else { global = typeof globalThis !== "undefined" ? globalThis : global || self; global.Watermark = factory(global.Watermark); } })(typeof window !== "undefined" ? window : void 0, function(AnotherWatermark) { let Watermark = function() { }; CanvasRenderingContext2D.prototype.letterSpacingText = function(text, x, y, letterSpacing) { var context = this; var canvas = context.canvas; if (!letterSpacing && canvas) { letterSpacing = parseFloat(window.getComputedStyle(canvas).letterSpacing); } if (!letterSpacing) { return this.fillText(text, x, y); } var arrText = text.split(""); var align = context.textAlign || "left"; var originWidth = context.measureText(text).width; var actualWidth = originWidth + letterSpacing * (arrText.length - 1); if (align == "center") { x = x - actualWidth / 2; } else if (align == "right") { x = x - actualWidth; } context.textAlign = "left"; arrText.forEach(function(letter) { var letterWidth = context.measureText(letter).width; context.fillText(letter, x, y); x = x + letterWidth + letterSpacing; }); context.textAlign = align; }; CanvasRenderingContext2D.prototype.wrapText = function(text, x, y, maxWidth, lineHeight, stroke) { if (typeof text != "string" || typeof x != "number" || typeof y != "number") { return; } var context = this; var canvas = context.canvas; if (typeof maxWidth == "undefined") { maxWidth = canvas && canvas.width || 300; } if (typeof lineHeight == "undefined") { lineHeight = canvas && parseInt(window.getComputedStyle(canvas).lineHeight) || parseInt(window.getComputedStyle(document.body).lineHeight); } var arrText = text.split(""); var line = ""; for (var n = 0; n < arrText.length; n++) { var testLine = line + arrText[n]; var metrics = context.measureText(testLine); var testWidth = metrics.width; if (testWidth > maxWidth && n > 0) { if (stroke) { context.strokeText(line, x, y, canvas.width); } else { context.fillText(line, x, y); } line = arrText[n]; y += lineHeight; } else { line = testLine; } } if (stroke) { context.strokeText(line, x, y, canvas.width); } else { context.fillText(line, x, y); } }; CanvasRenderingContext2D.prototype.fillTextVertical = function(text, x, y) { var context = this; context.canvas; var arrText = text.split(""); var arrWidth = arrText.map(function(letter) { return context.measureText(letter).width; }); var align = context.textAlign; var baseline = context.textBaseline; if (align == "left") { x = x + Math.max.apply(null, arrWidth) / 2; } else if (align == "right") { x = x - Math.max.apply(null, arrWidth) / 2; } if (baseline == "bottom" || baseline == "alphabetic" || baseline == "ideographic") { y = y - arrWidth[0] / 2; } else if (baseline == "top" || baseline == "hanging") { y = y + arrWidth[0] / 2; } context.textAlign = "center"; context.textBaseline = "middle"; arrText.forEach(function(letter, index) { var letterWidth = arrWidth[index]; var code = letter.charCodeAt(0); if (code <= 256) { context.translate(x, y); context.rotate(90 * Math.PI / 180); context.translate(-x, -y); } else if (index > 0 && text.charCodeAt(index - 1) < 256) { y = y + arrWidth[index - 1] / 2; } context.fillText(letter, x, y); context.setTransform(1, 0, 0, 1, 0, 0); var letterWidth = arrWidth[index]; y = y + letterWidth; }); context.textAlign = align; context.textBaseline = baseline; }; function loadFile(file) { let fileReader = new FileReader(); return new Promise((resolve) => { fileReader.onloadend = async function(event) { resolve(event); }; fileReader.readAsDataURL(file); }); } function loadImage(src) { let image = new Image(); return new Promise((resolve) => { image.onload = () => { resolve(image); }; image.src = src; }); } function checkInArrayByPos(arrayData, x, y) { let flag = false; Array.from(arrayData).forEach((item) => { if (item["x"] == x && item["y"] == y) { flag = true; return; } }); return flag; } function getRandValue(arr) { if (arr instanceof Array) { return arr[Math.floor(Math.random() * arr.length)]; } else { return arr; } } Watermark.prototype.setFile = function(file) { let that = this; return new Promise(async (resolve) => { try { var fileReader = await loadFile(file); await that.setImage(fileReader.target.result); resolve(true); } catch (error) { resolve(false); } }); }; Watermark.prototype.setImage = function(src) { this.dataUrl = src; let that = this; return new Promise(async (res) => { var image = await loadImage(src); that.sizes = { width: image.width, height: image.height }; var canvas = document.createElement("canvas"); canvas.width = that.sizes.width; canvas.height = that.sizes.height; var ctx = canvas.getContext("2d"); ctx.drawImage(image, 0, 0); image = null; that.canvas = canvas; res(true); }); }; Watermark.prototype.hasImage = function() { return !!this.dataUrl; }; Watermark.prototype.getSize = function() { return this.sizes; }; Watermark.prototype.clearMark = function() { let that = this; if (typeof that.canvas === "undefined") { return; } function _clearMark_() { var ctx = that.canvas.getContext("2d"); ctx.clearRect(0, 0, that.canvas.width, that.canvas.height); var w = that.canvas.width; var h = that.canvas.height; that.canvas.width = w; that.canvas.height = h; ctx.beginPath(); var image = new Image(); image.src = that.dataUrl; ctx.drawImage(image, 0, 0); image = null; } _clearMark_(); }; Watermark.prototype.addText = function(opts) { var options = { text: ["Call By waterMark.addText"], fontSize: "6vw", fontFamily: "Microsoft Yahei", color: "#000000", textAlign: "center", /* 描边 */ stroke: false, globalAlpha: 0.7, /* -360 ~ 360 */ rotateAngle: 50, /* 必须大于0 */ maxWidth: 100, /* 必须大于0 */ xMoveDistance: 30, /* 必须大于0 */ yMoveDistance: 30 }; for (let key in options) { if (typeof opts[key] !== "undefined") { options[key] = opts[key]; } } options.maxWidth = parseInt(options.maxWidth) > 0 ? options.maxWidth : 1; options.xMoveDistance = parseInt(options.xMoveDistance) > 0 ? options.xMoveDistance : 1; options.yMoveDistance = parseInt(options.yMoveDistance) > 0 ? options.yMoveDistance : 1; var ctx = this.canvas.getContext("2d"); var fontSize = options.fontSize; fontSize = fontSize.toString(); if (~fontSize.indexOf("vw")) { fontSize = (this.sizes.width / 100 * parseInt(fontSize)).toFixed(0); } fontSize = parseInt(fontSize); ctx.font = fontSize + "px " + options.fontFamily; ctx.fillStyle = options.color; ctx.textAlign = options.textAlign; ctx.globalAlpha = options.globalAlpha; let canvasWidth = this.sizes.width, canvasHeight = this.sizes.height; let rotateAngle = options.rotateAngle * Math.PI / 180; let xMoveDistance = options.xMoveDistance; let yMoveDistance = options.yMoveDistance; let maxWidth = options.maxWidth; let lineHeight = fontSize; let pos = []; for (var i = canvasWidth / 2; i < canvasWidth; i += xMoveDistance) { for (var j = canvasHeight / 2; j < canvasHeight; j += yMoveDistance) { if (!checkInArrayByPos(pos, i, j)) { pos = pos.concat({ x: i, y: j }); ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.translate(i, j); ctx.rotate(rotateAngle); ctx.wrapText( getRandValue(options.text), 0, 0, maxWidth, lineHeight, options.stroke ); } } for (var k = canvasHeight / 2; k > 0; k -= yMoveDistance) { if (!checkInArrayByPos(pos, i, k)) { pos = pos.concat({ x: i, y: k }); ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.translate(i, k); ctx.rotate(rotateAngle); ctx.wrapText( getRandValue(options.text), 0, 0, maxWidth, lineHeight, options.stroke ); } } } for (var i = canvasWidth / 2; i > 0; i -= xMoveDistance) { for (var j = canvasHeight / 2; j < canvasHeight; j += yMoveDistance) { if (!checkInArrayByPos(pos, i, j)) { pos = pos.concat({ x: i, y: j }); ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.translate(i, j); ctx.rotate(rotateAngle); ctx.wrapText( getRandValue(options.text), 0, 0, maxWidth, lineHeight, options.stroke ); } } for (var k = canvasHeight / 2; k > 0; k -= yMoveDistance) { if (!checkInArrayByPos(pos, i, k)) { pos = pos.concat({ x: i, y: k }); ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.translate(i, k); ctx.rotate(rotateAngle); ctx.wrapText( getRandValue(options.text), 0, 0, maxWidth, lineHeight, options.stroke ); } } } }; Watermark.prototype.addPixelText = function(opts) { var options = { text: "像素文字水印", /* 像素文字 */ big: { fontSize: 150, fontFamily: "微软雅黑", textAlign: "center", rotateAngle: 0, /* 描边 */ stroke: false }, /* 绘制像素的文字 */ small: { fontSize: 10, fontFamily: "微软雅黑", color: "#000", textAlign: "center", globalAlpha: 0.7 } }; for (let key in options) { if (typeof opts[key] !== "undefined") { options[key] = opts[key]; } } var ctx = this.canvas.getContext("2d"); var tmpCanvas = document.createElement("canvas"); var tmpctx = tmpCanvas.getContext("2d"); tmpCanvas.width = this.sizes.width; tmpCanvas.height = this.sizes.height; tmpctx.font = options.big.fontSize + "px " + options.big.fontFamily; tmpctx.textAlign = options.big.textAlign; tmpctx.textBaseline = "middle"; tmpctx.translate(tmpCanvas.width / 2, tmpCanvas.height / 2); tmpctx.rotate(options.big.rotateAngle * Math.PI / 180); tmpctx.translate(-tmpCanvas.width / 2, -tmpCanvas.height / 2); if (options.big.stroke) { tmpctx.strokeText( options.text, tmpCanvas.width / 2, tmpCanvas.height / 2, tmpCanvas.width ); } else { tmpctx.fillText(options.text, tmpCanvas.width / 2, tmpCanvas.height / 2); } var textArray = options.text.split(""); var textPixleInfo = tmpctx.getImageData( 0, 0, tmpCanvas.width, tmpCanvas.height ); var pixelArray = []; for (var i = 0; i < tmpCanvas.height; i += options.small.fontSize) { for (var j = 0; j < tmpCanvas.width; j += options.small.fontSize) { var index = j + i * tmpCanvas.width; var a = textPixleInfo.data[index * 4 + 3]; if (a > 128) { pixelArray.push({ text: getRandValue(textArray), x: j, y: i }); } } } ctx.font = options.small.fontSize + "px " + options.small.fontFamily; ctx.fillStyle = options.small.color; ctx.textAlign = options.small.textAlign; ctx.textBaseline = "middle"; ctx.globalAlpha = options.small.globalAlpha; pixelArray.forEach((item) => { ctx.fillText(item.text, item.x, item.y); }); }; Watermark.prototype.addImage = function(opts) { if (opts.imageArray == null) { alert("参数缺少imageArray"); return false; } if (opts.imageArray.length === 0) { alert("参数imageArray不能为空"); return false; } let options = { imageArray: [], /* 里面为水印Image对象 */ width: 50, /* 必须大于0 */ height: 50, /* 必须大于0 */ globalAlpha: 0.5, rotateAngle: 0, xMoveDistance: 70, /* 必须大于0 */ yMoveDistance: 70 /* 必须大于0 */ }; for (let key in options) { if (typeof opts[key] !== "undefined") { options[key] = opts[key]; } } options.width = parseInt(options.width) > 0 ? options.width : 1; options.height = parseInt(options.height) > 0 ? options.height : 1; options.xMoveDistance = parseInt(options.xMoveDistance) > 0 ? options.xMoveDistance : 1; options.yMoveDistance = parseInt(options.yMoveDistance) > 0 ? options.yMoveDistance : 1; let ctx = this.canvas.getContext("2d"); let waterImageCanvasArray = []; let waterImageCanvasDiagonal = parseInt( Math.sqrt(options.width * options.width + options.height * options.height) ); let canvasWidth = this.sizes.width, canvasHeight = this.sizes.height; let rotateAngle = options.rotateAngle * Math.PI / 180; let xMoveDistance = options.xMoveDistance; let yMoveDistance = options.yMoveDistance; let centerDrawLeftPosX = canvasWidth / 2 - waterImageCanvasDiagonal / 2; let centerDrawLeftPosY = canvasHeight / 2 - waterImageCanvasDiagonal / 2; let waterDrawPosX = (waterImageCanvasDiagonal - options.width) / 2; let waterDrawPosY = (waterImageCanvasDiagonal - options.height) / 2; Array.from(options.imageArray).forEach((item) => { var waterImageCanvas = document.createElement("canvas"); var waterctx = waterImageCanvas.getContext("2d"); waterImageCanvas.width = waterImageCanvasDiagonal; waterImageCanvas.height = waterImageCanvasDiagonal; waterctx.globalAlpha = options.globalAlpha; waterctx.translate( waterImageCanvasDiagonal / 2, waterImageCanvasDiagonal / 2 ); waterctx.rotate(rotateAngle); waterctx.translate( -waterImageCanvasDiagonal / 2, -waterImageCanvasDiagonal / 2 ); waterctx.drawImage( item, waterDrawPosX, waterDrawPosY, options.width, options.height ); waterImageCanvasArray = waterImageCanvasArray.concat(waterImageCanvas); }); function randomArrayData(array_data) { return array_data[Math.floor(Math.random() * array_data.length)]; } ctx.setTransform(1, 0, 0, 1, 0, 0); let pos = []; for (let i = centerDrawLeftPosX; i < canvasWidth; i += xMoveDistance) { for (let j = centerDrawLeftPosY; j < canvasHeight; j += yMoveDistance) { if (!checkInArrayByPos(pos, i, j)) { pos = pos.concat({ x: i, y: j }); ctx.drawImage( randomArrayData(waterImageCanvasArray), i, j ); } } for (let k = centerDrawLeftPosY; k > -Math.abs(waterImageCanvasDiagonal); k -= yMoveDistance) { if (!checkInArrayByPos(pos, i, k)) { pos = pos.concat({ x: i, y: k }); ctx.drawImage(randomArrayData(waterImageCanvasArray), i, k); } } } for (let i = centerDrawLeftPosX; i > -Math.abs(waterImageCanvasDiagonal); i -= xMoveDistance) { for (let j = centerDrawLeftPosY; j < canvasHeight; j += yMoveDistance) { if (!checkInArrayByPos(pos, i, j)) { pos = pos.concat({ x: i, y: j }); ctx.drawImage(randomArrayData(waterImageCanvasArray), i, j); } } for (let k = centerDrawLeftPosY; k > -Math.abs(waterImageCanvasDiagonal); k -= yMoveDistance) { if (!checkInArrayByPos(pos, i, k)) { pos = pos.concat({ x: i, y: k }); ctx.drawImage(randomArrayData(waterImageCanvasArray), i, k); } } } }; Watermark.prototype.getPreview = function() { return this.dataUrl; }; Watermark.prototype.render = function(type) { type = type === "png" ? "png" : "jpeg"; return this.canvas.toDataURL("image/" + type); }; Watermark.prototype.renderBlob = function() { let that = this; return new Promise((res) => { that.canvas.toBlob(function(blob) { res(window.URL.createObjectURL(blob)); }); }); }; Watermark.prototype.noConflict = function() { if (window.Watermark) { delete window.Watermark; } if (AnotherWatermark) { window.Watermark = AnotherWatermark; } return Watermark; }; return Watermark; }); const CommonUtil = { /** * 添加屏蔽CSS * @param args * @example * addBlockCSS("") * addBlockCSS("","") * addBlockCSS(["",""]) */ addBlockCSS(...args) { let selectorList = []; if (args.length === 0) { return; } if (args.length === 1 && typeof args[0] === "string" && args[0].trim() === "") { return; } args.forEach((selector) => { if (Array.isArray(selector)) { selectorList = selectorList.concat(selector); } else { selectorList.push(selector); } }); return addStyle(`${selectorList.join(",\n")}{display: none !important;}`); }, /** * 设置GM_getResourceText的style内容 * @param resourceMapData 资源数据 * @example * setGMResourceCSS({ * keyName: "ViewerCSS", * url: "https://example.com/example.css", * }) */ setGMResourceCSS(resourceMapData) { let cssText = typeof _GM_getResourceText === "function" ? _GM_getResourceText(resourceMapData.keyName) : ""; if (typeof cssText === "string" && cssText) { addStyle(cssText); } else { CommonUtil.loadStyleLink(resourceMapData.url); } }, /** * 添加标签 * @param url * @example * loadStyleLink("https://example.com/example.css") */ async loadStyleLink(url) { let $link = document.createElement("link"); $link.rel = "stylesheet"; $link.type = "text/css"; $link.href = url; domUtils.ready(() => { document.head.appendChild($link); }); }, /** * 添加