// ==UserScript==
// @name Price History - Amazon UK
// @description A non-intrusive way to display Amazon UK item's history price, featuring third-party price history.
// @version 1.0.3
// @name:zh-CN 价格历史 - 亚马逊英国
// @description:zh-CN 以非侵入式的方式来展示亚马逊英国商品的历史价格,使用第三方价格服务。
// @antifeature tracking Third-party site can collect/store/guess what you are going to purchase.
// @antifeature:zh-CN tracking 第三方网站可能会搜集、储存或推测你将要购买的物品。
// @namespace uk.jixun
// @match https://amazon.co.uk/*
// @match https://www.amazon.co.uk/*
// @match https://smile.amazon.co.uk/*
// @author Jixun
// @license bsd-3-clause
// @run-at document-start
// @grant none
// ==/UserScript==
let serviceEl = [];
const services = [{
name: 'CCC',
inline: false,
url: asin => `https://uk.camelcamelcamel.com/product/${asin}`,
}, {
name: 'Keepa',
inline: asin => () => {
const prevImage = $('keepa-history-embed');
if (prevImage) {
prevImage.style.display = prevImage.style.display === 'none' ? 'block' : 'none';
return;
}
const src = `https://graph.keepa.com/pricehistory.png?asin=${asin}&domain=co.uk`;
const $img = h('img', {src, id: 'keepa-history-embed', 'referrerPolicy': 'no-referrer'});
const $price = $('price');
if ($price) {
$price.parentNode.insertBefore($img, $price.nextSibling);
} else {
$('olp_feature_div').appendChild($img);
}
serviceEl.push($img);
},
url: asin => `https://keepa.com/#!product/2-${asin}`,
}];
const serviceStyle = {
'marginRight': '0.5em',
'display': 'inline-block',
};
const inlineStyle = {
background: 'none',
border: 'none',
};
function insertServices(asin) {
return services.map(service => h('li', { style: serviceStyle }, [
service.url && h('a', { href: service.url(asin), target: '_blank', rel: 'noreferrer' }, [service.name]),
!service.url && h('span', null, [service.name]),
service.inline && h('span', null, [
' (',
h('a', { href: 'javascript:void(0)', onclick: service.inline(asin) }, 'inline'),
')',
])
]));
}
function $(id) {
return document.getElementById(id);
}
function insertChildren(root, children = []) {
if (!children) return;
if (Array.isArray(children)) {
for (const c of children) {
insertChildren(root, c);
}
return;
}
if (typeof children === 'string') {
children = document.createTextNode(children);
}
root.appendChild(children);
}
function h(tag, attr, ...children) {
const el = document.createElement(tag);
if (attr) {
for(const [name, value] of Object.entries(attr)) {
if (name === 'style') {
Object.assign(el.style, value);
} else {
el[name] = value;
}
}
}
insertChildren(el, children);
return el;
}
function remove(node) {
node?.parentNode?.removeChild(node);
}
let lastRoot;
function injectPriceCompare() {
const $asin = $('ASIN');
if (!$asin || $asin.tagName !== 'INPUT') {
console.info('asin not found.');
return;
}
// clean up
serviceEl.forEach(remove);
const asin = $asin.value;
const $priceTable = document.querySelector('#price table > tbody') || $('olp_feature_div');
const root = h('tr', null, [
h('td', { className: 'a-color-secondary' }, ['History']),
h('td', null, [
h('ul', { style: {cssText: 'margin:0'} }, insertServices(asin)),
])
]);
$priceTable.appendChild(root);
serviceEl = [root];
}
function init() {
const root = $('desktop_buybox');
if (!root) {
return;
}
const observer = new MutationObserver((mutationsList, observer) => {
for(const {removedNodes} of mutationsList) {
console.info(removedNodes);
if (!removedNodes) continue;
for (const node of removedNodes) {
if (node.id === 'buybox') {
injectPriceCompare();
return;
}
}
}
});
// Start observing the target node for configured mutations
observer.observe(root, { childList: true });
injectPriceCompare();
}
addEventListener('DOMContentLoaded', init);