Greasy Fork

Greasy Fork is available in English.

SearchTimeMachine 搜索时光机

Display time filtering function in the right sidebar. 在右侧栏中显示时间过滤功能

当前为 2024-06-01 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         SearchTimeMachine 搜索时光机
// @namespace    http://tampermonkey.net/
// @version      0.0.2
// @description  Display time filtering function in the right sidebar. 在右侧栏中显示时间过滤功能
// @author       Exisi
// @license      MIT License
// @match        *.baidu.com/s*
// @match        *.google.com.*/search*
// @match        *.google.com/search*
// @match        *.google.com.hk/search*
// @match        *.bing.com/*search*
// @match        *.yahoo.com/search*
// @match        *.yandex.com/search*
// ==/UserScript==
(function () {
	"use strict";
	const data = [
		{
			name: "bing",
			timeFilterClass: [".b_dropdown div", "b_ans"],
			sideBarElement: "#b_context",
		},
		{
			name: "baidu",
			timeFilterClass: [],
			sideBarElement: "#content_right",
		},
		{
			name: "google",
			timeFilterClass: ["#hdtbMenus", "g-menu"],
			sideBarElement: "#rcnt>div:not(#center_col)",
			container: "#rcnt",
		},
		{
			name: "yahoo",
			timeFilterClass: ["#horizontal-bar .last .timefilter-list"],
			sideBarElement: "#right",
		},
		{
			name: "yandex",
			timeFilterClass: [],
			sideBarElement: "#search-result-aside",
		},
	];
	const url = window.location.href;
	const urlParams = new URLSearchParams(window.location.search);
	const type = data.findIndex((item) => url.includes(item.name));

	let filterItem = document.querySelector(data[type].timeFilterClass[0]);
	let sidebar = document.querySelector(data[type].sideBarElement);

	const style = document.createElement("style");
	style.innerHTML = `.form-footer button:hover{ background-color: #f5f5f6 !important;}`;
	document.head.appendChild(style);

	const customRangeFilter = `<div style="margin-top: 10px;font-size: 13px; border-top: 1px solid #ccc;">
		<div style="margin: 10px 0;">自定义范围</div>
		<form id="customDateFilter">
			<div class="form-container" style="display:flex;">
				<input class="filter-date-start" type="date"
					style="border-radius: 2px;border: 1px solid #ddd; line-height: 16px; padding: 5px;" />
				<input class="filter-date-end" type="date"
					style="margin-left: 10px; border-radius: 2px;border: 1px solid #ddd; line-height: 16px; padding: 5px;" />
			</div>
			<div class="form-footer" style="margin: 10px 0; display: flex; justify-content: space-between; align-items: center">
				<span class="validateMessage" style="visibility: hidden; color:red;font-size:12px;">*日期不合法</span>
				<button style="cursor:pointer; padding: 0 10px; min-height: 32px; background-color: #FAFAF9; color: #111; border-radius: 2px; border: 1px solid #ddd;">应用</button>
			</div>
		</form>
	</div>`;

	if (data[type].name == "bing") {
		const cloneFilterItem = filterItem.cloneNode(true);
		cloneFilterItem.style.padding = 0;
		cloneFilterItem.querySelectorAll("a").forEach((item) => {
			item.style.color = "#666";
			item.style.borderRadius = "5px";
			item.addEventListener("mouseover", () => {
				item.style.backgroundColor = "#f5f5f5";
			});
			item.addEventListener("mouseout", () => {
				item.style.backgroundColor = "#ffffff";
			});
		});

		const timeFilterItem = document.createElement("li");
		timeFilterItem.appendChild(cloneFilterItem);
		timeFilterItem.className = data[type].timeFilterClass[1] + " sidebar-filter";
		timeFilterItem.style.marginBottom = "35px";
		timeFilterItem.style.borderRadius = "6px";
		timeFilterItem.style.marginTop = "5px";
		timeFilterItem.style.padding = "10px 20px 5px 20px";
		timeFilterItem.style.border = "1px solid #ddd";

		sidebar.prepend(timeFilterItem);

		const customDateFilter = document.createElement("div");
		customDateFilter.innerHTML = customRangeFilter;
		const innerFilterItem = document.querySelector(data[type].sideBarElement + " .sidebar-filter");
		innerFilterItem.appendChild(customDateFilter);

		const startDateInput = document.querySelector(".filter-date-start");
		const endDateInput = document.querySelector(".filter-date-end");

		startDateInput.addEventListener("change", () => {
			if (!validateDate(startDateInput.value)) {
				startDateInput.value = "";
				return;
			}
		});

		endDateInput.addEventListener("change", () => {
			if (!validateDate(endDateInput.value)) {
				endDateInput.value = "";
				return;
			}
		});

		const rangeFilterBtn = document.querySelector(".form-footer button");
		rangeFilterBtn.addEventListener("click", (e) => {
			e.preventDefault();
			const startDateText = startDateInput.value;
			const endDateText = endDateInput.value;

			if (!startDateText || !endDateText) {
				return;
			}

			const startDayDiff = getDiffDay(startDateText, "1970/1/1");
			const endDayDiff = getDiffDay(endDateText, "1970/1/1");

			urlParams.set("filters", `ex1:"ez5_${startDayDiff}_${endDayDiff}"`);
			window.location.search = urlParams.toString();
		});
	}

	if (data[type].name == "baidu") {
		style.innerHTML += `.sidebar-filter-list li { background-color: #ffffff; padding: 5px; list-style-type: none; cursor: pointer; } .sidebar-filter-list li:hover { background-color: #f1f4fe; color: #2440b3; }`;

		const filterList = document.createElement("ul");
		filterList.className = "sidebar-filter-list";

		const liUnlimited = document.createElement("li");
		const liOneDay = document.createElement("li");
		const liOneWeek = document.createElement("li");
		const liOneMonth = document.createElement("li");
		const liOneYear = document.createElement("li");

		liUnlimited.textContent = "时间不限";
		liOneDay.textContent = "一天内";
		liOneWeek.textContent = "一周内";
		liOneMonth.textContent = "一月内";
		liOneYear.textContent = "一年内";

		liUnlimited.addEventListener("click", () => {
			urlParams.delete("gpc");
			window.location.search = urlParams.toString();
		});
		liOneDay.addEventListener("click", () => {
			const now = new Date();
			const curTimestamp = now.getTime().toString().slice(0, -3);
			const preDay = now.setDate(now.getDate() - 1);
			const preDayTimestamp = preDay.toString().slice(0, -3);

			const rangeTimeStamp = `stf=${preDayTimestamp},${curTimestamp}|stftype=1`;
			urlParams.set("gpc", rangeTimeStamp);
			window.location.search = urlParams.toString();
		});
		liOneWeek.addEventListener("click", () => {
			const now = new Date();
			const curTimestamp = now.getTime().toString().slice(0, -3);
			const preDay = now.setDate(now.getDate() - 7);
			const preDayTimestamp = preDay.toString().slice(0, -3);

			const rangeTimeStamp = `stf=${preDayTimestamp},${curTimestamp}|stftype=1`;
			urlParams.set("gpc", rangeTimeStamp);
			window.location.search = urlParams.toString();
		});
		liOneMonth.addEventListener("click", () => {
			const now = new Date();
			const curTimestamp = now.getTime().toString().slice(0, -3);
			const preMonth = now.setMonth(now.getMonth() - 1);
			const preMonthTimestamp = preMonth.toString().slice(0, -3);

			const rangeTimeStamp = `stf=${preMonthTimestamp},${curTimestamp}|stftype=1`;
			urlParams.set("gpc", rangeTimeStamp);
			window.location.search = urlParams.toString();
		});
		liOneYear.addEventListener("click", () => {
			const now = new Date();
			const curTimestamp = now.getTime().toString().slice(0, -3);
			const preYear = now.setFullYear(now.getFullYear() - 1);
			const preYearTimestamp = preYear.toString().slice(0, -3);

			const rangeTimeStamp = `stf=${preYearTimestamp},${curTimestamp}|stftype=1`;
			urlParams.set("gpc", rangeTimeStamp);
			window.location.search = urlParams.toString();
		});

		filterList.appendChild(liUnlimited);
		filterList.appendChild(liOneDay);
		filterList.appendChild(liOneWeek);
		filterList.appendChild(liOneMonth);
		filterList.appendChild(liOneYear);

		const customDateFilter = document.createElement("div");
		customDateFilter.innerHTML = customRangeFilter;

		const filterSidebarItem = document.createElement("div");
		filterSidebarItem.style.marginBottom = "20px";
		filterSidebarItem.appendChild(filterList);
		filterSidebarItem.appendChild(customDateFilter);

		sidebar.prepend(filterSidebarItem);

		const startDateInput = document.querySelector(".filter-date-start");
		const endDateInput = document.querySelector(".filter-date-end");

		startDateInput.addEventListener("change", () => {
			if (!validateDate(startDateInput.value)) {
				startDateInput.value = "";
				return;
			}
		});

		endDateInput.addEventListener("change", () => {
			if (!validateDate(endDateInput.value)) {
				endDateInput.value = "";
				return;
			}
		});

		const rangeFilterBtn = document.querySelector(".form-footer button");
		rangeFilterBtn.addEventListener("click", (e) => {
			e.preventDefault();
			const startDateText = startDateInput.value;
			const endDateText = endDateInput.value;

			if (!startDateText || !endDateText) {
				return;
			}

			const startDateTimestamp = new Date(startDateText).getTime().toString().slice(0, -3);
			const endDateTimestamp = new Date(endDateText).getTime().toString().slice(0, -3);

			urlParams.set("gpc", `stf=${startDateTimestamp},${endDateTimestamp}|stftype=2`);
			window.location.search = urlParams.toString();
		});
	}

	if (data[type].name == "google") {
		const observer = new MutationObserver(() => {
			filterItem = document.querySelector(data[type].timeFilterClass[0]);

			if (!filterItem) {
				return;
			}

			const filterMenu = filterItem.querySelectorAll("g-menu")[1];

			if (!filterMenu) {
				return;
			}

			const cloneFilterItem = filterMenu.cloneNode(true);
			cloneFilterItem.style.border = "1px solid #dadce0";
			cloneFilterItem.style.boxSizing = "border-box";
			cloneFilterItem.style.borderRadius = "8px";
			cloneFilterItem.style.padding = "5px";
			cloneFilterItem.style.marginBottom = "15px";

			if (!sidebar) {
				sidebar = document.createElement("div");
				sidebar.style.width = "372px";
				sidebar.style.marginLeft = "76px";
				const container = document.querySelector(data[type].container);
				container.appendChild(sidebar);
			}
			sidebar.prepend(cloneFilterItem);
			observer.disconnect();
		});
		observer.observe(document.body, { childList: true, subtree: true });
	}

	if (data[type].name == "yahoo") {
		const cloneFilterItem = filterItem.cloneNode(true);
		cloneFilterItem.className = "";
		cloneFilterItem.style.backgroundColor = "#fcfbfb";
		cloneFilterItem.style.marginBottom = "15px";
		cloneFilterItem.style.padding = "5px";
		cloneFilterItem.style.border = "1px solid rgba(0,0,0,.03)";
		cloneFilterItem.style.borderRadius = "16px";

		sidebar.prepend(cloneFilterItem);
	}

	if (data[type].name == "yandex") {
		style.innerHTML += `.sidebar-filter-list{ margin:0; padding: 10px; background-color: #ffffff; border-radius: 16px; box-shadow: 0 4px 12px 0#0d234308; } .sidebar-filter-list li { background-color: #ffffff; padding: 5px; list-style-type: none; cursor: pointer; } .sidebar-filter-list li:hover { background-color: #f1f4fe; color: #2440b3; }`;

		const filterList = document.createElement("ul");
		filterList.className = "sidebar-filter-list";

		const liUnlimited = document.createElement("li");
		const liOneDay = document.createElement("li");
		const liTwoWeek = document.createElement("li");
		const liOneMonth = document.createElement("li");

		liUnlimited.textContent = "All time";
		liOneDay.textContent = "Last day";
		liTwoWeek.textContent = "Last 2 weeks";
		liOneMonth.textContent = "Last month";

		liUnlimited.addEventListener("click", () => {
			urlParams.delete("within");
			window.location.search = urlParams.toString();
		});
		liOneDay.addEventListener("click", () => {
			urlParams.set("within", "77");
			window.location.search = urlParams.toString();
		});
		liTwoWeek.addEventListener("click", () => {
			urlParams.set("within", "1");
			window.location.search = urlParams.toString();
		});
		liOneMonth.addEventListener("click", () => {
			urlParams.set("within", "2");
			window.location.search = urlParams.toString();
		});

		filterList.appendChild(liUnlimited);
		filterList.appendChild(liOneDay);
		filterList.appendChild(liTwoWeek);
		filterList.appendChild(liOneMonth);

		const filterSidebarItem = document.createElement("div");
		filterSidebarItem.style.marginBottom = "20px";
		filterSidebarItem.appendChild(filterList);

		sidebar.prepend(filterSidebarItem);
	}

	function validateDate(date) {
		const validateMesBlock = document.querySelector(".validateMessage");
		const startDateInput = document.querySelector(".filter-date-start");
		const endDateInput = document.querySelector(".filter-date-end");

		if (isNaN(Date.parse(date))) {
			validateMesBlock.innerText = "*日期不合法";
			validateMesBlock.style.visibility = "visible";
			return false;
		}

		if (startDateInput.value && endDateInput.value && startDateInput.value > endDateInput.value) {
			validateMesBlock.innerText = "*开始日期不能大于结束日期";
			validateMesBlock.style.visibility = "visible";
			return false;
		}

		validateMesBlock.style.visibility = "hidden";
		return true;
	}

	function getDiffDay(startDate, endDate) {
		const oneDay = 1000 * 60 * 60 * 24;
		const timestamp = Date.parse(startDate) - Date.parse(endDate);
		return Math.floor(timestamp / oneDay);
	}
})();