Indexxx quick links

Creates quick links to search other sites from indexxx.com

  1. // ==UserScript==
  2. // @name Indexxx quick links
  3. // @description Creates quick links to search other sites from indexxx.com
  4. // @license WTFPL
  5. // @match https://www.indexxx.com/*
  6. // @match https://vipergirls.to/*
  7. // @match https://kitty-kats.net/*
  8. // @grant GM_addStyle
  9. // @grant GM_getValue
  10. // @grant GM_setValue
  11. // @grant GM_addValueChangeListener
  12. // @run-at document-end
  13. // @noframes
  14. // @version 0.3.1
  15. // @namespace https://greasyfork.org/users/1339655
  16. // ==/UserScript==
  17.  
  18. const { hostname, pathname } = window.location;
  19.  
  20. console.log("HOST", hostname);
  21.  
  22. const WINDOW_NAME = "userscript_501763";
  23.  
  24. const openTabs = {};
  25.  
  26. function openTab(url, windowName) {
  27. if (!openTabs[url] || openTabs[url].closed) {
  28. GM_setValue("opening", true);
  29.  
  30. openTabs[url] = window.open(url, windowName);
  31. }
  32. }
  33.  
  34. const HOME_CSS = `
  35. /* RESET */
  36.  
  37. html {
  38. box-sizing: border-box;
  39. }
  40.  
  41. *, *:before, *:after {
  42. box-sizing: inherit;
  43. }
  44.  
  45. body, h1, h2, h3, h4, h5, h6, p, ol, ul {
  46. margin: 0;
  47. padding: 0;
  48. font-weight: normal;
  49. }
  50.  
  51. ol, ul {
  52. list-style: none;
  53. }
  54.  
  55. img {
  56. max-width: 100%;
  57. height: auto;
  58. }
  59.  
  60. /* GLOBAL */
  61.  
  62. body {
  63. font-size: 16px;
  64. font-family: sans-serif;
  65. margin: 20px;
  66. }
  67.  
  68. a {
  69. color: #444;
  70. text-decoration: none;
  71. }
  72.  
  73. a:hover {
  74. text-decoration: underline;
  75. }
  76.  
  77. /* HIDE CRAP */
  78.  
  79. #navCol,
  80. #sidebar,
  81. #header,
  82. .d-flex:has(#googleSearch) {
  83. display: none;
  84. }
  85.  
  86. /* RE-STYLE */
  87.  
  88. .d-flex:has(.pset) {
  89. display: flex;
  90. flex-wrap: wrap;
  91. gap: 20px;
  92. align-items: flex-end;
  93. }
  94.  
  95. .pset {
  96. width: 320px;
  97. flex-grow: 1;
  98. }
  99.  
  100. .pset img {
  101. display: block;
  102. margin: 0 auto;
  103. pointer-events: none;
  104. }
  105.  
  106. .psetInfo {
  107. text-align: center;
  108. }
  109. `;
  110.  
  111. if (hostname === "www.indexxx.com") {
  112. if (pathname === "/home" || pathname.startsWith("/m/")) {
  113. const button = document.querySelector("h1").insertAdjacentElement("beforeend", document.createElement("button"));
  114.  
  115. button.innerText = "📷";
  116.  
  117. button.onclick = () => {
  118. document.querySelector("link[href^='/static/v2/css/joined.css']").remove();
  119.  
  120. GM_addStyle(HOME_CSS);
  121.  
  122. document.querySelectorAll(".photoSection img").forEach(img => {
  123. img.src = img.src.replace(/thumbs\/\d+x\d+\//, "");
  124. });
  125.  
  126. document.querySelectorAll("#model-header > :not(:has([itemtype='http://schema.org/Photograph']))").forEach(el => {
  127. el.remove();
  128. });
  129.  
  130. button.remove();
  131. }
  132. }
  133.  
  134. function createLink(url, keywords) {
  135. const link = document.createElement("span");
  136. link.innerText = `🔍`;
  137. link.style.cursor = "pointer";
  138. link.title = keywords;
  139. link.onclick = () => {
  140. GM_setValue("search", keywords);
  141. openTab(url, WINDOW_NAME);
  142. };
  143. return link;
  144. }
  145.  
  146. [...document.querySelectorAll("[itemtype='http://schema.org/Photograph']")].forEach(card => {
  147. const names = [...card.querySelectorAll("[itemprop='name']")];
  148.  
  149. names.forEach(el => {
  150. const keywords = el.innerText;
  151. el.parentElement.insertAdjacentElement("afterend", createLink("https://vipergirls.to/forum.php", keywords));
  152. el.parentElement.insertAdjacentElement("afterend", createLink("https://kitty-kats.net/", keywords));
  153. });
  154.  
  155. const allNames = names.map(el => el.innerText).join(" ");
  156. const link = card.querySelector("[itemprop='url']");
  157. const fullTitle = card.querySelector("img").alt;
  158. const keywords = cleanQuery(allNames + " " + (/(.*)\sin\s(?<title>.*),\s\sat\s/gm.exec(fullTitle)?.groups?.title || ''));
  159.  
  160. link.insertAdjacentElement("afterend", createLink("https://vipergirls.to/forum.php", keywords));
  161. link.insertAdjacentElement("afterend", createLink("https://kitty-kats.net/", keywords));
  162. })
  163. }
  164.  
  165. function handleSearch(targetHostname, performSearch) {
  166. if (hostname === targetHostname && window.name === WINDOW_NAME) {
  167. let lastKeywords = sessionStorage.getItem("search");
  168.  
  169. const search = () => {
  170. const keywords = GM_getValue("search");
  171.  
  172. if (keywords === lastKeywords) {
  173. return;
  174. }
  175.  
  176. sessionStorage.setItem("search", keywords);
  177.  
  178. console.log("SEARCH", targetHostname)
  179.  
  180. if (keywords) {
  181. console.log("KEYWORDS", keywords)
  182. performSearch(keywords);
  183. }
  184. };
  185.  
  186. GM_addValueChangeListener("search", search);
  187.  
  188. search();
  189. }
  190. }
  191.  
  192. handleSearch("kitty-kats.net", (keywords) => {
  193. document.querySelector("a[aria-label='Search']").click();
  194. document.querySelector("input[name='c[title_only]']").checked = true;
  195. document.querySelector("input[name='keywords']").value = keywords;
  196. document.querySelector("button.button--icon--search").click();
  197. });
  198.  
  199. handleSearch("vipergirls.to", (keywords) => {
  200. document.querySelector("#navbar_search input[name='query']").click();
  201. document.querySelector("#navbar_search input[name='query']").value = keywords;
  202. document.querySelector("#cb_navsearch_titleonly").checked = true;
  203. document.querySelector("#cb_navsearch_showposts").checked = true;
  204. document.querySelector("#navbar_search input[name='submit']").click();
  205. });
  206.  
  207. function cleanQuery(str) {
  208. const stopWords = "\\b(?:a|an|and|the|but|or|on|in|with|is|it|that|this|to|of|for|as|at|by|from|up|down|out|if|about|which|who|what|where|when|why|how)\\b";
  209. const regex = new RegExp(`\\b\\w*'\\w*\\b|${stopWords}`, 'gi');
  210.  
  211. return str
  212. .replace(regex, '')
  213. .replace(/[^a-zA-Z0-9 ']/g, '')
  214. .replace(/\s+/g, ' ')
  215. .trim();
  216. }