Clan depo quick sets

Арендовать кастомный набор со склада в 1 клик. Кнопка снять все арты, вернуть все арты на складе. Инструкция на скрине снизу.

// ==UserScript==
// @name         Clan depo quick sets
// @namespace    http://tampermonkey.net/
// @version      0.4.11
// @description  Арендовать кастомный набор со склада в 1 клик. Кнопка снять все арты, вернуть все арты на складе. Инструкция на скрине снизу.
// @author       Something begins
// @license     none
// @match       https://www.heroeswm.ru/sklad_info*
// @match       https://my.lordswm.com/sklad_info*
// @match       https://www.lordswm.com/sklad_info*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=lordswm.com
// @grant        none
// ==/UserScript==
const setAmount = 5;
const redirectTo = "/inventory.php";
const defaultSets = '{"1":"Меч холода, Кольцо холода, Кольцо холода, Доспех солнца, Сапоги солнца, Шлем солнца, Клевер фортуны, Плащ солнца, Щит холода","2":"Мифриловый перстень времён [N12E12A12W12F12], Великое кольцо аномалий [N12E12A12W12F12], Кулон сингулярности [N12E12A12W12F12]","3":"Мифриловый перстень времён [E11A11W11F11] || Мифриловый перстень времён [N10E10A10W10F10] || Мифриловый перстень времён [N12E12A12W12F12], Великий доспех ловчего [D12E12A12W12F12]","4":"","5":""}';
const defaultNames = '{"1":"Акционка","2":"КБО книга","3":"КБО раш","4":"","5":""}';
const stylesHTML = `
<style>
    .set_container {
        display: flex;
        flex-direction: row;
        align-items: flex-start;
    }

    .set_list {
        width: 100%;
        box-sizing: border-box;
        margin-bottom: 10px;
    }
    .set_name {
        width: 20%;
        box-sizing: border-box;
        margin-bottom: 10px;
        margin-right: 10px;
        align-self: center;
    }

    button, span, select.available_battles_count {
        width: auto;
        align-self: center;
        padding: 5px;
        margin-left: 5px;
    }
    .undress_button{
cursor: pointer;
align-self: center;
    }
</style>
`;

const setParentHTML = `
<div id = "set_parent" style="display: flex;flex-direction: column;"></div>
`;
const saveButtonHTML = `
<button id = "save_button"> Сохранить </button>
`;

const origin = location.origin + location.pathname + "?id=" + location.href.match(/id=(\d+)/)[1];
console.log(origin);

async function fetchMultipleUrls(urls) {
    const fetchPromises = urls.map(url => {
        return fetch(url, {
            method: 'GET',
            headers: new Headers({
                'Content-Type': 'text/html; charset=windows-1251',
            }),
        })
            .then(response => {
            if (!response.ok) {
                throw new Error(`Network response was not ok: ${response.status}`);
            }
            return response.arrayBuffer();
        })
            .then(buffer => {
            const decoder = new TextDecoder('windows-1251');
            return { url: url, text: decoder.decode(new Uint8Array(buffer)) };
        });
    });

    try {
        const results = await Promise.all(fetchPromises);
        return results;
    } catch (error) {
        console.error('Error fetching URLs:', error);
        throw error;
    }
}

function returnAll() {
    const allAs = document.querySelectorAll("a");
    const returnAs = Array.from(allAs).filter(a => { return a.href.includes("art_return") });
    const allLinks = returnAs.map(a => a.href);
    console.log(allLinks);
    consequetiveFetches(allLinks, () => { location.reload() });
}

function undress() {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', '/inventory.php?all_off=100', true);
    xhr.overrideMimeType('text/plain; charset=windows-1251');
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200)
            // send_storage_async_get(document.location);
            location.reload();
    };
    xhr.send(null);
}

function draw_undress_button(content) {
    content.insertAdjacentHTML("afterEnd", "<b>");
    var a = document.createElement('a');
    a.href = '';
    a.textContent = ' (вернуть все) ';

    content.appendChild(a);
    const undressButtonHTML = `<td><img class = 'undress_button' src = 'https://dcdn.heroeswm.ru/i/inv_im/btn_art_rem.png'></img></td>`;

    content.appendChild(a);
    document.querySelector("body > center > table:nth-child(2) > tbody > tr > td > table:nth-child(1) > tbody > tr:nth-child(4) > td > table > tbody:nth-child(1) > tr").insertAdjacentHTML("beforeEnd", undressButtonHTML);
    const undressButton = document.querySelector(".undress_button");
    a.addEventListener('click', function(e) {
        e.preventDefault();
        returnAll();
    });
    undressButton.addEventListener('click', function(e) {
        e.preventDefault();
        undress();
    });
    document.addEventListener("keydown", event => {
        if (event.altKey) {
            if (["q", "Q", "й", "Й"].includes(event.key)) {
                returnAll();
            }
            if (["w", "W", "Ц", "ц"].includes(event.key)) {
                undress();
            }
        }
    });
}

