Greasy Fork

Wish.com - Price filter & more

Filtering by min/max price, allow hidding free products, see reviews

目前为 2018-04-08 提交的版本。查看 最新版本

// ==UserScript==
// @name         Wish.com - Price filter & more
// @namespace    http://tampermonkey.net/
// @version      3.0
// @description  Filtering by min/max price, allow hidding free products, see reviews
// @author       Shuunen
// @match        https://*.wish.com/*
// @grant        none
// ==/UserScript==

$(document).ready(function() {

    console.log('wish price filter : init');

    // 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, 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);
        };
    }

    var activeRequests = 0;

    function fetchData(id, productEl, delay) {
        console.log('will get data for', id);
        return new Promise(resolve => {
            setTimeout(() => {
                const url = 'https://www.wish.com/c/' + id;
                console.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);
                    console.log(id, ': found a rating of', ratings, 'over', count, 'reviews :)');
                    let roundedRatings = Math.round(ratings);
                    let ratingsStr = '';
                    while(roundedRatings--) {
                        ratingsStr += '?';
                    }
                    if(count > 0){
                        ratingsStr += ' over ' + count + ' reviews';
                    } else {
                        ratingsStr = 'no reviews !';
                    }
                    productEl.find('.feed-details-row2').html(ratingsStr);
                    const shippingMatches = html.match(/"localized_shipping":\s{"localized_value":\s(\d)/i);
                    const shippingFees = parseInt(shippingMatches[1]);
                    console.log(id, ': shipping fees',shippingFees, '€');
                    const priceMatches = productEl.find('.feed-actual-price').text().match(/\d+/);
                    const price = parseInt((priceMatches && priceMatches.length) ? priceMatches[0] : 0);
                    console.log(id, ': base price',price, '€');
                    const totalPrice = (shippingFees + price) + ' €';
                    productEl.find('.feed-actual-price').html(totalPrice);
                    activeRequests--;
                    showHideProductsDebounced();
                    resolve({ id, ratings, count, shippingFees, price, totalPrice });
                })
                    .catch(error => {
                    activeRequests--;
                    console.error('did not managed to found ratings for product "', id, '"', error);
                });
            },delay);
        });
    }

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

    function getData() {
        const productEl = $(this);
        if(!productEl.hasClass('abw-with-data')){
            productEl.addClass('abw-with-data');
            const image = productEl.find('a.display-pic');
            const id = image.attr('href').split('/').reverse()[0];
            const originalPicture = image[0].style.backgroundImage;
            image[0].style.backgroundImage = 'url('+loadedUrl+')';
            image[0].style.backgroundSize = '10%';
            fetchData(id, productEl, 200).then(() => {
                image[0].style.backgroundImage = originalPicture;
                image[0].style.backgroundSize = '100%';
            });
        }
    }

    function showHideProducts() {
        // hide already rated products in order hsitory
        $('.edit-rating-button').parents('.transaction-expanded-row-item').hide();
        // hide products that can't be rated
        $('.late-box').parents('.transaction-expanded-row-item').hide();
        // delete useless marketing stuff
        $('.discount-banner, .urgency-inventory, .feed-crossed-price, .product-boost-rect, .header-hello').remove();
        console.log('wish price filter : showHideProducts');
        var minPrice = parseInt($("#wtc_min_price").val()) || 0;
        var maxPrice = parseInt($("#wtc_max_price").val()) || 1000;
        var hideFree = $("#wtc_hide_free").is(':checked');
        sessionStorage.wishHidefree = hideFree;
        // console.log('wish price filter : hide free items ?', hideFree);
        var items = $(".feed-actual-price");
        $.each(items, function(index) {
            var price = $(this).text().replace(/\D/g,'');
            var priceOk = (price <= maxPrice);
            if(minPrice && minPrice > 0){
                priceOk = priceOk && (price >= minPrice);
            }
            if(priceOk && hideFree && this.textContent.includes('Free')){
                priceOk = false;
            }
            const product = $(this).parent().parent().parent().parent();
            product.toggle(priceOk);
            if(priceOk && !product.hasClass('abw-on-hover')) {
                product.addClass('abw-on-hover');
                product.hover(getData);
            }
        });
    }

    // insert controllers
    if ($("#nav-search").length > 0){
        $('#mobile-app-buttons').hide();
        $('#nav-search-input-wrapper').width(320);
        var html = '<div id="wish_tweaks_config" style="float:left;margin-top:10px;display:flex;justify-content:space-between;width:280px;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; margin-left: 5px;">&nbsp;/<input id="wtc_max_price" type="text" style="width: 30px; margin-left: 5px;">';
        html += '<div style="margin-left: auto"></div>';
        html += 'Hide free : <input id="wtc_hide_free" type="checkbox" checked style="margin: 0; height: 16px; width: 16px; margin-left: 5px;">';
        html += '</div>';
        $("#header-left").after(html);
    }

    // restore previous choices
    var hideFreeCheckbox = $("#wtc_hide_free");
    hideFreeCheckbox.attr('checked', (sessionStorage.wishHidefree === 'true'));

    // setup cron like job
    /* function cron(){

    }
    setInterval(cron, 1000); */

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

    // trigger twice by default
    showHideProductsDebounced();
    setTimeout(showHideProductsDebounced, 1000);

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

    // when input value change
    $("#wtc_hide_free").change(showHideProductsDebounced);
    $("#wtc_min_price").keydown(showHideProductsDebounced);
    $("#wtc_max_price").keydown(showHideProductsDebounced);

});