Upload_Market_by_el9in

Upload Market

// ==UserScript==
// @name         Upload_Market_by_el9in
// @namespace    Upload_Market_by_el9in
// @version      0.2
// @description  Upload Market
// @author       el9in
// @match        https://lzt.market/mass-upload/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=zelenka.guru
// @grant        none
// @license      el9in
// ==/UserScript==

(function() {
    'use strict';
    const maxThreads = 3;
    const inputElement = document.querySelector('input[type="hidden"][name="_xfToken"]');
    const xfTokenValue = inputElement.value;
    const finishLoadElement = document.querySelector('div.MassUploadFinishedBadge.finishedBadge.hidden.mn-15-0');
    const url = window.location.href;
    const parts = url.split('/');
    const id = parts[parts.length - 2];
    const check = [];
    const divElements = document.querySelectorAll('div.account');
    const massUploadStats = document.querySelector('.MassUploadStats');
    const checked = massUploadStats.querySelector('.checked.label');
    const remaining = massUploadStats.querySelector('.left.label');
    const success = massUploadStats.querySelector('.success.label');
    const error = massUploadStats.querySelector('.error.label');
    var checkedCount = checked.textContent | 0;
    var remainingCount = remaining.textContent | 0;
    var successCount = success.textContent | 0;
    var errorCount = error.textContent | 0;
    divElements.forEach((divElement) => {
        const accountStatusElement = divElement.querySelector('.AccountStatus > .muted');
        const entryId = divElement.getAttribute('data-entry-id');
        check.push({
            entryId,
            statusElement: accountStatusElement
        });
    });
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    async function checkAccount(accountData,close) {
        const Local = {
            times: 0,
            maxTimes: 20
        };
        if(accountData.statusElement) accountData.statusElement.textContent = 'EL9IN: Начата проверка.';
        while(true) {
            if(Local.times >= Local.maxTimes) return 0;
            const response = await fetch(`https://lzt.market/mass-upload/${id}/check-account`, {
                "headers": {
                    "accept": "application/json, text/javascript, */*; q=0.01",
                    "accept-language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
                    "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
                    "x-ajax-referer": `https://lzt.market/mass-upload/${id}/`,
                    "x-requested-with": "XMLHttpRequest",
                    "Referer": `https://lzt.market/mass-upload/${id}/`,
                    "Referrer-Policy": "strict-origin-when-cross-origin"
                },
                "body": `entry_id=${accountData.entryId}&_xfRequestUri=%2Fmass-upload%2F${id}%2F&_xfNoRedirect=1&_xfToken=${xfTokenValue}&_xfResponseType=json`,
                "method": "POST"
            });
            const req = await response.json();
            const { error, item } = req;
            if(error == "captcha") {
                if(accountData.statusElement) accountData.statusElement.textContent = `EL9IN: ${error}`;
                Local.times++;
                await sleep(500);
                continue;
            } else if(error != null) {
                if(accountData.statusElement) accountData.statusElement.textContent = `EL9IN: ${error}`;
                Local.times++;
                errorCount ++;
                error.textContent = errorCount;
                return 0;
            } else {
                successCount ++;
                success.textContent = successCount;
                const { link } = item;
                if(accountData.statusElement) accountData.statusElement.textContent = `EL9IN: Успешно добавили ${link}`;
                if(close == true) {
                    const itemMarketId = extractIDFromURL(link);
                    try {
                        const status = await fetch(`https://lzt.market/${itemMarketId}/open-close?&_xfRequestUri=%2F${itemMarketId}%2F&_xfNoRedirect=1&_xfToken=${xfTokenValue}&_xfResponseType=json`, {
                            "headers": {
                                "accept": "application/json, text/javascript, */*; q=0.01",
                                "accept-language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
                                "x-ajax-referer": `https://lzt.market/${itemMarketId}/`,
                                "x-requested-with": "XMLHttpRequest",
                                "Referer": `https://lzt.market/${itemMarketId}/`,
                                "Referrer-Policy": "strict-origin-when-cross-origin"
                            },
                            "body": null,
                            "method": "GET"
                        });
                        const { _redirectStatus } = await status.json();
                        if(_redirectStatus == "ok") {
                            const svgHTML = `
						<svg viewBox="0 0 24 24" width="20" height="20" stroke="rgb(156 164 91)" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round" class="css-i6dzq1">
						  <rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
						  <path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
						</svg>
						`;
                            accountData.statusElement.insertAdjacentHTML('afterend', svgHTML);
                        }
                    } catch(error) {
                        return 2;
                    }
                }
            }
            return 1;
        }
    }
    const startStopButton = document.getElementById('MassStartStopButton');
    if(startStopButton) {
        const newButton = document.createElement('button');
        const newButtonAPI = document.createElement('button');
        newButton.id = 'MassStartStopButtonByEl9in';
        newButton.classList.add('toggle', 'primary', 'button');
        newButton.textContent = 'Начать и закрыть (EL9IN)';
        newButton.style.marginLeft = '3px';
        startStopButton.parentNode.insertBefore(newButton, startStopButton.nextSibling);
        newButton.addEventListener('click', async function() {
            startStopButton.parentNode.removeChild(startStopButton);
            newButton.parentNode.removeChild(newButton);
            newButtonAPI.parentNode.removeChild(newButtonAPI);
            runCheckAccounts(check,false);
        });
        newButtonAPI.id = 'MassStartStopButtonAPIByEl9in';
        newButtonAPI.classList.add('toggle', 'primary', 'button');
        newButtonAPI.textContent = 'Начать (EL9IN)';
        newButtonAPI.style.marginLeft = '3px';
        startStopButton.parentNode.insertBefore(newButtonAPI, startStopButton.nextSibling);
        newButtonAPI.addEventListener('click', async function() {
            startStopButton.parentNode.removeChild(startStopButton);
            newButton.parentNode.removeChild(newButton);
            newButtonAPI.parentNode.removeChild(newButtonAPI);
            runCheckAccounts(check,false);
        });
    }
    async function runCheckAccounts(check,close) {
        const semaphore = new Semaphore(maxThreads);
        const promises = [];
        for (let ck of check) {
            await semaphore.acquire();
            promises.push(
                (async () => {
                    await checkAccount(ck,close);
                    semaphore.release();
                })()
            );
            checkedCount ++;
            checked.textContent = checkedCount;
            remainingCount --;
            remaining.textContent = remainingCount;
        }
        await Promise.all(promises);
        if (finishLoadElement) {
            finishLoadElement.classList.remove('hidden');
        }
    }
    class Semaphore {
        constructor(maxCount) {
            this.maxCount = maxCount;
            this.counter = 0;
            this.waiters = [];
        }
        acquire() {
            if (this.counter < this.maxCount) {
                this.counter++;
                return Promise.resolve();
            } else {
                return new Promise(resolve => {
                    this.waiters.push(resolve);
                });
            }
        }
        release() {
            if (this.waiters.length > 0) {
                const waiter = this.waiters.shift();
                waiter();
            } else {
                this.counter--;
            }
        }
    }
    function extractIDFromURL(url) {
        const trimmedURL = url.endsWith('/') ? url.slice(0, -1) : url;
        const parts = trimmedURL.split('/');
        const id = parts[parts.length - 1];
        return id;
    }
})();