JS HTML Исходник FunPay Visual Empty Orders - визуальное скрытие покупок/продаж

discussion

Новичок
Автор темы
1
0
Автор: discussion
Связь: https://t.me/Netw0rk_Stresser
Тип: JavaScript / Tampermonkey
Сайт: FunPay
Версия: 2.0

Описание

FunPay Private Pages Cleaner - userscript для Tampermonkey (НАЕБАЛОВО.СОМ АДМИНОВ)

Скрипт приводит страницы к пустому виду:

— Мои покупки;
— Мои продажи;
— Сообщения;
— Финансы;
— бейджи возле Покупок, Продаж и Сообщений.

Скрипт ничего не удаляет на сервере FunPay.
Все заказы, переписки, операции, статусы и балансы остаются настоящими.
Это только локальная визуальная подмена в браузере.

После отключения скрипта или входа с другого браузера реальные данные снова будут видны.

Для чего может пригодиться

— запись экрана;
— стримы;
— демонстрация браузера;
— скриншоты;
(НАЕБАЛОВО.СОМ АДМИНОВ)

Что скрывает

— список покупок;
— список продаж;
— активные бейджи заказов;
— список диалогов;
— открытый чат;
— историю финансовых операций;
— реальные балансы;
— кнопку/таблицу операций;
— бейдж сообщений.

Что НЕ делает

— не удаляет заказы;
— не чистит переписки на сервере;
— не удаляет финансовые операции;
— не меняет баланс;
— не подтверждает сделки;
— не отправляет запросы на сервер;
— не перехватывает fetch/XHR;
— не является обходом правил площадки.

Установка

1. Установить Tampermonkey.
2. Создать новый userscript.
3. Полностью удалить стандартный шаблон.
4. Вставить код ниже.
5. Сохранить.
6. Открыть FunPay.

Важно: если у вас стояли старые версии этого скрипта - отключите или удалите их. Несколько версий одновременно могут конфликтовать.

Код

