FaviconizeGoogle

Adds favicons next to Google search results. Also works for Ecosia.

目前为 2019-10-14 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name FaviconizeGoogle
  3. // @namespace http://userscripts.org/users/89794 (joeytwiddle)
  4. // @description Adds favicons next to Google search results. Also works for Ecosia.
  5. // @homepage https://gf.qytechs.cn/en/scripts/7664-faviconizegoogle
  6. // @downstreamURL http://userscripts.org/scripts/source/48636.user.js
  7. // @license ISC
  8. // @version 1.4.8
  9. // @include /https?:\/\/((www\.)?|encrypted\.)google\.[a-z]{2,3}(\.[a-z]{2})?\/(search|webhp|\?gws_rd|\?gfe_rd)?.*/
  10. // @exclude /https?:\/\/(www\.|[a-z0-9-]*\.)?startpage\.com\/.*/
  11. // @include /https?:\/\/www\.ecosia\.org\/(search|news|videos)?.*/
  12. // @grant none
  13. // ==/UserScript==
  14.  
  15. var placeFaviconByUrl = false; // The little green link below the article title
  16. var placeFaviconAfter = false; // Display after the link instead of before it
  17. var placeFaviconInsideLink = false; // Makes the favicon clickable but may also get underlined
  18. var placeFaviconOffTheLeft = true; // Makes the favicon sit out to the left of the main column (not on startpage)
  19. var iconSize = 1.3;
  20. var centraliseIconVertically = iconSize < 2; // For smaller icon sizes, we center-align with the text, for larger we top-align
  21.  
  22. // With thanks to:
  23. // - NV
  24. // - darkred
  25. // - SirCumference
  26.  
  27. // Some alternatives/remixes:
  28. // - https://github.com/NV/faviconize-google.js (Chrome extension)
  29. // - https://gf.qytechs.cn/en/scripts/12395-google-favicons (works with Endless Google)
  30. // - https://gist.github.com/Sir-Cumference/223d36cbec6473b0e6927e5c50c11568 (very short code, @match works with Greasemonkey)
  31.  
  32. // 2018-10-14 Added support for ecosia.org!
  33. // 2018-10-14 Disabled startpage.com, because their CSP has blocked favicons from loading.
  34. // 2018-07-31 Dropped support for news.google.com, because it is now linking to local URLs, instead of to external websites.
  35.  
  36. // TODO: The relative positioning of the icon appears a bit off for sub-links of the main result.
  37.  
  38. // DONE: Provided more options where to place favicon: by the link or by the
  39. // url, before or after, inside or outside the link. However in my opinion
  40. // they all suck except the default. ;)
  41.  
  42. // Broken images would be messy, but Firefox seems to hide them after a while
  43. // anyway. We do still see the gap from the image's padding though!
  44. // It might be desirable to check each image actually exists/loads, or remove it.
  45. // Is that possible, without making an http request ourselves?
  46.  
  47. // Third-party host URL detection is implemented leniently, and accordingly
  48. // hostname extraction implemented aggressively, which results in favicons
  49. // being given to unexpected things like bookmarklets which contain a site url.
  50.  
  51. if (document.location.host.match(/\bstartpage\b/)) {
  52. // This feature doesn't work on startpage!
  53. placeFaviconOffTheLeft = false;
  54. }
  55.  
  56. if (document.location.search.match(/&tbm=nws/)) {
  57. // This feature doesn't work on Google News search
  58. placeFaviconOffTheLeft = false;
  59. // The layout is a bit too cramped for large favicons
  60. iconSize = 0.9;
  61. }
  62.  
  63. function createFaviconFor (url) {
  64. var host = url.replace(/^[^/]*:\/\//, '').replace(/\/.*$/, '');
  65. // if (host == document.location.host) {
  66. // return null;
  67. // }
  68. // Use protocol (http/https) of current page, to avoid mixed-content warnings/failures.
  69. //var protocol = document.location.protocol.replace(/:$/, '');
  70. //console.log("[FaviconizeGoogle.user.js] protocol:" ,protocol);
  71. // We may fail to access favicons, e.g. if the site only offers http, or due to CORS restrictions.
  72. // But it is still worth tryiing, because the fallback (google's s2) offers only low-res icons.
  73. var urlsToTry = [
  74. '//' + host + '/favicon.ico',
  75. '//' + host + '/favicon.png',
  76. '//www.google.com/s2/favicons?domain=' + host,
  77. ];
  78. // Google's cache will sometimes provide a favicon we would have missed, e.g. if the site uses .png instead of .ico. Thanks to NV for suggesting this, and to Google.
  79. var img = document.createElement('IMG');
  80. //img.src = protocol + '://'+host+'/favicon.ico';
  81. //img.src = '//g.etfv.co/http://" + host; // As suggested by decembre
  82. //img.width = '16';
  83. //img.height = '16';
  84. img.className = 'favicon';
  85. img.border = 0;
  86. img.style.display = 'none';
  87. var tryNextExtension = function () {
  88. if (urlsToTry.length === 0) {
  89. removeListeners();
  90. return;
  91. }
  92. img.src = urlsToTry.shift();
  93. };
  94. var showImage = function () {
  95. img.style.display = '';
  96. removeListeners();
  97. };
  98. var removeListeners = function () {
  99. img.removeEventListener('load', showImage);
  100. img.removeEventListener('error', tryNextExtension);
  101. };
  102. img.addEventListener('load', showImage, false);
  103. img.addEventListener('error', tryNextExtension, false);
  104. tryNextExtension();
  105. return img;
  106. }
  107.  
  108. function getGoogleResultsLinks () {
  109. // var links = document.evaluate("//a[@class='l']",document,null,6,null);
  110. // var links = filterListBy(document.links, function(x){ return x.className=='l'; } );
  111. // var links = document.links.filter( function(x){ return x.className=='l'; } );
  112.  
  113. /*
  114. return filterListBy(document.getElementsByTagName('a'), function (x) {
  115. // Most pages show links with class 'l'
  116. // But on pages where the first result has an indented block of sub-pages,
  117. // the indented links have class 'l' but all the other links have no class but parent class 'r'
  118. return x.className === 'l' || x.parentNode.className === 'r';
  119. });
  120. */
  121.  
  122. // For Google search
  123. // a.l
  124. // a.fl are small one-line sub-results. Search "squeak" and see the Wikipedia result.
  125. // a.B0IOdd are lists of images which appear underneath a section on the News tab (inside .card-section)
  126. var links = document.querySelectorAll('.g a:not(.fl):not(.B0IOdd)');
  127.  
  128. // For news.google.com
  129. if (links.length === 0) {
  130. //links = document.querySelectorAll('a.article:not(.esc-thumbnail-link)');
  131. links = document.querySelectorAll('article > a');
  132. }
  133.  
  134. // For startpage.com
  135. if (links.length === 0) {
  136. //links = document.querySelectorAll('.clk > a');
  137. links = document.querySelectorAll('.w-gl__result-title');
  138. }
  139.  
  140. // For ecosia.org
  141. if (links.length === 0) {
  142. links = document.querySelectorAll('.result-title');
  143. }
  144.  
  145. // Remove any links which contain only one image
  146. links = [...links].filter(link => {
  147. if (link.childNodes.length === 1 && link.childNodes[0].tagName === 'IMG') {
  148. return false;
  149. }
  150. return true;
  151. });
  152.  
  153. return links;
  154. }
  155.  
  156. var style = document.createElement('STYLE');
  157. var padSide = (placeFaviconAfter ? 'left' : 'right');
  158. var leftPadding = 1.2 * iconSize + 0.6;
  159. // We can try to centralise the icon with the text
  160. // Or we can top-align the icon with the text (better for larger icon sizes)
  161. var topPadding = centraliseIconVertically ? 0.95 - iconSize / 2 : 0.35;
  162. var extra = placeFaviconOffTheLeft ? 'position: absolute; left: -' + leftPadding + 'em; top: ' + topPadding + 'em;' : '';
  163. if (document.location.hostname === 'www.ecosia.org') {
  164. var topMargin = 0.1 + centraliseIconVertically * iconSize / 13;
  165. // Cancel the above padding (it stretches the icon on ecosia)
  166. // Use margin for vertical positioning
  167. extra += ' padding: 0; margin-top: ' + (-topMargin) + 'em;';
  168. }
  169. // If we are using placeFaviconOffTheLeft, then we don't need the paddings or alignment here
  170. style.innerHTML = ".favicon { padding-" + padSide + ": " + (iconSize / 2) + "em; vertical-align: middle; width: " + iconSize + "em; height: " + iconSize + "em; padding-bottom: 0.2em; " + extra + "}";
  171. document.getElementsByTagName('head')[0].appendChild(style);
  172.  
  173. function updateFavicons () {
  174. var links = getGoogleResultsLinks();
  175.  
  176. // Allows it to work on any sites:
  177. if (links.length === 0) {
  178. links = document.getElementsByTagName("A");
  179. }
  180. //console.log("Got links:", links);
  181.  
  182. // for (var i=0;i<links.snapshotLength;i++) {
  183. // var link = links.snapshotItem(i);
  184. for (var i = 0; i < links.length; i++) {
  185. var link = links[i];
  186. // if (link.href.match('^javascript:') || link.href.match('^#')) {
  187. // continue;
  188. // }
  189. var targetUrl = link.getAttribute('data-href') || link.href;
  190. //// Skip relative and same-host links:
  191. if (targetUrl.match(/^[/]/) || targetUrl.match("://" + document.location.host)) {
  192. continue;
  193. }
  194. //console.log("[faviconizegoogle.user.js] link.getAttribute(data-faviconized):" ,link.getAttribute("data-faviconized"));
  195. if (link.getAttribute("data-faviconized")) {
  196. // Already faviconized
  197. //console.log("[faviconizegoogle.user.js] Skipping");
  198. continue;
  199. }
  200. link.setAttribute("data-faviconized", "yes");
  201. var img = createFaviconFor(targetUrl);
  202. // <cite> is for google, .url is for startpage
  203. var targetNode = (placeFaviconByUrl && link.parentNode.parentNode.querySelector('cite, .url') || link);
  204. if (placeFaviconInsideLink) {
  205. if (placeFaviconAfter) {
  206. targetNode.appendChild(img);
  207. } else {
  208. targetNode.insertBefore(img, targetNode.firstChild);
  209. }
  210. } else {
  211. if (placeFaviconAfter) {
  212. targetNode.parentNode.insertBefore(img, targetNode.nextSibling);
  213. } else {
  214. targetNode.parentNode.insertBefore(img, targetNode);
  215. }
  216. }
  217. }
  218. }
  219.  
  220. // TODO: Use MutationObserver instead?
  221.  
  222. var last_srg = null;
  223. var results_count = -1;
  224.  
  225. function checkForUpdate () {
  226. // #ires was needed for the News tab, which doesn't have a .srg. Perhaps we could use ires for all tabs.
  227. var new_srg = document.querySelector('.srg') || document.querySelector('#ires');
  228. // startpage
  229. new_srg = new_srg || document.querySelector('.w-gl--default');
  230. // ecosia
  231. new_srg = new_srg || document.querySelector('.mainline');
  232. //console.log("[FaviconizeGoogle.user.js] last_srg:" ,last_srg);
  233. //console.log("[faviconizegoogle.user.js] new_srg:" ,new_srg);
  234. var new_results_count = getGoogleResultsLinks().length;
  235. if (new_srg !== last_srg || new_results_count !== results_count) {
  236. //console.log("Page change detected!");
  237. updateFavicons();
  238. last_srg = new_srg;
  239. results_count = new_results_count;
  240. } else {
  241. //console.log("Pages are the same:", last_srg, new_srg);
  242. }
  243. setTimeout(checkForUpdate, 1000);
  244. }
  245.  
  246. setTimeout(checkForUpdate, 100);

QingJ © 2025

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