// ==UserScript==
// @name Amazon Enhancer: ReviewMeta + Camel + Keepa + UI Panel + Dark Mode + Review Highlighter
// @namespace Eliminater74
// @version 1.3.0
// @description Adds ReviewMeta, CamelCamelCamel, and Keepa charts to Amazon product pages with a draggable UI panel, dark mode, best review highlighting, ad hiding, and more.
// @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
// @downloadURL none
// ==/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
};
const settings = JSON.parse(localStorage.getItem(SETTINGS_KEY)) || defaultSettings;
const locale = getLocale();
const asin = findASIN();
if (!asin) return;
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();
createToggleUI();
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;
}
`;
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 = `
`;
appendToTarget(div);
}
function injectKeepa(asin, locale) {
const div = document.createElement("div");
div.className = 'amazon-enhancer-box';
div.innerHTML = `
`;
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
? `ReviewMeta Adjusted: ${stars}/5
Fake Reviews: ${percent}
View on ReviewMeta`
: `ReviewMeta data not found.
Submit product`;
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 = "⚙️";
Object.assign(gear.style, {
position: "fixed",
bottom: "20px",
right: "20px",
width: "40px",
height: "40px",
background: "#fff",
border: "1px solid #ccc",
borderRadius: "50%",
display: "flex",
justifyContent: "center",
alignItems: "center",
cursor: "move",
zIndex: 99999
});
const panelWrapper = document.createElement("div");
panelWrapper.className = 'amazon-enhancer-panel';
panelWrapper.style.cssText = 'position:fixed;bottom:70px;right:20px;border:1px solid #ccc;padding:10px;border-radius:8px;z-index:99999;background:#fff;';
panelWrapper.style.display = 'none';
const toggleItems = [
['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']
];
panelWrapper.innerHTML = toggleItems.map(([key, label]) =>
`
`
).join('') + `
`;
toggleItems.forEach(([key]) => {
panelWrapper.querySelector(`#${key}`).addEventListener('change', (e) => {
settings[key] = e.target.checked;
saveSettings();
location.reload();
});
});
panelWrapper.querySelector('#themeSelect').addEventListener('change', (e) => {
settings.theme = e.target.value;
saveSettings();
applyTheme(settings.theme);
});
gear.addEventListener('click', () => {
panelWrapper.style.display = panelWrapper.style.display === 'none' ? 'block' : 'none';
});
gear.addEventListener('mousedown', function (e) {
const shiftX = e.clientX - gear.getBoundingClientRect().left;
const shiftY = e.clientY - gear.getBoundingClientRect().top;
function moveAt(pageX, pageY) {
gear.style.left = pageX - shiftX + 'px';
gear.style.top = pageY - shiftY + 'px';
gear.style.right = 'auto';
gear.style.bottom = 'auto';
}
function onMouseMove(e) {
moveAt(e.pageX, e.pageY);
}
document.addEventListener('mousemove', onMouseMove);
gear.onmouseup = function () {
document.removeEventListener('mousemove', onMouseMove);
gear.onmouseup = null;
};
});
gear.ondragstart = () => false;
document.body.appendChild(gear);
document.body.appendChild(panelWrapper);
}
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 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());
}
})();