// ==UserScript==
// @name 搜索引擎去广告
// @description 谷歌百度搜狗神马必应搜索去广告,适配电脑和手机,没去夸克,神马搜索就是夸克搜索,谷歌搜索拦截部分内容广场
// @author Lemon399
// @version 29
// @match *://www.google.co.jp/*
// @match *://www.google.com.hk/*
// @match *://www.google.com/*
// @match *://m.baidu.com/*
// @match *://www.baidu.com/*
// @match *://m.sm.cn/*
// @match *://yz.m.sm.cn/*
// @match *://wap.sogou.com/*
// @match *://m.sogou.com/*
// @match *://www.sogou.com/*
// @match *://cn.bing.com/*
// @match *://www.bing.com/*
// @require https://gf.qytechs.cn/scripts/452263-extended-css/code/extended-css.js?version=1124696
// @grant GM_addStyle
// @grant unsafeWindow
// @run-at document-start
// @namespace https://lemon399-bitbucket-io.vercel.app/
// @source https://gitee.com/lemon399/tampermonkey-cli/tree/master/projects/abp_parse
// @copyright GPL-3.0
// @license GPL-3.0
// ==/UserScript==
(function (tm, ExtendedCss) {
"use strict";
let defaultRules = `
! 没有 ## #@# #?# #@?#
! #$# #@$# #$?# #@$?# 的行和
! 开头为 ! 的行会忽略
!
! 由于语法限制,内置规则中
! 一个反斜杠需要改成两个,像这样 \\
www.google.com,www.google.com.hk,www.google.co.jp##DIV[data-sokoban-container]:has([href*='%E2%9C%94%EF%B8%8F%E2%96%9B']),DIV[data-sokoban-container]:has([href*='%E3%80%90%E2%9C%94%EF%B8%8F']),DIV[data-sokoban-container]:has([href*='%E2%9E%BF%E3%80%91']),DIV[data-sokoban-container]:has([href*='%E2%8F%AA%29']),DIV[data-sokoban-container]:has([href*='%E2%9A%BD%E3%80%91']),DIV[data-sokoban-container]:has([href*='-%E3%80%90']),DIV[data-sokoban-container]:has([href*='%E2%9C%94%EF%B8%8F'][href*='%E2%98%80%EF%B8%8F']),DIV[data-sokoban-container]:has([href*='-('][href*='%E2%9C%94%EF%B8%8F']),DIV[data-sokoban-container]:has([href*='%E2%9C%94%EF%B8%8F%29']),DIV[data-sokoban-container]:has([href*='-%E2%9C%94%EF%B8%8F'])
baidu.com#?#.ec_wise_ad
####DIV[data-text-ad]
##.ad-block
www.baidu.com##.result-op[tpl="right_game_recommend"]
www.baidu.com##div[id$="_canvas"]
www.baidu.com##style[id*="s-m"] + div[id^="m"]
www.baidu.com#?##content_left > *:not([id]) *,[class="result c-container new-pmd"][id="1"][tpl="se_com_default"][data-click="{"]
www.baidu.com#?##content_left > div:not([class]) > div[data-placeid]
www.baidu.com#?##content_right > table > tbody > tr > td > div:not(#con-ar):not([class])
www.baidu.com#?#div:not([id]) > style[id^="s-"] + div[id]
www.baidu.com#?##content_left > [style*="important"]
www.baidu.com#?#div[id$="_canvas"]
www.baidu.com#?#.c-container:-abp-has(.t > a[data-landurl])
m.baidu.com,www.baidu.com#?##results > div[class]:not(.result):not(.result-op):not(.sp-rslt-bar):not(.s-group-result)
baidu.com###content_left > *:not([id]) *
baidu.com##[class='result c-container new-pmd'][id='1'][tpl='se_com_default'][data-click='{']
baidu.com###content_right > table > tbody > tr > td > div:not(#con-ar):not([class])
baidu.com##.result-op[tpl='sp_hot_sale']
m.baidu.com##DIV#relativewords.se-relativewords.c-container.se-relativewords-new.c-bg-color-white
m.sm.cn##DIV.ad-alert-info
##.se-recommend-word-list-container
###se-recommend-word-list-container
##[class*="ball-wrapper"]
baidu.com##DIV#page-copyright.se-page-copyright[style='margin-bottom: 50px;']
baidu.com##DIV[style^='position: fixed; bottom: 0px; left: 0px; z-index: 300; width: 100%; height: 52px; background: rgb(255, 255, 255);']
##[ad_dot_url*="http"]
##.dl-banner-without-logo
##.ad_result
##[data-text-ad="1"]
###content_left > *:not([id]) *
##[class="result c-container new-pmd"][id="1"][tpl="se_com_default"][data-click="{"]
##.biz_sponsor
##.b_algospacing
##[onmousedown*="ad"][h*="Ads"]
bing.com##DIV#bnp_container
bing.com##li.b_ad
bing.com##.ad_sc
bing.com#?#li[class="b_algo"]:-abp-has(.b_attribution[data-partnertag]+p[class])
bing.com#?##b_results > li:-abp-has(.b_adProvider)
##[href^='http://yz.m.sm.cn/adclick']
`;
const ruleRE = [
/^(~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*)(,~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*))*)?##([^\s^+].*)/,
/^(~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*)(,~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*))*)?#@#([^\s+].*)/,
/^(~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*)(,~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*))*)?#\?#([^\s].*)/,
/^(~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*)(,~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*))*)?#@\?#([^\s].*)/,
/^(~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*)(,~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*))*)?#\$#([^\s].*)/,
/^(~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*)(,~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*))*)?#@\$#([^\s].*)/,
/^(~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*)(,~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*))*)?#\$\?#([^\s].*)/,
/^(~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*)(,~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*))*)?#@\$\?#([^\s].*)/,
];
function findMatches(string, res) {
let result = [-1, null];
res.forEach((re, i) => {
const match = string.match(re);
if (match) result = [i, match];
});
return result;
}
function makeRuleBox() {
return {
black: [],
white: [],
};
}
function domainChecker(domains) {
const results = [],
invResults = [],
urlSuffix = /\.+?[\w-]+$/.exec(location.hostname);
let totalResult = [0, false],
black = false,
white = false;
domains.forEach((domain) => {
if (domain.endsWith(".*") && Array.isArray(urlSuffix)) {
domain = domain.replace(".*", urlSuffix[0]);
}
const invert = domain[0] == "~";
if (invert) domain = domain.slice(1);
const result = location.hostname.endsWith(domain);
if (invert) {
if (result) white = true;
invResults.push([domain.length, !result]);
} else {
if (result) black = true;
results.push([domain.length, result]);
}
});
if (results.length > 0 && !black) {
return false;
} else if (invResults.length > 0 && !white) {
return true;
} else {
results.forEach((r) => {
if (r[0] >= totalResult[0] && r[1]) {
totalResult = r;
}
});
invResults.forEach((r) => {
if (r[0] >= totalResult[0] && !r[1]) {
totalResult = r;
}
});
return totalResult[1];
}
}
function hasSome(str, arr) {
return arr.some((word) => str.includes(word));
}
function ruleSpliter(rule) {
const result = findMatches(rule, ruleRE),
group = result[1];
if (group && (!group[1] || domainChecker(group[1].split(",")))) {
const sel = group.pop();
if (sel) {
return {
black: result[0] % 2 ? "white" : "black",
type: Math.floor(result[0] / 2),
sel,
};
}
}
}
function ruleLoader(rule) {
if (
hasSome(rule, [
":matches-path(",
":min-text-length(",
":watch-attr(",
":-abp-properties(",
":matches-property(",
"if-not(",
])
)
return;
// 去掉开头空格
rule = rule.replace(/^ +/, "");
// 如果 #$# 不包含 {} 就排除
// 可以尽量排除 Snippet Filters
if (/(\w|^)#\$#/.test(rule) && !/{.+}/.test(rule)) return;
// ## -> #?#
if (
/(\w|^)#@?#/.test(rule) &&
hasSome(rule, [
":has(",
":-abp-has(",
"[-ext-has=",
":has-text(",
"contains(",
"-abp-contains(",
"[-ext-contains=",
"matches-css(",
"[-ext-matches-css=",
"matches-css-before(",
"[-ext-matches-css-before=",
"matches-css-after(",
"[-ext-matches-css-after=",
"matches-attr(",
"nth-ancestor(",
"upward(",
"xpath(",
"remove()",
"not(",
])
) {
rule = rule.replace(/(\w|^)##/, "$1#?#").replace(/(\w|^)#@#/, "$1#@?#");
}
// :style(...) 转换
// example.com#?##id:style(color: red)
// example.com#$?##id { color: red }
if (rule.includes(":style(")) {
rule = rule
.replace(/(\w|^)##/, "$1#$#")
.replace(/(\w|^)#@#/, "$1#@$#")
.replace(/(\w|^)#\?#/, "$1#$?#")
.replace(/(\w|^)#@\?#/, "$1#@$?#")
.replace(/:style\(/, " { ")
.replace(/\)$/, " }");
}
return ruleSpliter(rule);
}
const selectors = makeRuleBox(),
extSelectors = makeRuleBox(),
styles = makeRuleBox(),
extStyles = makeRuleBox(),
data = {
allRules: defaultRules,
presetCss:
" {display: none !important;width: 0 !important;height: 0 !important;} ",
hideCss: "",
extraCss: "",
mutex: "__lemon__abp__parser__$__",
};
function styleApply() {
if (data.hideCss.length > 0) {
if (typeof tm.GM_addStyle == "function") {
tm.GM_addStyle(data.hideCss);
} else {
const elem = document.createElement("style");
elem.textContent = data.hideCss;
document.documentElement.appendChild(elem);
}
}
if (data.extraCss.length > 0) {
data.extraCss.split("\n").forEach((css) => {
new ExtendedCss({ styleSheet: css }).apply();
});
}
}
function parseRules() {
const boxes = ["hideCss", "extraCss"];
data.hideCss = "";
data.extraCss = "";
[styles, extStyles].forEach((r, t) => {
r.black
.filter((v) => !r.white.includes(v))
.forEach((s) => {
const checkResult = ExtendedCss.validate(s.split("{")[0]);
if (checkResult.ok) {
data[boxes[t]] += `${s} \n`;
} else {
console.warn("选择器检查错误:", s.split("{")[0], checkResult.error);
}
});
});
[selectors, extSelectors].forEach((r, t) => {
r.black
.filter((v) => !r.white.includes(v))
.forEach((s, i) => {
const checkResult = ExtendedCss.validate(s);
if (checkResult.ok) {
data[boxes[t]] += `${i == 0 ? "" : "\n"}${s + data.presetCss}`;
} else {
console.warn("选择器检查错误:", s, checkResult.error);
}
});
});
styleApply();
}
function splitRules() {
data.allRules.split("\n").forEach((rule) => {
const ruleObj = ruleLoader(rule),
boxes = [selectors, extSelectors, styles, extStyles];
if (typeof ruleObj != "undefined") {
if (
ruleObj.black == "black" &&
boxes[ruleObj.type].white.includes(ruleObj.sel)
)
return;
boxes[ruleObj.type][ruleObj.black].push(ruleObj.sel);
}
});
parseRules();
}
function runOnce(key, func) {
if (key in tm.unsafeWindow) return;
tm.unsafeWindow[key] = true;
func();
}
runOnce(data.mutex, splitRules);
})(
{
GM_info: typeof GM_info == "object" ? GM_info : {},
GM_addStyle: typeof GM_addStyle == "function" ? GM_addStyle : undefined,
unsafeWindow: typeof unsafeWindow == "object" ? unsafeWindow : window,
},
ExtendedCss
);