// ==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.2.9
// @run-at document-end
// @include /^https?:\/\/(.+\.)?github\./
// @include /^https?:\/\/(.+\.)?google\./
// @include /^https?:\/\/(.+\.)?zhihu\./
// ==/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.
_startMutationObserver(
{
"id":
[
"search", // all/videos/news/shopping/books/apps
],
"class":
[
"irc_rit", // images
"pspo-popout pspo-lpop", // shopping
]
},
this._block
);
},
// block redirects of google
_block: function ()
{
const base = document.querySelector("div#search");
if (base)
{
// 1. general
revealURL(
base.querySelectorAll(`a[href*="url="]`),
/.*url=(http[^&]+)/i
);
// 2. all/videos/news/apps
let elems = base.querySelectorAll(`a[onmousedown^="return rwt("]`);
_removeAttributes(elems, "onmousedown");
// 3. 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();
_startMutationObserver(
{
"id":
[
"js-home-feed-list", // 首页最新动态
"zh-question-answer-wrap", // 具体内容
],
"class":
[
"zm-item-rich-text expandable js-collapse-body", // 首页、话题显示全部
"zh-general-list clearfix", // 话题
"entry", // 专栏
],
"data-type":
[
"daily", // 发现
]
},
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 _startMutationObserver(p_filter, p_handler)
{
if (typeof p_handler === "function")
{
const filter = p_filter || {};
const observer = new window.MutationObserver((p_mutations) =>
{
let needUpdate = false;
for (let mutation of p_mutations)
{
for (let key in p_filter)
{
if (p_filter[key].indexOf(mutation.target.getAttribute(key)) != -1)
{
needUpdate = true;
break;
}
}
if (needUpdate)
{
break;
}
}
if (needUpdate)
{
p_handler();
}
});
observer.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";
}
}
rBlock.start();