您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
YM Real Price: An unofficial script for market.yandex.ru that displays each item’s original price directly on the list page. This script is not affiliated with or endorsed by Yandex. It runs entirely on the client side—parsing only publicly available DOM data—without using any private APIs or collecting/transmitting your personal information. Use at your own risk: changes to Yandex.Market’s page structure may break functionality, and the author accepts no liability for any resulting damages.
// ==UserScript== // @name YM Real Price // @namespace http://tampermonkey.net/ // @version 0.1 // @description YM Real Price: An unofficial script for market.yandex.ru that displays each item’s original price directly on the list page. This script is not affiliated with or endorsed by Yandex. It runs entirely on the client side—parsing only publicly available DOM data—without using any private APIs or collecting/transmitting your personal information. Use at your own risk: changes to Yandex.Market’s page structure may break functionality, and the author accepts no liability for any resulting damages. // @match https://market.yandex.ru/* // @grant GM_xmlhttpRequest // @license MIT // @license https://opensource.org/licenses/MIT // @connect market.yandex.ru // ==/UserScript== /* jshint esversion: 8 */ (async function() { 'use strict'; // —————— .ym-old-price —————— const style = document.createElement('style'); style.textContent = ` .ym-old-price .ds-text { color: black !important; font-weight: 600; } `; document.head.appendChild(style); // ———————————————— const SELECTOR_LINK = '[data-auto="snippet-link"]'; const SELECTOR_LINK_OLD = '[data-auto="snippet-price-old"]'; const SELECTOR_CONTAINERS = [ '[data-zone-name="ScrollBox"]', '[data-zone-name="searchPage"]', '[data-zone-name="RecommendationRoll"]', '[data-zone-name="carouselWithLogo"]' ].join(','); const ZONE_PRICE = 'price'; const SELECTOR_PRICE_LINE = '.ds-valueLine'; const inUse = new Set(); const initialized = new WeakSet(); function wait(ms){ return new Promise(r=>setTimeout(r,ms)); } function rnd(min,max){ return Math.floor(Math.random()*(max-min+1))+min; } // wrapper for GM_xmlhttpRequest → Promise of response object function gmFetch(url) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url, responseType: 'text', onload: res => resolve(res), onerror: err => reject(err) }); }); } // retry once after 3–4s if status 429 async function gmFetchWithRetry(url) { let res = await gmFetch(url); if (res.status === 429) { const delay = rnd(5000, 10000); console.warn(`YM Real Price: 429 for ${url}, retrying after ${delay}ms`); await wait(delay); res = await gmFetch(url); if (res.status === 429) { console.error(`YM Real Price: 429 again for ${url}, giving up`); throw new Error('429 Too Many Requests'); } } if (res.status < 200 || res.status >= 300) { throw new Error(`HTTP ${res.status}`); } return res.responseText; } async function processAllCards(container) { const cards = Array.from( container.querySelectorAll(SELECTOR_LINK) ).filter(c=> c.parentNode.parentNode.dataset.zoneName===ZONE_PRICE ); for(const card of cards){ const link = card.href; if(!link|| inUse.has(link)) continue; inUse.add(link); await wait(rnd(500,2000)); let html; try { html = await gmFetchWithRetry(link); } catch (e) { console.error(`YM Real Price: failed to fetch ${link}:`, e); continue; } try { const doc = new DOMParser().parseFromString(html, 'text/html'); const oldWrap = doc.querySelector(SELECTOR_LINK_OLD); if (!oldWrap) continue; const price = oldWrap.querySelector(SELECTOR_PRICE_LINE); price.className = 'ym-old-price'; card.appendChild(price); } catch (e) { console.warn(`YM Real Price: parsing/inject error for ${link}:`, e); } } } function initContainer(container) { if (initialized.has(container)) return; initialized.add(container); processAllCards(container); const mo = new MutationObserver(() => processAllCards(container)); mo.observe(container, { childList: true, subtree: true }); } function scanForContainers() { document .querySelectorAll(SELECTOR_CONTAINERS) .forEach(initContainer); } scanForContainers(); const bodyObserver = new MutationObserver(muts => { for (const m of muts) { for (const node of m.addedNodes) { if (!(node instanceof HTMLElement)) continue; if (node.matches(SELECTOR_CONTAINERS)) { initContainer(node); } node .querySelectorAll(SELECTOR_CONTAINERS) .forEach(initContainer); } } }); bodyObserver.observe(document.body, { childList: true, subtree: true }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址