Balance Changer

Скрытно меняет баланс на форуме.

// ==UserScript==
// @name         Balance Changer
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  Скрытно меняет баланс на форуме.
// @author       eretly
// @match        https://lzt.market/*
// @match        https://lolz.live/*
// @license      MIT
// @run-at       document-start
// @grant        none
// ==/UserScript==

;(() => {
    const amountToAdd = 2439.32
    let pageReady = false

    function hideMainContent() {
        const style = document.createElement("style")
        style.id = "balance-changer-style"
        style.textContent = `
            body > *:not(header):not(.header):not(#header):not(footer):not(.footer):not(#footer):not(script):not(style) {
                visibility: hidden !important;
                opacity: 0 !important;
                transition: none !important;
            }
            header, footer, .header, .footer,
            #header, #footer, .navigation, .nav,
            header *, footer *, .header *, .footer *,
            #header *, #footer * {
                visibility: visible !important;
                opacity: 1 !important;
            }
        `
        document.head.appendChild(style)
    }

    function showMainContent() {
        const style = document.getElementById("balance-changer-style")
        if (style) {
            style.remove()
        }
        pageReady = true
    }

    function formatNumber(num) {
        let formattedNum = num.toLocaleString('ru-RU', { minimumFractionDigits: 2 });

        if (formattedNum.endsWith(',00')) {
            formattedNum = formattedNum.slice(0, -3);
        }

        return formattedNum;
    }


    function formatContestPrize(num) {
        const integerOnly = Number.parseInt(num.toString().split(/[,.]/)[0])
        return integerOnly.toLocaleString("ru-RU")
    }

    function modifyMarketBalance() {
        const newBalanceElement = document.querySelector(".user-balance-block .balance-title")

        if (newBalanceElement && !newBalanceElement.dataset.modified) {
            try {
                const currentBalance =
                      Number.parseFloat(newBalanceElement.textContent.replace(/[^\d,.-]/g, "").replace(",", ".")) || 0
                const newBalance = currentBalance + amountToAdd
                const formattedBalance = formatNumber(newBalance)

                newBalanceElement.textContent = formattedBalance
                newBalanceElement.dataset.modified = "true"
            } catch (e) {
                console.error("Error modifying new balance element:", e)
            }
        }
    }

    function modifyBalance(element) {
        if (!element || element.dataset.modified) return

        if (element.classList.contains("muted")) return

        try {
            const currentBalance = Number.parseFloat(element.textContent.replace(/\s/g, "").replace(",", ".")) || 0
            const newBalance = currentBalance + amountToAdd
            element.textContent = formatNumber(newBalance)
            element.dataset.modified = "true"
        } catch (e) {
            console.error("Error", e)
        }
    }

    function modifyMethodBalance(element) {
        if (!element || element.dataset.modified) return;

        try {
            const text = element.textContent.trim();
            const balanceMatch = text.match(/\(([\d\s,.-]+)\s*₽\)/);

            if (balanceMatch) {
                let currentBalance = parseFloat(balanceMatch[1].replace(/\s/g, '').replace(',', '.')) || 0;
                let newBalance = currentBalance + amountToAdd;
                let formattedBalance = formatNumber(newBalance);

                const newText = text.replace(/\([\d\s,.-]+\s*₽\)/, `(${formattedBalance} ₽)`);
                element.textContent = newText;

                element.dataset.modified = "true";

            }
        } catch (e) {
            console.error("Error", e);
        }
    }

    function modifyContestBalance() {
        const contestBalanceElement = document.querySelector("#ContestPrizType--money .explain")
        if (contestBalanceElement && !contestBalanceElement.dataset.modified) {
            try {
                const text = contestBalanceElement.textContent.trim()
                const balanceMatch = text.match(/Доступный баланс\s*([\d\s,.-]+)\s*₽/)

                if (balanceMatch) {
                    const currentBalance = Number.parseFloat(balanceMatch[1].replace(/\s/g, "").replace(",", ".")) || 0
                    const newBalance = currentBalance + amountToAdd
                    const formattedBalance = formatNumber(newBalance)

                    const newText = text.replace(/Доступный баланс\s*[\d\s,.-]+\s*₽/, `Доступный баланс ${formattedBalance} ₽`)
                    contestBalanceElement.textContent = newText

                    contestBalanceElement.dataset.modified = "true"
                }
            } catch (e) {
                console.error("Error", e)
            }
        }
    }

    function modifyTransferAmount() {
        document.querySelectorAll(".bigTextHeading").forEach((element) => {
            if (!element.dataset.modified && element.textContent.includes("Сумма перевода (Доступно для перевода")) {
                try {
                    const match = element.textContent.match(/Доступно для перевода ([\d\s,.-]+)₽/)
                    if (match) {
                        const currentBalance = Number.parseFloat(match[1].replace(/\s/g, "").replace(",", ".")) || 0
                        const newBalance = currentBalance + amountToAdd
                        const formattedBalance = formatNumber(newBalance)

                        element.innerHTML = `Сумма перевода (Доступно для перевода ${formattedBalance} ₽)`
                        element.dataset.modified = "true"
                    }
                } catch (e) {
                    console.error("Ошибка при изменении суммы перевода:", e)
                }
            }
        })
    }

    function modifyLastTransferAmount() {
        const transferSpans = document.querySelectorAll(".Transfer[data-amount]")

        if (transferSpans.length > 0) {
            const lastTransfer = transferSpans[transferSpans.length - 1]

            if (!lastTransfer.dataset.modified) {
                try {
                    const currentAmount = Number.parseFloat(lastTransfer.dataset.amount.replace(/\s/g, "").replace(",", ".")) || 0
                    const newAmount = currentAmount + amountToAdd
                    const formattedAmount = formatNumber(newAmount)

                    lastTransfer.dataset.amount = formattedAmount
                    lastTransfer.querySelector("span:first-child").textContent = formattedAmount

                    lastTransfer.dataset.modified = "true"
                } catch (e) {
                    console.error("Ошибка при изменении суммы в <span class='Transfer'>:", e)
                }
            }
        }
    }

    function modifyPayoutBalance() {
        if (!window.location.href.includes("https://lzt.market/balance/payout")) return

        const payoutBalanceElement = document.querySelector(".explain .MarketAvailableBalance")
        if (payoutBalanceElement && !payoutBalanceElement.dataset.modified) {
            try {
                const currentBalance =
                      Number.parseFloat(payoutBalanceElement.textContent.replace(/[^\d,.-]/g, "").replace(",", ".")) || 0

                const newBalance = currentBalance + amountToAdd

                const formattedBalance = formatNumber(newBalance)

                payoutBalanceElement.textContent = formattedBalance + " ₽"

                payoutBalanceElement.dataset.modified = "true"
            } catch (e) {
                console.error("Error", e)
            }
        }
    }

    function updateUI() {
        const notEnoughMoneyElement = document.getElementById("NotEnoughMoney")
        const totalMoneyPrizeElement = document.getElementById("TotalMoneyPrizeData")
        const prizeInputElement = document.getElementById("prize_data_money")
        const contestBalanceElement = document.querySelector("#ContestPrizType--money .explain")

        if (!contestBalanceElement || !prizeInputElement || !totalMoneyPrizeElement || !notEnoughMoneyElement) return

        // Получаем измененный баланс
        const balanceMatch = contestBalanceElement.textContent.match(/Доступный баланс\s*([\d\s,.-]+)\s*₽/)
        if (!balanceMatch) return

        const availableBalance = Number.parseFloat(balanceMatch[1].replace(/\s/g, "").replace(",", ".")) || 0

        // Получаем введенную сумму
        const prizeAmount = Number.parseFloat(prizeInputElement.value.replace(/\s/g, "").replace(",", ".")) || 0

        if (prizeAmount === 0 || prizeInputElement.value.trim() === "") {
            // Если сумма равна 0 или поле пустое
            notEnoughMoneyElement.style.display = "none" // Скрываем красное сообщение
            totalMoneyPrizeElement.style.display = "none" // Скрываем блок списания
        } else if (prizeAmount <= availableBalance) {
            // Если сумма меньше или равна балансу
            notEnoughMoneyElement.style.display = "none" // Скрываем красное сообщение
            totalMoneyPrizeElement.style.display = "block" // Показываем блок списания

            // Обновляем сумму списания с удалением десятичной части и с пробелами между тысячами
            const valueElement = totalMoneyPrizeElement.querySelector(".Value")
            if (valueElement) {
                valueElement.textContent = formatContestPrize(prizeAmount)
            }
        } else {
            // Если сумма больше баланса
            notEnoughMoneyElement.style.display = "block" // Показываем красное сообщение
            totalMoneyPrizeElement.style.display = "none" // Скрываем блок списания
        }
    }

    function setupPrizeInputListener() {
        const prizeInputElement = document.getElementById("prize_data_money")
        if (prizeInputElement) {
            prizeInputElement.addEventListener("input", () => {
                setTimeout(updateUI, 100)
            })
        }
    }

    function applyChanges() {
        if (window.location.href.includes("lzt.market")) {
            document.querySelectorAll(".balanceValue, .Incomes").forEach(modifyBalance)
            modifyMarketBalance()
            document
                .querySelectorAll(".Method.method.full.balance.balance, .Method.method.full.balance.balance.selected")
                .forEach(modifyMethodBalance)
            modifyTransferAmount()
            modifyLastTransferAmount()
            modifyPayoutBalance()
        }

        if (window.location.href.includes("lolz.live")) {
            lolzLiveSpecificFix()
            modifyContestBalance()
            updateUI()
            setupPrizeInputListener()
        }
    }

    function startObserver() {
        if (!document.body) {
            setTimeout(startObserver, 100)
            return
        }

        const observer = new MutationObserver((mutationsList) => {
            for (const mutation of mutationsList) {
                if (mutation.type === "childList") {
                    mutation.addedNodes.forEach((node) => {
                        if (node.nodeType === Node.ELEMENT_NODE) {
                            const methodBalanceElements = node.querySelectorAll
                            ? node.querySelectorAll(
                                ".Method.method.full.balance.balance, .Method.method.full.balance.balance.selected",
                            )
                            : []
                            methodBalanceElements.forEach(modifyMethodBalance)

                            if (node.id === "ContestPrizType--money" || node.querySelector("#ContestPrizType--money")) {
                                modifyContestBalance()
                                updateUI()
                                setupPrizeInputListener()
                            }

                            if (window.location.href.includes("https://lzt.market/balance/payout")) {
                                modifyPayoutBalance()
                            }

                            modifyTransferAmount()
                            modifyLastTransferAmount()
                        }
                    })
                }
            }
        })

        observer.observe(document.body, { childList: true, subtree: true })
    }

    startObserver()

    hideMainContent()

    document.addEventListener("DOMContentLoaded", () => {
        setTimeout(() => {
            applyChanges()
            setTimeout(showMainContent, 150)
        }, 100)
    })

    window.addEventListener("load", () => {
        setTimeout(() => {
            applyChanges()
            if (!pageReady) {
                setTimeout(showMainContent, 150)
            }
        }, 200)
    })

    if (document.readyState !== "loading") {
        setTimeout(() => {
            applyChanges()
            setTimeout(showMainContent, 150)
        }, 100)
    }

    function lolzLiveSpecificFix() {
        const possibleSelectors = [
            "#AccountMenu .balanceValue",
            ".balanceRow .balanceValue",
            ".Menu.HeaderMenu .balanceValue",
            ".balanceValue",
        ]

        for (const selector of possibleSelectors) {
            const elements = document.querySelectorAll(selector)
            if (elements.length > 0) {
                elements.forEach(modifyBalance)
            }
        }
    }
})()