function getAllCatsURLs() {
    const weaponA = document.querySelector("body > center > table:nth-child(2) > tbody > tr > td > table:nth-child(2) > tbody > tr > td:nth-child(2) > a");
    const armorA = document.querySelector("body > center > table:nth-child(2) > tbody > tr > td > table:nth-child(2) > tbody > tr > td:nth-child(3) > a");
    const jewelA = document.querySelector("body > center > table:nth-child(2) > tbody > tr > td > table:nth-child(2) > tbody > tr > td:nth-child(4) > a")
    const backpackA = document.querySelector("body > center > table:nth-child(2) > tbody > tr > td > table:nth-child(2) > tbody > tr > td:nth-child(5) > a");
    if ([weaponA, armorA, jewelA, backpackA].includes(null)) return false;
    return [weaponA.href, armorA.href, jewelA.href, backpackA.href];
}


function countOccurrences(arr, target) {
    return arr.reduce((count, element) => (element === target ? count + 1 : count), 0);
}

function consequetiveFetches(urlArr, callback = () => {}, i = 0) {
    if (i >= urlArr.length) {
        callback();
        return;
    } else {
        fetch(urlArr[i]).then((response) => {
            if (!response.ok) {
                console.error(`HTTP error! Status: ${response.status}, Text: ${response.statusText}`);
                consequetiveFetches(urlArr, callback, i);
            } else {
                consequetiveFetches(urlArr, callback, i + 1);
            }
        })
    }
}

function getReqDepoArts(requiredArts, battlesAmount, fetchedData) {
    let allArts = [];
    const neededArts = [];
    const missingArts = [];
    for (const data of fetchedData) {
        const arts = getArtList(data.text);
        console.log("arts", arts);
        allArts = allArts.concat(arts);
    }
    for (let i = 0; i < allArts.length; i++) {
        allArts[i].index = i;
    }
    console.log("allArts", allArts);
    for (const reqArtName of requiredArts) {
        console.log("reqArtName", reqArtName);
        const alternatives = reqArtName.split("||");
        let matchedArts;
        if (alternatives.length > 1) {
            for (const alternative of alternatives) {
                matchedArts = allArts.filter(art => { return alternative.trim().toLowerCase() === art.name.toLowerCase() && !art.taken && art.availableBattlesCount >= battlesAmount });
                if (matchedArts.length === 0) {
                    matchedArts = allArts.filter(art => { return alternative.trim().toLowerCase() === art.name.toLowerCase() && !art.taken });
                }
                if (matchedArts.length > 0) break;
            }
        } else {
            matchedArts = allArts.filter(art => { return reqArtName.trim().toLowerCase() === art.name.toLowerCase() && !art.taken && art.availableBattlesCount >= battlesAmount });
            if (matchedArts.length === 0) matchedArts = allArts.filter(art => { return reqArtName.trim().toLowerCase() === art.name.toLowerCase() && !art.taken });
        }
        console.log("matchedArts", matchedArts);
        if (matchedArts.length === 0) {
            missingArts.push(reqArtName);
            continue;
        };
        const chosenArt = matchedArts[0];
        neededArts.push(chosenArt);
        allArts[chosenArt.index].taken = true;
    }
    console.log("neededArts", neededArts);
    return { neededArts: neededArts, missingArts: missingArts };
}
async function fetchDataAndProcess(requiredArts, battlesAmount) {
    const neededLinks = [];
    let warningMessage = "";
    const fetchedData = await fetchMultipleUrls(getAllCatsURLs());
    const artData = getReqDepoArts(requiredArts, battlesAmount, fetchedData);
    for (const chosenArt of artData.neededArts) {
        neededLinks.push(getRentLink(origin, chosenArt.artId, chosenArt.sign, chosenArt.category, battlesAmount));
        if (battlesAmount > chosenArt.availableBattlesCount) {
            warningMessage += "Взято " + chosenArt.name + " на " + chosenArt.availableBattlesCount + " боев;\n";
        }
    }
    for (const missingArtName of artData.missingArts) {
        warningMessage += missingArtName + " недоступен;\n";
    }
    consequetiveFetches(neededLinks, () => { location.href = location.origin + redirectTo });
    warningMessage !== "" && alert(warningMessage);
}

const parser = new DOMParser();


