您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds the currently-for-sale price average to BL store listings
// ==UserScript== // @name BrickLink Price Averages // @name:en BrickLink Price Averages // @namespace Violentmonkey Scripts // @match https://store.bricklink.com/* // @grant none // @version 1.0 // @author The0x539 // @description Adds the currently-for-sale price average to BL store listings // @run-at document-body // @license AGPL-3.0 // ==/UserScript== const RealXMLHttpRequest = window.XMLHttpRequest; class PatchedXMLHttpRequest extends RealXMLHttpRequest { constructor(...args) { super(...args); this.isSearch = false; this.jobDone = false; } open(...args) { if (args[1].startsWith('/ajax/clone/store/searchitems.ajax')) { this.isSearch = true; } return super.open(...args); } get responseText() { if (this.isSearch && !this.jobDone) { const response = JSON.parse(super.responseText); processSearchResponse(response); this.jobDone = true; } return super.responseText; } } window.XMLHttpRequest = PatchedXMLHttpRequest; const promises = new Map(); function processSearchResponse(response) { for (const item of response.result.groups.flatMap(g => g.items)) { const { itemID, colorID, itemName, colorName } = item; const key = (colorName + '\xA0' + itemName).trimStart(); if (!promises.has(key)) { promises.set(key, getPrices(itemID, colorID)); } } } async function getPrices(itemID, colorID) { const response = await fetch(`/v2/catalog/catalogitem_pgtab.page?idItem=${itemID}&idColor=${colorID}`); const html = await response.text(); const doc = new DOMParser().parseFromString(html, 'text/html'); const rows = doc.querySelectorAll('table.pcipgSummaryTable tr'); const averages = [...rows] .filter(row => row.firstElementChild.innerText === 'Avg Price:') .map(row => row.lastElementChild.innerText); const [new6Months, used6Months, newForSale, usedForSale] = averages; return { new6Months, used6Months, newForSale, usedForSale }; } function onUpdatePage(records, observer) { const selector = '.store-items article.table-row:not(:has(.buy div.average))'; const rows = records .flatMap(r => [...r.addedNodes]) .filter(n => n instanceof HTMLElement) .flatMap(n => [...n.querySelectorAll(selector)]); for (const row of rows) { addAverage(row); } } async function addAverage(listing) { const key = listing.querySelector('.description p').innerText; const prices = await promises.get(key); const condition = listing.querySelector('.condition strong').innerText; const price = (condition === 'Used') ? prices.usedForSale : prices.newForSale; const newHtml = ` <div class="average"> <span>Average: </span> <strong>${price}</strong> </div> `; listing.querySelector('.buy').children[1].insertAdjacentHTML('afterend', newHtml); } const observeOptions = { childList: true, subtree: true }; new MutationObserver(onUpdatePage).observe(document.body, observeOptions);