GeoGuessr XP FARM - The Best Cheat Out There!

One of the greatest geoguessr scripts out there able to farm xp very fast to precise location pinpointing + an whole new overlay to the site! this script will amaze you!

目前为 2024-04-12 提交的版本。查看 最新版本

// ==UserScript==
// @name         GeoGuessr XP FARM - The Best Cheat Out There!
// @namespace    http://tampermonkey.net/
// @version      3.0
// @description  One of the greatest geoguessr scripts out there able to farm xp very fast to precise location pinpointing + an whole new overlay to the site! this script will amaze you!
// @author       ems
// @match        https://www.geoguessr.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=geoguessr.com
// @connect      restcountries.eu
// @grant        none

// ==/UserScript==

(function() {
    'use strict';

    // Create and inject the logo HTML and CSS
    function createLogo() {
        const logoHTML = `
            <div id="exodusLogo" class="logo">Version v3.0 [BETA]</div>
        `;

        const logoCSS = `
            .logo {
                font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
                font-size: 18px; /* Smaller font size */
                color: transparent; /* Hide the text initially */
                text-shadow: 0 0 5px rgba(255, 0, 0, 0.8), 0 0 10px rgba(255, 0, 0, 0.8); /* Red text shadow */
                background: linear-gradient(45deg, rgba(255, 0, 0, 0.8), rgba(0, 0, 0, 0.8)); /* Gradient from red to black */
                background-clip: text; /* Apply the background to the text only */
                -webkit-background-clip: text; /* For Safari */
                position: fixed;
                top: 20px;
                left: 25px;
                z-index: 9999;
                animation: pulse 1s ease-in-out infinite alternate;
            }

            @keyframes pulse {
                0% { transform: scale(1); }
                100% { transform: scale(1.1); }
            }
        `;

        // Inject the logo HTML
        const logoContainer = document.createElement('div');
        logoContainer.innerHTML = logoHTML;
        document.body.appendChild(logoContainer);

        // Inject the logo CSS
        const style = document.createElement('style');
        style.textContent = logoCSS;
        document.head.appendChild(style);
    }

    // Call the function to create the logo
    createLogo();

})();


let globalCoordinates = {
    lat: 0,
    lng: 0
};

let globalPanoID = undefined;

var originalOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url) {
    if (url.startsWith('https://maps.googleapis.com/$rpc/google.internal.maps.mapsjs.v1.MapsJsInternalService/GetMetadata')) {
        this.addEventListener('load', function () {
            let interceptedResult = this.responseText;
            const pattern = /-?\d+\.\d+,-?\d+\.\d+/g;
            let match = interceptedResult.match(pattern)[0];
            let split = match.split(",");
            let lat = Number.parseFloat(split[0]);
            let lng = Number.parseFloat(split[1]);
            globalCoordinates.lat = lat;
            globalCoordinates.lng = lng;
        });
    }
    return originalOpen.apply(this, arguments);
};

function placeMarker(safeMode){
    let {lat,lng} = globalCoordinates;

    if (safeMode) {
        const sway = [Math.random() > 0.5, Math.random() > 0.5];
        const multiplier = Math.random() * 4;
        const horizontalAmount = Math.random() * multiplier;
        const verticalAmount = Math.random() * multiplier;
        sway[0] ? lat += verticalAmount : lat -= verticalAmount;
        sway[1] ? lng += horizontalAmount : lat -= horizontalAmount;
    }

    let element = document.getElementsByClassName("guess-map_canvas__JAHHT")[0];
    if(!element){
        placeMarkerStreaks();
        return;
    }
    const keys = Object.keys(element);
    const key = keys.find(key => key.startsWith("__reactFiber$"));
    const props = element[key];
    const x = props.return.return.memoizedProps.map.__e3_.click;
    const y = Object.keys(x)[0];
    const z = {
        latLng:{
            lat: () => lat,
            lng: () => lng,
        }
    };

    const xy = x[y];
    const a = Object.keys(x[y]);

    for(let i = 0; i < a.length ;i++){
        let q = a[i];
        if (typeof xy[q] === "function"){
            xy[q](z);
        }
    }
}

function placeMarkerStreaks(){
    let {lat,lng} = globalCoordinates;
    let element = document.getElementsByClassName("region-map_mapCanvas__R95Ki")[0];
    if(!element){
        return;
    }
    const keys = Object.keys(element);
    const key = keys.find(key => key.startsWith("__reactFiber$"));
    const props = element[key];
    const x = props.return.return.memoizedProps.map.__e3_.click;
    const y = Object.keys(x);
    const w = "(e.latLng.lat(),e.latLng.lng())}";
    const v = {
        latLng:{
            lat: () => lat,
            lng: () => lng,
        }
    };
    for(let i = 0; i < y.length; i++){
        const curr = Object.keys(x[y[i]]);
        let func = curr.find(l => typeof x[y[i]][l] === "function");
        let prop = x[y[i]][func];
        if(prop && prop.toString().slice(5) === w){
            prop(v);
        }
    }
}

function mapsFromCoords() {
    const {lat, lng} = globalCoordinates;
    if (!lat || !lng) {
        return;
    }

    const mapUrl = `https://maps.google.com/?output=embed&q=${lat},${lng}&ll=${lat},${lng}&z=5`;
    window.open(mapUrl, '_blank', 'width=600,height=600,resizable=yes,scrollbars=yes');
}

// Add a black box on the right side of the screen
function createBlackBox() {
    const blackBox = document.createElement('div');
    blackBox.id = 'blackBox'; // Adding an ID for easy reference
    blackBox.style.position = 'fixed';
    blackBox.style.top = '0';
    blackBox.style.right = '0';
    blackBox.style.width = '200px';
    blackBox.style.height = '2%';
    blackBox.style.backgroundColor = 'black';
    blackBox.style.color = 'white';
    blackBox.style.padding = '20px';
    blackBox.style.zIndex = '9999';
    blackBox.innerHTML = '<span style="font-size: 16px;">Press INSERT to view the guide</span>';

    document.body.appendChild(blackBox);

    // Schedule the removal of the black box after 5 seconds
    setTimeout(function() {
        const blackBoxToRemove = document.getElementById('blackBox');
        if (blackBoxToRemove) {
            blackBoxToRemove.style.opacity = '0';
            setTimeout(function() {
                blackBoxToRemove.remove();
            }, 1000); // Fade out transition time
        }
    }, 10000); // 5 seconds
}

// Call the function to create the black box on page load
createBlackBox();

let popupVisible = false;

