URL Modifier for Search Engines

Modify (Redirect) URL links in search engines results to alternative frontends or for other purposes

当前为 2024-02-02 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name URL Modifier for Search Engines
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.3.4
  5. // @description Modify (Redirect) URL links in search engines results to alternative frontends or for other purposes
  6. // @author Domenic
  7.  
  8. // @match *://www.google.com/search?*
  9. // @match *://www.google.ad/search?*
  10. // @match *://www.google.ae/search?*
  11. // @match *://www.google.com.af/search?*
  12. // @match *://www.google.com.ag/search?*
  13. // @match *://www.google.al/search?*
  14. // @match *://www.google.am/search?*
  15. // @match *://www.google.co.ao/search?*
  16. // @match *://www.google.com.ar/search?*
  17. // @match *://www.google.as/search?*
  18. // @match *://www.google.at/search?*
  19. // @match *://www.google.com.au/search?*
  20. // @match *://www.google.az/search?*
  21. // @match *://www.google.ba/search?*
  22. // @match *://www.google.com.bd/search?*
  23. // @match *://www.google.be/search?*
  24. // @match *://www.google.bf/search?*
  25. // @match *://www.google.bg/search?*
  26. // @match *://www.google.com.bh/search?*
  27. // @match *://www.google.bi/search?*
  28. // @match *://www.google.bj/search?*
  29. // @match *://www.google.com.bn/search?*
  30. // @match *://www.google.com.bo/search?*
  31. // @match *://www.google.com.br/search?*
  32. // @match *://www.google.bs/search?*
  33. // @match *://www.google.bt/search?*
  34. // @match *://www.google.co.bw/search?*
  35. // @match *://www.google.by/search?*
  36. // @match *://www.google.com.bz/search?*
  37. // @match *://www.google.ca/search?*
  38. // @match *://www.google.cd/search?*
  39. // @match *://www.google.cf/search?*
  40. // @match *://www.google.cg/search?*
  41. // @match *://www.google.ch/search?*
  42. // @match *://www.google.ci/search?*
  43. // @match *://www.google.co.ck/search?*
  44. // @match *://www.google.cl/search?*
  45. // @match *://www.google.cm/search?*
  46. // @match *://www.google.cn/search?*
  47. // @match *://www.google.com.co/search?*
  48. // @match *://www.google.co.cr/search?*
  49. // @match *://www.google.com.cu/search?*
  50. // @match *://www.google.cv/search?*
  51. // @match *://www.google.com.cy/search?*
  52. // @match *://www.google.cz/search?*
  53. // @match *://www.google.de/search?*
  54. // @match *://www.google.dj/search?*
  55. // @match *://www.google.dk/search?*
  56. // @match *://www.google.dm/search?*
  57. // @match *://www.google.com.do/search?*
  58. // @match *://www.google.dz/search?*
  59. // @match *://www.google.com.ec/search?*
  60. // @match *://www.google.ee/search?*
  61. // @match *://www.google.com.eg/search?*
  62. // @match *://www.google.es/search?*
  63. // @match *://www.google.com.et/search?*
  64. // @match *://www.google.fi/search?*
  65. // @match *://www.google.com.fj/search?*
  66. // @match *://www.google.fm/search?*
  67. // @match *://www.google.fr/search?*
  68. // @match *://www.google.ga/search?*
  69. // @match *://www.google.ge/search?*
  70. // @match *://www.google.gg/search?*
  71. // @match *://www.google.com.gh/search?*
  72. // @match *://www.google.com.gi/search?*
  73. // @match *://www.google.gl/search?*
  74. // @match *://www.google.gm/search?*
  75. // @match *://www.google.gr/search?*
  76. // @match *://www.google.com.gt/search?*
  77. // @match *://www.google.gy/search?*
  78. // @match *://www.google.com.hk/search?*
  79. // @match *://www.google.hn/search?*
  80. // @match *://www.google.hr/search?*
  81. // @match *://www.google.ht/search?*
  82. // @match *://www.google.hu/search?*
  83. // @match *://www.google.co.id/search?*
  84. // @match *://www.google.ie/search?*
  85. // @match *://www.google.co.il/search?*
  86. // @match *://www.google.im/search?*
  87. // @match *://www.google.co.in/search?*
  88. // @match *://www.google.iq/search?*
  89. // @match *://www.google.is/search?*
  90. // @match *://www.google.it/search?*
  91. // @match *://www.google.je/search?*
  92. // @match *://www.google.com.jm/search?*
  93. // @match *://www.google.jo/search?*
  94. // @match *://www.google.co.jp/search?*
  95. // @match *://www.google.co.ke/search?*
  96. // @match *://www.google.com.kh/search?*
  97. // @match *://www.google.ki/search?*
  98. // @match *://www.google.kg/search?*
  99. // @match *://www.google.co.kr/search?*
  100. // @match *://www.google.com.kw/search?*
  101. // @match *://www.google.kz/search?*
  102. // @match *://www.google.la/search?*
  103. // @match *://www.google.com.lb/search?*
  104. // @match *://www.google.li/search?*
  105. // @match *://www.google.lk/search?*
  106. // @match *://www.google.co.ls/search?*
  107. // @match *://www.google.lt/search?*
  108. // @match *://www.google.lu/search?*
  109. // @match *://www.google.lv/search?*
  110. // @match *://www.google.com.ly/search?*
  111. // @match *://www.google.co.ma/search?*
  112. // @match *://www.google.md/search?*
  113. // @match *://www.google.me/search?*
  114. // @match *://www.google.mg/search?*
  115. // @match *://www.google.mk/search?*
  116. // @match *://www.google.ml/search?*
  117. // @match *://www.google.com.mm/search?*
  118. // @match *://www.google.mn/search?*
  119. // @match *://www.google.com.mt/search?*
  120. // @match *://www.google.mu/search?*
  121. // @match *://www.google.mv/search?*
  122. // @match *://www.google.mw/search?*
  123. // @match *://www.google.com.mx/search?*
  124. // @match *://www.google.com.my/search?*
  125. // @match *://www.google.co.mz/search?*
  126. // @match *://www.google.com.na/search?*
  127. // @match *://www.google.com.ng/search?*
  128. // @match *://www.google.com.ni/search?*
  129. // @match *://www.google.ne/search?*
  130. // @match *://www.google.nl/search?*
  131. // @match *://www.google.no/search?*
  132. // @match *://www.google.com.np/search?*
  133. // @match *://www.google.nr/search?*
  134. // @match *://www.google.nu/search?*
  135. // @match *://www.google.co.nz/search?*
  136. // @match *://www.google.com.om/search?*
  137. // @match *://www.google.com.pa/search?*
  138. // @match *://www.google.com.pe/search?*
  139. // @match *://www.google.com.pg/search?*
  140. // @match *://www.google.com.ph/search?*
  141. // @match *://www.google.com.pk/search?*
  142. // @match *://www.google.pl/search?*
  143. // @match *://www.google.pn/search?*
  144. // @match *://www.google.com.pr/search?*
  145. // @match *://www.google.ps/search?*
  146. // @match *://www.google.pt/search?*
  147. // @match *://www.google.com.py/search?*
  148. // @match *://www.google.com.qa/search?*
  149. // @match *://www.google.ro/search?*
  150. // @match *://www.google.ru/search?*
  151. // @match *://www.google.rw/search?*
  152. // @match *://www.google.com.sa/search?*
  153. // @match *://www.google.com.sb/search?*
  154. // @match *://www.google.sc/search?*
  155. // @match *://www.google.se/search?*
  156. // @match *://www.google.com.sg/search?*
  157. // @match *://www.google.sh/search?*
  158. // @match *://www.google.si/search?*
  159. // @match *://www.google.sk/search?*
  160. // @match *://www.google.com.sl/search?*
  161. // @match *://www.google.sn/search?*
  162. // @match *://www.google.so/search?*
  163. // @match *://www.google.sm/search?*
  164. // @match *://www.google.sr/search?*
  165. // @match *://www.google.st/search?*
  166. // @match *://www.google.com.sv/search?*
  167. // @match *://www.google.td/search?*
  168. // @match *://www.google.tg/search?*
  169. // @match *://www.google.co.th/search?*
  170. // @match *://www.google.com.tj/search?*
  171. // @match *://www.google.tl/search?*
  172. // @match *://www.google.tm/search?*
  173. // @match *://www.google.tn/search?*
  174. // @match *://www.google.to/search?*
  175. // @match *://www.google.com.tr/search?*
  176. // @match *://www.google.tt/search?*
  177. // @match *://www.google.com.tw/search?*
  178. // @match *://www.google.co.tz/search?*
  179. // @match *://www.google.com.ua/search?*
  180. // @match *://www.google.co.ug/search?*
  181. // @match *://www.google.co.uk/search?*
  182. // @match *://www.google.com.uy/search?*
  183. // @match *://www.google.co.uz/search?*
  184. // @match *://www.google.com.vc/search?*
  185. // @match *://www.google.co.ve/search?*
  186. // @match *://www.google.co.vi/search?*
  187. // @match *://www.google.com.vn/search?*
  188. // @match *://www.google.vu/search?*
  189. // @match *://www.google.ws/search?*
  190. // @match *://www.google.rs/search?*
  191. // @match *://www.google.co.za/search?*
  192. // @match *://www.google.co.zm/search?*
  193. // @match *://www.google.co.zw/search?*
  194. // @match *://www.google.cat/search?*
  195.  
  196. // @match *://yandex.com/search/?*
  197. // @match *://yandex.ru/search/?*
  198.  
  199. // @match *://search.disroot.org/search*
  200. // @match *://searx.tiekoetter.com/search*
  201. // @match *://search.bus-hit.me/search*
  202. // @match *://search.inetol.net/search*
  203. // @match *://priv.au/search*
  204. // @match *://searx.be/search*
  205. // @match *://searxng.site/search*
  206. // @match *://search.hbubli.cc/search*
  207. // @match *://search.im-in.space/search*
  208. // @match *://opnxng.com/search*
  209. // @match *://search.upinmars.com/search*
  210. // @match *://search.sapti.me/search*
  211. // @match *://freesearch.club/search*
  212. // @match *://xo.wtf/search*
  213. // @match *://www.gruble.de/search*
  214. // @match *://searx.tuxcloud.net/search*
  215. // @match *://baresearch.org/search*
  216. // @match *://searx.daetalytica.io/search*
  217. // @match *://etsi.me/search*
  218. // @match *://search.leptons.xyz/search*
  219. // @match *://search.rowie.at/search*
  220. // @match *://search.mdosch.de/search*
  221. // @match *://searx.catfluori.de/search*
  222. // @match *://searx.si/search*
  223. // @match *://searx.namejeff.xyz/search*
  224. // @match *://search.itstechtime.com/search*
  225. // @match *://s.mble.dk/search*
  226. // @match *://searx.kutay.dev/search*
  227. // @match *://ooglester.com/search*
  228. // @match *://searx.ox2.fr/search*
  229. // @match *://searx.techsaviours.org/search*
  230. // @match *://searx.perennialte.ch/search*
  231. // @match *://s.trung.fun/searxng/search*
  232. // @match *://search.in.projectsegfau.lt/search*
  233. // @match *://search.projectsegfau.lt/search*
  234. // @match *://darmarit.org/searx/search*
  235. // @match *://searx.lunar.icu/search*
  236. // @match *://nyc1.sx.ggtyler.dev/search*
  237. // @match *://search.rhscz.eu/search*
  238. // @match *://paulgo.io/search*
  239. // @match *://northboot.xyz/search*
  240. // @match *://searx.zhenyapav.com/search*
  241. // @match *://searxng.ch/search*
  242. // @match *://copp.gg/search*
  243. // @match *://searx.sev.monster/search*
  244. // @match *://searx.oakleycord.dev/search*
  245. // @match *://searx.juancord.xyz/search*
  246. // @match *://searx.work/search*
  247. // @match *://search.ononoki.org/search*
  248. // @match *://search.demoniak.ch/search*
  249. // @match *://searx.cthd.icu/search*
  250. // @match *://searx.fmhy.net/search*
  251. // @match *://searx.headpat.exchange/search*
  252. // @match *://sex.finaltek.net/search*
  253. // @match *://search.gcomm.ch/search*
  254. // @match *://search.smnz.de/search*
  255. // @match *://searx.ankha.ac/search*
  256. // @match *://search.lvkaszus.pl/search*
  257. // @match *://searx.nobulart.com/search*
  258. // @match *://sx.t-1.org/search*
  259. // @match *://www.jabber-germany.de/searx/search*
  260. // @match *://sx.catgirl.cloud/search*
  261. // @match *://sx.vern.cc/searxng/search*
  262.  
  263. // @match *://www.startpage.com/search*
  264. // @match *://www.startpage.com/sp/search*
  265.  
  266. // @match *://search.brave.com/search*
  267.  
  268. // @match *://duckduckgo.com
  269. // @match *://duckduckgo.com/?*
  270.  
  271. // @match *://www.qwant.com/?*
  272. // @match *://www.ecosia.org/search?*
  273. // @match *://presearch.com/search?*
  274.  
  275. // @match *://swisscows.com/en/web?*
  276. // @match *://swisscows.com/de/web?*
  277. // @match *://swisscows.com/es/web?*
  278. // @match *://swisscows.com/fr/web?*
  279. // @match *://swisscows.com/it/web?*
  280. // @match *://swisscows.com/lv/web?*
  281. // @match *://swisscows.com/hu/web?*
  282. // @match *://swisscows.com/nl/web?*
  283. // @match *://swisscows.com/pt/web?*
  284. // @match *://swisscows.com/ru/web?*
  285. // @match *://swisscows.com/uk/web?*
  286.  
  287. // @match *://metager.org/meta/meta.ger3*
  288. // @match *://metager.org/da-DK/meta/meta.ger3*
  289. // @match *://metager.org/de-AT/meta/meta.ger3*
  290. // @match *://metager.org/de-CH/meta/meta.ger3*
  291. // @match *://metager.org/de-DE/meta/meta.ger3*
  292. // @match *://metager.org/en-GB/meta/meta.ger3*
  293. // @match *://metager.org/en-IE/meta/meta.ger3*
  294. // @match *://metager.org/en-MY/meta/meta.ger3*
  295. // @match *://metager.org/es-ES/meta/meta.ger3*
  296. // @match *://metager.org/es-MX/meta/meta.ger3*
  297. // @match *://metager.org/fi-FI/meta/meta.ger3*
  298. // @match *://metager.org/fr-CA/meta/meta.ger3*
  299. // @match *://metager.org/fr-FR/meta/meta.ger3*
  300. // @match *://metager.org/it-IT/meta/meta.ger3*
  301. // @match *://metager.org/nl-NL/meta/meta.ger3*
  302. // @match *://metager.org/pl-PL/meta/meta.ger3*
  303. // @match *://metager.org/sv-SE/meta/meta.ger3*
  304. // @match *://metager.de/meta/meta.ger3*
  305. // @match *://metager.de/da-DK/meta/meta.ger3*
  306. // @match *://metager.de/de-AT/meta/meta.ger3*
  307. // @match *://metager.de/de-CH/meta/meta.ger3*
  308. // @match *://metager.de/de-DE/meta/meta.ger3*
  309. // @match *://metager.de/en-GB/meta/meta.ger3*
  310. // @match *://metager.de/en-IE/meta/meta.ger3*
  311. // @match *://metager.de/en-MY/meta/meta.ger3*
  312. // @match *://metager.de/es-ES/meta/meta.ger3*
  313. // @match *://metager.de/es-MX/meta/meta.ger3*
  314. // @match *://metager.de/fi-FI/meta/meta.ger3*
  315. // @match *://metager.de/fr-CA/meta/meta.ger3*
  316. // @match *://metager.de/fr-FR/meta/meta.ger3*
  317. // @match *://metager.de/it-IT/meta/meta.ger3*
  318. // @match *://metager.de/nl-NL/meta/meta.ger3*
  319. // @match *://metager.de/pl-PL/meta/meta.ger3*
  320. // @match *://metager.de/sv-SE/meta/meta.ger3*
  321.  
  322. // @match *://ghosterysearch.com/search?*
  323.  
  324. // @match *://4get.ca/web?*
  325. // @match *://4get.silly.computer/web?*
  326. // @match *://4get.plunked.party/web?*
  327. // @match *://4get.konakona.moe/web?*
  328. // @match *://4get.sijh.net/web?*
  329. // @match *://4get.hbubli.cc/web?*
  330. // @match *://4get.perennialte.ch/web?*
  331. // @match *://4get.zzls.xyz/web?*
  332. // @match *://4getus.zzls.xyz/web?*
  333. // @match *://4get.seitan-ayoub.lol/web?*
  334. // @match *://4get.dcs0.hu/web?*
  335. // @match *://4get.psily.garden/web?*
  336. // @match *://4get.lvkaszus.pl/web?*
  337. // @match *://4get.kizuki.lol/web?*
  338.  
  339. // @match *://search.ahwx.org/search.php?*
  340. // @match *://search2.ahwx.org/search.php?*
  341. // @match *://search3.ahwx.org/search.php?*
  342. // @match *://ly.owo.si/search.php?*
  343. // @match *://librey.franklyflawless.org/search.php?*
  344. // @match *://librey.org/search.php?*
  345. // @match *://search.davidovski.xyz/search.php?*
  346. // @match *://search.milivojevic.in.rs/search.php?*
  347. // @match *://glass.prpl.wtf/search.php?*
  348. // @match *://librex.uk.to/search.php?*
  349. // @match *://librey.ix.tc/search.php?*
  350. // @match *://search.funami.tech/search.php?*
  351. // @match *://librex.retro-hax.net/search.php?*
  352. // @match *://librex.nohost.network/search.php?*
  353. // @match *://search.pabloferreiro.es/search.php?*
  354. // @match *://librey.baczek.me/search.php?*
  355. // @match *://lx.benike.me/search.php?*
  356. // @match *://search.seitan-ayoub.lol/search.php?*
  357. // @match *://librey.myroware.net/search.php?*
  358. // @match *://librey.nezumi.party/search.php?*
  359. // @match *://search.zeroish.xyz/search.php?*
  360.  
  361. // @match *://stract.com/search?*
  362.  
  363. // @match *://www.etools.ch/searchSubmit.do*
  364. // @match *://www.etools.ch/mobileSearch.do*
  365.  
  366. // @match *://www.mojeek.com/search?*
  367. // @match *://yep.com/web?*
  368. // @match *://www.torry.io/search*
  369. // @match *://oceanhero.today/web?*
  370. // @match *://search.lilo.org/?*
  371. // @match *://search.entireweb.com/search?*
  372. // @match *://search.gmx.com/web/result?*
  373. // @match *://search.gmx.com/web?*
  374. // @match *://spot.ecloud.global/search*
  375. // @match *://youcare.world/all?*
  376. // @match *://www.nona.de/?*
  377. // @match *://www.exalead.com/search/web/results/?*
  378. // @match *://search.seznam.cz/?*
  379. // @match *://gibiru.com/results.html?*
  380. // @match *://www.lukol.com/s.php?*
  381. // @match *://search.givewater.com/serp?*
  382. // @match *://results.excite.com/serp?*
  383. // @match *://www.webcrawler.com/serp?*
  384. // @match *://www.metacrawler.com/serp?*
  385. // @match *://www.dogpile.com/serp?*
  386.  
  387. // @grant none
  388. // @run-at document-end
  389. // @license GPL-2.0-only
  390. // ==/UserScript==
  391.  
  392. (function() {
  393. 'use strict';
  394.  
  395. // Define URL modification rules with precompiled regex
  396. const urlModificationRules = [
  397. {
  398. matchRegex: new RegExp(/^https?:\/\/((?!test)[a-z]+)\.?m?\.wikipedia\.org\/(?:[a-z]+|wiki)\/(?!Special:Search)(.*)/),
  399. replaceWith: 'https://www.wikiwand.com/$1/$2'
  400. },
  401. {
  402. matchRegex: new RegExp(/^https?:\/\/zh\.?m?\.wikipedia\.org\/(?:zh-hans|wiki)\/(.*)/),
  403. replaceWith: 'https://www.wikiwand.com/zh-hans/$1'
  404. },
  405. {
  406. matchRegex: new RegExp(/^https?:\/\/wikipedia\.org\/(?:[a-z]+|wiki)\/(?!Special:Search)(.*)/),
  407. replaceWith: 'https://www.wikiwand.com/en/$1'
  408. },
  409. {
  410. matchRegex: new RegExp(/^https?:\/\/(?:old|www)\.reddit\.com\/((?:r|u)\/.*)/),
  411. replaceWith: 'https://safereddit.com/$1'
  412. },
  413. {
  414. matchRegex: new RegExp(/^https?:\/\/www\.quora\.com\/((?=.*-)[\w-]+$|profile\/.*)/),
  415. replaceWith: 'https://quetre.iket.me/$1'
  416. },
  417. {
  418. matchRegex: new RegExp(/^https?:\/\/twitter\.com\/([A-Za-z_][\w]+)(\/status\/(\d+))?.*/),
  419. replaceWith: 'https://nitter.catsarch.com/$1$2'
  420. },
  421. {
  422. matchRegex: new RegExp(/^https?:\/\/stackoverflow\.com(\/questions\/\d+\/[\w-]+)/),
  423. replaceWith: 'https://ao.vern.cc$1'
  424. },
  425. {
  426. matchRegex: new RegExp(/^https?:\/\/((?:(?:.*?)?medium|towardsdatascience|betterprogramming|.*?plainenglish|.*?gitconnected|aninjusticemag|betterhumans|uxdesign|uxplanet)\.\w+\/(?=.*-)(?:[\w\/-]+|[\w@.]+\/[\w-]+))(?:\?source=.*)?/),
  427. replaceWith: 'https://freedium.cfd/https://$1'
  428. },
  429. {
  430. matchRegex: new RegExp(/^https?:\/\/(?:www\.|m\.)?youtube\.com\/((?:@|watch\?|playlist\?|channel\/|user\/|shorts\/).*)/),
  431. replaceWith: 'https://vid.puffyan.us/$1'
  432. },
  433. {
  434. matchRegex: new RegExp(/^https?:\/\/music\.youtube\.com\/((?:playlist\?|watch\?|channel\/|browse\/).*)/),
  435. replaceWith: 'https://hyperpipe.surge.sh/$1'
  436. },
  437. {
  438. matchRegex: new RegExp(/^https?:\/\/www\.twitch\.tv\/(\w+)$/),
  439. replaceWith: 'https://ttv.vern.cc/$1'
  440. },
  441. {
  442. matchRegex: new RegExp(/^https?:\/\/(?:m|www)\.imdb\.com(.*)/),
  443. replaceWith: 'https://ld.vern.cc$1'
  444. },
  445. {
  446. matchRegex: new RegExp(/^https?:\/\/www\.goodreads\.com\/((?:(?:[a-z]+\/)?book\/show|work\/quotes|series|author\/show)\/[\w.-]+)/),
  447. replaceWith: 'https://bl.vern.cc/$1'
  448. },
  449. {
  450. // only support English Fandom sites
  451. matchRegex: new RegExp(/^https?:\/\/((?!www|community).*?)\.fandom\.com\/wiki\/(.*)/),
  452. replaceWith: 'https://antifandom.com/$1/wiki/$2'
  453. },
  454. {
  455. matchRegex: new RegExp(/^https?:\/\/www\.urbandictionary\.com\/(define\.php\?term=.*)/),
  456. replaceWith: 'https://rd.vern.cc/$1'
  457. },
  458. {
  459. matchRegex: new RegExp(/^https?:\/\/github\.ink(.*)/),
  460. replaceWith: 'https://github.com$1'
  461. },
  462. {
  463. matchRegex: new RegExp(/^https?:\/\/www\.reuters\.com\/((?=.*\/)(?=.*-).*)/),
  464. replaceWith: 'https://nu.vern.cc/$1'
  465. },
  466. {
  467. matchRegex: new RegExp(/^https?:\/\/(www\.ft\.com\/content\/[\w-]+)/),
  468. replaceWith: 'https://archive.today/https://$1'
  469. },
  470. {
  471. matchRegex: new RegExp(/^https?:\/\/(www\.bloomberg\.com\/(?:(?:[a-z]+\/)?news|opinion)\/[\w\/-]+).*/),
  472. replaceWith: 'https://archive.today/https://$1'
  473. },
  474. {
  475. matchRegex: new RegExp(/^https?:\/\/www\.npr\.org\/(?:\d{4}\/\d{2}\/\d{2}|sections)\/(?:[A-Za-z-]+\/\d{4}\/\d{2}\/\d{2}\/)?(\d+)\/.*/),
  476. replaceWith: 'https://text.npr.org/$1'
  477. },
  478. {
  479. matchRegex: new RegExp(/^https?:\/\/news\.ycombinator\.com\/item\?id=(\d+)/),
  480. replaceWith: 'https://www.hckrnws.com/stories/$1'
  481. },
  482. {
  483. matchRegex: new RegExp(/^https?:\/\/(?:[a-z]+)\.slashdot\.org(.*)/),
  484. replaceWith: 'https://slashdot.org$1'
  485. },
  486. {
  487. matchRegex: new RegExp(/^https?:\/\/(?:(?:.*)arxiv\.org\/pdf|arxiv-export-lb\.library\.cornell\.edu\/(?:pdf|abs))\/(\d{4}\.\d{4,5}(v\d)?)(?:.*)/),
  488. replaceWith: 'https://arxiv.org/abs/$1'
  489. },
  490. {
  491. matchRegex: new RegExp(/^https?:\/\/(ieeexplore\.ieee\.org\/document\/\d+)\//),
  492. replaceWith: 'https://$1'
  493. },
  494. {
  495. matchRegex: new RegExp(/^https?:\/\/www\.snopes\.com(.*)/),
  496. replaceWith: 'https://sd.vern.cc$1'
  497. },
  498. {
  499. matchRegex: new RegExp(/^https?:\/\/www\.instructables\.com\/(.*)/),
  500. replaceWith: 'https://ds.vern.cc/$1'
  501. },
  502. {
  503. matchRegex: new RegExp(/^https?:\/\/genius\.com\/((?=[\w-]+lyrics|search\?q=).*)/),
  504. replaceWith: 'https://dm.vern.cc/$1'
  505. },
  506. {
  507. matchRegex: new RegExp(/^https?:\/\/(.*?)\.bandcamp\.com\//),
  508. replaceWith: 'https://tn.vern.cc/artist.php?name=$1'
  509. },
  510. {
  511. matchRegex: new RegExp(/^https?:\/\/(.*?)\.bandcamp\.com\/(.*?)\/(.*)/),
  512. replaceWith: 'https://tn.vern.cc/release.php?artist=$1&type=$2&name=$3'
  513. },
  514. {
  515. matchRegex: new RegExp(/^https?:\/\/bandcamp\.com\/search\?q=(.*)/),
  516. replaceWith: 'https://tn.vern.cc/search.php?query=$1'
  517. },
  518. {
  519. matchRegex: new RegExp(/^https?:\/\/f4\.bcbits\.com\/img\/(.*)/),
  520. replaceWith: 'https://tn.vern.cc/image.php?file=$1'
  521. },
  522. {
  523. matchRegex: new RegExp(/^https?:\/\/t4\.bcbits\.com\/stream\/(.*?)\/(.*?)\/(.*?)\?token=(.*)/),
  524. replaceWith: 'https://tn.vern.cc/audio.php?directory=$1&format=$2&file=$3&token=$4'
  525. },
  526. {
  527. matchRegex: new RegExp(/^https?:\/\/(?:\w+\.)?imgur.com\/((?:a\/)?(?!gallery)[\w.]+)/),
  528. replaceWith: 'https://rimgo.totaldarkness.net/$1'
  529. },
  530. {
  531. matchRegex: new RegExp(/^https?:\/\/www\.pixiv\.net\/(?:[a-z]+\/)?(artworks\/\d+|tags\/\w+|users\/\d+).*/),
  532. replaceWith: 'https://pixivfe.exozy.me/$1'
  533. },
  534. {
  535. matchRegex: new RegExp(/^https?:\/\/knowyourmeme\.com\/(.*)/),
  536. replaceWith: 'https://mm.vern.cc/$1'
  537. },
  538. {
  539. matchRegex: new RegExp(/^https?:\/\/tenor\.com\/((?:view|search)\/.*)/),
  540. replaceWith: 'https://sp.vern.cc/$1'
  541. },
  542. {
  543. matchRegex: new RegExp(/^https?:\/\/(?:\w+\.)?ifunny\.co\/(picture\/.*)/),
  544. replaceWith: 'https://uf.vern.cc/$1'
  545. },
  546. // Add more rules here as needed
  547. ];
  548.  
  549. // Define enhanced selector rules for each search engine
  550. const selectorRules = {
  551. 'google': [
  552. {
  553. selector: 'div.MjjYud div.yuRUbf div span a',
  554. childSelector: 'div.byrV5b cite',
  555. updateChildText: true,
  556. containProtocol: true,
  557. urlDisplayMethod: 1
  558. },
  559. {
  560. // selector for sub-results
  561. selector: 'div.MjjYud div.HiHjCd a'
  562. },
  563. {
  564. // selector for sidebar links
  565. selector: 'div.TQc1id#rhs a'
  566. }
  567. ],
  568. 'yandex': [
  569. {
  570. selector: 'ul#search-result li div.Organic-Subtitle div a',
  571. updateChildText: true,
  572. containProtocol: false,
  573. urlDisplayMethod: 1,
  574. },
  575. {
  576. selector: 'ul#search-result li div.Organic div a',
  577. }
  578. ],
  579. 'searx': [
  580. {
  581. selector: 'article.result a.url_wrapper',
  582. childSelector: 'span span',
  583. updateChildText: true,
  584. containProtocol: true,
  585. multiElementsForUrlDisplay: 1
  586. },
  587. {
  588. selector: 'article.result h3 a'
  589. },
  590. {
  591. selector: 'aside.infobox div.urls ul li a'
  592. }
  593. ],
  594. 'startpage': [
  595. {
  596. selector: 'a.w-gl__result-url.result-link',
  597. updateTextWithoutOverwrite: true,
  598. urlDisplayMethod: 2
  599. },
  600. {
  601. selector: 'a.w-gl__result-title.result-link'
  602. },
  603. {
  604. selector: 'div.sx-kp-main a'
  605. }
  606. ],
  607. 'brave': [
  608. {
  609. selector: 'div.snippet a.h',
  610. childSelector: 'div.site cite.snippet-url span',
  611. updateChildText: true,
  612. containProtocol: false,
  613. multiElementsForUrlDisplay: 1
  614. },
  615. {
  616. selector: 'div#discussions.snippet a',
  617. },
  618. {
  619. selector: 'div#infobox-snippet.snippet a'
  620. }
  621. ],
  622. 'duckduckgo': [
  623. {
  624. selector: 'a.eVNpHGjtxRBq_gLOfGDr.LQNqh2U1kzYxREs65IJu'
  625. },
  626. {
  627. selector: 'a.Rn_JXVtoPVAFyGkcaXyK',
  628. childSelector: 'span',
  629. updateChildText: true,
  630. containProtocol: true,
  631. multiElementsForUrlDisplay: 1
  632. },
  633. {
  634. // Selector for sub-results
  635. selector: 'ul.b269SZlC2oyR13Fcc4Iy li a.f3uDrYrWF3Exrfp1m3Og'
  636. },
  637. {
  638. selector: 'div.react-module div section div a'
  639. }
  640. ],
  641. 'ghostery': [
  642. {
  643. selector: 'li.result h2 a'
  644. },
  645. {
  646. selector: 'li.result div.snippet div.address a.url',
  647. updateTextByOverwrite: true,
  648. urlDisplayMethod: 2
  649. }
  650. ],
  651. 'presearch': [
  652. {
  653. selector: 'div.relative div.w-auto a',
  654. childSelector: 'div',
  655. updateChildText: true,
  656. urlDisplayMethod: 3,
  657. },
  658. {
  659. selector: 'div.relative div.inline-block a'
  660. }
  661. ],
  662. 'metager': [
  663. {
  664. selector: 'h2.result-title a'
  665. },
  666. {
  667. selector: 'div.result-subheadline a',
  668. updateTextWithoutOverwrite: true,
  669. urlDisplayMethod: 3
  670. },
  671. {
  672. selector: 'div.quicktip div.quicktip-headline h1 a'
  673. },
  674. {
  675. selector: 'div.quicktip div.quicktip-detail h2 a'
  676. }
  677. ],
  678. '4get': [
  679. {
  680. selector: 'div.text-result a.hover'
  681. },
  682. {
  683. selector: 'div.text-result div.sublinks a'
  684. },
  685. {
  686. selector: 'div.right-wrapper div.answer-wrapper div.answer div.answer-title a.answer-title'
  687. }
  688. ],
  689. 'librey': [
  690. {
  691. selector: 'div.text-result-wrapper a',
  692. updateTextWithoutOverwrite: true,
  693. useTopLevelDomain: true,
  694. urlDisplayMethod: 2
  695. },
  696. {
  697. selector: 'p.special-result-container a',
  698. updateTextWithoutOverwrite: true,
  699. urlDisplayMethod: 2
  700. },
  701. ],
  702. 'stract': [
  703. {
  704. selector: 'div.grid div div.flex div div div a',
  705. updateTextWithoutOverwrite: true,
  706. urlDisplayMethod: 2
  707. },
  708. {
  709. selector: 'div.grid div div.flex div div a'
  710. },
  711. {
  712. selector: 'div.mb-5.text-xl a'
  713. },
  714. {
  715. selector: 'div.text-sm a.text-link'
  716. }
  717. ],
  718. 'etools': [
  719. {
  720. // searchSubmit.do
  721. selector: 'td.record a.title'
  722. },
  723. {
  724. // mobileSearch.do
  725. selector: 'p a.title'
  726. }
  727. ],
  728. 'mojeek': [
  729. {
  730. selector: 'ul.results-standard li h2 a.title'
  731. },
  732. {
  733. selector: 'ul.results-standard li a.ob',
  734. childSelector: 'span.url',
  735. updateChildText: true,
  736. containProtocol: true,
  737. urlDisplayMethod: 1
  738. },
  739. {
  740. selector: 'div.infobox p a'
  741. },
  742. {
  743. selector: 'div.results.news-results li a'
  744. },
  745. {
  746. selector: 'div.right-col div.results ul li a'
  747. }
  748. ],
  749. 'yep': [
  750. {
  751. selector: 'div.css-102xgmn-card div div a',
  752. childSelector: 'div span',
  753. updateChildText: true,
  754. containProtocol: false,
  755. urlDisplayMethod: 1
  756. }
  757. ],
  758. 'torry': [
  759. {
  760. selector: 'div.searpList p a.toranclick',
  761. updateTextWithoutOverwrite: true,
  762. urlDisplayMethod: 2
  763. },
  764. {
  765. selector: 'div.searpList div h2 a.toranclick',
  766. },
  767. {
  768. selector: 'div.searpList ul li a',
  769. }
  770. ],
  771. 'qwant': [
  772. {
  773. selector: 'div._35zId._3A7p7 a.external'
  774. },
  775. {
  776. selector: 'div._35zId._3WA-c a.external',
  777. childSelector: 'span',
  778. updateChildText: true,
  779. containProtocol: false,
  780. multiElementsForUrlDisplay: 1
  781. },
  782. {
  783. // Selector for sub-results
  784. selector: 'div._12BMd div._2-LMx._2E8gc._16lFV.Ks7KS.tCpbb.m_hqb a.external'
  785. },
  786. {
  787. selector: 'div._3McWE.is-sidebar a.external'
  788. }
  789. ],
  790. 'ecosia': [
  791. {
  792. selector: 'div.mainline__result-wrapper div.result__header div.result__info a',
  793. childSelector: 'span span',
  794. updateChildText: true,
  795. containProtocol: true,
  796. multiElementsForUrlDisplay: 1
  797. },
  798. {
  799. selector: 'div.mainline__result-wrapper div.result__header div.result__title a'
  800. },
  801. {
  802. selector: 'div.mainline__result-wrapper div ul li a'
  803. },
  804. {
  805. selector: 'aside.sidebar article div.entity-links ul li a'
  806. },
  807. {
  808. selector: 'aside.sidebar article div.entity__content p a'
  809. }
  810. ],
  811. 'oceanhero': [
  812. {
  813. selector: 'div div div a',
  814. childSelector: 'span cite',
  815. updateChildText: true,
  816. containProtocol: false,
  817. urlDisplayMethod: 1
  818. },
  819. {
  820. selector: 'section div ul li a'
  821. },
  822. {
  823. selector: 'div div div p a'
  824. }
  825. ],
  826. 'swisscows': [
  827. {
  828. selector: 'article.item-web a',
  829. updateTextWithoutOverwrite: true,
  830. containProtocol: false,
  831. urlDisplayMethod: 1
  832. }
  833. ],
  834. 'lilo': [
  835. {
  836. selector: 'div.lilo-text-result div p a.has-text-grey-darker',
  837. childSelector: 'span',
  838. updateChildText: true,
  839. containProtocol: true,
  840. multiElementsForUrlDisplay: 2
  841. },
  842. {
  843. selector: 'div.lilo-text-result div a.has-text-primary'
  844. },
  845. {
  846. selector: 'div.column.is-two-fifths a'
  847. }
  848. ],
  849. 'entireweb': [
  850. {
  851. parentSelector: 'div.web-result',
  852. linkNodeSelector: 'a.web-result-title',
  853. textNodeSelector: 'div.web-result-domain',
  854. updateTextWithoutOverwrite: true,
  855. urlDisplayMethod: 3
  856. },
  857. {
  858. selector: 'div#infobox-list.card div.card-body a'
  859. },
  860. {
  861. parentSelector: 'div.gsc-webResult.gsc-result',
  862. linkNodeSelector: 'a.gs-title',
  863. textNodeSelector: 'div.gsc-url-top',
  864. updateTextByOverwrite: true,
  865. containProtocol: false,
  866. urlDisplayMethod: 1
  867. }
  868. ],
  869. 'gmx': [
  870. {
  871. selector: 'div.eMd a.eMdhl'
  872. },
  873. {
  874. selector: 'div.eMd a.eMdu',
  875. childSelector: 'span',
  876. updateChildText: true,
  877. containProtocol: true,
  878. multiElementsForUrlDisplay: 2
  879. },
  880. ],
  881. 'youcare': [
  882. {
  883. selector: 'div.search-result-item-text a.search-result-item-text__title'
  884. },
  885. {
  886. selector: 'div.search-result-item-text div div a.search-result-item-text-sitename'
  887. },
  888. {
  889. selector: 'div.search-result-item-text div div a.search-result-item-text__header-url',
  890. updateTextWithoutOverwrite: true,
  891. containProtocol: true,
  892. urlDisplayMethod: 1
  893. },
  894. {
  895. selector: "div.search-results-view__side a"
  896. }
  897. ],
  898. 'spot': [
  899. {
  900. selector: 'div.result h4 a'
  901. },
  902. {
  903. selector: 'div.result a.external-link',
  904. updateTextByOverwrite: true,
  905. urlDisplayMethod: 2
  906. },
  907. {
  908. selector: 'div.infobox div.footer div.links a'
  909. }
  910. ],
  911. 'nona': [
  912. {
  913. selector: 'section.result-section article.teaser div.teaser__container a.teaser__topline',
  914. updateTextByOverwrite: true,
  915. urlDisplayMethod: 2
  916. },
  917. {
  918. selector: 'section.result-section article.teaser div.teaser__container a.teaser__link'
  919. },
  920. {
  921. selector: 'section.result-section article.entity-teaser div.entity-teaser__wrapper a'
  922. }
  923. ],
  924. 'exalead': [
  925. {
  926. selector: 'li.media div.media-body a.ellipsis',
  927. updateTextByOverwrite: true,
  928. urlDisplayMethod: 3
  929. },
  930. {
  931. selector: 'li.media div.media-body a'
  932. }
  933. ],
  934. 'seznam': [
  935. {
  936. selector: 'div.f2c528 h3 a'
  937. },
  938. {
  939. selector: 'div.f2c528 a.d5e75c',
  940. updateTextByOverwrite: true,
  941. urlDisplayMethod: 3
  942. },
  943. ],
  944. 'gibiru': [
  945. {
  946. parentSelector: 'div.gs-webResult.gs-result',
  947. linkNodeSelector: 'a.gs-title',
  948. textNodeSelector: 'div.gsc-url-top div.gs-visibleUrl-breadcrumb',
  949. childSelector: 'span',
  950. updateChildText: true,
  951. containProtocol: false,
  952. multiElementsForUrlDisplay: 1
  953. }
  954. ],
  955. 'lukol': [
  956. {
  957. parentSelector: 'div.gsc-webResult.gsc-result',
  958. linkNodeSelector: 'a.gs-title',
  959. textNodeSelector: 'div.gsc-url-bottom div.gs-visibleUrl-long',
  960. updateTextByOverwrite: true,
  961. urlDisplayMethod: 2
  962. }
  963. ],
  964. 'givewater': [
  965. {
  966. parentSelector: 'div.web-bing__result',
  967. linkNodeSelector: 'a.web-bing__title',
  968. textNodeSelector: 'span.web-bing__url',
  969. updateTextByOverwrite: true,
  970. urlDisplayMethod: 2
  971. }
  972. ],
  973. 'excite': [
  974. {
  975. parentSelector: 'div.web-bing__result',
  976. linkNodeSelector: 'a.web-bing__title',
  977. textNodeSelector: 'span.web-bing__url',
  978. updateTextByOverwrite: true,
  979. urlDisplayMethod: 2
  980. }
  981. ],
  982. 'webcrawler': [
  983. {
  984. parentSelector: 'div.web-bing__result',
  985. linkNodeSelector: 'a.web-bing__title',
  986. textNodeSelector: 'span.web-bing__url',
  987. updateTextByOverwrite: true,
  988. urlDisplayMethod: 2
  989. }
  990. ],
  991. 'metacrawler': [
  992. {
  993. parentSelector: 'div.web-bing__result',
  994. linkNodeSelector: 'a.web-bing__title',
  995. textNodeSelector: 'span.web-bing__url',
  996. updateTextByOverwrite: true,
  997. urlDisplayMethod: 2
  998. }
  999. ],
  1000. 'dogpile': [
  1001. {
  1002. parentSelector: 'div.web-bing__result',
  1003. linkNodeSelector: 'a.web-bing__title',
  1004. textNodeSelector: 'span.web-bing__url',
  1005. updateTextByOverwrite: true,
  1006. urlDisplayMethod: 2
  1007. }
  1008. ]
  1009. // Additional search engines can be defined here...
  1010. };
  1011.  
  1012. // User-defined list of search engine instance URLs
  1013. const searchEngines = {
  1014. 'google': {
  1015. hosts: ['google.com'],
  1016. // search results container
  1017. // you can ignore this parameter if you don't want to set it, just delete it
  1018. // defult value is 'body'
  1019. resultContainerSelectors: ['div.GyAeWb#rcnt']
  1020. },
  1021. 'yandex': {
  1022. hosts: [
  1023. 'yandex.com',
  1024. 'yandex.ru'
  1025. ],
  1026. resultContainerSelectors: ['div.main__container']
  1027. },
  1028. 'searx': {
  1029. hosts: [
  1030. 'search.disroot.org',
  1031. 'searx.tiekoetter.com',
  1032. 'search.bus-hit.me',
  1033. 'search.inetol.net',
  1034. 'priv.au',
  1035. 'searx.be',
  1036. 'searxng.site',
  1037. 'search.hbubli.cc',
  1038. 'search.im-in.space',
  1039. 'opnxng.com',
  1040. 'search.upinmars.com',
  1041. 'search.sapti.me',
  1042. 'freesearch.club',
  1043. 'xo.wtf',
  1044. 'www.gruble.de',
  1045. 'searx.tuxcloud.net',
  1046. 'baresearch.org',
  1047. 'searx.daetalytica.io',
  1048. 'etsi.me',
  1049. 'search.leptons.xyz',
  1050. 'search.rowie.at',
  1051. 'search.mdosch.de',
  1052. 'searx.catfluori.de',
  1053. 'searx.si',
  1054. 'searx.namejeff.xyz',
  1055. 'search.itstechtime.com',
  1056. 's.mble.dk',
  1057. 'searx.kutay.dev',
  1058. 'ooglester.com',
  1059. 'searx.ox2.fr',
  1060. 'searx.techsaviours.org',
  1061. 'searx.perennialte.ch',
  1062. 's.trung.fun',
  1063. 'search.in.projectsegfau.lt',
  1064. 'search.projectsegfau.lt',
  1065. 'darmarit.org',
  1066. 'searx.lunar.icu',
  1067. 'nyc1.sx.ggtyler.dev',
  1068. 'search.rhscz.eu',
  1069. 'paulgo.io',
  1070. 'northboot.xyz',
  1071. 'searx.zhenyapav.com',
  1072. 'searxng.ch',
  1073. 'copp.gg',
  1074. 'searx.sev.monster',
  1075. 'searx.oakleycord.dev',
  1076. 'searx.juancord.xyz',
  1077. 'searx.work',
  1078. 'search.ononoki.org',
  1079. 'search.demoniak.ch',
  1080. 'searx.cthd.icu',
  1081. 'searx.fmhy.net',
  1082. 'searx.headpat.exchange',
  1083. 'sex.finaltek.net',
  1084. 'search.gcomm.ch',
  1085. 'search.smnz.de',
  1086. 'searx.ankha.ac',
  1087. 'search.lvkaszus.pl',
  1088. 'searx.nobulart.com',
  1089. 'sx.t-1.org',
  1090. 'www.jabber-germany.de',
  1091. 'sx.catgirl.cloud'
  1092. ],
  1093. resultContainerSelectors: [
  1094. 'main#main_results'
  1095. // 'maindiv#main_results div#urls'
  1096. // 'div#sidebar div#infoboxes'
  1097. ]
  1098. },
  1099. 'startpage': {
  1100. hosts: ['startpage.com'],
  1101. resultContainerSelectors: [
  1102. 'div.show-results',
  1103. ]
  1104. },
  1105. 'brave': {
  1106. hosts: ['search.brave.com'],
  1107. resultContainerSelectors: [
  1108. 'main.main-column',
  1109. 'aside.sidebar'
  1110. ]
  1111. },
  1112. 'duckduckgo': {
  1113. hosts: ['duckduckgo.com'],
  1114. resultContainerSelectors: [
  1115. 'section[data-testid="mainline"][data-area="mainline"]',
  1116. 'section[data-testid="sidebar"][data-area="sidebar"]'
  1117. ]
  1118. },
  1119. 'ghostery': {
  1120. hosts: ['ghosterysearch.com'],
  1121. resultContainerSelectors: ['section.results']
  1122. },
  1123. 'presearch': {
  1124. hosts: ['presearch.com'],
  1125. resultContainerSelectors: ['div.w-full']
  1126. },
  1127. 'metager': {
  1128. hosts: [
  1129. 'metager.org',
  1130. 'metager.de'
  1131. ],
  1132. resultContainerSelectors: [
  1133. 'div#results',
  1134. 'div#additions-container'
  1135. ]
  1136. },
  1137. '4get': {
  1138. hosts: [
  1139. '4get.ca',
  1140. '4get.silly.computer',
  1141. '4get.plunked.party',
  1142. '4get.konakona.moe',
  1143. '4get.sijh.net',
  1144. '4get.hbubli.cc',
  1145. '4get.perennialte.ch',
  1146. '4get.zzls.xyz',
  1147. '4getus.zzls.xyz',
  1148. '4get.seitan-ayoub.lol',
  1149. '4get.dcs0.hu',
  1150. '4get.psily.garden',
  1151. '4get.lvkaszus.pl',
  1152. '4get.kizuki.lol'
  1153. ],
  1154. resultContainerSelectors: ['div#overflow']
  1155. },
  1156. 'librey': {
  1157. hosts: [
  1158. 'search.ahwx.org',
  1159. 'search2.ahwx.org',
  1160. 'search3.ahwx.org',
  1161. 'ly.owo.si',
  1162. 'librey.franklyflawless.org',
  1163. 'librey.org',
  1164. 'search.davidovski.xyz',
  1165. 'search.milivojevic.in.rs',
  1166. 'glass.prpl.wtf',
  1167. 'librex.uk.to',
  1168. 'librey.ix.tc',
  1169. 'search.funami.tech',
  1170. 'librex.retro-hax.net',
  1171. 'librex.nohost.network',
  1172. 'search.pabloferreiro.es',
  1173. 'librey.baczek.me',
  1174. 'lx.benike.me',
  1175. 'search.seitan-ayoub.lol',
  1176. 'librey.myroware.net',
  1177. 'librey.nezumi.party',
  1178. 'search.zeroish.xyz',
  1179. 'search.zeroish.xyz'
  1180. ],
  1181. resultContainerSelectors: [
  1182. 'div.text-result-container',
  1183. 'p.special-result-container'
  1184. ]
  1185. },
  1186. 'stract': {
  1187. hosts: ['stract.com'],
  1188. resultContainerSelectors: [
  1189. 'div.col-start-1',
  1190. 'div.row-start-2'
  1191. ]
  1192. },
  1193. 'etools': {
  1194. hosts: ['etools.ch'],
  1195. // resultContainerSelectors: ['table.result']
  1196. },
  1197. 'mojeek': {
  1198. hosts: ['mojeek.com'],
  1199. resultContainerSelectors: ['div.container.serp-results']
  1200. },
  1201. 'yep': {
  1202. hosts: ['yep.com']
  1203. },
  1204. 'torry': {
  1205. hosts: ['torry.io'],
  1206. resultContainerSelectors: ['div.searpListouterappend'],
  1207. attribute: 'data-target'
  1208. },
  1209. 'qwant': {
  1210. hosts: ['qwant.com'],
  1211. resultContainerSelectors: ['div._35zId']
  1212. },
  1213. 'ecosia': {
  1214. hosts: ['ecosia.org'],
  1215. resultContainerSelectors: [
  1216. 'section.mainline.web__mainline',
  1217. 'aside.sidebar.web__sidebar'
  1218. ]
  1219. },
  1220. 'oceanhero': {
  1221. hosts: ['oceanhero.today']
  1222. },
  1223. 'swisscows': {
  1224. hosts: ['swisscows.com'],
  1225. resultContainerSelectors: ['section.container.page-results']
  1226. },
  1227. 'lilo': {
  1228. hosts: ['search.lilo.org'],
  1229. resultContainerSelectors: ['div.container#content']
  1230. },
  1231. 'entireweb': {
  1232. hosts: ['search.entireweb.com'],
  1233. resultContainerSelectors: ['div.container.search-container']
  1234. },
  1235. 'gmx': {
  1236. hosts: ['search.gmx.com']
  1237. },
  1238. 'youcare': {
  1239. hosts: ['youcare.world']
  1240. },
  1241. 'spot': {
  1242. hosts: ['spot.ecloud.global'],
  1243. resultContainerSelectors: ['div.container.contents']
  1244. },
  1245. 'nona': {
  1246. hosts: ['nona.de'],
  1247. resultContainerSelectors: ['main.search-results div.container']
  1248. },
  1249. 'exalead': {
  1250. hosts: ['exalead.com'],
  1251. resultContainerSelectors: ['ul.media-list']
  1252. },
  1253. 'seznam': {
  1254. hosts: ['search.seznam.cz'],
  1255. resultContainerSelectors: ['div.PageWrapper.SearchPage#searchpage-root'],
  1256. },
  1257. 'gibiru': {
  1258. hosts: ['gibiru.com'],
  1259. resultContainerSelectors: ['div.container#web-results'],
  1260. },
  1261. 'lukol': {
  1262. hosts: ['lukol.com']
  1263. },
  1264. 'givewater': {
  1265. hosts: ['search.givewater.com'],
  1266. resultContainerSelectors: ['div.mainline-results']
  1267. },
  1268. 'excite': {
  1269. hosts: ['results.excite.com'],
  1270. resultContainerSelectors: ['div.mainline-results']
  1271. },
  1272. 'webcrawler': {
  1273. hosts: ['webcrawler.com'],
  1274. resultContainerSelectors: ['div.web-bing'],
  1275. },
  1276. 'metacrawler': {
  1277. hosts: ['metacrawler.com'],
  1278. resultContainerSelectors: ['div.web-bing'],
  1279. },
  1280. 'dogpile': {
  1281. hosts: ['dogpile.com'],
  1282. resultContainerSelectors: ['div.web-bing'],
  1283. }
  1284. // ... more search engines
  1285. };
  1286.  
  1287. // Function to modify URLs and optionally text
  1288. const modifyUrls = (engine, observer, resultContainer, engineInfo) => {
  1289. try {
  1290. const selectors = selectorRules[engine];
  1291. if (selectors) {
  1292. // Disconnect the observer to prevent recursive triggering
  1293. observer.disconnect();
  1294.  
  1295. // Modify results
  1296. selectors.forEach(rule => {
  1297. if (rule.selector) {
  1298. processElements(rule.selector, rule, engineInfo);
  1299. } else if (rule.parentSelector) {
  1300. processParentElements(rule.parentSelector, rule, engineInfo);
  1301. }
  1302. });
  1303.  
  1304. // Reconnect the observer after DOM modifications are done
  1305. observer.observe(resultContainer, { childList: true, subtree: true });
  1306. }
  1307. } catch (error) {
  1308. console.error("URL Modification Error: ", error);
  1309. }
  1310. };
  1311.  
  1312. // Function to process elements specified by `selector`
  1313. const processElements = (selector, rule, engineInfo) => {
  1314. const elements = document.querySelectorAll(selector);
  1315. const additionalAttribute = engineInfo.attribute; // Get the additional attribute if specified
  1316. if (elements.length > 0) {
  1317. elements.forEach(element => {
  1318. for (let i = 0; i < urlModificationRules.length; i++) {
  1319. try {
  1320. const urlRule = urlModificationRules[i];
  1321. let urlToModify = additionalAttribute ? element.getAttribute(additionalAttribute) : element.href;
  1322. // update attribute
  1323. if (urlToModify && urlRule.matchRegex.test(urlToModify)) {
  1324. // Generate redirected URL
  1325. let newUrl = urlToModify.replace(urlRule.matchRegex, urlRule.replaceWith);
  1326. newUrl = rule.useTopLevelDomain ? extractTopLevelDomain(newUrl) : newUrl;
  1327. if (element.href) {
  1328. element.href = newUrl;
  1329. } else if (additionalAttribute) {
  1330. element.setAttribute(additionalAttribute, newUrl);
  1331. }
  1332. updateTextContent(element, rule, removeParameters(newUrl));
  1333. break;
  1334. }
  1335. } catch (error) {
  1336. console.error("Update Link/Text Error: ", error);
  1337. }
  1338. }
  1339. });
  1340. }
  1341. };
  1342.  
  1343. // Function to process elements specified by `parentSelector`
  1344. const processParentElements = (selector, rule, engineInfo) => {
  1345. const elements = document.querySelectorAll(selector);
  1346. const additionalAttribute = engineInfo.attribute; // Get the additional attribute if specified
  1347. if (elements.length > 0) {
  1348. elements.forEach(element => {
  1349. const linkElement = element.querySelector(rule.linkNodeSelector);
  1350. const textElement = element.querySelector(rule.textNodeSelector);
  1351.  
  1352. for (let i = 0; i < urlModificationRules.length; i++) {
  1353. try {
  1354. const urlRule = urlModificationRules[i];
  1355. let urlToModify = additionalAttribute ? element.getAttribute(additionalAttribute) : linkElement.href;
  1356. // update attribute
  1357. if (urlToModify && urlRule.matchRegex.test(urlToModify)) {
  1358. // Generate redirected URL
  1359. let newUrl = urlToModify.replace(urlRule.matchRegex, urlRule.replaceWith);
  1360. newUrl = rule.useTopLevelDomain ? extractTopLevelDomain(newUrl) : newUrl;
  1361. if (linkElement.href) {
  1362. linkElement.href = newUrl;
  1363. } else if (additionalAttribute) {
  1364. linkElement.setAttribute(additionalAttribute, newUrl);
  1365. }
  1366. updateTextContent(textElement, rule, removeParameters(newUrl));
  1367. break;
  1368. }
  1369. } catch (error) {
  1370. console.error("Update Link/Text Error: ", error);
  1371. }
  1372. }
  1373. });
  1374. }
  1375. };
  1376.  
  1377. // Function to update text content (displayed URL)
  1378. const updateTextContent = (element, rule, newUrl) => {
  1379. if (rule.updateTextWithoutOverwrite || rule.updateTextByOverwrite || rule.updateChildText) {
  1380. try {
  1381. if (rule.multiElementsForUrlDisplay) {
  1382. updateMultiElementContent(element, rule, newUrl);
  1383. } else {
  1384. let targetElement = element;
  1385. if (rule.childSelector) {
  1386. targetElement = element.querySelector(rule.childSelector)
  1387. }
  1388. updateSingleElementText(targetElement, rule, newUrl);
  1389. }
  1390. } catch (error) {
  1391. console.error("Update Displayed URL Error: ", error);
  1392. }
  1393. }
  1394. };
  1395.  
  1396. // Function to update text for multi elements (e.g. DuckDuckGo, Brave)
  1397. const updateMultiElementContent = (targetElement, rule, newUrl) => {
  1398. if (!targetElement) {
  1399. console.error("Target DOM Element not found for Multi-Element Text update!");
  1400. return;
  1401. }
  1402. // Remove the "https://" protocol if containProtocol is false
  1403. newUrl = rule.containProtocol ? newUrl : removeProtocol(newUrl);
  1404. let formattedUrl = breadCumbFormat(newUrl, rule.containProtocol);
  1405. let urlParts = formattedUrl.split(' › ');
  1406.  
  1407. const spans = targetElement.querySelectorAll(rule.childSelector)
  1408.  
  1409. switch (rule.multiElementsForUrlDisplay) {
  1410. case 1:
  1411. parallelElements(urlParts, spans);
  1412. break;
  1413. case 2:
  1414. mixedElements(urlParts, spans, targetElement);
  1415. break;
  1416. }
  1417. };
  1418.  
  1419. const parallelElements = (urlParts, elements) => {
  1420. if (elements && elements.length >= 2) {
  1421. elements.forEach(clearElementContent);
  1422. elements[0].textContent = urlParts[0]; // Update the first part
  1423. elements[1].textContent = ' › ' + urlParts.slice(1).join(' › '); // Update the second part
  1424. } else {
  1425. console.error("Script: Expected structure not found for Multi-Element (parallel elements) URL update!");
  1426. }
  1427. };
  1428.  
  1429. const mixedElements = (urlParts, elements, parent) => {
  1430. if (elements && elements.length >= 1) {
  1431. elements.forEach(clearElementContent);
  1432. updateTextWithoutOverwriteChildNodes(parent, urlParts[0]); // Update the first part
  1433. elements[0].textContent = ' › ' + urlParts.slice(1).join(' › '); // Update the second part
  1434. } else {
  1435. console.error("Script: Expected structure not found for Multi-Element (mixed elements) URL update!");
  1436. }
  1437. };
  1438.  
  1439. // Function to update text for a single element
  1440. const updateSingleElementText = (targetElement, rule, newUrl) => {
  1441. if (!targetElement) {
  1442. console.error("Target DOM Element not found for Single-Element Text update!");
  1443. return;
  1444. }
  1445. let formattedUrl = '';
  1446. switch (rule.urlDisplayMethod) {
  1447. case 1:
  1448. formattedUrl = breadCumbFormat(newUrl, rule.containProtocol);
  1449. break;
  1450. case 2:
  1451. formattedUrl = newUrl; // Full URL with protocol
  1452. break;
  1453. case 3:
  1454. formattedUrl = decodeURIComponent(removeProtocol(newUrl)); // Full URL without protocol
  1455. break;
  1456. }
  1457. if (rule.updateTextWithoutOverwrite) {
  1458. updateTextWithoutOverwriteChildNodes(targetElement, formattedUrl);
  1459. } if (rule.updateTextByOverwrite) {
  1460. updateTextByOverwriteEverything(targetElement, formattedUrl);
  1461. } else {
  1462. targetElement.textContent = formattedUrl;
  1463. }
  1464. };
  1465.  
  1466. // Function for Method 1 (Breadcrumb style URLs), leaving 'https://' intact
  1467. const breadCumbFormat = (url, containProtocol) => {
  1468. if (!containProtocol) {
  1469. url = removeProtocol(url);
  1470. }
  1471. // Split the URL while keeping 'https://' intact; Replace the second occurrence of 'https://' with 'https', if exists
  1472. // Replace the first occurrence of 'https://' with a placeholder
  1473. url = url.replace('https://', 'https›');
  1474. // Deal with the second 'https://'
  1475. let secondHttpsIndex = url.indexOf('https://');
  1476. if (secondHttpsIndex !== -1) {
  1477. url = url.substring(0, secondHttpsIndex) + 'https/' + url.substring(secondHttpsIndex + 8);
  1478. }
  1479. // Split the URL with '/'
  1480. let parts = url.split('/');
  1481. // Restore the first 'https://' in the URL
  1482. parts[0] = parts[0].replace('https›', 'https://');
  1483.  
  1484. // Join the URL parts with ' › '
  1485. let joinedUrl = parts.join(' › ');
  1486.  
  1487. // Decode the URL to convert encoded characters to their original form
  1488. return decodeURIComponent(joinedUrl);
  1489. };
  1490.  
  1491. // Function to update only the text node within an element, leave the child elements, if exist, intact
  1492. const updateTextWithoutOverwriteChildNodes = (element, newContent) => {
  1493. let foundTextNode = false;
  1494. // Iterate through child nodes
  1495. for (const node of element.childNodes) {
  1496. // Identify and update the first text node
  1497. if (node.nodeType === Node.TEXT_NODE) {
  1498. node.nodeValue = newContent;
  1499. foundTextNode = true;
  1500. break; // Stop after updating the first text node
  1501. }
  1502. }
  1503. };
  1504.  
  1505. // Function to update the content by overwriting everything
  1506. const updateTextByOverwriteEverything = (element, newContent) => {
  1507. clearElementContent(element);
  1508. element.textContent = newContent;
  1509. };
  1510.  
  1511. // Remove 'https://' from the URL link
  1512. const removeProtocol = (url) => {
  1513. return url.replace(/^https?:\/\//, '');
  1514. };
  1515.  
  1516. // Extract the top level domain from URL link
  1517. const extractTopLevelDomain = (url) => {
  1518. const parsedUrl = new URL(url);
  1519. return `${parsedUrl.protocol}//${parsedUrl.hostname}/`;
  1520. };
  1521.  
  1522. // Remove parameters (the part behind ?) in the URL link
  1523. const removeParameters = (url) => {
  1524. return url.split('?')[0];
  1525. };
  1526.  
  1527. // Function to clear existing content of an element
  1528. const clearElementContent = (element) => {
  1529. element.textContent = '';
  1530. };
  1531.  
  1532. // Improved function to determine the search engine
  1533. const getSearchEngineInfo = () => {
  1534. try {
  1535. const host = window.location.host;
  1536. for (const engine in searchEngines) {
  1537. if (searchEngines[engine].hosts.some(instanceHost => host.includes(instanceHost))) {
  1538. const selectors = searchEngines[engine].resultContainerSelectors || ['body']; // Default to 'body' if not specified
  1539. const attribute = searchEngines[engine].attribute; // Get the attribute if specified
  1540. return {
  1541. engine,
  1542. selectors: selectors,
  1543. attribute: attribute
  1544. };
  1545. }
  1546. }
  1547. } catch (error) {
  1548. console.error("Error determining search engine: ", error);
  1549. }
  1550. };
  1551.  
  1552. const observeToExecute = (engine, selector, engineInfo) => {
  1553. const resultContainers = document.querySelectorAll(selector);
  1554. if (resultContainers) {
  1555. resultContainers.forEach(resultContainer => {
  1556. // Observe changes in each result container
  1557. const observer = new MutationObserver(() => modifyUrls(engine, observer, resultContainer, engineInfo));
  1558. observer.observe(resultContainer, { childList: true, subtree: true });
  1559. modifyUrls(engine, observer, resultContainer, engineInfo);
  1560. });
  1561. }
  1562. };
  1563.  
  1564. // Run the script for the current search engine
  1565. try {
  1566. const engineInfo = getSearchEngineInfo();
  1567. if (engineInfo) {
  1568. engineInfo.selectors.forEach(containerSelector => {
  1569. observeToExecute(engineInfo.engine, containerSelector, engineInfo);
  1570. });
  1571. }
  1572. } catch (error) {
  1573. console.error("Error executing URL Modifier Script: ", error);
  1574. }
  1575. })();