Amazon Enhancements: Ratings Display and Filtering

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

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

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