// ==UserScript==
// @name steam价格转换
// @namespace https://github.com/marioplus/steam-price-converter
// @version 2.4.4
// @author marioplus
// @description steam商店中的价格转换为人民币
// @license GPL-3.0-or-later
// @icon https://vitejs.dev/logo.svg
// @homepage https://github.com/marioplus
// @match https://store.steampowered.com/*
// @match https://steamcommunity.com/*
// @require https://cdn.jsdelivr.net/npm/reflect-metadata@0.1.13/Reflect.min.js
// @require data:application/javascript,%3Bvar%20Reflect%3Dwindow.Reflect%3B
// @require https://cdn.jsdelivr.net/npm/mdui@2.1.1/mdui.global.min.js
// @require https://cdn.jsdelivr.net/npm/vue@3.3.4/dist/vue.global.prod.js
// @resource mdui/mdui.css https://cdn.jsdelivr.net/npm/mdui@2.1.1/mdui.css
// @connect api.augmentedsteam.com
// @connect store.steampowered.com
// @connect cdn.jsdelivr.net
// @grant GM_addStyle
// @grant GM_addValueChangeListener
// @grant GM_cookie
// @grant GM_deleteValue
// @grant GM_getResourceText
// @grant GM_getValue
// @grant GM_info
// @grant GM_registerMenuCommand
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// ==/UserScript==
(e=>{if(typeof GM_addStyle=="function"){GM_addStyle(e);return}const t=document.createElement("style");t.textContent=e,document.head.append(t)})(" .setting-item[data-v-34f99f99]{color:rgb(var(--mdui-color-on-surface));padding:1em .75em;min-width:33em}.setting-item-title[data-v-34f99f99]{display:flex;align-items:center;padding:8px 0}.setting-item-title label[data-v-34f99f99]{display:inline-block;padding-right:.4em;font-size:var(--mdui-typescale-body-large-size);font-weight:var(--mdui-typescale-body-medium-weight);letter-spacing:var(--mdui-typescale-body-medium-tracking);line-height:var(--mdui-typescale-body-medium-line-height)}.setting-item-title .setting-region-title-icon[data-v-34f99f99]{font-size:var(--mdui-typescale-body-large-size)}mdui-select[data-v-34f99f99]::part(menu){max-height:256px;overflow:auto}mdui-text-field[data-v-34f99f99]::part(suffix){color:#00f} ");
(async function (reflectMetadata, mdui, vue) {
'use strict';
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
const cssLoader = (e) => {
const t = GM_getResourceText(e);
return GM_addStyle(t), t;
};
cssLoader("mdui/mdui.css");
class AbstractConverter {
/**
* 匹配到的元素,是否匹配这个 exchanger
* @param elementSnap 选择器选择到的元素快照
*/
match(elementSnap) {
if (!elementSnap || !elementSnap.element) {
return false;
}
const content = elementSnap.textContext;
if (!content) {
return false;
}
if (content.match(/\d/) === null) {
return false;
}
if (/^[,.\d\s]+$/.test(content)) {
return false;
}
const parent = elementSnap.element.parentElement;
if (!parent) {
return false;
}
for (const selector of this.getCssSelectors()) {
const element = parent.querySelector(selector);
if (element && element === elementSnap.element) {
elementSnap.selector = selector;
return true;
}
}
return false;
}
/**
* 替换之后的操作
* @param elementSnap 选择器选择到的元素快照
*/
// @ts-ignore
afterConvert(elementSnap) {
}
}
var TransformationType;
(function(TransformationType2) {
TransformationType2[TransformationType2["PLAIN_TO_CLASS"] = 0] = "PLAIN_TO_CLASS";
TransformationType2[TransformationType2["CLASS_TO_PLAIN"] = 1] = "CLASS_TO_PLAIN";
TransformationType2[TransformationType2["CLASS_TO_CLASS"] = 2] = "CLASS_TO_CLASS";
})(TransformationType || (TransformationType = {}));
var MetadataStorage = (
/** @class */
function() {
function MetadataStorage2() {
this._typeMetadatas = /* @__PURE__ */ new Map();
this._transformMetadatas = /* @__PURE__ */ new Map();
this._exposeMetadatas = /* @__PURE__ */ new Map();
this._excludeMetadatas = /* @__PURE__ */ new Map();
this._ancestorsMap = /* @__PURE__ */ new Map();
}
MetadataStorage2.prototype.addTypeMetadata = function(metadata) {
if (!this._typeMetadatas.has(metadata.target)) {
this._typeMetadatas.set(metadata.target, /* @__PURE__ */ new Map());
}
this._typeMetadatas.get(metadata.target).set(metadata.propertyName, metadata);
};
MetadataStorage2.prototype.addTransformMetadata = function(metadata) {
if (!this._transformMetadatas.has(metadata.target)) {
this._transformMetadatas.set(metadata.target, /* @__PURE__ */ new Map());
}
if (!this._transformMetadatas.get(metadata.target).has(metadata.propertyName)) {
this._transformMetadatas.get(metadata.target).set(metadata.propertyName, []);
}
this._transformMetadatas.get(metadata.target).get(metadata.propertyName).push(metadata);
};
MetadataStorage2.prototype.addExposeMetadata = function(metadata) {
if (!this._exposeMetadatas.has(metadata.target)) {
this._exposeMetadatas.set(metadata.target, /* @__PURE__ */ new Map());
}
this._exposeMetadatas.get(metadata.target).set(metadata.propertyName, metadata);
};
MetadataStorage2.prototype.addExcludeMetadata = function(metadata) {
if (!this._excludeMetadatas.has(metadata.target)) {
this._excludeMetadatas.set(metadata.target, /* @__PURE__ */ new Map());
}
this._excludeMetadatas.get(metadata.target).set(metadata.propertyName, metadata);
};
MetadataStorage2.prototype.findTransformMetadatas = function(target, propertyName, transformationType) {
return this.findMetadatas(this._transformMetadatas, target, propertyName).filter(function(metadata) {
if (!metadata.options)
return true;
if (metadata.options.toClassOnly === true && metadata.options.toPlainOnly === true)
return true;
if (metadata.options.toClassOnly === true) {
return transformationType === TransformationType.CLASS_TO_CLASS || transformationType === TransformationType.PLAIN_TO_CLASS;
}
if (metadata.options.toPlainOnly === true) {
return transformationType === TransformationType.CLASS_TO_PLAIN;
}
return true;
});
};
MetadataStorage2.prototype.findExcludeMetadata = function(target, propertyName) {
return this.findMetadata(this._excludeMetadatas, target, propertyName);
};
MetadataStorage2.prototype.findExposeMetadata = function(target, propertyName) {
return this.findMetadata(this._exposeMetadatas, target, propertyName);
};
MetadataStorage2.prototype.findExposeMetadataByCustomName = function(target, name) {
return this.getExposedMetadatas(target).find(function(metadata) {
return metadata.options && metadata.options.name === name;
});
};
MetadataStorage2.prototype.findTypeMetadata = function(target, propertyName) {
return this.findMetadata(this._typeMetadatas, target, propertyName);
};
MetadataStorage2.prototype.getStrategy = function(target) {
var excludeMap = this._excludeMetadatas.get(target);
var exclude = excludeMap && excludeMap.get(void 0);
var exposeMap = this._exposeMetadatas.get(target);
var expose = exposeMap && exposeMap.get(void 0);
if (exclude && expose || !exclude && !expose)
return "none";
return exclude ? "excludeAll" : "exposeAll";
};
MetadataStorage2.prototype.getExposedMetadatas = function(target) {
return this.getMetadata(this._exposeMetadatas, target);
};
MetadataStorage2.prototype.getExcludedMetadatas = function(target) {
return this.getMetadata(this._excludeMetadatas, target);
};
MetadataStorage2.prototype.getExposedProperties = function(target, transformationType) {
return this.getExposedMetadatas(target).filter(function(metadata) {
if (!metadata.options)
return true;
if (metadata.options.toClassOnly === true && metadata.options.toPlainOnly === true)
return true;
if (metadata.options.toClassOnly === true) {
return transformationType === TransformationType.CLASS_TO_CLASS || transformationType === TransformationType.PLAIN_TO_CLASS;
}
if (metadata.options.toPlainOnly === true) {
return transformationType === TransformationType.CLASS_TO_PLAIN;
}
return true;
}).map(function(metadata) {
return metadata.propertyName;
});
};
MetadataStorage2.prototype.getExcludedProperties = function(target, transformationType) {
return this.getExcludedMetadatas(target).filter(function(metadata) {
if (!metadata.options)
return true;
if (metadata.options.toClassOnly === true && metadata.options.toPlainOnly === true)
return true;
if (metadata.options.toClassOnly === true) {
return transformationType === TransformationType.CLASS_TO_CLASS || transformationType === TransformationType.PLAIN_TO_CLASS;
}
if (metadata.options.toPlainOnly === true) {
return transformationType === TransformationType.CLASS_TO_PLAIN;
}
return true;
}).map(function(metadata) {
return metadata.propertyName;
});
};
MetadataStorage2.prototype.clear = function() {
this._typeMetadatas.clear();
this._exposeMetadatas.clear();
this._excludeMetadatas.clear();
this._ancestorsMap.clear();
};
MetadataStorage2.prototype.getMetadata = function(metadatas, target) {
var metadataFromTargetMap = metadatas.get(target);
var metadataFromTarget;
if (metadataFromTargetMap) {
metadataFromTarget = Array.from(metadataFromTargetMap.values()).filter(function(meta) {
return meta.propertyName !== void 0;
});
}
var metadataFromAncestors = [];
for (var _i = 0, _a = this.getAncestors(target); _i < _a.length; _i++) {
var ancestor = _a[_i];
var ancestorMetadataMap = metadatas.get(ancestor);
if (ancestorMetadataMap) {
var metadataFromAncestor = Array.from(ancestorMetadataMap.values()).filter(function(meta) {
return meta.propertyName !== void 0;
});
metadataFromAncestors.push.apply(metadataFromAncestors, metadataFromAncestor);
}
}
return metadataFromAncestors.concat(metadataFromTarget || []);
};
MetadataStorage2.prototype.findMetadata = function(metadatas, target, propertyName) {
var metadataFromTargetMap = metadatas.get(target);
if (metadataFromTargetMap) {
var metadataFromTarget = metadataFromTargetMap.get(propertyName);
if (metadataFromTarget) {
return metadataFromTarget;
}
}
for (var _i = 0, _a = this.getAncestors(target); _i < _a.length; _i++) {
var ancestor = _a[_i];
var ancestorMetadataMap = metadatas.get(ancestor);
if (ancestorMetadataMap) {
var ancestorResult = ancestorMetadataMap.get(propertyName);
if (ancestorResult) {
return ancestorResult;
}
}
}
return void 0;
};
MetadataStorage2.prototype.findMetadatas = function(metadatas, target, propertyName) {
var metadataFromTargetMap = metadatas.get(target);
var metadataFromTarget;
if (metadataFromTargetMap) {
metadataFromTarget = metadataFromTargetMap.get(propertyName);
}
var metadataFromAncestorsTarget = [];
for (var _i = 0, _a = this.getAncestors(target); _i < _a.length; _i++) {
var ancestor = _a[_i];
var ancestorMetadataMap = metadatas.get(ancestor);
if (ancestorMetadataMap) {
if (ancestorMetadataMap.has(propertyName)) {
metadataFromAncestorsTarget.push.apply(metadataFromAncestorsTarget, ancestorMetadataMap.get(propertyName));
}
}
}
return metadataFromAncestorsTarget.slice().reverse().concat((metadataFromTarget || []).slice().reverse());
};
MetadataStorage2.prototype.getAncestors = function(target) {
if (!target)
return [];
if (!this._ancestorsMap.has(target)) {
var ancestors = [];
for (var baseClass = Object.getPrototypeOf(target.prototype.constructor); typeof baseClass.prototype !== "undefined"; baseClass = Object.getPrototypeOf(baseClass.prototype.constructor)) {
ancestors.push(baseClass);
}
this._ancestorsMap.set(target, ancestors);
}
return this._ancestorsMap.get(target);
};
return MetadataStorage2;
}()
);
var defaultMetadataStorage = new MetadataStorage();
function getGlobal() {
if (typeof globalThis !== "undefined") {
return globalThis;
}
if (typeof global !== "undefined") {
return global;
}
if (typeof window !== "undefined") {
return window;
}
if (typeof self !== "undefined") {
return self;
}
}
function isPromise(p) {
return p !== null && typeof p === "object" && typeof p.then === "function";
}
var __spreadArray = function(to, from, pack) {
for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar)
ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
function instantiateArrayType(arrayType) {
var array = new arrayType();
if (!(array instanceof Set) && !("push" in array)) {
return [];
}
return array;
}
var TransformOperationExecutor = (
/** @class */
function() {
function TransformOperationExecutor2(transformationType, options) {
this.transformationType = transformationType;
this.options = options;
this.recursionStack = /* @__PURE__ */ new Set();
}
TransformOperationExecutor2.prototype.transform = function(source, value, targetType, arrayType, isMap, level) {
var _this = this;
if (level === void 0) {
level = 0;
}
if (Array.isArray(value) || value instanceof Set) {
var newValue_1 = arrayType && this.transformationType === TransformationType.PLAIN_TO_CLASS ? instantiateArrayType(arrayType) : [];
value.forEach(function(subValue, index) {
var subSource = source ? source[index] : void 0;
if (!_this.options.enableCircularCheck || !_this.isCircular(subValue)) {
var realTargetType = void 0;
if (typeof targetType !== "function" && targetType && targetType.options && targetType.options.discriminator && targetType.options.discriminator.property && targetType.options.discriminator.subTypes) {
if (_this.transformationType === TransformationType.PLAIN_TO_CLASS) {
realTargetType = targetType.options.discriminator.subTypes.find(function(subType) {
return subType.name === subValue[targetType.options.discriminator.property];
});
var options = { newObject: newValue_1, object: subValue, property: void 0 };
var newType = targetType.typeFunction(options);
realTargetType === void 0 ? realTargetType = newType : realTargetType = realTargetType.value;
if (!targetType.options.keepDiscriminatorProperty)
delete subValue[targetType.options.discriminator.property];
}
if (_this.transformationType === TransformationType.CLASS_TO_CLASS) {
realTargetType = subValue.constructor;
}
if (_this.transformationType === TransformationType.CLASS_TO_PLAIN) {
subValue[targetType.options.discriminator.property] = targetType.options.discriminator.subTypes.find(function(subType) {
return subType.value === subValue.constructor;
}).name;
}
} else {
realTargetType = targetType;
}
var value_1 = _this.transform(subSource, subValue, realTargetType, void 0, subValue instanceof Map, level + 1);
if (newValue_1 instanceof Set) {
newValue_1.add(value_1);
} else {
newValue_1.push(value_1);
}
} else if (_this.transformationType === TransformationType.CLASS_TO_CLASS) {
if (newValue_1 instanceof Set) {
newValue_1.add(subValue);
} else {
newValue_1.push(subValue);
}
}
});
return newValue_1;
} else if (targetType === String && !isMap) {
if (value === null || value === void 0)
return value;
return String(value);
} else if (targetType === Number && !isMap) {
if (value === null || value === void 0)
return value;
return Number(value);
} else if (targetType === Boolean && !isMap) {
if (value === null || value === void 0)
return value;
return Boolean(value);
} else if ((targetType === Date || value instanceof Date) && !isMap) {
if (value instanceof Date) {
return new Date(value.valueOf());
}
if (value === null || value === void 0)
return value;
return new Date(value);
} else if (!!getGlobal().Buffer && (targetType === Buffer || value instanceof Buffer) && !isMap) {
if (value === null || value === void 0)
return value;
return Buffer.from(value);
} else if (isPromise(value) && !isMap) {
return new Promise(function(resolve, reject) {
value.then(function(data) {
return resolve(_this.transform(void 0, data, targetType, void 0, void 0, level + 1));
}, reject);
});
} else if (!isMap && value !== null && typeof value === "object" && typeof value.then === "function") {
return value;
} else if (typeof value === "object" && value !== null) {
if (!targetType && value.constructor !== Object)
if (!Array.isArray(value) && value.constructor === Array)
;
else {
targetType = value.constructor;
}
if (!targetType && source)
targetType = source.constructor;
if (this.options.enableCircularCheck) {
this.recursionStack.add(value);
}
var keys = this.getKeys(targetType, value, isMap);
var newValue = source ? source : {};
if (!source && (this.transformationType === TransformationType.PLAIN_TO_CLASS || this.transformationType === TransformationType.CLASS_TO_CLASS)) {
if (isMap) {
newValue = /* @__PURE__ */ new Map();
} else if (targetType) {
newValue = new targetType();
} else {
newValue = {};
}
}
var _loop_1 = function(key2) {
if (key2 === "__proto__" || key2 === "constructor") {
return "continue";
}
var valueKey = key2;
var newValueKey = key2, propertyName = key2;
if (!this_1.options.ignoreDecorators && targetType) {
if (this_1.transformationType === TransformationType.PLAIN_TO_CLASS) {
var exposeMetadata = defaultMetadataStorage.findExposeMetadataByCustomName(targetType, key2);
if (exposeMetadata) {
propertyName = exposeMetadata.propertyName;
newValueKey = exposeMetadata.propertyName;
}
} else if (this_1.transformationType === TransformationType.CLASS_TO_PLAIN || this_1.transformationType === TransformationType.CLASS_TO_CLASS) {
var exposeMetadata = defaultMetadataStorage.findExposeMetadata(targetType, key2);
if (exposeMetadata && exposeMetadata.options && exposeMetadata.options.name) {
newValueKey = exposeMetadata.options.name;
}
}
}
var subValue = void 0;
if (this_1.transformationType === TransformationType.PLAIN_TO_CLASS) {
subValue = value[valueKey];
} else {
if (value instanceof Map) {
subValue = value.get(valueKey);
} else if (value[valueKey] instanceof Function) {
subValue = value[valueKey]();
} else {
subValue = value[valueKey];
}
}
var type = void 0, isSubValueMap = subValue instanceof Map;
if (targetType && isMap) {
type = targetType;
} else if (targetType) {
var metadata_1 = defaultMetadataStorage.findTypeMetadata(targetType, propertyName);
if (metadata_1) {
var options = { newObject: newValue, object: value, property: propertyName };
var newType = metadata_1.typeFunction ? metadata_1.typeFunction(options) : metadata_1.reflectedType;
if (metadata_1.options && metadata_1.options.discriminator && metadata_1.options.discriminator.property && metadata_1.options.discriminator.subTypes) {
if (!(value[valueKey] instanceof Array)) {
if (this_1.transformationType === TransformationType.PLAIN_TO_CLASS) {
type = metadata_1.options.discriminator.subTypes.find(function(subType) {
if (subValue && subValue instanceof Object && metadata_1.options.discriminator.property in subValue) {
return subType.name === subValue[metadata_1.options.discriminator.property];
}
});
type === void 0 ? type = newType : type = type.value;
if (!metadata_1.options.keepDiscriminatorProperty) {
if (subValue && subValue instanceof Object && metadata_1.options.discriminator.property in subValue) {
delete subValue[metadata_1.options.discriminator.property];
}
}
}
if (this_1.transformationType === TransformationType.CLASS_TO_CLASS) {
type = subValue.constructor;
}
if (this_1.transformationType === TransformationType.CLASS_TO_PLAIN) {
if (subValue) {
subValue[metadata_1.options.discriminator.property] = metadata_1.options.discriminator.subTypes.find(function(subType) {
return subType.value === subValue.constructor;
}).name;
}
}
} else {
type = metadata_1;
}
} else {
type = newType;
}
isSubValueMap = isSubValueMap || metadata_1.reflectedType === Map;
} else if (this_1.options.targetMaps) {
this_1.options.targetMaps.filter(function(map) {
return map.target === targetType && !!map.properties[propertyName];
}).forEach(function(map) {
return type = map.properties[propertyName];
});
} else if (this_1.options.enableImplicitConversion && this_1.transformationType === TransformationType.PLAIN_TO_CLASS) {
var reflectedType = Reflect.getMetadata("design:type", targetType.prototype, propertyName);
if (reflectedType) {
type = reflectedType;
}
}
}
var arrayType_1 = Array.isArray(value[valueKey]) ? this_1.getReflectedType(targetType, propertyName) : void 0;
var subSource = source ? source[valueKey] : void 0;
if (newValue.constructor.prototype) {
var descriptor = Object.getOwnPropertyDescriptor(newValue.constructor.prototype, newValueKey);
if ((this_1.transformationType === TransformationType.PLAIN_TO_CLASS || this_1.transformationType === TransformationType.CLASS_TO_CLASS) && // eslint-disable-next-line @typescript-eslint/unbound-method
(descriptor && !descriptor.set || newValue[newValueKey] instanceof Function))
return "continue";
}
if (!this_1.options.enableCircularCheck || !this_1.isCircular(subValue)) {
var transformKey = this_1.transformationType === TransformationType.PLAIN_TO_CLASS ? newValueKey : key2;
var finalValue = void 0;
if (this_1.transformationType === TransformationType.CLASS_TO_PLAIN) {
finalValue = value[transformKey];
finalValue = this_1.applyCustomTransformations(finalValue, targetType, transformKey, value, this_1.transformationType);
finalValue = value[transformKey] === finalValue ? subValue : finalValue;
finalValue = this_1.transform(subSource, finalValue, type, arrayType_1, isSubValueMap, level + 1);
} else {
if (subValue === void 0 && this_1.options.exposeDefaultValues) {
finalValue = newValue[newValueKey];
} else {
finalValue = this_1.transform(subSource, subValue, type, arrayType_1, isSubValueMap, level + 1);
finalValue = this_1.applyCustomTransformations(finalValue, targetType, transformKey, value, this_1.transformationType);
}
}
if (finalValue !== void 0 || this_1.options.exposeUnsetFields) {
if (newValue instanceof Map) {
newValue.set(newValueKey, finalValue);
} else {
newValue[newValueKey] = finalValue;
}
}
} else if (this_1.transformationType === TransformationType.CLASS_TO_CLASS) {
var finalValue = subValue;
finalValue = this_1.applyCustomTransformations(finalValue, targetType, key2, value, this_1.transformationType);
if (finalValue !== void 0 || this_1.options.exposeUnsetFields) {
if (newValue instanceof Map) {
newValue.set(newValueKey, finalValue);
} else {
newValue[newValueKey] = finalValue;
}
}
}
};
var this_1 = this;
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
var key = keys_1[_i];
_loop_1(key);
}
if (this.options.enableCircularCheck) {
this.recursionStack.delete(value);
}
return newValue;
} else {
return value;
}
};
TransformOperationExecutor2.prototype.applyCustomTransformations = function(value, target, key, obj, transformationType) {
var _this = this;
var metadatas = defaultMetadataStorage.findTransformMetadatas(target, key, this.transformationType);
if (this.options.version !== void 0) {
metadatas = metadatas.filter(function(metadata) {
if (!metadata.options)
return true;
return _this.checkVersion(metadata.options.since, metadata.options.until);
});
}
if (this.options.groups && this.options.groups.length) {
metadatas = metadatas.filter(function(metadata) {
if (!metadata.options)
return true;
return _this.checkGroups(metadata.options.groups);
});
} else {
metadatas = metadatas.filter(function(metadata) {
return !metadata.options || !metadata.options.groups || !metadata.options.groups.length;
});
}
metadatas.forEach(function(metadata) {
value = metadata.transformFn({ value, key, obj, type: transformationType, options: _this.options });
});
return value;
};
TransformOperationExecutor2.prototype.isCircular = function(object) {
return this.recursionStack.has(object);
};
TransformOperationExecutor2.prototype.getReflectedType = function(target, propertyName) {
if (!target)
return void 0;
var meta = defaultMetadataStorage.findTypeMetadata(target, propertyName);
return meta ? meta.reflectedType : void 0;
};
TransformOperationExecutor2.prototype.getKeys = function(target, object, isMap) {
var _this = this;
var strategy = defaultMetadataStorage.getStrategy(target);
if (strategy === "none")
strategy = this.options.strategy || "exposeAll";
var keys = [];
if (strategy === "exposeAll" || isMap) {
if (object instanceof Map) {
keys = Array.from(object.keys());
} else {
keys = Object.keys(object);
}
}
if (isMap) {
return keys;
}
if (this.options.ignoreDecorators && this.options.excludeExtraneousValues && target) {
var exposedProperties = defaultMetadataStorage.getExposedProperties(target, this.transformationType);
var excludedProperties = defaultMetadataStorage.getExcludedProperties(target, this.transformationType);
keys = __spreadArray(__spreadArray([], exposedProperties, true), excludedProperties);
}
if (!this.options.ignoreDecorators && target) {
var exposedProperties = defaultMetadataStorage.getExposedProperties(target, this.transformationType);
if (this.transformationType === TransformationType.PLAIN_TO_CLASS) {
exposedProperties = exposedProperties.map(function(key) {
var exposeMetadata = defaultMetadataStorage.findExposeMetadata(target, key);
if (exposeMetadata && exposeMetadata.options && exposeMetadata.options.name) {
return exposeMetadata.options.name;
}
return key;
});
}
if (this.options.excludeExtraneousValues) {
keys = exposedProperties;
} else {
keys = keys.concat(exposedProperties);
}
var excludedProperties_1 = defaultMetadataStorage.getExcludedProperties(target, this.transformationType);
if (excludedProperties_1.length > 0) {
keys = keys.filter(function(key) {
return !excludedProperties_1.includes(key);
});
}
if (this.options.version !== void 0) {
keys = keys.filter(function(key) {
var exposeMetadata = defaultMetadataStorage.findExposeMetadata(target, key);
if (!exposeMetadata || !exposeMetadata.options)
return true;
return _this.checkVersion(exposeMetadata.options.since, exposeMetadata.options.until);
});
}
if (this.options.groups && this.options.groups.length) {
keys = keys.filter(function(key) {
var exposeMetadata = defaultMetadataStorage.findExposeMetadata(target, key);
if (!exposeMetadata || !exposeMetadata.options)
return true;
return _this.checkGroups(exposeMetadata.options.groups);
});
} else {
keys = keys.filter(function(key) {
var exposeMetadata = defaultMetadataStorage.findExposeMetadata(target, key);
return !exposeMetadata || !exposeMetadata.options || !exposeMetadata.options.groups || !exposeMetadata.options.groups.length;
});
}
}
if (this.options.excludePrefixes && this.options.excludePrefixes.length) {
keys = keys.filter(function(key) {
return _this.options.excludePrefixes.every(function(prefix) {
return key.substr(0, prefix.length) !== prefix;
});
});
}
keys = keys.filter(function(key, index, self2) {
return self2.indexOf(key) === index;
});
return keys;
};
TransformOperationExecutor2.prototype.checkVersion = function(since, until) {
var decision = true;
if (decision && since)
decision = this.options.version >= since;
if (decision && until)
decision = this.options.version < until;
return decision;
};
TransformOperationExecutor2.prototype.checkGroups = function(groups) {
if (!groups)
return true;
return this.options.groups.some(function(optionGroup) {
return groups.includes(optionGroup);
});
};
return TransformOperationExecutor2;
}()
);
var defaultOptions = {
enableCircularCheck: false,
enableImplicitConversion: false,
excludeExtraneousValues: false,
excludePrefixes: void 0,
exposeDefaultValues: false,
exposeUnsetFields: true,
groups: void 0,
ignoreDecorators: false,
strategy: void 0,
targetMaps: void 0,
version: void 0
};
var __assign = function() {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s)
if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var ClassTransformer = (
/** @class */
function() {
function ClassTransformer2() {
}
ClassTransformer2.prototype.instanceToPlain = function(object, options) {
var executor = new TransformOperationExecutor(TransformationType.CLASS_TO_PLAIN, __assign(__assign({}, defaultOptions), options));
return executor.transform(void 0, object, void 0, void 0, void 0, void 0);
};
ClassTransformer2.prototype.classToPlainFromExist = function(object, plainObject, options) {
var executor = new TransformOperationExecutor(TransformationType.CLASS_TO_PLAIN, __assign(__assign({}, defaultOptions), options));
return executor.transform(plainObject, object, void 0, void 0, void 0, void 0);
};
ClassTransformer2.prototype.plainToInstance = function(cls, plain, options) {
var executor = new TransformOperationExecutor(TransformationType.PLAIN_TO_CLASS, __assign(__assign({}, defaultOptions), options));
return executor.transform(void 0, plain, cls, void 0, void 0, void 0);
};
ClassTransformer2.prototype.plainToClassFromExist = function(clsObject, plain, options) {
var executor = new TransformOperationExecutor(TransformationType.PLAIN_TO_CLASS, __assign(__assign({}, defaultOptions), options));
return executor.transform(clsObject, plain, void 0, void 0, void 0, void 0);
};
ClassTransformer2.prototype.instanceToInstance = function(object, options) {
var executor = new TransformOperationExecutor(TransformationType.CLASS_TO_CLASS, __assign(__assign({}, defaultOptions), options));
return executor.transform(void 0, object, void 0, void 0, void 0, void 0);
};
ClassTransformer2.prototype.classToClassFromExist = function(object, fromObject, options) {
var executor = new TransformOperationExecutor(TransformationType.CLASS_TO_CLASS, __assign(__assign({}, defaultOptions), options));
return executor.transform(fromObject, object, void 0, void 0, void 0, void 0);
};
ClassTransformer2.prototype.serialize = function(object, options) {
return JSON.stringify(this.instanceToPlain(object, options));
};
ClassTransformer2.prototype.deserialize = function(cls, json, options) {
var jsonObject = JSON.parse(json);
return this.plainToInstance(cls, jsonObject, options);
};
ClassTransformer2.prototype.deserializeArray = function(cls, json, options) {
var jsonObject = JSON.parse(json);
return this.plainToInstance(cls, jsonObject, options);
};
return ClassTransformer2;
}()
);
function Type(typeFunction, options) {
if (options === void 0) {
options = {};
}
return function(target, propertyName) {
var reflectedType = Reflect.getMetadata("design:type", target, propertyName);
defaultMetadataStorage.addTypeMetadata({
target: target.constructor,
propertyName,
reflectedType,
typeFunction,
options
});
};
}
var classTransformer = new ClassTransformer();
function instanceToPlain(object, options) {
return classTransformer.instanceToPlain(object, options);
}
function plainToInstance(cls, plain, options) {
return classTransformer.plainToInstance(cls, plain, options);
}
var __defProp$1 = Object.defineProperty;
var __decorateClass$1 = (decorators, target, key, kind) => {
var result = void 0;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = decorator(target, key, result) || result;
if (result)
__defProp$1(target, key, result);
return result;
};
class Setting {
constructor() {
/**
* 目标国家代码,默认CN
*/
__publicField(this, "countyCode", "CN");
/**
* 目标货币符号,默认 ¥
*/
__publicField(this, "currencySymbol", "¥");
/**
* 符号位置在首
*/
__publicField(this, "currencySymbolBeforeValue", true);
/**
* 汇率获取时间,默认1小时
*/
__publicField(this, "rateCacheExpired", 1e3 * 60 * 60);
/**
* 使用自定义汇率
*/
__publicField(this, "useCustomRate", false);
/**
* 自定义汇率
*/
__publicField(this, "customRate", 1);
/**
* 前一个版本
*/
__publicField(this, "oldVersion", "0.0.0");
/**
* 当前版本
*/
__publicField(this, "currVersion", "0.0.0");
__publicField(this, "logLevel", "info");
}
}
__decorateClass$1([
Type(() => String)
], Setting.prototype, "logLevel");
const STORAGE_KEY_PREFIX = "Storage:";
const STORAGE_KEY_RATE_CACHES = STORAGE_KEY_PREFIX + "RateCache";
const STORAGE_KEY_SETTING = STORAGE_KEY_PREFIX + "Setting";
const IM_MENU_SETTING = "设置";
var _GM_addValueChangeListener = /* @__PURE__ */ (() => typeof GM_addValueChangeListener != "undefined" ? GM_addValueChangeListener : void 0)();
var _GM_cookie = /* @__PURE__ */ (() => typeof GM_cookie != "undefined" ? GM_cookie : void 0)();
var _GM_deleteValue = /* @__PURE__ */ (() => typeof GM_deleteValue != "undefined" ? GM_deleteValue : void 0)();
var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
var _GM_info = /* @__PURE__ */ (() => typeof GM_info != "undefined" ? GM_info : void 0)();
var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)();
var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
class Http {
static get(cls, url2, details) {
if (!details) {
details = { url: url2 };
}
details.method = "GET";
return this.request(cls, details);
}
static post(url2, cls, details) {
if (!details) {
details = { url: url2 };
}
details.method = "POST";
return this.request(cls, details);
}
static request(cls, details) {
return new Promise((resolve, reject) => {
details.onload = (response) => {
if (cls.name === String.name) {
resolve(response.response);
} else {
const json = JSON.parse(response.response);
resolve(plainToInstance(cls, json));
}
};
details.onerror = (error) => reject(error);
_GM_xmlhttpRequest(details);
});
}
}
const url = `https://cdn.jsdelivr.net/gh/marioplus/steam-price-converter@v${_GM_info.script.version}/src/county/countyCurrencyCodes.json`;
const countyInfos = await( Http.get(Array, url));
const countyCode2Info = new Map(countyInfos.map((v) => [v.code, v]));
function initializeLogTitle() {
const isInIFrame = window.parent !== window || window.frames.length > 0;
return isInIFrame ? `steam-price-convertor iframe(${(/* @__PURE__ */ new Date()).getMilliseconds()})` : "steam-price-convertor";
}
function createLogStyle(color) {
return `
background: ${color};
color: white;
padding: 1px 3px;
border-radius: 2px;
`;
}
function composeLogHint() {
return `%c${initializeLogTitle()}`;
}
const LogDefinitions = {
debug: {
index: 0,
color: "#009688",
label: "debug",
bindMethod: console.info
},
info: {
index: 1,
color: "#2196f3",
label: "info",
bindMethod: console.info
},
warn: {
index: 2,
color: "#ffc107",
label: "warn",
bindMethod: console.warn
},
error: {
index: 3,
color: "#e91e63",
label: "error",
bindMethod: console.error
},
off: {
index: 4,
color: "",
label: "off",
bindMethod: () => {
}
}
};
const Logger = {
debug: noopLog.bind(null),
info: noopLog.bind(null),
warn: noopLog.bind(null),
error: noopLog.bind(null)
};
function noopLog() {
}
let currLogLevel = LogDefinitions.info;
function refreshBinding() {
const hint = composeLogHint();
Object.entries(LogDefinitions).forEach(([label, def]) => {
if (def.index >= currLogLevel.index) {
const logStyle = createLogStyle(def.color);
Logger[label.toLowerCase()] = def.bindMethod.bind(console, hint, logStyle);
} else {
Logger[label.toLowerCase()] = noopLog.bind(null);
}
});
}
function setLogLevel(levelLabel) {
const newLevel = LogDefinitions[levelLabel];
if (newLevel) {
currLogLevel = newLevel;
refreshBinding();
} else {
console.error(`Invalid log level: ${levelLabel}`);
}
}
refreshBinding();
class Strings {
static format(format, ...args) {
args = args || [];
let message = format;
for (let arg of args) {
message = message.replace("%s", arg);
}
return message;
}
}
class JsonUtils {
static toJson(obj) {
return instanceToPlain(obj);
}
static toJsonString(obj) {
return JSON.stringify(this.toJson(obj));
}
static readJson(json, cls) {
return plainToInstance(cls, json);
}
static readJsonString(jsonString, cls) {
return this.readJson(JSON.parse(jsonString), cls);
}
}
class GmUtils {
static getValue(cls, key, defaultValue) {
const value = _GM_getValue(key);
return value ? JsonUtils.readJsonString(value, cls) : defaultValue;
}
static setValue(key, value) {
_GM_setValue(key, JsonUtils.toJsonString(value));
}
static deleteValue(key) {
_GM_deleteValue(key);
}
static registerMenuCommand(caption, onClick, accessKey) {
const key = `GM_registerMenuCommand@${caption}`;
_GM_registerMenuCommand(
caption,
(event) => {
this.setValue(key, true);
Logger.debug("点击菜单:" + caption);
this.setValue(key, false);
if (onClick) {
onClick(event);
}
},
accessKey
);
}
static addMenuClickEventListener(caption, onClick) {
const key = `GM_registerMenuCommand@${caption}`;
_GM_addValueChangeListener(key, (name, oldValue, newValue) => {
if (newValue) {
onClick();
}
});
}
}
const _SettingManager = class _SettingManager {
constructor() {
__publicField(this, "setting");
this.setting = this.loadSetting();
}
loadSetting() {
const setting = GmUtils.getValue(Setting, STORAGE_KEY_SETTING, new Setting());
setting.oldVersion = setting.currVersion;
setting.currVersion = _GM_info.script.version;
if (setting.oldVersion === setting.currVersion) {
Logger.info("读取设置", setting);
} else {
Logger.debug(Strings.format(`版本更新重置设置:%s -> %s`, setting.oldVersion, setting.currVersion));
this.saveSetting(setting);
}
return setting;
}
/**
* 保存设置
* @param setting 设置
*/
saveSetting(setting) {
Logger.info("保存设置", setting);
this.setting = setting;
GmUtils.setValue(STORAGE_KEY_SETTING, setting);
}
setCountyCode(countyCode) {
const county = countyCode2Info.get(countyCode);
if (!county) {
throw Error(`国家代码不存在:${countyCode}`);
}
this.setting.countyCode = countyCode;
this.saveSetting(this.setting);
}
setCurrencySymbol(currencySymbol) {
this.setting.currencySymbol = currencySymbol;
this.saveSetting(this.setting);
}
setCurrencySymbolBeforeValue(isCurrencySymbolBeforeValue) {
this.setting.currencySymbolBeforeValue = isCurrencySymbolBeforeValue;
this.saveSetting(this.setting);
}
reset() {
this.saveSetting(new Setting());
}
setRateCacheExpired(rateCacheExpired) {
this.setting.rateCacheExpired = rateCacheExpired;
this.saveSetting(this.setting);
}
setUseCustomRate(isUseCustomRate) {
this.setting.useCustomRate = isUseCustomRate;
this.saveSetting(this.setting);
}
setCustomRate(customRate) {
this.setting.customRate = customRate;
this.saveSetting(this.setting);
}
};
__publicField(_SettingManager, "instance", new _SettingManager());
let SettingManager = _SettingManager;
function parsePrice(content) {
let priceStr = content.replace(/руб\./g, "").replace(/pуб\./g, "").replace(/\s/g, "").replace(/^[^0-9]+/, "").replace(/[^0-9,.]+$/, "").replace(/,(?=\d\d\d)/g, "");
const numberStr = priceStr.replace(/\D/g, "");
let price = Number.parseInt(numberStr) ?? 0;
if (priceStr.match(/\D/)) {
price = price / 100;
}
return price;
}
function convertPrice(price, rate) {
return Number.parseFloat((price / rate).toFixed(2));
}
function convertPriceContent(originalContent, rate) {
const safeContent = originalContent.trim().replaceAll(/\(.+$/g, "").trim();
const price = parsePrice(safeContent);
const convertedPrice = convertPrice(price, rate);
const setting = SettingManager.instance.setting;
let finalContent = setting.currencySymbolBeforeValue ? `${safeContent}(${setting.currencySymbol}${convertedPrice})` : `${safeContent}(${convertedPrice}${setting.currencySymbol})`;
const message = `转换前文本:${safeContent}; 提取到的价格:${price}; 转换后的价格:${convertedPrice}; 转换后文本:${finalContent}`;
Logger.debug(message);
return finalContent;
}
class ElementConverter extends AbstractConverter {
getCssSelectors() {
const category = [
// 原价
".Wh0L8EnwsPV_8VAu8TOYr",
// 折扣价
"._1EKGZBnKFWOr3RqVdnLMRN"
];
const account = [
"div.accountData.price a"
];
const selectors = [
// 商店
// 首页
".discount_original_price",
".discount_final_price",
".col.search_price.responsive_secondrow strike",
// 头像旁边
"#header_wallet_balance > span.tooltip",
// 愿望单总价值
".esi-wishlist-stat > .num",
// 新版卡片
".salepreviewwidgets_StoreOriginalPrice_1EKGZ",
".salepreviewwidgets_StoreSalePriceBox_Wh0L8",
// 分类查看游戏
".contenthubshared_OriginalPrice_3hBh3",
".contenthubshared_FinalPrice_F_tGv",
".salepreviewwidgets_StoreSalePriceBox_Wh0L8:not(.salepreviewwidgets_StoreSalePrepurchaseLabel_Wxeyn)",
//
// 购物车
".cart_item_price.with_discount > .original_price",
".cart_item_price.with_discount > div.price:not(.original_price)",
"#cart_estimated_total",
// 购物车 复核
".checkout_review_item_price > .price",
"#review_subtotal_value.price",
"#review_total_value.price",
".cart_item_price > .price",
// 市场
// 总余额
"#marketWalletBalanceAmount",
// 列表
"span.normal_price[data-price]",
"span.sale_price",
// 求购、求售统计
".market_commodity_orders_header_promote:nth-child(even)",
// 求购、求售列表
".market_commodity_orders_table td:nth-child(odd)",
// 详情列表
".market_table_value > span",
".jqplot-highlighter-tooltip",
// 消费记录
"tr.wallet_table_row > td.wht_total",
"tr.wallet_table_row > td.wht_wallet_change.wallet_column",
"tr.wallet_table_row > td.wht_wallet_balance.wallet_column",
// 捆绑包
".package_totals_row > .price:not(.bundle_discount)",
"#package_savings_bar > .savings.bundle_savings",
// 低于xxx 分类标题
".home_page_content_title a.btn_small_tall > span"
];
selectors.push(...category);
selectors.push(...account);
return selectors;
}
convert(elementSnap, rate) {
elementSnap.element.textContent = convertPriceContent(elementSnap.textContext, rate);
return true;
}
}
class TextNodeConverter extends AbstractConverter {
constructor() {
super(...arguments);
// @ts-ignore
__publicField(this, "parseFirstChildTextNodeFn", (el) => el.firstChild);
// @ts-ignore
__publicField(this, "targets", /* @__PURE__ */ new Map([
[
".col.search_price.responsive_secondrow",
[
// @ts-ignore
(el) => el.firstChild.nextSibling.nextSibling.nextSibling,
this.parseFirstChildTextNodeFn
]
],
["#header_wallet_balance", [this.parseFirstChildTextNodeFn]],
// iframe
[".game_purchase_price.price", [this.parseFirstChildTextNodeFn]],
// 低于xxx 分类标题
[".home_page_content_title", [this.parseFirstChildTextNodeFn]],
// dlc 中没有折扣
[".game_area_dlc_row > .game_area_dlc_price", [
(el) => el,
this.parseFirstChildTextNodeFn
]]
]));
}
getCssSelectors() {
return [...this.targets.keys()];
}
convert(elementSnap, rate) {
const selector = elementSnap.selector;
this.targets.get(selector);
const parseNodeFns = this.targets.get(selector);
if (!parseNodeFns) {
return false;
}
const textNode = this.safeParseNode(selector, elementSnap.element, parseNodeFns);
if (!textNode) {
return false;
}
const content = textNode.nodeValue;
if (!content || content.trim().length === 0) {
return false;
}
textNode.nodeValue = convertPriceContent(content, rate);
return true;
}
safeParseNode(selector, el, fns) {
for (let fn of fns) {
try {
const node = fn(el);
if (node.nodeName === "#text" && node.nodeValue && node.nodeValue.length > 0) {
return node;
}
} catch (e) {
console.debug("获取文本节点失败,但不确定该节点是否一定会出现。selector:" + selector);
}
}
return null;
}
}
const _ConverterManager = class _ConverterManager {
constructor() {
__publicField(this, "converters");
this.converters = [
new ElementConverter(),
new TextNodeConverter()
];
}
getSelector() {
return this.converters.map((exchanger) => exchanger.getCssSelectors()).flat(1).join(", ");
}
convert(elements, rate) {
if (!elements) {
return;
}
elements.forEach((element) => {
const elementSnap = {
element,
textContext: element.textContent,
classList: element.classList,
attributes: element.attributes
};
this.converters.filter((converter) => converter.match(elementSnap)).forEach((converter) => {
try {
const exchanged = converter.convert(elementSnap, rate);
if (exchanged) {
converter.afterConvert(elementSnap);
}
} catch (e) {
console.group("转换失败");
console.error(e);
console.error("转换失败请将下列内容反馈给开发者,右键 > 复制(copy) > 复制元素(copy element)");
console.error("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
console.error(element);
console.error("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
console.groupEnd();
}
});
});
}
};
__publicField(_ConverterManager, "instance", new _ConverterManager());
let ConverterManager = _ConverterManager;
var __defProp2 = Object.defineProperty;
var __decorateClass = (decorators, target, key, kind) => {
var result = void 0;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = decorator(target, key, result) || result;
if (result)
__defProp2(target, key, result);
return result;
};
class RateCache {
constructor(from, to, rate, createdAt) {
__publicField(this, "from");
__publicField(this, "to");
__publicField(this, "createdAt");
__publicField(this, "rate");
this.from = from;
this.to = to;
this.createdAt = createdAt || 0;
this.rate = rate || 0;
}
}
class RateCaches {
constructor() {
__publicField(this, "caches", /* @__PURE__ */ new Map());
}
getCache(from, to) {
return this.caches.get(this.buildCacheKey(from, to));
}
setCache(cache) {
this.caches.set(this.buildCacheKey(cache.from, cache.to), cache);
}
buildCacheKey(from, to) {
return `${from}:${to}`;
}
}
__decorateClass([
Type(() => Map)
], RateCaches.prototype, "caches");
class SpcContext {
constructor(setting, targetCountyInfo, targetCountyCode) {
__publicField(this, "_setting");
__publicField(this, "_targetCountyInfo");
__publicField(this, "_currentCountyInfo");
this._setting = setting;
this._targetCountyInfo = targetCountyInfo;
this._currentCountyInfo = targetCountyCode;
}
static getContext() {
return _unsafeWindow.spcContext;
}
get setting() {
return this._setting;
}
get targetCountyInfo() {
return this._targetCountyInfo;
}
get currentCountyInfo() {
return this._currentCountyInfo;
}
}
class AugmentedSteamRateApi {
getName() {
return "AugmentedSteamRateApi";
}
async getRate() {
const context = SpcContext.getContext();
Logger.info(Strings.format(
"通过 AugmentedSteam 获取汇率 %s(%s) -> %s(%s)...",
context.currentCountyInfo.currencyCode,
context.currentCountyInfo.name,
context.targetCountyInfo.currencyCode,
context.targetCountyInfo.name
));
const url2 = `https://api.augmentedsteam.com/rates/v1?to=${context.currentCountyInfo.currencyCode}`;
let rate = await Http.get(Map, url2).then((res) => res.get(context.targetCountyInfo.currencyCode)[context.currentCountyInfo.currencyCode]).catch((err) => Logger.error("通过 AugmentedSteam 获取汇率失败", err));
if (rate) {
return rate;
}
throw new Error(`通过 ${this.getName()} 获取汇率失败。`);
}
}
const _RateManager = class _RateManager {
constructor() {
__publicField(this, "rateApis");
__publicField(this, "rateCaches", new RateCaches());
this.rateApis = [
new AugmentedSteamRateApi()
];
}
getName() {
return "RateManager";
}
async getRate4Remote() {
Logger.info("远程获取汇率...");
let rate;
for (let rateApi of this.rateApis) {
try {
rate = await rateApi.getRate();
} catch (e) {
Logger.error(`使用实现(${rateApi.getName()})获取汇率失败`);
}
if (rate) {
return rate;
}
}
throw Error("所有汇率获取实现获取汇率均失败");
}
async getRate() {
const context = SpcContext.getContext();
if (context.setting.useCustomRate) {
Logger.info("使用自定义汇率");
return context.setting.customRate;
}
this.rateCaches = this.loadRateCache();
let cache = this.rateCaches.getCache(context.currentCountyInfo.code, context.targetCountyInfo.code);
const now = (/* @__PURE__ */ new Date()).getTime();
const expired = context.setting.rateCacheExpired;
if (!cache || !cache.rate || now > cache.createdAt + expired) {
Logger.info(`本地缓存已过期`);
cache = new RateCache(context.currentCountyInfo.code, context.targetCountyInfo.code);
cache.rate = await this.getRate4Remote();
cache.createdAt = (/* @__PURE__ */ new Date()).getTime();
this.rateCaches.setCache(cache);
this.saveRateCache();
}
return cache.rate;
}
loadRateCache() {
const setting = SpcContext.getContext().setting;
if (setting.oldVersion !== setting.currVersion) {
Logger.info(`脚本版本发生变化需要刷新汇率缓存`);
this.clear();
return new RateCaches();
}
Logger.info(`读取汇率缓存`);
return GmUtils.getValue(RateCaches, STORAGE_KEY_RATE_CACHES, new RateCaches());
}
saveRateCache() {
Logger.info("保存汇率缓存", this.rateCaches);
GmUtils.setValue(STORAGE_KEY_RATE_CACHES, this.rateCaches);
}
clear() {
GmUtils.deleteValue(STORAGE_KEY_RATE_CACHES);
}
};
__publicField(_RateManager, "instance", new _RateManager());
let RateManager = _RateManager;
async function main() {
const context = SpcContext.getContext();
if (context.currentCountyInfo.code === context.targetCountyInfo.code) {
Logger.info(`${context.currentCountyInfo.name}无需转换`);
return;
}
const rate = await RateManager.instance.getRate();
if (!rate) {
throw Error("获取汇率失败");
}
Logger.info(Strings.format(`汇率 %s -> %s:%s`, context.currentCountyInfo.currencyCode, context.targetCountyInfo.currencyCode, rate));
await convert(rate);
}
async function convert(rate) {
const exchangerManager = ConverterManager.instance;
const elements = document.querySelectorAll(exchangerManager.getSelector());
exchangerManager.convert(elements, rate);
const selector = exchangerManager.getSelector();
const priceObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
const target = mutation.target;
let priceEls = target.querySelectorAll(selector);
if (!priceEls || priceEls.length === 0) {
return;
}
exchangerManager.convert(priceEls, rate);
});
});
priceObserver.observe(document.body, {
childList: true,
subtree: true
});
}
const _withScopeId = (n) => (vue.pushScopeId("data-v-34f99f99"), n = n(), vue.popScopeId(), n);
const _hoisted_1 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("link", {
href: "https://fonts.googleapis.com/icon?family=Material+Icons",
rel: "stylesheet"
}, null, -1));
const _hoisted_2 = {
"close-on-overlay-click": "",
class: "setting"
};
const _hoisted_3 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", { slot: "headline" }, "设置", -1));
const _hoisted_4 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", { slot: "description" }, "随心所欲设置 steam-price-converter", -1));
const _hoisted_5 = { class: "setting-item" };
const _hoisted_6 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "setting-item-title" }, [
/* @__PURE__ */ vue.createElementVNode("label", null, "目标区域"),
/* @__PURE__ */ vue.createElementVNode("mdui-tooltip", {
content: "将价格转换为此区域的货币",
placement: "right"
}, [
/* @__PURE__ */ vue.createElementVNode("mdui-icon", {
name: "error",
class: "setting-region-title-icon"
})
])
], -1));
const _hoisted_7 = { class: "setting-item-content" };
const _hoisted_8 = ["value"];
const _hoisted_9 = ["value"];
const _hoisted_10 = { class: "setting-item" };
const _hoisted_11 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "setting-item-title" }, [
/* @__PURE__ */ vue.createElementVNode("label", null, "货币符号"),
/* @__PURE__ */ vue.createElementVNode("mdui-tooltip", {
content: "转换后的价格的货币符号",
placement: "right"
}, [
/* @__PURE__ */ vue.createElementVNode("mdui-icon", {
name: "error",
class: "setting-region-title-icon"
})
])
], -1));
const _hoisted_12 = { class: "setting-item-content" };
const _hoisted_13 = ["value"];
const _hoisted_14 = { class: "setting-item" };
const _hoisted_15 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "setting-item-title" }, [
/* @__PURE__ */ vue.createElementVNode("label", null, "货币符号展示位置"),
/* @__PURE__ */ vue.createElementVNode("mdui-tooltip", {
content: "控制转换后的价格货币符号的位置",
placement: "right"
}, [
/* @__PURE__ */ vue.createElementVNode("mdui-icon", {
name: "error",
class: "setting-region-title-icon"
})
])
], -1));
const _hoisted_16 = { class: "setting-item-content" };
const _hoisted_17 = ["value"];
const _hoisted_18 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("mdui-menu-item", { value: "true" }, "价格之前", -1));
const _hoisted_19 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("mdui-menu-item", { value: "false" }, "价格之后", -1));
const _hoisted_20 = [
_hoisted_18,
_hoisted_19
];
const _hoisted_21 = { class: "setting-item" };
const _hoisted_22 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "setting-item-title" }, [
/* @__PURE__ */ vue.createElementVNode("label", null, "汇率缓存有效期"),
/* @__PURE__ */ vue.createElementVNode("mdui-tooltip", {
content: "获取汇率后进行缓存,在此时间内将使用缓存汇率",
placement: "right"
}, [
/* @__PURE__ */ vue.createElementVNode("mdui-icon", {
name: "error",
class: "setting-region-title-icon"
})
])
], -1));
const _hoisted_23 = { class: "setting-item-content" };
const _hoisted_24 = ["value"];
const _hoisted_25 = { class: "setting-item" };
const _hoisted_26 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "setting-item-title" }, [
/* @__PURE__ */ vue.createElementVNode("label", null, "使用自定义汇率"),
/* @__PURE__ */ vue.createElementVNode("mdui-tooltip", {
content: "使用自定义汇率进行价格转换,不再获取区域,不再根据区域获取汇率",
placement: "right"
}, [
/* @__PURE__ */ vue.createElementVNode("mdui-icon", {
name: "error",
class: "setting-region-title-icon"
})
])
], -1));
const _hoisted_27 = { class: "setting-item-content" };
const _hoisted_28 = ["value"];
const _hoisted_29 = { class: "setting-item" };
const _hoisted_30 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "setting-item-title" }, [
/* @__PURE__ */ vue.createElementVNode("label", null, "自定义汇率"),
/* @__PURE__ */ vue.createElementVNode("mdui-tooltip", {
content: "开启“使用自定义汇率”后使用此汇率进行转换",
placement: "right"
}, [
/* @__PURE__ */ vue.createElementVNode("mdui-icon", {
name: "error",
class: "setting-region-title-icon"
})
])
], -1));
const _hoisted_31 = { class: "setting-item-content" };
const _hoisted_32 = ["value"];
const _hoisted_33 = { class: "setting-item" };
const _hoisted_34 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "setting-item-title" }, [
/* @__PURE__ */ vue.createElementVNode("label", null, "日志等级"),
/* @__PURE__ */ vue.createElementVNode("mdui-tooltip", {
content: "日志等级 debug > info > warn > error > off",
placement: "right"
}, [
/* @__PURE__ */ vue.createElementVNode("mdui-icon", {
name: "error",
class: "setting-region-title-icon"
})
])
], -1));
const _hoisted_35 = { class: "setting-item-content" };
const _hoisted_36 = ["value"];
const _hoisted_37 = ["value"];
const _hoisted_38 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("mdui-button", {
class: "setting-btn-canal",
slot: "action",
variant: "text"
}, "取消", -1));
const _hoisted_39 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("mdui-button", {
class: "setting-btn-save",
slot: "action",
variant: "tonal"
}, "保存", -1));
const _sfc_main = /* @__PURE__ */ vue.defineComponent({
__name: "App",
setup(__props) {
const vueCountyInfos = countyInfos;
const setting = Object.assign({}, SettingManager.instance.setting);
vue.onMounted(() => {
var _a, _b;
const dialog = document.querySelector(".setting");
(_a = dialog.querySelector(".setting-btn-canal")) == null ? void 0 : _a.addEventListener("click", () => dialog.open = false);
(_b = dialog.querySelector(".setting-btn-save")) == null ? void 0 : _b.addEventListener("click", () => {
SettingManager.instance.saveSetting(setting);
dialog.open = false;
});
GmUtils.addMenuClickEventListener(IM_MENU_SETTING, () => dialog.open = true);
});
function getSelected(target) {
var _a;
return (_a = target.querySelector("*[selected]")) == null ? void 0 : _a.value;
}
return (_ctx, _cache) => {
return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
_hoisted_1,
vue.createElementVNode("mdui-dialog", _hoisted_2, [
_hoisted_3,
_hoisted_4,
vue.createElementVNode("div", _hoisted_5, [
_hoisted_6,
vue.createElementVNode("div", _hoisted_7, [
vue.createElementVNode("mdui-select", {
value: vue.unref(setting).countyCode,
placement: "bottom",
onChange: _cache[0] || (_cache[0] = ($event) => vue.unref(setting).countyCode = getSelected($event.target))
}, [
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(vueCountyInfos), (countyInfo) => {
return vue.openBlock(), vue.createElementBlock("mdui-menu-item", {
value: countyInfo.code
}, vue.toDisplayString(countyInfo.name) + " (" + vue.toDisplayString(countyInfo.code) + ") ", 9, _hoisted_9);
}), 256))
], 40, _hoisted_8)
])
]),
vue.createElementVNode("div", _hoisted_10, [
_hoisted_11,
vue.createElementVNode("div", _hoisted_12, [
vue.createElementVNode("mdui-text-field", {
value: vue.unref(setting).currencySymbol,
onChange: _cache[1] || (_cache[1] = ($event) => vue.unref(setting).currencySymbol = $event.target.value)
}, null, 40, _hoisted_13)
])
]),
vue.createElementVNode("div", _hoisted_14, [
_hoisted_15,
vue.createElementVNode("div", _hoisted_16, [
vue.createElementVNode("mdui-select", {
value: vue.unref(setting).currencySymbolBeforeValue.toString(),
placement: "bottom",
onChange: _cache[2] || (_cache[2] = ($event) => vue.unref(setting).currencySymbolBeforeValue = getSelected($event.target) === "true")
}, _hoisted_20, 40, _hoisted_17)
])
]),
vue.createElementVNode("div", _hoisted_21, [
_hoisted_22,
vue.createElementVNode("div", _hoisted_23, [
vue.createElementVNode("mdui-text-field", {
type: "number",
value: vue.unref(setting).rateCacheExpired / (60 * 60 * 1e3),
suffix: "h",
onChange: _cache[3] || (_cache[3] = ($event) => vue.unref(setting).rateCacheExpired = $event.target.value * (60 * 60 * 1e3))
}, null, 40, _hoisted_24)
])
]),
vue.createElementVNode("div", _hoisted_25, [
_hoisted_26,
vue.createElementVNode("div", _hoisted_27, [
vue.createElementVNode("mdui-switch", {
slot: "end-icon",
value: vue.unref(setting).useCustomRate,
onChange: _cache[4] || (_cache[4] = ($event) => vue.unref(setting).useCustomRate = $event.target.checked)
}, null, 40, _hoisted_28)
])
]),
vue.createElementVNode("div", _hoisted_29, [
_hoisted_30,
vue.createElementVNode("div", _hoisted_31, [
vue.createElementVNode("mdui-text-field", {
type: "number",
value: vue.unref(setting).customRate,
onChange: _cache[5] || (_cache[5] = ($event) => vue.unref(setting).customRate = $event.target.value)
}, null, 40, _hoisted_32)
])
]),
vue.createElementVNode("div", _hoisted_33, [
_hoisted_34,
vue.createElementVNode("div", _hoisted_35, [
vue.createElementVNode("mdui-select", {
value: vue.unref(setting).logLevel,
onChange: _cache[6] || (_cache[6] = ($event) => vue.unref(setting).logLevel = getSelected($event.target))
}, [
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(LogDefinitions), (def) => {
return vue.openBlock(), vue.createElementBlock("mdui-menu-item", {
value: def.label
}, vue.toDisplayString(def.label), 9, _hoisted_37);
}), 256))
], 40, _hoisted_36)
])
]),
_hoisted_38,
_hoisted_39
])
], 64);
};
}
});
const _export_sfc = (sfc, props) => {
const target = sfc.__vccOpts || sfc;
for (const [key, val] of props) {
target[key] = val;
}
return target;
};
const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-34f99f99"]]);
class CookieCountyInfoGetter {
name() {
return "cookie";
}
match() {
return true;
}
async getCountyCode() {
return new Promise(async (resolve, reject) => {
const cookies = await _GM_cookie.list({ name: "steamCountry" });
if (cookies && cookies.length > 0) {
const match = cookies[0].value.match(/^[a-zA-Z][a-zA-Z]/);
if (match) {
resolve(match[0]);
}
}
reject();
});
}
}
class RequestStorePageCountyCodeGetter {
name() {
return "请求商店页面";
}
match() {
return !window.location.href.includes("store.steampowered.com");
}
async getCountyCode() {
return new Promise(async (resolve, reject) => {
try {
const storeHtml = await Http.get(String, "https://store.steampowered.com/");
const match = storeHtml.match(new RegExp("(?<=GDynamicStore.Init\\(.+')[A-Z][A-Z](?=',)"));
if (match) {
return resolve(match[0]);
}
} catch (err) {
Logger.error(err);
}
reject();
});
}
}
class StorePageCountyCodeGetter {
name() {
return "商店页面";
}
match() {
return window.location.href.includes("store.steampowered.com");
}
getCountyCode() {
return new Promise((resolve, reject) => {
var _a, _b;
try {
let countyCode = (_b = (_a = GStoreItemData == null ? void 0 : GStoreItemData.rgNavParams) == null ? void 0 : _a.__page_default_obj) == null ? void 0 : _b.countrycode;
if (countyCode) {
resolve(countyCode);
}
} catch (e) {
Logger.warn("读取商店页面区域代码变量失败: " + e.message);
}
document.querySelectorAll("script").forEach((scriptEl) => {
const scriptInnerText = scriptEl.innerText;
if (scriptInnerText.includes("$J( InitMiniprofileHovers );") || scriptInnerText.includes(`$J( InitMiniprofileHovers( 'https%3A%2F%2Fstore.steampowered.com%2F' ) );`)) {
const matcher = new RegExp("(?<=')[A-Z]{2}(?!=')", "g");
const match = scriptInnerText.match(matcher);
if (match) {
const countyCode = match.toString();
resolve(countyCode);
}
}
});
reject();
});
}
}
class MarketPageCountyCodeGetter {
name() {
return "市场页面";
}
match() {
return window.location.href.includes("steamcommunity.com");
}
getCountyCode() {
return new Promise((resolve, reject) => {
try {
const code = g_strCountryCode;
if (code)
return resolve(code);
} catch (err) {
Logger.error(err);
}
reject();
});
}
}
const _CountyCodeGetterManager = class _CountyCodeGetterManager {
constructor() {
__publicField(this, "getters");
this.getters = [
new StorePageCountyCodeGetter(),
new MarketPageCountyCodeGetter(),
new RequestStorePageCountyCodeGetter(),
new CookieCountyInfoGetter()
];
}
match() {
return true;
}
async getCountyCode() {
Logger.info("尝试获取区域代码");
for (let getter of this.getters) {
if (!getter.match()) {
continue;
}
Logger.debug(`尝试通过[${getter.name()}]获取区域代码`);
try {
const countyCode = await getter.getCountyCode();
Logger.info(`通过[${getter.name()}]获取区域代码成功`);
return countyCode;
} catch (e) {
Logger.error(`通过[${getter.name()}]获取区域代码失败`);
}
}
throw new Error("所有获取区域代码策略都获取失败");
}
};
__publicField(_CountyCodeGetterManager, "instance", new _CountyCodeGetterManager());
let CountyCodeGetterManager = _CountyCodeGetterManager;
const _SpcManager = class _SpcManager {
constructor() {
}
setCountyCode(code) {
SettingManager.instance.setCountyCode(code);
}
setCurrencySymbol(symbol) {
SettingManager.instance.setCurrencySymbol(symbol);
}
setCurrencySymbolBeforeValue(isCurrencySymbolBeforeValue) {
SettingManager.instance.setCurrencySymbolBeforeValue(isCurrencySymbolBeforeValue);
}
setRateCacheExpired(expired) {
SettingManager.instance.setRateCacheExpired(expired);
}
resetSetting() {
SettingManager.instance.reset();
}
clearCache() {
RateManager.instance.clear();
}
setUseCustomRate(isUseCustomRate) {
SettingManager.instance.setUseCustomRate(isUseCustomRate);
}
setCustomRate(customRate) {
SettingManager.instance.setCustomRate(customRate);
}
};
__publicField(_SpcManager, "instance", new _SpcManager());
let SpcManager = _SpcManager;
(async () => {
await initContext();
initApp();
registerMenu();
await main();
})();
function initApp() {
vue.createApp(App).mount(
(() => {
const app = document.createElement("div");
app.setAttribute("id", "spc-menu");
document.body.append(app);
return app;
})()
);
}
function registerMenu() {
GmUtils.registerMenuCommand(IM_MENU_SETTING);
}
async function initContext() {
const setting = SettingManager.instance.setting;
setLogLevel(setting.logLevel);
const targetCountyInfo = countyCode2Info.get(setting.countyCode);
if (!targetCountyInfo) {
throw Error("获取转换后的国家信息失败,国家代码:" + setting.countyCode);
}
Logger.info("目标区域:", targetCountyInfo);
const currCountyCode = await CountyCodeGetterManager.instance.getCountyCode();
const currCountInfo = countyCode2Info.get(currCountyCode);
if (!currCountyCode) {
throw Error("缺少当前国家的信息映射:county: " + currCountyCode);
}
Logger.info("当前区域:", currCountInfo);
_unsafeWindow.SpcManager = SpcManager.instance;
_unsafeWindow.spcContext = new SpcContext(setting, targetCountyInfo, currCountInfo);
}
})(Reflect, mdui, Vue);