// ==UserScript==
// @name 聚合搜索
// @description AI生成,整合百度、谷歌、必应搜索,支持无刷新自动翻页,关键词高亮,快捷键切换,根据系统主题自动切换暗色模式
// @version 1.0.2
// @author yinbao77
// @website https://github.com/yinbao77
// @match *://www.baidu.com/s*
// @match *://www.bing.com/search*
// @match *://cn.bing.com/search*
// @match *://www.google.com.hk/search*
// @match *://www.google.com/search*
// @namespace https://greasyfork.org/users/1489016
// ==/UserScript==
(function() {
'use strict';
// 配置
const engines = [
{ name: '百度', url: 'https://www.baidu.com/s?wd=', param: 'wd', test: /baidu\.com/, key: '1' },
{ name: '必应', url: 'https://www.bing.com/search?q=', param: 'q', test: /bing\.com/, key: '2' },
{ name: 'Google', url: 'https://www.google.com/search?q=', param: 'q', test: /google\.com/, key: '3' }
];
let isAutoPageOn = true;
let currentPage = 1;
let isLoading = false;
let isDarkMode = false;
// 主题
function detectDarkMode() {
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
}
function getTheme() {
return isDarkMode ? {
bg: '#2d2d2d', border: '#555', text: '#e0e0e0', textSec: '#b0b0b0',
active: '#4CAF50', hover: '#3a3a3a', highlight: '#ffd700'
} : {
bg: '#EEEEEE', border: '#ccc', text: '#333', textSec: '#666',
active: '#4CAF50', hover: '#f5f5f5', highlight: '#ffff00'
};
}
// 工具函数
function getCurrentEngine() {
return engines.find(e => e.test.test(location.href));
}
function getKeywords() {
const engine = getCurrentEngine();
if (!engine) return '';
const params = new URLSearchParams(location.search);
return params.get(engine.param) || '';
}
function showTip(text) {
const theme = getTheme();
let tip = document.getElementById('search-tip');
if (!tip) {
tip = document.createElement('div');
tip.id = 'search-tip';
document.body.appendChild(tip);
}
tip.textContent = text;
tip.style.cssText = `
position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
background: rgba(0,0,0,0.8); color: white; padding: 15px 25px;
border-radius: 10px; font-size: 16px; z-index: 10001; display: block;
`;
setTimeout(() => tip.style.display = 'none', 1500);
}
function jumpTo(engineUrl) {
const keywords = getKeywords();
if (keywords) {
showTip('正在跳转...');
setTimeout(() => {
location.href = engineUrl + encodeURIComponent(keywords);
}, 300);
}
}
// 创建侧边栏
function createSidebar() {
const current = getCurrentEngine();
if (!current) return;
const theme = getTheme();
const sidebar = document.createElement('div');
sidebar.id = 'search-sidebar';
sidebar.style.cssText = `
position: fixed; top: 50%; left: 20px; transform: translateY(-50%);
width: 120px; background: ${theme.bg}; border: 1px solid ${theme.border};
border-radius: 8px; font-size: 12px; z-index: 99999;
box-shadow: 0 4px 8px rgba(0,0,0,0.1); font-family: Arial, sans-serif;
`;
// 作者
const author = document.createElement('div');
author.textContent = 'by 丶恩嗯';
author.style.cssText = `text-align: center; margin: 8px 0; font-size: 12px; color: ${theme.textSec};`;
sidebar.appendChild(author);
// 标题
const title = document.createElement('div');
title.textContent = '🔍聚合搜索';
title.style.cssText = `text-align: center; margin: 10px 0; font-size: 14px; font-weight: bold; color: ${theme.text};`;
sidebar.appendChild(title);
// 引擎按钮
engines.forEach(engine => {
const btn = document.createElement('div');
btn.textContent = engine.name;
btn.title = `快捷键: Alt+${engine.key}`;
if (current.name === engine.name) {
btn.style.cssText = `
padding: 8px 0; text-align: center; cursor: pointer;
border-top: 1px solid ${theme.border}; background: ${theme.active};
color: white; font-weight: bold;
`;
} else {
btn.style.cssText = `
padding: 8px 0; text-align: center; cursor: pointer;
border-top: 1px solid ${theme.border}; color: ${theme.text};
`;
btn.onmouseover = () => btn.style.background = theme.hover;
btn.onmouseout = () => btn.style.background = '';
btn.onclick = () => jumpTo(engine.url);
}
sidebar.appendChild(btn);
});
// 自动翻页开关
const toggle = document.createElement('div');
toggle.innerHTML = `🔄 自动翻页: ${isAutoPageOn ? 'ON' : 'OFF'}`;
toggle.style.cssText = `
border-top: 1px solid ${theme.border}; padding: 8px 0; text-align: center;
font-size: 10px; cursor: pointer; color: ${theme.text};
background: ${isAutoPageOn ? (isDarkMode ? '#2d4a2d' : '#e8f5e8') : (isDarkMode ? '#3a3a3a' : '#f5f5f5')};
border-bottom-left-radius: 8px; border-bottom-right-radius: 8px;
`;
toggle.onclick = () => {
isAutoPageOn = !isAutoPageOn;
toggle.innerHTML = `🔄 自动翻页: ${isAutoPageOn ? 'ON' : 'OFF'}`;
toggle.style.background = isAutoPageOn ? (isDarkMode ? '#2d4a2d' : '#e8f5e8') : (isDarkMode ? '#3a3a3a' : '#f5f5f5');
localStorage.setItem('autoPageOn', isAutoPageOn);
};
sidebar.appendChild(toggle);
// 拖拽功能
let isDragging = false;
let startX, startY, initialX, initialY;
const dragElements = [sidebar, author, title];
dragElements.forEach(el => {
el.onmousedown = function(e) {
isDragging = true;
startX = e.clientX;
startY = e.clientY;
const rect = sidebar.getBoundingClientRect();
initialX = rect.left;
initialY = rect.top;
sidebar.style.cursor = 'move';
e.preventDefault();
};
});
document.onmousemove = function(e) {
if (isDragging) {
const deltaX = e.clientX - startX;
const deltaY = e.clientY - startY;
sidebar.style.left = (initialX + deltaX) + 'px';
sidebar.style.top = (initialY + deltaY) + 'px';
sidebar.style.transform = 'none';
}
};
document.onmouseup = function() {
if (isDragging) {
isDragging = false;
sidebar.style.cursor = '';
}
};
document.body.appendChild(sidebar);
}
// 回到顶部按钮
function createBackToTop() {
const btn = document.createElement('div');
btn.innerHTML = '⬆';
btn.id = 'back-to-top';
btn.style.cssText = `
position: fixed; bottom: 20px; right: 20px; width: 50px; height: 50px;
background: #007bff; color: white; border-radius: 50%; text-align: center;
line-height: 50px; font-size: 20px; cursor: pointer; display: none; z-index: 9999;
transition: all 0.3s ease;
`;
btn.onmouseover = () => {
btn.style.backgroundColor = '#0056b3';
btn.style.transform = 'scale(1.1)';
};
btn.onmouseout = () => {
btn.style.backgroundColor = '#007bff';
btn.style.transform = 'scale(1)';
};
btn.onclick = () => window.scrollTo({top: 0, behavior: 'smooth'});
document.body.appendChild(btn);
// 滚动监听
window.addEventListener('scroll', () => {
const scrollTop = window.pageYOffset;
btn.style.display = scrollTop > 300 ? 'block' : 'none';
// 自动翻页
if (isAutoPageOn && !isLoading) {
const windowHeight = window.innerHeight;
const documentHeight = document.documentElement.scrollHeight;
if (scrollTop + windowHeight >= documentHeight - 200) {
loadNextPage();
}
}
});
}
// 自动翻页
async function loadNextPage() {
const engine = getCurrentEngine();
if (!engine || currentPage >= 10) return;
isLoading = true;
currentPage++;
showTip(`正在加载第 ${currentPage} 页...`);
try {
const url = new URL(location.href);
if (engine.name === '百度') {
url.searchParams.set('pn', (parseInt(url.searchParams.get('pn') || '0') + 10).toString());
} else if (engine.name === '必应') {
url.searchParams.set('start', (parseInt(url.searchParams.get('start') || '0') + 10).toString());
} else if (engine.name === 'Google') {
url.searchParams.set('first', (parseInt(url.searchParams.get('first') || '1') + 10).toString());
}
const response = await fetch(url);
const html = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
let selector = '#content_left';
if (engine.name === '必应') selector = '#b_results';
if (engine.name === 'Google') selector = '#search';
const newResults = doc.querySelector(selector);
const currentResults = document.querySelector(selector);
if (newResults && currentResults) {
const theme = getTheme();
const pageIndicator = document.createElement('div');
pageIndicator.innerHTML = `━━━ 第 ${currentPage} 页 ━━━`;
pageIndicator.style.cssText = `
margin: 20px 0; padding: 10px; text-align: center; border-radius: 5px;
background: ${theme.bg === '#EEEEEE' ? '#f0f0f0' : '#3a3a3a'}; color: ${theme.text};
`;
currentResults.appendChild(pageIndicator);
Array.from(newResults.children).forEach(item => {
if (!item.classList.contains('page')) {
currentResults.appendChild(item);
}
});
setTimeout(highlightKeywords, 300);
}
} catch (e) {
showTip('翻页失败');
}
isLoading = false;
}
// 关键词高亮
function highlightKeywords() {
const keywords = getKeywords();
if (!keywords) return;
const keywordList = keywords.split(/\s+/).filter(word => word.length > 1);
if (!keywordList.length) return;
const engine = getCurrentEngine();
const selectors = ['#content_left', '#search', '#b_results'];
let container = null;
for (const sel of selectors) {
container = document.querySelector(sel);
if (container) break;
}
if (!container) return;
const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT);
const textNodes = [];
let node;
while (node = walker.nextNode()) {
const parent = node.parentNode;
if (parent.tagName !== 'SCRIPT' && parent.tagName !== 'STYLE' &&
!parent.closest('#search-sidebar, #search-tip, #back-to-top')) {
textNodes.push(node);
}
}
const theme = getTheme();
textNodes.forEach(textNode => {
let text = textNode.textContent;
let hasMatch = false;
keywordList.forEach(keyword => {
const regex = new RegExp(`(${keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
if (regex.test(text)) {
text = text.replace(regex, `<mark style="background: ${theme.highlight}; font-weight: bold; padding: 1px 2px; border-radius: 2px;">$1</mark>`);
hasMatch = true;
}
});
if (hasMatch) {
const wrapper = document.createElement('span');
wrapper.innerHTML = text;
textNode.parentNode.replaceChild(wrapper, textNode);
}
});
}
// 快捷键
function initShortcuts() {
document.addEventListener('keydown', (e) => {
if (e.altKey && !['INPUT', 'TEXTAREA'].includes(e.target.tagName)) {
const engine = engines.find(eng => eng.key === e.key);
if (engine) {
e.preventDefault();
showTip(`🚀 正在跳转到 ${engine.name}...`);
setTimeout(() => jumpTo(engine.url), 300);
}
}
});
}
// 主题切换监听
function initTheme() {
isDarkMode = detectDarkMode();
if (window.matchMedia) {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
isDarkMode = e.matches;
// 简单重载以应用新主题
location.reload();
});
}
}
// 初始化
function init() {
// 检查是否在搜索页面
if (!engines.some(e => e.test.test(location.href))) {
return;
}
// 初始化主题
initTheme();
// 读取设置
try {
const saved = localStorage.getItem('autoPageOn');
if (saved !== null) isAutoPageOn = saved === 'true';
} catch (e) {}
// 创建界面
createSidebar();
createBackToTop();
initShortcuts();
// 延迟高亮
setTimeout(highlightKeywords, 1000);
}
// 启动
setTimeout(init, 1500);
})();