function togglePopup() {
    const popup = document.getElementById('popup');

    if (!popup) {
        // Create popup element
        const popupElement = document.createElement('div');
        popupElement.id = 'popup';
        popupElement.style.position = 'fixed';
        popupElement.style.top = '50%';
        popupElement.style.left = '50%';
        popupElement.style.transform = 'translate(-50%, -50%)';
        popupElement.style.backgroundColor = 'black';
        popupElement.style.color = 'white';
        popupElement.style.padding = '20px';
        popupElement.style.zIndex = '9999';

        // Create an inner div for the text content
        const textDiv = document.createElement('div');
        textDiv.innerHTML = 'Press [1] to pick an close spot to the destination pin<br><br>Press [2] to place your pin on the exact location of the destination<br><br>Press [3] to open an separate window that opens google maps on the exact location<br><br>-----------------------------------------------------------------------------------------<br><br><span class="tooltip">Press [P] to start the xp bot hover over this message for more info<span class="tooltiptext">only use this in classic maps this way you will gain xp fast without an account ban coming your way! note: really do not use this spamming bot in multiplayer its 100% ban</span></span>';
        popupElement.appendChild(textDiv);

        // Create an inner div for the rainbow border
        const borderDiv = document.createElement('div');
        borderDiv.classList.add('popup-border');
        popupElement.appendChild(borderDiv);

        document.body.appendChild(popupElement);
        popupVisible = true;
    } else {
        popup.style.display = popupVisible ? 'none' : 'block';
        popupVisible = !popupVisible;
    }

    // Dynamically adjust the rainbow border size
    const borderDiv = document.querySelector('.popup-border');
    if (borderDiv) {
        const popupContent = document.getElementById('popup');
        if (popupContent) {
            borderDiv.style.width = `${popupContent.offsetWidth}px`;
            borderDiv.style.height = `${popupContent.offsetHeight}px`;
        }
    }
}
function pathMatches(path) {
    return location.pathname.match(new RegExp(`^/(?:[^/]+/)?${path}$`))
}

function getIndex(element) {
    if (!element) return -1

    let i = 0
    while (element = element.previousElementSibling) {
        i++
    }

    return i
}

const OBSERVER_CONFIG = {
    characterDataOldValue: false,
    subtree: true,
    childList: true,
    characterData: false
}

const SCRIPT_PREFIX = "csb__"
const CONFIG_KEY = SCRIPT_PREFIX + "config"
const STYLE_ID = SCRIPT_PREFIX + "style"
const PERCENTAGE_INPUT_CLASS = SCRIPT_PREFIX + "percentage-input"
const COLOR_INPUT_CLASS = SCRIPT_PREFIX + "color-input"
const TEXT_INPUT_CLASS = SCRIPT_PREFIX + "text-input"
const DELETE_BUTTON_CLASS = SCRIPT_PREFIX + "delete-button"
const STANDARD_BUTTON_CLASS = SCRIPT_PREFIX + "standard-button"
const DOWN_BUTTON_CLASS = SCRIPT_PREFIX + "down-button"
const UP_BUTTON_CLASS = SCRIPT_PREFIX + "up-button"
const CUSTOMIZE_STATUS_BAR_BUTTON_ID = SCRIPT_PREFIX + "customize-status-bar-button"
const ADD_GRADIENT_NODE_BUTTON_ID = SCRIPT_PREFIX + "add-gradient-node-button"
const CUSTOMIZE_STATUS_BAR_SCREEN_ID = SCRIPT_PREFIX + "customize-status-bar-screen"
const GRADIENT_NODE_LIST_ID = SCRIPT_PREFIX + "gradient-node-list"
const TEXT_COLOR_NODE_LIST_ID = SCRIPT_PREFIX + "text-color-node-list"
const RESUME_BUTTON_ID = SCRIPT_PREFIX + "resume-button"
const BACKGROUND_COLOR_ID = SCRIPT_PREFIX + "background-color"
const TEMP_COLOR_VAR = "--" + SCRIPT_PREFIX + "temp-color"
const RESET_DEFAULTS_BUTTON_ID = SCRIPT_PREFIX + "reset-defaults-button"

const defaultNode = () => ({
    color: "#000000",
    percentage: 100
})

const DEFAULT_BACKGROUND_COLOR = "var(--ds-color-purple-80)"

const DEFAULT_GRADIENT_NODES = [
    {
        color: "#a19bd999",
        percentage: 0
    },
    {
        color: "#00000000",
        percentage: 50
    },
    {
        color: "#00000000",
        percentage: 50
    }
]

const DEFAULT_TEXT_COLORS = [
    "var(--ds-color-purple-20)",
    "var(--ds-color-white)"
]

const configString = localStorage.getItem(CONFIG_KEY)
let gradientNodes = DEFAULT_GRADIENT_NODES
let textColors = DEFAULT_TEXT_COLORS
let backgroundColor = DEFAULT_BACKGROUND_COLOR

if (configString) {
    const config = JSON.parse(configString)

    gradientNodes = config.gradient
    textColors = config.textColors
    backgroundColor = config.backgroundColor
}

const CUSTOMIZE_STATUS_BAR_BUTTON = `
  <button id="${CUSTOMIZE_STATUS_BAR_BUTTON_ID}" class="button_button__CnARx button_variantSecondary__lSxsR">
    Customize status bar
  </button>
  <div class="game-menu_divider__f2BbL"></div>
`

const COLOR_WIDGET = `
  <input type="color" class="${COLOR_INPUT_CLASS}" ></input>
  <input type="text" class="${TEXT_INPUT_CLASS}" style="width: 5.5rem;" required></input>
`

const GRADIENT_NODE = `
  <div style="
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto;
  ">
    <div class="grid-element">
      <input type="number" class="${PERCENTAGE_INPUT_CLASS}" min="0" max="100" step="any" required></input>
      <div style="font-weight: 700;">%</div>
    </div>
    <div class="grid-element" style="flex-direction: row-reverse">
      <button class="${DELETE_BUTTON_CLASS}">X</button>
      <button class="${STANDARD_BUTTON_CLASS} ${DOWN_BUTTON_CLASS}">↓</button>
      <button class="${STANDARD_BUTTON_CLASS} ${UP_BUTTON_CLASS}" style="margin-left: 1rem;">↑</button>
      ${COLOR_WIDGET}
    </div>
  </div>
`

const colorNode = (label, id) => `
  <div id="${id}" style="
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto;
  ">
    <div class="grid-element">
      <div style="font-weight: 700;">${label}</div>
    </div>
    <div class="grid-element" style="flex-direction: row-reverse">
      ${COLOR_WIDGET}
    </div>
  </div>
`

