什么值得买 自动计算单价

在什么值得买搜索页面、首页及关注动态等页面,自动计算单价

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

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

(I already have a user script manager, let me install it!)

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.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name        什么值得买 自动计算单价
// @namespace   leizingyiu.net
// @version     2022.08.07
// @description 在什么值得买搜索页面、首页及关注动态等页面,自动计算单价
// @icon        https://www.smzdm.com/favicon.ico
// @author      Leizingyiu
// @include     *://search.smzdm.com/*
// @include     *://www.smzdm.com/
// @include     *://www.smzdm.com/#follow
// @include     *://wiki.smzdm.com/*
// @grant       GM_setValue
// @grant       GM_getValue
// @license     GNU AGPLv3 
// 
// ==/UserScript==


function checkAndSetLocalValue(key, value) {
    const checking_local_reagent = "___";
    if (GM_getValue(key, checking_local_reagent) == checking_local_reagent) {
        GM_setValue(key, value);
    } else {
        GM_setValue("备份_" + key, GM_getValue(key));
    }
}

const checking_local_reagent = "___",
    local_words_key = "请填写需要计算的关键字",
    default_words = "包 条 个 袋 杯 枚 颗 罐 公斤 斤 两 盒 桶";
checkAndSetLocalValue(local_words_key, default_words);

var words = GM_getValue(local_words_key, default_words)
    .split(/\s{1,}/)
    .filter((a) => Boolean(a)),
    wordsReg = new RegExp(
        "\\d[\\d\\.]*s*(" +
        (words.map((word) => `(${word})`).join("|") + ")\\s*(\\*\\d{1,})*")
    ),
    textReplaceReg = /(\([^\)]*\))|(\[[^\]]*\])|(「[^」]*」)|(([^)]*))/g,
    priceReg = /\d[\d.]*\s*(?=元)/,
    gramReg =
        /\d[\d.]*\s*(([千克]{1,})|(((kg)|(KG)|(Kg)|(g)|(G)){1,}))\s*(\*\d{1,})*/,
    volReg = /\d[\d.]*\s*(([毫升]{1,})|((L)|(ml)|(ML){1,}))\s*(\*\d{1,})*/,
    loadingWaitTime = 1000;

const default_conditions = {
    "挂面 面条": {
        "大于": "",
        "小于": "6",
        "单位": "kg"
    },
}, local_conditions_key = "高亮条件";

checkAndSetLocalValue(local_conditions_key, default_conditions);

const localConditions = GM_getValue(local_conditions_key, default_conditions);
const hiliConditions = Object.keys(localConditions).map(k => {
    let O = localConditions[k], o = {};
    o.match = typeof k == 'string' ? new RegExp('(' + k.split(/\s{1,}/).filter((a) => Boolean(a)).map((word) => `(${word})`).join("|") + ')') : (k instanceof RegExp ? condition.match : '');
    if (o.match === '') { return false; };
    const dict = {
        "大于": "moreThan",
        "小于": "lessThan",
        "单位": "unit"
    };
    ["大于", "小于", "单位"].map(_k => {
        if (O.hasOwnProperty(_k) && O[_k] != "" && (O[_k].match(/\S/))) { o[dict[_k]] = O[_k].match(/[^\d]/g) ? O[_k] : Number(O[_k]) }
    });
    return o;
}).filter(Boolean);


const default_less_style = 'background:#dcf9d7;', default_more_style = 'background:#fde9f0;',
    local_less_key = '低于价格高亮样式', local_more_key = '高于价格高亮样式';

checkAndSetLocalValue(local_less_key, default_less_style);
checkAndSetLocalValue(local_more_key, default_more_style);

const local_less_value = GM_getValue(local_less_key, default_less_style),
    local_more_value = GM_getValue(local_more_key, default_more_style);

const lessThanClass = 'yiu_lessthan', moreThanClass = 'yiu_morethan';
let yiuUnitPriceStyle = document.createElement('style');
yiuUnitPriceStyle.id = 'yiu_unit_price_style';
yiuUnitPriceStyle.innerHTML = `
.yiu_price{ float : right!important; }
.yiu_lessthan .yiu_price{ ${local_less_value} }
.yiu_morethan .yiu_price{ ${local_more_value} }
`;
document.querySelector('body').appendChild(yiuUnitPriceStyle);

