Bing 时光机

随意跳转必应不同时间搜索结果

  1. // ==UserScript==
  2. // @name Bing 时光机
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.3
  5. // @description 随意跳转必应不同时间搜索结果
  6. // @author hzhbest
  7. // @match https://*.bing.com/search?*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=bing.com
  9. // @grant none
  10. // @license GNU GPLv3
  11. // ==/UserScript==
  12.  
  13. (function () {
  14. 'use strict';
  15.  
  16. // 根据 location.href 识别日期区间搜索行为
  17. // https://www.bing.com/search?q=AAAA&filters=ex1%3a%22ez5_18993_19052%22
  18. // 其中,“q=”后面是关键词,“filters=”后面是结果过滤,“ex1%3a%22ez5……%22”是日期区间的标识
  19. // 识别搜索关键词 kw 和日期区间始末点 qiri 和 vsri
  20. // 构建时光机框【divMain【labelTitle】【labelStart】【inputStart】【labelEnd】【inputEnd】【divBtnGo】】
  21. // 转换 qiri 和 vsri 为日期格式(yyyy-m-d)文本 qistr 和 vsstr 并放入 inputStart 和 inputEnd 中
  22. // 点 divBtnGo 时,补全两 input* 中的 *str 为日期格式,并转换为日期数 *ri,与 kw 重组新网址,并当前页面加载
  23.  
  24. const d0 = Date.parse('1970-1-1');
  25. const msxd = 24 * 60 * 60 * 1000;
  26. const units = ['天', '周', '月', '年'];
  27. let divMain = document.body.appendChild(document.createElement('div'));
  28. divMain.id = 'TM_Main';
  29. setTimeout(init, 2000);
  30.  
  31. let csstxt = `
  32. .TM_Main {position: fixed; top: 100px; left: 0px; z-index: 100000; background: #fff;
  33. padding: 4px; border: 1px solid #ddd; font-size: 14pt; width: 115px; overflow: hidden;
  34. transition: width 0.2s linear 3s;}
  35. .TM_Main:hover {width: 190px; transition: width 0.2s linear 0s; box-shadow: 0 1px 12px 4px #ccc;}
  36. .TM_Title {font-size: 15pt; font-weight: bold;}
  37. .TM_Label {overflow: hidden; white-space: nowrap; display: block; color: #969696; padding-top: 9px;}
  38. .TM_Input {width: 180px; font-size: larger; border-bottom: 1px solid #cecece;
  39. border-top: none; border-left: none; border-right: none; margin-bottom: 1px;}
  40. .TM_Input:hover {border-bottom: 2px solid #878787; margin-bottom: 0px;}
  41. .TM_ilbox {width: 185px; padding-top: 9px;}
  42. #TM_last, #TM_unit {display: inline;}
  43. #TM_last {width: 40px;}
  44. .TM_Main:hover #TM_last {width: 65px;}
  45. #TM_unit {width: 45px; margin-left: 5px; outline: none; background: transparent;
  46. border-bottom: 1px solid #cecece; border-top: none; border-left: none; border-right: none;}
  47. #TM_unit:hover {border-bottom: 2px solid #878787;}
  48. .TM_Button {margin:5px; padding: 0px 5px; width: 50px; height: 50px;
  49. cursor: default; position: absolute; left: 120px; bottom: 3px;
  50. text-align: center; background: #f5f5f5;}
  51. .TM_Button:hover {outline: 2px solid #99e; background: #eef; color: black;}
  52. .TM_Button:active {outline: 2px solid #22f; background: #cce;}
  53. `;
  54. addCSS(csstxt);
  55.  
  56.  
  57. function init() {
  58. let kw, qiri, vsri, arri;
  59. let lTitle, lKword, inKword, lLast, inLast, seUnit, lStart, lEnd, inStart, inEnd, divBtnGo;
  60.  
  61. lTitle = creaElemIn('label', divMain);
  62. lKword = creaElemIn('label', divMain);
  63. inKword = creaElemIn('input', divMain);
  64. let inlinebox = creaElemIn('div', divMain);
  65. lLast = creaElemIn('label', inlinebox);
  66. inLast = creaElemIn('input', inlinebox);
  67. seUnit = creaElemIn('select', inlinebox);
  68. units.forEach(unit => {
  69. let opUnit = creaElemIn('option', seUnit);
  70. opUnit.value = unit;
  71. opUnit.innerHTML = unit;
  72. });
  73. lStart = creaElemIn('label', divMain);
  74. inStart = creaElemIn('input', divMain);
  75. lEnd = creaElemIn('label', divMain);
  76. inEnd = creaElemIn('input', divMain);
  77. divBtnGo = creaElemIn('div', divMain);
  78.  
  79. lTitle.innerHTML = "Bing时光机";
  80. lKword.innerHTML = "搜索关键词";
  81. lLast.innerHTML = "最近:";
  82. lStart.innerHTML = "开始日期";
  83. lEnd.innerHTML = "结束日期";
  84. divBtnGo.innerHTML = "立即穿梭";
  85. inKword.title = "在此输入关键词,跟随时光机穿梭!";
  86. inLast.title = "在此输入数字,可用鼠标滚轮增减";
  87. seUnit.title = "在此选择时间单位,可用鼠标滚轮切换";
  88. inStart.title = "开始日期,可只输年份或年月,可用鼠标滚轮增减月份";
  89. inEnd.title = "结束日期,可只输年份或年月,可用鼠标滚轮增减月份";
  90.  
  91. inKword.id = 'TM_kword';
  92. inStart.id = 'TM_start';
  93. inEnd.id = 'TM_end';
  94. inLast.id = 'TM_last';
  95. seUnit.id = 'TM_unit';
  96. divMain.className = 'TM_Main';
  97. lTitle.className = 'TM_Title';
  98. lKword.className = lStart.className = lEnd.className = 'TM_Label';
  99. lLast.className = 'TM_llast';
  100. inKword.className = inStart.className = inEnd.className = inLast.className = 'TM_Input';
  101. inlinebox.className = 'TM_ilbox';
  102. inLast.value = 1;
  103.  
  104. var wheelEvt = "onwheel" in document.createElement("div") ? "wheel" : (document.onmousewheel !== undefined ? "mousewheel" : "DOMMouseScroll"); //compatibility fix for Chrome-core browsers
  105. inLast.addEventListener(wheelEvt, changenumber);
  106. inLast.addEventListener('input', refreshLastdate);
  107. inLast.addEventListener('keypress', submit);
  108. seUnit.addEventListener(wheelEvt, changeunit);
  109. seUnit.addEventListener('change', refreshLastdate);
  110. inStart.addEventListener(wheelEvt, changemonth);
  111. inEnd.addEventListener(wheelEvt, changemonth);
  112. inStart.addEventListener('blur', checkdate);
  113. inEnd.addEventListener('blur', checkdate);
  114. inStart.addEventListener('keypress', submit);
  115. inEnd.addEventListener('keypress', submit);
  116. inKword.addEventListener('keypress', submit);
  117. divBtnGo.className = 'TM_Button';
  118. divBtnGo.addEventListener('click', go);
  119.  
  120. kw = getkw(location.href);
  121. inKword.value = decodeURI(kw);
  122.  
  123. arri = getds(location.href); //console.log(arri);
  124. qiri = arri[0];
  125. vsri = arri[1];
  126. let edate, sdate;
  127. if (qiri == 0 || vsri == 0) {
  128. edate = new Date();
  129. sdate = new Date(edate - 180 * msxd);
  130. } else {
  131. edate = numTOdate(vsri);
  132. sdate = numTOdate(qiri);
  133. }
  134. inEnd.value = edate.getFullYear() + "-" + (edate.getMonth() + 1) + "-" + edate.getDate();
  135. inStart.value = sdate.getFullYear() + "-" + (sdate.getMonth() + 1) + "-" + sdate.getDate();
  136. }
  137.  
  138. function go() { //点“穿梭”按钮后以时光机内的关键词和日期进行跳转(若关键词为空则使用当前关键词)
  139. let inS = document.querySelector('#TM_start');
  140. let inE = document.querySelector('#TM_end');
  141. let inK = document.querySelector('#TM_kword');
  142. let ednum, sdnum;
  143. ednum = dateTOnum(fulldate(inE.value, true));//console.log(ednum);
  144. sdnum = dateTOnum(fulldate(inS.value, false));//console.log(sdnum);
  145. let kw = inK.value || getkw(location.href);
  146. window.location.href = "https://www.bing.com/search?q=" + kw + "&filters=ex1%3a%22ez5_" + sdnum + "_" + ednum + "%22";
  147. }
  148.  
  149. function changemonth(e) {
  150. e.preventDefault();
  151. e.stopPropagation();
  152. let isend = (e.target.id == 'TM_end') ? true : false;
  153. let cdate = new Date(fulldate(e.target.value, isend));
  154. let ddate = dateUnitConv(cdate, wheelToNum(e), "月");
  155. e.target.value = dateToStr(ddate);
  156. }
  157.  
  158. function changenumber(e) {
  159. e.preventDefault();
  160. e.stopPropagation();
  161. let c = parseInt(e.target.value);
  162. e.target.value = wheelToNum(e, c);
  163. refreshLastdate();
  164. }
  165.  
  166. function refreshLastdate() {
  167. let inS = document.querySelector('#TM_start');
  168. let inE = document.querySelector('#TM_end');
  169. let inL = document.querySelector('#TM_last');
  170. let seU = document.querySelector('#TM_unit');
  171. let cdate = new Date();
  172. inE.value = dateToStr(cdate);
  173. let ddate = dateUnitConv(cdate, -inL.value, seU.value);
  174. inS.value = dateToStr(ddate);
  175. }
  176.  
  177. function changeunit(e) {
  178. e.preventDefault();
  179. e.stopPropagation();
  180. let seU = e.target;
  181. let c = seU.selectedIndex;
  182. c = wheelToNum(e, c);
  183. if (c >= seU.options.length) {
  184. c = 0;
  185. } else if (c < 0) {
  186. c = seU.options.length - 1;
  187. }
  188. seU.selectedIndex = c;
  189. refreshLastdate();
  190. }
  191.  
  192. function checkdate(e) {
  193. let t = e.target;
  194. let d = fulldate(t.value, t.id == "TM_end");
  195. t.value = dateToStr(d);
  196. }
  197.  
  198. function submit(e) {
  199. if (e.which == 10 || e.which == 13) {
  200. go();
  201. }
  202. }
  203.  
  204. // https://cn.bing.com/search?q=js&filters=ex1%3a%22ez5_19327_19359%22
  205. function getkw(url) { //从url中提取关键词
  206. let exp = /(?<=q\=)[^&]+(?=&?)/i;
  207. return exp.exec(url)[0];
  208. }
  209.  
  210. function getds(url) { //从url中提取日期数数组[qiri,vsri]
  211. let exp = /(?<=filters\=ex1\%3a\%22ez5_)[\d_\.]+(?=\%22)/i; //不知为啥有时候出的日期会带小数点……
  212. let ds = exp.exec(url); console.log(ds);
  213. if (!!ds) {
  214. return ds[0].split("_"); //正则匹配出的是结果的“数组”,因此第一匹配结果需要是数组index 0的元素
  215. } else {
  216. return "0_0".split("_");
  217. }
  218. }
  219.  
  220.  
  221. function wheelToNum(e, initval) {
  222. console.log(e.deltaY);
  223. let v = initval || 0;
  224. return ((e.deltaY > 0) ? 1 : -1) + v;
  225. }
  226.  
  227. function dateUnitConv(sdate, num, unit) {
  228. let y = sdate.getFullYear(), m = sdate.getMonth(), d = sdate.getDate();
  229. switch (unit) {
  230. case "天":
  231. return new Date(y, m, d + num);
  232. case "周":
  233. return new Date(y, m, d + num * 7);
  234. case "月":
  235. return new Date(y, m + num, d);
  236. case "年":
  237. return new Date(y + num, m, d);
  238. }
  239. }
  240.  
  241. function dateToStr(ddate) {
  242. return ddate.getFullYear() + "-" + (ddate.getMonth() + 1) + "-" + ddate.getDate();
  243. }
  244.  
  245. function fulldate(str, isend) { //将文本补全为“yyyy-m-d”格式,并输出日期,其中要补全的文本必须有四位年,可缺日或缺月日,即“yyyy”、“yyyy-m”格式
  246. let odate, oy, om, od;
  247. let ard = str.split('-');
  248. if (ard.length == 1) { // 只有年的话,非结尾则输出1月1日,结尾输出12月31日
  249. om = (isend) ? 11 : 0;
  250. od = (isend) ? 31 : 1;
  251. odate = new Date(parseInt(str), om, od);
  252. } else if (ard.length == 2) { // 只有年月的话,非结尾输出当月1日,结尾输出当月末日(下月0日)
  253. oy = parseInt(ard[0]);
  254. om = parseInt(ard[1]) - 1;
  255. odate = (isend) ? new Date(oy, om + 1, 0) : new Date(oy, om, 1);
  256. } else {
  257. odate = Date.parse(str) // 年月日皆有则直接输出
  258. }
  259. return odate;
  260. }
  261.  
  262. function dateTOnum(odate) { //日期转换成日数
  263. return (odate - d0) / msxd;
  264. }
  265.  
  266. function numTOdate(onum) { //日数转换为日期对象
  267. return new Date(d0 + onum * msxd);
  268. }
  269.  
  270. function creaElemIn(tagname, destin) {
  271. let theElem = destin.appendChild(document.createElement(tagname));
  272. return theElem;
  273. }
  274.  
  275. function addCSS(css) {
  276. let stylenode = creaElemIn('style', document.getElementsByTagName('head')[0]);
  277. stylenode.textContent = css;
  278. stylenode.type = 'text/css';
  279. stylenode.id = 'ali_c_toc';
  280. }
  281.  
  282.  
  283.  
  284.  
  285. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址