// ==UserScript== // @name Google Search Sidebar // @namespace http://tampermonkey.net/ // @version 1.1 // @description Add a sidebar on Google Search for easier information filtering // @author Kamiya Minoru // @icon https://www.google.com/favicon.ico // @match https://www.google.com/* // @match https://www.google.com.tw/* // @match https://www.google.co.jp/* // @grant none // @downloadURL none // ==/UserScript== (function() { 'use strict'; const userLang = navigator.language || navigator.userLanguage; const i18n = { 'zh-TW': { languageSection: '語言過濾', timeSection: '時間過濾 …', advancedSearch: '進階搜尋', languages: { any: '不限語言搜尋', zhTW: '以繁體中文搜尋', zh: '以中文搜尋', ja: '以日文搜尋', en: '以英文搜尋' }, times: { any: '不限時間', hour: '過去1小時', day: '過去24小時', week: '過去7天', month: '過去1個月', months3: '過去3個月', year: '過去1年', years3: '過去3年' // 新增的選項 } }, 'ja': { languageSection: '言語フィルター', timeSection: '期間フィルター', advancedSearch: '検索オプション', languages: { any: '言語指定なし', zhTW: '繁体中国語で検索', zh: '中国語で検索', ja: '日本語で検索', en: '英語で検索' }, times: { any: '期間指定なし', hour: '1時間以内', day: '24時間以内', week: '1週間以内', month: '1か月以内', months3: '3か月以内', year: '1年以内', years3: '3年以内' // 新增的選項 } }, 'en': { languageSection: 'Language Filter', timeSection: 'Time Filter', advancedSearch: 'Advanced Search', languages: { any: 'Any Language', zhTW: 'Traditional Chinese', zh: 'All Chinese', ja: 'Japanese', en: 'English' }, times: { any: 'Any Time', hour: 'Past Hour', day: 'Past 24 Hours', week: 'Past Week', month: 'Past Month', months3: 'Past 3 Months', year: 'Past Year', years3: 'Past 3 Years' } } }; function getLocale() { if (i18n[userLang]) { return i18n[userLang]; } const primaryLang = userLang.split('-')[0]; if (i18n[primaryLang]) { return i18n[primaryLang]; } return i18n['en']; } const locale = getLocale(); const languageFilters = [ { text: locale.languages.any, param: '&lr=' }, { text: locale.languages.zhTW, param: '&lr=lang_zh-TW' }, { text: locale.languages.zh, param: '&lr=lang_zh' }, { text: locale.languages.ja, param: '&lr=lang_ja' }, { text: locale.languages.en, param: '&lr=lang_en' } ]; const timeFilters = [ { text: locale.times.any, param: '&tbs=' }, { text: locale.times.hour, param: '&tbs=qdr:h' }, { text: locale.times.day, param: '&tbs=qdr:d' }, { text: locale.times.week, param: '&tbs=qdr:w' }, { text: locale.times.month, param: '&tbs=qdr:m' }, { text: locale.times.months3, param: '&tbs=qdr:m3' }, { text: locale.times.year, param: '&tbs=qdr:y' }, { text: locale.times.years3, param: '&tbs=qdr:y3' } ]; function createAdvancedSearchLink() { const link = document.createElement('a'); link.textContent = locale.advancedSearch; link.href = getAdvancedSearchUrl(); link.style.cssText = ` display: block; color: #1a73e8; text-decoration: none; font-size: 13px; padding: 8px; margin-top: 10px; background: #f8f9fa; border-radius: 8px; text-align: center; transition: background-color 0.2s; `; link.addEventListener('mouseover', () => { link.style.backgroundColor = '#e8f0fe'; }); link.addEventListener('mouseout', () => { link.style.backgroundColor = '#f8f9fa'; }); return link; } function createFilterSection(title, filters, collapsible = false, defaultExpanded = false) { const section = document.createElement('div'); section.style.cssText = ` margin: 10px 0; padding: 8px; background: #f8f9fa; border-radius: 8px; `; const titleElement = document.createElement('h3'); titleElement.textContent = title; titleElement.style.cssText = ` margin: 0 0 8px 0; font-size: 13px; color: #202124; font-weight: 500; cursor: ${collapsible ? 'pointer' : 'default'}; `; section.appendChild(titleElement); const linkContainer = document.createElement('div'); linkContainer.style.cssText = ` display: flex; flex-direction: column; gap: 6px; ${collapsible && !defaultExpanded ? 'display: none;' : ''} `; filters.forEach(filter => { const link = document.createElement('a'); link.textContent = filter.text; link.href = getCurrentUrlWithParam(filter.param); link.style.cssText = ` color: #888888; // 非高亮文字顏色 text-decoration: none; font-size: 12px; padding: 3px 6px; border-radius: 4px; transition: background-color 0.2s, color 0.2s; `; const urlParams = new URL(window.location.href).searchParams; if (urlParams.get('lr') === filter.param.replace('&lr=', '') || urlParams.get('tbs') === filter.param.replace('&tbs=', '')) { link.style.color = '#1a73e8'; // 高亮文字顏色 link.style.fontWeight = 'bold'; } link.addEventListener('mouseover', () => { link.style.backgroundColor = '#e8f0fe'; }); link.addEventListener('mouseout', () => { if (urlParams.get('lr') !== filter.param.replace('&lr=', '') && urlParams.get('tbs') !== filter.param.replace('&tbs=', '')) { link.style.backgroundColor = 'transparent'; } }); linkContainer.appendChild(link); }); section.appendChild(linkContainer); if (collapsible) { titleElement.addEventListener('click', () => { linkContainer.style.display = linkContainer.style.display === 'none' ? 'flex' : 'none'; }); } return section; } function getCurrentUrlWithParam(param) { const url = new URL(window.location.href); // Preserve existing parameters const existingParams = new URLSearchParams(url.search); // Remove existing language or time parameters if "any" is selected if (param.includes('lr=')) { existingParams.delete('lr'); } if (param.includes('tbs=')) { existingParams.delete('tbs'); } // Add new parameters if (param) { const cleanParam = param.startsWith('&') ? param.substring(1) : param; const [key, value] = cleanParam.split('='); if (value) { existingParams.set(key, value); } else { existingParams.delete(key); } } url.search = existingParams.toString(); return url.toString(); } function getAdvancedSearchUrl() { const url = new URL('https://www.google.com/advanced_search'); const currentParams = new URLSearchParams(window.location.search); return url.toString(); } function addFiltersToPage() { const searchResults = document.getElementById('search'); if (!searchResults) return; const sidebar = document.createElement('div'); sidebar.style.cssText = ` position: fixed; top: 15px; left: 10px; width: 160px; z-index: 1000; `; sidebar.appendChild(createFilterSection(locale.languageSection, languageFilters)); sidebar.appendChild(createFilterSection(locale.timeSection, timeFilters, true, window.location.href.includes('&tbs='))); sidebar.appendChild(createAdvancedSearchLink()); document.body.appendChild(sidebar); } const observer = new MutationObserver((mutations, obs) => { const searchResults = document.getElementById('search'); if (searchResults) { addFiltersToPage(); obs.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); })(); (function() { 'use strict'; function createScrollButton(innerHTML, onClick) { var button = document.createElement('div'); button.innerHTML = innerHTML; button.style.width = '30px'; button.style.height = '30px'; button.style.cursor = 'pointer'; button.style.backgroundColor = 'transparent'; button.style.color = 'grey'; button.style.textAlign = 'center'; button.style.fontSize = '30px'; button.style.borderRadius = '0px'; button.style.userSelect = 'none'; button.style.marginBottom = '1px'; button.style.opacity = '0.2'; button.style.transition = 'all 0s'; button.style.filter = 'drop-shadow(0 0 0 grey)'; button.addEventListener('click', onClick); button.addEventListener('mouseover', function() { button.style.opacity = '1'; button.style.filter = 'drop-shadow(0 0 2px grey)'; button.style.color = '#FFF'; }); button.addEventListener('mouseout', function() { button.style.opacity = '0.1'; button.style.filter = 'drop-shadow(0 0 0 grey)'; button.style.color = 'grey'; }); return button; } function addScrollButtonsToSidebar() { const sidebar = document.querySelector('div[style*="position: fixed"]'); if (!sidebar) return; const scrollContainer = document.createElement('div'); scrollContainer.style.cssText = ` position: absolute; top: 1px; left: 130px; display: flex; flex-direction: column; align-items: center; margin-top: 10px; `; scrollContainer.appendChild(createScrollButton('⇑', function() { window.scrollTo({ top: 0, behavior: 'instant' }); })); scrollContainer.appendChild(createScrollButton('⇡', function() { window.scrollBy({ top: -window.innerHeight, behavior: 'instant' }); })); scrollContainer.appendChild(createScrollButton('⇣', function() { window.scrollBy({ top: window.innerHeight, behavior: 'instant' }); })); scrollContainer.appendChild(createScrollButton('⇓', function() { window.scrollTo({ top: document.body.scrollHeight, behavior: 'instant' }); })); sidebar.appendChild(scrollContainer); } const observer = new MutationObserver((mutations, obs) => { const sidebar = document.querySelector('div[style*="position: fixed"]'); if (sidebar) { addScrollButtonsToSidebar(); obs.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); })();