function smzdm_unitPrice() {
    var isFollow = window.location.href.indexOf("#follow") != -1,
        isHomePage =
            window.location.hostname == "www.smzdm.com" &&
            window.location.href.indexOf("#follow") == -1,
        isSearch = window.location.hostname.indexOf("search") != -1;
    var selector = "";
    switch (true) {
        case isHomePage:
            selector = "#feed-main-list .has-price";
            break;
        case isSearch:
            selector = "#feed-main-list h5.feed-block-title";
            break;
        case isFollow:
            selector = "#follow-list h5.feed-block-title";
            break;
        default:
            selector = "h5.feed-block-title";
    }
    [...document.querySelectorAll(selector)]
        .filter((dom) => !dom.hasAttribute("yiu_price_calculated"))
        .map(function (dom) {
            var priceDom = isHomePage
                ? dom.parentElement.querySelector(".z-highlight")
                : dom.querySelector(".z-highlight"),
                pre_text = isHomePage
                    ? dom.innerText + "\n" + priceDom.innerText
                    : dom.innerText,
                text = pre_text.replace(textReplaceReg, ""),
                price = text.match(priceReg),
                gram = text.match(gramReg),
                vol = text.match(volReg);
            var otherUnit = text.match(wordsReg);
            var unit = "",
                num = 0,
                priceText = "",
                priceKg,
                priceL,
                priceU;
            if (price == null || (gram == null && vol == null && otherUnit == null)) {
                priceText = "--";
            } else {
                price = Number(price[0]);


                if (gram != null) {
                    gram = Number(
                        eval(gram[0].replace(/[克gG]/g, "").replace(/[kK千]/, "*1000"))
                    );
                    priceKg = (price / gram) * 1000;
                    priceText += priceKg.toFixed(2) + "/kg";
                }
                if (vol != null) {
                    vol = Number(
                        eval(vol[0].replace(/[升lL]/g, "").replace(/[毫mM]/, "/1000"))
                    );
                    priceL = price / vol;
                    priceText = (gram != null ? " | " : "") + priceL.toFixed(2) + "/L";
                }

                if (otherUnit != null) {
                    num = Number(otherUnit[0].match(/\d*/));
                    unit = otherUnit[0].replace(/\d*/, "");
                    priceU = price / num;
                    priceText +=
                        (gram != null || vol != null ? " | " : "") +
                        priceU.toFixed(2) +
                        "/" +
                        unit;
                    if (unit == "斤") {
                        priceKg = (priceU * 2).toFixed(2)
                        priceText += " | " + priceKg + "/kg";
                    }
                    if (unit == "两") {
                        priceKg = (priceU * 20).toFixed(2);
                        priceText += " | " + priceKg + "/kg";
                    }
                }


                if (priceText == "") {
                    priceText += "___";
                }

                switch (true) {
                    case priceText.indexOf('/kg') != -1:
                        dom.setAttribute('data-kg', priceKg)
                        break;
                    case priceText.indexOf('/L') != -1:
                        dom.setAttribute('data-L', priceL);
                        break;
                    default:
                        dom.setAttribute('data-price', priceU);
                }
            }

            hiliConditions.map(condition => {
                if (text.match(condition.match)) {
                    let _price = '';
                    if (condition.hasOwnProperty('unit')) {
                        _price = dom.hasAttribute(`data-${condition.unit}`) ? dom.getAttribute(`data-${condition.unit}`) : '';
                    } else {
                        _price = dom.getAttribute('data-price');
                    }
                    if (_price == '') { return false; }
                    if (condition.hasOwnProperty('lessThan') && _price < condition.lessThan) { dom.classList.add(lessThanClass); }
                    if (condition.hasOwnProperty('moreThan') && _price < condition.moreThan) { dom.classList.add(moreThanClass); }
                }
            });

            priceDom.style.display = "block";
            if (isSearch) {
                priceDom.parentElement.style.width = "100%";
            }
            var span = document.createElement("span");
            span.classList.add('yiu_price');
            span.innerText = priceText;
            priceDom.appendChild(span);
            dom.setAttribute("yiu_price_calculated", true);
        });
}
const promiseIt = function (fn) {
    return new Promise((resolve, reject) => {
        fn();
        resolve();
    });
};
var timer = null;
const targetNode = document.querySelector("body"),
    config = { attributes: true, childList: true, subtree: true },
    callback = function (mutationsList, observer) {
        observer.disconnect();
        for (let mutation of mutationsList) {
            promiseIt(() => {
                smzdm_unitPrice();
            });
        }
        timer = timer
            ? null
            : setTimeout(() => {
                observer.disconnect();
                promiseIt(() => {
                    smzdm_unitPrice();
                });
                timer = null;
                observer.observe(targetNode, config);
            }, loadingWaitTime);
    },
    observer = new MutationObserver(callback);
observer.observe(targetNode, config);