// ==UserScript== // @name 学术科研网页辅助工具 // @namespace http://tampermonkey.net/ // @version 1.3 // @description 一款 // @author 哔哩哔哩:凇月落 // @match https://fanyi.baidu.com/* // @match https://dict.cnki.net/* // @match https://www.kdocs.cn/* // @match https://sc.panda985.com/* // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_addStyle // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @run-at document-start // @license MIT // @downloadURL none // ==/UserScript== (function() { 'use strict'; //***********谷粉学术********************************* if (window.location.href.includes('sc.panda985.com')) { // 1. 第一步:在页面渲染前注入CSS立即隐藏广告 GM_addStyle(` .ad, [class*="ad-"], [id*="ad-"] { display: none !important; visibility: hidden !important; opacity: 0 !important; height: 0 !important; width: 0 !important; padding: 0 !important; margin: 0 !important; } `); // 2. 第二步:等待DOM可用后移除广告元素 const removeAds = () => { const ads = document.querySelectorAll('.ad, .adsbygoogle'); ads.forEach(ad => ad.remove()); // 3. 第三步:持续监听动态加载的广告 if (window.adObserver) adObserver.disconnect(); window.adObserver = new MutationObserver(mutations => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { // 检查直接添加的广告节点 if (node.nodeType === 1 && ( node.matches('.ad, .adsbygoogle') || node.querySelector('.ad, .adsbygoogle') )) { node.remove(); return; } // 检查子节点中的广告 if (node.querySelectorAll) { node.querySelectorAll('.ad, .adsbygoogle').forEach(ad => { ad.remove(); }); } }); }); }); adObserver.observe(document.documentElement, { childList: true, subtree: true, attributes: false, characterData: false }); }; // 根据页面状态选择执行时机 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', removeAds); } else { removeAds(); } //****************翻页*********************** // 配置参数 const PAGES_PER_LOAD = 20; // 每次加载的页数 const LOAD_THRESHOLD = 300; // 距离底部多少像素触发加载 const LOAD_DELAY = 1000; // 加载延迟(毫秒) const RESULT_CONTAINER = '#gs_res_ccl'; // 结果容器选择器 const RESULT_ITEM = '.gs_r'; // 结果项选择器 const NEXT_BUTTON = '.gs_ico_nav_next'; // 下一页按钮选择器 // 状态变量 let totalLoadedPages = GM_getValue('totalLoadedPages', 0); let currentCyclePages = GM_getValue('currentCyclePages', 0); let isLoading = false; currentCyclePages = 0 totalLoadedPages = 0 // 添加自定义样式 GM_addStyle(` .auto-loading-indicator { position: fixed; bottom: 20px; right: 20px; background: #4CAF50; color: white; padding: 10px 15px; border-radius: 20px; z-index: 9999; box-shadow: 0 2px 10px rgba(0,0,0,0.2); font-size: 14px; transition: all 0.3s ease; } .auto-loading-indicator.paused { background: #FF9800; } .auto-loading-indicator.completed { background: #f44336; } .loading-indicator { text-align: center; padding: 15px 0; color: #666; display: none; } .loading-indicator.active { display: block; } .loading-spinner { border: 3px solid #f3f3f3; border-top: 3px solid #4285f4; border-radius: 50%; width: 24px; height: 24px; animation: spin 1s linear infinite; display: inline-block; margin-right: 10px; vertical-align: middle; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .load-more-container { text-align: center; padding: 20px 0; margin: 20px 0; } .load-more-btn { display: inline-block; padding: 12px 30px; background: #4285f4; color: white; border: none; border-radius: 30px; cursor: pointer; text-align: center; font-size: 16px; font-weight: bold; box-shadow: 0 3px 10px rgba(66, 133, 244, 0.3); transition: all 0.3s ease; } .load-more-btn:hover { background: #3367d6; transform: translateY(-2px); box-shadow: 0 5px 15px rgba(66, 133, 244, 0.4); } .load-more-btn:active { transform: translateY(0); } .load-more-btn.pulse { animation: pulse 2s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(66, 133, 244, 0.7); } 70% { box-shadow: 0 0 0 10px rgba(66, 133, 244, 0); } 100% { box-shadow: 0 0 0 0 rgba(66, 133, 244, 0); } } `); // 创建状态指示器 const createStatusBanner = () => { const banner = document.createElement('div'); banner.className = 'auto-loading-indicator'; updateStatusBanner(banner); document.body.appendChild(banner); return banner; }; // 更新状态指示器 const updateStatusBanner = (banner) => { if (currentCyclePages >= PAGES_PER_LOAD) { banner.className = 'auto-loading-indicator paused'; banner.innerHTML = `⏸️ 已加载 ${totalLoadedPages} 页`; } else if (isLoading) { banner.className = 'auto-loading-indicator'; banner.innerHTML = `⏳ 正在加载第 ${totalLoadedPages + 1} 页...`; } else { banner.className = 'auto-loading-indicator'; banner.innerHTML = `📚 已加载 ${totalLoadedPages} 页`; } }; // 创建加载指示器 const createLoadingIndicator = () => { const indicator = document.createElement('div'); indicator.className = 'loading-indicator'; indicator.innerHTML = `
正在加载更多结果... `; document.querySelector(RESULT_CONTAINER).appendChild(indicator); return indicator; }; // 创建"加载更多"按钮 const createLoadMoreButton = () => { // 移除可能存在的旧按钮 const existingBtn = document.querySelector('.load-more-container'); if (existingBtn) existingBtn.remove(); const container = document.createElement('div'); container.className = 'load-more-container'; const button = document.createElement('button'); button.className = 'load-more-btn pulse'; button.innerHTML = `加载更多 ${PAGES_PER_LOAD} 页结果`; container.appendChild(button); document.querySelector(RESULT_CONTAINER).appendChild(container); return button; }; // 获取下一页URL const getNextPageUrl = () => { const nextBtn = document.querySelector(NEXT_BUTTON); return nextBtn ? nextBtn.closest('a').href : null; }; // 从HTML中提取搜索结果 const extractResults = (html) => { const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); return doc.querySelectorAll(RESULT_ITEM); }; // 滚动事件处理器 const handleScroll = (banner, loadingIndicator) => { // 如果正在加载或已达到当前周期限制,不处理滚动 if (isLoading || currentCyclePages >= PAGES_PER_LOAD) return; // 计算是否到达底部 const scrollPosition = window.scrollY + window.innerHeight; const pageHeight = document.documentElement.scrollHeight; if (scrollPosition > pageHeight - LOAD_THRESHOLD) { // 防止重复加载 if (loadingIndicator.classList.contains('active')) return; // 显示加载指示器 loadingIndicator.classList.add('active'); isLoading = true; updateStatusBanner(banner); // 延迟加载以提供视觉反馈 setTimeout(() => { loadNextPage(banner, loadingIndicator); }, LOAD_DELAY); } }; // AJAX加载下一页内容 const loadNextPage = (banner, loadingIndicator) => { const nextUrl = getNextPageUrl(); if (!nextUrl) { finishLoading(banner, loadingIndicator); return; } GM_xmlhttpRequest({ method: "GET", url: nextUrl, onload: function(response) { const results = extractResults(response.responseText); if (results.length > 0) { // 添加新结果到页面 const container = document.querySelector(RESULT_CONTAINER); // 插入新结果 results.forEach(item => { container.insertBefore(item.cloneNode(true), loadingIndicator); }); // 更新页数 totalLoadedPages++; currentCyclePages++; // 保存状态 GM_setValue('totalLoadedPages', totalLoadedPages); GM_setValue('currentCyclePages', currentCyclePages); // 更新状态指示器 updateStatusBanner(banner); // 如果达到当前周期限制,添加"加载更多"按钮 if (currentCyclePages >= PAGES_PER_LOAD) { const loadMoreBtn = createLoadMoreButton(); loadMoreBtn.onclick = () => { // 重置当前周期计数 currentCyclePages = 0; GM_setValue('currentCyclePages', 0); // 移除按钮并更新状态 loadMoreBtn.remove(); updateStatusBanner(banner); // 手动触发加载 loadingIndicator.classList.add('active'); isLoading = true; loadNextPage(banner, loadingIndicator); }; } } finishLoading(banner, loadingIndicator); }, onerror: function(error) { console.error('加载失败:', error); finishLoading(banner, loadingIndicator); } }); }; // 完成加载处理 const finishLoading = (banner, loadingIndicator) => { loadingIndicator.classList.remove('active'); isLoading = false; updateStatusBanner(banner); // 检查是否需要立即加载下一页 if (currentCyclePages < PAGES_PER_LOAD) { setTimeout(() => { const scrollPosition = window.scrollY + window.innerHeight; const pageHeight = document.documentElement.scrollHeight; if (scrollPosition > pageHeight - LOAD_THRESHOLD) { handleScroll(banner, loadingIndicator); } }, 500); } }; // 主初始化函数 const init = () => { // 创建状态指示器 const banner = createStatusBanner(); // 创建加载指示器 const loadingIndicator = createLoadingIndicator(); // 设置滚动监听 const scrollHandler = () => handleScroll(banner, loadingIndicator); window.addEventListener('scroll', scrollHandler); // 初始加载检查 setTimeout(() => { // 检查初始页面是否已滚动到底部 const scrollPosition = window.scrollY + window.innerHeight; const pageHeight = document.documentElement.scrollHeight; if (scrollPosition > pageHeight - LOAD_THRESHOLD && currentCyclePages < PAGES_PER_LOAD) { scrollHandler(); } // 如果已达到周期限制,显示加载更多按钮 if (currentCyclePages >= PAGES_PER_LOAD) { const loadMoreBtn = createLoadMoreButton(); loadMoreBtn.onclick = () => { // 重置当前周期计数 currentCyclePages = 0; GM_setValue('currentCyclePages', 0); // 移除按钮并更新状态 loadMoreBtn.closest('.load-more-container').remove(); updateStatusBanner(banner); // 手动触发加载 loadingIndicator.classList.add('active'); isLoading = true; loadNextPage(banner, loadingIndicator); }; } }, 2000); }; // 页面加载完成后执行 document.addEventListener('DOMContentLoaded', init); // 如果需要完全加载后的操作 window.addEventListener('load', function() { // 仅处理需要完全加载资源的代码 }); } //**********谷歌学术自动翻页************************************* // 调试模式开关 if (window.location.href.includes('scholar.google.com')){ const DEBUG_MODE = false; // 调试日志函数 function debugLog(message) { if (DEBUG_MODE) { console.log(`[ScholarScroll] ${message}`); GM_log(`[ScholarScroll] ${message}`); } } // 添加自定义样式 GM_addStyle(` .infinite-scroll-loader { display: flex; justify-content: center; padding: 20px; margin: 30px 0; } .loading-spinner { width: 40px; height: 40px; border: 4px solid rgba(0, 0, 0, 0.1); border-left: 4px solid #4285f4; border-radius: 50%; animation: spin 1s linear infinite; } .infinite-scroll-status { text-align: center; padding: 10px; color: #5f6368; font-size: 14px; } .debug-panel { position: fixed; bottom: 10px; right: 10px; background: white; border: 1px solid #ddd; padding: 10px; border-radius: 4px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); z-index: 9999; max-width: 300px; font-size: 12px; } .debug-header { font-weight: bold; margin-bottom: 5px; color: #1a73e8; } .debug-content { max-height: 150px; overflow-y: auto; font-family: monospace; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } `); // 主函数 function initInfiniteScroll() { debugLog("初始化无限滚动功能"); // 检查是否在搜索结果页面 const resultsContainer = document.querySelector('#gs_res_ccl'); if (!resultsContainer) { debugLog("错误:找不到结果容器 (#gs_res_ccl)"); return; } // 创建UI元素 const loader = document.createElement('div'); loader.className = 'infinite-scroll-loader'; loader.innerHTML = ''; loader.style.display = 'none'; const statusDiv = document.createElement('div'); statusDiv.className = 'infinite-scroll-status'; const container = document.createElement('div'); container.id = 'infinite-scroll-container'; container.appendChild(loader); container.appendChild(statusDiv); resultsContainer.after(container); let isLoading = false; let hasMorePages = true; let nextPageUrl = null; // 创建调试面板 if (DEBUG_MODE) { createDebugPanel(); } // 查找下一页URL function findNextPageUrl() { const nextButton = document.querySelector('.gs_ico.gs_ico_nav_next')?.closest('a'); const url = nextButton ? nextButton.href : null; debugLog(`找到下一页URL: ${url}`); return url; } // 初始化下一页URL nextPageUrl = findNextPageUrl(); // 加载下一页 async function loadNextPage() { if (isLoading) { debugLog("加载被阻止:当前正在加载中"); return; } if (!hasMorePages) { debugLog("加载被阻止:没有更多页面"); return; } if (!nextPageUrl) { debugLog("加载被阻止:没有下一页URL"); hasMorePages = false; statusDiv.textContent = '已加载所有结果'; return; } isLoading = true; loader.style.display = 'flex'; statusDiv.textContent = '正在加载更多结果...'; debugLog(`开始加载: ${nextPageUrl}`); try { // 使用GM_xmlhttpRequest获取下一页内容 const response = await fetchPage(nextPageUrl); // 解析新内容 const newContent = parseNewContent(response); if (newContent && newContent.results) { debugLog(`成功获取新内容,找到 ${newContent.results.length} 个结果`); // 添加新内容 addNewResults(newContent.results); // 更新下一页URL nextPageUrl = newContent.nextPageUrl; debugLog(`更新下一页URL: ${nextPageUrl}`); statusDiv.textContent = ''; if (!nextPageUrl) { hasMorePages = false; statusDiv.textContent = '已加载所有结果'; debugLog("没有更多页面了"); } } else { debugLog("未找到新内容"); hasMorePages = false; statusDiv.textContent = '没有更多结果了'; } } catch (error) { debugLog(`加载错误: ${error.message}`); statusDiv.textContent = '加载失败,请重试'; GM_notification({ title: 'Google Scholar 无限滚动', text: '加载下一页时出错', silent: true }); } finally { isLoading = false; loader.style.display = 'none'; } } // 使用GM_xmlhttpRequest获取页面内容 function fetchPage(url) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "GET", url: url, onload: function(response) { if (response.status >= 200 && response.status < 300) { debugLog(`页面加载成功,状态码: ${response.status}`); resolve(response.responseText); } else { debugLog(`请求失败,状态码: ${response.status}`); reject(new Error(`请求失败,状态码: ${response.status}`)); } }, onerror: function(error) { debugLog(`网络错误: ${error}`); reject(new Error('网络请求失败')); }, ontimeout: function() { debugLog("请求超时"); reject(new Error('请求超时')); } }); }); } // 解析新内容 function parseNewContent(html) { const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); // 提取结果列表 const newResultsContainer = doc.querySelector('#gs_res_ccl'); if (!newResultsContainer) { debugLog("解析错误:找不到结果容器"); return null; } // 提取结果项 const resultItems = newResultsContainer.querySelectorAll('.gs_r.gs_or.gs_scl, .gs_ri'); if (resultItems.length === 0) { debugLog("解析错误:找不到结果项"); return null; } // 提取下一页URL const nextButton = doc.querySelector('.gs_ico.gs_ico_nav_next')?.closest('a'); const nextPageUrl = nextButton ? nextButton.href : null; return { results: Array.from(resultItems), nextPageUrl: nextPageUrl }; } // 添加新结果到页面 function addNewResults(results) { const resultsContainer = document.querySelector('#gs_res_ccl'); results.forEach(item => { // 克隆节点以避免文档树问题 const clonedItem = item.cloneNode(true); resultsContainer.appendChild(clonedItem); }); debugLog(`成功添加 ${results.length} 个新结果`); } // 检查滚动位置 function checkScrollPosition() { if (isLoading || !hasMorePages) return; const scrollPosition = window.scrollY + window.innerHeight; const documentHeight = document.documentElement.scrollHeight; const threshold = 1000; // 提前500px加载 if (scrollPosition >= documentHeight - threshold) { debugLog(`触发滚动加载 (${scrollPosition} >= ${documentHeight} - ${threshold})`); loadNextPage(); } // 更新调试信息 if (DEBUG_MODE) { updateDebugInfo(); } } // 创建调试面板 function createDebugPanel() { const debugPanel = document.createElement('div'); debugPanel.className = 'debug-panel'; debugPanel.innerHTML = `