// Transforms an arbitrary css color value (like "rgb(0, 0, 0)" or "var(--some-color)") into a hex color
// (pretty hacky)
const evaluateColor = (color) => {
    const statusBar = document.querySelector(".game_status__q_b7N")
    statusBar.style.setProperty(TEMP_COLOR_VAR, color)
    const hexColor = window.getComputedStyle(statusBar).getPropertyValue(TEMP_COLOR_VAR)

    // Verify that it's indeed a hex color
    if (!hexColor.startsWith("#")) {
        console.log("could not evaluate color!")
        return "#000000"
    }

    // Strip the alpha channel
    if (hexColor.length > 7) {
        return hexColor.substr(0, 7)
    }

    // Expand the color, if it's in compressed form
    if (hexColor.length == 4) {
        return "#" + hexColor.substr(1).split("").map(char => char + char).join("")
    }

    return hexColor
}

const appendTextColorNode = (parent, label, index) => {
    parent.insertAdjacentHTML("beforeend", colorNode(label, ""))
    const textColorNode = parent.lastElementChild

    const colorInput = textColorNode.querySelector(`.${COLOR_INPUT_CLASS}`)
    const colorTextInput = textColorNode.querySelector(`.${TEXT_INPUT_CLASS}`)

    console.log(evaluateColor(textColors[index]))
    colorInput.value = evaluateColor(textColors[index])
    colorTextInput.value = textColors[index]

    colorInput.oninput = () => {
        textColors[index] = colorInput.value
        colorTextInput.value = textColors[index]
        updateStatusBarStyles()
    }

    colorTextInput.oninput = () => {
        textColors[index] = colorTextInput.value
        colorInput.value = evaluateColor(textColors[index])
        updateStatusBarStyles()
    }
}

const generateGradientString = () => {
    return `linear-gradient(180deg, ${
        gradientNodes.map((node) => `${node.color} ${node.percentage}%`).join(",")
    })`
}

const updateStatusBarStyles = () => {
    const style = document.getElementById(STYLE_ID)

    style.innerHTML = `
      .slanted-wrapper_variantPurple__95_Ub {
        --variant-background-color: ${generateGradientString()}, ${backgroundColor};
      }

      .slanted-wrapper_variantPurple__95_Ub .status_label__SNHKT {
        color: ${textColors[0]}
      }

      .slanted-wrapper_variantPurple__95_Ub .status_value__xZMNY {
        color: ${textColors[1]}
      }
    `

    localStorage.setItem(CONFIG_KEY, JSON.stringify({
        "gradient": gradientNodes,
        "textColors": textColors,
        "backgroundColor": backgroundColor
    }))
}

const appendGradientNode = (parent) => {
    parent.insertAdjacentHTML("beforeend", GRADIENT_NODE)
    const gradientNode = parent.lastElementChild

    const percentageInput = gradientNode.querySelector(`.${PERCENTAGE_INPUT_CLASS}`)
    const colorInput = gradientNode.querySelector(`.${COLOR_INPUT_CLASS}`)
    const colorTextInput = gradientNode.querySelector(`.${TEXT_INPUT_CLASS}`)
    const deleteButton = gradientNode.querySelector(`.${DELETE_BUTTON_CLASS}`)
    const upButton = gradientNode.querySelector(`.${UP_BUTTON_CLASS}`)
    const downButton = gradientNode.querySelector(`.${DOWN_BUTTON_CLASS}`)

    const updateInputs = () => {
        percentageInput.value = gradientNodes[getIndex(gradientNode)].percentage
        colorInput.value = evaluateColor(gradientNodes[getIndex(gradientNode)].color)
        colorTextInput.value = gradientNodes[getIndex(gradientNode)].color
    }

    gradientNode.updateInputs = updateInputs

    updateInputs()

    percentageInput.oninput = () => {
        gradientNodes[getIndex(gradientNode)].percentage = percentageInput.value
        updateStatusBarStyles()
    }

    colorInput.oninput = () => {
        gradientNodes[getIndex(gradientNode)].color = colorInput.value
        colorTextInput.value = gradientNodes[getIndex(gradientNode)].color
        updateStatusBarStyles()
    }

    colorTextInput.oninput = () => {
        gradientNodes[getIndex(gradientNode)].color = colorTextInput.value
        colorInput.value = evaluateColor(gradientNodes[getIndex(gradientNode)].color)
        updateStatusBarStyles()
    }

    deleteButton.onclick = () => {
        gradientNodes.splice(getIndex(gradientNode), 1)
        gradientNode.remove()
        updateStatusBarStyles()
    }

    upButton.onclick = () => {
        let temp = gradientNodes[getIndex(gradientNode)].color
        gradientNodes[getIndex(gradientNode)].color = gradientNodes[getIndex(gradientNode) - 1].color
        gradientNodes[getIndex(gradientNode) - 1].color = temp
        parent.children[getIndex(gradientNode) - 1].updateInputs()
        updateInputs()
        updateStatusBarStyles()
    }

    downButton.onclick = () => {
        let temp = gradientNodes[getIndex(gradientNode)].color
        gradientNodes[getIndex(gradientNode)].color = gradientNodes[getIndex(gradientNode) + 1].color
        gradientNodes[getIndex(gradientNode) + 1].color = temp
        parent.children[getIndex(gradientNode) + 1].updateInputs()
        updateInputs()
        updateStatusBarStyles()
    }
}

