Subeta Sorting

This script sorts NPC shops prices by profit.

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

You will need to install an extension such as Tampermonkey to install this script.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==UserScript==
// @name         Subeta Sorting
// @namespace    http://artees.pw/
// @description  This script sorts NPC shops prices by profit.
// @version      1.8
// @author       Artees
// @match        *://subeta.net/shop.php?shop*
// @require      https://greasyfork.org/scripts/30529-subeta-searching/code/Subeta%20Searching.js?version=203734
// @grant        none
// @icon         https://subeta.net/favicon.ico
// @icon64       https://img.subeta.net/items/bottle_apothecary_06.gif
// ==/UserScript==

const KEY_MIN_PROFIT = "minProfit",
    KEY_MAX_ITEMS = "maxItems",
    KEY_BUYING = "buying",
    KEY_SHOP_URL = "shopUrl";

var curItem = parseItemsForSorting(),
    sortedItems = [],
    minProfit = getFromStorage(localStorage, KEY_MIN_PROFIT, 0),
    maxItems = getFromStorage(localStorage, KEY_MAX_ITEMS, 10),
    buyCountdown = null,
    isBuying = getFromStorage(localStorage, KEY_BUYING, false),
    buyingIntervalId = 0,
    buyingTimeoutId = 0,
    isSortingComplete = false,
    pricedCount = 0;

function parseItemsForSorting() {
    var itemDivs = document.getElementsByClassName("two wide column");
    if (itemDivs.length === 0 || itemDivs[0].getElementsByTagName("form").length === 0) return null;
    function getPriceField(itemDiv) {
        return new PriceField(itemDiv);
    }
    return parseItems(itemDivs, getPriceField);
}

function Item(itemDiv, priceField) {
    var start = itemDiv.innerHTML.indexOf("<br>"),
        end = itemDiv.innerHTML.indexOf("<br>", start + 4);
    this.itemDiv = itemDiv;
    this.name = replaceAll(itemDiv.innerHTML.substring(start + 4, end), "	", "");
    this.name = replaceAll(this.name, "\n", "");
    this.cacheKey = "c " + this.name;
    this.next = null;
    this.isPriced = false;
    this.priceField = priceField;
    this.resetPrice = function () {
        var end = this.priceField.value.indexOf(CY) + CY.length;
        return this.priceField.value.substring(0, end);
    };
    this.priceField.value = this.resetPrice();
    this.getPrice = function () {
        var priceString = replaceAll(this.resetPrice(), ",", "");
        return parseInt(priceString);
    };
    this.actualPrice = this.getPrice();
    var isComplete = true;
    this.onSelect = function() {
        isComplete = true;
        forEachItem(getNext);
        if (isComplete) {
            isSortingComplete = true;
            switchBuying();
        }
        return !isComplete;
    };
    function getNext(i) {
        if (i === null || !i.isPriced) {
            curItem = i;
            isComplete = false;
            return false;
        }
        return true;
    }
}

function PriceField(itemDiv) {
    var label = itemDiv.getElementsByTagName("b")[0];
    return {
        get value() {
            return label.innerText;
        },
        set value(value) {
            label.innerText = value;
        },
        get style() {
            return label.style;
        },
        set style(value) {
            label.style = value;
        }
    };
}

createUI();

function createUI() {
    var s = document.getElementsByClassName("shop_item_container")[0];
    if (s === undefined) {
        goBackAfterBuying();
        return;
    }
    var ui = s.insertBefore(document.createElement("div"), s.firstChild);
    ui.appendChild(document.createTextNode("Delay: "));
    var itemDelayInput = document.createElement("INPUT");
    itemDelayInput.value = itemDelay + " sec.";
    itemDelayInput.onchange = function () {
        itemDelay = parseInt(this.value);
        localStorage[KEY_ITEM_DELAY] = itemDelay;
    };
    ui.appendChild(itemDelayInput);
    ui.appendChild(createSpace());
    var button = document.createElement("a");
    button.className = "ui button tiny";
    button.innerText = "Purge Cache";
    button.onclick = function () {
        forEachItem(function (i) {
            localStorage.removeItem(i.cacheKey);
            location.reload();
            return true;
        });
    };
    ui.appendChild(button);
    ui.appendChild(document.createElement("br"));
    var autobuy = document.createElement("input");
    autobuy.type = "checkbox";
    autobuy.checked = isBuying;
    autobuy.onchange = function () {
        isBuying = this.checked;
        localStorage[KEY_BUYING] = isBuying;
        switchBuying();
    };
    ui.appendChild(autobuy);
    ui.appendChild(document.createTextNode(" Autobuy"));
    ui.appendChild(createSpace());
    ui.appendChild(document.createTextNode("Min profit: "));
    var minProfitInput = document.createElement("INPUT");
    minProfitInput.value = minProfit + CY;
    minProfitInput.onchange = function () {
        minProfit = parseInt(this.value);
        localStorage[KEY_MIN_PROFIT] = minProfit;
        switchBuying();
    };
    ui.appendChild(minProfitInput);
    ui.appendChild(createSpace());
    ui.appendChild(document.createTextNode("Number of items: "));
    var maxItemsInput = document.createElement("INPUT");
    maxItemsInput.value = maxItems;
    maxItemsInput.onchange = function () {
        maxItems = parseInt(this.value);
        localStorage[KEY_MAX_ITEMS] = maxItems;
        switchBuying();
    };
    ui.appendChild(maxItemsInput);
    ui.appendChild(createSpace());
    buyCountdown = document.createTextNode("Disabled");
    ui.appendChild(buyCountdown);
}

