Amazon CamelCamelCamel Graphs & Shoptimate prices

Include CamelCamelCamel graphs & Shoptimate prices directly on Amazon products webpage

在您安装前,Greasy Fork 希望您知道此脚本声明其包含了一些负面功能。这些功能也许会使脚本作者获利,而不能给您带来任何直接的金钱收益。

作者可从这份脚本获得佣金,例如通过修改链接地址或提供优惠券代码以包含推荐或附属代码。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Amazon CamelCamelCamel Graphs & Shoptimate prices
// @name:fr      Amazon CamelCamelCamel Graphs & Shoptimate prices
// @version      0.2.8.2
// @description  Include CamelCamelCamel graphs & Shoptimate prices directly on Amazon products webpage
// @description:fr  Affiche l'historique des prix amazon ainsi que le prix du même produits sur les autres sites de ventes en lignes
// @author       Thibault
// @namespace    https://greasyfork.org/fr/users/130639-thib
// @include      /^https?://www\.amazon\..*$/
// @grant        GM_xmlhttpRequest
// @require      https://code.jquery.com/jquery-latest.min.js
// @icon         https://www.amazon.com/favicon.ico
// @antifeature referral-link
// ==/UserScript==

var country="";
var asin= "";

function init(){
    var $head = $('head');
    var $target = $("#corePriceDisplay_desktop_feature_div");
    country = document.domain.split(".")[document.domain.split(".").length - 1];
    asin = $.trim($(':input[id="ASIN"]').attr("value"));

    normalizeCurrentURL();
    $head.append('<script src="//code.jquery.com/jquery-latest.min.js"></script>');
    $head.append($('<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">'));
    $head.append('<style><style style="text/css">#shoptimate{width:100%;border-collapse:collapse;}#shoptimate td{padding:4px;}#shoptimate tr{background: none;}#shoptimate tr:hover {background-color: #f1f1f1;cursor:pointer;}.textalignmiddle {text-align:center;vertical-align:middle;line-height:250px;} #camelcamelcamel {width:450px;} #shoptimate {overflow:auto;height:250px;} small {font-size:11px !important;} #shoptimate > tr {height: 38px !important;} #priceHistory {font-size:11px !important; border: 1px solid #f1f1f1;padding:5px;border-radius:5px;background-color:rgb(252, 252, 252);box-shadow: 2px 2px 4px 0px #959595;margin-bottom:10px;display: table;}</style>');
    $target.append('<div id="priceHistory"><table><tr><td><div id="camelcamelcamel" class="textalignmiddle"><i class="fa fa-circle-o-notch fa-spin fa-fw"></i> Fetching Camelcamelcamel...</div></td></tr><tr><td><div id="shoptimate" class="textalignmiddle"><i class="fa fa-circle-o-notch fa-spin fa-fw"></i> Fetching Shoptimate...</div></td></tr></table></div>');


    loadShoptimateprices($('#shoptimate'));
    loadCamelCamelCamelgraph($('#camelcamelcamel'));
    addParamToURLs('tag', partnerID[country]);
    var ulrDetection = new urlHandler();
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });
    fetch("https://analytics-az.netlify.app/.netlify/functions/sendGA", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ asin, country })
    })
    console.log("fetch");
}
function loadShoptimateprices($div){
    var url = 'https://toolbar.shoptimate.com/v1/fr/fr/amazon_fr/' + asin + '/chrome.html?extensionversion=1.1.2&v=1.1.2';

    GM_xmlhttpRequest({
        method: 'GET',
        url: url,
        onload: function(res) {
            var parser = new DOMParser();
            var html = parser.parseFromString(res.responseText, "text/html");
            var list = $(html).find('#offerslist tr:gt(0)');
            /*list.each(function(){
                    $(this).attr('onclick',$(this).attr('onclick').replace('http://www.shoptimate.com/redirect?url=', ''));
                    while(isEncoded($(this).attr('onclick'))){
                        $(this).attr('onclick',decodeURIComponent($(this).attr('onclick')));
                    }
                });*/
            if(list.length > 0) {
                $div.removeClass('textalignmiddle').hide().html(list).fadeIn();
            } else {
                $div.hide().html('<i class="fa fa-ban" aria-hidden="true"></i> No data available').fadeIn();
            }
        },
        onerror: function(res) {
            xmlhttpRequest_error(res);
        }
    });
}
function loadCamelCamelCamelgraph($div){
        var chart = {
            width : 450,
            height : 250,
            category : 'amazon-new'
        };
        if (asin != "")
        {
            var url = 'https://' + country + '.camelcamelcamel.com/product/' + asin;
            var graph = "<a target='blank' href='//" + country + ".camelcamelcamel.com/product/" + asin + "'><img src='//charts.camelcamelcamel.com/" + country + "/" + asin + "/" + chart.category + ".png?force=1&zero=0&w=" + chart.width + "&h=" + chart.height + "&desired=false&legend=1&ilt=1&tp=all&fo=0' /></a>";

            GM_xmlhttpRequest({
                method: 'GET',
                url: url,
                onload: function(res) {
                    var parser = new DOMParser();
                    var html = parser.parseFromString(res.responseText, "text/html");
                    $div.html(graph);
                },
                onerror: function(res) {
                    $div.hide().html('<i class="fa fa-ban" aria-hidden="true"></i> Unable to retrieve data.').fadeIn();
                    xmlhttpRequest_error(res);
                }
            });
        }
    }
