Amazon Enhancer: Monthly + ReviewMeta + Camel + Keepa + UI + Dark + Review Highlights

Highlights monthly payments, adds ReviewMeta, CamelCamelCamel, Keepa, sticky UI, themes, ad hiding, and more for Amazon users. Gear icon is now moveable again.

// ==UserScript==
// @name         Amazon Enhancer: Monthly + ReviewMeta + Camel + Keepa + UI + Dark + Review Highlights
// @namespace    Eliminater74
// @version      1.4.2
// @description  Highlights monthly payments, adds ReviewMeta, CamelCamelCamel, Keepa, sticky UI, themes, ad hiding, and more for Amazon users. Gear icon is now moveable again.
// @author       Eliminater74
// @license      MIT
// @match        https://www.amazon.com/*
// @match        https://www.amazon.co.uk/*
// @match        https://www.amazon.de/*
// @match        https://www.amazon.fr/*
// @match        https://www.amazon.it/*
// @match        https://www.amazon.es/*
// @match        https://www.amazon.ca/*
// @match        https://smile.amazon.com/*
// @grant        GM_xmlhttpRequest
// @connect      reviewmeta.com
// @run-at       document-end
// ==/UserScript==

(function () {
    'use strict';

    const SETTINGS_KEY = 'amazonEnhancerSettings';
    const defaultSettings = {
        showReviewMeta: true,
        showCamel: true,
        showKeepa: true,
        theme: 'auto',
        highlightBestReviews: true,
        hideAds: true,
        showSoldBy: true,
        stickyPriceBox: true,
        autoSortReviews: true,
        expandReviewsQA: true,
        highlightMonthlyPayments: true,
        filterOnlyMonthly: false
    };

    const settings = JSON.parse(localStorage.getItem(SETTINGS_KEY)) || defaultSettings;
    const locale = getLocale();
    const asin = findASIN();

    if (asin) {
        applyTheme(settings.theme);
        if (settings.showReviewMeta) injectReviewMeta(asin, locale);
        if (settings.showCamel) injectCamel(asin, locale);
        if (settings.showKeepa) injectKeepa(asin, locale);
    }

    if (settings.highlightBestReviews) highlightReviews();
    if (settings.hideAds) hideSponsored();
    if (settings.showSoldBy) showSoldByBox();
    if (settings.stickyPriceBox) makeStickyPriceBox();
    if (settings.autoSortReviews) autoSortReviews();
    if (settings.expandReviewsQA) expandSections();
    if (settings.highlightMonthlyPayments || settings.filterOnlyMonthly) scanMonthlyPayments();

    createToggleUI();
    observePageChanges();

    function saveSettings() {
        localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));
    }

    function applyTheme(mode) {
        const html = document.documentElement;
        const theme = (mode === 'auto') ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : mode;
        html.setAttribute('data-enhancer-theme', theme);

        let style = document.getElementById('amazon-enhancer-theme-style');
        if (style) style.remove();
        style = document.createElement('style');
        style.id = 'amazon-enhancer-theme-style';
        style.textContent = `
            [data-enhancer-theme="dark"] .amazon-enhancer-box {
                background: #1d1d1d !important;
                color: #f0f0f0 !important;
                border-color: #555 !important;
            }
            [data-enhancer-theme="dark"] .amazon-enhancer-box a {
                color: #7dddf2 !important;
            }
            [data-enhancer-theme="dark"] .amazon-enhancer-panel {
                background: #2c2c2c !important;
                color: #eee !important;
                border-color: #555;
            }
            .highlighted-review {
                border: 2px solid gold !important;
                background-color: #fffbea !important;
            }
            .monthly-badge {
                position: absolute;
                top: 10px;
                left: 10px;
                background: #0099cc !important;
                color: #ffffff !important;
                padding: 2px 6px;
                font-weight: bold;
                font-size: 12px;
                border-radius: 4px;
                z-index: 2147483647 !important;
            }
        `;
        document.head.appendChild(style);
    }

    function getLocale() {
        const host = location.hostname;
        if (host.includes(".co.uk")) return "uk";
        if (host.includes(".de")) return "de";
        if (host.includes(".fr")) return "fr";
        if (host.includes(".es")) return "es";
        if (host.includes(".it")) return "it";
        if (host.includes(".ca")) return "ca";
        return "us";
    }

    function findASIN() {
        const match = location.href.match(/\/([A-Z0-9]{10})(?:[/?]|$)/);
        if (match) return match[1];
        const el = document.getElementById("ASIN") || document.querySelector('[name="ASIN.0"]');
        return el?.value || null;
    }

    function injectCamel(asin, locale) {
        const div = document.createElement("div");
        div.className = 'amazon-enhancer-box';
        div.innerHTML = `<a href='https://${locale}.camelcamelcamel.com/product/${asin}' target='_blank'>
            <img src='https://charts.camelcamelcamel.com/${locale}/${asin}/amazon-new-used.png?force=1&zero=0&w=500&h=300' style='max-width:100%;'>
        </a>`;
        appendToTarget(div);
    }

    function injectKeepa(asin, locale) {
        const div = document.createElement("div");
        div.className = 'amazon-enhancer-box';
        div.innerHTML = `<a href='https://keepa.com/#!product/1-${asin}' target='_blank'>
            <img src='https://graph.keepa.com/pricehistory.png?used=1&amazon=1&new=1&domain=${locale}&asin=${asin}' style='max-width:100%;height:auto;'>
        </a>`;
        appendToTarget(div);
    }

    function injectReviewMeta(asin, locale) {
        const url = `https://reviewmeta.com/amazon${locale === 'us' ? '' : '-' + locale}/${asin}`;
        GM_xmlhttpRequest({
            method: 'GET',
            url,
            onload: res => {
                const doc = new DOMParser().parseFromString(res.responseText, "text/html");
                const stars = doc.querySelector('#adjusted-rating-large')?.textContent?.trim();
                const percent = Array.from(doc.querySelectorAll('small')).find(e => e.textContent.includes('potentially unnatural'))?.querySelector('span span')?.textContent?.trim();

                const div = document.createElement('div');
                div.className = 'amazon-enhancer-box';
                div.style = 'margin-top:10px;padding:10px;border:1px solid #ccc;';
                div.innerHTML = stars
                    ? `<b>ReviewMeta Adjusted:</b> <span style='color:firebrick'>${stars}/5</span><br/>
                       <b>Fake Reviews:</b> <span style='color:firebrick'>${percent}</span><br/>
                       <a href='${url}' target='_blank' style='color:green;'>View on ReviewMeta</a>`
                    : `<b style='color:red;'>ReviewMeta data not found.</b><br/><a href='${url}' target='_blank'>Submit product</a>`;
                appendToTarget(div);
            }
        });
    }

    function appendToTarget(el) {
        const target = document.getElementById("unifiedPrice_feature_div") || document.getElementById("title")?.closest(".a-section");
        if (target) target.appendChild(el);
    }

    function createToggleUI() {
        const gear = document.createElement("div");
        gear.innerText = "⚙️";
        gear.id = "amazon-enhancer-gear";
        gear.style.cssText = `
            position: fixed;
            bottom: 20px;
            right: 20px;
            width: 40px;
            height: 40px;
            font-size: 22px;
            background: #222;
            color: #fff;
            border: 2px solid #888;
            border-radius: 50%;
            display: flex;
            justify-content: center;
            align-items: center;
            cursor: move;
            box-shadow: 0 0 12px rgba(0,0,0,0.8);
            z-index: 2147483647;
        `;

        const panel = document.createElement("div");
        panel.className = 'amazon-enhancer-panel';
        panel.style.cssText = 'position:fixed;bottom:70px;right:20px;border:1px solid #ccc;padding:10px;border-radius:8px;z-index:99999;background:#fff;display:none;';

        const toggles = [
            ['showReviewMeta', 'ReviewMeta'],
            ['showCamel', 'CamelCamelCamel'],
            ['showKeepa', 'Keepa'],
            ['highlightBestReviews', 'Highlight Best Reviews'],
            ['hideAds', 'Hide Sponsored Ads'],
            ['showSoldBy', 'Show Sold By'],
            ['stickyPriceBox', 'Sticky Price Box'],
            ['autoSortReviews', 'Auto Sort Reviews'],
            ['expandReviewsQA', 'Expand Q&A/Reviews'],
            ['highlightMonthlyPayments', 'Highlight Monthly Payments'],
            ['filterOnlyMonthly', 'Filter: Only Monthly Payment Items']
        ];

        panel.innerHTML = toggles.map(([key, label]) =>
            `<label><input type='checkbox' id='${key}' ${settings[key] ? 'checked' : ''}/> ${label}</label><br/>`
        ).join('') + `
        <label>Theme:
            <select id='themeSelect'>
                <option value='auto' ${settings.theme === 'auto' ? 'selected' : ''}>Auto</option>
                <option value='light' ${settings.theme === 'light' ? 'selected' : ''}>Light</option>
                <option value='dark' ${settings.theme === 'dark' ? 'selected' : ''}>Dark</option>
            </select>
        </label>`;

        toggles.forEach(([key]) => {
            panel.querySelector(`#${key}`).addEventListener('change', e => {
                settings[key] = e.target.checked;
                saveSettings();
                location.reload();
            });
        });

        panel.querySelector('#themeSelect').addEventListener('change', e => {
            settings.theme = e.target.value;
            saveSettings();
            applyTheme(settings.theme);
        });

        // Make gear draggable and clickable
        let isDragging = false, offsetX = 0, offsetY = 0;
        gear.addEventListener('mousedown', (e) => {
            isDragging = true;
            offsetX = e.clientX - gear.getBoundingClientRect().left;
            offsetY = e.clientY - gear.getBoundingClientRect().top;
            e.preventDefault();
        });

        document.addEventListener('mousemove', (e) => {
            if (isDragging) {
                gear.style.left = `${e.clientX - offsetX}px`;
                gear.style.top = `${e.clientY - offsetY}px`;
                gear.style.right = 'auto';
                gear.style.bottom = 'auto';
            }
        });

        document.addEventListener('mouseup', () => {
            if (!isDragging) return;
            isDragging = false;
        });

        gear.addEventListener('click', () => {
            if (!isDragging) panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
        });

        gear.ondragstart = () => false;

        document.body.appendChild(gear);
        document.body.appendChild(panel);
    }

    function highlightReviews() {
        const reviews = [...document.querySelectorAll('.review')];
        const scored = reviews.map(el => {
            const helpful = parseInt(el.innerText.match(/(\d+,?\d*) people found this helpful/)?.[1]?.replace(',', '') || '0');
            const verified = el.innerHTML.includes('Verified Purchase') ? 5 : 0;
            const longText = el.innerText.length > 500 ? 5 : 0;
            const hasMedia = el.querySelectorAll('img').length ? 5 : 0;
            return { el, score: helpful + verified + longText + hasMedia };
        });
        scored.sort((a, b) => b.score - a.score);
        scored.slice(0, 3).forEach(r => r.el.classList.add('highlighted-review'));
    }

    function scanMonthlyPayments() {
        const results = document.querySelectorAll('[data-component-type="s-search-result"], .s-result-item');
        results.forEach(result => {
            const text = result.innerText;
            const match = /(?:\$\d+\.\d{2}\/month|\d+\s+monthly payments|\$[\d,]+(?:\.\d+)?\/mo\.?)/i.test(text);
            const already = result.querySelector('.monthly-badge');

            if (match) {
                if (!already && settings.highlightMonthlyPayments) {
                    const badge = document.createElement('div');
                    badge.className = 'monthly-badge';
                    badge.textContent = '💳 Monthly Payments';
                    result.style.position = 'relative';
                    result.appendChild(badge);
                }
                result.style.display = '';
            } else if (settings.filterOnlyMonthly) {
                result.style.display = 'none';
            } else {
                result.style.display = '';
            }
        });
    }

    function hideSponsored() {
        document.querySelectorAll("[data-component-type='sp-sponsored-result']").forEach(el => el.remove());
    }

    function showSoldByBox() {
        const el = document.querySelector("#merchant-info");
        if (el) el.style.border = "2px dashed orange";
    }

    function makeStickyPriceBox() {
        const box = document.getElementById("corePrice_feature_div");
        if (box) {
            box.style.position = "sticky";
            box.style.top = "0";
            box.style.background = "#fff";
            box.style.zIndex = 9999;
            box.style.borderBottom = "2px solid #ccc";
        }
    }

    function autoSortReviews() {
        const sortSelect = document.querySelector('select[name="sortBy"]');
        if (sortSelect) sortSelect.value = "recent";
    }

    function expandSections() {
        document.querySelectorAll(".a-expander-prompt").forEach(e => e.click());
    }

    function observePageChanges() {
        const observer = new MutationObserver(() => {
            if (settings.highlightMonthlyPayments || settings.filterOnlyMonthly) scanMonthlyPayments();
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }
})();