Amazon Enhancements: Ratings Display and Filtering

Display rating scores and add filtering capabilities on Amazon search results.

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 or Violentmonkey 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 Amazon Enhancements: Ratings Display and Filtering
// @namespace http://tampermonkey.net/
// @version 2.3
// @description Display rating scores and add filtering capabilities on Amazon search results.
// @author Dave w/ Claudi.ai & ChatGPT
// @match https://*.amazon.com/s?*
// @grant none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    let currentFilter = 0;

    // Function to enhance rating display
    const enhanceRatingDisplay = (result) => {
        const ratingElement = result.querySelector('i.a-icon-star-small span.a-icon-alt');
        if (ratingElement && !result.classList.contains('enhanced-rating')) {
            const ratingText = ratingElement.textContent.trim();
            const ratingValue = parseFloat(ratingText.split(' ')[0]);
            const newRatingElement = document.createElement('span');
            newRatingElement.textContent = ratingValue + ' ';
            newRatingElement.style.fontWeight = 'bold';
            newRatingElement.style.color = '#007600'; // Change color if needed
            newRatingElement.style.marginRight = '5px'; // Add some spacing between the ratings
            ratingElement.parentElement.parentElement.insertBefore(newRatingElement, ratingElement.parentElement);
            result.dataset.ratingValue = ratingValue;
            result.classList.add('enhanced-rating');
        }
    };

    // Function to add filter dropdown and refresh icon
    const addFilterDropdown = () => {
        const filterBar = document.createElement('div');
        filterBar.id = 'rating-filter-bar';

        const filterLabel = document.createElement('span');
        filterLabel.textContent = 'Filter by star rating: ';
        filterLabel.style.marginRight = '5px';
        filterBar.appendChild(filterLabel);

        const filterDropdown = document.createElement('select');
        filterDropdown.style.marginRight = '10px';

        // Define dropdown options and their actions
        const filters = [
            { text: 'All', score: 0 },
            { text: '4.9+', score: 4.9 },
            { text: '4.8+', score: 4.8 },
            { text: '4.7+', score: 4.7 },
            { text: '4.6+', score: 4.6 },
            { text: '4.5+', score: 4.5 },
            { text: '4.4+', score: 4.4 },
            { text: '4.3+', score: 4.3 },
            { text: '4.2+', score: 4.2 },
            { text: '4.1+', score: 4.1 }
        ];

        filters.forEach(filter => {
            const option = document.createElement('option');
            option.value = filter.score;
            option.textContent = filter.text;
            filterDropdown.appendChild(option);
        });

        filterDropdown.addEventListener('change', (event) => {
            currentFilter = parseFloat(event.target.value);
            filterResults(currentFilter);
        });

        filterBar.appendChild(filterDropdown);

        const refreshIcon = document.createElement('span');
        refreshIcon.innerHTML = '↻'; // HTML entity for refresh icon
        refreshIcon.style.cursor = 'pointer';
        refreshIcon.style.marginLeft = '5px';
        refreshIcon.addEventListener('click', () => {
            filterResults(currentFilter);
        });

        filterBar.appendChild(refreshIcon);

        // Insert the filter bar at the top of the search results
        const searchResults = document.querySelector('div.s-main-slot.s-result-list.s-search-results.sg-row');
        if (searchResults) {
            searchResults.insertBefore(filterBar, searchResults.firstChild);
        }
    };

    // Function to filter results based on rating score
    const filterResults = (minScore) => {
        const results = document.querySelectorAll('div[data-asin]:not(.s-pagination-container)');
        results.forEach(result => {
            if (!result.querySelector('.s-pagination-container')) {
                const ratingValue = parseFloat(result.dataset.ratingValue);
                result.style.display = ratingValue >= minScore ? '' : 'none';
            }
        });
    };

    // Function to process search results
    const processSearchResults = () => {
        const searchResults = document.querySelectorAll('div[data-asin]:not(.s-pagination-container)');
        searchResults.forEach(result => {
            enhanceRatingDisplay(result);
        });
        filterResults(currentFilter);
    };

    // Throttle function to limit the rate of execution
    const throttle = (func, delay) => {
        let timeoutId = null;
        return (...args) => {
            if (timeoutId === null) {
                func(...args);
                timeoutId = setTimeout(() => {
                    timeoutId = null;
                }, delay);
            }
        };
    };

    // Throttled version of processSearchResults
    const throttledProcessSearchResults = throttle(processSearchResults, 500);

    // Observe changes in the search results
    const observeSearchResults = () => {
        const searchResultsContainer = document.querySelector('div.s-main-slot.s-result-list.s-search-results.sg-row');
        if (searchResultsContainer) {
            const observer = new MutationObserver(throttledProcessSearchResults);
            observer.observe(searchResultsContainer, {
                childList: true,
                subtree: true
            });
        }
    };

    // Initialize the script
    const init = () => {
        addFilterDropdown();
        processSearchResults();
        observeSearchResults();
    };

    // Run the script when the page has loaded
    window.addEventListener('load', init);
})();