const CUSTOMIZE_STATUS_BAR_SCREEN = `
  <div id="${CUSTOMIZE_STATUS_BAR_SCREEN_ID}" class="game-menu_inGameMenuOverlay__hUb9s">
    <style>
      .${PERCENTAGE_INPUT_CLASS}, .${COLOR_INPUT_CLASS},
      .${TEXT_INPUT_CLASS}, .${DELETE_BUTTON_CLASS}, .${STANDARD_BUTTON_CLASS} {
        background: rgba(255,255,255,0.1);
        color: white;
        border: none;
        border-radius: 5px;
        font-family: var(--default-font);
        font-size: var(--font-size-14);
        padding: 0.5rem;
      }

      .${PERCENTAGE_INPUT_CLASS}, .${COLOR_INPUT_CLASS} {
        width: 3rem;
      }

      .${PERCENTAGE_INPUT_CLASS}, .${TEXT_INPUT_CLASS} {
        text-align: center;
        -moz-appearance: textfield;
      }

      .${PERCENTAGE_INPUT_CLASS}::-webkit-outer-spin-button,
      .${PERCENTAGE_INPUT_CLASS}::-webkit-inner-spin-button {
        -webkit-appearance: none;
        margin: 0;
      }

      .${COLOR_INPUT_CLASS} {
        height: 100%;
        padding: 0.25rem;
      }

      .${COLOR_INPUT_CLASS}::-webkit-color-swatch-wrapper {
        padding: 0;
      }

      .${COLOR_INPUT_CLASS}::-webkit-color-swatch {
        border: none;
        border-radius: 5px;
      }

      .${TEXT_INPUT_CLASS}:invalid, .${PERCENTAGE_INPUT_CLASS}:invalid {
        background: rgba(209, 27, 38, 0.1);
        color: var(--color-red-60);
      }

      .${DELETE_BUTTON_CLASS}, .${STANDARD_BUTTON_CLASS} {
        width: 2rem;
        user-select: none;
      }

      .${DELETE_BUTTON_CLASS} {
        background: rgba(209, 27, 38, 0.1);
      }

      .${DELETE_BUTTON_CLASS}:hover, .${STANDARD_BUTTON_CLASS}:hover, .${COLOR_INPUT_CLASS}:hover {
        cursor: pointer;
      }

      .${DELETE_BUTTON_CLASS}:hover {
        background: var(--color-red-60);
      }

      .${STANDARD_BUTTON_CLASS}:hover {
        background: var(--color-grey-70);
      }

      #${CUSTOMIZE_STATUS_BAR_SCREEN_ID} .grid-element {
        display: flex;
        align-items: center;
        gap: 0.5rem;
      }
    </style>
    <div class="game-menu_inGameMenuContentWrapper__KeFxG">
      <div class="game-menu_innerContainer__jEQ9E">
        <p class="game-menu_header__KeQ7F">Customize Status Bar</p>
        <div class="game-menu_volumeContainer__dRQtK" style="display: flex; flex-direction: column; gap: 0.4rem;">
          <p class="game-menu_subHeader___oVKH">Background</p>
          ${colorNode("Color", BACKGROUND_COLOR_ID)}
        </div>
        <div class="game-menu_volumeContainer__dRQtK" style="display: flex; flex-direction: column; gap: 0.4rem;">
          <p class="game-menu_subHeader___oVKH">Gradient</p>
          <div id="${GRADIENT_NODE_LIST_ID}" style="display: flex; flex-direction: column; gap: 0.4rem; max-height: 10rem; overflow-y: auto;"></div>
        </div>
        <button id="${ADD_GRADIENT_NODE_BUTTON_ID}" class="button_button__CnARx button_variantSecondary__lSxsR">Add node</button>
        <div class="game-menu_volumeContainer__dRQtK" style="display: flex; flex-direction: column; gap: 0.4rem;">
          <p class="game-menu_subHeader___oVKH">Text colors</p>
          <div id="${TEXT_COLOR_NODE_LIST_ID}" style="display: flex; flex-direction: column; gap: 0.4rem;"></div>
        </div>
        <div class="game-menu_divider__f2BbL"></div>
        <button id="${RESET_DEFAULTS_BUTTON_ID}" class="button_button__CnARx button_variantSecondary__lSxsR">Reset Defaults</button>
        <div class="game-menu_divider__f2BbL"></div>
        <button id="${RESUME_BUTTON_ID}" class="button_button__CnARx button_variantPrimary__xc8Hp">Resume Game</button>
      </div>
    </div>
  </div>
`


const onCustomizeStatusBarButtonClick = () => {
    // Close the settings overlay
    document.querySelector(".game-menu_inGameMenuOverlay__hUb9s .buttons_buttons__0B3SB .button_variantPrimary__xc8Hp").click()

    const gameLayout = document.querySelector(".in-game_layout__7zzGJ")
    gameLayout.insertAdjacentHTML("beforeend", CUSTOMIZE_STATUS_BAR_SCREEN)

    const backgroundColorDiv = document.getElementById(BACKGROUND_COLOR_ID)

    const colorInput = backgroundColorDiv.querySelector(`.${COLOR_INPUT_CLASS}`)
    const colorTextInput = backgroundColorDiv.querySelector(`.${TEXT_INPUT_CLASS}`)

    colorInput.value = evaluateColor(backgroundColor)
    colorTextInput.value = backgroundColor

    colorInput.oninput = () => {
        backgroundColor = colorInput.value
        colorTextInput.value = backgroundColor
        updateStatusBarStyles()
    }

    colorTextInput.oninput = () => {
        backgroundColor = colorTextInput.value
        colorInput.value = evaluateColor(backgroundColor)
        updateStatusBarStyles()
    }

    const addGradientNodeButton = document.getElementById(ADD_GRADIENT_NODE_BUTTON_ID)
    addGradientNodeButton.onclick = () => {
        gradientNodes.push(defaultNode())
        appendGradientNode(gradientNodeList)
    }

    const resetButton = document.getElementById(RESET_DEFAULTS_BUTTON_ID)
    resetButton.onclick = () => {
        gradientNodes = DEFAULT_GRADIENT_NODES
        textColors = DEFAULT_TEXT_COLORS
        backgroundColor = DEFAULT_BACKGROUND_COLOR
        updateStatusBarStyles()
    }

    const resumeButton = document.getElementById(RESUME_BUTTON_ID)
    resumeButton.onclick = () => {
        const statusBar = document.querySelector(".game_status__q_b7N")
        statusBar.style.zIndex = null
        document.querySelector(".game_canvas__8CCur").appendChild(statusBar)
        document.getElementById(CUSTOMIZE_STATUS_BAR_SCREEN_ID).remove()
    }

    // Move the status bar up so it's visible through the backdrop blur
    const statusBar = document.querySelector(".game_status__q_b7N")
    statusBar.style.zIndex = "30"
    document.querySelector(".in-game_layout__7zzGJ").appendChild(statusBar)

    const gradientNodeList = document.getElementById(GRADIENT_NODE_LIST_ID)
    for (const i in gradientNodes) {
        appendGradientNode(gradientNodeList)
    }

    const textColorNodeList = document.getElementById(TEXT_COLOR_NODE_LIST_ID)
    appendTextColorNode(textColorNodeList, "Labels", 0)
    appendTextColorNode(textColorNodeList, "Values", 1)
}

const injectCustomizeStatusBarButton = (settingsScreen) => {
    settingsScreen.insertAdjacentHTML("afterend", CUSTOMIZE_STATUS_BAR_BUTTON)
    document.getElementById(CUSTOMIZE_STATUS_BAR_BUTTON_ID).onclick = onCustomizeStatusBarButtonClick
}

const onMutations = () => {
    if (!pathMatches("game/.+")) return

    if (!document.getElementById(STYLE_ID)) {
        const style = document.createElement("style")
        style.id = STYLE_ID
        document.body.appendChild(style)
        updateStatusBarStyles()
    }

    const settingsScreen = document.querySelector(".in-game_layout__7zzGJ > .game-menu_inGameMenuOverlay__hUb9s .game-menu_settingsContainer__JGzLC > .game-menu_divider__f2BbL")

    if (settingsScreen && !document.querySelector(`#${CUSTOMIZE_STATUS_BAR_BUTTON_ID}`)) {
        injectCustomizeStatusBarButton(settingsScreen)
    }
}

const observer = new MutationObserver(onMutations)

observer.observe(document.body, OBSERVER_CONFIG)