loadCache();

function loadCache() {
    forEachItem(function (i) {
        if (i === null) return false;
        if (localStorage[i.cacheKey] !== undefined) {
            var profit = getFromStorage(localStorage, i.cacheKey, 0) - i.getPrice();
            setProfit(i, profit);
        }
        return true;
    });
    sortPrices();
}

function setProfit(item, profit) {
    item.priceField.value = profit + CY;
    item.priceField.style.color = profit > 0 ? "green" : "red";
    item.isPriced = true;
    pricedCount++;
}

if (curItem !== null && curItem.onSelect()) {
    search();
}

function filterPrices(prices) {
    if (prices.length > 0) {
        for (var i = 0; i < prices.length; i++) {
            var price = prices[i];
            if (price.isNPC()) continue;
            localStorage[curItem.cacheKey] = price.valueOf();
            var profit = price.valueOf() - curItem.getPrice();
            setProfit(curItem, profit);
            break;
        }
    } else {
        curItem.priceField.value = "(!) " + curItem.resetPrice() + CY;
        curItem.priceField.style.color = "orange";
    }
    sortPrices();
}

function sortPrices() {
    sortedItems = [];
    forEachItem(function (i) {
        if (i === null) return false;
        sortedItems.push(i);
        return true;
    });
    sortedItems.sort(comparePrices);
    function comparePrices(a, b) {
        if (!b.isPriced) return -1e100;
        if (!a.isPriced) return 1e100;
        return b.getPrice() - a.getPrice();
    }
    for (var i = 0; i < sortedItems.length; i++) {
        sortedItems[i].itemDiv.parentNode.appendChild(sortedItems[i].itemDiv);
    }
    switchBuying();
}

function switchBuying() {
    if (buyCountdown === null) return;
    highlightItems();
    function highlightItems() {
        for (var i = 0; i < sortedItems.length; i++) {
            var item = sortedItems[i];
            item.priceField.style.fontWeight =
                (item.isPriced && item.getPrice() < minProfit) ? "normal" : "bold";
        }
    }
    var item = getMostProfitableItem();
    function getMostProfitableItem() {
        var spText = document.getElementsByClassName("widget-login-sp")[0].innerText,
            sp = parseInt(replaceAll(spText, ",", ""));
        for (var i = 0; i < sortedItems.length; i++) {
            if (sortedItems[i].actualPrice <= sp) {
                return sortedItems[i];
            }
        }
        return null;
    }
    if (!isBuying || !isSortingComplete || maxItems <= 0 || item === null ||
        item.getPrice() < minProfit) {
        clearInterval(buyingIntervalId);
        clearTimeout(buyingTimeoutId);
        if (isBuying && isSortingComplete && maxItems > 0 && item !== null) {
            buyCountdown.data = "Go to random shop...";
            goToNextShop();
        }
        else {
            buyCountdown.data =
                (isSortingComplete || !isBuying) ? "Disabled" : getProgress();
        }
        if (item === null) {
            buyCountdown.data = "Not enough sP!";
        }
        return;
    }
    function getProgress() {
        var k = 8,
            p = Math.floor(pricedCount/k),
            l = Math.floor(sortedItems.length/k) - p;
        return "Sorting " + new Array(p).join("█") + new Array(l).join("░");
    }
    var count = 5;
    buyCountdown.data = count.toString();
    buyingIntervalId = setInterval(buyItem, 1000);
    function buyItem() {
        count--;
        buyCountdown.data = count.toString();
        if (count > 0) return;
        clearInterval(buyingIntervalId);
        buyCountdown.data = "Buying...";
        sessionStorage[KEY_SHOP_URL] = location.href;
        buyingTimeoutId = setTimeout(click, 1000);
        function click() {
            maxItems--;
            localStorage[KEY_MAX_ITEMS] = maxItems;
            item.itemDiv.getElementsByClassName("ui image")[0].click();
        }
    }
}

function goToNextShop() {
    var shops = [36, 31, 28, 30, 32, 41, 11, 14, 34, 6, 29, 37, 16, 5, 19, 2, 22, 46, 49, 40,
            24, 45, 26, 23, 12, 44, 27, 39, 42, 9, 21, 4, 17, 20, 47, 25],
        url = location.href.split("="),
        iNext = Math.floor(Math.random()*shops.length),//shops.indexOf(parseInt(url[1])) + 1,
        next = url[0] + "=" + shops[(iNext >= shops.length) ? 0 : iNext].toString();
    open(next, "_self");
}

function goBackAfterBuying() {
    var url = sessionStorage[KEY_SHOP_URL];
    if (url === undefined) return;
    sessionStorage.removeItem(KEY_SHOP_URL);
    open(url, "_self");
}

onComplete();

function onComplete() {
    if (document.body.textContent.indexOf("There are no items stocked") > -1) {
        goToNextShop();
    }
}