在您安装前,Greasy Fork 希望您知道此脚本声明其包含了一些负面功能。这些功能也许会使脚本作者获利,而不能给您带来任何直接的金钱收益。
作者可从这份脚本获得佣金,例如通过修改链接地址或提供优惠券代码以包含推荐或附属代码。
此脚本含有追踪您的操作的代码。
Maximize your savings by effortlessly comparing prices across Amazon.fr, .de, .es, .it, .be, .nl, .co.uk, and .com. Automatically detect coupons, enjoy fast dynamic result displays, access comprehensive price histories with CamelCamelCamel, convert prices to EUR based on current exchange rates, and find the best product alternatives on AliExpress with intelligent searches. Save more with every purchase!
当前为
// ==UserScript== // @name Amazon Price Checker (FR, DE, ES, IT, BE, NL, UK, COM) + AliExpress // @namespace http://tampermonkey.net/ // @version 3.10 // @description Maximize your savings by effortlessly comparing prices across Amazon.fr, .de, .es, .it, .be, .nl, .co.uk, and .com. Automatically detect coupons, enjoy fast dynamic result displays, access comprehensive price histories with CamelCamelCamel, convert prices to EUR based on current exchange rates, and find the best product alternatives on AliExpress with intelligent searches. Save more with every purchase! // @icon https://i.ibb.co/qrjrcVy/amz-price-checker.png // @match https://www.amazon.fr/* // @match https://www.amazon.de/* // @match https://www.amazon.es/* // @match https://www.amazon.it/* // @match https://www.amazon.com.be/* // @match https://www.amazon.nl/* // @match https://www.amazon.co.uk/* // @match https://www.amazon.com/* // @grant GM_xmlhttpRequest // @connect amazon.fr // @connect amazon.de // @connect amazon.es // @connect amazon.it // @connect amazon.com.be // @connect amazon.nl // @connect amazon.co.uk // @connect amazon.com // @connect summarizer.mon-bnj.workers.dev // @connect api.frankfurter.app // @license MIT // @antifeature referral-link // @antifeature tracking // ==/UserScript== (function(){ 'use strict'; const ASIN_REGEX = /\/([A-Z0-9]{10})(?:[/?]|$)/; const PARTNER_IDS = { fr: 'bnjmazon-21', es: 'bnjmazon08-21', it: 'bnjmazon0d-21', de: 'geeksince190d-21', 'com.be': 'geeksince1900', nl: 'bnjmazon-21', 'co.uk': 'bnjmazon-UK-21', com: 'bnjmazon-20' }; const amazonSites = [ { name:'Amazon.fr', country:'fr', flag:'https://flagcdn.com/w20/fr.png', currency: 'EUR', needsConversion: false }, { name:'Amazon.es', country:'es', flag:'https://flagcdn.com/w20/es.png', currency: 'EUR', needsConversion: false }, { name:'Amazon.it', country:'it', flag:'https://flagcdn.com/w20/it.png', currency: 'EUR', needsConversion: false }, { name:'Amazon.de', country:'de', flag:'https://flagcdn.com/w20/de.png', currency: 'EUR', needsConversion: false }, { name:'Amazon.be', country:'com.be', flag:'https://flagcdn.com/w20/be.png', currency: 'EUR', needsConversion: false }, { name:'Amazon.nl', country:'nl', flag:'https://flagcdn.com/w20/nl.png', currency: 'EUR', needsConversion: false }, { name:'Amazon.co.uk', country:'co.uk', flag:'https://flagcdn.com/w20/gb.png', currency: 'GBP', needsConversion: true }, { name:'Amazon.com', country:'com', flag:'https://flagcdn.com/w20/us.png', currency: 'USD', needsConversion: true } ]; let asin, basePrice, selectedTimePeriod = 'all'; let priceResults = [], requestCount = 0, firstPriceLoaded = false; let tableContainer, headerRow, priceContainer; let exchangeRates = null; let footerAdded = false; async function main(){ if(!extractASIN() || !await getBasePrice()) return; injectStyles(); createLoadingContainer(); await fetchExchangeRates(); fetchPricesFromOtherSites(); } function extractASIN(){ const m = window.location.href.match(ASIN_REGEX); if(!m) return false; asin = m[1]; return true; } async function getBasePrice(){ basePrice = getPriceFromDocument(document, getCurrentCountryCode()); return basePrice !== null; } async function fetchExchangeRates(){ const cachedRates = localStorage.getItem('exchangeRates'); const cachedTime = localStorage.getItem('exchangeRatesTimestamp'); const now = new Date().getTime(); if(cachedRates && cachedTime && (now - cachedTime < 3600000)){ exchangeRates = JSON.parse(cachedRates); console.log('Utilisation des taux de change mis en cache:', exchangeRates); return; } try{ const response = await new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url: 'https://api.frankfurter.app/latest?from=EUR&to=USD,GBP,EUR', onload: (r) => resolve(r), onerror: () => reject(new Error('Échec de la récupération des taux de change')) }); }); if(response.status === 200){ const data = JSON.parse(response.responseText); exchangeRates = data.rates; localStorage.setItem('exchangeRates', JSON.stringify(exchangeRates)); localStorage.setItem('exchangeRatesTimestamp', now); console.log('Taux de change récupérés:', exchangeRates); } else { throw new Error('Réponse non 200'); } } catch(e){ console.error('Erreur lors de la récupération des taux de change:', e); exchangeRates = { USD: 0.90, GBP: 1.15, EUR: 1 }; } } function getCouponFromDocument(doc, currentPrice) { let label = doc.querySelector('label[id^="couponText"]'); if(!label) { label = doc.querySelector('label[id^="greenBadgepctch"]'); } if(!label) return 0; let text = label.textContent || ''; text = text.replace(/\u00A0/g,' ').toLowerCase().trim(); let coupon = 0; const pctRegex = /(\d+(?:[.,]\d+)?)\s*%/; const mPct = pctRegex.exec(text); if(mPct){ const pctVal = parseFloat(mPct[1].replace(',', '.')); if(!isNaN(pctVal) && pctVal>0 && pctVal<100){ coupon = currentPrice * (pctVal / 100); } } const moneyRegex = /(?:€\s*(\d+(?:[.,]\d+)?)|(\d+(?:[.,]\d+))\s*€)/; const mMoney = moneyRegex.exec(text); if(mMoney){ const valStr = (mMoney[1] || mMoney[2] || '').replace(',', '.'); const val = parseFloat(valStr); if(!isNaN(val) && val>0 && val<=currentPrice){ coupon = Math.max(coupon, val); } } return coupon; } function injectStyles(){ const css=` #amazonPriceComparisonContainer { margin-top:20px; padding:10px; background:#f9f9f9; border:1px solid #ccc; border-radius:8px; position:relative; font-size:11px; text-align:center; } .comparison-row { cursor:pointer; display:flex; justify-content:space-between; padding:2px 0; border-bottom:1px solid #ccc; } .comparison-row:hover { background:#f1f1f1; } .comparison-row.header-row { border-bottom:2px solid #000; font-weight:bold; pointer-events:none; } .comparison-row > div { flex:1; margin:0 2px; } .first-col { min-width: 100px; flex: 0 0 100px; white-space: nowrap; text-align: left; overflow: hidden; } #loadingMessage { text-align:center; font-weight:bold; font-size:14px; display:flex; flex-direction:column; align-items:center; background-clip:text; color:transparent; background-image:linear-gradient(270deg,black 0%,black 20%,#FF9900 50%,black 80%,black 100%); background-size:200% 100%; animation:loadingAnimation 2s linear infinite; } @keyframes loadingAnimation { 0%{background-position:100% 50%} 100%{background-position:0 50%} } .price-difference-positive { color:green; } .price-difference-negative { color:red; } .controls-container { text-align:center; margin:10px; display:flex; justify-content:space-around; align-items:center; } .control-button { padding:5px 10px; border:1px solid #ccc; border-radius:4px; background:#fff; cursor:pointer; font-size:11px; } .control-button.active { background:#FF9900; color:#fff; } .checkbox-container { display:flex; align-items:center; margin-left:5px; } .checkbox-label { margin-left:2px; font-size:11px; } .aliexpress-container { margin-top:20px; padding:5px 10px; border:1px solid #ccc; border-radius:8px; text-align:center; max-width:200px; margin:20px auto; cursor:pointer; background:transparent; color:#ff5722; font-weight:bold; display:flex; align-items:center; justify-content:center; } .aliexpress-icon { width:24px; margin-right:8px; } .aliexpress-container:hover { background:#ffe6cc; } .loading-text { background-clip:text; color:transparent; background-image:linear-gradient(270deg,black 0%,black 20%,#FF9900 50%,black 80%,black 100%); background-size:200% 100%; animation:loadingAnimation 2s linear infinite; } .footer { text-align:right; font-size:.7em; color:#666; margin-top:10px; } .footer-logo { width:20px; height:20px; vertical-align:middle; margin-right:5px; } .chart-container { text-align:center; margin:20px 0; } .loader { position:relative; width:48px; height:48px; border-radius:50%; display:inline-block; border-top:4px solid #FFF; border-right:4px solid transparent; box-sizing:border-box; animation:rotation 1s linear infinite; } .loader::after { content:''; box-sizing:border-box; position:absolute; left:0; top:0; width:48px; height:48px; border-radius:50%; border-left:4px solid #FF3D00; border-bottom:4px solid transparent; animation:rotation .5s linear infinite reverse; } @keyframes rotation { 0%{transform:rotate(0deg);} 100%{transform:rotate(360deg);} } @keyframes fadeIn { from{opacity:0;} to{opacity:1;} } .fade-in { animation:fadeIn .4s ease-in-out; } .product-summary-encart { margin-top:20px; padding:10px; background:#eee; border:1px solid #ccc; border-radius:8px; text-align:left; } .product-summary-encart h3 { margin-top:0; font-size:1.2em; color:#0d47a1; } .product-summary-encart p { margin:5px 0; color:#333; } .exchange-info-icon { margin-left: 3px; cursor: help; font-size: 0.8em; vertical-align: middle; } ._Y3Itc_selected_2-xMA { font-weight: bold !important; } #cr-product-insights-cards * { font-size: 11px !important; } `; const st=document.createElement('style'); st.type='text/css'; st.innerText=css; document.head.appendChild(st); } function createLoadingContainer(){ const priceElement = document.querySelector('.priceToPay,#priceblock_ourprice,#priceblock_dealprice,#priceblock_saleprice'); if(priceElement && priceElement.parentNode){ const c=document.createElement('div'); c.id='amazonPriceComparisonContainer'; c.innerHTML=` <div id="loadingMessage"> <img src="https://i.ibb.co/qrjrcVy/amz-price-checker.png" style="width:50px;height:50px;margin-bottom:10px;"> Checking other Amazon sites... </div>`; priceElement.parentNode.appendChild(c); } } function fetchPricesFromOtherSites(){ amazonSites.forEach(s=>{ const url=`https://www.amazon.${s.country}/dp/${asin}?tag=${PARTNER_IDS[s.country]}`; GM_xmlhttpRequest({ method:'GET', url, headers:{'User-Agent':'Mozilla/5.0','Accept-Language':'en-US,en;q=0.5'}, onload:r=>handleResponse(s,r), onerror:()=>handleResponse(s,null) }); }); } function handleResponse(site, response){ requestCount++; if(response && response.status===200){ const doc=new DOMParser().parseFromString(response.responseText,'text/html'); const originalPrice = getPriceFromDocument(doc, site.country); const delivery = getDeliveryPriceFromDocument(doc); if(originalPrice !== null){ const coupon = getCouponFromDocument(doc, originalPrice); const convertedPrice = convertToEUR(originalPrice, site.currency); const convertedDelivery = convertToEUR(delivery, getCurrencyByCountry(site.country)); const convertedCoupon = convertToEUR(coupon, site.currency); if(!firstPriceLoaded){ firstPriceLoaded=true; priceContainer = document.querySelector('#amazonPriceComparisonContainer'); if(!priceContainer) return; priceContainer.innerHTML=''; createComparisonTableSkeleton(priceContainer); addControls(priceContainer); addCamelCamelCamelChart(priceContainer); addAliExpressLink(priceContainer); addProductSummary(priceContainer); addFooterAfterProductSummary(); } insertPriceRow({ site, price: convertedPrice, delivery: convertedDelivery, coupon: convertedCoupon, originalCurrency: site.currency }); } } } function createComparisonTableSkeleton(container){ tableContainer = document.createElement('div'); headerRow = document.createElement('div'); headerRow.className = 'comparison-row header-row'; ['Site','Price (EUR)','Coupon (EUR)','Delivery (EUR)','Total (EUR)','Difference'].forEach(h=>{ headerRow.appendChild(createCell(h,true)); }); tableContainer.appendChild(headerRow); container.appendChild(tableContainer); } function insertPriceRow({site, price, delivery, coupon, originalCurrency}){ const total = price - (coupon || 0) + (delivery || 0); const row = document.createElement('div'); row.className = 'comparison-row fade-in'; row.onclick = () => window.open(`https://www.amazon.${site.country}/dp/${asin}?tag=${PARTNER_IDS[s.country]}`, '_blank'); const diff = total - basePrice; const perc = ((diff/basePrice)*100).toFixed(2); const diffClass = diff < 0 ? 'price-difference-positive' : diff > 0 ? 'price-difference-negative' : ''; function createPriceContent(amount){ if(site.needsConversion && exchangeRates[originalCurrency]){ return `€${amount.toFixed(2)}<span class="exchange-info-icon" title="Exchange Rate: 1 EUR = ${exchangeRates[originalCurrency]} ${originalCurrency}">ℹ️</span>`; } else { return `€${amount.toFixed(2)}`; } } row.append( createCell(` <img src="${site.flag}" style="vertical-align:middle;margin-right:5px;width:20px;height:13px;"> ${site.name} `, false, 'first-col'), createCell(createPriceContent(price)), createCell( coupon > 0 ? `<img src="https://img.icons8.com/arcade/64/discount-ticket.png" width="20" style="vertical-align:middle;margin-right:5px;"> €${coupon.toFixed(2)}${site.needsConversion ? `<span class="exchange-info-icon" title="Exchange Rate: 1 EUR = ${exchangeRates[originalCurrency]} ${originalCurrency}">ℹ️</span>` : ''}` : '-' ), createCell( delivery ? `<img src="https://img.icons8.com/arcade/64/in-transit.png" width="20" style="vertical-align:middle;margin-right:5px;"> €${delivery.toFixed(2)}${site.needsConversion ? `<span class="exchange-info-icon" title="Exchange Rate: 1 EUR = ${exchangeRates[originalCurrency]} ${originalCurrency}">ℹ️</span>` : ''}` : '-' ), createCell(`€${total.toFixed(2)}${site.needsConversion ? `<span class="exchange-info-icon" title="Exchange Rate: 1 EUR = ${exchangeRates[originalCurrency]} ${originalCurrency}">ℹ️</span>` : ''}`), createCell( diff !== 0 ? `<span class="${diffClass}"> ${diff >= 0 ? '+' : ''}€${diff.toFixed(2)} (${perc}%) </span>` : '-' ) ); let inserted=false; const rows=[...tableContainer.querySelectorAll('.comparison-row:not(.header-row)')]; for(let i=0;i<rows.length;i++){ const cells=rows[i].querySelectorAll('div'); const existingTotalText = cells[4].textContent.replace(/[^\d.,-]/g,'').replace(',','.'); const existingTotal = parseFloat(existingTotalText) || 999999; if(total < existingTotal){ tableContainer.insertBefore(row,rows[i]); inserted=true; break; } } if(!inserted) tableContainer.appendChild(row); } function createCell(content,isHeader=false,extraClass=''){ const c=document.createElement('div'); c.style.flex='1'; c.innerHTML=content; if(isHeader) c.style.fontWeight='bold'; if(extraClass) c.classList.add(extraClass); return c; } function addControls(container){ const ctrls=document.createElement('div'); ctrls.className='controls-container'; const tps=[ {id:'btn1M',label:'1 Month',val:'1m'}, {id:'btn3M',label:'3 Months',val:'3m'}, {id:'btn6M',label:'6 Months',val:'6m'}, {id:'btn1Y',label:'1 Year',val:'1y'}, {id:'btnAll',label:'All',val:'all'} ]; tps.forEach(tp=>{ const b=document.createElement('button'); b.id=tp.id; b.textContent=tp.label; b.className=`control-button ${tp.val===selectedTimePeriod?'active':''}`; b.addEventListener('click',()=>{ selectedTimePeriod=tp.val; document.querySelectorAll('.control-button').forEach(x=>x.classList.remove('active')); b.classList.add('active'); updateChartUrl(); }); ctrls.appendChild(b); }); const cbs=[ {id:'checkboxAmazon', label:'Amazon', fn:'amazon', dis:true, chk:true}, {id:'checkboxNew', label:'New', fn:'new', chk:true}, {id:'checkboxUsed', label:'Used', fn:'used', chk:false} ]; cbs.forEach(cb=>{ const wrap=document.createElement('div'); wrap.className='checkbox-container'; const i=document.createElement('input'); i.type='checkbox'; i.id=cb.id; i.checked=cb.chk; if(cb.dis) i.disabled=true; i.addEventListener('change',updateChartUrl); const lbl=document.createElement('label'); lbl.htmlFor=cb.id; lbl.textContent=cb.label; lbl.className='checkbox-label'; wrap.append(i,lbl); ctrls.appendChild(wrap); }); container.appendChild(ctrls); } function addCamelCamelCamelChart(container){ const c=document.createElement('div'); c.className='chart-container'; const cc=getCurrentCountryCode(); const url=getCamelChartUrl(cc,asin,selectedTimePeriod); const camelUrl=`https://${cc}.camelcamelcamel.com/product/${asin}`; const spin=document.createElement('div'); spin.className='loader'; const img=document.createElement('img'); img.alt=`Price history for ${asin}`; img.className='chart-image'; img.style.display='none'; img.addEventListener('load',()=>{ spin.style.display='none'; img.style.display='block'; }); img.addEventListener('error',()=>{ spin.style.display='none'; img.style.display='block'; img.src='https://via.placeholder.com/600x300?text=Image+Unavailable'; }); img.src=url; const a=document.createElement('a'); a.href=camelUrl; a.target='_blank'; a.appendChild(img); c.append(spin,a); container.appendChild(c); } function getCamelChartUrl(cc, asin, tp){ const f=getSelectedFilenames(); const base=`https://charts.camelcamelcamel.com/${cc}/${asin}/${f}.png?force=1&zero=0&w=600&h=300&desired=false&legend=1&ilt=1&tp=${tp}&fo=0&lang=en`; return `https://camelcamelcamel.mon-bnj.workers.dev/?target=${encodeURIComponent(base)}`; } function getSelectedFilenames(){ const cbs=[ {id:'checkboxAmazon',fn:'amazon'}, {id:'checkboxNew', fn:'new'}, {id:'checkboxUsed', fn:'used'} ]; return Array.from(document.querySelectorAll('input[type="checkbox"]:checked')) .map(x=>cbs.find(z=>z.id===x.id)?.fn) .filter(Boolean) .join('-'); } function updateChartUrl(){ const cc=getCurrentCountryCode(); const url=getCamelChartUrl(cc,asin,selectedTimePeriod); const camelUrl=`https://${cc}.camelcamelcamel.com/product/${asin}`; const i=document.querySelector('#amazonPriceComparisonContainer img.chart-image'); if(i){ const spin=i.parentElement.parentElement.querySelector('.loader'); if(spin) spin.style.display='inline-block'; i.style.display='none'; i.src=url; i.parentElement.href=camelUrl; } } function createAliExpressLink(title){ const d=document.createElement('div'); d.className='aliexpress-container'; d.innerHTML=` <img src="https://img.icons8.com/color/48/aliexpress.png" class="aliexpress-icon"> <span class="aliexpress-text">Check on AliExpress</span>`; d.addEventListener('click',()=>{ const t=d.querySelector('.aliexpress-text'); t.classList.add('loading-text'); t.textContent='Loading...'; GM_xmlhttpRequest({ method:'GET', url:`https://summarizer.mon-bnj.workers.dev/?text=${encodeURIComponent(title)}`, onload:r=>handleAliExpressResponse(r,d), onerror:()=>{resetAliExpressButton(d);} }); }); return d; } function handleAliExpressResponse(r,c){ try{ const j=JSON.parse(r.responseText); if(j.summary){ const u=`https://www.aliexpress.com/wholesale?SearchText=${encodeURIComponent(j.summary)}`; resetAliExpressButton(c); setTimeout(()=>{window.open(u,'_blank');},100); } else { throw new Error('No summary'); } }catch(e){ resetAliExpressButton(c); } } function resetAliExpressButton(c){ const ic=c.querySelector('.aliexpress-icon'); c.innerHTML=''; c.appendChild(ic); const sp=document.createElement('span'); sp.className='aliexpress-text'; sp.textContent='Check on AliExpress'; c.appendChild(sp); } function addAliExpressLink(c){ const t=document.querySelector('#productTitle'); const pt=t ? t.textContent.trim() : null; if(!pt) return; const ali=createAliExpressLink(pt); c.appendChild(ali); } function addFooterAfterProductSummary(){ if(footerAdded) return; const summaryDiv = document.querySelector('#cr-product-insights-cards'); if(summaryDiv){ const footer=document.createElement('div'); footer.className='footer'; footer.innerHTML=` <img src="https://i.ibb.co/qrjrcVy/amz-price-checker.png" class="footer-logo"> Amazon Price Checker v${GM_info.script.version} `; summaryDiv.parentNode.insertBefore(footer, summaryDiv.nextSibling); footerAdded = true; } } function getCurrentCountryCode(){ const h=window.location.hostname; if(h.includes('amazon.com') && !h.includes('amazon.com.be') && !h.includes('amazon.co.uk')) return 'com'; if(h.includes('amazon.de')) return 'de'; if(h.includes('amazon.es')) return 'es'; if(h.includes('amazon.it')) return 'it'; if(h.includes('amazon.com.be')) return 'com.be'; if(h.includes('amazon.nl')) return 'nl'; if(h.includes('amazon.co.uk')) return 'co.uk'; return 'fr'; } function getCurrencyByCountry(country){ const site = amazonSites.find(s => s.country === country); return site ? site.currency : 'EUR'; } function convertToEUR(amount, currency){ if(!exchangeRates) return amount; if(currency === 'EUR') return amount; const rate = exchangeRates[currency]; if(!rate) return amount; return amount / rate; } function getPriceFromDocument(doc, country){ const el=doc.querySelector('.priceToPay,#priceblock_ourprice,#priceblock_dealprice,#priceblock_saleprice'); if(!el) return null; const rawPrice = parsePrice(el.textContent); const currency = getCurrencyByCountry(country); return convertToEUR(rawPrice, currency); } function parsePrice(t){ if(!t) return null; const c=t.replace(/[^0-9,\.]/g,'').replace(',', '.'); const p=parseFloat(c); return isNaN(p)?null:p; } function getDeliveryPriceFromDocument(doc){ const m=doc.body.innerHTML.match(/data-csa-c-delivery-price="[^"]*?(\d+[.,]\d{2})/); if(m){ const x=m[1].replace(',', '.'); const p=parseFloat(x); return isNaN(p)?0:p; } return 0; } function addProductSummary(container){ const summaryDiv = document.querySelector('#cr-product-insights-cards'); if(summaryDiv){ const summaryClone = summaryDiv.cloneNode(true); summaryClone.classList.add('product-summary-encart'); summaryClone.querySelectorAll('i[id^="close-button-"]').forEach(icon => icon.remove()); container.appendChild(summaryClone); addAspectButtonListeners(summaryClone); } } function addAspectButtonListeners(clonedSummary){ const aspectButtons = clonedSummary.querySelectorAll('[id^="aspect-button-0-"]'); aspectButtons.forEach(button => { button.addEventListener('click', () => { const buttonId = button.id; const parts = buttonId.split('-'); const X = parts[3]; const bottomSheet = document.getElementById(`aspect-bottom-sheet-0-${X}`); if(!bottomSheet){ console.warn(`Feuille inférieure pour ${buttonId} non trouvée.`); return; } document.querySelectorAll('[id^="aspect-bottom-sheet-0-"]').forEach(sheet => sheet.style.display = 'none'); bottomSheet.style.display = 'block'; aspectButtons.forEach(btn => btn.classList.remove('_Y3Itc_selected_2-xMA')); button.classList.add('_Y3Itc_selected_2-xMA'); }); }); } main(); })();