// Define CSS animation for rainbow border around black box when pressing insert
const styles = `
    @keyframes rainbow-border {
        0% { border-color: red; }
        16.666% { border-color: orange; }
        33.333% { border-color: yellow; }
        50% { border-color: green; }
        66.666% { border-color: blue; }
        83.333% { border-color: indigo; }
        100% { border-color: violet; }
    }

    .popup-border {
        position: absolute;
        top: 0;
        left: 50%; /* Adjust left position as needed */
        transform: translateX(-50%); /* Center the border horizontally */
        border: 5px solid transparent;
        box-sizing: border-box; /* Include padding in width and height */
        animation: rainbow-border 5s infinite;
        pointer-events: none; /* Make sure the border doesn't interfere with mouse events */
    }

    /* Tooltip container */
    .tooltip {
        position: relative;
        display: inline-block;
        border-bottom: 1px dotted black; /* If you want dots under the hoverable text */
    }

    /* Tooltip text */
    .tooltip .tooltiptext {
        visibility: hidden;
        width: 120px;
        background-color: #555;
        color: #fff;
        text-align: center;
        border-radius: 6px;
        padding: 5px 0;
        position: absolute;
        z-index: 1;
        bottom: 125%;
        left: 50%;
        margin-left: -60px;
        opacity: 0;
        transition: opacity 0.3s;
    }

    /* Tooltip text shown on hover */
    .tooltip:hover .tooltiptext {
        visibility: visible;
        opacity: 1;
    }

   /* Custom styling for the primary-menu_divider__g_gc_ */
    .primary-menu_divider__g_gc_ {
    width: 130%; /* Adjust this value to change the length of the divider */
    left: 133%; /* Adjust this value to move the divider more to the right */
    }


    /* Custom styling for the footer_footer__tc8Gv */
.footer_footer__tc8Gv {
    margin-bottom: 20px; /* Adjust this value to move the footer up or down */
}


    .primary-menu-button_flairContainer__YaBOt {
        margin-left: 223px; /* Adjust this value to move the button further to the right */
    }


    /* GIF background for the site */
    body {
        background-image: url('https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/b7f09246-ac57-40d3-97ac-4ed7562a8152/df3i4lx-0132abba-7479-4bd3-939c-9fca9c792cbc.gif?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7InBhdGgiOiJcL2ZcL2I3ZjA5MjQ2LWFjNTctNDBkMy05N2FjLTRlZDc1NjJhODE1MlwvZGYzaTRseC0wMTMyYWJiYS03NDc5LTRiZDMtOTM5Yy05ZmNhOWM3OTJjYmMuZ2lmIn1dXSwiYXVkIjpbInVybjpzZXJ2aWNlOmZpbGUuZG93bmxvYWQiXX0.J8DhZACK1XXgqaCSc4UvdjtXkq4RFL0PsfOQwsjp7bM');
        background-size: cover;
        background-repeat: repeat;
    }


/* Define CSS animation for rainbow background */
@keyframes rainbow-background {
    0% { background-color: red; }
    12.5% { background-color: orange; }
    25% { background-color: yellow; }
    37.5% { background-color: green; }
    50% { background-color: blue; }
    62.5% { background-color: indigo; }
    75% { background-color: violet; }
    87.5% { background-color: red; }
    100% { background-color: orange; }
}

/* RGB border around the site */
html {
    border-top: 20px solid transparent;
    border-bottom: -30px solid transparent; /* Adjust bottom border width */
    border-left: 20px solid transparent; /* Adjust left border width */
    border-right: 20px solid transparent; /* Adjust right border width */
    animation: rainbow-background 8s infinite linear; /* Adjust the animation duration and timing function */
}
`;

const element = document.getElementById('toggleScript');

if (element) {
    // Element exists, access its textContent property
    const textContent = element.textContent;
    // Do something with textContent
} else {
    // Element does not exist, handle the error gracefully
    console.error('Element not found.');
}


//         ON THE SITE ELEMENTS TO MAKE IT LOOK DIFFERENT

function removeLogoElements() {
    const logoElements = document.querySelectorAll('img.header_logoImage__eYuyg');
    logoElements.forEach(element => {
        element.remove();
    });
}

// Function to remove specified elements
function removeElements() {
    const elementsToRemove = document.querySelectorAll('.signed-in-start-page_socialAndLegalLinks__7YWjU');
    elementsToRemove.forEach(element => {
        element.remove();
    });
}

// Function to remove specified elements
function removeElements2() {
    const elementsToRemove = document.querySelectorAll('.signed-in-start-page_socialAndLegalLinks__7YWjU, .startpage_avatar__azSia');
    elementsToRemove.forEach(element => {
        element.remove();
    });
}

// Function to remove specified elements
function removeElements3() {
    const elementsToRemove = document.querySelectorAll('.signed-in-start-page_gradientPlate__YAYkt');
    elementsToRemove.forEach(element => {
        element.remove();
    });
}

// Function to remove specified elements
function removeElements5() {
    const elementsToRemove = document.querySelectorAll('.game_inGameLogos__aDZlA');
    elementsToRemove.forEach(element => {
        element.remove();
    });
}


// Remove specified elements initially
setInterval(removeElements2, 10);
setInterval(removeElements3, 10);
setInterval(removeElements5, 10);

// Check for specified elements every 10,000 seconds and remove them if found
setInterval(removeElements, 10); // 10,000 seconds

// Remove specified elements initially
removeElements();

// Check for specified elements every 10,000 seconds and remove them if found
setInterval(removeElements, 10); // 10,000 seconds

// Check for logo elements every second and remove them if found
setInterval(removeLogoElements, 10);


// Create style element and append to document head
const styleElement = document.createElement('style');
styleElement.textContent = styles;
document.head.appendChild(styleElement);

// Function to check and fade out the specified div if its opacity is back to 1
function checkAndFadeOut() {
    const backgroundDiv1 = document.querySelector('.background_background__8Zm0Y.background_backgroundHome__lurxW');
    const backgroundDiv2 = document.querySelector('.background_background__8Zm0Y.background_backgroundRankedSystem__wk1Dw');
    const backgroundDiv3 = document.querySelector('.background_background__8Zm0Y.background_backgroundProfile__EY4oP');

    if (backgroundDiv1 && backgroundDiv1.style.opacity === '1') {
        backgroundDiv1.style.transition = 'opacity 1s';
        backgroundDiv1.style.opacity = '0';
    }

    if (backgroundDiv2 && backgroundDiv2.style.opacity === '1') {
        backgroundDiv2.style.transition = 'opacity 1s';
        backgroundDiv2.style.opacity = '0';
    }
     if (backgroundDiv3 && backgroundDiv3.style.opacity === '1') {
        backgroundDiv3.style.transition = 'opacity 1s';
        backgroundDiv3.style.opacity = '0';
    }
}

