您需要先安装一个扩展,例如 篡改猴、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);