function getArtList(HTMLText) {

    const arts = [];
    const doc = parser.parseFromString(HTMLText, 'text/html');
    const tbody = doc.querySelector("body > center > table:nth-child(2) > tbody > tr > td > table:nth-child(3) > tbody > tr > td > table > tbody");
    for (const tr of tbody.children) {
        const nameEle = tr.querySelector("font");
        if (!nameEle) continue;
        let name = nameEle.textContent.match(/\'(.*?)\'/);
        // const _dura = nameEle.textContent.match(/(\d+)\//)[1];
        if (!name) {
            console.log(tr);
            console.error("Название арта не найдено");
            continue;
        }
        name = name[1];
        // name = name.split("[")[0].trim();
        name = name.trim();

        const button = tr.querySelector("input[value='Взять в аренду']");
        if (!button) continue;
        const artId = button.id.match(/\d+/)[0];
        const sign = tr.querySelector("input[name='sign']").value;
        const category = tr.querySelector("input[name='cat']").value;
        const availableBattlesCount = tr.querySelector("select").children.length;
        arts.push({ name: name, artId: artId, sign: sign, category: category, availableBattlesCount: availableBattlesCount, taken: false });
    }
    return arts;
}

function getRentLink(origin, artId, sign, category, battlesAmount) {
    const link = origin + "&sign=" + sign + "&cat" + category + "&action=rent&inv_id=" + artId + "&set_id=0&bcnt" + artId + "=" + battlesAmount;
    return link;
}
document.addEventListener("input", event => {
    if (!["set_list", "set_name"].includes(event.target.className)) return;
    event.target.style.height = "auto";
    event.target.style.height = `${event.target.scrollHeight+2}px`;
});
const attachTo = document.querySelector("body > center > table:nth-child(2) > tbody > tr > td > table:nth-child(1) > tbody > tr:nth-child(1) > td:nth-child(1)");
attachTo.insertAdjacentHTML("afterbegin", stylesHTML + setParentHTML);
const parent = document.querySelector("#set_parent");
let sets = localStorage.getItem("depoScript1_sets");
let names = localStorage.getItem("depoScript1_set_names");

if (!sets) sets = JSON.parse(defaultSets);
else sets = JSON.parse(sets);
if (!names) names = JSON.parse(defaultNames);
else names = JSON.parse(names);

console.log("sets", sets);
for (let i = 0; i < setAmount; i++) {
    const test = sets[i + 1];
    const set = test ? test.toString() : "";
    const test2 = names[i + 1];
    const name = test2 ? test2.toString() : "";

    const setHTML = `
<div class="set_container">
    <span>${i+1}. </span>
    <textarea class = "set_name" placeholder = "Навание комплекта" rows="2" cols="3">${name}</textarea>
    <textarea class="set_list" placeholder="Список артефактов через запятую, альтернативы через ||. Пример: Меч холода, Амулет холода || Клевер фортуны, Кольцо холода" cols="5" rows="3">${set}</textarea>
    <span> на </span>
    <select id = "set_select${i}" class="available_battles_count"></select>
    <span> боев </span>
    <button class="set_button"> Аренда </button>
</div>
`;
    parent.insertAdjacentHTML("beforeend", setHTML);
    console.log("check", document.querySelector(`#set_select${i}`));
    const select = document.querySelector(`#set_select${i}`);
    for (let i = 1; i <= 20; i++) {
        select.insertAdjacentHTML("beforeend", `<option value=${i}>${i}</option>`);
    }
}
[".set_list", ".set_name"].forEach(selector => {
    for (const textarea of document.querySelectorAll(selector)) {
        textarea.style.height = "auto";
        textarea.style.height = `${textarea.scrollHeight+2}px`;
    }
})
parent.insertAdjacentHTML("beforeend", saveButtonHTML);
document.querySelector("body > center > table:nth-child(2) > tbody > tr > td > table:nth-child(1) > tbody").textContent.includes("Ваша аренда") && draw_undress_button(document.querySelector("body > center > table:nth-child(2) > tbody > tr > td > table:nth-child(1) > tbody > tr:nth-child(3) > td"));
document.addEventListener("click", event => {
    const ele = event.target;
    if (ele.className === "set_button") {
        const areaText = ele.parentElement.querySelector(".set_list").value;
        const battlesAmount = ele.parentElement.querySelector(".available_battles_count").selectedIndex + 1;
        let requiredArts = areaText.split(",");
        for (let i = 0; i < requiredArts.length; i++) {
            requiredArts[i] = requiredArts[i].trim();
        }
        requiredArts = requiredArts.filter(artName => { return artName !== "" && artName !== " " });
        ele.textContent = " Загрузка... ";
        fetchDataAndProcess(requiredArts, battlesAmount);
    }
    if (ele.id === "save_button") {
        const dict = {};
        const names = {};
        for (const setTextArea of document.querySelectorAll(".set_list")) {
            const areaNo = setTextArea.parentElement.querySelector("span").textContent.match(/\d+/)[0];
            dict[areaNo] = setTextArea.value;
        }
        for (const nameTextArea of document.querySelectorAll(".set_name")) {
            const areaNo = nameTextArea.parentElement.querySelector("span").textContent.match(/\d+/)[0];
            names[areaNo] = nameTextArea.value;
        }
        // set_name
        console.log(dict);
        localStorage.setItem("depoScript1_sets", JSON.stringify(dict));
        localStorage.setItem("depoScript1_set_names", JSON.stringify(names));

    }
});