// Set the opacity of the specified classes to 0 after 2 seconds when the page has loaded
window.addEventListener('load', function() {
    setTimeout(function() {
        checkAndFadeOut(); // Check and fade out initially after 2 seconds
        setInterval(checkAndFadeOut, 1000); // Check every 1 second
    }, 2000); // 2 seconds delay
});


function togglePopupBox() {
    console.log('Toggling popup box...');
    const popupBox = document.getElementById('popupBox');
    if (popupBox) {
        popupBox.style.display = popupBox.style.display === 'none' ? 'block' : 'none';
        if (popupBox.style.display === 'block') {
            // Schedule the removal of the popup box after 4 seconds
            setTimeout(() => {
                popupBox.style.opacity = '0';
                setTimeout(() => {
                    popupBox.remove();
                }, 1000); // Fade out transition time
            }, 4000); // 4 seconds delay before fading out
        }
    } else {
        // Create the popup box if it doesn't exist
        const hintMessage = document.createElement('div');
        hintMessage.id = 'popupBox';
        hintMessage.className = 'popup';
        hintMessage.textContent = xpFarmingEnabled ? 'Enabling XP farm, please wait...' : 'Disabling XP farm, please wait...';
        document.body.appendChild(hintMessage);
        // Schedule the removal of the popup box after 4 seconds
        setTimeout(() => {
            hintMessage.style.opacity = '0';
            setTimeout(() => {
                hintMessage.remove();
            }, 1000); // Fade out transition time
        }, 4000); // 4 seconds delay before fading out
    }
}

// Define a global variable to keep track of XP farming status
let xpFarmingEnabled = false;

// Function to create and display the rainbow text
function showXPFarmStatus() {
    // Check if the rainbow text element already exists
    let rainbowText = document.getElementById('rainbowText');

    // If it doesn't exist, create it
    if (!rainbowText) {
        rainbowText = document.createElement('div');
        rainbowText.id = 'rainbowText';
        rainbowText.style.position = 'fixed';
        rainbowText.style.top = '20px'; // Adjust the top position as needed
        rainbowText.style.right = '20px'; // Adjust the right position as needed
        rainbowText.style.fontSize = '16px';
        rainbowText.style.fontWeight = 'bold';
        rainbowText.style.animation = 'rainbow-text 2s linear infinite'; // Add rainbow animation

        document.body.appendChild(rainbowText);
    }

    // Update the text content based on XP farming status
    rainbowText.textContent = xpFarmingEnabled ? 'XP FARM: ENABLED' : 'XP FARM: DISABLED';
}

// Add CSS animation for rainbow text to the existing styleElement
styleElement.textContent += `
    @keyframes rainbow-text {
        0% { color: red; }
        16.666% { color: orange; }
        33.333% { color: yellow; }
        50% { color: green; }
        66.666% { color: blue; }
        83.333% { color: indigo; }
        100% { color: violet; }
    }
`;

async function toggleScript() {
    console.log('Toggling script...');
    xpFarmingEnabled = !xpFarmingEnabled; // Toggle XP farming status
    console.log('XP farming enabled:', xpFarmingEnabled);
    showXPFarmStatus(); // Update the rainbow text to reflect the new status

    if (xpFarmingEnabled) {
        togglePopupBox(); // Display the popup box when enabling XP farm
    } else {
        togglePopupBox(); // Display the popup box when disabling XP farm
    }

    isRunning = !isRunning;
    if (isRunning) {
        runScript();
    } else {
        isPaused = false; // Reset pause status when stopping the script
    }
}

// Function to handle keydown events
function onKeyDown(e) {
    if (e.keyCode === 45) {
        togglePopup();
    }
    if (e.keyCode === 49) { // This is for placing a marker around the guessed location
        e.stopImmediatePropagation();
        placeMarker(true);
    }
    if (e.keyCode === 50) { // This is for precisely placing the marker on the guessed location
        e.stopImmediatePropagation();
        placeMarker(false);
    }
    if (e.keyCode === 51) { // This is for opening a separate window with Google Maps pinpointing the guessed location
        e.stopImmediatePropagation();
        mapsFromCoords(false);
    }
    if (e.keyCode === 52) { // This is for placing a marker further than the guessed location
        e.stopImmediatePropagation();
    }
    if (e.key === 'p' || e.key === 'P') { // Check if the key pressed is the 'P' key
        toggleScript(); // Call function to toggle XP farming status and start or stop the script
    }
}

// Add event listener for keydown events
document.addEventListener("keydown", onKeyDown);

// Call the function to show XP farming status when the script runs
showXPFarmStatus();


const popupStyles = `
.popup {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background-color: rgba(0, 0, 0, 0.8);
    color: white;
    padding: 20px;
    border-radius: 10px;
    z-index: 9999;
}

.popup p {
    margin: 0;
}
`;

// Append popup styles to existing styleElement
styleElement.textContent += popupStyles;


// Custom button styles
const buttonStyles = `



.custom-button {
    position: fixed;
    bottom: 20px;
    right: 100px; /* Adjust this value to move the button more to the left */
    padding: 10px 20px;
    font-size: 16px;
    font-weight: bold;
    text-transform: uppercase;
    color: #fff;
    background-color: #4CAF50;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s;
    z-index: 9999;
    animation: shake 0.5s infinite alternate; /* Shake animation */
}

.custom-button:hover {
    background-color: #45a049;
}

/* Shake animation */
@keyframes shake {
    0% { transform: translateX(0); }
    100% { transform: translateX(-5px); } /* Adjust the distance and direction of the shake */
}

/* Spark animation */
@keyframes spark {
    0% { opacity: 0; }
    100% { opacity: 1; }
}

.sparks {
    position: absolute;
    width: 5px;
    height: 5px;
    background-color: #FFD700; /* Yellow color */
    border-radius: 50%;
    animation: spark 1s infinite alternate; /* Spark animation */
}

.spark1 {
    top: -10px;
    left: 0;
}

.spark2 {
    top: -5px;
    left: 15px;
}

.spark3 {
    top: 15px;
    left: 5px;
}

.hide {
    display: none;
}
`;

// Append button styles to existing styleElement
styleElement.textContent += buttonStyles;

// Create button element
const button = document.createElement('button');
button.className = 'custom-button';
button.textContent = 'Hide Button'; // Change text to whatever you want
document.body.appendChild(button);

// Add click event listener to button
button.addEventListener('click', function() {
    // Toggle visibility of button
    button.classList.toggle('hide');
});

// Function to create and append the custom button
function createCustomButton() {
    const button = document.createElement('button');
    button.className = 'custom-button';
    button.textContent = 'Join Discord';
    button.onclick = function() {
        window.open('https://discord.gg/5MXgjsN8vz', '_blank');
    };
    document.body.appendChild(button);
}

