Reddit on Google Search (forked from Alexyoe's original script)

Adds a button to search Reddit via Google Search

  1. // ==UserScript==
  2. // @name Reddit on Google Search (forked from Alexyoe's original script)
  3. // @version 1.1.0
  4. // @description Adds a button to search Reddit via Google Search
  5. // @author mefengl (original author: Alexyoe)
  6. // @namespace https://github.com/mefengl/Reddit-on-Google-Search
  7. // @license MIT
  8. // @include http*://www.google.*/search*
  9. // @include http*://google.*/search*
  10. // @run-at document-end
  11. // @grant GM_getValue
  12. // @grant GM_setValue
  13. // @grant GM_registerMenuCommand
  14. // ==/UserScript==
  15.  
  16. function useOption(optionName, defaultValue, type = "boolean", enumOptions = []) {
  17. let value = GM_getValue(optionName, defaultValue);
  18.  
  19. if (type === "boolean") {
  20. GM_registerMenuCommand(`Toggle ${optionName} (currently ${value ? "Enabled" : "Disabled"})`, () => {
  21. GM_setValue(optionName, !value);
  22. window.location.reload();
  23. });
  24. } else if (type === "enum") {
  25. GM_registerMenuCommand(`Cycle ${optionName} (currently ${value})`, () => {
  26. const currentIndex = enumOptions.indexOf(value);
  27. const nextIndex = (currentIndex + 1) % enumOptions.length;
  28. GM_setValue(optionName, enumOptions[nextIndex]);
  29. window.location.reload();
  30. });
  31. }
  32.  
  33. return value;
  34. }
  35.  
  36. // Settings
  37. const iconVisible = useOption("iconVisible", true); // Toggle icon visibility
  38. const nameVisible = useOption("nameVisible", true); // Toggle name visibility
  39. const btnPosition = useOption("btnPosition", "end", "enum", ["start", "end"]); // Start or End
  40. const fixSize = useOption("fixSize", false); // Expands the search buttons bar
  41.  
  42. // Start Code
  43. const queryRegex = /q=[^&]+/g;
  44. const siteRegex = /\+site(?:%3A|\:).+\.[^&+]+/g;
  45. const redditUrl = "+site%3Areddit.com";
  46. const hackerNewsUrl = "+site%3Anews.ycombinator.com";
  47. let redditIcon =
  48. '<svg class="DCxYpf" foscusable="false" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="..."></path></svg>';
  49. let hackerNewsIcon =
  50. '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 512 512"><path d="M416 96v320H96V96h320m32-32H64v384h384V64z" fill="currentColor"/><path d="M296.7 159H342l-63.9 120v72h-39.9v-72L172 159h47.1l39.7 83.6 37.9-83.6z" fill="currentColor"/></svg>';
  51. const isImageSearch = /[?&]tbm=isch/.test(location.search);
  52.  
  53. // Allow importing SVG
  54. if (typeof trustedTypes !== "undefined") {
  55. const policy = trustedTypes.createPolicy("html", {
  56. createHTML: (input) => input,
  57. });
  58. redditIcon = policy.createHTML(redditIcon);
  59. hackerNewsIcon = policy.createHTML(hackerNewsIcon);
  60. }
  61.  
  62. // Main function runs on load
  63. (function () {
  64. // Create the main link element
  65. const el = document.createElement("a");
  66. el.className = isImageSearch ? "NZmxZe" : "nPDzT T3FoJb";
  67.  
  68. // Create the div element for the text
  69. const hackerNewsEl = document.createElement("a");
  70. hackerNewsEl.className = isImageSearch ? "NZmxZe" : "nPDzT T3FoJb";
  71.  
  72. [el, hackerNewsEl].forEach((el, index) => {
  73. const icon = index === 0 ? redditIcon : hackerNewsIcon;
  74. const siteUrl = index === 0 ? redditUrl : hackerNewsUrl;
  75. const text = index === 0 ? "Reddit" : "Hacker News";
  76.  
  77. const mainDiv = document.createElement("div");
  78. mainDiv.className = "GKS7s";
  79.  
  80. // Create the span to wrap the icon and title
  81. const span = document.createElement("span");
  82. span.style.cssText = "display:inline-flex;gap:5px;";
  83. span.className = isImageSearch ? "m3kSL" : "FMKtTb UqcIvb";
  84.  
  85. // create the div to hold our SVG
  86. const iconDiv = document.createElement("div");
  87. iconDiv.style.cssText = nameVisible
  88. ? "height:16px;width:16px;display:block;fill:white;"
  89. : "height:16px;width:16px;display:block;margin:auto;fill:white;";
  90. iconDiv.innerHTML = icon;
  91.  
  92. // Create the text node to hold the button title
  93. const textNode = document.createTextNode(text);
  94. // Add iconDiv to the span element
  95. if (iconVisible) {
  96. span.appendChild(iconDiv);
  97. }
  98. // Add textNode to the span element
  99. if (nameVisible) {
  100. if (!isImageSearch) {
  101. span.appendChild(textNode);
  102. }
  103. }
  104.  
  105. // Add span to the mainDiv
  106. mainDiv.appendChild(span);
  107. // Add mainDiv to the main link element
  108. el.appendChild(mainDiv);
  109. // Add text node last if isImageSearch is true
  110. if (isImageSearch) {
  111. el.appendChild(textNode);
  112. }
  113.  
  114. // Add site:reddit.com to the query
  115. el.href = window.location.href.replace(queryRegex, (match) =>
  116. match.search(siteRegex) >= 0
  117. ? match.replace(siteRegex, siteUrl)
  118. : match + siteUrl
  119. );
  120. });
  121.  
  122. // Insert the link into Google search
  123. if (isImageSearch) {
  124. let menuBar = document.querySelector(".T47uwc");
  125. menuBar.insertBefore(el, menuBar.children[menuBar.childElementCount - 1]);
  126. } else {
  127. let menuBar = document.querySelectorAll(".IUOThf")[0];
  128. switch (btnPosition) {
  129. case "start":
  130. menuBar.insertBefore(el, menuBar.children[0]);
  131. menuBar.insertBefore(hackerNewsEl, menuBar.children[1]);
  132. break;
  133. case "end":
  134. menuBar.appendChild(el);
  135. menuBar.appendChild(hackerNewsEl);
  136. break;
  137. default:
  138. menuBar.appendChild(el);
  139. menuBar.appendChild(hackerNewsEl);
  140. break;
  141. }
  142. }
  143.  
  144. // Fix Sizing
  145. if (fixSize) {
  146. const buttonBox = document.querySelector(".xhjkHe");
  147. buttonBox.style.maxWidth = "inherit";
  148. }
  149. })();