Greasy Fork is available in English.
Wargaming商店外区货币价值转换为CNY并附代充折扣显示(目前支持ARS、SGD、HKD、TWD)
当前为
// ==UserScript==
// @name Wargaming商店外区货币转换器
// @namespace http://tampermonkey.net/
// @version 1.1
// @description Wargaming商店外区货币价值转换为CNY并附代充折扣显示(目前支持ARS、SGD、HKD、TWD)
// @author SundayRX
// @match https://wargaming.net/shop/*
// @grant GM_xmlhttpRequest
// @connect api.exchangerate-api.com
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// 配置
const CONFIG = {
// 打折
discount:0.87, //代冲折扣(自行修改)
// 更新间隔(毫秒)
updateInterval: 600000, // 10分钟
// 高亮样式
highlightStyle: `
.ars-to-cny-conversion {
background-color: #ffffcc;
border-radius: 3px;
padding: 2px 4px;
margin-left: 5px;
font-weight: bold;
font-size: 0.9em;
color: #d32f2f;
}
.ars-to-cny-processed {
display: inline-flex;
align-items: center;
}
`,
// 是否显示原始值
showOriginalValue: true
};
class Currency {
constructor(Type, ExchangeRateAPI, ExchangeRate, MatchRegex) {
this.Type = Type;
this.ExchangeRateAPI = ExchangeRateAPI;
this.ExchangeRate = ExchangeRate;
this.MatchRegex = MatchRegex;
}
}
const CurrencyDict = [
new Currency('ARS', 'https://api.exchangerate-api.com/v4/latest/ARS',0.005,/([\d,]+(?:\.\d+)?)\s*(ARS)/i),
new Currency('SGD', 'https://api.exchangerate-api.com/v4/latest/SGD',5.5,/([\d,]+(?:\.\d+)?)\s*(SGD)/i),
new Currency('HKD', 'https://api.exchangerate-api.com/v4/latest/HKD',0.916,/([\d,]+(?:\.\d+)?)\s*(HKD)/i),
new Currency('TWD', 'https://api.exchangerate-api.com/v4/latest/TWD',0.233,/([\d,]+(?:\.\d+)?)\s*(TWD)/i)
];
let isProcessing = false;
let observer = null;
// 初始化脚本
function init() {
console.log('ARS转CNY转换器已加载');
// 添加样式
addStyles();
// 获取汇率
FetchExchangeRate();
// 设置定期更新汇率
setInterval(FetchExchangeRate, CONFIG.updateInterval);
// 初始转换
convertPageARSValues();
// 监听DOM变化
observeDOMChanges();
}
// 添加样式到页面
function addStyles() {
const style = document.createElement('style');
style.textContent = CONFIG.highlightStyle;
document.head.appendChild(style);
}
// 获取汇率
function FetchExchangeRate() {
for(let C=0;C<CurrencyDict.length;C++)
{
GM_xmlhttpRequest({
method: 'GET',
url: CurrencyDict[C].ExchangeRateAPI,
onload: function(response) {
try {
const data = JSON.parse(response.responseText);
if (data && data.rates && data.rates.CNY) {
CurrencyDict[C].ExchangeRate = data.rates.CNY;
console.log(`汇率已更新: 1 ${CurrencyDict[C].Type} = ${CurrencyDict[C].ExchangeRate} CNY`);
// 更新页面上的转换值
updateConvertedValues();
} else {
console.warn('无法从API获取汇率,使用备用汇率');
}
} catch (e) {
console.warn('解析汇率API响应失败:', e);
}
},
onerror: function(error) {
console.warn('获取汇率失败:', error, '使用备用汇率');
}
});
}
}
function ContainsSpecialValue(text) {
for(let C=0;C<CurrencyDict.length;C++)
{
const arsRegex = CurrencyDict[C].MatchRegex;
if(arsRegex.test(text)) return true;
}
return false;
}
function ExtractSpecialValue(text) {
for(let C=0;C<CurrencyDict.length;C++)
{
const match = text.match(CurrencyDict[C].MatchRegex);
if (match && match[1])
{
const numericValue = match[1].replace(/,/g, '');
return [parseFloat(numericValue),CurrencyDict[C].Type];
}
}
return [null,null];
}
function FormatCurrency(value, currency) {
for(let C=0;C<CurrencyDict.length;C++)
{
if (currency === CurrencyDict[C].Type)
{
const fixValue= value * CurrencyDict[C].ExchangeRate*CONFIG.discount;
return `${(value * CurrencyDict[C].ExchangeRate).toFixed(2)}\(${fixValue.toFixed(2)}\)CNY`;
}
}
return value.toFixed(2);
}
// 转换页面中的ARS值
function convertPageARSValues() {
if (isProcessing) return;
isProcessing = true;
// 暂停DOM监听器,避免重复处理
if (observer) {
observer.disconnect();
}
// 查找所有价格元素
const priceElements = findPriceElements();
// 处理价格元素
priceElements.forEach(processPriceElement);
// 重新启动DOM监听器
if (observer) {
observer.observe(document.body, {
childList: true,
subtree: true
});
}
isProcessing = false;
}
// 查找所有价格元素
function findPriceElements() {
const elements = [];
const seenElements = new Set(); // 用于去重
// 使用更精确的选择器,避免重复匹配
const selectors = [
// '.product-price_old:not(.ars-to-cny-processed)',
// '[data-qa="original_product_price"]:not(.ars-to-cny-processed)',
'.product-price_wrap > span:not(.ars-to-cny-processed)',
'[data-qa="product_price"] > span:not(.ars-to-cny-processed)'
];
selectors.forEach(selector => {
const foundElements = document.querySelectorAll(selector);
foundElements.forEach(element => {
// 检查元素是否包含ARS货币值且未被见过
if (ContainsSpecialValue(element.textContent) && !seenElements.has(element)) {
elements.push(element);
seenElements.add(element);
}
});
});
return elements;
}
// 处理价格元素
function processPriceElement(element) {
if (element.classList.contains('ars-to-cny-processed')) {
return;
}
const originalText = element.textContent.trim();
const [PriceValue,PriceType] = ExtractSpecialValue(originalText);
if (PriceValue !== null && PriceValue!=null) {
const formattedCNY = FormatCurrency(PriceValue, PriceType);
// 检查是否已经存在转换元素
const existingConversion = findExistingConversion(element);
if (existingConversion) {
// 如果已存在,更新它
existingConversion.textContent = `≈${formattedCNY}`;
existingConversion.title = `${formatNumber(PriceValue)} ARS ≈ ${formattedCNY}`;
} else {
// 如果不存在,创建新的转换元素
const conversionElement = document.createElement('span');
conversionElement.className = 'ars-to-cny-conversion';
conversionElement.textContent = `≈${formattedCNY}`;
conversionElement.title = `${formatNumber(PriceValue)} ARS ≈ ${formattedCNY}`;
// 插入到价格元素后面
element.parentNode.insertBefore(conversionElement, element.nextSibling);
}
// 标记元素为已处理
element.classList.add('ars-to-cny-processed');
}
}
// 查找已存在的转换元素
function findExistingConversion(element) {
// 检查相邻的兄弟元素
let sibling = element.nextElementSibling;
while (sibling) {
if (sibling.classList && sibling.classList.contains('ars-to-cny-conversion')) {
return sibling;
}
sibling = sibling.nextElementSibling;
}
// 检查父元素的兄弟元素(针对某些特殊布局)
const parent = element.parentElement;
if (parent && parent.nextElementSibling) {
const nextSibling = parent.nextElementSibling;
if (nextSibling.classList && nextSibling.classList.contains('ars-to-cny-conversion')) {
return nextSibling;
}
}
return null;
}
// 格式化数字(添加千位分隔符)
function formatNumber(num) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
// 更新已转换的值
function updateConvertedValues() {
const convertedElements = document.querySelectorAll('.ars-to-cny-conversion');
convertedElements.forEach(element => {
// 查找相邻的价格元素
const priceElement = findAdjacentPriceElement(element);
if (priceElement) {
const originalText = priceElement.textContent.trim();
const [PriceValue,PriceType] = ExtractSpecialValue(originalText);
if (PriceValue !== null && PriceType!=null) {
const formattedCNY = FormatCurrency(PriceValue, PriceType);
element.textContent = `≈${formattedCNY}`;
element.title = `${formatNumber(PriceValue)} ARS ≈ ${formattedCNY}`;
}
}
});
}
// 查找相邻的价格元素
function findAdjacentPriceElement(conversionElement) {
// 检查前一个兄弟元素
let sibling = conversionElement.previousElementSibling;
while (sibling) {
if (sibling.classList && sibling.classList.contains('ars-to-cny-processed')) {
return sibling;
}
sibling = sibling.previousElementSibling;
}
// 检查父元素的前一个兄弟元素
const parent = conversionElement.parentElement;
if (parent && parent.previousElementSibling) {
const prevSibling = parent.previousElementSibling;
if (prevSibling.classList && prevSibling.classList.contains('ars-to-cny-processed')) {
return prevSibling;
}
}
return null;
}
// 监听DOM变化
function observeDOMChanges() {
observer = new MutationObserver(function(mutations) {
let shouldConvert = false;
mutations.forEach(function(mutation) {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(function(node) {
if (node.nodeType === Node.ELEMENT_NODE) {
// 检查新添加的元素是否包含价格元素
const priceSelectors = [
// '.product-price_old:not(.ars-to-cny-processed)',
// '[data-qa="original_product_price"]:not(.ars-to-cny-processed)',
'.product-price_wrap > span:not(.ars-to-cny-processed)',
'[data-qa="product_price"] > span:not(.ars-to-cny-processed)'
];
const priceElements = node.querySelectorAll ?
node.querySelectorAll(priceSelectors.join(', ')) : [];
if (priceElements.length > 0) {
shouldConvert = true;
}
// 检查元素本身是否是价格元素
if (node.matches && node.matches(priceSelectors.join(', '))) {
shouldConvert = true;
}
}
});
}
});
if (shouldConvert && !isProcessing) {
// 使用防抖,避免频繁处理
clearTimeout(window.arsToCnyTimeout);
window.arsToCnyTimeout = setTimeout(() => {
convertPageARSValues();
}, 500);
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
// 页面加载完成后初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();