JavaScript:
// ==UserScript==
// @name         FunPay Private Pages Cleaner
// @namespace    fp.private.cleaner
// @version      2.0
// @description  Визуально очищает покупки, продажи, сообщения, финансы и бейджи на FunPay
// @author       discussion
// @match        https://funpay.com/*
// @match        https://*.funpay.com/*
// @run-at       document-start
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    const styleId = 'fp-private-cleaner-style';
    const cleanedAttr = 'data-fp-cleaned';
    const readyAttr = 'data-fp-ready';

    const pageClasses = [
        'fp-hide-orders',
        'fp-hide-chat',
        'fp-hide-finance'
    ];

    const orderTitles = new Set([
        'Мои покупки',
        'Мои продажи',
        'Мої покупки',
        'Мої продажі',
        'My purchases',
        'My sales',
        'Purchases',
        'Sales'
    ]);

    const chatTitles = new Set([
        'Сообщения',
        'Повідомлення',
        'Messages'
    ]);

    const financeTitles = [
        'Финансы',
        'Фінанси',
        'Finance',
        'Finances'
    ];

    function text(value) {
        return String(value || '').replace(/\s+/g, ' ').trim();
    }

    function safe(value) {
        return String(value)
            .replaceAll('&', '&')
            .replaceAll('<', '&lt;')
            .replaceAll('>', '&gt;')
            .replaceAll('"', '&quot;')
            .replaceAll("'", '&#039;');
    }

    function route(url = location.href) {
        try {
            const parsed = new URL(url, location.origin);
            const path = parsed.pathname.replace(/\/+$/, '');

            if (path === '/orders' || path === '/orders/trade') return 'orders';
            if (path === '/chat') return 'chat';
            if (path === '/account/balance') return 'finance';
        } catch {}

        return '';
    }

    function clearRouteClasses() {
        document.documentElement.classList.remove(...pageClasses);
    }

    function lockPage(type = route()) {
        clearRouteClasses();

        if (type === 'orders') document.documentElement.classList.add('fp-hide-orders');
        if (type === 'chat') document.documentElement.classList.add('fp-hide-chat');
        if (type === 'finance') document.documentElement.classList.add('fp-hide-finance');
    }

    function unlockPage(type) {
        if (type === 'orders') document.documentElement.classList.remove('fp-hide-orders');
        if (type === 'chat') document.documentElement.classList.remove('fp-hide-chat');
        if (type === 'finance') document.documentElement.classList.remove('fp-hide-finance');
    }

    function addStyle() {
        if (document.getElementById(styleId)) return;

        const style = document.createElement('style');
        style.id = styleId;

        style.textContent = `
            html.fp-hide-orders .page-content-full:not([${readyAttr}="1"]),
            html.fp-hide-finance .page-content-full:not([${readyAttr}="1"]) {
                visibility: hidden !important;
                opacity: 0 !important;
            }

            html.fp-hide-chat .chat-full-container:not([${readyAttr}="1"]),
            html.fp-hide-chat .chat-full:not([${readyAttr}="1"]) {
                visibility: hidden !important;
                opacity: 0 !important;
            }

            .page-content-full form.orders-filter,
            .page-content-full .orders-filter,
            .page-content-full .orders-table,
            .page-content-full .dyn-table.orders-table,
            .page-content-full .tc.tc-finance.table-hover.table-clickable.dyn-table.orders-table {
                display: none !important;
                visibility: hidden !important;
                opacity: 0 !important;
                pointer-events: none !important;
            }

            .chat-full:not([${cleanedAttr}="chat"]) .contact-item,
            .chat-full:not([${cleanedAttr}="chat"]) .chat-message-list,
            .chat-full:not([${cleanedAttr}="chat"]) .chat-detail,
            .chat-full:not([${cleanedAttr}="chat"]) .chat-float:not(.chat-not-selected) {
                display: none !important;
                visibility: hidden !important;
                opacity: 0 !important;
                pointer-events: none !important;
            }

            .page-content-full:not([${cleanedAttr}="finance"]) .finance-controls,
            .page-content-full:not([${cleanedAttr}="finance"]) .transactions,
            .page-content-full:not([${cleanedAttr}="finance"]) .dyn-table-form,
            .page-content-full:not([${cleanedAttr}="finance"]) .dyn-table-continue,
            .page-content-full:not([${cleanedAttr}="finance"]) .tc-item,
            .page-content-full:not([${cleanedAttr}="finance"]) .modal-transaction {
                display: none !important;
                visibility: hidden !important;
                opacity: 0 !important;
                pointer-events: none !important;
            }

            .menu-item-orders .badge-orders,
            .menu-item-trade .badge-trade,
            .menu-item-chat .badge-chat,
            .badge.badge-orders,
            .badge.badge-trade,
            .badge.badge-chat {
                display: none !important;
                visibility: hidden !important;
                opacity: 0 !important;
                pointer-events: none !important;
            }
        `;

        (document.head || document.documentElement).appendChild(style);
    }

    function emptyLabel(title) {
        const lower = title.toLowerCase();

        if (
            lower.includes('мої') ||
            lower.includes('фінанси') ||
            lower.includes('повідомлення')
        ) {
            return 'Порожньо.';
        }

        if (
            lower.includes('my') ||
            lower.includes('purchases') ||
            lower.includes('sales') ||
            lower.includes('messages') ||
            lower.includes('finance')
        ) {
            return 'Empty.';
        }

        return 'Пусто.';
    }

    function ordersHtml(title) {
        return `
<h1 class="page-header page-header-no-hr">${safe(title)}</h1>


    <p class="lead">${safe(emptyLabel(title))}</p>`;
    }

    function userId() {
        const link = document.querySelector('a.user-link-dropdown[href*="/users/"], a[href*="/users/"].user-link-dropdown');
        const href = link ? link.getAttribute('href') : '';
        const match = String(href || '').match(/\/users\/(\d+)\//);

        if (match) return match[1];

        const chat = document.querySelector('.chat.chat-float[data-user]');
        if (chat && chat.dataset.user) return chat.dataset.user;

        return '';
    }

    function bookmarksTag() {
        const chat = document.querySelector('.chat.chat-float[data-bookmarks-tag]');
        if (chat && chat.dataset.bookmarksTag) return chat.dataset.bookmarksTag;

        const block = document.querySelector('.chat-full [data-bookmarks-tag]');
        if (block && block.dataset.bookmarksTag) return block.dataset.bookmarksTag;

        return 'empty';
    }

    function chatHeight() {
        const block = document.querySelector('.chat-full');

        if (block && block.style && block.style.height) {
            return block.style.height;
        }

        return '851px';
    }

    function chatHtml(title) {
        const id = safe(userId());
        const tag = safe(bookmarksTag());
        const height = safe(chatHeight());

        return `
<div class="container">
    <div class="chat-full chat-bookmarks-empty moved" style="height: ${height};" ${cleanedAttr}="chat" ${readyAttr}="1">
        <div class="chat-contacts">
            <div class="chat-full-header">
                <h1>${safe(title)}</h1>
            </div>
            <div class="contact-list custom-scroll">
            </div>
        </div>

        <div class="js-chat-top"></div>
        <div class="chat chat-float chat-not-selected" data-user="${id}" data-bookmarks-tag="${tag}">
            <div class="chat-header">
                <div class="media-user-name h2">
                    <a href="https://funpay.com/">Чат</a>
                </div>
                <div class="chat-header-controls">
                    <a class="btn btn-info-icon btn-info-sm btn-gray chat-control" href="https://support.funpay.com/tickets/new" target="_blank" title="Пожаловаться">
                        <i class="fa fa-exclamation-triangle icon"></i>
                    </a>
                </div>
                <a class="chat-back"><i class="fa fa-chevron-left"></i></a>
            </div>

            <div class="chat-message-container">
                <div class="chat-message-list hidden" style="">
                </div>
                <div class="chat-empty">
                    <div class="chat-not-selected-info">
                        <i class="fas fa-comments"></i>
                        <span class="bookmarks-empty">Здесь пока ничего нет ¯\\_(ツ)_/¯</span>
                        <span class="bookmarks-nonempty">Выберите диалог слева.<br>Уверены, у вас всё получится.</span>
                    </div>
                </div>
            </div>

            <div class="chat-form">
                <form action="https://funpay.com/chat/message" method="post">
                    <div class="chat-form-input">
                        <div class="form-group" id="comments">
                            <textarea class="form-control" name="content" cols="30" rows="1" placeholder="Написать..." autofocus=""></textarea><div class="hiddendiv"></div>
                        </div>
                    </div>
                    <div class="chat-form-btn">
                        <button type="submit" class="btn btn-gray btn-round"><i class="fa fa-arrow-right"></i></button>
                    </div>
                </form>
            </div>
        </div>

        <div class="chat-detail">
            <div class="chat-detail-list custom-scroll">
            </div>
        </div>
    </div>
</div>`;
    }

    function financeHtml() {
        return `
<h1 class="page-header balances-header">
    Финансы<span class="balances-list"><span class="balances-delimiter">·</span><span class="balances-value">0 €</span><span class="balances-delimiter">·</span><span class="balances-value">0 ¤</span><span class="balances-delimiter">·</span><span class="balances-value">0 $</span></span>
</h1>

<div class="alert-container"><div class="alert alert-with-icon alert-info" role="alert">
        <i class="fa fa-exclamation-circle alert-icon"></i>
    Операции по выводу USD и EUR проводятся в национальной валюте по курсу, близкому к биржевому.</div></div>

<div>
    <p class="text-lg margin-bottom">Деньги были, деньги будут, сейчас денег нет.</p>
    <a href="javascript:void(0)" class="btn btn-primary btn-wide withdraw">Способы вывода средств</a>
</div>

<div class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
    <div class="modal-dialog modal-sm">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><i class="fas fa-times"></i></button>
        <div class="modal-content">
            <div class="modal-header"><h4 class="h1 modal-title">Вывод средств</h4></div>
            <div class="modal-body">
                <div class="withdraw-box" data-data="">
                    <form action="https://funpay.com/withdraw/withdraw" method="post">
                        <input type="hidden" name="preview">
                        <div class="form-group currency-box">
                            <label>Счёт</label>
                            <div class="withdraw-select">
                                <select name="currency_id" class="form-control input-lg selectpicker" data-dropup-auto="false">
                                    <option value="eur">Евро — 0 €</option>
                                    <option value="rub">Рубли — 0 ₽</option>
                                    <option value="usd">Доллары — 0 $</option>
                                </select>
                            </div>
                        </div>
                        <div class="page page-error">
                            <span class="text-danger">Вывод данной валюты временно невозможен.</span>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>`;
    }

    function cleanBadges() {
        document.querySelectorAll('.badge-orders, .badge-trade, .badge-chat').forEach((badge) => {
            badge.textContent = '0';
            badge.classList.add('hidden');
            badge.setAttribute('aria-hidden', 'true');

            badge.style.display = 'none';
            badge.style.visibility = 'hidden';
            badge.style.opacity = '0';
            badge.style.pointerEvents = 'none';
        });
    }

    function isFinance(title) {
        return financeTitles.some((item) => (
            title === item ||
            title.startsWith(item + ' ') ||
            title.startsWith(item + '·') ||
            title.startsWith(item + ' ·')
        ));
    }

    function cleanPages() {
        document.querySelectorAll('.page-content-full').forEach((block) => {
            const h1 = block.querySelector('h1.page-header, h1');
            if (!h1) return;

            const title = text(h1.textContent);
            if (!title) return;

            if (orderTitles.has(title)) {
                const label = emptyLabel(title);
                const expected = `${title} ${label}`;
                const current = text(block.textContent);

                if (
                    block.getAttribute(cleanedAttr) === 'orders' &&
                    block.getAttribute(readyAttr) === '1' &&
                    current === expected
                ) {
                    unlockPage('orders');
                    return;
                }

                block.setAttribute(cleanedAttr, 'orders');
                block.innerHTML = ordersHtml(title);
                block.setAttribute(readyAttr, '1');

                unlockPage('orders');
                return;
            }

            if (isFinance(title) || route() === 'finance') {
                if (
                    block.getAttribute(cleanedAttr) === 'finance' &&
                    block.getAttribute(readyAttr) === '1' &&
                    text(block.textContent).includes('Деньги были, деньги будут, сейчас денег нет.')
                ) {
                    unlockPage('finance');
                    return;
                }

                block.setAttribute(cleanedAttr, 'finance');
                block.innerHTML = financeHtml();
                block.setAttribute(readyAttr, '1');

                unlockPage('finance');
            }
        });
    }

    function cleanChat() {
        const wrapper = document.querySelector('.chat-full-container');

        if (wrapper) {
            const h1 = wrapper.querySelector('.chat-full-header h1, h1');
            const title = text(h1 ? h1.textContent : 'Сообщения') || 'Сообщения';

            if (!chatTitles.has(title) && route() !== 'chat') return;

            if (
                wrapper.getAttribute(cleanedAttr) === 'chat' &&
                wrapper.getAttribute(readyAttr) === '1' &&
                text(wrapper.textContent).includes('Здесь пока ничего нет')
            ) {
                unlockPage('chat');
                return;
            }

            wrapper.setAttribute(cleanedAttr, 'chat');
            wrapper.innerHTML = chatHtml(title);
            wrapper.setAttribute(readyAttr, '1');

            unlockPage('chat');
            return;
        }

        const block = document.querySelector('.chat-full');
        if (!block) return;

        const h1 = block.querySelector('.chat-full-header h1, h1');
        const title = text(h1 ? h1.textContent : 'Сообщения') || 'Сообщения';

        if (!chatTitles.has(title) && route() !== 'chat') return;

        block.classList.remove('chat-bookmarks-nonempty');
        block.classList.add('chat-bookmarks-empty', 'moved');

        block.setAttribute(cleanedAttr, 'chat');
        block.innerHTML = chatHtml(title);
        block.setAttribute(readyAttr, '1');

        unlockPage('chat');
    }

    function run() {
        addStyle();
        cleanBadges();
        cleanPages();
        cleanChat();
    }

    function burst() {
        const current = route();

        if (current) {
            lockPage(current);
        }

        run();

        requestAnimationFrame(run);

        setTimeout(run, 20);
        setTimeout(run, 50);
        setTimeout(run, 100);
        setTimeout(run, 200);
        setTimeout(run, 400);
        setTimeout(run, 700);
        setTimeout(run, 1200);
        setTimeout(run, 2000);
        setTimeout(run, 3000);

        setTimeout(() => {
            const currentRoute = route();

            if (currentRoute === 'orders') {
                const ready = document.querySelector(`.page-content-full[${readyAttr}="1"]`);
                if (!ready) unlockPage('orders');
            }

            if (currentRoute === 'finance') {
                const ready = document.querySelector(`.page-content-full[${readyAttr}="1"]`);
                if (!ready) unlockPage('finance');
            }

            if (currentRoute === 'chat') {
                const ready = document.querySelector(`.chat-full-container[${readyAttr}="1"], .chat-full[${readyAttr}="1"]`);
                if (!ready) unlockPage('chat');
            }
        }, 5000);
    }

    function isTargetClick(event) {
        const link = event.target.closest?.('a, [data-href], .pseudo-a');
        if (!link) return false;

        const label = text(link.textContent).toLowerCase();

        const href = String(
            link.getAttribute('href') ||
            link.getAttribute('data-href') ||
            ''
        );

        return (
            link.classList.contains('menu-item-orders') ||
            link.classList.contains('menu-item-trade') ||
            link.classList.contains('menu-item-chat') ||
            link.classList.contains('menu-item-balance') ||

            label.includes('покупки') ||
            label.includes('продажи') ||
            label.includes('сообщения') ||
            label.includes('финансы') ||

            label.includes('продажі') ||
            label.includes('повідомлення') ||
            label.includes('фінанси') ||

            label.includes('purchases') ||
            label.includes('sales') ||
            label.includes('messages') ||
            label.includes('finance') ||

            Boolean(route(href))
        );
    }

    addStyle();
    lockPage(route());

    document.addEventListener('pointerdown', (event) => {
        if (!isTargetClick(event)) return;

        const link = event.target.closest?.('a, [data-href], .pseudo-a');
        const href = link ? String(link.getAttribute('href') || link.getAttribute('data-href') || '') : '';

        lockPage(route(href) || route());
    }, true);

    document.addEventListener('click', (event) => {
        if (isTargetClick(event)) {
            burst();
        }
    }, true);

    window.addEventListener('pageshow', burst, true);
    window.addEventListener('popstate', burst, true);

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', burst, { once: true });
    } else {
        burst();
    }

    window.addEventListener('load', burst, { once: true });
})();

Совместимость

Скрипт рассчитан на текущую верстку FunPay и использует классы вроде:

Код:
.page-content-full
.orders-filter
.orders-table
.chat-full-container
.chat-full
.contact-list
.badge-orders
.badge-trade
.badge-chat
.menu-item-orders
.menu-item-trade
.menu-item-chat
.menu-item-balance

Если FunPay изменит верстку, скрипт может потребовать обновления.

Баги и обновления

Если что-то не работает, появились мигания, сайт изменил верстку или какой-то блок перестал скрываться - пишите в Telegram:


Желательно сразу присылать:

— браузер;
— версию Tampermonkey;
— ссылку на страницу, где проблема;
— скрин;
— HTML проблемного элемента через Inspect.

По возможности пофикшу и выкачу обновленную версию.

Примечание

Скрипт работает только визуально в вашем браузере.
На стороне FunPay ничего не удаляется и не изменяется.