Wish.com - Price filter & more edited.

Filtering by min/max price, allow hidding nsfw products, see reviews. Edited by Son_Of_Diablo, adding option to exclude shipping for prices and disable console logging.

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         Wish.com - Price filter & more edited.
// @namespace    http://tampermonkey.net/
// @version      4.0.SOD
// @description  Filtering by min/max price, allow hidding nsfw products, see reviews. Edited by Son_Of_Diablo, adding option to exclude shipping for prices and disable console logging.
// @original-author       Shuunen
// @author       Son_Of_Diablo
// @match        https://*.wish.com/*
// @require      http://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    log('wish price filter : init');

    var $ = jQuery.noConflict(true);
    var minPrice = parseInt(localStorage.abwMinPrice) || 0;
    var maxPrice = parseInt(localStorage.abwMaxPrice) || 1000;
    var minStars = parseInt(localStorage.abwMinStars) || 1;
    var hideNsfw = localStorage.abwHideNsfw !== 'false';
    // --- Added by Son_Of_Diablo --- //
    var enableLogging = localStorage.abwEnableLogging !== 'false';
    var includeShipping = localStorage.abwIncludeShipping !== 'false';
    // --- Added by Son_Of_Diablo --- //

    // Returns a function, that, as long as it continues to be invoked, will not
    // be triggered. The function will be called after it stops being called for
    // N milliseconds. If `immediate` is passed, trigger the function on the
    // leading edge, instead of the trailing.
    function debounce(func, wait, immediate) {
        var timeout;
        return function() {
            var context = this;
            var args = arguments;
            var later = function() {
                timeout = null;
                if (!immediate) func.apply(context, args);
            };
            var callNow = immediate && !timeout;
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
            if (callNow) func.apply(context, args);
        };
    }

    function fetchData(id, productEl, originalPicture) {
        log('will get data for', id);
        const url = 'https://www.wish.com/c/' + id;
        log('getting data for', id);
        fetch(url)
            .then((r) => r.text())
            .then((html) => {
            const dataMatches = html.match(/"aggregateRating" : ([\w\W\n]+"\n}),/gi);
            const dataStr = dataMatches[0];
            const data = JSON.parse('{' + dataStr.replace('},', '}').replace(/\n/g, '') + '}');
            const ratings = Math.round(data.aggregateRating.ratingValue * 100) / 100;
            const count = Math.round(data.aggregateRating.ratingCount);
            log(id, ': found a rating of', ratings, 'over', count, 'reviews :)');
            let roundedRatings = Math.round(ratings);
            let ratingsStr = '';
            while (roundedRatings--) {
                ratingsStr += '<img class="abw-star" src="https://cdn0.iconfinder.com/data/icons/small-n-flat/24/678064-star-20.png" />';
            }
            if (count > 0) {
                ratingsStr += '<hr> over ' + count + ' reviews';
            } else {
                ratingsStr = 'no reviews !';
            }
            productEl.find('.feed-details-row2').css('display', 'flex').css('align-items', 'center').html(ratingsStr);
            const shippingMatches = html.match(/"localized_shipping":\s{"localized_value":\s(\d)/i);
            const shippingFees = parseInt(shippingMatches[1]);
            log(id, ': shipping fees', shippingFees);
            const priceMatches = productEl.find('.feed-actual-price').text().match(/\d+/);
            const price = parseInt(priceMatches && priceMatches.length ? priceMatches[0] : 0);
            log(id, ': base price', price);
            const totalPrice = price + shippingFees;
            const priceEl = productEl.find('.feed-actual-price');
            if(includeShipping){
                priceEl.html(totalPrice + ' ' + getCurrency());
            }else{
                priceEl.html(price + ' ' + getCurrency());
            }
            const nsfwMatches = html.match(/sex|lingerie|crotch|masturbat|vibrator|bdsm|bondage|nipple/gi);
            if (nsfwMatches && nsfwMatches.length) {
                productEl.addClass('abw-nsfw');
            }
            showHideProduct(productEl, originalPicture);
        })
            .catch((error) => {
            log('did not managed to found ratings for product "' + id + '"' + error, true);
        });
    }

    var currency = null;
    function getCurrency(){
        if(currency){
            return currency;
        }
        $('.feed-actual-price').each(function(index, el){
            if(currency) {
                return;
            }
            var arr = el.textContent.replace(/\d+/, '_').split('_');
            if(arr.length === 2){
                log('currency found at iteration', index);
                currency = arr[1];
            }
        });
        log('detected currency :', currency);
        return currency;
    }

    var loadedUrl = '//main.cdn.wish.com/fd9acde14ab5/img/ajax_loader_16.gif?v=13';

    function getData(element) {
        const productEl = $(element.tagName ? element : element.currentTarget);
        if (productEl.hasClass('abw-with-data')) {
            log('product has already data');
            return;
        }
        productEl.addClass('abw-with-data');
        const image = productEl.find('a.display-pic');
        if (!image || !image[0]) {
            log('did not found image on product' + productEl, true);
            return;
        }
        var href = image.attr('href');
        if (!href) {
            log('did not found href on product' + productEl, true);
            return;
        }
        const id = href.split('/').reverse()[0];
        const originalPicture = image[0].style.backgroundImage;
        image[0].style.backgroundImage = 'url(' + loadedUrl + ')';
        image[0].style.backgroundSize = '10%';
        fetchData(id, productEl, originalPicture);
    }

    function getNextData() {
        const amount = 10;
        log('getting next', amount, 'items data');
        $('.feed-product-item:visible:not(.abw-with-data):lt(' + amount + ')').each((index, element) => {
            setTimeout(() => getData(element), index * 300);
        });
    }

    function showHideProduct(element, originalPicture) {
        const productEl = $(element);
        const priceEl = productEl.find('.feed-actual-price');
        var price = priceEl.text().replace(/\D/g, '');
        var nbStars = productEl.find('img.abw-star').size();
        var priceOk = price <= maxPrice;
        if(!price){
            log(productEl, true);
        }
        if (minPrice && minPrice > 0) {
            priceOk = priceOk && price >= minPrice;
        }

        if (priceOk && minStars && minStars > 0 && productEl.hasClass('abw-with-data')) {
            priceOk = nbStars >= minStars;
        }
        if (priceOk && hideNsfw && productEl.hasClass('abw-nsfw')) {
            priceOk = false;
        }
        if (originalPicture) {
            const image = productEl.find('a.display-pic');
            if (!image || !image[0]) {
                log('did not found image on product' + productEl, true);
                return;
            }
            image[0].style.backgroundImage = originalPicture;
            image[0].style.backgroundSize = '100%';
        }
        if (priceOk) {
            productEl.show('fast');
            if (!productEl.hasClass('abw-on-hover')) {
                productEl.addClass('abw-on-hover');
                productEl.hover(getData);
            }
        } else {
            productEl.hide('fast');
        }
    }

    function showHideProducts(event) {
        log('wish price filter : showHideProducts');
        setTimeout(hideUseless, 100);
        setTimeout(getNextData, 100);
        $('.feed-product-item').each((index, element) => {
            showHideProduct(element);
        });
    }

    // prepare a debounced function
    var showHideProductsDebounced = debounce(showHideProducts, 100);

    // activate when window is scrolled
    window.onscroll = showHideProductsDebounced;

    function hideUseless() {
        // hide products that can't be rated in order hsitory
        $('.transaction-expanded-row-item .rate-button').parents('.transaction-expanded-row-item').addClass('abw-has-rate');
        $('.transaction-expanded-row-item:not(.abw-has-rate)').remove();
        // delete useless marketing stuff
        $('.discount-banner, .product-name + .error, .urgency-inventory, .product-boost-rect, .header-hello, .badge-details, .faster-shipping-wrapper, #footer-like, #FixedNavBarWrapper').remove();
        // delete fake original prices
        $('.feed-crossed-price, .original-price, [class*="CrossedPrice"]').remove()
        // delete sms reminders
        $('.transaction-opt-in-banner, .sms-div, .sms-notification-request').remove()
    }

    setTimeout(hideUseless, 100);

    var html = '<div id="wish_tweaks_config" style="float:left; white-space: nowrap; margin-right:10px;display:flex;justify-content:space-between;align-items:center;font-weight: bold;font-size: 13px;font-family: sans-serif;color: white;background-color: steelblue;padding:6px 12px;border-radius: 5px;">';
    html += 'Min / Max Price : <input id="wtc_min_price" type="text" style="width: 30px; text-align: center; margin-left: 5px;">&nbsp;/<input id="wtc_max_price" type="text" style="width: 30px; text-align: center; margin-left: 5px; margin-right: 10px;">';
    html += 'Min stars : <input id="wtc_min_stars" type="text" style="width: 20px; text-align: center; margin: 0 5px;">&nbsp;';
    html += 'Hide nsfw : <input id="wtc_hide_nsfw" type="checkbox" checked style="margin: 0; height: 16px; width: 16px; margin: 0 5px;">';
    // --- Added by Son_Of_Diablo --- //
    html += 'Include Shipping : <input id="wtc_include_shipping" type="checkbox" checked style="margin: 0; height: 16px; width: 16px; margin: 0 5px;">';
    html += 'Enable logging : <input id="wtc_enable_logging" type="checkbox" checked style="margin: 0; height: 16px; width: 16px; margin: 0 5px;">';
    // --- Added by Son_Of_Diablo --- //
    html += '</div>';

    if ($('#header-left').length) {
        // insert controllers in v1 header
        $('#mobile-app-buttons').remove();
        $('#nav-search-input-wrapper').width(320);
        $('#header-left').after(html);
    } else if ($('.left.feed-v2').length) {
        // insert controllers in v2 header
        $('.left.feed-v2').before(html);
    } else {
        log('failed at inserting controllers', true)
    }

    // get elements
    var hideNsfwCheckbox = $('#wtc_hide_nsfw');
    var minStarsInput = $('#wtc_min_stars');
    var minPriceInput = $('#wtc_min_price');
    var maxPriceInput = $('#wtc_max_price');
    // --- Added by Son_Of_Diablo --- //
    var includeShipppingCheckbox = $('#wtc_include_shipping');
    var enableLoggingCheckbox = $('#wtc_enable_logging');
    // --- Added by Son_Of_Diablo --- //

    // restore previous choices
    hideNsfwCheckbox.attr('checked', hideNsfw);
    minStarsInput.val(minStars);
    // --- Added by Son_Of_Diablo --- //
    minPriceInput.val(minPrice);
    maxPriceInput.val(maxPrice);
    includeShipppingCheckbox.attr('checked', includeShipping);
    enableLoggingCheckbox.attr('checked', enableLogging);
    // --- Added by Son_Of_Diablo --- //

    // start filtering by default
    setTimeout(() => {
        showHideProductsDebounced();
        getNextData();
    }, 1000);

    // when input value change
    hideNsfwCheckbox.change((event) => {
        hideNsfw = event.currentTarget.checked;
        localStorage.abwHideNsfw = hideNsfw;
        log('hideNsfw is now', hideNsfw);
        showHideProductsDebounced();
    });
    // --- Added by Son_Of_Diablo --- //
    includeShipppingCheckbox.change((event) => {
        includeShipping = event.currentTarget.checked;
        localStorage.abwIncludeShipping = includeShipping;
        log('includeShipping is now', includeShipping);
        showHideProductsDebounced();
    });
    enableLoggingCheckbox.change((event) => {
        enableLogging = event.currentTarget.checked;
        localStorage.abwEnableLogging = enableLogging;
        log('enableLogging is now', enableLogging);
        showHideProductsDebounced();
    });
    // --- Added by Son_Of_Diablo --- //
    minPriceInput.change((event) => {
        minPrice = parseInt(event.currentTarget.value) || 0;
        // --- Added by Son_Of_Diablo --- //
        localStorage.abwMinPrice = minPrice;
        // --- Added by Son_Of_Diablo --- //
        log('minPrice is now', minPrice);
        showHideProductsDebounced();
    });
    maxPriceInput.change((event) => {
        maxPrice = parseInt(event.currentTarget.value) || 1000;
        // --- Added by Son_Of_Diablo --- //
        localStorage.abwMaxPrice = maxPrice;
        // --- Added by Son_Of_Diablo --- //
        log('maxPrice is now', maxPrice);
        showHideProductsDebounced();
    });
    minStarsInput.change((event) => {
        minStars = parseInt(event.currentTarget.value);
        localStorage.abwMinStars = minStars;
        log('minStars is now', minStars);
        showHideProductsDebounced();
    });

    // --- Added by Son_Of_Diablo --- //
    function log(message, error) {
        if(enableLogging){
        	if(!error){
        		console.log(message);
        	}else{
        		console.error(message);
        	}
    	}
    }
    // --- Added by Son_Of_Diablo --- //

})();