Unlimit-Web

解除网页限制: 恢复文本的选中和复制, 过滤文本小尾巴, 恢复右键菜单. Remove webpage restrictions: restore the selection and copy of text, clear the text tail, and restore the right-click menu.

当前为 2025-02-09 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Unlimit-Web
  3. // @description 解除网页限制: 恢复文本的选中和复制, 过滤文本小尾巴, 恢复右键菜单. Remove webpage restrictions: restore the selection and copy of text, clear the text tail, and restore the right-click menu.
  4. // @version 13.0
  5. // @author xcanwin
  6. // @namespace https://github.com/xcanwin/Unlimit-Web/
  7. // @supportURL https://github.com/xcanwin/Unlimit-Web/
  8. // @icon data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24" stroke-width="2" fill="none" stroke="currentColor"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
  9. // @license GPL-2.0-only
  10. // @match *://www.zhihu.com/*
  11. // @match *://blog.csdn.net/*
  12. // @match *://www.bilibili.com/*
  13. // @match *://www.360doc.com/*
  14. // @match *://guofeng.yuedu.163.com/*
  15. // @match *://www.kuwo.cn/*
  16. // @match *://chuangshi.qq.com/*
  17. // @match *://read.qidian.com/*
  18. // @match *://dafrok.github.io/*
  19. // @match *://shushan.zhangyue.net/*
  20. // @match *://aqistudy.cn/*
  21. // @match *://www.xuexila.com/*
  22. // @match *://www.51test.net/*
  23. // @match *://www.laokaoya.com/*
  24. // @match *://utaten.com/*
  25. // @match *://book.qq.com/*
  26. // @match *://doc.mbalib.com/*
  27. // @match *://www.oh100.com/*
  28. // @match *://51test.net/*
  29. // @match *://www.cspengbo.com/*
  30. // @match *://www.diyifanwen.com/*
  31. // @match *://www.ahsrst.cn/*
  32. // @match *://kt250.com/*
  33. // @match *://*/*
  34. // @grant GM_getValue
  35. // @grant GM_setValue
  36. // @grant GM_registerMenuCommand
  37. // @grant GM_unregisterMenuCommand
  38. // @run-at document-end
  39. // ==/UserScript==
  40.  
  41. (function() {
  42. 'use strict';
  43.  
  44. const $ = (Selector, el) => (el || document).querySelector(Selector);
  45. const $$ = (Selector, el) => (el || document).querySelectorAll(Selector);
  46.  
  47. const muob = (Selector, el, func) => {
  48. const observer = new MutationObserver((mutationsList, observer2) => {
  49. for (let mutation of mutationsList) {
  50. if (mutation.type === 'childList') {
  51. const target = mutation.target.querySelector(Selector);
  52. if (target && !target.hasAttribute('data-duplicate')) {
  53. target.setAttribute('data-duplicate', 'true');
  54. func(target);
  55. }
  56. }
  57. }
  58. });
  59. observer.observe(el, {
  60. childList: true,
  61. subtree: true
  62. });
  63. };
  64.  
  65. /*黑名单: 需解除限制*/
  66. const block_list = {
  67. // 域名
  68. domain: {
  69. // 初始化,首次安装插件时使用此列表,之后使用插件存储的列表
  70. init: ["www.zhihu.com", "blog.csdn.net","www.bilibili.com","www.360doc.com","guofeng.yuedu.163.com","www.kuwo.cn","chuangshi.qq.com","read.qidian.com","dafrok.github.io","shushan.zhangyue.net","aqistudy.cn","www.xuexila.com","www.51test.net","www.laokaoya.com","utaten.com","book.qq.com","doc.mbalib.com","www.oh100.com","51test.net","www.cspengbo.com","www.diyifanwen.com","www.ahsrst.cn","kt250.com"],
  71. // 硬编码,除了使用插件存储的列表,每次也会使用此硬编码列表
  72. hard: [],
  73. }
  74. };
  75.  
  76. /*白名单: 指的是放行,无需解除限制*/
  77. const allow_list = {
  78. // 网页元素
  79. element: ['script', 'style', 'video'],
  80. };
  81.  
  82. const symbol = ["❎", "✅"];
  83. const symbol2 = ["未勾选", "已勾选"];
  84. let mc = [];
  85.  
  86. const sv = (key, value = "") => {
  87. GM_setValue(key, value);
  88. };
  89.  
  90. const gv = (key, value = "") => {
  91. return GM_getValue(key, value);
  92. };
  93.  
  94. /*枚举元素*/
  95. const eNum = (EL = null) => {
  96. $$("*", EL).forEach(unLimit);
  97. try {
  98. console.clear = () => {};
  99. window.debugger = () => {};
  100. } catch (e) {
  101. }
  102. };
  103.  
  104. /*判断是否包含*/
  105. const isIn = (el, list) => {
  106. return list.element.some(item => item.toLowerCase() === el.toLowerCase());
  107. };
  108.  
  109. /*解除限制*/
  110. const unLimit = (el = null) => {
  111. if (isIn(el.nodeName, allow_list.element)) return;
  112.  
  113. [
  114. "user-select", "-webkit-user-select", "-moz-user-select", "-ms-user-select", "-khtml-user-select", "pointer-events",
  115. ].forEach(xcanwin => {
  116. const ec = el.childNodes;
  117. const j1 = ec && ec.length == 1 && ec[0] && ec[0].nodeType && ec[0].nodeType == 3;
  118. const style = document.defaultView.getComputedStyle(el, null)[xcanwin];
  119. const j2 = style && style != 'auto';
  120. if (j1 || j2){
  121. // 处理第一个子标签是text类型的标签 或者 处理select值被修改过的标签
  122. el.style.setProperty(xcanwin, "unset", "important");
  123. }
  124. });
  125.  
  126. [
  127. "onselect", "onselectstart", "onselectionchange",
  128. "oncopy", "onbeforecopy",
  129. "onpaste", "onbeforepaste", "oncut", "onbeforecut",
  130. "onpointercancel", "onpointerdown", "onpointerenter", "onpointerleave", "onpointerlockchange", "onpointerlockerror", "onpointermove", "onpointerout", "onpointerover", "onpointerrawupdate", "onpointerup",
  131. ].forEach(xcanwin => {
  132. el[xcanwin] = e => {
  133. // 处理能影响文本的事件
  134. e.stopImmediatePropagation();
  135. }
  136. });
  137.  
  138. [
  139. "onmouseenter", "onmousedown", "onmouseup", "onmouseout", "onmouseleave", "onmouseover",
  140. ].forEach(xcanwin => {
  141. el[xcanwin] = e => {
  142. if ([ "P" ].indexOf(e.target.nodeName) >=0 && e.button == 0) {
  143. // 处理单击左键和滑动左键下的html文本标签
  144. e.stopImmediatePropagation();
  145. }
  146. }
  147. });
  148.  
  149. [
  150. "onkeypress", "onkeyup", "onkeydown",
  151. ].forEach(xcanwin => {
  152. el[xcanwin] = e => {
  153. const keyCode = e.keyCode || e.which || e.charCode;
  154. const ctrlKey = e.ctrlKey || e.metaKey;
  155. if ((ctrlKey && keyCode == 67) || keyCode == 123) {
  156. // 处理ctrl+c和F12
  157. e.stopImmediatePropagation();
  158. }
  159. }
  160. });
  161.  
  162. [
  163. "oncontextmenu",
  164. ].forEach(xcanwin => {
  165. el[xcanwin] = e => {
  166. if (e.target && e.target.points == undefined){
  167. // 处理普通的单击右键,跳过滑动右键
  168. e.stopImmediatePropagation();
  169. }
  170. }
  171. });
  172. };
  173.  
  174. /*加入自动破解列表*/
  175. const switchAuto = (domain) => {
  176. let autolist = JSON.parse(gv("ul_autolist", "[]"));
  177. domain = domain ? domain : getdomain();
  178. if (isIn(domain, autolist)) {
  179. autolist = autolist.filter(el => el !== domain);
  180. } else {
  181. autolist.push(domain);
  182. }
  183. sv("ul_autolist", JSON.stringify(autolist));
  184. rmc();
  185. unLimit();
  186. };
  187.  
  188. /*查看自动破解列表*/
  189. const showAuto = () => {
  190. prompt("自动破解列表", gv("ul_autolist", "[]"));
  191. };
  192.  
  193. /*初始化自动破解列表*/
  194. const initAutoList = () => {
  195. const init = block_list.domain.init;
  196. //为空或者为[]时,说明首次运行,进行初始化
  197. if (gv("ul_autolist", "[]") === "[]") {
  198. sv("ul_autolist", JSON.stringify(init));
  199. }
  200. //解析移除时,进行初始化
  201. try {
  202. JSON.parse(gv("ul_autolist", "[]"));
  203. } catch (e) {
  204. sv("ul_autolist", JSON.stringify(init));
  205. }
  206. };
  207.  
  208. /*取消注册菜单*/
  209. const unrmc = () => {
  210. mc.forEach(x => GM_unregisterMenuCommand(x));
  211. };
  212.  
  213. /*注册菜单*/
  214. const rmc = () => {
  215. unrmc();
  216. let isauto;
  217. const autolist = JSON.parse(gv("ul_autolist", "[]"));
  218. const domain = getdomain();
  219. if (isIn(domain, autolist.concat(block_list.domain.block))) {
  220. isauto = 1;
  221. } else {
  222. isauto = 0;
  223. }
  224. mc.push(GM_registerMenuCommand(`查看自动破解列表`, showAuto));
  225. mc.push(GM_registerMenuCommand(`临时破解:${domain}`, unLimit));
  226. mc.push(GM_registerMenuCommand(`自动破解:${domain} ${symbol[isauto]}${symbol2[isauto]}`, () => switchAuto(domain)));
  227. };
  228.  
  229. const getdomain = () => {
  230. return (new URL(location.href)).hostname;
  231. };
  232.  
  233. const main = () => {
  234. initAutoList();
  235. rmc();
  236. const autolist = JSON.parse(gv("ul_autolist", "[]"));
  237. const domain = getdomain();
  238. if (isIn(domain, autolist.concat(block_list.domain.block))) {
  239. eNum();
  240. setInterval(eNum, 3000);
  241. muob(`*`, $(`body`), (el) => {
  242. unLimit(el);
  243. });
  244. }
  245. };
  246.  
  247. main();
  248.  
  249. })();