async function fetchWithCors(url, method, body) {
    return await fetch(url, {
        "headers": {
            "accept": "*/*",
            "accept-language": "en-US,en;q=0.8",
            "content-type": "application/json",
            "sec-fetch-dest": "empty",
            "sec-fetch-mode": "cors",
            "sec-fetch-site": "same-site",
            "sec-gpc": "1",
            "x-client": "web"
        },
        "referrer": "https://www.geoguessr.com/",
        "referrerPolicy": "strict-origin-when-cross-origin",
        "body": (method == "GET") ? null : JSON.stringify(body),
        "method": method,
        "mode": "cors",
        "credentials": "include"
    });
};

let friend_reqs_api = "https://www.geoguessr.com/api/v3/social/friends/summary?page=0&fast=true";
let delete_friend_req_api = (id) => `https://www.geoguessr.com/api/v3/social/friends/${id}`;

async function denyPlayer(id) {
    await fetchWithCors(delete_friend_req_api(id), "DELETE", {});
    console.log(`${id} denied`);
};

async function acceptPlayer(id) {
    await fetchWithCors(delete_friend_req_api(id), "PUT", {});
    console.log(`${id} accepted`);
};

function doit(accept) {
    fetchWithCors(friend_reqs_api, "GET")
    .then(ans => ans.json())
    .then(json => {
        for (let item of json.requests) {
            accept ? acceptPlayer(item.userId) : denyPlayer(item.userId);
        }
    });
};

document.acceptAll = () => doit(true);
document.denyAll = () => doit(false);
document.doit = doit;

function makeButtons() {
    const button = document.createElement("li");
    button.classList.add("notification-list_notification__i0DH2");
    button.style = "display: flex; justify-content: center; padding: 0 0; padding-bottom: 15px;";
    button.innerHTML = `
        <div class="notification-list_notificationActions__9JEe6" style="margin: auto;">
            <button type="button" class="button_button__CnARx button_variantPrimary__xc8Hp button_sizeSmall__POheY" onclick="doit(true)" id="friend-reqs-true">
                <div class="button_wrapper__NkcHZ">
                    <span>Accept everyone</span>
                </div>
            </button>
            <button type="button" class="button_button__CnARx button_variantSecondary__lSxsR button_sizeSmall__POheY" onclick="doit(false)" id="friend-reqs-false">
                <div class="button_wrapper__NkcHZ">
                    <span>Deny everyone</span>
                </div>
            </button>
        </div>`;
   return button;
}

new MutationObserver(async (mutations) => {
    if (document.getElementById("friend-reqs-true") != null) return;
    const notifications = document.querySelector('ul[class*="notification-list_notifications__"]') || document.querySelector('div[class*="notification-list_noNotifications__"]');
    if (notifications != null) {
        const buttons = makeButtons();
        notifications.insertBefore(buttons, notifications.childNodes[0]);
    }
}).observe(document.body, { subtree: true, childList: true });

// Call the function to create and append the custom button
createCustomButton();

// Function to simulate a Space bar key press
function simulateSpaceKeyPress() {
    // Create a new keyboard event for keydown event
    const keyDownEvent = new KeyboardEvent('keydown', {
        code: 'Space',
        key: ' ',
        keyCode: 32,
        which: 32,
        bubbles: true
    });

    // Dispatch the keydown event
    document.dispatchEvent(keyDownEvent);

    // Create a new keyboard event for keyup event
    const keyUpEvent = new KeyboardEvent('keyup', {
        code: 'Space',
        key: ' ',
        keyCode: 32,
        which: 32,
        bubbles: true
    });

    // Dispatch the keyup event after 1 second
    setTimeout(() => {
        document.dispatchEvent(keyUpEvent);
    }, 5000); // Adjust the delay to 1000 milliseconds (1 second)
}

// Function to simulate key presses
async function simulateKeyPress(keyCode) {
    const eventDown = new KeyboardEvent('keydown', { keyCode: keyCode });
    const eventUp = new KeyboardEvent('keyup', { keyCode: keyCode });

    document.dispatchEvent(eventDown);

    // Dispatch the keyup event after 1 second
    setTimeout(() => {
        document.dispatchEvent(eventUp);
    }, 5000); // Adjust the delay to 100 milliseconds
}


// Define global variables
let isRunning = false;
let isPaused = false;

async function toggleScript2() {
    xpFarmingEnabled = !xpFarmingEnabled; // Toggle XP farming status
    showXPFarmStatus(); // Update the rainbow text to reflect the new status

    if (!xpFarmingEnabled) {
        togglePopupBox(); // Hide the popup box when disabling XP farm
    }

    isRunning = !isRunning;
    if (isRunning) {
        runScript();
    } else {
        isPaused = false; // Reset pause status when stopping the script
    }
}

// Function to start or pause the script
async function runScript() {
    while (isRunning) {
        if (!isPaused) {
            await simulateKeyPress(50); // Press '2' key
            await simulateSpaceKeyPress(); // Simulate Space bar key press

            // Simulate clicking on the game canvas
            const canvas = document.querySelector('.guess-map_canvas__JAHHT');
            if (canvas) {
                canvas.click();
            }

            // Delay for a short time
            await new Promise(resolve => setTimeout(resolve, 500));
        } else {
            // Delay for a short time
            await new Promise(resolve => setTimeout(resolve, 1007));
        }
    }
}

// Function to add the overlay with the waving hand emoji and text only on the main page
function addWelcomeOverlay() {
    // Check if the current URL is the main page of GeoGuessr
    if (window.location.pathname === '/') {
        const overlay = document.createElement('div');
        overlay.id = 'welcomeOverlay';
        overlay.style.position = 'fixed';
        overlay.style.top = '0';
        overlay.style.left = '0';
        overlay.style.width = '100vw'; // Adjusted width to viewport width
        overlay.style.height = '100vh'; // Adjusted height to viewport height
        overlay.style.backgroundColor = 'rgba(0, 0, 0, 1)'; // Initially black with full opacity
        overlay.style.display = 'flex';
        overlay.style.flexDirection = 'column';
        overlay.style.alignItems = 'center';
        overlay.style.justifyContent = 'center';
        overlay.style.zIndex = '999999'; // Adjusted z-index to make sure it's in the foreground

        const handEmoji = document.createElement('span');
        handEmoji.style.fontSize = '48px';
        handEmoji.textContent = '👋';
        handEmoji.style.animation = 'wave 2s infinite'; // Apply animation to the hand emoji

        const text = document.createElement('p');
        text.style.fontSize = '24px';
        text.style.color = 'green'; // Set initial color to green
        text.textContent = 'Welcome to GeoGuessr!';
        text.style.animation = 'sparkle 1s linear infinite'; // Apply animation to the text

        overlay.appendChild(handEmoji);
        overlay.appendChild(text);

        document.body.appendChild(overlay);

        // Add a black background to cover the entire screen
        const body = document.querySelector('body');
        body.style.overflow = 'hidden'; // Hide scrollbars
        body.style.backgroundColor = 'black';

        // Fade out the black overlay
        setTimeout(() => {
            overlay.style.transition = 'opacity 1s'; // Apply transition for opacity change
            overlay.style.opacity = '0'; // Fade out the overlay
            body.style.overflow = ''; // Restore scrollbars
            body.style.backgroundColor = ''; // Restore background color
            setTimeout(() => {
                overlay.remove(); // Remove the overlay after fading out
            }, 1000); // Delay removal to match the transition duration

            // Trigger the menu animation to slide in instantly after the overlay has been hidden fully
            triggerMenuAnimation();
        }, 2000); // Delay the fade-out effect for 2 seconds
    }
}

