SA:MP JS Удобный, легкий и полный пробив игроков по серверам Arizona Role Play

normalped

Участник
Автор темы
51
22
Версия SA-MP
  1. Любая
  2. Другая
Скрипт, позволяющий без лишних усилий получить всю доступную информацию про пользователя с любых серверов Arizona Role Play. Все, что нужно - вставить код в консоль разработчика в браузере и пользоваться его функционалом.

Настройка:
1. Зайдите на сайт и войдите в свой аккаунт.
2. Откройте консоль браузера из DevTools.
3. Вставьте главный код скрипта из спойлера ниже в поле для ввода и нажмите Enter.

Использование:
Теперь, чтобы получить информацию, вам нужно так же выполнить код из примера, указав ник игрока и диапазон номеров от серверов для поиска.


JavaScript:
Finder.find('Nick_Name', '1, 2, 5 - 6');

Здесь мы получаем информацию про игрока на Phoenix, Tucson, Brainburg, Saint-Rose.

Обратите внимание, что в диапазоне не обязательно добавлять пробелы, и номера мобильных серверов начинаются с сотни, например у Mobile 1 номер будет 101. Также после обновлений сайта работоспособность скрипта может нарушиться. Попробуйте изменить переменную sitekey в основном скрипте на более актуальную: откройте вкладку Elements в DevTools и с помощью поиска (Ctrl + F) найдите подобный, но актуальный ключ по запросу sitekey.


1744796917659.png

1744796943841.png
JavaScript:
class Finder {
    static accessToken;
    static captchaToken;
    static servers = [];
    static sitekey = '0x4AAAAAAA4cVvk7rjr3XWxi'

    static server = (id) =>
        this.servers[id] ? `${this.servers[id].title} (${id})` : `Server (${id})`

    static cookie = (name) => {
        const value = `; ${document.cookie}`;
        const parts = value.split(`; ${name}=`);
        if (parts.length === 2) return parts.pop().split(';').shift();
    };

    static captcha = () => new Promise(resolve => {
        window.turnstile.render(document.querySelector('#cf-turnstile'), {
            sitekey: this.sitekey,
            callback: resolve
        });
    });

    static parseRange = (str) => {
        const res = str
            .split(',')
            .flatMap(part => {
                if (part.includes('-')) {
                    const [start, end] = part.split('-').map(Number);
                    return Array.from({ length: end - start + 1 }, (_, i) => start + i);
                }
                return [Number(part)];
            });

        if (res.length < 1) throw new Error('Не удалось запарсить диапазон!');
        return [...new Set(res)];
    };

