1. Гость, если сервер для Вас недоступен - попробуйте добавить папку с клиентом игры в исключения антивируса и выполните проверку в Лаунчере. Ознакомьтесь с F.A.Q на форуме и нашим Telegram каналом: @mmoclassic

Апгрейдим котобазу

Тема в разделе "Обо Всем", создана пользователем Колд, 21 сен 2020.

Статус темы:
Закрыта.
  1. Колд

    Колд Местный Пользователь

    Сообщения:
    99
    Симпатии:
    42
    Баллы:
    28
    Все мы любим котобазу почти так же сильно как наших родителей, детей и супругов. Но порой хочется от нее чего-то большего. И это возможно благодаря пользовательскому JavaScript.

    Для начала я расскажу как можно следить за своими котом через котобазу. Вдруг кто не знает. Для начала найдите лут, который выставлен в вашем коте, а после в списке найдите вашего кота с вашей ценой и кликните по названию кота. Вуаля, откроются все товары с вашего кота. Можно выставить в один из слотов кота какой-нибудь дешевый предмет за очень большие деньги, чтобы его никто не купил и потом поискать этого кота по этому предмету. Тогда можно будет ссылку добавить в закладки, она не изменится.

    Формируется ссылка на кота следующим образом
    https://pwcats.info/mmoclassic/15308/212544
    В этой ссылке есть два числа. Первое - идентификатор предмета, второе - идентификатор кота.

    Но это наверное все знали. Теперь непосредственно про апгрейд. Когда я смотрю своего кота мне не хватает трех вещей - количества предметов в коте, общей суммы продажи и покупки а так же цен на покупку и продажу в других котаъ. Подобной стандартной функциональности в котобазе нет, поэтому я добавляю ее с помощью, так называемого пользовательского JS. Суть в том, что есть браузерные расширения, который позволяют модифицировать код страницы. Используя эту возможность я делаю необходимые мне манипуляции.

    Нужно сделать следующее:
    1. Добавить в браузер расширение, которое позволяет модифицировать JS. Я использую User JavaScript and CSS. Но их довольно много, можете взять любое другое.
    2. В настройках для страницы pwcats.info добавляю следующий код.
    JavaScirpt:
    Код:
    // Идентификтор таблицы
    const ITEMS_TABLE_ID = 'sort_adw';
    const table = document.querySelector(`#${ITEMS_TABLE_ID}`);
    
    // Добавляет номера строк
    const addRowNumbers = () => {
        const rows = table.querySelectorAll('tbody tr');
    
        // Добавляем номера к строкам с конетнтом
        rows.forEach((row, index) => {
            row.insertAdjacentHTML('afterbegin', `<td>${index + 1}</td>`)
        });
    
        // Добавляем номер к строке с заголовком
        table.querySelector('thead tr').insertAdjacentHTML('afterbegin', '<th>#</th>')
    }
    
    // Считает сумму покупки и продажи
    const addCount = () => {
        const tbody = table.querySelector('tbody');
        const rows = tbody.querySelectorAll('tr');
    
        let buyAmount = 0;
        let sellAmount = 0;
    
        // Высчитываем сумму покупку и продажи
        rows.forEach(row => {
            const cells = row.querySelectorAll('td');
    
            const num = Number(cells[4].textContent.match(/\(.+\)/)[0].slice(1, -1));
            const buyPrice = Number(cells[5].textContent.replace(/\s/g, ''));
            const sellPrice = Number(cells[6].textContent.replace(/\s/g, ''));
    
            if(buyPrice > 0) {
                buyAmount += buyPrice * num;
            }
    
            if(sellPrice > 0) {
                sellAmount += sellPrice * num;
            }
        });
    
    
        // Добавляем в таблицу строку с суммой покупки и продажи
        tbody.insertAdjacentHTML('beforeend', `
            <tr class="item_tr">
                <td colspan="5"></td>
                <td class="sell">${buyAmount.toLocaleString('ru')}</td>
                <td class="buy">${sellAmount.toLocaleString('ru')}</td>
            </tr>
        `);
    }
    
    // Парсер текста в HTML
    const parseResponse = response => (new DOMParser()).parseFromString(response, "text/html");
    
    // Добавляет цены для сравнения
    const addCompareRow = (priceRow, [sellPrices, buyPrices]) => {
        const tbody = table.querySelector('tbody');
        const [sellMin, sellMax] = sellPrices;
        const [buyMin, buyMax] = buyPrices;
    
        priceRow.insertAdjacentHTML('afterend', `
            <tr class="item_tr item_tr--compare">
                <td colspan="5" class="td_right">
                    Минимальная:<br>
                    Максимальная:
                </td>
                <td class="sell td_right">
                    ${sellMin}<br>
                    ${sellMax}
                </td>
                <td class="buy td_right">
                    ${buyMin}<br>
                    ${buyMax}
                </td>
            </tr>
        `);
    }
    
    // Если цены нет - ставим прочерк
    const definePrice = price => price || '—';
    
    // Обрабатываем ответ сервера
    const processResponse = (response) => {
        const content = parseResponse(response);
        const pricesTable = content.querySelector(`#${ITEMS_TABLE_ID}`);
    
        // Цены продажи
        const sellPrices = [...pricesTable.querySelectorAll('.sell')]
            .map(cell => cell.textContent)
            .filter(Boolean);
        const sellMin = definePrice(sellPrices[0]);
        const sellMax = definePrice(sellPrices[sellPrices.length - 1]);
    
        // Цены покупки
        const buyPrices = [...pricesTable.querySelectorAll('.buy')]
            .map(cell => cell.textContent)
            .filter(Boolean);
        const buyMin = definePrice(buyPrices[0]);
        const buyMax = definePrice(buyPrices[buyPrices.length - 1]);
    
        return [[sellMin, sellMax], [buyMin, buyMax]]
    }
    
    const fetchAllPrices = () => {
        const tbody = table.querySelector('tbody');
        const rows = tbody.querySelectorAll('tr');
    
        rows.forEach((row, index) => {
            // Задержка в 500 милисекунд на каждый запрос, чтобы не дудосить котобазу
            // мы ведь все ее нежно любим и не хотим ей зла
            setTimeout(() => {
                // Получаем ссылку на товар
                const cells = row.querySelectorAll('td');
                const link = cells[4].querySelector('a');
       
                if(link && link.href) {
                    // Запрашиваем цену на товар
                    fetch(link.href)
                        .then(response => response.text())
                        .then(response => {
                            // Когда мы успешно ее получили — добавляем строку
                            addCompareRow(row, processResponse(response))
                        })
                        .catch(console.erorr)
                }
            }, 500 * index);
        })
    }
    
    // Добавляем кнопку запроса цен
    const addFetchButton = () => {
        const title = document.querySelector('.box-title');
    
        if(!title) {
            return;
        }
    
        title.insertAdjacentHTML(
            'afterend',
            '<button class="btn fetch-prices">Загрузить цены</button>'
        );
    
        const fetchButton = document.querySelector('.fetch-prices');
        fetchButton.addEventListener('click', () => {
            // После того как цены запросили кнопка больше не нужны
            fetchButton.disabled = true;
            fetchButton.style.visibility = 'hidden';
    
            // Запрашиваем цены
            fetchAllPrices();
        })
    }
    
    
    // Инициализация
    if(table) {
        addRowNumbers();
        addCount();
        addFetchButton();
    }
    
    CSS:
    Код:
    .item_tr--compare.item_tr td {
        border-top: none;
    }
    
    .box-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
    }
    
    .box-header:before,
    .box-header:after {
        display: none;
    }
    
    3. После нужно сохранить код и обновить страницу вашего кота на котобазе. Вы увидите нечто подобное:

    pwcats.info_mmoclassic_15308_212544.png
    И после загрузки цен:

    Снимок экрана 2020-09-22 в 14.33.14.png

    Видео-пример:


    Видео-инструкция:


    Возможно это вам поможет. Так же если у вас есть какие-то идеи по модификациям, но сами вы их воплотить в жизнь не можете, то, возможно, я помогу.

    UPD 22.09.2020: Добавлена возможность собирать минимальные и максимальные цены.

    UPD 23.09.2020: Добавлены забытые стили.

    UPD 24.09.2020: Добавлена видео-инструкция по настройке.

    Не уверен, что этот гайд может претендовать на награду, но если может, то игровой ник - Колд
     
    Последнее редактирование: 24 сен 2020
    rotmar, Balustrad, ПОЯСНИ ЗА ПВ и 7 другим нравится это.
  2. СуровыЙ

    СуровыЙ Местный Пользователь

    Сообщения:
    155
    Симпатии:
    33
    Баллы:
    28
    Ну это лайк.
     
  3. KANO

    KANO Активный участник Пользователь

    Сообщения:
    28
    Симпатии:
    20
    Баллы:
    18
    Программисты подъехали Tigers18
     
  4. Numark

    Numark Местный Пользователь

    Сообщения:
    160
    Симпатии:
    48
    Баллы:
    28
    Отлично, но ...она постоянно лагает или не грузит вообще.
     
  5. Колд

    Колд Местный Пользователь

    Сообщения:
    99
    Симпатии:
    42
    Баллы:
    28
    На это, к сожалению, я повлиять никак не могу.
     
  6. Numark

    Numark Местный Пользователь

    Сообщения:
    160
    Симпатии:
    48
    Баллы:
    28
    Попросите их доступ к бд и серваку. Фиксанем :)
     
  7. Колд

    Колд Местный Пользователь

    Сообщения:
    99
    Симпатии:
    42
    Баллы:
    28
    Я изменил верхний пост. Добавил возможность парсить минимальные и максимальные цены на товар. Возможно вам это тоже будет полезно.
     
  8. Errant

    Errant Местный Пользователь

    Сообщения:
    428
    Симпатии:
    86
    Баллы:
    28
    Темка прикольная, делать я этого конечно не буду, но все равно топчик. Думаю это не предел возможностей)
     
  9. Колд

    Колд Местный Пользователь

    Сообщения:
    99
    Симпатии:
    42
    Баллы:
    28
    На самом деле мне кажется, что подобные фишки должен вводить владелец котобазы, возможно всякие дополнительные штуки по какой-то подписке ежемесячной или типа того.
     
  10. Errant

    Errant Местный Пользователь

    Сообщения:
    428
    Симпатии:
    86
    Баллы:
    28
    Согласен, ибо много функционала нет на пвкетс, который довольно легко сделать. Причём внесёт много комфорта по поиску и сравнению цен. Но увы пвкетс уже давно не развивается....
     
  11. Колд

    Колд Местный Пользователь

    Сообщения:
    99
    Симпатии:
    42
    Баллы:
    28
    Добавил еще видео-пример того, как это работает.
     
  12. RDX

    RDX Новичок Пользователь

    Сообщения:
    2
    Симпатии:
    0
    Баллы:
    1
    Код с комментами
    [​IMG]
     
  13. Колд

    Колд Местный Пользователь

    Сообщения:
    99
    Симпатии:
    42
    Баллы:
    28
    Справедливости ради это не те комментарии, которые привыкли видеть в коде программисты. Это комменты для непосвященных, чтобы было примерно понятно, что я не угоняю какие-то персональные данные.
     
  14. RDX

    RDX Новичок Пользователь

    Сообщения:
    2
    Симпатии:
    0
    Баллы:
    1
    Зависит от того что пишут, тут как для плагина они очень даже уместны, описывать аргументы и т.д. тут смысла не вижу, а вот сооринтироваться в незнакомом коде очень даже помогут такие комменты.
     
  15. Колд

    Колд Местный Пользователь

    Сообщения:
    99
    Симпатии:
    42
    Баллы:
    28
    Мне пожаловались, что непонятно как настроить, поэтому я добавил к посту видео-инструкцию.
     
  16. Aqualon

    Aqualon Житель форума Пользователь

    Сообщения:
    288
    Симпатии:
    154
    Баллы:
    43
    есть вопрос кста, там апи публичный? Можно ли будет сфетчить данные с другого домена или локалхоста? Если нет то печально, но даже так можно тупо вотчер на кота поставить или на цены и присылать уведомления когда цена изменилась
     
  17. Колд

    Колд Местный Пользователь

    Сообщения:
    99
    Симпатии:
    42
    Баллы:
    28
    Там нет никакого АПИ и при попытке забрать данные таким способом с другого домена вы сталкнетесь с корсами. Если говорить исключительно о браузере, то, наверное, можно на открытой вкладке по интервалу перепроверять цены и присылать уведомления, но это требует всегда открытой вкладки. Откровенно говоря решение стремное. Я бы как-то иначе подходил к решению этой задачи.
     
  18. Aqualon

    Aqualon Житель форума Пользователь

    Сообщения:
    288
    Симпатии:
    154
    Баллы:
    43
    Что-то такое я и думал сделать, но да, действительно решение не самое лучшее, просто первое что пришло в голову.
     
  19. Колд

    Колд Местный Пользователь

    Сообщения:
    99
    Симпатии:
    42
    Баллы:
    28
    Первая мысль — забирать страницы по крону с помощью курла на сервере, как-то парсить, разбирать, сравнивать с сохранёнными результатами и потом куда-то уведомлять.
     
  20. ___

    ___ Новичок Пользователь

    Сообщения:
    4
    Симпатии:
    0
    Баллы:
    1
    ну вообще не обязательно ставить на крон и т.п. Можно написать простое приложение с встроенным http клиентом (да даже на том же jsе есть нода) и при запросе на твой api с помощью клиента на запросе вытаскивать данные и парсить с сайта ну и при этом можно поставить к примеру кэш минут на 5, чтобы повторные запросы к твоему api обрабатывались побыстрее, так как фетчинг и парсинг очень долгие операции ( относительно )
     
Статус темы:
Закрыта.

Поделиться этой страницей