Lemmy Universal Link Switcher

Ensures that all URLs to Lemmy instances always point to your main/home instance.

От 05.07.2023. Виж последната версия.

  1. // ==UserScript==
  2. // @name Lemmy Universal Link Switcher
  3. // @namespace http://azzurite.tv/
  4. // @license GPLv3
  5. // @version 1.2.4
  6. // @description Ensures that all URLs to Lemmy instances always point to your main/home instance.
  7. // @homepageURL https://gitlab.com/azzurite/lemmy-universal-link-switcher
  8. // @supportURL https://gitlab.com/azzurite/lemmy-universal-link-switcher/-/issues
  9. // @author Azzurite
  10. // @match *://*/*
  11. // @icon https://gitlab.com/azzurite/lemmy-universal-link-switcher/-/raw/main/resources/favicon.png?inline=true
  12. // @grant GM.setValue
  13. // @grant GM.getValue
  14. // @grant GM.xmlHttpRequest
  15. // @connect *
  16. // @require https://unpkg.com/@popperjs/core@2
  17. // @require https://unpkg.com/tippy.js@6
  18. // ==/UserScript==
  19.  
  20. (() => {
  21. // src/debug.js
  22. var DEBUG = false;
  23. function debug() {
  24. if (DEBUG)
  25. console.debug(`Rewriter | `, ...arguments);
  26. }
  27. function trace() {
  28. if (DEBUG === `trace`)
  29. console.debug(`Rewriter Trace | `, ...arguments);
  30. }
  31.  
  32. // src/instances.js
  33. function isLemmyInstance(url) {
  34. return isInstance(INSTANCES_LEMMY, url);
  35. }
  36. function isKbinInstance(url) {
  37. return isInstance(INSTANCES_KBIN, url);
  38. }
  39. function isInstance(instances, url) {
  40. if (url.origin) {
  41. return instances.has(url.origin);
  42. } else {
  43. return false;
  44. }
  45. }
  46. trace(`Define instances sets start`);
  47. var INSTANCES_LEMMY = /* @__PURE__ */ new Set([
  48. "http://lemmy.brdsnest.net",
  49. "https://0v0.social",
  50. "https://0xdd.org.ru",
  51. "https://1337lemmy.com",
  52. "https://158436977.xyz",
  53. "https://2dl.eu",
  54. "https://acqrs.co.uk",
  55. "https://actuallyruben.nl",
  56. "https://ag.batlord.org",
  57. "https://aggregation.cafe",
  58. "https://agora.nop.chat",
  59. "https://aiparadise.moe",
  60. "https://alfredoautomation.com",
  61. "https://algebro.xyz",
  62. "https://americas.cloud",
  63. "https://androiddev.network",
  64. "https://ani.social",
  65. "https://animoe.xyz",
  66. "https://apollo.town",
  67. "https://areality.social",
  68. "https://arpa.dev",
  69. "https://ascy.mooo.com",
  70. "https://atosoul.asuscomm.com",
  71. "https://aulem.org",
  72. "https://aussie.zone",
  73. "https://baomi.tv",
  74. "https://baraza.africa",
  75. "https://bbg.lol",
  76. "https://bbs.9tail.net",
  77. "https://bbs.darkwitch.net",
  78. "https://beehaw.org",
  79. "https://beer.andma.la",
  80. "https://beevibes.net",
  81. "https://bethe.kingofdog.de",
  82. "https://biglemmowski.win",
  83. "https://bin.pztrn.online",
  84. "https://bluuit.org",
  85. "https://board.minimally.online",
  86. "https://bookwormstory.social",
  87. "https://borg.chat",
  88. "https://botnet.club",
  89. "https://bubblesthebunny.com",
  90. "https://bulletintree.com",
  91. "https://burrp.xyz",
  92. "https://butts.international",
  93. "https://c.calciumlabs.com",
  94. "https://caint.org",
  95. "https://campfyre.nickwebster.dev",
  96. "https://cavy.rocks",
  97. "https://cdda.social",
  98. "https://centennialstate.social",
  99. "https://chat.maiion.com",
  100. "https://cigar.cx",
  101. "https://civilloquy.com",
  102. "https://clatter.eu",
  103. "https://cnvrs.net",
  104. "https://cocte.au",
  105. "https://code4lib.net",
  106. "https://coeus.sbs",
  107. "https://communick.news",
  108. "https://communities.azkware.net",
  109. "https://community.adiquaints.moe",
  110. "https://community.destinovate.com",
  111. "https://community.nicfab.it",
  112. "https://compuverse.uk",
  113. "https://crystals.rest",
  114. "https://culture0.cc",
  115. "https://cybercrime.zip",
  116. "https://dandroid.app",
  117. "https://darmok.xyz",
  118. "https://databend.run",
  119. "https://demmy.co.uk",
  120. "https://demotheque.com",
  121. "https://dendarii.alaeron.com",
  122. "https://derp.foo",
  123. "https://derpzilla.net",
  124. "https://dgngrnder.com",
  125. "https://diggit.xyz",
  126. "https://digipres.cafe",
  127. "https://digitalgoblin.uk",
  128. "https://discuss.as200950.com",
  129. "https://discuss.divergentparenting.space",
  130. "https://discuss.dizl.de",
  131. "https://discuss.icewind.me",
  132. "https://discuss.jacen.moe",
  133. "https://discuss.ntfy.sh",
  134. "https://discuss.online",
  135. "https://discuss.tchncs.de",
  136. "https://distress.digital",
  137. "https://dmv.social",
  138. "https://donky.social",
  139. "https://dork.farm",
  140. "https://dormi.zone",
  141. "https://drachennetz.com",
  142. "https://drak.gg",
  143. "https://drlemmy.net",
  144. "https://ds9.lemmy.ml",
  145. "https://dsilo061298.ddns.net",
  146. "https://dubvee.org",
  147. "https://ducks.dev",
  148. "https://einweckglas.com",
  149. "https://endlesstalk.org",
  150. "https://endofti.me",
  151. "https://enterprise.lemmy.ml",
  152. "https://eslemmy.es",
  153. "https://eventfrontier.com",
  154. "https://eviltoast.org",
  155. "https://exploding-heads.com",
  156. "https://ezlemmy.io",
  157. "https://f.jbradaric.me",
  158. "https://f.soopy.moe",
  159. "https://fadoverso.pt",
  160. "https://fanaticus.social",
  161. "https://fanexus.com",
  162. "https://fed.creve.com",
  163. "https://fed.rosssi.co.uk",
  164. "https://feddi.no",
  165. "https://feddit.afop.tech",
  166. "https://feddit.at",
  167. "https://feddit.ch",
  168. "https://feddit.cl",
  169. "https://feddit.de",
  170. "https://feddit.dk",
  171. "https://feddit.dnico.io",
  172. "https://feddit.eu",
  173. "https://feddit.fun",
  174. "https://feddit.it",
  175. "https://feddit.jp",
  176. "https://feddit.nl",
  177. "https://feddit.nu",
  178. "https://feddit.nz",
  179. "https://feddit.pl",
  180. "https://feddit.ro",
  181. "https://feddit.rocks",
  182. "https://feddit.site",
  183. "https://feddit.strike23.de",
  184. "https://feddit.uk",
  185. "https://feddit.win",
  186. "https://federated.community",
  187. "https://fedibb.ml",
  188. "https://fedii.me",
  189. "https://fedit.io",
  190. "https://feditown.com",
  191. "https://fediverse.ro",
  192. "https://fedjlailu.fr",
  193. "https://feed.newt.wtf",
  194. "https://feed.sokolik.info",
  195. "https://feedly.j-cloud.uk",
  196. "https://femboys.bar",
  197. "https://fenbushi.site",
  198. "https://fernchat.esotericmonkey.com",
  199. "https://fjdk.uk",
  200. "https://fl0w.cc",
  201. "https://forkk.me",
  202. "https://foro.markoop.org",
  203. "https://foros.fediverso.gal",
  204. "https://forum.basedcount.com",
  205. "https://forum.bruvland.com",
  206. "https://forum.liberatedsystems.co.uk",
  207. "https://forum.stellarcastle.net",
  208. "https://fost.hu",
  209. "https://frig.social",
  210. "https://gadgetro.id",
  211. "https://gathering.pikafan.de",
  212. "https://geddit.social",
  213. "https://gekinzuku.com",
  214. "https://gertie.uk",
  215. "https://gioia.news",
  216. "https://glasstower.nl",
  217. "https://gmestock.com",
  218. "https://goddess.name",
  219. "https://gonelemmy.xyz",
  220. "https://granitestate.social",
  221. "https://greg.city",
  222. "https://grinnit.grin.hu",
  223. "https://group.lt",
  224. "https://grumpf.horcrux.dev",
  225. "https://grumpy.schuppentier.club",
  226. "https://hakbox.social",
  227. "https://halubilo.social",
  228. "https://hammerdown.0fucks.nl",
  229. "https://heckoverflow.net",
  230. "https://heylemmy.heybro.nz",
  231. "https://hive.atlanten.se",
  232. "https://hoodlem.me",
  233. "https://hoodratshit.org",
  234. "https://hyperfair.link",
  235. "https://iboughtthisdomainbecauseithoughtitscheap.uk",
  236. "https://iceorchid.net",
  237. "https://info.prou.be",
  238. "https://infosec.pub",
  239. "https://insane.dev",
  240. "https://invariant-marxism.red",
  241. "https://iusearchlinux.fyi",
  242. "https://jalim.xyz",
  243. "https://jamie.moe",
  244. "https://jasdemi.com",
  245. "https://jemmy.jeena.net",
  246. "https://jlai.lu",
  247. "https://ka.tet42.org",
  248. "https://keeb.lol",
  249. "https://kerala.party",
  250. "https://keylog.zip",
  251. "https://kleptonix.com",
  252. "https://klingon.nl",
  253. "https://krabb.org",
  254. "https://kulupu.duckdns.org",
  255. "https://kuu.kohana.fi",
  256. "https://kwarr.com",
  257. "https://kyu.de",
  258. "https://l.1in1.net",
  259. "https://l.60228.dev",
  260. "https://l.7rg1nt.moe",
  261. "https://l.antiope.link",
  262. "https://l.biendeo.com",
  263. "https://l.bxy.sh",
  264. "https://l.dustybeer.com",
  265. "https://l.jugregator.org",
  266. "https://l.lucitt.com",
  267. "https://l.mathers.fr",
  268. "https://l.mchome.net",
  269. "https://l.nulltext.org",
  270. "https://l.plabs.social",
  271. "https://l.rickebo.com",
  272. "https://l.roofo.cc",
  273. "https://l.tunahan.social",
  274. "https://l.twos.dev",
  275. "https://l.vidja.social",
  276. "https://labdegato.com",
  277. "https://laguna.chat",
  278. "https://latte.isnot.coffee",
  279. "https://le-me.xyz",
  280. "https://le.fduck.net",
  281. "https://le.mnau.xyz",
  282. "https://leaf.dance",
  283. "https://leby.dev",
  284. "https://leddit.danmark.party",
  285. "https://leddit.social",
  286. "https://lef.li",
  287. "https://lem.agoomem.xyz",
  288. "https://lem.ainyataovi.net",
  289. "https://lem.amd.im",
  290. "https://lem.clinicians-exchange.org",
  291. "https://lem.cochrun.xyz",
  292. "https://lem.cyb3rdelia.net",
  293. "https://lem.dru5k1.com",
  294. "https://lem.elbullazul.com",
  295. "https://lem.free.as",
  296. "https://lem.lyk.pw",
  297. "https://lem.monster",
  298. "https://lem.ph3j.com",
  299. "https://lem.serkozh.me",
  300. "https://lem.simple-gear.com",
  301. "https://lem.southcape.social",
  302. "https://lem.ur-mom.gay",
  303. "https://lem.zevs.me",
  304. "https://lemdit.com",
  305. "https://lemdro.id",
  306. "https://lemellem.dasonic.xyz",
  307. "https://lemitar.meta1203.com",
  308. "https://lemiverse.xyz",
  309. "https://lemm.ee",
  310. "https://lemmerz.org",
  311. "https://lemmie.be",
  312. "https://lemmings.basic-domain.com",
  313. "https://lemmings.world",
  314. "https://lemmit.online",
  315. "https://lemmit.xyz",
  316. "https://lemmonade.marbledfennec.net",
  317. "https://lemmony.click",
  318. "https://lemmus.org",
  319. "https://lemmy.01110100.xyz",
  320. "https://lemmy.0x3d.uk",
  321. "https://lemmy.1204.org",
  322. "https://lemmy.2kd.de",
  323. "https://lemmy.4d2.org",
  324. "https://lemmy.6px.eu",
  325. "https://lemmy.86thumbs.net",
  326. "https://lemmy.absolutesix.com",
  327. "https://lemmy.adambowl.es",
  328. "https://lemmy.aguiarvieira.pt",
  329. "https://lemmy.alexland.ca",
  330. "https://lemmy.amxl.com",
  331. "https://lemmy.amyjnobody.com",
  332. "https://lemmy.ananace.dev",
  333. "https://lemmy.animal-machine.com",
  334. "https://lemmy.anji.nl",
  335. "https://lemmy.anonion.social",
  336. "https://lemmy.antemeridiem.xyz",
  337. "https://lemmy.antisocial.ly",
  338. "https://lemmy.anymore.nl",
  339. "https://lemmy.appeine.com",
  340. "https://lemmy.arpatubes.net",
  341. "https://lemmy.arun.cloud",
  342. "https://lemmy.asc6.org",
  343. "https://lemmy.ashes.wtf",
  344. "https://lemmy.atay.dev",
  345. "https://lemmy.atheos.org",
  346. "https://lemmy.aucubin.de",
  347. "https://lemmy.austinite.online",
  348. "https://lemmy.austinvaness.com",
  349. "https://lemmy.austinwadeheller.com",
  350. "https://lemmy.avata.social",
  351. "https://lemmy.azamserver.com",
  352. "https://lemmy.bapp.run",
  353. "https://lemmy.barnacles.one",
  354. "https://lemmy.baswag.de",
  355. "https://lemmy.beckmeyer.us",
  356. "https://lemmy.beebl.es",
  357. "https://lemmy.beep.computer",
  358. "https://lemmy.belegost.net",
  359. "https://lemmy.benrasich.com",
  360. "https://lemmy.beru.co",
  361. "https://lemmy.beyondcombustion.net",
  362. "https://lemmy.bitgoblin.tech",
  363. "https://lemmy.bitlab21.com",
  364. "https://lemmy.biz",
  365. "https://lemmy.blackeco.com",
  366. "https://lemmy.blad.is",
  367. "https://lemmy.blahaj.zone",
  368. "https://lemmy.bleh.au",
  369. "https://lemmy.bloodmoon-network.de",
  370. "https://lemmy.blue",
  371. "https://lemmy.blugatch.tube",
  372. "https://lemmy.boats",
  373. "https://lemmy.borlax.com",
  374. "https://lemmy.bothhands.ca",
  375. "https://lemmy.brad.ee",
  376. "https://lemmy.bran.ink",
  377. "https://lemmy.brief.guru",
  378. "https://lemmy.bringdaruck.us",
  379. "https://lemmy.browntown.dev",
  380. "https://lemmy.brynstuff.co.uk",
  381. "https://lemmy.bulbousnub.com",
  382. "https://lemmy.buller.cc",
  383. "https://lemmy.bulwarkob.com",
  384. "https://lemmy.burger.rodeo",
  385. "https://lemmy.burningboard.net",
  386. "https://lemmy.buzz",
  387. "https://lemmy.ca",
  388. "https://lemmy.cablepick.net",
  389. "https://lemmy.cafe",
  390. "https://lemmy.caffeinated.social",
  391. "https://lemmy.calebmharper.com",
  392. "https://lemmy.calvss.com",
  393. "https://lemmy.cat",
  394. "https://lemmy.catgirl.biz",
  395. "https://lemmy.cevn.io",
  396. "https://lemmy.ch3n2k.com",
  397. "https://lemmy.chatterverse.social",
  398. "https://lemmy.chiisana.net",
  399. "https://lemmy.chromozone.dev",
  400. "https://lemmy.ciechom.eu",
  401. "https://lemmy.click",
  402. "https://lemmy.cloud.aboutcher.co.uk",
  403. "https://lemmy.cloudhub.social",
  404. "https://lemmy.cloudsecurityofficehours.com",
  405. "https://lemmy.clueware.org",
  406. "https://lemmy.cmstactical.net",
  407. "https://lemmy.cnschn.com",
  408. "https://lemmy.cock.social",
  409. "https://lemmy.codesink.io",
  410. "https://lemmy.coeus.icu",
  411. "https://lemmy.com.tr",
  412. "https://lemmy.comfysnug.space",
  413. "https://lemmy.comm.social",
  414. "https://lemmy.commodore.social",
  415. "https://lemmy.computing.zone",
  416. "https://lemmy.cook.gg",
  417. "https://lemmy.cornspace.space",
  418. "https://lemmy.corrigan.xyz",
  419. "https://lemmy.coupou.fr",
  420. "https://lemmy.crafty-codes.ch",
  421. "https://lemmy.criticalbasics.xyz",
  422. "https://lemmy.croc.pw",
  423. "https://lemmy.cronocide.net",
  424. "https://lemmy.cuken.net",
  425. "https://lemmy.cultimean.group",
  426. "https://lemmy.darmstadt.social",
  427. "https://lemmy.datatekniker.dev",
  428. "https://lemmy.davidbuckley.ca",
  429. "https://lemmy.davidfreina.at",
  430. "https://lemmy.dblclk.dev",
  431. "https://lemmy.dbzer0.com",
  432. "https://lemmy.dcrich.net",
  433. "https://lemmy.deabreu.family",
  434. "https://lemmy.death916.xyz",
  435. "https://lemmy.decronym.xyz",
  436. "https://lemmy.deev.io",
  437. "https://lemmy.dekay.se",
  438. "https://lemmy.demonoftheday.eu",
  439. "https://lemmy.design",
  440. "https://lemmy.devils.house",
  441. "https://lemmy.direktoratet.se",
  442. "https://lemmy.discothe.quest",
  443. "https://lemmy.dlgreen.com",
  444. "https://lemmy.dnet.social",
  445. "https://lemmy.doesnotexist.club",
  446. "https://lemmy.dogboy.xyz",
  447. "https://lemmy.dominikoso.me",
  448. "https://lemmy.donmcgin.com",
  449. "https://lemmy.doomeer.com",
  450. "https://lemmy.dormedas.com",
  451. "https://lemmy.douwes.co.uk",
  452. "https://lemmy.downcorp.tf",
  453. "https://lemmy.dudeami.win",
  454. "https://lemmy.dunkelmann.eu",
  455. "https://lemmy.dupper.net",
  456. "https://lemmy.dynatron.me",
  457. "https://lemmy.easfrq.live",
  458. "https://lemmy.eatsleepcode.ca",
  459. "https://lemmy.ecliptik.com",
  460. "https://lemmy.eco.br",
  461. "https://lemmy.edgarchirivella.com",
  462. "https://lemmy.edgeburnmedia.com",
  463. "https://lemmy.efradaphi.de",
  464. "https://lemmy.eic.lu",
  465. "https://lemmy.einval.net",
  466. "https://lemmy.eldarerathis.com",
  467. "https://lemmy.elest.io",
  468. "https://lemmy.elmusfire.xyz",
  469. "https://lemmy.emopolarbear.com",
  470. "https://lemmy.enchanted.social",
  471. "https://lemmy.enter-key.net",
  472. "https://lemmy.escapebigtech.info",
  473. "https://lemmy.estrogen.plus",
  474. "https://lemmy.eus",
  475. "https://lemmy.fail",
  476. "https://lemmy.fakecake.org",
  477. "https://lemmy.fanboys.xyz",
  478. "https://lemmy.fap.ie",
  479. "https://lemmy.fauxreigner.net",
  480. "https://lemmy.fbievan.live",
  481. "https://lemmy.fbxl.net",
  482. "https://lemmy.fdvrs.xyz",
  483. "https://lemmy.federate.cc",
  484. "https://lemmy.fedi.bub.org",
  485. "https://lemmy.fedihub.social",
  486. "https://lemmy.fediverse.jp",
  487. "https://lemmy.film",
  488. "https://lemmy.finance",
  489. "https://lemmy.flauschbereich.de",
  490. "https://lemmy.flugratte.dev",
  491. "https://lemmy.flunky.club",
  492. "https://lemmy.fmhy.ml",
  493. "https://lemmy.fosshost.com",
  494. "https://lemmy.fourbees.net",
  495. "https://lemmy.foxden.party",
  496. "https://lemmy.franciscogil.pt.eu.org",
  497. "https://lemmy.freddeliv.me",
  498. "https://lemmy.fredhs.net",
  499. "https://lemmy.fribyte.no",
  500. "https://lemmy.friheter.com",
  501. "https://lemmy.fromshado.ws",
  502. "https://lemmy.frozeninferno.xyz",
  503. "https://lemmy.froztbyte.dev",
  504. "https://lemmy.fucs.io",
  505. "https://lemmy.fun",
  506. "https://lemmy.funami.tech",
  507. "https://lemmy.funkyfish.cool",
  508. "https://lemmy.funkylab.xyz",
  509. "https://lemmy.fwgx.uk",
  510. "https://lemmy.fyi",
  511. "https://lemmy.g191919.com",
  512. "https://lemmy.g97.top",
  513. "https://lemmy.game-files.net",
  514. "https://lemmy.gamingnight.uy",
  515. "https://lemmy.gareth.computer",
  516. "https://lemmy.genkmc.de",
  517. "https://lemmy.giggly.de",
  518. "https://lemmy.gimmin.com",
  519. "https://lemmy.gjz010.com",
  520. "https://lemmy.glasgow.social",
  521. "https://lemmy.gmprojects.pro",
  522. "https://lemmy.graphics",
  523. "https://lemmy.graz.social",
  524. "https://lemmy.grenicmars.xyz",
  525. "https://lemmy.gross.hosting",
  526. "https://lemmy.grygon.com",
  527. "https://lemmy.gsp8181.co.uk",
  528. "https://lemmy.gtfo.social",
  529. "https://lemmy.gumpri.ch",
  530. "https://lemmy.hackerbots.net",
  531. "https://lemmy.hacktheplanet.be",
  532. "https://lemmy.haigner.me",
  533. "https://lemmy.halfbro.xyz",
  534. "https://lemmy.halfhosted.com",
  535. "https://lemmy.hamrick.xyz",
  536. "https://lemmy.havocperil.uk",
  537. "https://lemmy.helheim.net",
  538. "https://lemmy.helios42.de",
  539. "https://lemmy.hellwhore.com",
  540. "https://lemmy.help",
  541. "https://lemmy.helvetet.eu",
  542. "https://lemmy.heorot.uk",
  543. "https://lemmy.hogru.ch",
  544. "https://lemmy.holmosapien.com",
  545. "https://lemmy.hosted.frl",
  546. "https://lemmy.hpost.no",
  547. "https://lemmy.hqueue.dev",
  548. "https://lemmy.hugovr.dev",
  549. "https://lemmy.hutch.chat",
  550. "https://lemmy.icyserver.eu",
  551. "https://lemmy.id",
  552. "https://lemmy.insley.cloud",
  553. "https://lemmy.intai.tech",
  554. "https://lemmy.irrealis.net",
  555. "https://lemmy.itermori.de",
  556. "https://lemmy.iys.io",
  557. "https://lemmy.jacaranda.club",
  558. "https://lemmy.jamesj999.co.uk",
  559. "https://lemmy.jasondove.me",
  560. "https://lemmy.jasonsanta.xyz",
  561. "https://lemmy.jcaks.net",
  562. "https://lemmy.jcm.re",
  563. "https://lemmy.jengo.ca",
  564. "https://lemmy.jerick.xyz",
  565. "https://lemmy.jigoku.us.to",
  566. "https://lemmy.jlh.name",
  567. "https://lemmy.jmss.io",
  568. "https://lemmy.jmtr.org",
  569. "https://lemmy.jnks.xyz",
  570. "https://lemmy.johnpanos.com",
  571. "https://lemmy.jonaharagon.net",
  572. "https://lemmy.jpaulus.io",
  573. "https://lemmy.jpiolho.com",
  574. "https://lemmy.jsnordmann.de",
  575. "https://lemmy.jstsmthrgk.eu",
  576. "https://lemmy.jtmn.dev",
  577. "https://lemmy.juggler.jp",
  578. "https://lemmy.justin.rs",
  579. "https://lemmy.k6qw.com",
  580. "https://lemmy.kaelig.ovh",
  581. "https://lemmy.kagura.eu",
  582. "https://lemmy.kaouenn-noz.fr",
  583. "https://lemmy.karaolidis.com",
  584. "https://lemmy.kazsi.hu",
  585. "https://lemmy.kde.social",
  586. "https://lemmy.kemomimi.fans",
  587. "https://lemmy.kensand.net",
  588. "https://lemmy.keychat.org",
  589. "https://lemmy.kghorvath.com",
  590. "https://lemmy.khorne.me",
  591. "https://lemmy.kiberness.xyz",
  592. "https://lemmy.kilo666.com",
  593. "https://lemmy.kitsuna.net",
  594. "https://lemmy.kizaing.ca",
  595. "https://lemmy.ko4abp.com",
  596. "https://lemmy.kodeklang.social",
  597. "https://lemmy.korgen.xyz",
  598. "https://lemmy.koski.co",
  599. "https://lemmy.kozow.com",
  600. "https://lemmy.krobbel.xyz",
  601. "https://lemmy.krobier.com",
  602. "https://lemmy.kussi.me",
  603. "https://lemmy.kutara.io",
  604. "https://lemmy.kuub.io",
  605. "https://lemmy.kwain.net",
  606. "https://lemmy.kweb.ovh",
  607. "https://lemmy.l00p.org",
  608. "https://lemmy.l0nax.org",
  609. "https://lemmy.lantian.pub",
  610. "https://lemmy.legally-berlin.de",
  611. "https://lemmy.lemist.de",
  612. "https://lemmy.lettucegarden.net",
  613. "https://lemmy.lif.ovh",
  614. "https://lemmy.link",
  615. "https://lemmy.linuxuserspace.show",
  616. "https://lemmy.littleberrylodge.co.uk",
  617. "https://lemmy.loomy.li",
  618. "https://lemmy.loungerat.io",
  619. "https://lemmy.loutsenhizer.com",
  620. "https://lemmy.lpcha.im",
  621. "https://lemmy.lt",
  622. "https://lemmy.lukeog.com",
  623. "https://lemmy.lundgrensjostrom.com",
  624. "https://lemmy.m0rk.space",
  625. "https://lemmy.m1k.cloud",
  626. "https://lemmy.macaddict89.me",
  627. "https://lemmy.mackners.com",
  628. "https://lemmy.magnor.ovh",
  629. "https://lemmy.maisputain.ovh",
  630. "https://lemmy.mambastretch.com",
  631. "https://lemmy.management",
  632. "https://lemmy.maples.dev",
  633. "https://lemmy.mararead.com",
  634. "https://lemmy.marud.fr",
  635. "https://lemmy.mats.ooo",
  636. "https://lemmy.matthe815.dev",
  637. "https://lemmy.max-p.me",
  638. "https://lemmy.mazurka.xyz",
  639. "https://lemmy.mb-server.com",
  640. "https://lemmy.mbirth.uk",
  641. "https://lemmy.mbl.social",
  642. "https://lemmy.megumin.org",
  643. "https://lemmy.meissners.me",
  644. "https://lemmy.meli.dev",
  645. "https://lemmy.memmex.de",
  646. "https://lemmy.menf.in",
  647. "https://lemmy.meowchat.xyz",
  648. "https://lemmy.meridiangrp.co.uk",
  649. "https://lemmy.micheal65536.duckdns.org",
  650. "https://lemmy.miichelle.moe",
  651. "https://lemmy.mildgrim.com",
  652. "https://lemmy.minie4.de",
  653. "https://lemmy.minionflo.net",
  654. "https://lemmy.minji.xyz",
  655. "https://lemmy.ml",
  656. "https://lemmy.mlaga97.space",
  657. "https://lemmy.mlsn.fr",
  658. "https://lemmy.modshiftx.com",
  659. "https://lemmy.monster",
  660. "https://lemmy.moonling.nl",
  661. "https://lemmy.mooo.com",
  662. "https://lemmy.morrisherd.com",
  663. "https://lemmy.mrm.one",
  664. "https://lemmy.mrmonkey.xyz",
  665. "https://lemmy.mumbled.xyz",
  666. "https://lemmy.munsell.io",
  667. "https://lemmy.mws.rocks",
  668. "https://lemmy.mxh.nu",
  669. "https://lemmy.my.id",
  670. "https://lemmy.mykhoury.com",
  671. "https://lemmy.mypinghertz.com",
  672. "https://lemmy.myserv.one",
  673. "https://lemmy.myspamtrap.com",
  674. "https://lemmy.mywire.xyz",
  675. "https://lemmy.naga.sh",
  676. "https://lemmy.name",
  677. "https://lemmy.namwen.me",
  678. "https://lemmy.nauk.io",
  679. "https://lemmy.nbsp.one",
  680. "https://lemmy.neeley.cloud",
  681. "https://lemmy.neoluxcommunications.com",
  682. "https://lemmy.nerdcore.social",
  683. "https://lemmy.nexus",
  684. "https://lemmy.nikore.net",
  685. "https://lemmy.nine-hells.net",
  686. "https://lemmy.ninja",
  687. "https://lemmy.noogs.me",
  688. "https://lemmy.nope.ly",
  689. "https://lemmy.nopro.be",
  690. "https://lemmy.nowsci.com",
  691. "https://lemmy.nrd.li",
  692. "https://lemmy.nz",
  693. "https://lemmy.obrell.se",
  694. "https://lemmy.oilyeagle.com",
  695. "https://lemmy.omat.nl",
  696. "https://lemmy.one",
  697. "https://lemmy.onlylans.io",
  698. "https://lemmy.orefice.win",
  699. "https://lemmy.otakufarms.com",
  700. "https://lemmy.ourdoma.in",
  701. "https://lemmy.paesserver.de",
  702. "https://lemmy.pastwind.top",
  703. "https://lemmy.pathoris.de",
  704. "https://lemmy.pcft.eu",
  705. "https://lemmy.pe1uca.dev",
  706. "https://lemmy.pec0ra.ch",
  707. "https://lemmy.pen15.club",
  708. "https://lemmy.perigrine.ca",
  709. "https://lemmy.perthchat.org",
  710. "https://lemmy.phiresky.xyz",
  711. "https://lemmy.phoenix591.com",
  712. "https://lemmy.physfluids.fr",
  713. "https://lemmy.picote.ch",
  714. "https://lemmy.pierre-couy.fr",
  715. "https://lemmy.pipe01.net",
  716. "https://lemmy.piperservers.net",
  717. "https://lemmy.pipipopo.pl",
  718. "https://lemmy.piracy.guide",
  719. "https://lemmy.pit.ninja",
  720. "https://lemmy.place",
  721. "https://lemmy.plasmatrap.com",
  722. "https://lemmy.platypus-sandbox.com",
  723. "https://lemmy.podycust.co.uk",
  724. "https://lemmy.potatoe.ca",
  725. "https://lemmy.ppl.town",
  726. "https://lemmy.pro",
  727. "https://lemmy.procrastinati.org",
  728. "https://lemmy.productionservers.net",
  729. "https://lemmy.programmerhumor.io",
  730. "https://lemmy.pryst.de",
  731. "https://lemmy.pt",
  732. "https://lemmy.pub",
  733. "https://lemmy.pubsub.fun",
  734. "https://lemmy.pussthecat.org",
  735. "https://lemmy.pwarde.nl",
  736. "https://lemmy.pwzle.com",
  737. "https://lemmy.pxm.nl",
  738. "https://lemmy.quad442.com",
  739. "https://lemmy.r4r3.me",
  740. "https://lemmy.r6e.dev",
  741. "https://lemmy.radio",
  742. "https://lemmy.ramble.moe",
  743. "https://lemmy.rat.academy",
  744. "https://lemmy.ravc.tech",
  745. "https://lemmy.reckless.dev",
  746. "https://lemmy.recursed.net",
  747. "https://lemmy.remotelab.uk",
  748. "https://lemmy.remoteplay.im",
  749. "https://lemmy.rhymelikedi.me",
  750. "https://lemmy.richardkramer.de",
  751. "https://lemmy.riffel.family",
  752. "https://lemmy.riichi.me",
  753. "https://lemmy.rimkus.it",
  754. "https://lemmy.robotra.sh",
  755. "https://lemmy.rollenspiel.monster",
  756. "https://lemmy.ronsmans.eu",
  757. "https://lemmy.room409.xyz",
  758. "https://lemmy.roombob.cat",
  759. "https://lemmy.rubenernst.dev",
  760. "https://lemmy.run",
  761. "https://lemmy.ruud.je",
  762. "https://lemmy.s9m.xyz",
  763. "https://lemmy.safe-internet.org",
  764. "https://lemmy.saik0.com",
  765. "https://lemmy.samad.one",
  766. "https://lemmy.sascamooch.com",
  767. "https://lemmy.sbs",
  768. "https://lemmy.scam-mail.me",
  769. "https://lemmy.schlunker.com",
  770. "https://lemmy.schuerz.at",
  771. "https://lemmy.scootaloo.pl",
  772. "https://lemmy.scottlabs.io",
  773. "https://lemmy.scurry.io",
  774. "https://lemmy.sdfeu.org",
  775. "https://lemmy.sdfjp.org",
  776. "https://lemmy.sebbem.se",
  777. "https://lemmy.secnd.me",
  778. "https://lemmy.sedimentarymountains.com",
  779. "https://lemmy.seifert.id",
  780. "https://lemmy.self-hosted.site",
  781. "https://lemmy.selfip.org",
  782. "https://lemmy.servarr.com",
  783. "https://lemmy.server.fifthdread.com",
  784. "https://lemmy.serverfail.party",
  785. "https://lemmy.services.coupou.fr",
  786. "https://lemmy.sh",
  787. "https://lemmy.shattervideoisland.com",
  788. "https://lemmy.sherry.moe",
  789. "https://lemmy.shihaam.me",
  790. "https://lemmy.shinomoroll.net",
  791. "https://lemmy.shtuf.eu",
  792. "https://lemmy.shwizard.chat",
  793. "https://lemmy.sidh.bzh",
  794. "https://lemmy.sietch.online",
  795. "https://lemmy.sikorski.cloud",
  796. "https://lemmy.simpl.website",
  797. "https://lemmy.skillissue.dk",
  798. "https://lemmy.skl.works",
  799. "https://lemmy.slyfabi.de",
  800. "https://lemmy.smeargle.fans",
  801. "https://lemmy.smoothbrain.org",
  802. "https://lemmy.snoot.tube",
  803. "https://lemmy.socdojo.com",
  804. "https://lemmy.songsforno.one",
  805. "https://lemmy.soontm.de",
  806. "https://lemmy.soulfly.dk",
  807. "https://lemmy.spacestation14.com",
  808. "https://lemmy.sprawl.club",
  809. "https://lemmy.srv.eco",
  810. "https://lemmy.srv0.lol",
  811. "https://lemmy.st",
  812. "https://lemmy.staphup.nl",
  813. "https://lemmy.stardust.wtf",
  814. "https://lemmy.stark-enterprise.net",
  815. "https://lemmy.starless.one",
  816. "https://lemmy.starlightkel.xyz",
  817. "https://lemmy.starmade.de",
  818. "https://lemmy.steken.xyz",
  819. "https://lemmy.stellarvortex.com",
  820. "https://lemmy.sthorne.dev",
  821. "https://lemmy.stormlight.space",
  822. "https://lemmy.storo.social",
  823. "https://lemmy.stuart.fun",
  824. "https://lemmy.studio",
  825. "https://lemmy.suchmeme.nl",
  826. "https://lemmy.sudoer.ch",
  827. "https://lemmy.sumuun.net",
  828. "https://lemmy.svc.vesey.tech",
  829. "https://lemmy.sveri.de",
  830. "https://lemmy.swedencentral.cloudapp.azure.com",
  831. "https://lemmy.sweevo.net",
  832. "https://lemmy.swrc.dev",
  833. "https://lemmy.syntrofos.xyz",
  834. "https://lemmy.syrasu.com",
  835. "https://lemmy.sysctl.io",
  836. "https://lemmy.tabbynet.com",
  837. "https://lemmy.tancomps.net",
  838. "https://lemmy.tanktrace.de",
  839. "https://lemmy.tario.org",
  840. "https://lemmy.tarsis.org",
  841. "https://lemmy.teaisatfour.com",
  842. "https://lemmy.tealshark.net",
  843. "https://lemmy.tebro.fi",
  844. "https://lemmy.techhaven.io",
  845. "https://lemmy.technosorcery.net",
  846. "https://lemmy.techstache.com",
  847. "https://lemmy.tedomum.net",
  848. "https://lemmy.telaax.com",
  849. "https://lemmy.temporus.me",
  850. "https://lemmy.tf",
  851. "https://lemmy.tgxn.net",
  852. "https://lemmy.thanatos.at",
  853. "https://lemmy.the-goblin.net",
  854. "https://lemmy.thebias.nl",
  855. "https://lemmy.thecpe.xyz",
  856. "https://lemmy.thegoodoldinternet.com",
  857. "https://lemmy.theia.cafe",
  858. "https://lemmy.themainframe.org",
  859. "https://lemmy.thenullcore.com",
  860. "https://lemmy.theonecurly.page",
  861. "https://lemmy.thepixelproject.com",
  862. "https://lemmy.thesharpcheddar.net",
  863. "https://lemmy.thesilentlink.org",
  864. "https://lemmy.thesmokinglounge.club",
  865. "https://lemmy.thias.xyz",
  866. "https://lemmy.tillicumnet.com",
  867. "https://lemmy.timdn.com",
  868. "https://lemmy.timgilbert.be",
  869. "https://lemmy.timon.sh",
  870. "https://lemmy.timwaterhouse.com",
  871. "https://lemmy.tobyvin.dev",
  872. "https://lemmy.today",
  873. "https://lemmy.toldi.eu",
  874. "https://lemmy.toot.pt",
  875. "https://lemmy.tostiman.com",
  876. "https://lemmy.towards.vision",
  877. "https://lemmy.tr00st.co.uk",
  878. "https://lemmy.trevor.coffee",
  879. "https://lemmy.trippy.pizza",
  880. "https://lemmy.trizz.io",
  881. "https://lemmy.trojaner.dev",
  882. "https://lemmy.trumpi.co.za",
  883. "https://lemmy.ubergeek77.chat",
  884. "https://lemmy.uhhoh.com",
  885. "https://lemmy.umainfo.live",
  886. "https://lemmy.uncomfortable.business",
  887. "https://lemmy.unfiltered.social",
  888. "https://lemmy.uninsane.org",
  889. "https://lemmy.unknownsys.com",
  890. "https://lemmy.utopify.org",
  891. "https://lemmy.utveckla.re",
  892. "https://lemmy.va-11-hall-a.cafe",
  893. "https://lemmy.vanoverloop.xyz",
  894. "https://lemmy.vepta.org",
  895. "https://lemmy.villa-straylight.social",
  896. "https://lemmy.vinodjam.com",
  897. "https://lemmy.vip",
  898. "https://lemmy.virtim.dev",
  899. "https://lemmy.vrchat-dev.tech",
  900. "https://lemmy.vyizis.tech",
  901. "https://lemmy.w.on-t.work",
  902. "https://lemmy.w9r.de",
  903. "https://lemmy.website",
  904. "https://lemmy.weckhorst.no",
  905. "https://lemmy.weiser.social",
  906. "https://lemmy.weomucat.com",
  907. "https://lemmy.whalesinspace.de",
  908. "https://lemmy.whynotdrs.org",
  909. "https://lemmy.wiuf.net",
  910. "https://lemmy.wizjenkins.com",
  911. "https://lemmy.works",
  912. "https://lemmy.world",
  913. "https://lemmy.wraithsquadrongaming.com",
  914. "https://lemmy.wtf",
  915. "https://lemmy.wxbu.de",
  916. "https://lemmy.wyattsmith.org",
  917. "https://lemmy.x3i.tech",
  918. "https://lemmy.xcoolgroup.com",
  919. "https://lemmy.xe.net.nz",
  920. "https://lemmy.xoynq.com",
  921. "https://lemmy.zelinsky.dev",
  922. "https://lemmy.zell-mbc.com",
  923. "https://lemmy.zephyrix.com",
  924. "https://lemmy.zip",
  925. "https://lemmy.zkr.io",
  926. "https://lemmy.zone",
  927. "https://lemmy.zroot.org",
  928. "https://lemmy.zwanenburg.info",
  929. "https://lemmy2.addictmud.org",
  930. "https://lemmy4lemmy.com",
  931. "https://lemmybedan.com",
  932. "https://lemmydeals.com",
  933. "https://lemmyf.uk",
  934. "https://lemmyfi.com",
  935. "https://lemmyfly.org",
  936. "https://lemmygrad.ml",
  937. "https://lemmyis.fun",
  938. "https://lemmyland.com",
  939. "https://lemmyngton.au",
  940. "https://lemmynow.com",
  941. "https://lemmynsfw.com",
  942. "https://lemmyonline.com",
  943. "https://lemmypets.xyz",
  944. "https://lemmyrs.org",
  945. "https://lemmyunchained.net",
  946. "https://lemmyverse.org",
  947. "https://lemmywinks.com",
  948. "https://lemmywinks.xyz",
  949. "https://lemnt.telaax.com",
  950. "https://lemthony.com",
  951. "https://lemuria.es",
  952. "https://lemux.minnix.dev",
  953. "https://lib.lgbt",
  954. "https://libreauto.app",
  955. "https://liminal.southfox.me",
  956. "https://link.fossdle.org",
  957. "https://linkage.ds8.zone",
  958. "https://linkopath.com",
  959. "https://links.dartboard.social",
  960. "https://links.decafbad.com",
  961. "https://links.expressional.social",
  962. "https://links.hackliberty.org",
  963. "https://links.lowsec.club",
  964. "https://links.rebel.ar",
  965. "https://links.rocks",
  966. "https://links.roobre.es",
  967. "https://links.wageoffsite.com",
  968. "https://linux.community",
  969. "https://livesound.world",
  970. "https://livy.one",
  971. "https://lm.bittervets.org",
  972. "https://lm.boing.icu",
  973. "https://lm.byteme.social",
  974. "https://lm.curlefry.net",
  975. "https://lm.electrospek.com",
  976. "https://lm.gsk.moe",
  977. "https://lm.halfassmart.net",
  978. "https://lm.helilot.com",
  979. "https://lm.inu.is",
  980. "https://lm.korako.me",
  981. "https://lm.m0e.space",
  982. "https://lm.madiator.cloud",
  983. "https://lm.melonbread.dev",
  984. "https://lm.mythoranium.com",
  985. "https://lm.paradisus.day",
  986. "https://lm.put.tf",
  987. "https://lm.qtt.no",
  988. "https://lm.rdbt.no",
  989. "https://lm.runnerd.net",
  990. "https://lm.sethp.cc",
  991. "https://lm.suitwaffle.com",
  992. "https://lm.sysv.dev",
  993. "https://lm.thesqooid.com",
  994. "https://lm.williampuckering.com",
  995. "https://lmmy.io",
  996. "https://lmmy.net",
  997. "https://lmmy.tvdl.dev",
  998. "https://lmmy.ylwsgn.cc",
  999. "https://lmy.axi.cx",
  1000. "https://lmy.dotcomitsa.website",
  1001. "https://lmy.mymte.de",
  1002. "https://lmy.singinwhale.com",
  1003. "https://local106.com",
  1004. "https://lolimbeer.com",
  1005. "https://lostcheese.com",
  1006. "https://lsmu.schmurian.xyz",
  1007. "https://lululemmy.com",
  1008. "https://lurk.fun",
  1009. "https://mander.xyz",
  1010. "https://marginalcuriosity.net",
  1011. "https://matejc.com",
  1012. "https://matts.digital",
  1013. "https://meganice.online",
  1014. "https://melly.0x-ia.moe",
  1015. "https://merv.news",
  1016. "https://mesita.link",
  1017. "https://metapowers.org",
  1018. "https://mh.znark.us",
  1019. "https://mhl.onl",
  1020. "https://midwest.social",
  1021. "https://milksteak.org",
  1022. "https://mimiclem.me",
  1023. "https://mindshare.space",
  1024. "https://mlem.a-smol-cat.fr",
  1025. "https://mlem.lea.moe",
  1026. "https://mobilemmohub.com",
  1027. "https://monero.town",
  1028. "https://monyet.cc",
  1029. "https://moose.best",
  1030. "https://moot.place",
  1031. "https://moto.teamswollen.org",
  1032. "https://mtgzone.com",
  1033. "https://mujico.org",
  1034. "https://mylem.eu",
  1035. "https://mylem.me",
  1036. "https://mylem.my",
  1037. "https://mylemmy.win",
  1038. "https://narod.city",
  1039. "https://nc.gnzl.cl",
  1040. "https://negativenull.com",
  1041. "https://netmonkey.tech",
  1042. "https://news.cosocial.ca",
  1043. "https://news.deghg.org",
  1044. "https://news.idlestate.org",
  1045. "https://nlemmy.nl",
  1046. "https://no.lastname.nz",
  1047. "https://nonewfriends.club",
  1048. "https://normalcity.life",
  1049. "https://not-enough-sci.fi",
  1050. "https://notdigg.com",
  1051. "https://notlemmy.notawebsite.fr",
  1052. "https://notyour.rodeo",
  1053. "https://novoidspace.com",
  1054. "https://nrsk.no",
  1055. "https://nunu.dev",
  1056. "https://nwdr.club",
  1057. "https://occult.social",
  1058. "https://oceanbreeze.earth",
  1059. "https://odin.lanofthedead.xyz",
  1060. "https://omg.qa",
  1061. "https://on.syrma.cc",
  1062. "https://opendmz.social",
  1063. "https://orava.dev",
  1064. "https://orzen.games",
  1065. "https://ou0.de",
  1066. "https://outpost.zeuslink.net",
  1067. "https://overctrl.dbzer0.com",
  1068. "https://parapheum.com",
  1069. "https://partizle.com",
  1070. "https://pathfinder.social",
  1071. "https://pathofexile-discuss.com",
  1072. "https://pawb.social",
  1073. "https://pcglinks.com",
  1074. "https://philly.page",
  1075. "https://plork.monster",
  1076. "https://pootusmaximus.xyz",
  1077. "https://popplesburger.hilciferous.nl",
  1078. "https://poptalk.scrubbles.tech",
  1079. "https://possumpat.io",
  1080. "https://posta.no",
  1081. "https://postit.quantentoast.de",
  1082. "https://preserve.games",
  1083. "https://pricefield.org",
  1084. "https://prime8s.xyz",
  1085. "https://programming.dev",
  1086. "https://proit.org",
  1087. "https://psychedelia.ink",
  1088. "https://purrito.kamartaj.xyz",
  1089. "https://quex.cc",
  1090. "https://quo.ink",
  1091. "https://r-sauna.fi",
  1092. "https://r.dcotta.eu",
  1093. "https://r.gir.st",
  1094. "https://r.rosettast0ned.com",
  1095. "https://rabbitea.rs",
  1096. "https://radiation.party",
  1097. "https://rammy.site",
  1098. "https://rational-racoon.de",
  1099. "https://rblind.com",
  1100. "https://rc.liftoff-app.org",
  1101. "https://rdr.lol",
  1102. "https://re.tei.li",
  1103. "https://read.widerweb.org",
  1104. "https://red.cyberhase.de",
  1105. "https://reddit.moonbeam.town",
  1106. "https://reddrefuge.com",
  1107. "https://reddthat.com",
  1108. "https://rekabu.ru",
  1109. "https://reseed.it",
  1110. "https://retarded.dev",
  1111. "https://ripo.st",
  1112. "https://rlyeh.cc",
  1113. "https://rlyeh.icu",
  1114. "https://roznotech.xyz",
  1115. "https://rustyshackleford.cfd",
  1116. "https://s.itskhanow.com",
  1117. "https://s.jape.work",
  1118. "https://s0ss.net",
  1119. "https://sambaspy.com",
  1120. "https://scif6.nsalanparty.com",
  1121. "https://sedd.it",
  1122. "https://seemel.ink",
  1123. "https://selfhosted.forum",
  1124. "https://sffa.community",
  1125. "https://sh.itjust.works",
  1126. "https://sha1.nl",
  1127. "https://shinobu.cloud",
  1128. "https://shitposting.monster",
  1129. "https://shork.online",
  1130. "https://sideone.co.uk",
  1131. "https://sigmet.io",
  1132. "https://skwerl.dev",
  1133. "https://slangenettet.pyjam.as",
  1134. "https://slrpnk.net",
  1135. "https://sneakernet.social",
  1136. "https://snkkis.me",
  1137. "https://snuv.win",
  1138. "https://soccer.forum",
  1139. "https://social.belowland.com",
  1140. "https://social.coalition.space",
  1141. "https://social.cyb3r.dog",
  1142. "https://social.dn42.us",
  1143. "https://social.fossware.space",
  1144. "https://social.fr4me.io",
  1145. "https://social.ggbox.fr",
  1146. "https://social.hamington.net",
  1147. "https://social.jears.at",
  1148. "https://social.nerdhouse.io",
  1149. "https://social.poisson.me",
  1150. "https://social.sour.is",
  1151. "https://social.styxem.xyz",
  1152. "https://social.vmdk.ca",
  1153. "https://solstice.etbr.top",
  1154. "https://sopuli.xyz",
  1155. "https://spgrn.com",
  1156. "https://stable.liftoff-app.org",
  1157. "https://stammtisch.hallertau.social",
  1158. "https://stanx.page",
  1159. "https://startrek.website",
  1160. "https://sub.rdls.dev",
  1161. "https://sub.wetshaving.social",
  1162. "https://sublight.one",
  1163. "https://sudood.us",
  1164. "https://suguha.net",
  1165. "https://sullen.social",
  1166. "https://superdark.social",
  1167. "https://suppo.fi",
  1168. "https://support.futbol",
  1169. "https://surlesworld.com",
  1170. "https://surom.de",
  1171. "https://switter.su",
  1172. "https://szmer.info",
  1173. "https://t.bobamilktea.xyz",
  1174. "https://tabletop.place",
  1175. "https://tagpro.lol",
  1176. "https://talk.kururin.tech",
  1177. "https://talka.live",
  1178. "https://techy.news",
  1179. "https://terefere.eu",
  1180. "https://textandmetal.com",
  1181. "https://tezzo.f0rk.pl",
  1182. "https://thaumatur.ge",
  1183. "https://thechurchofmemes.com",
  1184. "https://theculture.social",
  1185. "https://thediscussion.site",
  1186. "https://thegarden-u4873.vm.elestio.app",
  1187. "https://thegarden.land",
  1188. "https://thelemmy.club",
  1189. "https://theotter.social",
  1190. "https://thepride.hexodine.com",
  1191. "https://thesidewalkends.io",
  1192. "https://thesimplecorner.org",
  1193. "https://thevapor.space",
  1194. "https://tkohhh.social",
  1195. "https://toast.ooo",
  1196. "https://toons.zone",
  1197. "https://tortoisewrath.com",
  1198. "https://tslemmy.duckdns.org",
  1199. "https://ttrpg.network",
  1200. "https://tucson.social",
  1201. "https://typemi.me",
  1202. "https://upvote.au",
  1203. "https://va11halla.bar",
  1204. "https://vlemmy.net",
  1205. "https://voltage.vn",
  1206. "https://voxpop.social",
  1207. "https://voyager.alec.is",
  1208. "https://voyager.lemmy.ml",
  1209. "https://wallstreets.bet",
  1210. "https://waveform.social",
  1211. "https://wayfarershaven.eu",
  1212. "https://werm.social",
  1213. "https://whata.clusterfsck.com",
  1214. "https://whiskers.bim.boats",
  1215. "https://wilbo.tech",
  1216. "https://wirebase.org",
  1217. "https://wired.bluemarch.art",
  1218. "https://wizanons.dev",
  1219. "https://wumbo.buzz",
  1220. "https://www.jrz.city",
  1221. "https://www.korzekwa.io",
  1222. "https://xbdv.com",
  1223. "https://xcore.social",
  1224. "https://xffxe4.lol",
  1225. "https://xrs.cx",
  1226. "https://yakiak.com",
  1227. "https://yall.theatl.social",
  1228. "https://yamasaur.com",
  1229. "https://yiffit.net",
  1230. "https://ymmel.nl",
  1231. "https://yogibytes.page",
  1232. "https://zemmy.cc",
  1233. "https://zen.lema.cl",
  1234. "https://zeronull.xyz",
  1235. "https://zoo.splitlinux.org"
  1236. ]);
  1237. var INSTANCES_KBIN = /* @__PURE__ */ new Set([
  1238. "https://1001.coolest.zone",
  1239. "https://baguette.pub",
  1240. "https://bin.pol.social",
  1241. "https://community.yshi.org",
  1242. "https://feddit.online",
  1243. "https://fedi196.gay",
  1244. "https://fedia.io",
  1245. "https://fediverse.boo",
  1246. "https://forum.fail",
  1247. "https://fr3diver.se",
  1248. "https://gehirneimer.de",
  1249. "https://jlailu.social",
  1250. "https://k.fe.derate.me",
  1251. "https://karab.in",
  1252. "https://kayb.ee",
  1253. "https://kbin.buzz",
  1254. "https://kbin.cafe",
  1255. "https://kbin.chat",
  1256. "https://kbin.dk",
  1257. "https://kbin.donar.dev",
  1258. "https://kbin.ectolab.net",
  1259. "https://kbin.fedi.cr",
  1260. "https://kbin.holmosapien.com",
  1261. "https://kbin.korgen.xyz",
  1262. "https://kbin.lgbt",
  1263. "https://kbin.lol",
  1264. "https://kbin.melroy.org",
  1265. "https://kbin.nz",
  1266. "https://kbin.place",
  1267. "https://kbin.primitivebits.social",
  1268. "https://kbin.projectsegfau.lt",
  1269. "https://kbin.rocks",
  1270. "https://kbin.run",
  1271. "https://kbin.sh",
  1272. "https://kbin.social",
  1273. "https://kbin.tech",
  1274. "https://kbin.thicknahalf.com",
  1275. "https://kilioa.org",
  1276. "https://kopnij.in",
  1277. "https://longley.ws",
  1278. "https://nadajnik.org",
  1279. "https://nerdbin.social",
  1280. "https://no.faux.moe",
  1281. "https://nolani.academy",
  1282. "https://open-source.social",
  1283. "https://readit.buzz",
  1284. "https://remy.city",
  1285. "https://social.tath.link",
  1286. "https://socialnetworks.rodeo",
  1287. "https://streetbikes.club",
  1288. "https://the.coolest.zone",
  1289. "https://thebrainbin.org",
  1290. "https://tuna.cat",
  1291. "https://vdcw.social",
  1292. "https://wiku.hu",
  1293. "https://www.fedia.io"
  1294. ]);
  1295. trace(`Define instances sets end`);
  1296.  
  1297. // src/our-changes.js
  1298. var OUR_CHANGES = { addedNodes: {} };
  1299. function getAddedNodesSelectors() {
  1300. return Object.values(OUR_CHANGES.addedNodes);
  1301. }
  1302. function registerAddedNode(id, selector) {
  1303. OUR_CHANGES.addedNodes[id] = selector;
  1304. }
  1305.  
  1306. // src/constants.js
  1307. var constants_default = {
  1308. ICON_CLASS: withNS(`icon`),
  1309. ICON_LOADING_CLASS: withNS(`loading`),
  1310. ICON_STYLES_ID: withNS(`icon-styles`),
  1311. ICON_LINK_CLASS: withNS(`icon-link`),
  1312. ICON_LINK_SYMBOL_ID: withNS(`icon-link-symbol`),
  1313. ICON_SPINNER_CLASS: withNS(`icon-spinner`),
  1314. ICON_SPINNER_SYMBOL_ID: withNS(`icon-spinner-symbol`),
  1315. ORIGINAL_LINK_CLASS: withNS(`original-link`),
  1316. SHOW_AT_HOME_BUTTON_CLASS: withNS(`show-at-home`),
  1317. MAKE_HOME_BUTTON_ID: withNS(`make-home`),
  1318. ICON_SVG_TEMPLATE_ID: withNS(`icon-template`),
  1319. AUTH_WRONG: `AUTH_WRONG`,
  1320. AUTH_MISSING: `AUTH_MISSING`,
  1321. REWRITE_STATUS: withNSCamelCase(`localUrlStatus`),
  1322. REWRITE_STATUS_PENDING: `pending`,
  1323. REWRITE_STATUS_SUCCESS: `success`,
  1324. REWRITE_STATUS_ERROR: `error`,
  1325. REWRITE_STATUS_UNRESOLVED: `unresolved`,
  1326. SETUP_AUTH_MESSAGE: `Lemmy Universal Link Switcher: Visit your home instance once to set up post/comment rewriting`
  1327. };
  1328. function withNS(identifier) {
  1329. return `lemmy-rewrite-urls-` + identifier;
  1330. }
  1331. function withNSCamelCase(identifier) {
  1332. return `lemmyRewriteUrls` + identifier.charAt(0).toUpperCase() + identifier.slice(1);
  1333. }
  1334.  
  1335. // src/rewriting/helpers.js
  1336. function isHashLink(link) {
  1337. return link.hash && link.origin + link.pathname + link.search === location.origin + location.pathname + location.search;
  1338. }
  1339. function isSamePage(url1, url2) {
  1340. return url1.host === url2.host && url1.pathname === url2.pathname;
  1341. }
  1342. function isV17() {
  1343. return isoData?.site_res?.version.startsWith(`0.17`);
  1344. }
  1345. var stopEventHandler = (event) => {
  1346. event.preventDefault();
  1347. event.stopPropagation();
  1348. };
  1349.  
  1350. // src/gm.js
  1351. async function setValue(key, value) {
  1352. trace(`GM.setValue key ${key}, value ${value}`);
  1353. await GM.setValue(key, value);
  1354. }
  1355. async function getValue(key) {
  1356. return await GM.getValue(key);
  1357. }
  1358. function parseResponse(response) {
  1359. try {
  1360. return JSON.parse(response.response);
  1361. } catch (e) {
  1362. debug(`Error parsing response JSON`, e);
  1363. return response.response;
  1364. }
  1365. }
  1366. function logRequest(response, data) {
  1367. trace(
  1368. `FinalUrl`,
  1369. response.finalUrl,
  1370. `status`,
  1371. response.status,
  1372. `text`,
  1373. response.statusText,
  1374. `response`,
  1375. data || response.response
  1376. );
  1377. trace(`responseHeaders`, response.responseHeaders);
  1378. }
  1379. function performXmlHttpRequest(url, doneCallback) {
  1380. GM.xmlHttpRequest({
  1381. url,
  1382. onloadend: (response) => {
  1383. const data = parseResponse(response);
  1384. logRequest(response, data);
  1385. doneCallback(response, data);
  1386. }
  1387. });
  1388. }
  1389.  
  1390. // src/rewriting/auth.js
  1391. var AUTH;
  1392. function getAuthFromCookie() {
  1393. return document.cookie.split("; ").find((row) => row.startsWith("jwt="))?.split("=")[1];
  1394. }
  1395. async function setAuth(auth) {
  1396. AUTH = auth;
  1397. await setValue(`auth`, auth);
  1398. }
  1399. async function initAuth() {
  1400. const curAuth = await getAuth();
  1401. if (curAuth) {
  1402. AUTH = curAuth;
  1403. return;
  1404. }
  1405. if (location.origin === HOME) {
  1406. const newAuth = getAuthFromCookie();
  1407. await setAuth(newAuth);
  1408. if (newAuth && await getValue(`authNoticeShown`)) {
  1409. alert(`Lemmy Universal Link Switcher: Post/comment rewriting has been set up successfully`);
  1410. await setValue(`authNoticeShown`, null);
  1411. }
  1412. } else if (HOME && !await getValue(`authNoticeShown`)) {
  1413. await setValue(`authNoticeShown`, `true`);
  1414. alert(constants_default.SETUP_AUTH_MESSAGE);
  1415. }
  1416. }
  1417. function updateAuthPeriodically() {
  1418. setInterval(async () => {
  1419. const prev = AUTH;
  1420. const newAuth = location.origin === HOME ? getAuthFromCookie() : await getAuth();
  1421. if (prev !== newAuth) {
  1422. debug(`Auth changed`);
  1423. await setAuth(newAuth);
  1424. clearMissingUrlsInCache();
  1425. triggerRewrite();
  1426. }
  1427. }, 1234);
  1428. }
  1429. async function getAuth() {
  1430. return await getValue(`auth`);
  1431. }
  1432.  
  1433. // src/rewriting/url-mapping.js
  1434. function splitPaths(url) {
  1435. return url.pathname.split(`/`).slice(1);
  1436. }
  1437. function isRemoteLemmyUrl(url) {
  1438. return url.origin !== HOME && isLemmyInstance(url);
  1439. }
  1440. function isRemoteKbinUrl(url) {
  1441. return url.origin !== HOME && isKbinInstance(url);
  1442. }
  1443. function isRemoteUrl(url) {
  1444. return isRemoteLemmyUrl(url) || isRemoteKbinUrl(url);
  1445. }
  1446. function findLocalUrlForStandardAtFormat(url, rootPath) {
  1447. const paths = splitPaths(url);
  1448. const name = paths[1].includes(`@`) ? paths[1] : paths[1] + `@` + url.host;
  1449. return `${HOME}/${rootPath || paths[0]}/${name}` + url.search + url.hash;
  1450. }
  1451. function findLocalUrlForLemmyUrl(url) {
  1452. if (isLemmyUserOrCommunityUrl(url)) {
  1453. return findLocalUrlForStandardAtFormat(url);
  1454. } else {
  1455. return null;
  1456. }
  1457. }
  1458. function findLocalUrlForKbinUserUrl(url) {
  1459. const paths = splitPaths(url);
  1460. const user = paths[1].startsWith(`@`) ? paths[1].substring(1) : paths[1];
  1461. const name = user.includes(`@`) ? user : user + `@` + url.host;
  1462. return `${HOME}/u/${name}` + url.search + url.hash;
  1463. }
  1464. function findLocalUrlForKbinUrl(url) {
  1465. if (isKbinMagazineUrl(url)) {
  1466. return findLocalUrlForStandardAtFormat(url, mappedKbinRootPath(url));
  1467. } else if (isKbinUserUrl(url)) {
  1468. return findLocalUrlForKbinUserUrl(url);
  1469. } else {
  1470. return null;
  1471. }
  1472. }
  1473. function findLocalUrl(url) {
  1474. if (isRemoteLemmyUrl(url))
  1475. return findLocalUrlForLemmyUrl(url);
  1476. if (isRemoteKbinUrl(url))
  1477. return findLocalUrlForKbinUrl(url);
  1478. return null;
  1479. }
  1480. async function fetchApIdFromRemote(url) {
  1481. const endpoint = isLemmyPostUrl(url) ? `post` : `comment`;
  1482. const paths = splitPaths(url);
  1483. const id = paths[1];
  1484. return new Promise((resolve, reject) => {
  1485. performXmlHttpRequest(`${url.origin}/api/v3/${endpoint}?id=${id}`, (response, data) => {
  1486. const apId = data[`${endpoint}_view`]?.[endpoint]?.ap_id;
  1487. if (response.status === 200 && apId) {
  1488. resolve(apId);
  1489. } else {
  1490. handleFailedRequest(`fetching AP ID`, response, reject);
  1491. }
  1492. });
  1493. });
  1494. }
  1495. function handleFailedRequest(requestName, response, reject) {
  1496. if (response.status >= 200 && response.status <= 299) {
  1497. reject(`${requestName}: Unhandled successful response, status: ${response.status}`);
  1498. } else if (response.status >= 400 && response.status <= 599) {
  1499. reject(`${requestName}: Error, status: ${response.status}`);
  1500. } else {
  1501. reject(`${requestName}: Something weird happened, status: ${response.status}`);
  1502. }
  1503. }
  1504. async function resolveObjectFromHome(url) {
  1505. return new Promise(async (resolve, reject) => {
  1506. const auth = await getAuth();
  1507. if (!auth) {
  1508. debug(`No auth token found`);
  1509. reject(constants_default.AUTH_MISSING);
  1510. }
  1511. performXmlHttpRequest(
  1512. `${HOME}/api/v3/resolve_object?auth=${auth}&q=${encodeURIComponent(url.href)}`,
  1513. (response, data) => {
  1514. if (response.status === 200 && data.post?.post?.id) {
  1515. resolve(`${HOME}/post/${data.post.post.id}${url.search}${url.hash}`);
  1516. } else if (response.status === 200 && data.comment?.comment?.id) {
  1517. resolve(`${HOME}/comment/${data.comment.comment.id}${url.search}${url.hash}`);
  1518. } else if (response.status === 400 && data?.error === `couldnt_find_object`) {
  1519. resolve(null);
  1520. } else if (response.status === 400 && data?.error === `not_logged_in`) {
  1521. reject(constants_default.AUTH_WRONG);
  1522. } else {
  1523. handleFailedRequest(`resolving object`, response, reject);
  1524. }
  1525. }
  1526. );
  1527. });
  1528. }
  1529. var urlCache = {};
  1530. function clearMissingUrlsInCache() {
  1531. for (const value of Object.values(urlCache)) {
  1532. if (value.error)
  1533. delete value.error;
  1534. if (value.localUrl === null)
  1535. delete value.localUrl;
  1536. }
  1537. }
  1538. function getCacheKey(url) {
  1539. return url.host + url.pathname + url.search;
  1540. }
  1541. function cacheResult(url, localUrl) {
  1542. const key = getCacheKey(url);
  1543. if (!urlCache[key]) {
  1544. urlCache[key] = {};
  1545. }
  1546. if (urlCache[key].error)
  1547. delete urlCache[key].error;
  1548. urlCache[key].localUrl = localUrl;
  1549. return localUrl;
  1550. }
  1551. function cacheErrorResult(url, error) {
  1552. const key = getCacheKey(url);
  1553. if (!urlCache[key]) {
  1554. urlCache[key] = {};
  1555. }
  1556. urlCache[key].error = error;
  1557. }
  1558. function getLocalUrlfromCache(url) {
  1559. const key = getCacheKey(url);
  1560. if (urlCache[key]?.error) {
  1561. throw urlCache[key]?.error;
  1562. } else {
  1563. return urlCache[key]?.localUrl;
  1564. }
  1565. }
  1566. async function fetchLocalUrl(url, loadFromCache = true) {
  1567. if (loadFromCache) {
  1568. const cached = getLocalUrlfromCache(url);
  1569. if (cached !== void 0) {
  1570. trace(`Found URL ${url} in cache: ${cached}`);
  1571. return cached;
  1572. }
  1573. }
  1574. try {
  1575. return cacheResult(url, await fetchLocalUrlNoCache(url));
  1576. } catch (e) {
  1577. debug(`fetchLocalUrl error`, e);
  1578. cacheErrorResult(url, e);
  1579. throw e;
  1580. }
  1581. }
  1582. async function fetchLocalUrlNoCache(url) {
  1583. trace(`Trying to resolve URL ${url} directly`);
  1584. const localUrl = await resolveObjectFromHome(url);
  1585. if (localUrl !== null) {
  1586. return localUrl;
  1587. } else {
  1588. trace(`Did not find URL ${url} directly`);
  1589. }
  1590. const apId = new URL(await fetchApIdFromRemote(url));
  1591. trace(`Found AP ID for URL ${url}: ${apId}`);
  1592. if (!apId.search) {
  1593. apId.search = url.search;
  1594. }
  1595. if (!apId.hash) {
  1596. apId.hash = url.hash;
  1597. }
  1598. if (isSamePage(url, apId)) {
  1599. trace(`Previous URL was AP ID already, URL not federated for some reason`);
  1600. return null;
  1601. } else {
  1602. return await resolveObjectFromHome(apId);
  1603. }
  1604. }
  1605. function isInstantlyRewritable(url) {
  1606. return isRemoteLemmyUrl(url) && isLemmyUserOrCommunityUrl(url) || isRemoteKbinUrl(url) && (isKbinMagazineUrl(url) || isKbinUserUrl(url));
  1607. }
  1608. function isRewritableAfterResolving(url) {
  1609. return isRemoteLemmyUrl(url) && (isLemmyPostUrl(url) || isLemmyCommentUrl(url));
  1610. }
  1611. function isLemmyPostUrl(url) {
  1612. const paths = splitPaths(url);
  1613. return paths[0] === `post`;
  1614. }
  1615. function isLemmyCommentUrl(url) {
  1616. const paths = splitPaths(url);
  1617. return paths[0] === `comment`;
  1618. }
  1619. function isLemmyUserOrCommunityUrl(url) {
  1620. const paths = splitPaths(url);
  1621. return paths[0] === `c` || paths[0] === `u`;
  1622. }
  1623. function isKbinPostUrl(url) {
  1624. const paths = splitPaths(url);
  1625. return paths[0] === `m` && paths.length > 2 && paths[2] === `t`;
  1626. }
  1627. function isKbinMicroblogUrl(url) {
  1628. const paths = splitPaths(url);
  1629. return paths[0] === `m` && paths.length > 2 && paths[2] === `p`;
  1630. }
  1631. function isKbinMicroblogOverviewUrl(url) {
  1632. const paths = splitPaths(url);
  1633. return paths[0] === `m` && paths.length > 2 && paths[2] === `microblog`;
  1634. }
  1635. function isKbinMagazinePeopleUrl(url) {
  1636. const paths = splitPaths(url);
  1637. return paths[0] === `m` && paths.length > 2 && paths[2] === `people`;
  1638. }
  1639. function isKbinMagazineUrl(url) {
  1640. const paths = splitPaths(url);
  1641. return paths[0] === `m` && !isKbinPostUrl(url) && !isKbinMagazinePeopleUrl(url) && !isKbinMicroblogUrl(url) && !isKbinMicroblogOverviewUrl(url);
  1642. }
  1643. function mappedKbinRootPath(url) {
  1644. const paths = splitPaths(url);
  1645. if (paths[0] === `m`) {
  1646. return `c`;
  1647. } else {
  1648. return null;
  1649. }
  1650. }
  1651. function isKbinUserUrl(url) {
  1652. const paths = splitPaths(url);
  1653. return paths.length === 2 && paths[0] === `u`;
  1654. }
  1655.  
  1656. // src/rewriting/links/icon.js
  1657. function getIcon(link) {
  1658. return link.querySelector(`.` + constants_default.ICON_CLASS);
  1659. }
  1660. function createIcon(link) {
  1661. ensureTemplateAvailable();
  1662. ensureIconStylesAdded();
  1663. const wrapper = document.createElement(`span`);
  1664. registerAddedNode(constants_default.ICON_CLASS, `.` + constants_default.ICON_CLASS);
  1665. wrapper.classList.add(constants_default.ICON_CLASS);
  1666. if (link.children.length === 0 || getComputedStyle(link.children[link.children.length - 1]).marginRight === `0px`) {
  1667. wrapper.style.marginLeft = `0.5em`;
  1668. }
  1669. const linkIcon = createSVG();
  1670. linkIcon.classList.add(constants_default.ICON_LINK_CLASS);
  1671. linkIcon.innerHTML = `<use href=#${constants_default.ICON_LINK_SYMBOL_ID} />`;
  1672. wrapper.append(linkIcon);
  1673. const spinnerIcon = createSVG();
  1674. spinnerIcon.classList.add(constants_default.ICON_SPINNER_CLASS);
  1675. spinnerIcon.innerHTML = `<use href=#${constants_default.ICON_SPINNER_SYMBOL_ID} />`;
  1676. wrapper.append(spinnerIcon);
  1677. return wrapper;
  1678. }
  1679. function createSVG() {
  1680. return document.createElementNS(`http://www.w3.org/2000/svg`, `svg`);
  1681. }
  1682. function ensureTemplateAvailable() {
  1683. if (document.querySelector(`#` + constants_default.ICON_SVG_TEMPLATE_ID))
  1684. return;
  1685. const template = createSVG();
  1686. template.id = constants_default.ICON_SVG_TEMPLATE_ID;
  1687. template.innerHTML = `<defs>
  1688. <symbol id=${constants_default.ICON_LINK_SYMBOL_ID} viewBox="0 0 100 100"><path d="M52.8 34.6c.8.8 1.8 1.2 2.8 1.2s2-.4 2.8-1.2c1.5-1.5 1.5-4 0-5.6l-5.2-5.2h26v30.6c0 2.2 1.8 3.9 3.9 3.9 2.2 0 3.9-1.8 3.9-3.9V19.8c0-2.2-1.8-3.9-3.9-3.9h-30l5.2-5.2c1.5-1.5 1.5-4 0-5.6s-4-1.5-5.6 0l-11.8 12c-1.5 1.5-1.5 4 0 5.6l11.9 11.9zM31.1 28.7V11c0-3-2.5-5.5-5.5-5.5H8C5 5.5 2.5 8 2.5 11v17.7c0 3 2.5 5.5 5.5 5.5h17.7c3 0 5.4-2.5 5.4-5.5zM47.2 65.4c-1.5-1.5-4-1.5-5.6 0s-1.5 4 0 5.6l5.2 5.2h-26V45.6c0-2.2-1.8-3.9-3.9-3.9S13 43.5 13 45.6v34.5c0 2.2 1.8 3.9 3.9 3.9h30l-5.2 5.2c-1.5 1.5-1.5 4 0 5.6.8.8 1.8 1.2 2.8 1.2s2-.4 2.8-1.2l11.9-11.9c1.5-1.5 1.5-4 0-5.6l-12-11.9zM92 65.8H74.4c-3 0-5.5 2.5-5.5 5.5V89c0 3 2.5 5.5 5.5 5.5H92c3 0 5.5-2.5 5.5-5.5V71.3c0-3-2.5-5.5-5.5-5.5z"/></symbol>
  1689. <symbol id=${constants_default.ICON_SPINNER_SYMBOL_ID} viewBox="0 0 32 32"><path d="M16 32c-4.274 0-8.292-1.664-11.314-4.686s-4.686-7.040-4.686-11.314c0-3.026 0.849-5.973 2.456-8.522 1.563-2.478 3.771-4.48 6.386-5.791l1.344 2.682c-2.126 1.065-3.922 2.693-5.192 4.708-1.305 2.069-1.994 4.462-1.994 6.922 0 7.168 5.832 13 13 13s13-5.832 13-13c0-2.459-0.69-4.853-1.994-6.922-1.271-2.015-3.066-3.643-5.192-4.708l1.344-2.682c2.615 1.31 4.824 3.313 6.386 5.791 1.607 2.549 2.456 5.495 2.456 8.522 0 4.274-1.664 8.292-4.686 11.314s-7.040 4.686-11.314 4.686z"/></symbol>
  1690. </defs>`;
  1691. registerAddedNode(constants_default.ICON_SVG_TEMPLATE_ID, `#` + constants_default.ICON_SVG_TEMPLATE_ID);
  1692. document.head.append(template);
  1693. }
  1694. function ensureIconStylesAdded() {
  1695. if (document.querySelector(`#` + constants_default.ICON_STYLES_ID))
  1696. return;
  1697. const style = document.createElement(`style`);
  1698. style.id = constants_default.ICON_STYLES_ID;
  1699. style.innerHTML = `
  1700. .${constants_default.ICON_SPINNER_CLASS} {
  1701. display: none;
  1702. animation: spins 2s linear infinite;
  1703. }
  1704. .${constants_default.ICON_LINK_CLASS} {
  1705. display: inline-block;
  1706. }
  1707. .${constants_default.ICON_LOADING_CLASS} > .${constants_default.ICON_LINK_CLASS} {
  1708. display: none;
  1709. }
  1710. .${constants_default.ICON_LOADING_CLASS} > .${constants_default.ICON_SPINNER_CLASS} {
  1711. display: inline-block;
  1712. }
  1713. .${constants_default.ICON_CLASS} > svg {
  1714. vertical-align: sub;
  1715. height: 1em; width: 1em;
  1716. stroke: currentColor;
  1717. fill: currentColor;
  1718. }`;
  1719. registerAddedNode(constants_default.ICON_STYLES_ID, `#` + constants_default.ICON_STYLES_ID);
  1720. document.head.append(style);
  1721. }
  1722.  
  1723. // src/tippy.js
  1724. var tippy_default = window.tippy;
  1725.  
  1726. // src/rewriting/links/tooltip.js
  1727. function getOriginalLinkHtml(originalHref) {
  1728. registerAddedNode(constants_default.ORIGINAL_LINK_CLASS, `.` + constants_default.ORIGINAL_LINK_CLASS);
  1729. return `Original link: <a class="${constants_default.ORIGINAL_LINK_CLASS}" href="${originalHref}">${originalHref}</a>`;
  1730. }
  1731. function defaultOptions(link) {
  1732. return {
  1733. appendTo: () => link.parentNode,
  1734. allowHTML: true,
  1735. interactive: true,
  1736. animation: false,
  1737. placement: "bottom",
  1738. hideOnClick: false
  1739. };
  1740. }
  1741. function createOriginalLinkTooltip(link, originalHref) {
  1742. trace(`Create original link tooltip`, link, originalHref);
  1743. getIcon(link).addEventListener(`click`, stopEventHandler);
  1744. return createLinkTooltip(link, getOriginalLinkHtml(originalHref));
  1745. }
  1746. function createLinkTooltip(link, content) {
  1747. return tippy_default(getIcon(link), {
  1748. ...defaultOptions(link),
  1749. content
  1750. });
  1751. }
  1752. function createLinkLoadTooltip(link) {
  1753. trace(`Create link load tooltip`, link);
  1754. getIcon(link).classList.add(constants_default.ICON_LOADING_CLASS);
  1755. return createLinkTooltip(link, `Loading home URL...<br />Don't want to wait? ${getOriginalLinkHtml(link.href)}`);
  1756. }
  1757. function linkLoadTooltipSuccess(tooltip, originalHref) {
  1758. linkLoadResult(tooltip, `\u2714\uFE0F Changed link to home instance`, getOriginalLinkHtml(originalHref));
  1759. }
  1760. function linkLoadTooltipError(tooltip, error) {
  1761. linkLoadResult(tooltip, `\u274C ` + error);
  1762. }
  1763. function linkLoadResult(tooltip, result, finalContent = result) {
  1764. const icon = tooltip.reference;
  1765. icon.classList.remove(constants_default.ICON_LOADING_CLASS);
  1766. icon.addEventListener(`click`, stopEventHandler);
  1767. if (tooltip.state.isVisible) {
  1768. tooltip.setContent(result);
  1769. setTimeout(() => {
  1770. tooltip.hide();
  1771. tooltip.setContent(finalContent);
  1772. }, 2e3);
  1773. } else {
  1774. tooltip.setContent(finalContent);
  1775. }
  1776. }
  1777.  
  1778. // src/rewriting/links/links.js
  1779. function changeLinkHref(link, localUrl) {
  1780. const treeWalker = document.createTreeWalker(link, NodeFilter.SHOW_TEXT, (node) => {
  1781. if (node.textContent.toLowerCase().trim() === link.href.toLowerCase().trim()) {
  1782. return NodeFilter.FILTER_ACCEPT;
  1783. } else {
  1784. return NodeFilter.FILTER_SKIP;
  1785. }
  1786. });
  1787. let textNode;
  1788. while ((textNode = treeWalker.nextNode()) !== null) {
  1789. textNode.textContent = localUrl;
  1790. }
  1791. link.href = localUrl;
  1792. link.addEventListener(`click`, (event) => {
  1793. if (event.button === 0 && !event.ctrlKey && link.target !== `_blank`) {
  1794. location.href = localUrl;
  1795. }
  1796. });
  1797. }
  1798. function appendIconTo(elem, icon) {
  1799. if (elem.children.length === 0 || getComputedStyle(elem.children[elem.children.length - 1]).display !== `inline-block`) {
  1800. elem.append(icon);
  1801. } else {
  1802. appendIconTo(elem.children[elem.children.length - 1], icon);
  1803. }
  1804. }
  1805. function addFetchLocalUrlHandler(link) {
  1806. let tooltip;
  1807. const handler = async (event) => {
  1808. if (event.type === `click`) {
  1809. stopEventHandler(event);
  1810. if (tooltip)
  1811. tooltip.show();
  1812. return;
  1813. }
  1814. link.removeEventListener(`focus`, handler);
  1815. link.removeEventListener(`mouseenter`, handler);
  1816. if (link.dataset[constants_default.REWRITE_STATUS] === constants_default.REWRITE_STATUS_PENDING)
  1817. return;
  1818. link.dataset[constants_default.REWRITE_STATUS] = constants_default.REWRITE_STATUS_PENDING;
  1819. tooltip = createLinkLoadTooltip(link);
  1820. try {
  1821. const localUrl = await fetchLocalUrl(link);
  1822. if (!localUrl) {
  1823. debug(`Local URL for ${link.href} could not be found`);
  1824. linkLoadTooltipError(tooltip, `Home URL could not be found`);
  1825. return;
  1826. }
  1827. trace(`Local URL for ${link.href} found: ${localUrl}`);
  1828. const oldHref = link.href;
  1829. changeLinkHref(link, localUrl);
  1830. linkLoadTooltipSuccess(tooltip, oldHref);
  1831. link.dataset[constants_default.REWRITE_STATUS] = constants_default.REWRITE_STATUS_SUCCESS;
  1832. } catch (e) {
  1833. debug(`Error while trying to resolve local URL`, e);
  1834. let msg;
  1835. if (e === constants_default.AUTH_WRONG) {
  1836. msg = `Saved login expired. Return to your home instance and log in again.`;
  1837. } else if (e === constants_default.AUTH_MISSING) {
  1838. msg = constants_default.SETUP_AUTH_MESSAGE;
  1839. } else {
  1840. msg = `Error while trying to find home URL`;
  1841. }
  1842. linkLoadTooltipError(tooltip, msg);
  1843. link.dataset[constants_default.REWRITE_STATUS] = constants_default.REWRITE_STATUS_ERROR;
  1844. } finally {
  1845. link.removeEventListener(`click`, handler);
  1846. }
  1847. };
  1848. link.addEventListener(`click`, handler);
  1849. link.addEventListener(`focus`, handler);
  1850. link.addEventListener(`mouseenter`, handler);
  1851. }
  1852. function isFediverseLink(link) {
  1853. const svg = link.querySelector(`svg`);
  1854. if (!svg)
  1855. return false;
  1856. if (svg.children.length === 0)
  1857. return false;
  1858. return svg.children[0].getAttribute(`xlink:href`)?.includes(`#icon-fedilink`);
  1859. }
  1860. function rewriteToLocal(link) {
  1861. if (!link.parentNode)
  1862. return false;
  1863. if (link.classList.contains(constants_default.ORIGINAL_LINK_CLASS))
  1864. return false;
  1865. if (link.dataset[constants_default.REWRITE_STATUS] === constants_default.REWRITE_STATUS_SUCCESS)
  1866. return false;
  1867. if (isHashLink(link))
  1868. return false;
  1869. if (!isRemoteUrl(link))
  1870. return false;
  1871. if (isFediverseLink(link))
  1872. return false;
  1873. if (isInstantlyRewritable(link)) {
  1874. const localUrl = findLocalUrl(link);
  1875. if (!localUrl)
  1876. return false;
  1877. if (isSamePage(new URL(localUrl), location))
  1878. return false;
  1879. const oldHref = link.href;
  1880. changeLinkHref(link, localUrl);
  1881. const icon = createIcon(link);
  1882. appendIconTo(link, icon);
  1883. createOriginalLinkTooltip(link, oldHref);
  1884. link.dataset[constants_default.REWRITE_STATUS] = constants_default.REWRITE_STATUS_SUCCESS;
  1885. trace(`Rewrite link`, link, ` from`, oldHref, `to`, localUrl);
  1886. return true;
  1887. } else if (isRewritableAfterResolving(link)) {
  1888. if (!getIcon(link)) {
  1889. appendIconTo(link, createIcon(link));
  1890. }
  1891. if (!link.dataset[constants_default.REWRITE_STATUS]) {
  1892. link.dataset[constants_default.REWRITE_STATUS] = constants_default.REWRITE_STATUS_UNRESOLVED;
  1893. addFetchLocalUrlHandler(link);
  1894. }
  1895. }
  1896. }
  1897. function findLinksInChange(change) {
  1898. if (change.type === `childList`) {
  1899. const links = Array.from(change.addedNodes).flatMap((addedNode) => {
  1900. if (addedNode.tagName?.toLowerCase() === `a`) {
  1901. return addedNode;
  1902. } else if (addedNode.querySelectorAll) {
  1903. return Array.from(addedNode.querySelectorAll(`a`));
  1904. } else {
  1905. return [];
  1906. }
  1907. });
  1908. if (links.length > 0)
  1909. trace(`Change`, change, `contained the links`, links);
  1910. return links;
  1911. } else if (change.type === `attributes`) {
  1912. return change.target.matches?.(`a`) ? change.target : [];
  1913. } else {
  1914. return [];
  1915. }
  1916. }
  1917. function findLinksToRewrite(changes) {
  1918. if (!changes) {
  1919. return document.querySelectorAll(`a`);
  1920. }
  1921. return changes.flatMap(findLinksInChange);
  1922. }
  1923. async function rewriteLinksToLocal(changes) {
  1924. const links = findLinksToRewrite(changes);
  1925. const chunkSize = 50;
  1926. return await async function processChunk(currentChunk) {
  1927. const startIdx = currentChunk * chunkSize;
  1928. const endChunkIdx = (currentChunk + 1) * chunkSize;
  1929. const endIdx = Math.min(links.length, endChunkIdx);
  1930. debug(
  1931. `Processing ${links.length} links, current chunk `,
  1932. currentChunk,
  1933. `processing links ${startIdx} to ${endIdx}`
  1934. );
  1935. let anyRewritten = false;
  1936. for (let i = startIdx; i < endIdx; ++i) {
  1937. const rewritten = rewriteToLocal(links[i]);
  1938. anyRewritten = anyRewritten || rewritten;
  1939. }
  1940. debug(`Processed links ${startIdx} to ${endIdx}`);
  1941. if (endChunkIdx >= links.length) {
  1942. return anyRewritten;
  1943. }
  1944. const chunkResult = await new Promise((resolve) => setTimeout(async () => {
  1945. resolve(await processChunk(currentChunk + 1));
  1946. }, 0));
  1947. return anyRewritten || chunkResult;
  1948. }(0);
  1949. }
  1950.  
  1951. // src/rewriting/make-home.js
  1952. function addMakeHomeButton() {
  1953. if (document.querySelector(`#` + constants_default.MAKE_HOME_BUTTON_ID))
  1954. return false;
  1955. if (!isRemoteLemmyUrl(location) || location.pathname !== `/settings`)
  1956. return false;
  1957. const insertAfter = document.querySelector(`#user-password`)?.closest(`.card`);
  1958. if (!insertAfter)
  1959. return;
  1960. const button = document.createElement(`button`);
  1961. button.id = constants_default.MAKE_HOME_BUTTON_ID;
  1962. button.setAttribute(`class`, `btn btn-block btn-primary mr-4 w-100`);
  1963. button.innerHTML = `Make this my home instance for URL rewriting`;
  1964. button.addEventListener(`click`, () => {
  1965. setHome(location.origin);
  1966. button.remove();
  1967. });
  1968. registerAddedNode(constants_default.MAKE_HOME_BUTTON_ID, `#` + constants_default.MAKE_HOME_BUTTON_ID);
  1969. insertAfter.insertAdjacentElement("afterend", button);
  1970. return true;
  1971. }
  1972.  
  1973. // src/rewriting/show-at-home.js
  1974. function showAtHomeButtonText() {
  1975. const host = new URL(HOME).hostname;
  1976. return `Show on ${host}`;
  1977. }
  1978. function createShowAtHomeAnchor(localUrl) {
  1979. const showAtHome = document.createElement(`a`);
  1980. showAtHome.dataset.creationHref = location.href;
  1981. showAtHome.classList.add(constants_default.SHOW_AT_HOME_BUTTON_CLASS);
  1982. showAtHome.innerHTML = showAtHomeButtonText();
  1983. showAtHome.href = localUrl;
  1984. registerAddedNode(constants_default.SHOW_AT_HOME_BUTTON_CLASS, `.` + constants_default.SHOW_AT_HOME_BUTTON_CLASS);
  1985. return showAtHome;
  1986. }
  1987. function addLemmyShowAtHomeButton(localUrl) {
  1988. const logo = document.querySelector(`a.navbar-brand`);
  1989. const navbarIcons = isV17() ? document.querySelector(`[title="Search"]`)?.closest(`.navbar-nav`) : document.querySelector(`#navbarIcons`);
  1990. if (!logo || !navbarIcons) {
  1991. debug(`Could not find position to insert ShowAtHomeButton at`);
  1992. return false;
  1993. }
  1994. const mobile = createShowAtHomeAnchor(localUrl);
  1995. mobile.classList.add(`d-md-none`);
  1996. mobile.style[`margin-right`] = `8px`;
  1997. mobile.style[`margin-left`] = `auto`;
  1998. if (isV17()) {
  1999. document.querySelector(`.navbar-nav.ml-auto`)?.classList.remove(`ml-auto`);
  2000. }
  2001. logo.insertAdjacentElement("afterend", mobile);
  2002. const desktop = createShowAtHomeAnchor(localUrl);
  2003. desktop.classList.add(`d-md-inline`);
  2004. desktop.style[`margin-right`] = `8px`;
  2005. navbarIcons.insertAdjacentElement("beforebegin", desktop);
  2006. return true;
  2007. }
  2008. function addKbinShowAtHomeButton(localUrl) {
  2009. const prependTo = document.querySelector(`#header menu:not(.head-nav__menu)`);
  2010. if (!prependTo) {
  2011. debug(`Could not find position to insert ShowAtHomeButton at`);
  2012. return false;
  2013. }
  2014. const item = document.createElement(`li`);
  2015. item.append(createShowAtHomeAnchor(localUrl));
  2016. prependTo.prepend(item);
  2017. return true;
  2018. }
  2019. function addButton(localUrl) {
  2020. const oldButton = document.querySelectorAll(`.` + constants_default.SHOW_AT_HOME_BUTTON_CLASS);
  2021. if (oldButton.length > 0 && oldButton[0].dataset.creationHref !== location.href) {
  2022. debug(`Removing old show at home button`);
  2023. oldButton.forEach((btn) => btn.remove());
  2024. } else if (oldButton.length > 0) {
  2025. debug(`Old show at home button still exists`);
  2026. return false;
  2027. }
  2028. if (!localUrl) {
  2029. debug(`No local URL for show at home button found`);
  2030. return false;
  2031. } else if (isRemoteLemmyUrl(location)) {
  2032. return addLemmyShowAtHomeButton(localUrl);
  2033. } else if (isRemoteKbinUrl(location)) {
  2034. return addKbinShowAtHomeButton(localUrl);
  2035. } else {
  2036. return false;
  2037. }
  2038. }
  2039. async function addShowAtHomeButton() {
  2040. if (isInstantlyRewritable(location)) {
  2041. return addButton(findLocalUrl(location));
  2042. } else if (isRewritableAfterResolving(location)) {
  2043. try {
  2044. return addButton(await fetchLocalUrl(location));
  2045. } catch (e) {
  2046. debug(`Error while trying to add "show at home" button`, e);
  2047. }
  2048. }
  2049. }
  2050.  
  2051. // src/rewriting/rewrite.js
  2052. function triggerRewrite() {
  2053. doAllDomChanges();
  2054. }
  2055. function isOrHasOurAddedNode(node) {
  2056. return getAddedNodesSelectors().some((selector) => node.matches?.(selector) || node.querySelector?.(selector));
  2057. }
  2058. function isIrrelevantChange(change) {
  2059. if (change.type === `childList`) {
  2060. if (Array.from(change.removedNodes).some(isOrHasOurAddedNode)) {
  2061. trace(`Change`, change, `is relevant because a removed node is/has ours`);
  2062. return false;
  2063. }
  2064. if (!Array.from(change.addedNodes).every(isOrHasOurAddedNode)) {
  2065. trace(`Change`, change, `is relevant because not every added node is/has ours`);
  2066. return false;
  2067. }
  2068. } else if (change.type === `attributes` && isRemoteUrl(new URL(change.target.href))) {
  2069. trace(`Change`, change, `is relevant because href changed to a remote URL`);
  2070. return false;
  2071. }
  2072. trace(`Change`, change, `is irrelevant`);
  2073. return true;
  2074. }
  2075. async function startRewriting() {
  2076. new MutationObserver((changes, observer) => {
  2077. debug(`MutationObserver triggered`, changes);
  2078. if (changes.every(isIrrelevantChange)) {
  2079. debug(`All observed changes are irrelevant`);
  2080. return;
  2081. }
  2082. doAllDomChanges(changes);
  2083. }).observe(document.body, {
  2084. subtree: true,
  2085. childList: true,
  2086. attributeFilter: [`href`]
  2087. });
  2088. await doAllDomChanges();
  2089. }
  2090. async function doAllDomChanges(changes) {
  2091. debug(`doAllDomChanges start`);
  2092. const addedMakeHomeButton = addMakeHomeButton();
  2093. if (addedMakeHomeButton)
  2094. debug(`Added Make Home Button`);
  2095. const addedShowAtHomeButton = HOME ? addShowAtHomeButton() : false;
  2096. if (addedShowAtHomeButton)
  2097. debug(`Added Show At Home Button`);
  2098. const rewrittenLinks = HOME ? await rewriteLinksToLocal(changes) : false;
  2099. if (rewrittenLinks)
  2100. debug(`Rewritten some links`);
  2101. debug(`doAllDomChanges end`);
  2102. }
  2103.  
  2104. // src/home.js
  2105. var HOME;
  2106. async function initHome() {
  2107. HOME = await getValue(`home`);
  2108. if (!HOME && isLemmyInstance(location) && confirm(`Lemmy Universal Link Switcher: Set this instance to be your home instance to which all URLs get rewritten to?`)) {
  2109. setHome(location.origin);
  2110. }
  2111. }
  2112. async function setHome(newHome) {
  2113. if (typeof newHome !== `string`) {
  2114. newHome = null;
  2115. }
  2116. HOME = newHome;
  2117. await setValue(`home`, newHome);
  2118. }
  2119. async function getHome() {
  2120. return await getValue(`home`);
  2121. }
  2122. function updateHomePeriodically() {
  2123. debug(`Current HOME`, HOME);
  2124. setInterval(async () => {
  2125. const prev = HOME;
  2126. await setHome(await getHome());
  2127. if (prev !== HOME) {
  2128. debug(`HOME changed from`, prev, `to`, HOME);
  2129. triggerRewrite();
  2130. }
  2131. }, 1337);
  2132. }
  2133.  
  2134. // src/main.js
  2135. (async () => {
  2136. await initHome();
  2137. updateHomePeriodically();
  2138. await initAuth();
  2139. updateAuthPeriodically();
  2140. startRewriting();
  2141. })();
  2142. })();