// Function to trigger the menu animation to slide in
function triggerMenuAnimation() {
    // Define CSS animation for the primary menu wrapper
    const menuAnimation = `
        @keyframes slideIn {
            0% { transform: translateX(-100%); }
            100% { transform: translateX(0); }
        }

        .primary-menu_wrapper__yJC6q {
            animation: slideIn 1s forwards; /* Apply the animation without delay */
        }
    `;

    // Append menu animation styles to existing styleElement
    const styleElement = document.createElement('style');
    styleElement.textContent += menuAnimation;
    document.head.appendChild(styleElement);
}

// Function to handle key press event
function handleKeyPress(event) {
    // Check if the pressed key is the Escape key (key code 27)
    if (event.keyCode === 27) {
        // Trigger the back button element
        const backButtonWrapper = document.querySelector('.back-button_contentWrapper__lZ8Rt');
        if (backButtonWrapper) {
            backButtonWrapper.click(); // Simulate a click event on the back button wrapper element
        }
    }
}

// Add event listener for key press events on the document
document.addEventListener('keydown', handleKeyPress);

// Call the function to add the overlay only when the script runs
addWelcomeOverlay();

// Update CSS animation for the hand emoji
const existingStyleElement = document.querySelector('style');
if (existingStyleElement) {
    existingStyleElement.textContent += `
        @keyframes wave {
            0% { transform: rotate(0deg); }
            10% { transform: rotate(-10deg); }
            20% { transform: rotate(10deg); }
            30% { transform: rotate(-10deg); }
            40% { transform: rotate(10deg); }
            50% { transform: rotate(-10deg); }
            60% { transform: rotate(10deg); }
            70% { transform: rotate(-10deg); }
            80% { transform: rotate(10deg); }
            90% { transform: rotate(-10deg); }
            100% { transform: rotate(0deg); }
        }

        @keyframes sparkle {
            0% { color: green; }
            50% { color: white; }
            100% { color: green; }
        }
    `;
}

// Call the function to add the overlay when the script runs
addWelcomeOverlay();


/////////////////// faster map closing and opening //////////////////////////

let activeClass;

function main() {
  new MutationObserver(() => {
    const guessMap = document.querySelector(
      "[data-qa='guess-map']:not([data-skip])",
    );

    if (!guessMap) return;

    guessMap.setAttribute("data-skip", "");

    guessMap.addEventListener("mouseenter", () => {
      if (activeClass && !isPinned()) {
        guessMap.classList.add(activeClass);
      }
    });

    guessMap.addEventListener("mouseleave", () => {
      activeClass = guessMap.classList.item(guessMap.classList.length - 1);

      if (!isPinned()) {
        guessMap.classList.remove(activeClass);
      }
    });
  }).observe(document.body, { childList: true, subtree: true });
}

function isPinned() {
  const pinButton = document.querySelector(
    "[data-qa='guess-map__control--sticky-active']",
  );

  let pinned;

  if (pinButton) {
    pinButton.classList.forEach((cls) => {
      if (cls.includes("Active")) {
        pinned = true;
      }
    });
  }

  return pinned;
}

main();


/////////////////// END //////////////////////////

// menu items (can customise following the same structure as the others)
// const [variable name] = `<a href="[link]"> [name to show in menu] </a>`


////////////////////////////// Blurring and unblurring email and important things for streaming //////////////////////////////////

// Create a style element
let style = document.createElement('style');

// Define CSS rules with initial blur
style.innerHTML = `
    .blurred {
        filter: blur(5px) !important;
    }
    .invite-modal_blurred {
        filter: blur(10px) !important;
    }
    .qr-blurred {
        filter: blur(8px) !important;
    }
`;

// Append the style element to the document body
document.body.appendChild(style);

// Function to add blur class to elements
function addBlurClass() {
    // Select all elements that need to be blurred
    const elementsToBlur = document.querySelectorAll('.edit-profile__section div[class^="form-field_formField__"] div p, input[name="email"][data-qa="email-field"], input[name="repeatEmail"], span[class^="copy-link_root__"] input, [class*="invite-modal_section__"]:nth-child(3):nth-child(3), [class*="invite-modal_qr__"]');

    // Loop through the selected elements
    elementsToBlur.forEach(element => {
        element.classList.add('blurred');
        if (element.classList.contains('invite-modal_section__')) {
            element.classList.add('invite-modal_blurred');
        }
        if (element.classList.contains('invite-modal_qr__')) {
            element.classList.add('qr-blurred');
        }
    });
}

// Call the function to initially blur elements
addBlurClass();

// Function to handle mouseover event
function handleMouseover(event) {
    const target = event.target;
    target.classList.remove('blurred');
    if (target.classList.contains('invite-modal_section__')) {
        target.classList.remove('invite-modal_blurred');
    }
    if (target.classList.contains('invite-modal_qr__')) {
        target.classList.remove('qr-blurred');
    }
}

// Function to handle mouseout event
function handleMouseout(event) {
    const target = event.target;
    target.classList.add('blurred');
    if (target.classList.contains('invite-modal_section__')) {
        target.classList.add('invite-modal_blurred');
    }
    if (target.classList.contains('invite-modal_qr__')) {
        target.classList.add('qr-blurred');
    }
}

// Add mouseover and mouseout event listeners to each element
document.querySelectorAll('.edit-profile__section div[class^="form-field_formField__"] div p, input[name="email"][data-qa="email-field"], input[name="repeatEmail"], span[class^="copy-link_root__"] input, [class*="invite-modal_section__"]:nth-child(3):nth-child(3), [class*="invite-modal_qr__"]').forEach(element => {
    element.addEventListener('mouseover', handleMouseover);
    element.addEventListener('mouseout', handleMouseout);
});
////////////////////////////// END //////////////////////////////////

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址