Bing Search AutoPager

必应自动翻页,网站预览图。

  1. // ==UserScript==
  2. // @name Bing Search AutoPager
  3. // @author Crab
  4. // @namespace autopager@bing.com
  5. // @description 必应自动翻页,网站预览图。
  6. // @include /^https?:\/\/[^\.]+\.bing\.com\/search\?.*/
  7. // @version 0.7
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. var loadingBar = null,
  12. scrollTimeout = null,
  13. originList = document.querySelectorAll('#b_results>li'),//初始页列表
  14. currentList = document.getElementsByClassName('b_algo'),//结果列表,live HTMLCollection
  15. resultsLength = currentList.length,
  16. queryString = location.search.match(/q=[^&]+/)[0],
  17. pageNum = Math.floor(((location.search.match(/&first=(\d+)/) || [0, 0])[1] - 0) / resultsLength + 1), //初始页码
  18. imagesList = [],
  19. isLastPage = false;
  20.  
  21. var cE = function(name, attr, parent){
  22. var e = document.createElement(name);
  23. for (var i in attr || [])
  24. i == 'text' ? (e.textContent = attr[i]) : e.setAttribute(i, attr[i]);
  25. parent && (Array.isArray(parent) ?
  26. parent[0].insertBefore(e, parent.length == 2 ? parent[1] : parent[0].firstChild) :
  27. parent.appendChild(e));
  28. return e;
  29. }, addPreviews = function(list){
  30. [].forEach.call(list, function(li){
  31. var match = li.querySelector('h2>a').href.match(/https?:\/\/([^\/]+)/);
  32. imagesList.push(cE('img', {align: 'left', 'pic-src': 'https://'+ match[1].charAt(0) + '.searchpreview.de/preview?s='+ match[0] +'&ra=0'}, [li]));
  33. });
  34. }, toggleLoadingBar = function(show){
  35. (loadingBar || (loadingBar = cE('div', {id:'loadingBar'}, cE('li', null, [currentList[0].parentNode, currentList[0].parentNode.lastElementChild.previousElementSibling]))))
  36. .classList[show ? 'add' : 'remove']('loading');
  37. }, getNextPageData = function(url, callback){
  38. var req = new XMLHttpRequest();
  39. req.open('GET', url, true);
  40. req.send();
  41. req.onload = function(){
  42. callback((new DOMParser()).parseFromString(req.responseText, 'text/html'));
  43. };
  44. }, nextPage = function(){
  45. toggleLoadingBar(true);
  46. var url = 'search?pc=MOZI&first='+ (pageNum * resultsLength + 1) + '&' + queryString;
  47. getNextPageData(url, function(doc){
  48. //修复自带预览图
  49. [].forEach.call(doc.querySelectorAll('body>script:not([src]):not([data-rms])'), function(s){
  50. var match = s.textContent.match(/x=_ge\('(emb\d+)'\);if\(x\)\{x\.src='(data:image[^']+)/);
  51. if(match) doc.getElementById(match[1]).src = match[2];
  52. });
  53. var df = document.createDocumentFragment(),
  54. last = currentList[currentList.length - 1];
  55. [].forEach.call(doc.querySelectorAll('#b_results>.b_algo'), df.appendChild.bind(df));
  56. //添加预览图
  57. addPreviews(df.children);
  58. //往最后结果后面插入
  59. last.parentNode.insertBefore(df, last.nextElementSibling);
  60. //替换新页码
  61. var pageNumMenu = doc.getElementById('b_results').lastElementChild;
  62. last.parentNode.replaceChild(pageNumMenu, last.parentNode.lastElementChild);
  63. //更新地址
  64. history.pushState({}, doc.title, url);
  65. toggleLoadingBar();
  66. onScroll();
  67. if(!pageNumMenu.querySelector('nav[role="navigation"]') ||
  68. pageNumMenu.querySelector('nav>ul>li:last-of-type>a:not([href])')){
  69. return (isLastPage = true) && !imagesList.length && removeEventListener('scroll', onScroll); //图片都加载完成 最后一页
  70. }else{
  71. isLastPage = false;
  72. }
  73. pageNum++;
  74. });
  75. }, onResize = function(){
  76. var b_context = document.getElementById('b_context'), //右侧栏高度
  77. li_ch = 0, //第一页搜索项累计高
  78. isMaxWidth = document.documentElement.clientWidth < 800;
  79. onScroll();
  80. b_context.classList[isMaxWidth ? 'remove' : 'add']('b_resize');
  81. b_context.style.width = isMaxWidth ? 'auto' : '250px';
  82. [].forEach.call(originList, function(li){
  83. li.style.width = (li_ch < b_context.clientHeight) ? (isMaxWidth ? '' : 'calc(90% - '+ b_context.clientWidth +'px)') : '';
  84. li_ch += li.clientHeight;
  85. });
  86. }, onScroll = function(){
  87. clearTimeout(scrollTimeout);
  88. scrollTimeout = setTimeout(function(){
  89. var de = document.documentElement;
  90. if(!de.scrollTop) de = document.body;//兼容chrome
  91. !isLastPage && de.scrollTop + window.innerHeight > de.scrollHeight - 5 && nextPage();
  92. //lazyload
  93. var loadedList = [];
  94. imagesList.forEach(function(img){
  95. var r = img.getBoundingClientRect();
  96. if(r.bottom >= 0 && window.innerHeight >= r.top){
  97. loadedList.push(img);
  98. img.parentNode.classList.add('loading');
  99. img._loadCount = 0;
  100. img.onload = function(){
  101. this.parentNode.classList.remove('loading');
  102. this.onload = this.onerror = null;
  103. };
  104. //首字母递增重试5次
  105. img.onerror = function(){
  106. this._loadCount++;
  107. if(this._loadCount > 4) return this.onload();
  108. this.src = this.src.replace(/.(?=\.)/, function(s){
  109. s = s.charCodeAt();
  110. return String.fromCharCode(((s >= 48 && s < 57) || (s >= 97 && s < 122)) ? s + 1 : (s == 57 ? 97 : 48));
  111. });
  112. };
  113. img.src = img.getAttribute('pic-src');
  114. img.removeAttribute('pic-src');
  115. }
  116. });
  117. loadedList.forEach(function(img){
  118. imagesList.splice(imagesList.indexOf(img), 1);
  119. });
  120. }, 300);
  121. };
  122.  
  123. var cssText = (function(){/*
  124. #b_content{
  125. padding: 0px 0px 20px 5%!important;
  126. }
  127. #b_results{
  128. width:95%;
  129. }
  130. .b_navbar {
  131. width: auto!important;
  132. }
  133. #b_context.b_resize {
  134. position: absolute;
  135. right: 5%;
  136. }
  137.  
  138. // 序号
  139. body {
  140. counter-reset: resultNum;
  141. min-width: 600px!important;
  142. --loading-spinner: url('data:image/gif;base64,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') no-repeat center;
  143. }
  144. #b_results .b_algo h2::before{
  145. content: counter(resultNum) ". ";
  146. counter-increment: resultNum;
  147. color: #000 !important;
  148. }
  149.  
  150. .b_algo .b_title .b_imagePair, .b_ans .b_title .b_imagePair {
  151. display: block;
  152. }
  153. .b_algo>img{
  154. width:111px;
  155. height:82px;
  156. border: 1px solid #BBB;
  157. margin: 2px 4px 5px 0px;
  158. }
  159. .b_algo>.b_title, .b_algo>.b_caption{
  160. text-overflow: ellipsis;
  161. overflow: hidden;
  162. }
  163. .b_algo{
  164. position: relative;
  165. }
  166. .b_algo.loading::before{
  167. content: '';
  168. position: absolute;
  169. left: 21px;
  170. top: 10px;
  171. width: 111px;
  172. height: 82px;
  173. background: rgba(255,255,255,.8) var(--loading-spinner);
  174. }
  175. .b_algo>img{
  176. opacity:1;
  177. transition: opacity 500ms ease-in-out 0s;
  178. }
  179. .b_algo.loading>img{
  180. opacity:.3;
  181. }
  182. #loadingBar{
  183. width: 32px;
  184. height: 32px;
  185. margin-left: calc(50% - 16px);
  186. background: var(--loading-spinner);
  187. }
  188. #loadingBar:not(.loading){
  189. display:none;
  190. }
  191. */}).toString().replace(/^.*|\/\/.*|.*\}$/g, '');
  192. if(navigator.userAgent.indexOf('WebKit')>-1 || //chrome 还不支持css变量;
  193. navigator.userAgent.indexOf('Firefox')>-1 &&
  194. parseInt(navigator.userAgent.match(/Firefox\/(\d+)/)[1]) < 31 //FF31下不支持标准css变量
  195. ){
  196. cssText = cssText.replace(/var\(--loading-spinner\)/g, cssText.match(/--loading-spinner\s*:(.*)/)[1]);
  197. }
  198. cE('style', {text: cssText}, document.head);
  199.  
  200. //noreferrer
  201. cE('meta', {name: 'referrer', content: 'never'}, document.head);
  202. //第一页预览
  203. addPreviews(currentList);
  204. onResize();
  205. onScroll();
  206. addEventListener('resize', onResize);
  207. addEventListener('scroll', onScroll);