// ==UserScript== // @name rBlock // @author nonoroazoro // @description 移除一些网站用于数据统计的链接跳转及部分其他功能,加快网站访问速度。 // @description:en Remove redirects and some features of web sites. // @homepageURL https://github.com/nonoroazoro/rBlock // @namespace https://greasyfork.org/zh-CN/scripts/20568-rblock // @grant none // @version 1.3.1 // @run-at document-end // @include /^https?:\/\/(.+\.)?github\./ // @include /^https?:\/\/(.+\.)?google\./ // @include /^https?:\/\/(.+\.)?zhihu\./ // @downloadURL none // ==/UserScript== const rBlock = { _blockers: [], start: function () { this.init(); this._blockers.forEach(blocker => blocker.start()); }, init: function () { this._blockers = []; const _host = window.location.host; // 1. google if (/^(.+\.)?google\./.test(_host)) { this._blockers.push({ start: function () { // 1. for static pages. // when google instant predictions is disabled, // this blocker will only be called once. this._block(); // 2. for dynamic pages. // when google instant predictions is enabled, // this blocker will be call whenever the current page is updated. _observe(this._block); }, // block redirects of google _block: function () { // 1. general let elems = document.querySelectorAll(`a[href*="url="]`); revealURL(elems, /.*url=(http[^&]+)/i); // 2. images elems = document.querySelectorAll(`a[jsaction][href]:not(.rg_l)`); _removeAttributes(elems, "jsaction"); // 3. all/videos/news/apps elems = document.querySelectorAll(`a[onmousedown^="return rwt("]`); _removeAttributes(elems, "onmousedown"); // 4. cached links elems = document.querySelectorAll(`a[href^="http://webcache.googleusercontent."], a[href^="https://webcache.googleusercontent."]`); const targets = document.querySelectorAll(`a.rblock-cached-link`); if (elems.length !== targets.length * 2) { // prevent duplication let menuLink; let cacheLink; elems.forEach((elem) => { elem.style.display = "inline"; menuLink = elem.closest("div.action-menu.ab_ctl"); cacheLink = document.createElement("a"); cacheLink.setAttribute("href", elem.getAttribute("href").replace(/^http\:/, "https:")); cacheLink.setAttribute("class", "rblock-cached-link"); cacheLink.target = "_blank"; cacheLink.innerText = " Cached "; menuLink.parentNode.insertBefore(cacheLink, menuLink); }); } } }); } // 2. zhihu if (/^(.+\.)?zhihu\./.test(_host)) { this._blockers.push({ start: function () { this._block(); _observe(this._block); }, _block: function () { // 1. general revealURL( document.querySelectorAll(`a[href*="?target="]`), /.*target=(http[^&]+)/i ); // 2. open in new tab document.querySelectorAll(`a.internal`).forEach((elem) => _openInNewTab(elem)); } }); } // 3. github if (/^(.+\.)?github\./.test(_host)) { this._blockers.push({ start: function () { this._block(); }, _block: function () { // 1. disable keyboard shortcuts: "s" and "w" document.addEventListener("keydown", (e) => { if (e.key === "s" || e.key === "S" || e.key === "w" || e.key === "W") { e.stopPropagation(); } }, true); } }); } } }; function _observe(p_callback) { if (typeof p_callback === "function" && document.body) { (new window.MutationObserver(debounce(p_callback))).observe(document.body, { childList: true, subtree: true }); } } function _removeAttributes(p_elements, p_attributes) { if (p_elements && typeof p_attributes === "string") { const attributes = p_attributes.split(/\W+/) || []; p_elements.forEach((elem) => { attributes.forEach((attr) => { elem.removeAttribute(attr); }); }); } } function _removeListeners(p_element, p_events) { if (p_element && typeof p_events === "string") { const events = p_events.split(/\W+/) || []; events.forEach((event) => { p_element.removeEventListener(event, _preventDefaultAction, true); p_element.addEventListener(event, _preventDefaultAction, true); }); } } function _preventDefaultAction(e) { e.stopPropagation(); } function revealURL(p_elems, p_regex) { if (p_elems && p_regex) { let groups; p_elems.forEach((elem) => { // reveal url & open in new tab groups = decodeURIComponent(elem.getAttribute("href")).match(p_regex); if (groups && groups[1]) { elem.setAttribute("href", groups[1]); _openInNewTab(elem); } }); } } function _openInNewTab(p_elem) { if (p_elem) { p_elem.target = "_blank"; } } function debounce(p_callback, p_delay = 500) { let timer = null; return function (...args) { const context = this; window.clearTimeout(timer); timer = window.setTimeout(() => { p_callback.apply(context, args); }, p_delay); }; } function throttle(p_callback, p_threshhold = 500, p_scope) { let last; let timer; return function (...args) { let now = +new Date(); let context = p_scope || this; if (last && now < last + p_threshhold) { window.clearTimeout(timer); timer = window.setTimeout(() => { last = now; p_callback.apply(context, args); }, p_threshhold); } else { last = now; p_callback.apply(context, args); } }; } rBlock.start();