- // ==UserScript==
- // @name 聚合搜索V4
- // @namespace http://tampermonkey.net/
- // @version 1.0.0
- // @description 整合百度、F搜、Google、微信、Bing、知乎、知网空间搜索,提高搜索效率,可以自由添加和删除搜索引擎
- // @author Liao Brant
- // @match *://*/*
- // @grant unsafeWindow
- // @grant window.onload
- // @grant GM_registerMenuCommand
- // @grant GM_getValue
- // @grant GM_setValue
- // @run-at document-body
-
- // @license MIT
- // ==/UserScript==
-
- const defaultUrlMap = [
- {
- name: '百度',
- searchUrl: 'https://www.baidu.com/s?wd=%s',
- keyName: 'wd',
- },
- {
- name: 'F搜',
- searchUrl: 'https://fsoufsou.com/search?q=%s',
- keyName: 'q',
- },
- {
- name: 'Google',
- searchUrl: 'https://www.google.com/search?q=%s',
- keyName: 'q',
- },
- {
- name: '开发者',
- searchUrl: 'https://kaifa.baidu.com/searchPage?wd=%s&module=SEARCH',
- keyName: 'wd',
- },
- {
- name: '微信文章',
- searchUrl: 'https://weixin.sogou.com/weixin?type=2&s_from=input&query=%s',
- keyName: 'query',
- },
- {
- name: 'Bing',
- searchUrl: 'https://www.bing.com/search?ensearch=0&q=%s',
- keyName: 'q',
- },
- {
- name: '知乎',
- searchUrl: 'https://www.zhihu.com/search?type=content&q=%s',
- keyName: 'q',
- },
- {
- name: '知网空间',
- searchUrl: 'https://search.cnki.com.cn/Search/Result?content=%s',
- keyName: 'q',
- },
- ];
-
- // 获取搜索配置
- function getSearchConfig() {
- const urlConfig = GM_getValue('SearchList');
- if (!urlConfig || !urlConfig.length) {
- // 默认的网址配置
- GM_setValue('SearchList', defaultUrlMap);
- return defaultUrlMap;
- } else {
- return urlConfig;
- }
- }
-
- // 搜索网址配置
- let urlMapping = getSearchConfig();
-
- // JS获取url参数
- function getQueryVariable(variable) {
- let query = window.location.search.substring(1);
- let pairs = query.split('&');
- for (let pair of pairs) {
- let [key, value] = pair.split('=');
- if (key == variable) {
- return decodeURIComponent(value);
- }
- }
- return null;
- }
-
- // 从url中获取搜索关键词
- function getKeywords() {
- let keywords = '';
- for (let item of urlMapping) {
- // 判断url是否符合搜索配置的条件
- if (item.searchUrl.includes(window.location.hostname + window.location.pathname)) {
- keywords = getQueryVariable(item.keyName);
- break;
- }
- }
- console.log(keywords);
- return keywords;
- }
-
- // 域名
- const hostname = window.location.hostname;
-
- let isBlank = GM_getValue('isBlank');
-
- console.log('新标签页打开?', isBlank);
- if (isBlank === undefined) {
- GM_setValue('isBlank', false);
- isBlank = false;
- }
-
- // 改变打开搜索引擎的方式
- const engine = document.getElementsByClassName('search-engine-a');
- function triggerAttribute(value) {
- for (const item of engine) {
- item.target = value;
- }
- }
-
- // 适配火狐浏览器的百度搜索
- const isFirefox = () => {
- if (navigator.userAgent.indexOf('Firefox') > 0) {
- console.warn('[ Firefox ] 🚀');
- urlMapping[0].searchUrl = 'https://www.baidu.com/baidu?wd=%s';
- } else {
- }
- };
-
- // 适配cn.bing.com的必应域名
- const cnBing = {
- name: 'Bing',
- searchUrl: 'https://cn.bing.com/search?q=%s',
- keyName: 'q',
- };
- // 匹配到cn.bing就修改必应配置对象
- if (window.location.hostname === 'cn.bing.com') {
- for (let item of urlMapping) {
- if (item.name === 'Bing') {
- item = cnBing;
- }
- }
- }
-
- // 添加自定义样式
- function addStyle() {
- const styleSheet = document.createElement('style');
- document.head.appendChild(styleSheet);
-
- styleSheet.textContent = `
- .search-container {
- position: fixed;
- top: 160px;
- left: 20px;
- width: 100px;
- background-color: #EEEEEE;
- font-size: 12px;
- z-index: 99999;
- }
-
- .search-title {
- display: block;
- text-align: center;
- margin-top: 10px;
- margin-bottom: 5px;
- font-size: 14px;
- font-weight: bold;
- -webkit-user-select:none;
- -moz-user-select:none;
- -ms-user-select:none;
- user-select:none;
- }
-
- .search-list__item {
- display: flex;
- justify-content: space-between;
- align-items: center;
- color: #333333 !important;
- padding-right: 6px;
- }
- .search-list__item:hover {
- color: #ffffff !important;
- background-color: #666666;
- }
-
- .search-list__item .search-engine-a {
- color: inherit !important;
- padding: 10px 6px 10px 20px;
- text-decoration: none;
- flex-grow: 2;
- }
-
- .search-list__close {
- width: 12px;
- height: 12px;
- opacity: 0;
- z-index: 10;
- }
- .search-list__close:hover {
- opacity: 1;
- }
-
- #search-black_over {
- content: "";
- position: absolute;
- top: 0;
- left: 0;
- width: 100vw;
- height: 100%;
- // background-color: #F0F5FF;
- background-color: #f0f5ffe3;
- z-index: 999;
- }
- #search-popup {
- position: fixed;
- top: 50vh;
- left: 50vw;
- background-color: #FFFFFF;
- width: 460px;
- transform: translate(-50%, -50%);
- z-index: 1000;
- }
- #setting-engine-ul {
- padding: 20px;
- height: 60vh;
- min-height: 400px;
- overflow: auto;
- }
- #setting-engine-ul::-webkit-scrollbar {
- width: 10px;
- }
-
- #setting-engine-ul::-webkit-scrollbar-thumb {
- background-color: #d9d9d9;
- border-radius: 9999em;
- }
- .setting-engine-item{
- margin-bottom: 10px;
- padding: 10px 0;
- border-radius: 4px !important;
- box-shadow: 0 2px 8px rgb(22 93 255 / 8%) !important;
- }
- .engine-info{
- margin: 5px;
- }
- .engine-label{
- width: 70px;
- display: inline-block;
- }
- .engine-info input {
- width: 275px;
- }
-
- .setting-engine-header, .setting-engine-footer{
- display: flex;
- padding: 15px;
- justify-content: space-between;
- align-items: center;
- border-top: 1px solid #e8e8e8;
- }
- `;
- }
-
- // 添加节点
- function addBox() {
- // 主元素
- const div = document.createElement('div');
- div.id = 'search-app-box';
- div.className = 'search-container';
- document.body.insertAdjacentElement('afterBegin', div);
-
- // 标题
- let title = document.createElement('span');
- title.innerText = '聚合搜索';
- title.className = 'search-title';
- title.style.textDecoration = isBlank ? 'underline' : '';
- title.ondblclick = () => {
- title.style.textDecoration = !isBlank ? 'underline' : '';
- GM_setValue('isBlank', !isBlank);
- isBlank = !isBlank;
- triggerAttribute(isBlank ? '_blank' : '');
- };
- div.appendChild(title);
-
- // 搜索列表
- for (let index in urlMapping) {
- const item = urlMapping[index];
- // 单个搜索引擎
- const searchItem = document.createElement('div');
- searchItem.className = 'search-list__item';
- const a_target = !item.searchUrl.includes(hostname) && isBlank ? '_blank' : '';
-
- searchItem.innerHTML = `
- <a class="search-engine-a" href="${item.searchUrl.replace('%s', getKeywords())}" ${a_target}>
- ${item.name}
- </a>
- `;
- // 移除按钮
- const closeImg = document.createElement('img');
- closeImg.className = 'search-list__close';
- closeImg.src =
- 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNjY4ODU1MDA0ODc1IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjI2ODEiIGRhdGEtc3BtLWFuY2hvci1pZD0iYTMxM3guNzc4MTA2OS4wLmkxIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiPjxwYXRoIGQ9Ik01MDkuMjYyNzEzIDUuNDc0NTc0YzI4MS4yNzIxNjIgMCA1MDkuMjYyNzEzIDIyOC4wMjIzOCA1MDkuMjYyNzEzIDUwOS4yNjI3MTMgMCAyODEuMjcyMTYyLTIyNy45OTA1NTEgNTA5LjI2MjcxMy01MDkuMjYyNzEzIDUwOS4yNjI3MTNzLTUwOS4yNjI3MTMtMjI3Ljk5MDU1MS01MDkuMjYyNzEzLTUwOS4yNjI3MTNjMC0yODEuMjQwMzMzIDIyNy45OTA1NTEtNTA5LjI2MjcxMyA1MDkuMjYyNzEzLTUwOS4yNjI3MTN6IG0xMzUuMDUwMTA2IDI3OC43MjU4NDlMNTA5LjI2MjcxMyA0MTkuMjUwNTI4bC0xMzUuMDUwMTA2LTEzNS4wNTAxMDUtOTAuMDEyMTg0IDkwLjAxMjE4NEw0MTkuMTg2ODcxIDUwOS4yNjI3MTNsLTEzNS4wMTgyNzcgMTM1LjA4MTkzNSA5MC4wMTIxODQgOTAuMDEyMTg0TDUwOS4yNjI3MTMgNTk5LjI3NDg5N2wxMzUuMDUwMTA2IDEzNS4wNTAxMDYgOTAuMDEyMTg0LTkwLjAxMjE4NEw1OTkuMjc0ODk3IDUwOS4yNjI3MTNsMTM1LjA1MDEwNi0xMzUuMDUwMTA2LTkwLjAxMjE4NC05MC4wMTIxODR6IiBwLWlkPSIyNjgyIiBkYXRhLXNwbS1hbmNob3ItaWQ9ImEzMTN4Ljc3ODEwNjkuMC5pMCIgY2xhc3M9IiIgZmlsbD0iI2UxNjUzMSI+PC9wYXRoPjwvc3ZnPg==';
- // 点击按钮移除节点
- closeImg.onclick = function () {
- urlMapping.splice(index, 1);
- searchItem.remove();
- GM_setValue('SearchList', urlMapping);
- };
-
- searchItem.appendChild(closeImg);
- div.appendChild(searchItem);
- }
- }
- // 重新生成节点
- function addBoxAgain() {
- document.getElementById('search-app-box')?.remove();
- addBox();
- }
- // 关闭面板
- closePanel = () => {
- document.getElementById('search-black_over')?.remove();
- document.getElementById('search-popup')?.remove();
- };
- // 新增搜索引擎
- addEngine = () => {
- const engineUl = document.getElementById('setting-engine-ul');
- const li = document.createElement('li');
- li.className = 'setting-engine-item';
- li.innerHTML = `
- <div class="engine-info">
- <label class="engine-label">引擎名称</label>
- <input class="GF-engine-name__input" />
- </div>
- <div class="engine-info">
- <label class="engine-label">引擎地址</label>
- <input class="GF-engine-url__input"/>
- </div>
- <div class="engine-info">
- <label class="engine-label">搜索参数</label>
- <input class="GF-engine-key__input" />
- </div>
- `;
- engineUl.appendChild(li);
- };
- // 重置配置
- resetEngineConfig = () => {
- urlMapping = defaultUrlMap;
- addBoxAgain();
- closePanel();
- };
- // 保存配置
- saveEngineConfig = () => {
- const list = [];
- const names = document.getElementsByClassName('GF-engine-name__input');
- const urls = document.getElementsByClassName('GF-engine-url__input');
- const keys = document.getElementsByClassName('GF-engine-key__input');
-
- for (let index = 0; index < names.length; index++) {
- list.push({
- name: names[index]?.value,
- searchUrl: urls[index]?.value,
- keyName: keys[index]?.value,
- });
- }
-
- urlMapping = list;
- GM_setValue('SearchList', list);
- addBoxAgain();
- closePanel();
- };
- // 创建设置面板
- function createSettingPanel() {
- // 遮罩
- const over = document.createElement('div');
- over.id = 'search-black_over';
- // 弹窗
- const popup = document.createElement('div');
- popup.id = 'search-popup';
-
- let engineList = '';
- urlMapping.forEach((item) => {
- engineList += `<li class="setting-engine-item">
- <div class="engine-info">
- <label class="engine-label">引擎名称</label>
- <input class="GF-engine-name__input" value="${item.name}" />
- </div>
- <div class="engine-info">
- <label class="engine-label">引擎地址</label>
- <input class="GF-engine-url__input" value="${item.searchUrl}" />
- </div>
- <div class="engine-info">
- <label class="engine-label">搜索参数</label>
- <input class="GF-engine-key__input" value="${item.keyName}" />
- </div>
- </li>`;
- });
-
- popup.innerHTML = `
- <div class="setting-engine-header">
- <button id="setting-engine-reset" onclick="closePanel()">关闭</button>
- <button id="setting-engine-save" onclick="addEngine()">新增</button>
- </div>
- <ul id="setting-engine-ul">${engineList}</ul>
- <div class="setting-engine-footer">
- <button id="setting-engine-reset" onclick="resetEngineConfig()">重置</button>
- <button id="setting-engine-save" onclick="saveEngineConfig()">保存</button>
- </div>
- `;
-
- document.body.insertAdjacentElement('afterBegin', popup);
- document.body.insertAdjacentElement('afterBegin', over);
- }
- // 添加油猴设置菜单
- function addUserSetting() {
- GM_registerMenuCommand('设置', createSettingPanel);
- }
- // 初始化
- function init() {
- if (!getKeywords()) return;
- addStyle();
- isFirefox();
- addBox();
- addUserSetting();
- }
-
- (function () {
- 'use strict';
- window.onload = init();
- })();