您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
This script sorts NPC shops prices by profit.
// ==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(); } }