// ==UserScript==
// @name 百度搜索 - 优化
// @namespace http://tampermonkey.net/
// @home-url https://greasyfork.org/zh-CN/scripts/31642
// @description 1、屏蔽百度推广 2、关闭百度广告联盟信息收集 3、绑定快捷键 4、布局调整 5、居中单列(可选) 6、居中双列(可选)
// @version 4.1.7
// @author 浮生未歇
// @run-at document-start
// @include https://www.baidu.com/
// @include https://www.baidu.com/s?*
// @incluce https://www.baidu.com/#*
// @include https://www.baidu.com/baidu?*
// @exclude https://www.baidu.com/home*
// @exclude https://www.baidu.com/sf*
// @exclude https://www.baidu.com/search*
// @exclude https://www.baidu.com/link*
// @exclude https://www.baidu.com/s*tn=news*
// @resource baiduIndexStyle https://cdn.jsdelivr.net/gh/sinlin/[email protected]/2018-10-30/indexStyle.css
// @resource baiduCommonStyle https://cdn.jsdelivr.net/gh/sinlin/[email protected]/2018-10-30/commonStyle.css
// @resource baiduMenu https://cdn.jsdelivr.net/gh/sinlin/[email protected]/2018-10-30/menu.css
// @resource baiduOne https://cdn.jsdelivr.net/gh/sinlin/[email protected]/2018-10-30/one.css
// @resource baiduTwo https://cdn.jsdelivr.net/gh/sinlin/[email protected]/2018-10-30/two.css
// @resource baiduThree https://cdn.jsdelivr.net/gh/sinlin/[email protected]/2018-10-30/three.css
// @connect *
// @grant GM_addStyle
// @grant GM_getResourceText
// @grant GM_getResourceURL
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @grant GM_xmlhttpRequest
// ==/UserScript==
(() => {
//初始化配置
const Config = {
//是否调试
IS_DEBUG: false,
//壁纸地址
BACKGROUND_URL: "https://ss2.bdstatic.com/lfoZeXSm1A5BphGlnYG/skin/37.jpg",
//菜单按钮 ID
MENU_BUTTON_ID: "CustomMenu",
//菜单功能页 ID
MENU_PAGE_ID: "menulist",
//菜单保存按钮 ID
MENU_SAVA_ID: "menusava",
//功能配置
OPTIONS: [
//页面布局:1:普通页面,2:单列居中,3:双列居中,4:三列居中
{ name: "SELECT_PAGE", value: 1 },
//重定向
{ name: "SWITCH_IS_REDIRECT", value: false },
//加载下一页
{ name: "SWITCH_IS_LOADPAGE", value: false },
//固定侧边栏
{ name: "SWITCH_IS_FIXEDSILDER", value: false },
//加载背景
{ name: "SWITCH_IS_BACKGOUND", value: false }
],
//百度样式
BAIDU_STYLES: [
{
//百度首页
INDEX: GM_getResourceText("baiduIndexStyle"),
//普通页
COMMON: GM_getResourceText("baiduCommonStyle"),
//菜单
MENU: GM_getResourceText("baiduMenu"),
//单页
ONE: GM_getResourceText("baiduOne"),
//双页
TWO: GM_getResourceText("baiduTwo"),
//三页
THREE: GM_getResourceText("baiduThree")
}
],
//过滤功能 ,不能设置 G(已被 Google搜索 占用)
FILTERS: [
{
name: "B",
value: "-baijiahao"
},
{
name: "C",
value: "site:bbs.csdn.net"
},
{
name: "T",
value: "site:tieba.baidu.com"
},
{
name: "J",
value: "site:juejin.im"
},
{
name: "S",
value: "site:segmentfault.com"
},
{
name: "V",
value: "site:v2ex.com"
},
{
name: "Z",
value: "site:zhihu.com"
}
]
};
//打包
const BaiduConfig = { window, document, location, Config };
//Baidu
const Baidu = (({ window, document, location, Config }) => {
//创建空对象
const Baidu = Object.create(null);
const Options = Object.create(null);
//引用
const BAIDU_STYLES = Config.BAIDU_STYLES[0];
const BAIDU_OPTIONS = Config.OPTIONS;
//菜单功能页选项
Options.SELECT_PAGE = BAIDU_OPTIONS[0];
Options.SWITCH_IS_REDIRECT = BAIDU_OPTIONS[1];
Options.SWITCH_IS_LOADPAGE = BAIDU_OPTIONS[2];
Options.SWITCH_IS_FIXEDSILDER = BAIDU_OPTIONS[3];
Options.SWITCH_IS_BACKGOUND = BAIDU_OPTIONS[4];
/**
* 实现 ready 功能, 文档完成后即执行
* 举例 : Baidu.ready = function(){}
*/
Reflect.defineProperty(Baidu, "ready", {
set: fn => {
if (document.readyState === "complete") {
fn();
}
else if (!!document.addEventListener) {
document.addEventListener("DOMContentLoaded", () => {
fn();
}, true);
}
else {
throw new Error("Baidu.ready can't use");
}
}
});
/**
* 延时执行
*/
Baidu.delayRun = (callback, count = 0) => {
if (count === 0) {
window.requestAnimationFrame(() => {
callback();
});
}
else {
window.requestAnimationFrame(() => {
Baidu.delayRun(callback, --count);
});
}
};
/**
* DOM缓存
*/
class DomCache {
constructor() {
this.cache = {};
}
hasDomCache(name) {
return this.cache.hasOwnProperty(name) && !!this.cache[name]
? true
: false;
}
deleteCache() {
this.cache = {};
}
getElementById(name) {
if (!this.hasDomCache(name)) {
this.cache[name] = document.getElementById(name);
}
return this.cache[name];
}
}
Baidu.DOM = new DomCache();
/**
* GM数据类
* @class GM
*/
let GM = class {
static getValue(selection) {
try {
return GM_getValue(selection.name, selection.value);
}
catch (error) {
throw new Error(error);
}
}
static setValue(name, value) {
try {
GM_setValue(name, value);
}
catch (error) {
throw new Error(error);
}
}
static addStyle(style) {
try {
GM_addStyle(style);
}
catch (error) {
throw new Error(error);
}
}
static xmlhttpRequest(object) {
try {
GM_xmlhttpRequest(object);
}
catch (error) {
throw new Error(error);
}
}
};
/**
* 减少执行
*/
class ReduceExecute {
constructor() {
this.isNormalExecuteState = true;
}
/**
* 是否正常执行
*/
isNormalExecute() {
return this.isNormalExecuteState;
}
/**
* 停止正常执行
*/
stopNormalExecute() {
this.isNormalExecuteState = false;
return this;
}
/**
* 恢复正常执行
* @param time 时间片 1 = 16.7ms
*/
regainNormalExecute(time) {
Baidu.delayRun(() => {
this.isNormalExecuteState = true;
}, time);
}
}
/**
* 缓存类
* 用于对数据的缓存
* @class Cache
*
*/
class Cache {
constructor() {
this.cache = "";
}
/**
* 删除缓存
*/
delCache() {
this.cache = "";
}
/**
* 添加缓存
* @param Content {string} 缓存内容
*/
addCache(Content) {
this.cache += Content;
}
/**
* 获取缓存内容
*/
getCache() {
return this.cache;
}
}
/**
* 样式
* @class Style
* @extends Cache
*
*/
class Style {
constructor() {
this.Cache = new Cache();
this.GM = GM;
}
/**
* 导入样式
* @method importStyle
*
*/
importStyle() {
let styles = this.Cache.getCache();
try {
this.GM.addStyle(styles);
}
catch (error) {
throw new Error("can't import styles:" + error);
}
}
/**
* 将样式加入缓存
* @param {stirng} style 样式
* @return {Style} this 该实例
*/
add(style) {
this.Cache.addCache(style);
return this;
}
/**
* 结束
* 开始将缓存样式导入,并清空缓存
*/
end() {
this.importStyle();
this.Cache.delCache();
}
}
/**
* 函数执行器 - 组合执行
*/
class Commond {
constructor() {
this.commondList = [];
}
/**
* 添加数组缓存中
* @param {object} command 对象实例
*/
add(command) {
this.commondList.push(command);
}
/**
* 执行数值缓存中的实例
* 如果执行实例返回 true 停止执行。
*/
execute(isSplitExecute = false) {
for (let i = 0, command; (command = this.commondList[i++]);) {
command.execute();
}
}
}
/**
* 检测功能 - 避免代码多次执行
* @class AvoidMulExecute
*/
class AvoidMulExecute {
constructor() {
//标志名称
this.signName = "isRun";
}
/**
* 增加标志位
*/
setSign() {
let signName = this.signName;
let container = document.getElementById("content_left");
container.setAttribute(signName, true);
}
/**
* 判断是否存在标志位
*/
hasSign() {
let signName = this.signName;
let container = document.getElementById("content_left");
return !!container.hasAttribute(signName);
}
}
/**
* 重定向搜索地址
* @class RedirectURL
*/
class RedirectURL {
constructor() {
this.end = "&baidu";
}
/**
* 重定向地址
* @method redirectURL
*/
redirectURL() {
let end = this.end;
let URL = location.href;
if (!URL.endsWith(end)) {
//判断是否存在步进值,没有使用默认值 20
if (!URL.includes("&rn=")) {
URL += "&rn=20";
}
//拼接地址
URL += end;
//去除推广链接
URL = URL.replace(/\&tn=\S+\&/, "&");
//跳转
location.href = URL;
}
}
/**
* 初始化
* @method init
*/
init() {
this.redirectURL();
}
/**
* 启动
* @method execute
*/
execute() {
this.init();
}
}
/**
* 首页样式
* @class IMportIndexStyle
*/
class ImportIndexStyle {
constructor() {
//实例化
this.Style = new Style();
}
/**
* 导入样式
* @method import
*/
import() {
let style = this.Style;
style.add(BAIDU_STYLES.INDEX);
style.end();
}
/**
* 初始化
* @method init
*/
init() {
this.import();
}
/**
* 执行
* @method execute
*/
execute() {
this.init();
}
}
/**
* 导入普通结果页样式
* @class ImportCommonStyle
*/
class ImportCommonStyle {
constructor() {
//实例化
this.Style = new Style();
this.GM = GM;
//功能选项
this.Options = Options;
//背景地址
this.backgoundURL = Config.BACKGROUND_URL;
//布局类型
this.layoutType = Number(this.GM.getValue(this.Options.SELECT_PAGE));
//是否导入背景
this.isImportBackground = Boolean(this.GM.getValue(this.Options.SWITCH_IS_BACKGOUND));
//是否导入样式
this.isImportFixedSlider = Boolean(this.GM.getValue(this.Options.SWITCH_IS_FIXEDSILDER));
}
/**
* 样式 - 背景
* @method styleForBackground
* @returns {string} 样式
*/
styleForBackground() {
let defaultURL = this.backgoundURL;
if (this.isImportBackground) {
return `body{background-color:transparent!important}body:after{content:"";position:fixed;top:0;bottom:0;left:0;right:0;background-image:url(${defaultURL})!important;background-size:cover!important;z-index:-1}#head{background-color:hsla(0, 0%, 100%, 0.65)!important;border-bottom-color:hsla(0, 0%, 52%, 0.3)!important}#content_left .c-container,#rs{border:none!important;background: hsla(0, 0%, 100%, 0.85)!important}#form>.s_ipt_wr.bg{background:#fff!important}#u>a{color: hsl(216, 80%, 63%)!important}#u>a:after{background:transparent!important;border:1px solid!important;}`;
}
else {
return "";
}
}
/**
* 样式 - 固定侧边栏
* @method styleForFixedSilder
* @returns {string} 样式
*/
styleForFixedSilder() {
if (this.isImportFixedSlider) {
return "#s_tab{left:0!important;opacity:1!important;}";
}
else {
return "";
}
}
/**
* 样式 - 页面布局
* @method styleForPageLayout
* @returns {string} 样式
*/
styleForPageLayout() {
let layoutType = this.layoutType;
switch (layoutType) {
case 1:
return "";
case 2:
return BAIDU_STYLES.ONE;
case 3:
return BAIDU_STYLES.TWO;
case 4:
return BAIDU_STYLES.THREE;
}
}
/**
* 样式 - 菜单
* @method styleForMenu
* @returns {string} 样式
*/
styleForMenu() {
return BAIDU_STYLES.MENU;
}
/**
* 样式 - 结果页
* @method styleForCommand
* @returns {string} 样式
*/
styleForCommand() {
return BAIDU_STYLES.COMMON;
}
/**
* 导入样式
* @method import
*/
import() {
let style = this.Style;
style.add(this.styleForCommand());
style.add(this.styleForMenu());
style.add(this.styleForPageLayout());
style.add(this.styleForFixedSilder());
style.add(this.styleForBackground());
style.end();
}
/**
* 初始化
* @method init
*/
init() {
this.import();
}
/**
* 执行
* @method execute
*/
execute() {
this.init();
}
}
/**
* 菜单功能页
* @class MenuItemsOptions
* @extends MenuCommand
*/
class MenuItemsOptions {
constructor() {
this.GM = GM;
this.Options = Options;
this.layoutTagName = "baidupage";
this.switchTagName = "baiduswitch";
//页面布局类型
this.layoutType = Number(this.GM.getValue(this.Options.SELECT_PAGE));
}
/**
* 获得 HTML - 页面布局选项
* @param content 显示的内容
* @param layoutType 页面布局类型
*/
getContentPageSelect(content, layoutType) {
let checked = this.layoutType === layoutType ? "checked" : "";
return `<li><input type="radio" name="${this.layoutTagName}" value="${layoutType}" ${checked}>${content}</li>`;
}
/**
* 获得 HTML - 功能选项选项
* @param content 显示的内容
* @param selection 功能配置
*/
getContentFunSelect(content, selection) {
let switchName = selection.name;
let checked = Boolean(this.GM.getValue(selection))
? "checked"
: "";
return `<li><input type="checkbox" name="${this.switchTagName}" value="${switchName}" ${checked}>${content}</li>`;
}
/**
* 获得 HTML - 保存
* @param content 显示的内容
*/
getContentSava(content) {
let idName = Config.MENU_SAVA_ID;
return `<input id='${idName}' type='button' style='display:block;width:100%' value='${content}'>`;
}
//获取整体 HTML
getContent() {
let content = "";
content += "<ol>页面选择";
content += this.getContentPageSelect("普通页面", 1);
content += this.getContentPageSelect("单页居中", 2);
content += this.getContentPageSelect("双页居中", 3);
content += this.getContentPageSelect("三页居中", 4);
content += "</ol>";
content += "<ol>功能选择";
content += this.getContentFunSelect("使用重定向", this.Options.SWITCH_IS_REDIRECT);
content += this.getContentFunSelect("自动下一页", this.Options.SWITCH_IS_LOADPAGE);
content += this.getContentFunSelect("固定侧边栏", this.Options.SWITCH_IS_FIXEDSILDER);
content += this.getContentFunSelect("加载背景", this.Options.SWITCH_IS_BACKGOUND);
content += "</ol>";
content += this.getContentSava("保存");
return content;
}
/**
* 绑定保存事件
*/
bindSavaClick() {
let sava = document.getElementById(Config.MENU_SAVA_ID);
sava.onclick = event => {
let e = event || window.event;
//页面布局选项
let radios = document.getElementsByName(this.layoutTagName);
for (let i = 0, radio; (radio = radios[i++]);) {
if (radio.checked) {
let name = Options.SELECT_PAGE.name;
let value = radio.value;
this.GM.setValue(name, value);
break;
}
}
//功能选项
let checkboxs = document.getElementsByName(this.switchTagName);
for (let i = 0, checkbox; (checkbox = checkboxs[i++]);) {
let name = checkbox.value;
if (checkbox.checked) {
this.GM.setValue(name, true);
}
else {
this.GM.setValue(name, false);
}
}
e.stopPropagation();
location.href = location.href;
};
}
/**
* 插入节点
*/
insertNode() {
let container = document.getElementById("u"), content = this.getContent(), div = document.createElement("div");
div.id = Config.MENU_PAGE_ID;
div.style.display = "none";
div.innerHTML = `<div>${content}</div>`;
container.insertBefore(div, container.firstChild);
}
/**
* 初始化
*/
init() {
let isExecute = document.getElementById(Config.MENU_PAGE_ID);
if (!isExecute) {
this.insertNode();
//异步执行绑定事件
Baidu.delayRun(() => {
this.bindSavaClick();
}, 10);
}
}
/**
* 执行
*/
execute() {
Baidu.ready = () => {
try {
this.init();
}
catch (e) {
throw new Error(e);
}
};
}
}
/**
* 菜单按钮
* @class MenuButton
* @extends MenuCommand
*/
class MenuButton {
constructor() {
this.MenuItemsOptions = new MenuItemsOptions();
}
/**
* 修复未登录按钮错位问题
*/
fixedNoLoginButtonPosition() {
let container = document.getElementById("u");
let isExecute = container.querySelector("#u>a[name='tj_login']");
if (isExecute) {
let selector = document.getElementById(Config.MENU_BUTTON_ID);
selector.setAttribute("style", "top:-4px!important");
}
}
/**
* 第二次单击隐藏
*/
bindClickHide() {
document.onclick = event => {
let e = event || window.event;
let container = document.getElementById("container");
let items = document.getElementById(Config.MENU_PAGE_ID);
let isScreenClick = e.target
? e.target == container
: e.srcElement == container;
if (isScreenClick) {
items.style.display = "none";
}
};
}
/**
* 单击打开功能选项页
*/
bindClick() {
let container = document.getElementById(Config.MENU_BUTTON_ID);
container.onclick = event => {
let e = event || window.event;
let items = document.getElementById(Config.MENU_PAGE_ID);
let style = items.style;
let isShow = style.display === "block";
if (isShow) {
style.display = "none";
}
else {
style.display = "block";
}
//阻止冒泡
e.stopPropagation();
};
}
/**
* 插入节点
*/
insertNode() {
let container = document.getElementById("u");
let div = document.createElement("a");
div.id = Config.MENU_BUTTON_ID;
div.innerHTML = "自定义";
container.insertBefore(div, container.firstChild);
}
/**
* 初始化
*/
init() {
let isExecute = document.getElementById(Config.MENU_BUTTON_ID);
if (!isExecute) {
this.insertNode();
//异步绑定事件
Baidu.delayRun(() => {
this.bindClick();
this.bindClickHide();
}, 10);
}
}
/**
* 执行
*/
execute() {
Baidu.ready = () => {
Promise.resolve().then(() => {
this.init();
});
};
//执行菜单功能面板
Promise.resolve().then(() => {
this.MenuItemsOptions.execute();
});
}
}
/**
* 多页布局
* @class MUlPageLayout
*/
class MulPageLayout {
constructor() {
this.GM = GM;
this.DOM = Baidu.DOM;
this.container = null;
this.lists = null;
//多列布局值集合
this.layoutTypes = [3, 4];
//当前布局类型
this.layoutType = Number(this.GM.getValue(Options.SELECT_PAGE));
//根据 类名 模拟高度
this.VIRTUAL_HEIGHTS_BY_CLASSNAE = [
{ name: ".c-container>.op-b2b-straight", value: 420 },
{ name: ".c-container>.c-offset", value: 320 },
{ name: ".c-container>.c-border", value: 270 },
{
name: ".c-container>.op-tieba-general-lookmore",
value: 260
},
{
name: ".c-container>.op-img-address-desktop-cont",
value: 210
},
{ name: ".c-container>.c-gap-top-small", value: 130 }
];
//根据 srcid 属性值 模拟高度
this.VIRTUAL_HEIGHTS_BY_SRCID = [
{ name: 1599, value: 128 },
{ name: 1508, value: 170 },
{ name: 1527, value: 170 },
{ name: 1528, value: 220 },
{ name: 1529, value: 220 },
{ name: 1537, value: 510 },
{ name: 1539, value: 280 },
{ name: 1545, value: 230 },
{ name: 1547, value: 230 },
{ name: 4515, value: 540 },
{ name: 5103, value: 400 },
{ name: 8041, value: 260 },
{ name: 8191, value: 200 },
{ name: 10, value: 260 },
{ name: 13, value: 220 },
{ name: 19, value: 200 }
];
}
/**
* 是否为多列布局
* @return {boolean}
*/
isMulLayout() {
let layoutType = this.layoutType;
let layoutTypes = this.layoutTypes;
return layoutTypes.includes(layoutType);
}
/**
* 初始化
*/
resetDOM() {
this.container = null;
this.lists = null;
}
/**
* 获取 #content_left 节点
*/
getDomForContainer() {
if (!this.container) {
this.container = this.DOM.getElementById("content_left");
}
return this.container;
}
/**
* 获取 list 节点
*/
getDomForLists() {
if (!this.lists) {
let container = this.getDomForContainer();
this.lists = container.getElementsByClassName("list");
}
return this.lists;
}
//获取list高度合集
getListsHeight() {
let lists = this.getDomForLists();
let heights = [];
for (let i = 0, list; (list = lists[i++]);) {
heights.push(list.clientHeight);
}
return heights;
}
/**
* 模拟高度
* 防止获取真实高度导致性能问题
* @param item
*/
getItemVirtualHeight(item) {
// 获取虚拟高度合集
let VIRTUAL_DATAS = this.VIRTUAL_HEIGHTS_BY_SRCID;
//默认高度
let height = 122;
//匹配 srcid 正则
let reg = /srcid="\d+"/;
//获取srcid
let srcid = Number(/\d+/.exec(reg.exec(item.outerHTML)));
//根据srcid值获取虚拟高度
for (let i = 0, data; (data = VIRTUAL_DATAS[i++]);) {
//大于 10000 直接赋予新高度
if (srcid > 10000) {
height = 310;
break;
}
else if (srcid === data["name"]) {
height = data["value"];
break;
}
}
return height;
}
/**
* 01 - 添加内容到lists
* 使用 DOM 到 DOM, 即将 #content_left 下的子元素移动到 lists
* 注意:需要提前将 DOM片段 添加到 #content_left下
*/
addWebUseDomToDom() {
let container = this.getDomForContainer();
let lists = this.getDomForLists();
let items = container.querySelectorAll("#content_left>.c-container");
let heights = this.getListsHeight();
let frames = [];
//初始化
for (let i = 0, length = lists.length; i < length; i++) {
//缓存
frames.push(document.createDocumentFragment());
}
//将 item 添加到虚拟DOM中
for (let i = 0, item; (item = items[i++]);) {
//获取最小的高度值
let minHeight = Reflect.apply(Math.min, null, heights);
//获取最小的高度的索引值
let index = heights.indexOf(minHeight);
//添加到高度
heights[index] += item.clientHeight;
//缓存
frames[index].appendChild(item);
}
//添加到真实DOM
for (let i = 0, length = lists.length; i < length; i++) {
Baidu.delayRun(() => {
lists[i].appendChild(frames[i]);
}, i);
}
}
/**
* 02 - 添加内容到lists
*
*
* @param frame DOM片段
*/
addWebUseFrameToDom(frame) {
//获取lists
let lists = this.getDomForLists();
//获取列表合集
let items = frame.getElementsByClassName("c-container");
//获取初始化高度集合
let heights = this.getListsHeight();
//将 item 添加到list中
for (let i = 0, item; (item = items[i]);) {
//获取高度合集
//获取最小的高度值
let minHeight = Reflect.apply(Math.min, null, heights);
//获取最小的高度的索引值
let index = heights.indexOf(minHeight);
//添加到list中
lists[index].appendChild(item);
//更新高度
heights = this.getListsHeight();
}
}
/**
* 03 - 添加内容到 lists
* 使用"模拟高度"进行添加
*
* @param frame DOM片段
*/
addWebUseVirtualToDom(frame) {
let lists = this.getDomForLists();
let frames = [];
//获取列表合集
let items = frame.getElementsByClassName("c-container");
if (items.length <= 0) {
return;
}
//获取初始化高度集合
let heights = this.getListsHeight();
//初始化
for (let i = 0, length = lists.length; i < length; i++) {
frames[i] = document.createDocumentFragment();
}
//将 item 添加到list中
for (let i = 0, item; (item = items[i]);) {
//获取最小的高度值
let minHeight = Reflect.apply(Math.min, null, heights);
//获取最小的高度的索引值
let index = heights.indexOf(minHeight);
//获取模拟高度
heights[index] += this.getItemVirtualHeight(item);
//添加到list中
frames[index].appendChild(item);
}
Baidu.delayRun(() => {
//插入内容到list
for (let i = 0, length = lists.length; i < length; i++) {
lists[i].appendChild(frames[i]);
}
}, 1);
}
/**
* 是否存在list节点
*/
hasListNode() {
let lists = this.getDomForLists();
return lists.length > 0;
}
/**
* 向网页添加列表
*/
insertListNode() {
let layoutType = this.layoutType;
let container = this.getDomForContainer();
let frame = document.createDocumentFragment();
//创建list节点
for (let i = 1, div, length = layoutType; i < length; i++) {
div = document.createElement("div");
div.id = "list" + i;
div.className = "list";
frame.appendChild(div);
}
//将节点插入到文档中
container.insertBefore(frame, container.firstChild);
return this;
}
/**
* 添加内容到 lists
*/
addListContent(frame) {
this.resetDOM();
Baidu.delayRun(() => {
this.addWebUseVirtualToDom(frame);
}, 0);
}
/**
* 初始化
*/
init() {
try {
this.resetDOM();
if (!this.hasListNode()) {
//插入list节点并刷新节点
this.insertListNode();
}
this.addWebUseDomToDom();
}
catch (error) {
console.error(error);
}
}
/**
* 执行
*/
execute() {
if (this.isMulLayout()) {
Baidu.ready = () => {
this.init();
};
}
}
}
/**
* 自动加载下一页
* @class AutoLoadNextPage
*/
class AutoLoadNextPage {
/**
* 构造函数
*/
constructor() {
//赋值
this.GM = GM;
//DOM
this.DOM = Baidu.DOM;
//实例化 - 多页布局
this.MulpageLayout = new MulPageLayout();
//实例化 - 重定向
this.Redirect = new Redirect();
//实例化 -
this.Parser = new DOMParser();
//减少频率
this.Reduce = new ReduceExecute();
this.isExecute = Boolean(this.GM.getValue(Options.SWITCH_IS_LOADPAGE));
}
/**
* 重置
*/
reset() {
//是否第一次执行
this.isFirstRun = true;
//是否导入过
(this.isImport = false),
//下一页真实地址
(this.realNextURL = null);
//模板地址
this.templateURL = null;
//步进值(默认值)
this.step = 0;
//每页起始值
this.count = 0;
//偏移高度
this.offsetHight = 1000;
//缓存
this.cache = [];
//缓存量
this.cacheSize = 1;
//节点缓存
this.container = this.DOM.getElementById("content_left");
}
/**
* 获取真实下一个的地址
* @returns {string} 下一页地址
*/
getNextPageRealURL() {
if (!this.realNextURL) {
let page = document.getElementById("page");
this.realNextURL = page
.getElementsByClassName("n")[0]
.getAttribute("href");
}
return this.realNextURL;
}
/**
* 获取步进值
* @returns {number} 步进值
*/
getNextPageStepValue() {
if (!this.step) {
//提取 &pn=20 中的20
let regParam = /(&pn=\d+)/;
let regValue = /\d+/;
let result = regParam.exec(this.getNextPageRealURL());
this.step = Number(regValue.exec(result));
}
return this.step;
}
/**
* 获取模板地址
* @returns {string} this.templateURL: 模板地址
*/
getTempletURL() {
this.templateURL =
this.templateURL ||
this.getNextPageRealURL().replace(/&pn=\d+/, "");
return this.templateURL;
}
/**
* 获取下一页合成地址
* @returns {sting} 下一页的地址
*/
getNextPageComposeURL() {
this.count += this.getNextPageStepValue();
return this.getTempletURL() + `&pn=${this.count}`;
}
/**
* 判断是否存在缓存
* @returns {boolean} 存在: true
* @returns {boolean} 不存在:false
*/
hasCache() {
return this.cache.length >= this.cacheSize;
}
/**
* 将响应文本添加到缓存中
* @param responseText 响应文本
*/
addCache(responseText) {
//转化为DOM对象
let reg = /<body[\s\S.]+<\/body>/;
let parser = this.Parser;
let htmlDoc = parser.parseFromString(reg.exec(responseText)[0], "text/html");
//获取Items
let items = htmlDoc
.getElementById("content_left")
.getElementsByClassName("c-container");
//添加到缓存
let frame = document.createElement("div");
//appendchild 自动执行迭代器 导致 i++ (小心);
for (let i = 0, item; (item = items[i]);) {
frame.appendChild(item);
}
//加入缓存
this.cache.push(frame);
}
/**
* 监测滚动位置
*/
checkScrollPosition() {
if (this.Reduce.isNormalExecute()) {
this.Reduce.stopNormalExecute().regainNormalExecute(5);
let element = document.documentElement, clientHeight = element.clientHeight, scrollTop = element.scrollTop ||
window.pageYOffset ||
document.body.scrollTop ||
0, scrollHeight = Number(element.scrollHeight);
//判断
if (clientHeight + scrollTop + this.offsetHight >
scrollHeight) {
this.removeScrollEvent();
this.task();
}
}
}
/**
* 移除滚动事件
*/
removeScrollEvent() {
document.onscroll = event => {
let e = event || window.event;
e.preventDefault();
};
return this;
}
/**
* 绑定滚动触发事件
*/
bindScrollEvent() {
document.onscroll = () => {
this.checkScrollPosition();
};
}
/**
* 将 DOM 插入到相应的位置
*/
addItemsToWeb() {
//插入内容到DOM节点
if (this.MulpageLayout.isMulLayout()) {
this.MulpageLayout.addListContent(this.cache.shift());
}
else {
this.container.innerHTML += this.cache.shift().innerHTML;
}
}
/**
* 发送请求
*/
requireNextPageContent() {
this.GM.xmlhttpRequest({
method: "GET",
url: this.getNextPageComposeURL(),
timeout: 3000,
responseType: "text",
onload: response => {
if (response.status === 200 ||
response.status === 304) {
//如果不存在缓存,再发一次
if (!this.hasCache()) {
this.requireNextPageContent();
}
//添加响应文本到缓存
this.addCache(response.responseText);
//开始导入数据到网页
if (!this.isImport) {
this.import();
}
}
},
onerror: response => {
console.error(response);
}
});
}
/**
* 导入数据到网页
*/
import() {
this.isImport = true;
//添加内容到网页
this.addItemsToWeb();
//重定向
this.Redirect.execute();
//绑定滚动事件
Baidu.delayRun(() => {
this.removeScrollEvent().bindScrollEvent();
}, 3);
}
/**
* 任务调度
* @param URL
*/
task() {
//设置有导入过
this.isImport = false;
//发送请求
this.requireNextPageContent(); //如果有缓存
//如果存在缓存
if (this.hasCache()) {
this.import();
}
}
/**
* 隐藏元素
*/
hideElement() {
let page = document.getElementById("page");
page.style.visibility = "hidden";
}
/**
* 初始化
*/
init() {
//重置配置
this.reset();
//开始加载
this.task();
//隐藏元素
Baidu.delayRun(() => {
this.hideElement();
}, 3);
}
/**
* 入口
* @returns {void}
*/
execute() {
if (this.isExecute) {
Baidu.ready = () => {
this.init();
};
}
}
}
/**
* 重定向
* @class Redirect
*/
class Redirect {
constructor() {
this.GM = GM;
this.DOM = Baidu.DOM;
//重定向后需添加类名(防止重复重定向)
this.redirectClassName = "isredirect";
//是否执行
this.isExecute = Boolean(this.GM.getValue(Options.SWITCH_IS_REDIRECT));
}
/**
* 重定向
* @param item a节点
*/
redirect(item) {
this.GM.xmlhttpRequest({
method: "HEAD",
url: item.href,
onload: response => {
let realURL = response.finalUrl;
item.href = realURL;
//加入重定向标志
item.className = this.redirectClassName;
//移除不必要的属性
item.removeAttribute("data-click");
}
});
}
/**
* 开始
*/
start() {
let container = this.DOM.getElementById("content_left");
let items = container.querySelectorAll("h3>a:not([class])");
for (let i = 0, item; (item = items[i++]);) {
//延时执行
Baidu.delayRun(() => {
this.redirect(item);
}, i);
}
}
/**
* 初始化
*/
init() {
this.start();
}
/**
* 执行
*/
execute() {
if (this.isExecute) {
Baidu.ready = () => {
Baidu.delayRun(() => {
this.init();
}, 5);
};
}
}
}
/**
* 回到顶部
* @class BackToTop
*/
class BackToTop {
/**
* 单击回到顶部
*/
bindClick() {
let container = document.getElementsByClassName("s_form")[0];
container.onclick = event => {
let e = event || window.event;
let isContainer = e.target
? e.target === container
: e.srcElement === container;
if (isContainer) {
//setInterval方案
let element = document.documentElement;
let body = document.body;
let node = element.scrollTop ? element : body;
let top = node.scrollTop;
let step = top / 20;
let timer = setInterval(() => {
if (node.scrollTop <= 0) {
node.scrollTop = 0;
clearInterval(timer);
}
node.scrollTop -= step;
}, 10);
e.stopPropagation();
}
};
}
/**
* 初始化
*/
init() {
this.bindClick();
}
/**
* 执行
*/
execute() {
Baidu.ready = () => {
Promise.resolve().then(() => {
Baidu.delayRun(() => {
this.init();
}, 10);
});
};
}
}
/**
* 谷歌
* 双击使用 google 搜索
* @class Google
*/
class Google {
googleSearch() {
let googlePath = "https://www.google.com/search?q=";
let searchContent = document.getElementById("kw").value.trim();
let url = googlePath + encodeURIComponent(searchContent);
window.open(url);
}
/**
* 绑定双击打开Google搜索
*/
bindDoubleClick() {
let button = document.getElementById("su");
button.ondblclick = () => {
this.googleSearch();
};
}
/**
* 初始化
*/
init() {
this.bindDoubleClick();
}
/**
* 执行
*/
execute() {
Baidu.ready = () => {
Promise.resolve().then(() => {
this.init();
});
};
}
}
/**
* 替换首页搜索栏
* @class ReplaceSearch
*/
class ReplaceSearch {
constructor() {
this.inputId = "baiduinput";
this.searchPath = "https://www.baidu.com/s?ie=UTF-8&wd=";
}
/**
* 搜索
*/
search() {
let value = document.getElementById(this.inputId).value.trim();
if (value !== "") {
location.href = this.searchPath + encodeURIComponent(value);
}
}
/**
* 绑定提交事件
*/
bindSubmit() {
let button = document.getElementById("su");
button.setAttribute("type", "button");
button.onclick = event => {
let e = event || window.event;
this.search();
e.stopPropagation();
};
}
/**
* 检测输入
*/
bindKeydown() {
let input = document.getElementById(this.inputId);
input = document.getElementById("form");
input.onkeydown = event => {
let e = event || window.event;
let keyCode = e.keyCode || e.which || e.charCode;
if (keyCode === 13) {
this.search();
}
e.stopPropagation();
};
}
/**
* 插入节点
* 覆盖原来的搜索框
*/
insertNode() {
//屏蔽原来文本输入
document
.getElementById("kw")
.setAttribute("disabled", "disabled");
let container = document.getElementById("s_kw_wrap") ||
document.getElementsByClassName("s_ipt_wr")[0];
let div = document.createElement("input");
div.id = this.inputId;
div.type = "text";
div.autofocus = true;
div.autocomplete = "off";
container.appendChild(div);
//延时聚焦
Promise.resolve().then(() => {
document.getElementById(this.inputId).focus();
});
}
/**
* 初始化
*/
init() {
try {
this.insertNode();
Promise.resolve().then(() => {
this.bindSubmit();
this.bindKeydown();
});
}
catch (e) {
throw new Error(e);
}
}
/**
* 执行
*/
execute() {
Baidu.ready = () => {
this.init();
};
}
}
/**
* 执行广告和无用的节点
* @class RemoveNode
*/
class RemoveNode {
constructor() {
this.nodes = ["content_right", "content_bottom", "foot"];
this.style = "display:block !important";
}
/**
* 根据 ID 移除
*/
removeNodeForID() {
let items = this.nodes;
for (let i = 0, item; (item = items[i++]);) {
let node = document.getElementById(item);
node.parentNode.removeChild(node);
}
}
removeNodeForStyle() {
let container = document.getElementById("content_left");
let items = container.querySelectorAll(`#content_left>div[style*="${this.style}"]`);
for (let i = 0, item; (item = items[i++]);) {
item.parentNode.removeChild(item);
}
}
/**
*/
init() {
try {
this.removeNodeForID();
}
catch (error) { }
}
/**
* 执行
*/
execute() {
Baidu.ready = () => {
this.init();
};
}
}
/**
* 快捷键
* @class ShortcutKeys
*/
class ShortcutKeys {
constructor() {
this.Google = new Google();
this.filters = Config.FILTERS;
this.target = null;
this.KEY_ENTER = 13;
this.KEY_ALT = 18;
this.KEY_SHIFT = 16;
this.KEY_CTRL = 17;
this.KEY_GOOGLE = "G";
}
/**
* 过滤搜索
*/
filterSearch(filterName) {
//移除如 "-baijiahao" 正则
let reg1 = /\s\-\S+/;
//移除如 "site:baidu" 正则
let reg2 = /\ssite\:\S+/;
let URL = "https://www.baidu.com/s?ie=utf-8&wd=";
let content = document.getElementById("kw").value.trim();
content = content.replace(reg1, "").trim();
content = content.replace(reg2, "").trim();
location.href =
URL + encodeURIComponent(content) + " " + filterName;
}
/**
* 选择全部
*/
selectAllContent() {
let input = document.getElementById("kw");
input.focus();
input.selectionStart = 0;
input.selectionEnd = input.value.length;
}
/**
* 绑定快捷键
*/
bindKeys() {
let defaultTarget = this.target;
document.onkeyup = event => {
let e = event || window.event;
if (e.target === defaultTarget || e.target === document) {
let keyCode = e.keyCode || e.which || e.charCode;
//Ctrl + Enter 全选中
if (keyCode == this.KEY_ENTER && e.ctrlKey) {
this.selectAllContent();
return;
}
//谷歌搜索
if (keyCode ===
this.KEY_GOOGLE.toUpperCase().charCodeAt() && !e.altKey && !e.shiftKey && !e.ctrlKey && !e.metaKey) {
this.Google.googleSearch();
return;
}
//过滤搜索
for (let { name, value } of this.filters) {
if (keyCode === name.toUpperCase().charCodeAt() && !e.altKey && !e.shiftKey && !e.ctrlKey && !e.metaKey) {
this.filterSearch(value);
return;
}
}
}
e.stopPropagation();
};
}
/**
* 重置
*/
reset() {
this.target = document.getElementsByTagName("body")[0] || null;
}
/**
* 初始化
*/
init() {
try {
this.reset();
this.bindKeys();
}
catch (error) { }
}
/**
* 执行
*/
execute() {
Baidu.ready = () => {
this.init();
};
}
}
/**
* Base地址重置
*/
class BaseURL {
run() {
location.href = location.href.replace("https://www.baidu.com/#", "https://www.baidu.com/s?");
}
}
/**
* 首页
*/
class PageIndex {
run() {
//组合模式
let command = new Commond();
command.add(new ImportIndexStyle());
command.add(new ReplaceSearch());
command.execute();
}
}
/**
* 搜索结果页
*/
class PageCommon {
run() {
/**
* 01 - 初始化执行
*/
let command = new Commond();
command.add(new ImportCommonStyle());
command.add(new MenuButton());
command.add(new MulPageLayout());
command.add(new AutoLoadNextPage());
command.add(new Redirect());
command.add(new BackToTop());
command.add(new Google());
command.add(new ShortcutKeys());
command.execute();
/**
* 02 - 设置标志位
* 防止后期多次无用执行
*/
let avoidMulExecute = new AvoidMulExecute();
//设置标志位
Baidu.ready = () => {
avoidMulExecute.setSign();
};
/**
* 03 - 监测 DOM
*/
//调用函数
let mutationfunc = () => {
//只执行一次
if (!avoidMulExecute.hasSign()) {
//设置标志位
avoidMulExecute.setSign();
//清除缓存
Baidu.DOM.deleteCache();
//执行
command.execute();
}
};
//加载完成后 - 根据 DOM 变化重新执行函数( 防止Bash值改变时不触发脚本)
window.onload = () => {
let MutationObserver = window.MutationObserver ||
window.WebKitMutationObserver ||
window.MozMutationObserver;
if (!!MutationObserver) {
let observer = new MutationObserver(mutationfunc);
let wrapper = document.querySelector("#wrapper");
let observerConfig = {
childList: true,
subtree: true
//"attributes": true,
//"characterData":true,
//"attributesFilter": ["class"],
};
//开始观察
observer.observe(wrapper, observerConfig);
}
else {
console.error("百度搜索-优化: 浏览器不兼容 MutationObserver 接口, 请升级浏览器版本");
}
};
}
}
/**
* 简单工厂
*/
class Factory {
/**
*
* @param url
*/
static create(url) {
//BASE地址(BASE地址会导致样式跳转,需要重定向)
const URL_BASE = "https://www.baidu.com/#";
//普通页 01
const URL_COMMON_01 = "https://www.baidu.com/s";
//普通页 02
const URL_COMMON_02 = "https://www.baidu.com/baidu";
//首页
const URL_INDEX = "https://www.baidu.com";
//返回BASE
if (url.startsWith(URL_BASE)) {
return new BaseURL();
}
//返回结果页
if (url.startsWith(URL_COMMON_01)) {
return new PageCommon();
}
//返回结果页
if (url.startsWith(URL_COMMON_02)) {
return new PageCommon();
}
//返回首页
if (url.startsWith(URL_INDEX)) {
return new PageIndex();
}
}
}
/**
* 启动函数
*/
Baidu.start = () => {
Factory.create(location.href).run();
};
//返回对象
return Baidu;
})(BaiduConfig);
//启动
try {
Baidu.start();
}
catch (msg) {
if (Config.IS_DEBUG) {
console.error(msg);
}
}
})();