MIRPriceHelperPlus

生产成本快速计算(改)

// ==UserScript==
// @name         MIRPriceHelperPlus
// @description  生产成本快速计算(改)
// @namespace    mirror
// @version      0.1.1.1
// @author       玛吉卡帕瓦 - 柔风海湾(原)/Toumei99改
// @match        https://5p.nbbjack.com/
// @require      https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    function ext_getValue(key, default_value) {
        let val = window.localStorage.getItem(key);
        if (val === undefined || val === null) {
            return default_value;
        }
        try {
            val = JSON.parse(val);
            if (val == '[]') {
                val = []
            }
            return val;
        } catch (err) {
            console.trace(err);
            return val;
        }
    }

    function ext_setValue(key, val) {
        return window.localStorage.setItem(key, JSON.stringify(val));
    }

    const delay = (t) => {
        return new Promise((r) => {
            setTimeout(()=>{
            r();
            }, t*1000)
        })
    }

    let queryMap = {};
    async function queryJSON(url) {
        if (!queryMap[url]) {
            const req = new Promise(async (resolve, reject) => {
                console.log(url);
                let tryCount = 0;
                const maximumTryCount = 5;
                while (1) {
                    tryCount ++;
                    try {
                        let res = await (await fetch(url)).json()
                        resolve(res)
                        return;
                    } catch (err) {
                        if (tryCount >= maximumTryCount) {
                            delete queryMap[url];
                            reject(new Error());
                            return;
                        } else {
                            await delay(1);
                        }
                    }
                }
            });
            queryMap[url] = req;
        }
        return queryMap[url];
    }

    let itemNameMapItem = ext_getValue("mir.itemNameMapItem", {});
    let itemIdMapItem = ext_getValue("mir.itemIdMapItem", {});
    async function queryItemByName(itemName) {
        if (itemNameMapItem[itemName]) {
            console.log(itemNameMapItem[itemName]);
            return itemNameMapItem[itemName];
        }
        const api = `https://cafemaker.wakingsands.com/search?indexes=item&string=${itemName}`;
        const allList = (await queryJSON(api)).Results;
        let items = [];
        allList.forEach((item) => {
            let aItem = {
                'id': item.ID, 'name': item.Name, 'icon': `https://cafemaker.wakingsands.com${item.Icon}`
            };
            items.push(aItem);
            itemIdMapItem[item.ID] = aItem;
        });
        console.log(items);
        ext_setValue("mir.itemIdMapItem", itemIdMapItem);
        itemNameMapItem[itemName] = items;
        ext_setValue("mir.itemNameMapItem", itemNameMapItem);
        return items;
    }

    async function queryItemById(itemId) {
        if (itemIdMapItem[itemId]) {
            console.log(itemIdMapItem[itemId]);
            return itemIdMapItem[itemId];
        }
        const api = `https://cafemaker.wakingsands.com/item/${itemId}`;
        const dict = (await queryJSON(api));
        let item = {
            'id': itemId, 'name': dict.Name_chs, 'icon': `https://cafemaker.wakingsands.com${dict.Icon}`
        };
        console.log(item);
        itemIdMapItem[itemId] = item;
        ext_setValue("mir.itemIdMapItem", itemIdMapItem);
        itemNameMapItem[item.name] = item;
        ext_setValue("mir.itemNameMapItem", itemNameMapItem);
        return item;
    }

    let itemServerListingMapPrice = ext_getValue("mir.itemServerListingMapPrice", {});
    const cacheTime = 10*60*1000;   // 10min
    let worldName = ext_getValue('mir.worldName', '宇宙和音');
    let serverName = ext_getValue('mir.serverName', '陆行鸟');
    const listingCount = 1;
    async function queryPriceByItemId(itemId) {
        let key = `${itemId}-${worldName}-${serverName}-${listingCount}`;
        if (itemServerListingMapPrice[key]) {
            let cachePrice = itemServerListingMapPrice[key];
            if (new Date().getTime() - cachePrice.timestamp < cacheTime) {
                console.log('cache price', cachePrice);
                return cachePrice;
            }
        }
        // const api = `https://universalis.app/api/v2/${serverName}/${itemId}?noGst=true&listings=${listingCount}`;
        const api = `https://universalis.app/api/v2/${serverName}/${itemId}?noGst=true`;
        const allList = (await queryJSON(api));

        let listingItems = [];
        let historyItems = [];
        let lowestItem = null;
        console.log(allList);
        allList.listings.forEach((item) => {
            let aItem = {
                'worldName': item.worldName,
                'pricePerUnit': item.pricePerUnit,
                'timestamp': item.lastReviewTime
            };
            if (aItem.worldName === worldName) {
                listingItems.push(aItem);
            }
            if (!lowestItem || lowestItem.pricePerUnit > aItem.pricePerUnit) {
                lowestItem = aItem;
            }
        });
        allList.recentHistory.forEach((item) => {
            historyItems.push({
                'worldName': item.worldName,
                'pricePerUnit': item.pricePerUnit,
                'timestamp': item.timestamp
            });
        });
        listingItems = listingItems.sort((a, b) => {return a.pricePerUnit - b.pricePerUnit});
        historyItems = historyItems.sort((a, b) => {return a.pricePerUnit - b.pricePerUnit});
        const price =  {
            "timestamp": new Date().getTime(),
            "itemId": itemId,
            "itemName": itemIdMapItem[itemId].name,
            "listing": listingItems,
            "history": historyItems,
            "lowest": lowestItem
        };
        itemServerListingMapPrice[key] = price;
        ext_setValue("mir.itemServerListingMapPrice", itemServerListingMapPrice);
        return price;
    }

    async function queryPriceByItemName(itemName) {
        const items = await queryItemByName(itemName);
        if (!items || items.length == 0) {
            return null;
        }
        const item = items[0];
        const price = await queryPriceByItemId(item.id);
        return price;
    }

    $('body').prepend(`
        <style>
        .mir-nav {
            float: right;
        }

        .mir-wrapper {
            color: #DED7BE;
            text-shadow: -1px 0 2px #795516, 0 1px 2px #795516, 1px 0 2px #795516, 0 -1px 2px #795516;
            font-family: "Meiryo";
            white-space: nowrap;
            margin: 0 5px;
        }

        .mir-price-wrapper {
            float: right;
        }

        .mir-sum-wrapper {
            border: 1px solid #DED7BE;
            margin: 0 0 0 20px;
            padding: 1px 5px;
            text-align: center;
        }
        </style>
    `)

    let serverWorldMap = {
        '猫小胖': ['紫水栈桥', '延夏', '静语庄园', '摩杜纳', '海猫茶屋', '柔风海湾', '琥珀原'],
        '莫古力': ['白银乡', '白金幻象', '神拳痕', '潮风亭', '旅人栈桥', '拂晓之间', '龙巢神殿', '梦羽宝境'],
        '陆行鸟': ['红玉海', '神意之地', '拉诺西亚', '幻影群岛', '萌芽池', '宇宙和音', '沃仙曦染', '晨曦王座'],
        '豆豆柴': ['水晶塔', '银泪湖', '太阳海岸', '伊修加德', '红茶川'],
    };

    setInterval(() => {
        if ($('#top .mir-nav').length <= 0) {
            $('#top').append(`<div class='mir-nav'></div>`);
            const wrapper = $('#top .mir-nav');
            function serverSelect() {
                let html = `<select class="mir-server-select">`;
                Object.keys(serverWorldMap).forEach(name => {
                    html += `<option value="${name}" ${(name == serverName) ?'selected="selected"' :''}>${name}</option>`;
                });
                html += `</select>`;
                return html;
            }

            function worldSelect(serverName) {
                let html = `<select class="mir-world-select">`;
                serverWorldMap[serverName].forEach(name => {
                    html += `<option value="${name}" ${(name == worldName) ?'selected="selected"' :''}>${name}</option>`;
                });
                html += `</select>`;
                return html;
            }
            wrapper.append(serverSelect());
            wrapper.append(worldSelect(serverName));

            function onServerChange() {
                serverName = $('.mir-server-select').val();
                ext_setValue('mir.serverName', serverName);
                console.log(`${serverName}`);

                $(".mir-world-select").remove();
                wrapper.append(worldSelect(serverName));
                $(".mir-world-select").change(onWorldChange);
                onWorldChange();
            }

            function onWorldChange() {
                worldName = $(".mir-world-select").val();
                ext_setValue('mir.worldName', worldName);
                console.log(`${worldName}`);
            }

            $(".mir-server-select").change(onServerChange);
            $(".mir-world-select").change(onWorldChange);
        }

        $('.ivu-modal-body .copyname').each(async function(){
            const itemName = $(this).text();
            const parent = $(this).parents('li')[0];
            if ($(parent).find('.mir-price-wrapper').length <= 0) {
                $(parent).append(`<div class="mir-wrapper mir-price-wrapper"><span class="mir-world">...</span><span>|</span><span class="mir-server">...</span></div>`);
                const wrapper = $(parent).find('.mir-price-wrapper');
                queryPriceByItemName(itemName).then((price) => {
                    if (!price) {
                        return;
                    }
                    if (price.listing && price.listing.length > 0) {
                        wrapper.find('.mir-world').text(price.listing[0].pricePerUnit);
                    } else {
                        console.log(price);
                        wrapper.find('.mir-world').text('无记录');
                    }
                    if (price.lowest) {
                        wrapper.find('.mir-server').text(`${price.lowest.pricePerUnit}(${price.lowest.worldName.substr(0, 1)})`);
                    } else {
                        console.log(price);
                        wrapper.find('.mir-server').text('无记录');
                    }
                });
            };
            if (!$(parent).hasClass('mir-item')) {
                $(parent).addClass('mir-item');
            }
        });

        $('.ivu-modal-body .treeview').children('ul').each(function(){
            if ($(this).find('.mir-sum-wrapper').length <= 0) {
                $(this).append('<div class="mir-wrapper mir-sum-wrapper">总计: ......</div>');
            }
            const wrapper = $(this).find('.mir-sum-wrapper');

            let worldSum = 0;
            let worldNoCount = 0;
            let serverSum = 0;
            let serverNoCount = 0;
            let itemCount = 0;
            $(this).find('.mir-item').each(function(){
                itemCount++;
                let count = 1;
                const countText = $(this).find('.copyname').parent().next().text();
                if (countText.length > 0 && countText.indexOf('x') >= 0) {
                    count = parseInt(countText.substr(countText.indexOf('x') + 1));
                }
                $(this).find('.mir-world').each((_, elem) => {
                    if ($(elem).text() === '无记录') {
                        worldNoCount ++; return;
                    }
                    worldSum += parseInt($(elem).text()) * count;
                });
                $(this).find('.mir-server').each((_, elem) => {
                    if ($(elem).text() === '无记录') {
                        serverNoCount ++; return;
                    }
                    serverSum += parseInt($(elem).text()) * count;
                });
            });
            if (itemCount > 0) {
                wrapper.text(`总计: ${worldSum}${worldNoCount > 0 ?`(${worldNoCount}项无记录)` :''}  |  ${serverSum}${serverNoCount > 0 ?`(${serverNoCount}项无记录)` :''}`);
            } else {
                wrapper.text('');
            }
        });

        $('.ivu-row-flex .copyname').each(async function(){
            const itemName = $(this).text();
            const parent = $(this).parents('li')[0];
            if ($(parent).find('.mir-price-wrapper').length <= 0) {
                $(parent).append(`<div class="mir-wrapper mir-price-wrapper"><span class="mir-world">...</span><span>|</span><span class="mir-server">...</span></div>`);
                const wrapper = $(parent).find('.mir-price-wrapper');
                queryPriceByItemName(itemName).then((price) => {
                    if (!price) {
                        return;
                    }
                    if (price.listing && price.listing.length > 0) {
                        wrapper.find('.mir-world').text(price.listing[0].pricePerUnit);
                    } else {
                        console.log(price);
                        wrapper.find('.mir-world').text('无记录');
                    }
                    if (price.lowest) {
                        wrapper.find('.mir-server').text(`${price.lowest.pricePerUnit}(${price.lowest.worldName.substr(0, 1)})`);
                    } else {
                        console.log(price);
                        wrapper.find('.mir-server').text('无记录');
                    }
                });
            };
            if (!$(parent).hasClass('mir-item')) {
                $(parent).addClass('mir-item');
            }
        });

        $('.ivu-row-flex .treeview').children('ul').each(function(){
            if ($(this).find('.mir-sum-wrapper').length <= 0) {
                $(this).append('<div class="mir-wrapper mir-sum-wrapper">总计: ......</div>');
            }
            const wrapper = $(this).find('.mir-sum-wrapper');

            let worldSum = 0;
            let worldNoCount = 0;
            let serverSum = 0;
            let serverNoCount = 0;
            let itemCount = 0;
            $(this).find('.mir-item').each(function(){
                itemCount++;
                let count = 1;
                const countText = $(this).find('.copyname').parent().next().text();
                if (countText.length > 0 && countText.indexOf('x') >= 0) {
                    count = parseInt(countText.substr(countText.indexOf('x') + 1));
                }
                $(this).find('.mir-world').each((_, elem) => {
                    if ($(elem).text() === '无记录') {
                        worldNoCount ++; return;
                    }
                    worldSum += parseInt($(elem).text()) * count;
                });
                $(this).find('.mir-server').each((_, elem) => {
                    if ($(elem).text() === '无记录') {
                        serverNoCount ++; return;
                    }
                    serverSum += parseInt($(elem).text()) * count;
                });
            });
            if (itemCount > 0) {
                wrapper.text(`总计: ${worldSum}${worldNoCount > 0 ?`(${worldNoCount}项无记录)` :''}  |  ${serverSum}${serverNoCount > 0 ?`(${serverNoCount}项无记录)` :''}`);
            } else {
                wrapper.text('');
            }
        });

         $('.ivu-row-flex .item-list').each(function(){
            if ($(this).find('.mir-sum-wrapper').length <= 0) {
                $(this).append('<div class="mir-wrapper mir-sum-wrapper" style="margin-top:50px">总计: ......</div>');
            }
            const wrapper = $(this).find('.mir-sum-wrapper');

            let worldSum = 0;
            let worldNoCount = 0;
            let serverSum = 0;
            let serverNoCount = 0;
            let itemCount = 0;
            $(this).find('.mir-item').each(function(){
                itemCount++;
                let count = 1;
                const countText = $(this).find('.copyname').parent().next().text();
                if (countText.length > 0 && countText.indexOf('x') >= 0) {
                    count = parseInt(countText.substr(countText.indexOf('x') + 1));
                }
                $(this).find('.mir-world').each((_, elem) => {
                    if ($(elem).text() === '无记录') {
                        worldNoCount ++; return;
                    }
                    worldSum += parseInt($(elem).text()) * count;
                });
                $(this).find('.mir-server').each((_, elem) => {
                    if ($(elem).text() === '无记录') {
                        serverNoCount ++; return;
                    }
                    serverSum += parseInt($(elem).text()) * count;
                });
            });
            if (itemCount > 0) {
                wrapper.text(`总计: ${worldSum}${worldNoCount > 0 ?`(${worldNoCount}项无记录)` :''}  |  ${serverSum}${serverNoCount > 0 ?`(${serverNoCount}项无记录)` :''}`);
            } else {
                wrapper.text('');
            }
        });
    }, 1000);
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址