    static fetchPlayer = async (name, server) => {
        this.captchaToken = await this.captcha();

        const body = {
            gReCaptchaToken: this.captchaToken,
            login: name,
            server: server
        };

        const config = {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${this.accessToken}`,
                'Content-Type': 'application/json',
                'Referer': 'https://arizona-rp.com/',
            },
            body: JSON.stringify(body)
        };

        const res = await fetch('https://n-api.arizona-rp.com/api/account/find', config);
        let data;

        try {
            data = await res.json();
        } catch {
            data = null;
        }

        return res.ok ? data : { code: res.status, message: data?.message || res.statusText };
    };

    static fetchEstate = async (name, server) => {
        const res = await fetch(`https://n-api.arizona-rp.com/api/map/${server}`);
        if (res.ok) {
            const data = await res.json();
            const businesses = {};
            const houses = {};

            data.businesses.noAuction = Object.values(data.businesses.noAuction).flat()

            const filter = (target, source, keys) => {
                keys.forEach(key => {
                    target[key] = source[key].filter(obj => obj.owner === name);
                });
            };

            filter(businesses, data.businesses, ['noAuction', 'onAuction', 'onMarketplace']);
            filter(houses, data.houses, ['hasOwner', 'onAuction', 'onMarketplace']);

            return { businesses, houses };
        }
        return { code: res.status, message: res.statusText }
    };

    static fetchServers = async () => {
        const res = await fetch('https://n-api.arizona-rp.com/api/servers/arizona');
        if (res.ok) return await res.json();
        return { code: res.status, message: res.statusText }
    };

    static fetch = async (...args) => {
        const res = { errors: [] };
        const player = await this.fetchPlayer(...args);
        const estate = await this.fetchEstate(...args);

        for (const data of [ player, estate ]) {
            if (data.code) {
                res.errors.push(data);
                continue;
            }
            Object.assign(res, data);
        }

        return res;
    };

    static format = (data, name, server) => {
        if (data.errors.length > 0) {
            console.groupCollapsed(`%c❌ ${this.server(server)} - Ошибка: ${data.errors[0].code} | ${data.errors[0].message}`, 'color: #f92f60; font-size: 1.8rem;');
            console.groupEnd();
            return;
        }

        console.groupCollapsed(`%c✅ ${this.server(server)} - Игрок найден:`, 'color: #00d26a; font-size: 1.8rem;');

        const number = (amount, suffix = '$') => {
            if (!amount && typeof amount !== 'number') return;
            if (typeof amount === 'string') {
                amount = Number(amount.replace(/\s/g, ''));
                if (isNaN(amount)) return;
            }
            if (typeof amount !== 'number' || isNaN(amount)) return;
            return new Intl.NumberFormat(navigator.language || 'en-US', {
                style: 'decimal',
                minimumFractionDigits: 0
            }).format(amount) + ' ' + suffix;
        };

        const bank = (amount) => amount !== -1 ? number(amount) : 'Не открыт';

        const estate = (arr) => {
            if (!Array.isArray(arr) || arr.length === 0) return 'Пусто';
            return '\n' + arr
                .map((item, i) => ` ${i + 1}. #${item?.id} - ${item?.name};`)
                .join('\n');
        };

        const lines = [
            ['🏷️ Имя', data?.name],
            ['📈 Уровень', data?.level],
            ['✨ Очки опыта', `${data?.xp} / ${data?.maxXp}`],
            ['❓ Пол', data?.gender],
            ['⭐ VIP', `${data?.vip ?? 'нет'}${data?.vip ? ` (${data?.vipExpirationDate ?? 'Вечный'})` : ''}`],
            ['⌛ Наиграно', number(data?.PlayHours, 'ч.')],
            ['🪙 AZ-Coins', number(data?.coins, 'AZ')],
            ['💰 Накопления', number(data?.money)],
            ['💵 Наличные деньги', number(data?.cash)],
            ['💳 Деньги в банке', number(data?.bank)],
            ['🏦 Деньги на депозите', number(data?.deposit)],
            ['📑 Личный счет #1', bank(data?.bankAccount1)],
            ['📑 Личный счет #2', bank(data?.bankAccount2)],
            ['📑 Личный счет #3', bank(data?.bankAccount3)],
            ['📑 Личный счет #4', bank(data?.bankAccount4)],
            ['📑 Личный счет #5', bank(data?.bankAccount5)],
            ['📑 Личный счет #6', bank(data?.bankAccount6)],
            ['💳 Банковская карта', data?.bankCard ? 'есть' : 'нет'],
            ['📱 Номер телефона', data?.telephone ?? 'нет'],
            ['📱 Баланс телефона', number(data?.telephoneBalance) ?? 'нет'],
            ['🔗 Зависимость', data?.drugAddict],
            ['💼 Работа', data?.hasJob],
            ['💍 Супруг(а)', data?.married || 'нет'],
            ['🕵️ Уровень розыска', data?.wantedLevel],
            ['❤️ Здоровье', data?.hp],
            ['🍖 Голод', `${data?.hunger} / ${data?.maxHunger}`],
            ['⚠️ Предупреждения', data?.warns],
            ['🙏 Благотворительность', number(data?.blago) ?? 'нет'],
            ['🏠 Дома', estate(data?.houses?.hasOwner)],
            ['🏠 Дома на аукционе', estate(data?.houses?.onAuction)],
            ['🏠 Дома на маркетплейсе', estate(data?.houses?.onMarketplace)],
            ['🏢 Бизнесы', estate(data?.businesses?.noAuction)],
            ['🏢 Бизнесы на аукционе', estate(data?.businesses?.onAuction)],
            ['🏢 Бизнесы на маркетплейсе', estate(data?.businesses?.onMarketplace)],
        ];

        const output = lines.map(([key, value]) =>
            [`%c${key}%c — %c${value ?? '-'}`,
            'font-size: 1.1rem;',
            'font-size: 1.5rem; color: gray;',
            'font-size: 1.1rem; font-weight: bold']
        );

        const format = output.map(o => o[0]).join('\n');
        const styles = output.flatMap(o => o.slice(1));

        console.log(format, ...styles);
        console.groupEnd();
    };

    static find = async (name, range) => {
        this.accessToken = this.cookie('accessToken');
        const servers = this.parseRange(range);
        const res = {};

        const data = await this.fetchServers();
        if (!data.code) {
            this.servers = data.reduce((acc, item) => {
                acc[item.id] = item;
                return acc;
            }, {});
        }

        for (const server of servers) {
            const data = await this.fetch(name, server);
            this.format(data, name, server);
            res[server] = data;
        }

        const keys = Object.keys(res).length;
        if (keys > 1) {
            console.log('\n');
            const failed = Object.entries(res).filter(([key, value]) => value?.errors?.length > 0);
            console.groupCollapsed(`%cℹ️ Итого (${keys - failed.length} / ${keys}):`, 'color: #0092d1; font-size: 1.8rem;');

            for (const key in res) {
                this.format(res[key], name, key);
            }

            console.groupEnd();
            console.log('\n');
        }
    };
}

Автором являюсь я. При распространении или использовании не локально указывать автора.
 
Последнее редактирование: