在您安装前,Greasy Fork 希望您知道此脚本声明其包含了一些负面功能。这些功能也许会使脚本作者获利,而不能给您带来任何直接的金钱收益。
作者可从这份脚本获得佣金,例如通过修改链接地址或提供优惠券代码以包含推荐或附属代码。
此脚本含有追踪您的操作的代码。
Maximize your savings by effortlessly comparing prices across Amazon.fr, .de, .es, .it, .be, .nl, and .com. Automatically detect coupons, enjoy fast dynamic result displays, access comprehensive price histories with CamelCamelCamel, 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, COM) + AliExpress // @namespace http://tampermonkey.net/ // @version 3.04 // @description Maximize your savings by effortlessly comparing prices across Amazon.fr, .de, .es, .it, .be, .nl, and .com. Automatically detect coupons, enjoy fast dynamic result displays, access comprehensive price histories with CamelCamelCamel, 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.com/* // @grant GM_xmlhttpRequest // @connect amazon.fr // @connect amazon.es // @connect amazon.it // @connect amazon.de // @connect amazon.com.be // @connect amazon.nl // @connect amazon.com // @connect summarizer.mon-bnj.workers.dev // @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', com: 'bnjmazon-20' }; const amazonSites = [ { name:'Amazon.fr', country:'fr', flag:'https://flagcdn.com/w20/fr.png' }, { name:'Amazon.es', country:'es', flag:'https://flagcdn.com/w20/es.png' }, { name:'Amazon.it', country:'it', flag:'https://flagcdn.com/w20/it.png' }, { name:'Amazon.de', country:'de', flag:'https://flagcdn.com/w20/de.png' }, { name:'Amazon.be', country:'com.be', flag:'https://flagcdn.com/w20/be.png' }, { name:'Amazon.nl', country:'nl', flag:'https://flagcdn.com/w20/nl.png' }, { name:'Amazon.com', country:'com', flag:'https://flagcdn.com/w20/us.png' } ]; let asin, basePrice, selectedTimePeriod = 'all'; let priceResults = [], requestCount = 0, firstPriceLoaded = false; let tableContainer, headerRow, priceContainer; function main(){ if(!extractASIN() || !getBasePrice()) return; injectStyles(); createLoadingContainer(); fetchPricesFromOtherSites(); } function extractASIN(){ const m = window.location.href.match(ASIN_REGEX); if(!m) return false; asin = m[1]; return true; } function getBasePrice(){ basePrice = getPriceFromDocument(document); return basePrice !== null; } 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; //text-align:right !important; } .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 } .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 } `; 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 p=getPriceFromDocument(doc); const d=getDeliveryPriceFromDocument(doc); if(p!==null){ const c=getCouponFromDocument(doc,p); if(!firstPriceLoaded){ priceContainer = document.querySelector('#amazonPriceComparisonContainer'); if(!priceContainer) return; priceContainer.innerHTML=''; createComparisonTableSkeleton(priceContainer); addControls(priceContainer); addCamelCamelCamelChart(priceContainer); addAliExpressLink(priceContainer); addFooter(priceContainer); firstPriceLoaded=true; } insertPriceRow({site,price:p,delivery:d,coupon:c}); } } } function createComparisonTableSkeleton(container){ tableContainer = document.createElement('div'); headerRow = document.createElement('div'); headerRow.className = 'comparison-row header-row'; ['Site','Price','Coupon','Delivery','Total','Difference'].forEach(h=>{ headerRow.appendChild(createCell(h,true)); }); tableContainer.appendChild(headerRow); container.appendChild(tableContainer); } function insertPriceRow({site,price,delivery,coupon}){ 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[site.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' : ''; row.append( createCell(` <img src="${site.flag}" style="vertical-align:middle;margin-right:5px;width:20px;height:13px;"> ${site.name} `, false, 'first-col'), createCell(`€${price.toFixed(2)}`), 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)}` : '-' ), 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)}` : '-' ), createCell(`€${total.toFixed(2)}`), 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.className='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 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 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 addFooter(c){ const f=document.createElement('div'); f.className='footer'; f.innerHTML=` <img src="https://i.ibb.co/qrjrcVy/amz-price-checker.png" class="footer-logo"> Amazon Price Checker v${GM_info.script.version} `; c.appendChild(f); } function getCurrentCountryCode(){ const h=window.location.hostname; if(h.includes('amazon.com') && !h.includes('amazon.com.be')) 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'; return 'fr'; } function getPriceFromDocument(doc){ const el=doc.querySelector('.priceToPay,#priceblock_ourprice,#priceblock_dealprice,#priceblock_saleprice'); if(!el) return null; return parsePrice(el.textContent); } 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; } main(); })();