GeoGuessr Background Replacer

Replaces the background of the geoguessr pages with your own images

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

  1. // ==UserScript==
  2. // @name GeoGuessr Background Replacer
  3. // @description Replaces the background of the geoguessr pages with your own images
  4. // @version 2.1.11
  5. // @author Tyow#3742
  6. // @match *://*.geoguessr.com/*
  7. // @license MIT
  8. // @require https://unpkg.com/@popperjs/core@2.11.5/dist/umd/popper.min.js
  9. // @namespace https://greasyfork.org/users/1011193
  10. // @grant GM_addStyle
  11. // @grant GM_setValue
  12. // @grant GM_getValue
  13. // @require https://update.greasyfork.org/scripts/460322/1408713/Geoguessr%20Styles%20Scan.js
  14. // ==/UserScript==
  15.  
  16. // Some code for popup adapted from blink script: https://greasyfork.org/en/scripts/438579-geoguessr-blink-mode
  17.  
  18. /* ############################################################################### */
  19. /* ##### DON'T MODIFY ANYTHING BELOW HERE UNLESS YOU KNOW WHAT YOU ARE DOING ##### */
  20. /* ############################################################################### */
  21.  
  22. const guiHTMLHeader = `
  23. <div id="backgroundReplacerPopupWrapper">
  24. <div id="backgroundReplacerSearchWrapper">
  25. <div id="backgroundReplacerInputWrapper">
  26. <div id="backgroundReplacerPopup" style="background: rgba(26, 26, 46, 0.9); padding: 15px; border-radius: 10px; max-height: 80vh; overflow-y: auto; width: 28em">
  27. <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px;">
  28. <span id="backgroundReplacerLabel1" style="margin: 0; padding-right: 6px;">Add Home Page image</span>
  29. <input type="url" id="homepageInput" name="homepage" style="background: rgba(255,255,255,0.1); color: white; border: none; border-radius: 5px">
  30. </div>
  31. <span>Home Page Images:</span>
  32. <div id="homePageImages" style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px; flex-direction: column"></div>
  33. <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px;">
  34. <span id="backgroundReplacerLabel2" style="margin: 0; padding-right: 6px;">Add Other Page Image</span>
  35. <input type="url" id="otherpagesInput" name="otherpages" style="background: rgba(255,255,255,0.1); color: white; border: none; border-radius: 5px">
  36. </div>
  37. <span>Other Pages Images:</span>
  38. <div id="otherPagesImages" style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px; flex-direction: column"></div>
  39. </div>
  40. <button style="width: 59.19px" id="backgroundReplacerToggle"><picture id="backgroundReplacerTogglePicture" style="justify-content: center"><img src="https://www.svgrepo.com/show/342899/wallpaper.svg" style="width: 15px; filter: brightness(0) invert(1); opacity: 100%;"></picture></button>
  41. </div>
  42. </div>
  43. </div>
  44. `
  45. let homePageImageList = GM_getValue("homepageImages");
  46. let otherImages = GM_getValue("otherImages");
  47.  
  48. // Defaults
  49. if (homePageImageList == undefined) {
  50. homePageImageList = [
  51. "https://cdn.wallpapersafari.com/6/80/9ZbpYo.jpg",
  52. "https://cdn.wallpapersafari.com/25/72/dtkc16.jpg",
  53. "https://i.imgur.com/l9K9IOq.jpg",
  54. ];
  55. GM_setValue("homepageImages", homePageImageList);
  56. }
  57. if (otherImages == undefined) {
  58. otherImages = [
  59. "https://imgur.com/eK23SeH.jpg",
  60. "https://i.imgur.com/l9K9IOq.jpg"
  61. ];
  62. GM_setValue("otherImages", otherImages);
  63. }
  64.  
  65. let hide = false;
  66. let styles = GM_getValue("backgroundReplacerStyles");
  67. if (!styles) {
  68. hide = true;
  69. styles = {};
  70. }
  71.  
  72. let homePageImgURL;
  73.  
  74. //console.log(cn("label_variantWhite__"))
  75.  
  76. const setHomePageImg = (img = false) => {
  77. if (img) {
  78. homePageImgURL = img;
  79. } else if(homePageImageList.length) {
  80. homePageImgURL = homePageImageList[Math.floor((Math.random()*homePageImageList.length))];
  81. } else {
  82. homePageImgURL = "";
  83. }
  84. // console.log(homePageImgURL);
  85. }
  86.  
  87. setHomePageImg();
  88.  
  89. let otherPagesImgURL;
  90.  
  91. const setOtherImg = (img = false) => {
  92. if (img) {
  93. otherPagesImgURL = img;
  94. } else if(otherImages.length) {
  95. otherPagesImgURL = otherImages[Math.floor((Math.random()*otherImages.length))];
  96. } else {
  97. otherPagesImgURL = "";
  98. }
  99. }
  100.  
  101. setOtherImg();
  102.  
  103. let css = `.customBackground { bottom: 0;
  104. display: block;
  105. height: 100%;
  106. object-fit: cover;
  107. pointer-events: none;
  108. position: fixed;
  109. right: 0;
  110. transition: .2s ease-in-out;
  111. width: 100%;
  112. }
  113. .zindex {
  114. z-index: -1;
  115. }
  116. .deleteIcon {
  117. width: 25px;
  118. filter: brightness(0) invert(1);
  119. opacity: 60%;
  120. }
  121. .backgroundImage {
  122. width: 20em;
  123. }
  124. .deleteButton {
  125. width: 59.19px;
  126. margin-bottom: 8em;
  127. }
  128. .backgroundImageWrapper {
  129. display: flex;
  130. padding: .5em;
  131. }
  132. .backgroundImageWrapper {
  133. position: relative;
  134. display: flex; /* To lay out the imageContainer and button side by side */
  135. align-items: center; /* Vertically center align the contents */
  136. }
  137.  
  138. .imageContainer {
  139. position: relative;
  140. width: /* e.g., 300px; */;
  141. height: /* e.g., 200px; */;
  142. overflow: hidden;
  143. cursor: pointer; /* This line changes the cursor */
  144. }
  145.  
  146. .backgroundImage {
  147. width: 100%;
  148. height: 100%;
  149. transition: opacity 0.3s ease;
  150. vertical-align: bottom;
  151. }
  152.  
  153. .overlay {
  154. position: absolute;
  155. top: 0;
  156. left: 0;
  157. width: 100%;
  158. height: 100%;
  159. background: rgba(0,0,0,0.7);
  160. display: flex;
  161. justify-content: center;
  162. align-items: center;
  163. opacity: 0;
  164. transition: opacity 0.3s ease;
  165. }
  166.  
  167. .imageContainer:hover .backgroundImage {
  168. opacity: 0.3;
  169. }
  170.  
  171. .imageContainer:hover .overlay {
  172. opacity: 1;
  173. }
  174.  
  175. .overlay span {
  176. color: white;
  177. font-size: 18px;
  178. }
  179.  
  180. /* Add some margin if you want space between the image and the button */
  181. .backgroundImageWrapper button {
  182. margin-left: 10px; /* adjust as needed */
  183. }
  184.  
  185.  
  186. /* You can style the text within the overlay here */
  187. .overlay span {
  188. color: white;
  189. font-size: 18px;
  190. text-align: center;
  191. }
  192. .deleteIconPicture {
  193. justifyContent:center;
  194. }
  195. .removeBackground {
  196. background: none !important
  197. }
  198.  
  199. .shadow {
  200. box-shadow: 0 .25rem 2.75rem rgba(32,17,46,.2),0 1.125rem 2.25rem -1.125rem rgba(0,0,0,.24),0 1.875rem 3.75rem -.625rem rgba(0,0,0,.16);
  201. background: rgba(0, 0, 0, 0.35);
  202. }
  203.  
  204. .blurBefore::before {
  205. content: '';
  206. position: absolute;
  207. top: 0;
  208. left: 0;
  209. right: 0;
  210. bottom: 0;
  211. background: rgba(0, 0, 0, 0.35);
  212. filter: blur(10px);
  213. z-index: -1;
  214. }
  215.  
  216. .highscoreModification {
  217. border-radius: .5rem;
  218. background: var(--ds-color-white-10);
  219. backdrop-filter: blur(11px);
  220. padding: .5rem;
  221. }
  222.  
  223. .mapInfoModification {
  224. padding: 1rem;
  225. border-radius: .5rem;
  226. background: var(--ds-color-white-10);
  227. backdrop-filter: blur(12px);
  228. }
  229.  
  230. .textShadow {
  231. text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.5);
  232. }
  233. .cardModification {
  234. backdrop-filter: blur(12px);
  235. }
  236. .mapSelectorModification {
  237. background: var(--ds-color-white-10);
  238. backdrop-filter: blur(12px);
  239. }
  240. .highScoreTitleModification {
  241. background: var(--ds-color-white-10);
  242. backdrop-filter: blur(12px);
  243. border-radius: .5rem;
  244. padding: .5rem;
  245. }
  246. `;
  247. GM_addStyle(css);
  248.  
  249.  
  250. const showPopup = (showButton, popup) => {
  251. popup.style.display = 'block';
  252. Popper.createPopper(showButton, popup, {
  253. placement: 'bottom',
  254. modifiers: [
  255. {
  256. name: 'offset',
  257. options: {
  258. offset: [0, 10],
  259. },
  260. },
  261. ],
  262. });
  263. }
  264.  
  265. const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
  266.  
  267. const iterativeSetTimeout = async (func, initDelay, cond) => {
  268. while (!cond()) {
  269. await delay(initDelay);
  270. await func();
  271. initDelay *= 2;
  272. stylesUsed.forEach(style => {
  273. styles[style] = cn(style);
  274. });
  275. }
  276. };
  277.  
  278. // Caching system for styles
  279. // Basically, we have a browser stored styles object,
  280. // which contains the most recent classNames found by scanStyles()
  281. // This is what the script will immediately use upon loading,
  282. // so that there's no pause in delivering the UI to the user
  283. // But the script will also fire off this function
  284. // which will use the above iterativeSetTimeout function to call scanStyles
  285. // This is so there aren't a thousand calls in quick succession.
  286. // Once all the classNames we're looking for are found,
  287. // it will update the local storage and the ui with the (possibly) new classnames
  288. const stylesUsed = [
  289. "header_item__",
  290. "quick-search_wrapper__",
  291. "quick-search_searchInputWrapper__",
  292. "quick-search_searchInputButton__",
  293. "quick-search_iconSection__",
  294. ];
  295.  
  296. const uploadDownloadStyles = async () => {
  297. stylesUsed.forEach(style => {
  298. // styles[style] = cn(style);
  299. // console.log(style);
  300. // console.log(cn(style));
  301. });
  302. await iterativeSetTimeout(scanStyles, 0.1, () => checkAllStylesFound(stylesUsed) !== undefined);
  303. if (hide) {
  304. document.querySelector("#backgroundReplacerPopupWrapper").hidden = "";
  305. }
  306. stylesUsed.forEach(style => {
  307. styles[style] = cn(style);
  308. // console.log(style);
  309. // console.log(cn(style));
  310. });
  311. setStyles();
  312. GM_setValue("backgroundReplacerStyles", styles);
  313. }
  314.  
  315. const getStyle = style => {
  316. return styles[style];
  317. }
  318.  
  319. const setStyles = () => {
  320. try {
  321. document.querySelector("#backgroundReplacerPopupWrapper").className = getStyle("header_item__");
  322. document.querySelector("#backgroundReplacerSearchWrapper").className = getStyle("quick-search_wrapper__");
  323. document.querySelector("#backgroundReplacerInputWrapper").className = getStyle("quick-search_searchInputWrapper__");
  324. document.querySelector("#backgroundReplacerToggle").className = getStyle("quick-search_searchInputButton__");
  325. document.querySelector("#backgroundReplacerLabel1").className = getStyle("label_sizeXSmall__") + getStyle("label_variantWhite__");
  326. document.querySelector("#backgroundReplacerLabel2").className = getStyle("label_sizeXSmall__") + getStyle("label_variantWhite__");
  327. document.querySelector("#backgroundReplacerTogglePicture").className = getStyle("quick-search_iconSection__");
  328. document.querySelectorAll(".deleteButton").forEach(el => el.className = el.className + " " + getStyle("quick-search_searchInputButton__"));
  329. } catch (err) {
  330. console.error(err);
  331. }
  332. }
  333.  
  334.  
  335. const insertHeaderGui = async (header, gui) => {
  336.  
  337. header.insertAdjacentHTML('afterbegin', gui);
  338.  
  339. // Resolve class names
  340. if (hide) {
  341. document.querySelector("#backgroundReplacerPopupWrapper").hidden = "true"
  342. }
  343.  
  344. scanStyles().then(() => uploadDownloadStyles());
  345. setStyles();
  346.  
  347.  
  348.  
  349. const showButton = document.querySelector('#backgroundReplacerToggle');
  350. const popup = document.querySelector('#backgroundReplacerPopup');
  351. popup.style.display = 'none';
  352.  
  353. document.addEventListener('click', (e) => {
  354. const target = e.target;
  355. if (target == popup || popup.contains(target) || !document.contains(target)) return;
  356. if (target.matches('#backgroundReplacerToggle, #backgroundReplacerToggle *')) {
  357. e.preventDefault();
  358. showPopup(showButton, popup);
  359. } else {
  360. popup.style.display = 'none';
  361. }
  362. });
  363. }
  364.  
  365. // Global to track whether the most recent image insertion was done on homepage
  366. let isHomePage = location.pathname == "/";
  367.  
  368. const addShadows = () => {
  369. const mapSelector = document.querySelector("[class^='map-selector_selector__'")
  370. if (mapSelector && !mapSelector.classList.contains("mapSelectorModification")) {
  371. mapSelector.classList.add("mapSelectorModification")
  372. // mapSelector.classList.add("blurBefore")
  373. }
  374. const highscoreRoot = document.querySelector("[class^='map-highscore_root__'")
  375. if (highscoreRoot && !highscoreRoot.classList.contains("highscoreModification")) {
  376. highscoreRoot.classList.add("highscoreModification")
  377. }
  378. const mapStatsText = document.querySelectorAll("[class^='map-stats_mapStatMetricValue__'")
  379. if (mapStatsText) {
  380. for (const el of mapStatsText) {
  381. if (!el.classList.contains("textShadow")) {
  382. el.classList.add("textShadow")
  383. }
  384. }
  385. }
  386. const mapInfo = document.querySelector("[class^='map-block_mapInfo__'")
  387. if (mapInfo && !mapInfo.classList.contains("mapInfoModification")) {
  388. mapInfo.classList.add("mapInfoModification")
  389. }
  390. const howItWorks = document.querySelector("[class^='ranked-system-how-it-works-page_root__'")
  391. if (howItWorks && !howItWorks.classList.contains("mapInfoModification")) {
  392. howItWorks.classList.add("mapInfoModification")
  393. }
  394. const userStatsCards = document.querySelectorAll("[class^='user-stats-overview_card__'")
  395. if (userStatsCards) {
  396. for (const el of userStatsCards) {
  397. if (!el.classList.contains("cardModification")) {
  398. el.classList.add("cardModification")
  399. }
  400. }
  401. }
  402. const mapStats = document.querySelectorAll("[class^='map-stats_mapStat__'")
  403. if (mapStats) {
  404. for (const el of mapStats) {
  405. if (!el.classList.contains("cardModification")) {
  406. el.classList.add("cardModification")
  407. }
  408. }
  409. }
  410. const cards = document.querySelectorAll("[class^='card_card__'")
  411. if (cards) {
  412. for (const el of cards) {
  413. if (!el.classList.contains("cardModification")) {
  414. el.classList.add("cardModification")
  415. }
  416. }
  417. }
  418. // const highScoreTitle = document.querySelectorAll("[class^='headline_heading__'")
  419. // for (const el of highScoreTitle) {
  420. // if (el.textContent == "Highscore" && !el.classList.contains("highScoreTitleModification")) {
  421. // el.classList.add("highScoreTitleModification")
  422. // }
  423. // }
  424. const mapsCenter = document.querySelector("[class^='maps_center__'")
  425. if (mapsCenter && !mapsCenter.classList.contains("mapsCenterMoved")) {
  426. const mapsSwitch = document.querySelector("[class^='map-highscore_switchContainer__'")
  427. highscoreRoot.insertBefore(mapsCenter, mapsSwitch);
  428. mapsCenter.classList.add("mapsCenterMoved")
  429. }
  430. }
  431.  
  432. const homepageModification = () => {
  433. const startPageWrapper = document.querySelector("[class^=startpage_newWrapper__")
  434. if (startPageWrapper && !startPageWrapper.classList.contains("removeBackground")) {
  435. startPageWrapper.classList.add('removeBackground');
  436. }
  437. }
  438.  
  439. const extraStyling = () => {
  440. addShadows()
  441. homepageModification()
  442. }
  443.  
  444. const insertBackground = (refresh=false) => {
  445. let inGame = false;
  446. let el = document.querySelector("[class^='background_wrapper']");
  447. if (!el) {
  448. inGame = true;
  449. el = document.querySelector("#__next");
  450. if (!el) return;
  451. // Because this element has multiple classes, we need to use a different selector
  452. const def = document.querySelector("[class*=in-game_backgroundDefault__]");
  453. let reg = /^in-game_backgroundDefault__/;
  454. if (def) {
  455. def.classList = Array.from(def.classList).filter(cl => !cl.match(reg));
  456. }
  457. const partyRoot = document.querySelector("[class^=party_root__]");
  458. if (partyRoot) {
  459. partyRoot.style.background = "none";
  460. }
  461. // Without this, you can see the background behind the map in a game summary
  462.  
  463. // Purple color used by geoguessr, with .9 alpha
  464. const purple9 = "rgba(12 12 46 / .9)";
  465. // .7 alpha
  466. const purple7 = "rgba(12 12 46 / .7)";
  467. const gameSummary = document.querySelector("[class^=game-summary_container__");
  468. if (gameSummary) {
  469. gameSummary.style.opacity = "1";
  470. gameSummary.style.backgroundColor = purple9;
  471. }
  472. const header = document.querySelector("[class^=game-summary_playedRoundsHeader__");
  473. if (header) {
  474. header.style.backgroundColor = purple7;
  475. }
  476.  
  477. }
  478. // We only want the zindex = -1 to exist in game settings, on other pages it's detrimental
  479. let img = document.querySelector('.customBackground');
  480. if (refresh) {
  481. img.remove();
  482. img = document.querySelector('.customBackground');
  483. }
  484. if (img) {
  485. if (!inGame) {
  486. img.classList = Array.from(img.classList).filter(cl => cl != 'zindex');
  487. }
  488. // Return if most recent insertion was in same area (homepage vs not)
  489. if (isHomePage == (location.pathname == "/")) {
  490. return;
  491. }
  492. img.remove();
  493. // Update isHomePage
  494. }
  495. if (!img) {
  496. img = document.createElement("img")
  497. img.classList.add("customBackground");
  498. if (inGame) {
  499. img.classList.add("zindex");
  500. } else {
  501. img.classList = Array.from(img.classList).filter(cl => cl != 'zindex');
  502. }
  503. }
  504. isHomePage = location.pathname == "/";
  505. if (isHomePage && homePageImgURL) {
  506. img.src = homePageImgURL;
  507. } else if (!isHomePage && otherPagesImgURL) {
  508. img.src = otherPagesImgURL;
  509. } else {
  510. return
  511. }
  512. el.appendChild(img);
  513. }
  514.  
  515. const updateStorage = (listName, newList) => {
  516. GM_setValue(listName, newList);
  517. }
  518.  
  519. const validate = (e, homepage) => {
  520. const patt = new RegExp(".*.(jpg|png|gif|jpeg|webp|svg|avif)","i");
  521. if (e.key == "Enter") {
  522. if (patt.test(e.target.value)) {
  523. if (homepage) {
  524. let homepageImages = GM_getValue("homepageImages");
  525. homepageImages.push(e.target.value);
  526. if (homepageImages.length == 1) {
  527. homePageImgURL = homepageImages[0];
  528. }
  529. GM_setValue("homepageImages", homepageImages);
  530. homePageImageList = homepageImages
  531. } else {
  532. let otherImagesNew = GM_getValue("otherImages");
  533. otherImagesNew.push(e.target.value);
  534. if (otherImagesNew.length == 1) {
  535. otherPagesImgURL = otherImagesNew[0];
  536. }
  537. GM_setValue("otherImages", otherImagesNew);
  538. otherImages = otherImagesNew;
  539. }
  540. refreshPopup();
  541. e.target.value = "";
  542. } else {
  543. window.alert("This link doesn't seem to be to an image file, it should end in .jpg, .jpeg, .png, .gif, .webp, .avif, or .svg");
  544. }
  545. }
  546. }
  547.  
  548. const removeImage = (image, div, list, listName) => {
  549. let result = window.confirm("Are you sure you want to remove this image?");
  550. if (!result) {
  551. return
  552. }
  553. let i = list.indexOf(image);
  554. if (i != -1) {
  555. list.splice(i, 1);
  556. updateStorage(listName, list);
  557. refreshPopup();
  558. if (listName == "otherImages" && !list.includes(image)) {
  559. setOtherImg();
  560. updateImage(true);
  561. }
  562. if (listName == "homepageImages" && !list.includes(image)) {
  563. setHomePageImg();
  564. updateImage(true);
  565. }
  566. }
  567. };
  568.  
  569. // displays an image in the popup
  570. const displayImage = (image, imagesDiv, list, listName) => {
  571. const img = document.createElement("img");
  572. const div = document.createElement("div");
  573. div.className = "backgroundImageWrapper";
  574. const container = document.createElement("div");
  575. container.className = "imageContainer";
  576.  
  577. img.src = image
  578. img.className = "backgroundImage";
  579. div.appendChild(container);
  580. container.appendChild(img);
  581.  
  582. const deleteIcon = document.createElement("img");
  583. deleteIcon.className = "deleteIcon";
  584. deleteIcon.src = "https://www.svgrepo.com/show/493964/delete-1.svg";
  585.  
  586. const deleteButton = document.createElement("button");
  587. deleteButton.className = getStyle("quick-search_searchInputButton__") + " " + "deleteButton";
  588. deleteButton.appendChild(deleteIcon);
  589. deleteButton.addEventListener("click", e => {
  590. removeImage(image, div, list, listName);
  591. });
  592.  
  593. const overlay = document.createElement("div");
  594. overlay.className = "overlay";
  595. const span = document.createElement("span");
  596. isHomePage = location.pathname == "/";
  597. span.innerText = ((isHomePage && listName == "homepageImages")
  598. || (!isHomePage && listName == "otherImages"))
  599. ? "Make current image" : "You're not on a page where this image will display";
  600. overlay.appendChild(span);
  601.  
  602. container.appendChild(overlay);
  603. div.appendChild(deleteButton);
  604.  
  605. imagesDiv.appendChild(div);
  606. container.addEventListener('click', function() {
  607. if (listName == "homepageImages") {
  608. setHomePageImg(image);
  609. }
  610. if (listName == "otherImages") {
  611. setOtherImg(image);
  612. }
  613. insertBackground(true);
  614. });
  615. }
  616.  
  617. const refreshPopup = () => {
  618. if (document.querySelector("#backgroundReplacerPopupWrapper") != null && document.querySelector('[class^=header-tablet-desktop_root__]') != null) {
  619. let div = document.querySelector("#homePageImages");
  620. while (div.children.length) {
  621. div.removeChild(div.children[0]);
  622. }
  623. div = document.querySelector("#otherPagesImages");
  624. while (div.children.length) {
  625. div.removeChild(div.children[0]);
  626. }
  627. addPopup(true);
  628. const showButton = document.querySelector('#backgroundReplacerToggle');
  629. const popup = document.querySelector('#backgroundReplacerPopup');
  630. showPopup(showButton, popup);
  631. }
  632. }
  633.  
  634. const addPopup = (refresh=false) => {
  635. if ((refresh || (document.querySelector('[class^=header-tablet-desktop_root__]') || document.querySelector('[class^=header-desktop_root__]')) && document.querySelector('#backgroundReplacerPopupWrapper') === null)) {
  636. if (!refresh) {
  637. let section = document.querySelector('[class^=header-tablet-desktop_desktopSectionRight__]')
  638. if (!section) section = document.querySelector('[class^=header-desktop_desktopSectionRight__]')
  639. insertHeaderGui(section, guiHTMLHeader)
  640. const homepageInput = document.querySelector("#homepageInput");
  641. homepageInput.addEventListener("keyup", e => {
  642. validate(e, true);
  643. });
  644. const otherpagesInput = document.querySelector("#otherpagesInput");
  645. otherpagesInput.addEventListener("keyup", e => {
  646. validate(e, false);
  647. });
  648. }
  649. const homePageImagesDiv = document.querySelector('#homePageImages');
  650. if (homePageImagesDiv) {
  651. // Loop through images and display them
  652. for (let i = 0; i < homePageImageList.length; i++) {
  653. displayImage(homePageImageList[i], homePageImagesDiv,homePageImageList, "homepageImages");
  654. }
  655. }
  656. const otherPagesImagesDiv = document.querySelector("#otherPagesImages");
  657. if (otherPagesImagesDiv) {
  658. // Loop through images and display them
  659. for (let i = 0; i < otherImages.length; i++) {
  660. displayImage(otherImages[i], otherPagesImagesDiv, otherImages, "otherImages");
  661. }
  662. }
  663. }
  664. }
  665.  
  666. const updateImage = (refresh=false) => {
  667. // Don't do anything while the page is loading
  668. if (document.querySelector("[class^=page-loading_loading__]")) return;
  669. addPopup();
  670. insertBackground(refresh);
  671. extraStyling()
  672. }
  673.  
  674.  
  675.  
  676. new MutationObserver(async (mutations) => {
  677. updateImage()
  678. }).observe(document.body, { subtree: true, childList: true });