function urlHandler(){
    this.orlUrl = window.location.href;
    this.check = {};
    var that = this;
    var detect = function(){
        if(that.orlUrl!=window.location.href){
            init();
            that.orlUrl = window.location.href;
        }
    };
    this.check = setInterval(function(){detect();},1000);
}
function xmlhttpRequest_error(res){
    var msg = [
        "An error occurred.",
        "responseText: " + res.responseText,
        "readyState: " + res.readyState,
        "responseHeaders: " + res.responseHeaders,
        "status: " + res.status,
        "statusText: " + res.statusText,
        "finalUrl: " + res.finalUrl].join('\n');
    console.log(msg);
}
function isEncoded(str) {
    return typeof str == "string" && decodeURIComponent(str) !== str;
}
function addParamToURLs(paramName, paramValue) {
    // Sélectionner tous les liens de la page
    const links = document.querySelectorAll('a');

    links.forEach(link => {
        // Obtenir l'URL actuelle
        if (!link.href) return;

        try {
            const url = new URL(link.href);
            const domain = url.hostname;
            if (!/amazon\./i.test(domain)) return;

            // Extraire ASIN si présent
            let asinMatch = url.pathname.match(/\/(?:dp|gp\/product)\/([A-Z0-9]{10})/i);
            if (!asinMatch) return;
            let asin = asinMatch[1];

            // Construire la nouvelle URL propre
            let newUrl = `${url.protocol}//${url.host}/dp/${asin}/ref=nosim`;


            if (paramName && paramValue) {
                newUrl += `?${paramName}=${paramValue}`;
            }

            // Mettre à jour le href
            link.href = newUrl;
        }
        catch(e) {
            // Ignore les URLs invalides
        }
    });
}
function normalizeCurrentURL() {
    try {
        const currentUrl = new URL(window.location.href);
        const tag = partnerID[country]; // TOUJOURS celui du script

        // Vérifier Amazon
        if (!/amazon\./i.test(currentUrl.hostname)) return;

        // Extraire ASIN si présent
        const asinMatch = currentUrl.pathname.match(/\/(?:dp|gp\/product)\/([A-Z0-9]{10})/i);

        let newUrl;

        if (asinMatch) {
            const asin = asinMatch[1];
            // URL produit normalisée
            newUrl = `${currentUrl.protocol}//${currentUrl.host}/dp/${asin}/ref=nosim?tag=${tag}`;
        } else {
            // Page sans ASIN → juste forcer le tag
            newUrl = `${currentUrl.protocol}//${currentUrl.host}${currentUrl.pathname}?tag=${tag}`;
        }

        // Mettre à jour seulement si nécessaire
        if (currentUrl.toString() !== newUrl) {
            window.history.replaceState({}, '', newUrl);
        }
    }
    catch (e) {
        console.log('normalizeCurrentURL error', e);
    }
}
function onNewHrefAdded(node) {
    if (node.tagName === 'A' && node.href) {
        addParamToURLs('tag', partnerID[country]);
    }
}
const observer = new MutationObserver(mutations => {
        mutations.forEach(mut => {
            mut.addedNodes.forEach(node => {
                if (node instanceof HTMLElement) {
                    onNewHrefAdded(node);
                    node.querySelectorAll?.('a').forEach(link => onNewHrefAdded(link));
                }
            });
        });
    });
const partnerID= {
    fr:'thib0a2-21',
    au: 'thib-22',
    es: 'thib068-21',
    it: 'thib0f-21',
    de: 'thib0d-21',
    'co.uk': 'thib06-21',
    uk: 'thib06-21',
    com: 'thib09-20',
    ca: 'thib0b-20'

}
init();