koishi-plugin-warframe 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,14 +8,16 @@ Toolkit for warframe. **(In development)**
8
8
 
9
9
  | Command Name | Default Alias | Description |
10
10
  | ------------------------ | ---------------------- | ------------------------------------------------------------------------------------------- |
11
- | wmi | | Warframe market orders. |
12
- | wmr | | Warframe market orders. |
11
+ | wmi [name:string] | | Warframe market orders. |
12
+ | wmr [name:string] | | Warframe market orders. |
13
13
  | arbitration [day:number] | arbi, 仲裁, 仲裁表 | High-value arbitration schedule. The arg decide how long in days to display, defaults to 3. |
14
14
  | fissure | 裂缝, 裂隙 | Current fissures. |
15
15
  | spfissure | 钢铁裂缝, 钢铁裂隙 | Current steelpath fissures. |
16
16
  | rjfissure | 九重天裂缝, 九重天裂隙 | Current railjack fissures. |
17
17
  | circuit | 灵化, 灵化之源 | Weekly rewards of circuit, both warframe parts and incarnons. |
18
- | about | 关于 | About information. |
18
+ | relic [name:string] | 遗物, 核桃 | Relic rewards with corresponding data, including wfm medium price and ducats value. |
19
+ | weekly | 周常 | Weekly mission info (archon hunt, deep archimedea, temporal archimedea) |
20
+ | environment | env, 地球, 福尔图娜 | Region environment (time) |
19
21
 
20
22
  ## Install
21
23
 
package/lib/index.d.ts CHANGED
@@ -3,10 +3,29 @@ import Puppeteer from 'koishi-plugin-puppeteer';
3
3
  import Element from '@satorijs/element';
4
4
  import { Element, Argv, Context, Schema } from 'koishi';
5
5
  import WorldState from 'warframe-worldstate-parser';
6
+ export const toTimeStamp: (timeStr: string) => number;
7
+ /**
8
+ * 毫秒转「X小时X分钟X秒」格式(0单位不显示)
9
+ * @param {number} ms - 待转换的毫秒数(非负)
10
+ * @returns {string} 示例:3661000ms → "1小时1分钟1秒";61000ms → "1分钟1秒";500ms → "0秒"
11
+ */
12
+ export const msToHumanReadable: (ms: number) => string;
13
+ /**
14
+ * Creates an async cache with a time-to-live (TTL).
15
+ * @param fetchFn Function to fetch fresh data.
16
+ * @param ttlMs Time-to-live in milliseconds.
17
+ * @returns
18
+ */
19
+ export function createAsyncCache<T>(fetchFn: () => Promise<T>, ttlMs: number): {
20
+ get: () => Promise<T>;
21
+ };
22
+ export const normalizeName: (text: string) => string;
23
+ export const fullWidthToHalfWidth: (text: string) => string;
24
+ export const removeSpace: (text: string) => string;
25
+ export const pascalToSpaced: (text: string) => string;
26
+ export const toPascalCase: (text: string) => string;
6
27
  export const fetchAsyncText: (url: string, method?: string) => Promise<string | null>;
7
28
  export const fetchAsyncData: <T>(url: string, method?: string) => Promise<T | null>;
8
- export const fullWidthToHalfWidth: (str: string) => string;
9
- export const removeSpace: (text: string) => string;
10
29
  export const listToDict: <T>(dict: T[], predict: (obj: T) => string[]) => {
11
30
  [key: string]: T;
12
31
  };
@@ -18,13 +37,6 @@ export const dictToKeyDict: <T>(dict: {
18
37
  }, predict: (obj: T) => string[]) => {
19
38
  [key: string]: string;
20
39
  };
21
- export const toTimeStamp: (timeStr: string) => number;
22
- /**
23
- * 毫秒转「X小时X分钟X秒」格式(0单位不显示)
24
- * @param {number} ms - 待转换的毫秒数(非负)
25
- * @returns {string} 示例:3661000ms → "1小时1分钟1秒";61000ms → "1分钟1秒";500ms → "0秒"
26
- */
27
- export const msToHumanReadable: (ms: number) => string;
28
40
  export const getSolNodeKey: (name: string) => Promise<string>;
29
41
  export const getMissionTypeKey: (name: string) => Promise<string>;
30
42
  export const fissureTierName: {
@@ -45,11 +57,29 @@ export const regionToShort: (region: IRegion, dict: any) => {
45
57
  maxLevel: number;
46
58
  minLevel: number;
47
59
  };
60
+ export const relicQualityToName: (quality: string) => RelicQuality;
61
+ /** transform relic quality to translation key, return original if not matched.
62
+ *
63
+ * eg. "VPQ_BRONZE" => "/Lotus/Language/Relics/VoidProjectionQuality_Bronze".
64
+ * @param quality directly provided from `IRelic.quality` expected to start with "VPQ_".
65
+ */
66
+ export const relicQualityToTransKey: (quality: string) => string;
67
+ /** transform relic era to translation key.
68
+ *
69
+ * eg. "Lith" => "/Lotus/Language/Relics/Era_LITH".
70
+ * @param era directly provided from `IRelic.era`.
71
+ */
72
+ export const relicEraToTransKey: (era: string) => string;
73
+ export const fixRelicRewardKey: (item: string) => string;
48
74
  export const getWFMItemList: () => Promise<WFMResponse<ItemShort[] | null>>;
49
75
  export const getWFMOrderList: (itemId: string) => Promise<WFMResponse<OrderWithUser[] | null>>;
50
76
  export const getWFMRivenItemList: () => Promise<WFMResponse<RivenItem[] | null>>;
51
- export const getWFMRivenOrderList: (itemId: string) => Promise<WFMResponseV1<RivenOrder> | null>;
77
+ export const getWFMRivenOrderList: (itemId: string) => Promise<WFMResponseV1<Auction<RivenOrder>> | null>;
52
78
  export const getWFMRivenAttributeList: () => Promise<WFMResponse<RivenAttribute[]> | null>;
79
+ export const getWFMDucatnator: () => Promise<WFMResponseV1<{
80
+ previous_day: Ducatnator[];
81
+ previous_hour: Ducatnator[];
82
+ }>>;
53
83
  export const getHtmlString: (body: string, title?: string) => string;
54
84
  export const getHtmlImageBase64: (puppe: Puppeteer, html: string, type?: "png" | "jpeg" | "webp") => Promise<string>;
55
85
  export const OutputImage: (imgBase64: string) => Element;
@@ -70,8 +100,8 @@ export const getRivenOrders: (input: string) => Promise<{
70
100
  orders: RivenOrder[];
71
101
  }>;
72
102
  export const generateRivenOrderOutput: (puppe: Puppeteer, item: RivenItem, orders: RivenOrder[]) => Promise<import("koishi").Element>;
73
- export const loadRelicData: (relic: Relic) => OutputRelic;
74
- export const inputToItem: (input: string) => ItemShort | undefined;
103
+ export const applyRelicData: (relic: Relic) => Promise<OutputRelic>;
104
+ export const stringToWFMItem: (input: string) => ItemShort | undefined;
75
105
  declare const _default: {
76
106
  SolNode147: number;
77
107
  SolNode149: number;
@@ -91,9 +121,8 @@ export const FissureTable: (fissures: Fissure[], type: "fissure" | "sp-fissure"
91
121
  export const WeeklyTable: (archon: string, deepArchimedea: ArchiMedea, temporalArchimedea: ArchiMedea) => Promise<string>;
92
122
  export const RelicComponent: (relic: OutputRelic) => Element;
93
123
  export const getWorldState: () => Promise<WorldState>;
94
- export const getRelicsDropTable: (puppe: Puppeteer) => Promise<Record<string, Relic>>;
95
124
  export const wfOnReady: () => Promise<void>;
96
- export const getRelic: (puppe: Puppeteer, input: string) => Promise<Relic | string>;
125
+ export const getRelic: (input: string) => Promise<Relic | string>;
97
126
  export const generateRelicOutput: (puppe: Puppeteer, relic: OutputRelic) => Promise<import("koishi").Element>;
98
127
  export const getArbitrations: (day?: number) => Arbitration[] | string;
99
128
  export const generateArbitrationsOutput: (puppe: Puppeteer, arby: Arbitration[]) => Promise<import("koishi").Element>;
@@ -112,9 +141,9 @@ export const generateCircuitWeekOutput: (puppe: Puppeteer, data: {
112
141
  incarnons: string[];
113
142
  warframes: string[];
114
143
  }) => Promise<import("koishi").Element>;
115
- export const getFissures: () => Promise<Fissure[] | "内部错误,获取最新信息失败">;
116
- export const getSteelPathFissures: () => Promise<Fissure[] | "内部错误,获取最新信息失败">;
117
- export const getRailjackFissures: () => Promise<Fissure[] | "内部错误,获取最新信息失败">;
144
+ export const getFissures: () => Promise<any[] | "内部错误,获取最新信息失败">;
145
+ export const getSteelPathFissures: () => Promise<any[] | "内部错误,获取最新信息失败">;
146
+ export const getRailjackFissures: () => Promise<any[] | "内部错误,获取最新信息失败">;
118
147
  export const generateFissureOutput: (puppe: Puppeteer, fissures: Fissure[], type: "fissure" | "sp-fissure" | "rj-fissure") => Promise<import("koishi").Element>;
119
148
  export const wmCommand: (action: Argv, input: string) => Promise<string | import("koishi").Element>;
120
149
  export const wmrCommand: (action: Argv, input: string) => Promise<string | import("koishi").Element>;
package/lib/index.js CHANGED
@@ -37,7 +37,62 @@ __export(index_exports, {
37
37
  module.exports = __toCommonJS(index_exports);
38
38
  var import_koishi = require("koishi");
39
39
 
40
- // src/utils/common.ts
40
+ // src/utils/time.ts
41
+ var toTimeStamp = /* @__PURE__ */ __name((timeStr) => {
42
+ return new Date(timeStr).getTime();
43
+ }, "toTimeStamp");
44
+ var msToHumanReadable = /* @__PURE__ */ __name((ms) => {
45
+ const totalMs = Math.max(Number(ms) || 0, 0);
46
+ const totalSeconds = Math.floor(totalMs / 1e3);
47
+ const hours = Math.floor(totalSeconds / 3600);
48
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
49
+ const seconds = totalSeconds % 60;
50
+ const parts = [];
51
+ if (hours > 0) parts.push(`${hours}小时`);
52
+ if (minutes > 0) parts.push(`${minutes}分钟`);
53
+ parts.push(`${seconds}秒`);
54
+ return parts.join("");
55
+ }, "msToHumanReadable");
56
+
57
+ // src/utils/cache.ts
58
+ function createAsyncCache(fetchFn, ttlMs) {
59
+ let cache = null;
60
+ let lastUpdatedAt = 0;
61
+ let inFlight = null;
62
+ async function get() {
63
+ const now = Date.now();
64
+ if (cache && now - lastUpdatedAt < ttlMs) {
65
+ return cache;
66
+ }
67
+ if (inFlight) {
68
+ return inFlight;
69
+ }
70
+ inFlight = (async () => {
71
+ try {
72
+ const result = await fetchFn();
73
+ cache = result;
74
+ lastUpdatedAt = Date.now();
75
+ return cache;
76
+ } finally {
77
+ inFlight = null;
78
+ }
79
+ })();
80
+ return inFlight;
81
+ }
82
+ __name(get, "get");
83
+ return { get };
84
+ }
85
+ __name(createAsyncCache, "createAsyncCache");
86
+
87
+ // src/utils/text.ts
88
+ var normalizeName = /* @__PURE__ */ __name((text) => fullWidthToHalfWidth(text).toLowerCase().replace(/[·'\-+()【】\[\]{},。!?;:_]/g, "").replace(/\s+/g, ""), "normalizeName");
89
+ var fullWidthToHalfWidth = /* @__PURE__ */ __name((text) => text.replace(/[\uFF01-\uFF5E]/g, (char) => {
90
+ return String.fromCharCode(char.charCodeAt(0) - 65248);
91
+ }).replace(/\u3000/g, " "), "fullWidthToHalfWidth");
92
+ var removeSpace = /* @__PURE__ */ __name((text) => text.replace(/\s/g, ""), "removeSpace");
93
+ var pascalToSpaced = /* @__PURE__ */ __name((text) => text.replace(/([A-Z])/g, " $1").trim(), "pascalToSpaced");
94
+
95
+ // src/utils/http.ts
41
96
  var fetchAsyncText = /* @__PURE__ */ __name(async (url, method = "GET") => {
42
97
  const response = await fetch(url, {
43
98
  method,
@@ -74,12 +129,8 @@ var fetchAsyncData = /* @__PURE__ */ __name(async (url, method = "GET") => {
74
129
  return null;
75
130
  }
76
131
  }, "fetchAsyncData");
77
- var fullWidthToHalfWidth = /* @__PURE__ */ __name((str) => {
78
- return str.replace(/[\uFF01-\uFF5E]/g, (char) => {
79
- return String.fromCharCode(char.charCodeAt(0) - 65248);
80
- }).replace(/\u3000/g, " ");
81
- }, "fullWidthToHalfWidth");
82
- var removeSpace = /* @__PURE__ */ __name((text) => text.replace(/\s/g, ""), "removeSpace");
132
+
133
+ // src/utils/collection.ts
83
134
  var listToDict = /* @__PURE__ */ __name((dict, predict) => {
84
135
  const result = {};
85
136
  for (const obj of dict) {
@@ -105,23 +156,6 @@ var dictToKeyDict = /* @__PURE__ */ __name((dict, predict) => {
105
156
  return result;
106
157
  }, "dictToKeyDict");
107
158
 
108
- // src/utils/time.ts
109
- var toTimeStamp = /* @__PURE__ */ __name((timeStr) => {
110
- return new Date(timeStr).getTime();
111
- }, "toTimeStamp");
112
- var msToHumanReadable = /* @__PURE__ */ __name((ms) => {
113
- const totalMs = Math.max(Number(ms) || 0, 0);
114
- const totalSeconds = Math.floor(totalMs / 1e3);
115
- const hours = Math.floor(totalSeconds / 3600);
116
- const minutes = Math.floor(totalSeconds % 3600 / 60);
117
- const seconds = totalSeconds % 60;
118
- const parts = [];
119
- if (hours > 0) parts.push(`${hours}小时`);
120
- if (minutes > 0) parts.push(`${minutes}分钟`);
121
- parts.push(`${seconds}秒`);
122
- return parts.join("");
123
- }, "msToHumanReadable");
124
-
125
159
  // src/utils/wfcd-adapter.ts
126
160
  var solNodesEnDict = null;
127
161
  var getSolNodeKey = /* @__PURE__ */ __name(async (name2) => {
@@ -170,6 +204,9 @@ var regionToShort = /* @__PURE__ */ __name((region, dict) => {
170
204
  minLevel: region.minEnemyLevel
171
205
  };
172
206
  }, "regionToShort");
207
+ var fixRelicRewardKey = /* @__PURE__ */ __name((item) => {
208
+ return item.replace("StoreItems/", "");
209
+ }, "fixRelicRewardKey");
173
210
 
174
211
  // src/api/wfm-api.ts
175
212
  var wfmApiV1Base = "https://api.warframe.market/v1/";
@@ -197,6 +234,9 @@ var getWFMRivenAttributeList = /* @__PURE__ */ __name(async () => {
197
234
  `${wfmApiV2Base}riven/attributes`
198
235
  );
199
236
  }, "getWFMRivenAttributeList");
237
+ var getWFMDucatnator = /* @__PURE__ */ __name(async () => {
238
+ return await fetchAsyncData(`${wfmApiV1Base}tools/ducats`);
239
+ }, "getWFMDucatnator");
200
240
 
201
241
  // src/components/wfm.tsx
202
242
  var import_jsx_runtime = require("@satorijs/element/jsx-runtime");
@@ -559,13 +599,119 @@ var RivenAttributeComponent = /* @__PURE__ */ __name((attr, index) => {
559
599
  }, "RivenAttributeComponent");
560
600
 
561
601
  // src/services/wfm-service.ts
602
+ var import_warframe_public_export_plus2 = require("warframe-public-export-plus");
603
+ var globalDucatnatorIDDict = createAsyncCache(
604
+ async () => {
605
+ const data = await getWFMDucatnator();
606
+ if (!data || !data.payload) {
607
+ return void 0;
608
+ }
609
+ return listToDict(data.payload.previous_hour, (d) => [d.item]);
610
+ },
611
+ 36e5
612
+ );
562
613
  var globalItemList = [];
563
614
  var globalRivenItemList = [];
564
615
  var globalRivenAttributeList = [];
565
616
  var globalItemDict = {};
566
617
  var globalRivenItemDict = {};
567
618
  var globalRivenAttributeDict = {};
568
- var globalItemNameToIDDict = {};
619
+ var globalItemNameToSlugDict = {};
620
+ var globalItemGameRefDict = {};
621
+ var warframeAlias = {
622
+ Volt: ["电", "电男", "伏特"],
623
+ Trinity: ["奶妈", "奶"],
624
+ Rhino: ["犀牛", "牛", "铁甲犀牛"],
625
+ Mag: ["磁妹", "磁力"],
626
+ Loki: ["洛基"],
627
+ Excalibur: ["咖喱棒", "圣剑", "咖喱"],
628
+ Ember: ["火鸡"],
629
+ Ash: ["灰烬", "灰烬之刃"],
630
+ Nyx: ["脑溢血"],
631
+ Frost: ["冰男", "冰雪寒霜", "冰队", "冰"],
632
+ Saryn: ["毒妈", "毒"],
633
+ Banshee: ["女妖", "女高音"],
634
+ Vauban: ["工程"],
635
+ Nova: ["诺娃", "加速", "加速娃"],
636
+ Nekros: ["摸尸", "摸"],
637
+ Valkyr: ["瓦尔基里", "瓦喵", "瓦"],
638
+ Oberon: ["奶爸", "龙王", "奥伯龙"],
639
+ Zephyr: ["鸟姐", "鸟"],
640
+ Hydroid: ["水男"],
641
+ Mirage: ["小丑", "丑"],
642
+ Limbo: ["小明", "李明博", "明"],
643
+ Mesa: ["女枪"],
644
+ Chroma: ["龙甲", "龙"],
645
+ Equinox: ["阴阳", "双子"],
646
+ Atlas: ["土石魔像", "土"],
647
+ Wukong: ["猴子", "齐天大圣", "悟空", "猴"],
648
+ Ivara: ["弓妹", "弓"],
649
+ Nezha: ["哪吒", "三太子"],
650
+ Inaros: ["沙"],
651
+ Titania: ["蝶妹"],
652
+ Nidus: ["蛆甲", "蛆"],
653
+ Octavia: ["DJ", "音乐"],
654
+ Harrow: ["主教"],
655
+ Gara: ["玻璃"],
656
+ Khora: ["猫"],
657
+ Revenant: ["夜灵"],
658
+ Garuda: ["血妈", "血"],
659
+ Baruuk: ["武僧"],
660
+ Hildryn: ["母牛"],
661
+ Wisp: ["花"],
662
+ Gauss: ["高斯"],
663
+ Grendel: ["肥宅"],
664
+ Protea: ["茶", "茶妹"],
665
+ Xaku: ["骨"],
666
+ Lavos: ["炼金", "药水", "药水哥", "蛇"],
667
+ Sevagoth: ["鬼", "鲨鱼"],
668
+ Yareli: ["水妹"],
669
+ Caliban: ["卡利班"],
670
+ Gyre: ["电妹"],
671
+ Styanax: ["斯巴达"],
672
+ Voruna: ["狼", "狼妹"],
673
+ Citrine: ["水晶", "宝石"],
674
+ Kullervo: ["刀哥"],
675
+ Dagath: ["马", "赛马娘", "马娘"],
676
+ Qorvex: ["暖气片"],
677
+ Dante: ["但丁"],
678
+ Jade: ["翡翠", "天使"],
679
+ Koumei: [],
680
+ "Cyte-09": ["Cyte09", "老九", "9", "九"],
681
+ Temple: ["吉他"],
682
+ Nokko: ["蘑菇"]
683
+ };
684
+ var warframeAliasDict = ((aliasObject) => {
685
+ const transformedObject = {};
686
+ for (const [key, aliases] of Object.entries(aliasObject)) {
687
+ transformedObject[key] = key;
688
+ for (const alias of aliases) {
689
+ if (typeof alias === "string" && alias.length > 0) {
690
+ transformedObject[alias] = key;
691
+ const warframeNameWithSuffix = `${alias}甲`;
692
+ transformedObject[warframeNameWithSuffix] = key;
693
+ }
694
+ }
695
+ }
696
+ return transformedObject;
697
+ })(warframeAlias);
698
+ var setSuffix = "一套";
699
+ var bpSuffix = "蓝图";
700
+ var primeSuffix = "prime";
701
+ var warframePartSuffix = ["系统", "头部神经光元", "机体"];
702
+ var weaponPartSuffix = [
703
+ "枪管",
704
+ "枪托",
705
+ "枪机",
706
+ "弓弦",
707
+ "上弓臂",
708
+ "下弓臂",
709
+ "刀刃",
710
+ "握柄",
711
+ "拳套",
712
+ "圆盘",
713
+ "连接器"
714
+ ];
569
715
  var wmOnReady = /* @__PURE__ */ __name(async () => {
570
716
  const data = await getWFMItemList();
571
717
  if (!data) {
@@ -588,18 +734,19 @@ var wmOnReady = /* @__PURE__ */ __name(async () => {
588
734
  var setGlobalItem = /* @__PURE__ */ __name((data) => {
589
735
  globalItemList = data;
590
736
  globalItemDict = listToDict(data, (i) => [i.slug]);
591
- globalItemNameToIDDict = ((list) => {
737
+ globalItemNameToSlugDict = ((list) => {
592
738
  const result = {};
593
739
  for (const item of list) {
594
740
  if (item.i18n["zh-hans"]?.name) {
595
- result[normalizeOrderName(item.i18n["zh-hans"].name)] = item.slug;
741
+ result[normalizeName(item.i18n["zh-hans"].name)] = item.slug;
596
742
  }
597
743
  if (item.i18n["en"]?.name) {
598
- result[normalizeOrderName(item.i18n["en"].name)] = item.slug;
744
+ result[normalizeName(item.i18n["en"].name)] = item.slug;
599
745
  }
600
746
  }
601
747
  return result;
602
748
  })(globalItemList);
749
+ globalItemGameRefDict = listToDict(data, (i) => [i.gameRef]);
603
750
  }, "setGlobalItem");
604
751
  var setGlobalRivenItem = /* @__PURE__ */ __name((data) => {
605
752
  globalRivenItemList = data;
@@ -611,7 +758,7 @@ var setGlobalRivenAttribute = /* @__PURE__ */ __name((data) => {
611
758
  }, "setGlobalRivenAttribute");
612
759
  var getItemOrders = /* @__PURE__ */ __name(async (input) => {
613
760
  if (!input) return null;
614
- input = normalizeOrderName(input);
761
+ input = normalizeName(input);
615
762
  const isFullLevel = /^满级|满级$/.test(input);
616
763
  if (isFullLevel) {
617
764
  if (input.match(/^满级/)) {
@@ -620,7 +767,7 @@ var getItemOrders = /* @__PURE__ */ __name(async (input) => {
620
767
  input = input.slice(0, input.length - 2);
621
768
  }
622
769
  }
623
- const targetItem = inputToItem(input);
770
+ const targetItem = stringToWFMItem(input);
624
771
  if (!targetItem) {
625
772
  return null;
626
773
  }
@@ -666,191 +813,41 @@ var generateRivenOrderOutput = /* @__PURE__ */ __name(async (puppe, item, orders
666
813
  const imgBase64 = await getHtmlImageBase64(puppe, element.toString());
667
814
  return OutputImage(imgBase64);
668
815
  }, "generateRivenOrderOutput");
669
- var loadRelicData = /* @__PURE__ */ __name((relic) => {
670
- const relicTierMap = {
671
- Lith: "古纪",
672
- Meso: "前纪",
673
- Neo: "中纪",
674
- Axi: "后纪",
675
- Requiem: "安魂",
676
- Vanguard: "先锋"
677
- };
678
- relic.tier = relicTierMap[relic.tier] ?? relic.tier;
816
+ var applyRelicData = /* @__PURE__ */ __name(async (relic) => {
817
+ const tier = import_warframe_public_export_plus2.dict_zh[relic.tierKey] ?? relic.tier;
818
+ const wfmDict = await globalDucatnatorIDDict.get();
679
819
  const loadedItems = relic.items.map((element) => {
680
- const item = nameToItem(element.name);
820
+ const item = globalItemGameRefDict[element.name];
681
821
  if (!item) {
822
+ const nameArr = element.name.split("/");
823
+ const name2 = pascalToSpaced(nameArr[nameArr.length - 1]).replace(
824
+ "Blueprint",
825
+ "蓝图"
826
+ );
827
+ const quantityPrefix = element.quantity > 1 ? `${element.quantity} X ` : "";
682
828
  return {
683
- name: element.name.replace("Blueprint", "蓝图"),
684
- ducats: 0,
685
- rate: element.rate
829
+ ...element,
830
+ name: quantityPrefix + name2,
831
+ ducats: 0
686
832
  };
687
833
  }
834
+ const platinum = wfmDict ? wfmDict[item.id]?.median : void 0;
688
835
  return {
836
+ ...element,
689
837
  name: item.i18n["zh-hans"].name,
690
838
  ducats: item.ducats,
691
- rate: element.rate
839
+ platinum
692
840
  };
693
841
  });
694
842
  return {
695
- ...relic,
843
+ tier,
844
+ num: relic.num,
696
845
  items: loadedItems
697
846
  };
698
- }, "loadRelicData");
699
- var warframeAlias = {
700
- Volt: ["电", "电男", "伏特"],
701
- Trinity: ["奶妈", "奶"],
702
- Rhino: ["犀牛", "牛", "铁甲犀牛"],
703
- Mag: ["磁妹", "磁力"],
704
- Loki: ["洛基"],
705
- Excalibur: ["咖喱棒", "圣剑", "咖喱"],
706
- Ember: ["火鸡"],
707
- Ash: ["灰烬", "灰烬之刃"],
708
- Nyx: ["脑溢血"],
709
- Frost: ["冰男", "冰雪寒霜", "冰队", "冰"],
710
- Saryn: ["毒妈", "毒"],
711
- Banshee: ["女妖", "女高音"],
712
- Vauban: ["工程"],
713
- Nova: ["诺娃", "加速", "加速娃"],
714
- Nekros: ["摸尸", "摸"],
715
- Valkyr: ["瓦尔基里", "瓦喵", "瓦"],
716
- Oberon: ["奶爸", "龙王", "奥伯龙"],
717
- Zephyr: ["鸟姐", "鸟"],
718
- Hydroid: ["水男"],
719
- Mirage: ["小丑", "丑"],
720
- Limbo: ["小明", "李明博", "明"],
721
- Mesa: ["女枪"],
722
- Chroma: ["龙甲", "龙"],
723
- Equinox: ["阴阳", "双子"],
724
- Atlas: ["土石魔像", "土"],
725
- Wukong: ["猴子", "齐天大圣", "悟空", "猴"],
726
- Ivara: ["弓妹", "弓"],
727
- Nezha: ["哪吒", "三太子"],
728
- Inaros: ["沙"],
729
- Titania: ["蝶妹"],
730
- Nidus: ["蛆甲", "蛆"],
731
- Octavia: ["DJ", "音乐"],
732
- Harrow: ["主教"],
733
- Gara: ["玻璃"],
734
- Khora: ["猫"],
735
- Revenant: ["夜灵"],
736
- Garuda: ["血妈", "血"],
737
- Baruuk: ["武僧"],
738
- Hildryn: ["母牛"],
739
- Wisp: ["花"],
740
- Gauss: ["高斯"],
741
- Grendel: ["肥宅"],
742
- Protea: ["茶", "茶妹"],
743
- Xaku: ["骨"],
744
- Lavos: ["炼金", "药水", "药水哥", "蛇"],
745
- Sevagoth: ["鬼", "鲨鱼"],
746
- Yareli: ["水妹"],
747
- Caliban: ["卡利班"],
748
- Gyre: ["电妹"],
749
- Styanax: ["斯巴达"],
750
- Voruna: ["狼", "狼妹"],
751
- Citrine: ["水晶", "宝石"],
752
- Kullervo: ["刀哥"],
753
- Dagath: ["马", "赛马娘", "马娘"],
754
- Qorvex: ["暖气片"],
755
- Dante: ["但丁"],
756
- Jade: ["翡翠", "天使"],
757
- Koumei: [],
758
- "Cyte-09": ["Cyte09", "老九", "9", "九"],
759
- Temple: ["吉他"],
760
- Nokko: ["蘑菇"]
761
- };
762
- var warframeAliasDict = ((aliasObject) => {
763
- const transformedObject = {};
764
- for (const [key, aliases] of Object.entries(aliasObject)) {
765
- for (const alias of aliases) {
766
- if (typeof alias === "string" && alias.length > 0) {
767
- transformedObject[alias] = key;
768
- const warframeNameWithSuffix = `${alias}甲`;
769
- transformedObject[warframeNameWithSuffix] = key;
770
- }
771
- transformedObject[key] = key;
772
- }
773
- }
774
- return transformedObject;
775
- })(warframeAlias);
776
- var setSuffix = "一套";
777
- var bpSuffix = "蓝图";
778
- var primeSuffix = "prime";
779
- var warframePartSuffix = ["系统", "头部神经光元", "机体"];
780
- var weaponPartSuffix = [
781
- "枪管",
782
- "枪托",
783
- "枪机",
784
- "弓弦",
785
- "上弓臂",
786
- "下弓臂",
787
- "刀刃",
788
- "握柄",
789
- "拳套",
790
- "圆盘",
791
- "连接器"
792
- ];
793
- var removeNameSuffix = /* @__PURE__ */ __name((input) => {
794
- let hasBPSuffix = false;
795
- if (input.endsWith(bpSuffix)) {
796
- input = input.replace(new RegExp(`${bpSuffix}$`), "");
797
- hasBPSuffix = true;
798
- }
799
- if (input.endsWith(setSuffix)) {
800
- input = input.replace(new RegExp(`${setSuffix}$`), "");
801
- }
802
- if (input.endsWith(bpSuffix)) {
803
- input = input.replace(new RegExp(`${bpSuffix}$`), "");
804
- hasBPSuffix = true;
805
- }
806
- const suffix = warframePartSuffix.find((value) => input.endsWith(value)) ?? weaponPartSuffix.find((value) => input.endsWith(value)) ?? (input.endsWith("头") ? "头部神经光元" : void 0) ?? (hasBPSuffix ? bpSuffix : void 0) ?? "";
807
- if (suffix) {
808
- input = input.endsWith("头") ? input.replace(/头$/, "") : input;
809
- const pure = input.replace(new RegExp(`${suffix}$`), "");
810
- return {
811
- pure,
812
- suffix
813
- };
814
- } else {
815
- return {
816
- pure: input,
817
- suffix
818
- };
819
- }
820
- }, "removeNameSuffix");
821
- var shortHandProcess = /* @__PURE__ */ __name((input) => {
822
- const { pure: inputNoSuffix, suffix } = removeNameSuffix(input);
823
- if (inputNoSuffix === input) {
824
- const fixSet = input + setSuffix;
825
- const fixSetRes = globalItemNameToIDDict[fixSet];
826
- if (fixSetRes) return globalItemDict[fixSetRes];
827
- const fixPrime = input.endsWith(primeSuffix) ? input : input.endsWith("p") ? input.slice(0, input.length - 1) + primeSuffix : input + primeSuffix;
828
- const fixPrimeRes = globalItemNameToIDDict[fixPrime];
829
- if (fixPrimeRes) return globalItemDict[fixPrimeRes];
830
- const fixPrimeSet = fixPrime + setSuffix;
831
- const fixPrimeSetRes = globalItemNameToIDDict[fixPrimeSet];
832
- if (fixPrimeSetRes) return globalItemDict[fixPrimeSetRes];
833
- const fixBP = input + bpSuffix;
834
- const fixBPRes = globalItemNameToIDDict[fixBP];
835
- if (fixBPRes) return globalItemDict[fixBPRes];
836
- const fixPrimeBP = fixPrime + bpSuffix;
837
- const fixPrimeBPRes = globalItemNameToIDDict[fixPrimeBP];
838
- if (fixPrimeBPRes) return globalItemDict[fixPrimeBPRes];
839
- } else {
840
- const fixBP = inputNoSuffix + suffix + bpSuffix;
841
- const fixBPRes = globalItemNameToIDDict[fixBP];
842
- if (fixBPRes) return globalItemDict[fixBPRes];
843
- const fixPrime = inputNoSuffix.endsWith(primeSuffix) ? inputNoSuffix : inputNoSuffix.endsWith("p") ? inputNoSuffix.slice(0, inputNoSuffix.length - 1) + primeSuffix : inputNoSuffix + primeSuffix;
844
- const fixPrimeRes = globalItemNameToIDDict[fixPrime + suffix];
845
- if (fixPrimeRes) return globalItemDict[fixPrimeRes];
846
- const fixPrimeBP = fixPrime + suffix + bpSuffix;
847
- const fixPrimeBPRes = globalItemNameToIDDict[fixPrimeBP];
848
- if (fixPrimeBPRes) return globalItemDict[fixPrimeBPRes];
849
- }
850
- }, "shortHandProcess");
851
- var inputToItem = /* @__PURE__ */ __name((input) => {
852
- input = normalizeOrderName(input);
853
- const slug = globalItemNameToIDDict[input];
847
+ }, "applyRelicData");
848
+ var stringToWFMItem = /* @__PURE__ */ __name((input) => {
849
+ input = normalizeName(input);
850
+ const slug = globalItemNameToSlugDict[input];
854
851
  if (slug) return globalItemDict[slug];
855
852
  const normalShortHandRes = shortHandProcess(input);
856
853
  if (normalShortHandRes) return normalShortHandRes;
@@ -859,7 +856,7 @@ var inputToItem = /* @__PURE__ */ __name((input) => {
859
856
  const mappedAliasHasEndP = warframeAliasDict[aliasHasEndP];
860
857
  if (mappedAliasHasEndP) {
861
858
  const aliasHasEndPRes = shortHandProcess(
862
- normalizeOrderName(mappedAliasHasEndP) + primeSuffix + suffix
859
+ normalizeName(mappedAliasHasEndP) + primeSuffix + suffix
863
860
  );
864
861
  if (aliasHasEndPRes) return aliasHasEndPRes;
865
862
  }
@@ -868,7 +865,7 @@ var inputToItem = /* @__PURE__ */ __name((input) => {
868
865
  const mappedAliasNoEndP = warframeAliasDict[aliasNoEndP];
869
866
  if (mappedAliasNoEndP) {
870
867
  const aliasNoEndPRes = shortHandProcess(
871
- normalizeOrderName(mappedAliasNoEndP) + primeSuffix + suffix
868
+ normalizeName(mappedAliasNoEndP) + primeSuffix + suffix
872
869
  );
873
870
  if (aliasNoEndPRes) return aliasNoEndPRes;
874
871
  }
@@ -877,8 +874,8 @@ var inputToItem = /* @__PURE__ */ __name((input) => {
877
874
  if (!input2 || !standard || typeof input2 !== "string" || typeof standard !== "string") {
878
875
  return false;
879
876
  }
880
- const normalizedInput = normalizeOrderName(input2);
881
- const normalizedStandard = normalizeOrderName(standard);
877
+ const normalizedInput = normalizeName(input2);
878
+ const normalizedStandard = normalizeName(standard);
882
879
  if (!normalizedInput || !normalizedStandard) return false;
883
880
  const normalizedStandardNoSet = normalizedStandard.replace(/一套/g, "");
884
881
  const normalizedStandardNoSetSimplifiedPrime = normalizedStandardNoSet.replace(/prime/g, "p");
@@ -906,14 +903,14 @@ var inputToItem = /* @__PURE__ */ __name((input) => {
906
903
  / Prime/g,
907
904
  "p"
908
905
  );
909
- const normalizedInput = normalizeOrderName(input2);
910
- const normalizedStandard = normalizeOrderName(standard);
906
+ const normalizedInput = normalizeName(input2);
907
+ const normalizedStandard = normalizeName(standard);
911
908
  if (!normalizedInput || !normalizedStandard) return false;
912
- const normalizedStandardNoSet = normalizeOrderName(standardNoSet);
913
- const normalizedStandardSimplifiedPrime = normalizeOrderName(
909
+ const normalizedStandardNoSet = normalizeName(standardNoSet);
910
+ const normalizedStandardSimplifiedPrime = normalizeName(
914
911
  standardSimplifiedPrime
915
912
  );
916
- const normalizedStandardNoBlueprint = normalizeOrderName(
913
+ const normalizedStandardNoBlueprint = normalizeName(
917
914
  standardNoBlueprintSimplifiedPrime
918
915
  );
919
916
  return normalizedInput === normalizedStandard || normalizedInput === normalizedStandardNoSet || normalizedInput === normalizedStandardSimplifiedPrime || normalizedInput === normalizedStandardNoBlueprint;
@@ -923,32 +920,77 @@ var inputToItem = /* @__PURE__ */ __name((input) => {
923
920
  ) ?? globalItemList.find(
924
921
  (item) => compareENOrderName(input, item.i18n["en"].name)
925
922
  );
926
- }, "inputToItem");
923
+ }, "stringToWFMItem");
924
+ var removeNameSuffix = /* @__PURE__ */ __name((input) => {
925
+ let hasBPSuffix = false;
926
+ if (input.endsWith(bpSuffix)) {
927
+ input = input.replace(new RegExp(`${bpSuffix}$`), "");
928
+ hasBPSuffix = true;
929
+ }
930
+ if (input.endsWith(setSuffix)) {
931
+ input = input.replace(new RegExp(`${setSuffix}$`), "");
932
+ }
933
+ if (input.endsWith(bpSuffix)) {
934
+ input = input.replace(new RegExp(`${bpSuffix}$`), "");
935
+ hasBPSuffix = true;
936
+ }
937
+ const suffix = warframePartSuffix.find((value) => input.endsWith(value)) ?? weaponPartSuffix.find((value) => input.endsWith(value)) ?? (input.endsWith("头") ? "头部神经光元" : void 0) ?? (hasBPSuffix ? bpSuffix : void 0) ?? "";
938
+ if (suffix) {
939
+ input = input.endsWith("头") ? input.replace(/头$/, "") : input;
940
+ const pure = input.replace(new RegExp(`${suffix}$`), "");
941
+ return {
942
+ pure,
943
+ suffix
944
+ };
945
+ } else {
946
+ return {
947
+ pure: input,
948
+ suffix
949
+ };
950
+ }
951
+ }, "removeNameSuffix");
952
+ var shortHandProcess = /* @__PURE__ */ __name((input) => {
953
+ const { pure: inputNoSuffix, suffix } = removeNameSuffix(input);
954
+ if (inputNoSuffix === input) {
955
+ const fixSet = input + setSuffix;
956
+ const fixSetRes = globalItemNameToSlugDict[fixSet];
957
+ if (fixSetRes) return globalItemDict[fixSetRes];
958
+ const fixPrime = input.endsWith(primeSuffix) ? input : input.endsWith("p") ? input.slice(0, input.length - 1) + primeSuffix : input + primeSuffix;
959
+ const fixPrimeRes = globalItemNameToSlugDict[fixPrime];
960
+ if (fixPrimeRes) return globalItemDict[fixPrimeRes];
961
+ const fixPrimeSet = fixPrime + setSuffix;
962
+ const fixPrimeSetRes = globalItemNameToSlugDict[fixPrimeSet];
963
+ if (fixPrimeSetRes) return globalItemDict[fixPrimeSetRes];
964
+ const fixBP = input + bpSuffix;
965
+ const fixBPRes = globalItemNameToSlugDict[fixBP];
966
+ if (fixBPRes) return globalItemDict[fixBPRes];
967
+ const fixPrimeBP = fixPrime + bpSuffix;
968
+ const fixPrimeBPRes = globalItemNameToSlugDict[fixPrimeBP];
969
+ if (fixPrimeBPRes) return globalItemDict[fixPrimeBPRes];
970
+ } else {
971
+ const fixBP = inputNoSuffix + suffix + bpSuffix;
972
+ const fixBPRes = globalItemNameToSlugDict[fixBP];
973
+ if (fixBPRes) return globalItemDict[fixBPRes];
974
+ const fixPrime = inputNoSuffix.endsWith(primeSuffix) ? inputNoSuffix : inputNoSuffix.endsWith("p") ? inputNoSuffix.slice(0, inputNoSuffix.length - 1) + primeSuffix : inputNoSuffix + primeSuffix;
975
+ const fixPrimeRes = globalItemNameToSlugDict[fixPrime + suffix];
976
+ if (fixPrimeRes) return globalItemDict[fixPrimeRes];
977
+ const fixPrimeBP = fixPrime + suffix + bpSuffix;
978
+ const fixPrimeBPRes = globalItemNameToSlugDict[fixPrimeBP];
979
+ if (fixPrimeBPRes) return globalItemDict[fixPrimeBPRes];
980
+ }
981
+ }, "shortHandProcess");
927
982
  var compareRivenItemName = /* @__PURE__ */ __name((input, standard) => {
928
983
  if (!input || !standard || typeof input !== "string" || typeof standard !== "string") {
929
984
  return false;
930
985
  }
931
- const normalizedInput = normalizeOrderName(input);
932
- const normalizedStandard = normalizeOrderName(standard);
986
+ const normalizedInput = normalizeName(input);
987
+ const normalizedStandard = normalizeName(standard);
933
988
  if (!normalizedInput || !normalizedStandard) return false;
934
989
  return normalizedInput === normalizedStandard;
935
990
  }, "compareRivenItemName");
936
- var normalizeOrderName = /* @__PURE__ */ __name((str) => {
937
- const normalize = /* @__PURE__ */ __name((str2) => {
938
- return fullWidthToHalfWidth(str2).toLowerCase().replace(/[·'\-+()【】\[\]{},。!?;:_]/g, "").replace(/\s+/g, "");
939
- }, "normalize");
940
- return normalize(str);
941
- }, "normalizeOrderName");
942
- var nameToItem = /* @__PURE__ */ __name((name2) => {
943
- const id = globalItemNameToIDDict[normalizeOrderName(name2)];
944
- if (id) {
945
- return globalItemDict[id];
946
- }
947
- return null;
948
- }, "nameToItem");
949
991
 
950
992
  // src/services/wf-service.ts
951
- var import_warframe_public_export_plus2 = require("warframe-public-export-plus");
993
+ var import_warframe_public_export_plus3 = require("warframe-public-export-plus");
952
994
 
953
995
  // src/assets/zh.json
954
996
  var zh_default = {
@@ -45668,7 +45710,7 @@ var CircuitTable = /* @__PURE__ */ __name((incarnons, warframes) => {
45668
45710
  )
45669
45711
  ] });
45670
45712
  }, "CircuitTable");
45671
- var FissureTable = /* @__PURE__ */ __name((fissures2, type) => {
45713
+ var FissureTable = /* @__PURE__ */ __name((fissures, type) => {
45672
45714
  const titles = {
45673
45715
  fissure: "虚空裂缝",
45674
45716
  "sp-fissure": "虚空裂缝 (钢铁之路)",
@@ -45684,7 +45726,7 @@ var FissureTable = /* @__PURE__ */ __name((fissures2, type) => {
45684
45726
  ];
45685
45727
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: "display:flex;flex-direction:column;align-items:center;", children: [
45686
45728
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { style: "font-size: 50px;", children: titles[type] }),
45687
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { style: "font-size: 30px;margin-top:30px;", children: fissures2.filter((f) => f.expiry - Date.now() > 0).map((f) => {
45729
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { style: "font-size: 30px;margin-top:30px;", children: fissures.filter((f) => f.expiry - Date.now() > 0).map((f) => {
45688
45730
  let timeLeft = f.expiry - Date.now();
45689
45731
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { style: "margin-top: 10px;", children: [
45690
45732
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: `color:${colors[f.tierNum - 1]};`, children: `${f.tier}(T${f.tierNum})` }),
@@ -45752,15 +45794,20 @@ ${deepRes}
45752
45794
  ${tempRes}`;
45753
45795
  }, "WeeklyTable");
45754
45796
  var RelicComponent = /* @__PURE__ */ __name((relic) => {
45755
- const gold = relic.items.filter((i) => i.rate.Intact === 2);
45756
- const silver = relic.items.filter((i) => i.rate.Intact === 11);
45757
- const bronze = relic.items.filter((i) => i.rate.Intact === 25.33);
45758
- const getRateColor = /* @__PURE__ */ __name((rate) => {
45759
- if (rate === 2) return "#ffd700";
45760
- if (rate === 11) return "#c0c0c0";
45761
- if (rate === 25.33) return "#cd7f32";
45797
+ const gold = relic.items.filter((i) => i.rarity === "RARE");
45798
+ const silver = relic.items.filter((i) => i.rarity === "UNCOMMON");
45799
+ const bronze = relic.items.filter((i) => i.rarity === "COMMON");
45800
+ const getRateColor = /* @__PURE__ */ __name((rarity) => {
45801
+ if (rarity === "RARE") return "#ffd700";
45802
+ if (rarity === "UNCOMMON") return "#c0c0c0";
45803
+ if (rarity === "COMMON") return "#cd7f32";
45762
45804
  return "#000000";
45763
45805
  }, "getRateColor");
45806
+ const relicRewardDropRate = {
45807
+ RARE: "2/4/6/10",
45808
+ UNCOMMON: "11/13/17/20",
45809
+ COMMON: "25/23/20/17"
45810
+ };
45764
45811
  const renderRewards = /* @__PURE__ */ __name((items) => {
45765
45812
  if (items.length === 0) return null;
45766
45813
  return items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
@@ -45770,7 +45817,7 @@ var RelicComponent = /* @__PURE__ */ __name((relic) => {
45770
45817
  margin: 4px 0;
45771
45818
  border-radius: 4px;
45772
45819
  background-color: rgba(255, 255, 255, 0.05);
45773
- border-left: 4px solid ${getRateColor(item.rate.Intact)};
45820
+ border-left: 4px solid ${getRateColor(item.rarity)};
45774
45821
  display: flex;
45775
45822
  justify-content: space-between;
45776
45823
  align-items: center;
@@ -45786,7 +45833,24 @@ var RelicComponent = /* @__PURE__ */ __name((relic) => {
45786
45833
  display:flex;
45787
45834
  gap:10px;`,
45788
45835
  children: [
45789
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: "color: #a0a000;display:flex;line-height:1;", children: [
45836
+ item.platinum ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
45837
+ "span",
45838
+ {
45839
+ style: "\n color: #0d93b8;\n display:flex;\n line-height:1;",
45840
+ children: [
45841
+ item.platinum,
45842
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
45843
+ "svg",
45844
+ {
45845
+ viewBox: "0 0 18 18",
45846
+ style: "\n color: rgb(64 64 64 / 75%);\n height: 1em;\n width: 1em;\n vertical-align: -.125em;\n fill: currentcolor;\n margin-left:2px;",
45847
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("use", { href: `#icon-platinum` })
45848
+ }
45849
+ )
45850
+ ]
45851
+ }
45852
+ ) : "",
45853
+ item.ducats ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: "color: #a0a000;display:flex;line-height:1;", children: [
45790
45854
  item.ducats,
45791
45855
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
45792
45856
  "svg",
@@ -45796,9 +45860,9 @@ var RelicComponent = /* @__PURE__ */ __name((relic) => {
45796
45860
  children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("use", { href: `#icon-ducats` })
45797
45861
  }
45798
45862
  )
45799
- ] }),
45863
+ ] }) : "",
45800
45864
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
45801
- item.rate.Intact,
45865
+ relicRewardDropRate[item.rarity],
45802
45866
  "%"
45803
45867
  ] })
45804
45868
  ]
@@ -45819,7 +45883,7 @@ var RelicComponent = /* @__PURE__ */ __name((relic) => {
45819
45883
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
45820
45884
  color: #000000;
45821
45885
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
45822
- max-width: 400px;
45886
+ max-width: 500px;
45823
45887
  min-width: 320px;`,
45824
45888
  children: [
45825
45889
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
@@ -45918,7 +45982,7 @@ var RelicComponent = /* @__PURE__ */ __name((relic) => {
45918
45982
  font-size: 10px;
45919
45983
  color: #888888;
45920
45984
  text-align: center;`,
45921
- children: "掉落率基于Intact遗物品质"
45985
+ children: "价格数据来源于 WFM Ducanator, 约有1小时延迟"
45922
45986
  }
45923
45987
  )
45924
45988
  ]
@@ -45934,75 +45998,6 @@ var getWorldState = /* @__PURE__ */ __name(async () => {
45934
45998
  const ws = await WorldStateParser.WorldState.build(response);
45935
45999
  return ws;
45936
46000
  }, "getWorldState");
45937
- var getRelicsDropTable = /* @__PURE__ */ __name(async (puppe) => {
45938
- const dropTableUrl = "https://www.warframe.com/droptables";
45939
- const response = await fetchAsyncText(dropTableUrl);
45940
- const relicList = await puppe.render(response, async (p) => {
45941
- const body = await p.waitForSelector("body");
45942
- const title = await body.waitForSelector("#relicRewards");
45943
- const result2 = await title.evaluate((el) => {
45944
- const table = el.nextElementSibling;
45945
- if (!table) {
45946
- return null;
45947
- }
45948
- const relicList2 = [];
45949
- let current = { items: [] };
45950
- for (const tr of table.children[0].children) {
45951
- if (tr.className.includes("blank-row")) {
45952
- relicList2.push(current);
45953
- current = { items: [] };
45954
- continue;
45955
- }
45956
- const first = tr.children[0];
45957
- if (first.tagName.toLocaleLowerCase() === "th") {
45958
- const splitRes = first.textContent.split("(");
45959
- const name2 = splitRes[0].replace(/Relic$/, "").trim();
45960
- const tier = name2.split(" ")[0];
45961
- const num = name2.split(" ")[1] ?? "";
45962
- const quality = splitRes[1].split(")")[0].trim();
45963
- current.tier = tier;
45964
- current.num = num;
45965
- current.quality = quality;
45966
- } else {
45967
- const rateStr = tr.children[1].textContent;
45968
- const rate = parseFloat(rateStr.split("(")[1].split("%")[0]);
45969
- current.items.push({ name: first.textContent, rate });
45970
- }
45971
- }
45972
- return relicList2;
45973
- });
45974
- return result2;
45975
- });
45976
- const result = {};
45977
- relicList.forEach((r) => {
45978
- const nameKey = r.tier + r.num;
45979
- if (!result[nameKey]) {
45980
- result[nameKey] = {
45981
- tier: r.tier,
45982
- num: r.num,
45983
- items: r.items.map((i) => {
45984
- return {
45985
- name: i.name,
45986
- rate: {
45987
- Intact: void 0,
45988
- Exceptional: void 0,
45989
- Flawless: void 0,
45990
- Radiant: void 0
45991
- }
45992
- };
45993
- })
45994
- };
45995
- }
45996
- const itemsMap = new Map(
45997
- result[nameKey].items.map((item) => [item.name, item])
45998
- );
45999
- for (const target of r.items) {
46000
- const item = itemsMap.get(target.name);
46001
- item.rate[r.quality] = target.rate;
46002
- }
46003
- });
46004
- return result;
46005
- }, "getRelicsDropTable");
46006
46001
 
46007
46002
  // src/services/wf-service.ts
46008
46003
  var arbitrationSchedule = arbys_default.split("\n").map((line) => line.split(",")).filter((arr) => arr.length == 2).map((arr) => {
@@ -46011,46 +46006,95 @@ var arbitrationSchedule = arbys_default.split("\n").map((line) => line.split(","
46011
46006
  node: arr[1]
46012
46007
  };
46013
46008
  });
46014
- var worldState = null;
46015
- var worldStateLastUpdatedAt = null;
46016
- var worldstateUpdating = false;
46017
- var fissures = [];
46018
- var spFissures = [];
46019
- var rjFissures = [];
46009
+ var globalWorldState = createAsyncCache(async () => {
46010
+ const worldState = await getWorldState();
46011
+ const fissures = [];
46012
+ const rjFissures = [];
46013
+ const spFissures = [];
46014
+ for (const fissure of worldState.fissures) {
46015
+ const nodeKey = await getSolNodeKey(fissure.nodeKey);
46016
+ const obj = {
46017
+ category: fissure.isStorm ? "rj-fissures" : fissure.isHard ? "sp-fissures" : "fissures",
46018
+ hard: fissure.isHard,
46019
+ activation: fissure.activation.getTime(),
46020
+ expiry: fissure.expiry.getTime(),
46021
+ node: regionToShort(import_warframe_public_export_plus3.ExportRegions[nodeKey], import_warframe_public_export_plus3.dict_zh),
46022
+ tier: import_warframe_public_export_plus3.dict_zh[fissureTierName[fissure.tierNum]],
46023
+ tierNum: fissureTierNumToNumber(fissure.tierNum)
46024
+ };
46025
+ if (fissure.isStorm) {
46026
+ rjFissures.push(obj);
46027
+ } else if (fissure.isHard) {
46028
+ spFissures.push(obj);
46029
+ } else {
46030
+ fissures.push(obj);
46031
+ }
46032
+ }
46033
+ fissures.sort((a, b) => a.tierNum - b.tierNum);
46034
+ spFissures.sort((a, b) => a.tierNum - b.tierNum);
46035
+ rjFissures.sort((a, b) => a.tierNum - b.tierNum);
46036
+ return { raw: worldState, fissures, spFissures, rjFissures };
46037
+ }, 12e4);
46038
+ var loadRelics = /* @__PURE__ */ __name(() => {
46039
+ const result = {};
46040
+ for (const key in import_warframe_public_export_plus3.ExportRelics) {
46041
+ const exportRelic = import_warframe_public_export_plus3.ExportRelics[key];
46042
+ const exportRewards = import_warframe_public_export_plus3.ExportRewards[exportRelic.rewardManifest];
46043
+ const era = "/Lotus/Language/Relics/Era_" + exportRelic.era.toUpperCase();
46044
+ const relicKey = normalizeName(exportRelic.era + exportRelic.category);
46045
+ const rewards = (exportRewards[0] ?? []).map((r) => {
46046
+ const item = fixRelicRewardKey(r.type);
46047
+ return {
46048
+ name: item,
46049
+ rarity: r.rarity,
46050
+ quantity: r.itemCount
46051
+ };
46052
+ });
46053
+ const relic = {
46054
+ tier: exportRelic.era,
46055
+ tierKey: era,
46056
+ num: exportRelic.category,
46057
+ items: rewards
46058
+ };
46059
+ result[relicKey] = relic;
46060
+ }
46061
+ relics = result;
46062
+ }, "loadRelics");
46020
46063
  var relics = null;
46064
+ var tierListForMatch = [
46065
+ "古纪",
46066
+ "前纪",
46067
+ "中纪",
46068
+ "后纪",
46069
+ "安魂",
46070
+ "先锋",
46071
+ "Lith",
46072
+ "Meso",
46073
+ "Neo",
46074
+ "Axi",
46075
+ "Requiem",
46076
+ "Vanguard"
46077
+ ].map((t) => normalizeName(t));
46021
46078
  var wfOnReady = /* @__PURE__ */ __name(async () => {
46079
+ loadRelics();
46022
46080
  }, "wfOnReady");
46023
- var getRelic = /* @__PURE__ */ __name(async (puppe, input) => {
46024
- if (!relics || Object.entries(relics).length === 0) {
46025
- relics = await getRelicsDropTable(puppe);
46026
- if (!relics || Object.entries(relics).length === 0) {
46027
- return "获取遗物信息失败";
46028
- }
46081
+ var getRelic = /* @__PURE__ */ __name(async (input) => {
46082
+ if (!input) {
46083
+ return "请提供正确的遗物名称";
46029
46084
  }
46030
- input = removeSpace(input);
46031
- const tierList = [
46032
- "古纪",
46033
- "前纪",
46034
- "中纪",
46035
- "后纪",
46036
- "安魂",
46037
- "先锋",
46038
- "Lith",
46039
- "Meso",
46040
- "Neo",
46041
- "Axi",
46042
- "Requiem",
46043
- "Vanguard"
46044
- ];
46045
- const tier = tierList.find((t) => input.startsWith(t));
46046
- if (!tier) {
46047
- return "输入非法";
46085
+ input = normalizeName(input);
46086
+ if (!input) {
46087
+ return "请提供正确的遗物名称";
46088
+ }
46089
+ if (!relics) {
46090
+ return "遗物数据未加载完成,请稍后再试";
46048
46091
  }
46049
- let body = input.replace(new RegExp(`^${tier}`), "");
46050
- if (body.endsWith("遗物") || body.endsWith("Relic")) {
46051
- body = body.replace(/遗物$|Relic$/, "");
46092
+ const tier = tierListForMatch.find((t) => input.startsWith(t));
46093
+ if (!tier) {
46094
+ return "请提供正确的遗物名称";
46052
46095
  }
46053
- const tierMap = {
46096
+ let category = input.replace(new RegExp(`^${tier}`), "").replace(/遗物$|relic$/, "");
46097
+ const zhTierMap = {
46054
46098
  古纪: "Lith",
46055
46099
  前纪: "Meso",
46056
46100
  中纪: "Neo",
@@ -46058,9 +46102,9 @@ var getRelic = /* @__PURE__ */ __name(async (puppe, input) => {
46058
46102
  安魂: "Requiem",
46059
46103
  先锋: "Vanguard"
46060
46104
  };
46061
- const mappedTier = tierMap[tier];
46062
- const key = mappedTier + body;
46063
- return relics[key];
46105
+ const enTier = zhTierMap[tier] ?? tier;
46106
+ const key = normalizeName(enTier + category);
46107
+ return relics[key] ?? "未找到对应遗物信息";
46064
46108
  }, "getRelic");
46065
46109
  var generateRelicOutput = /* @__PURE__ */ __name(async (puppe, relic) => {
46066
46110
  const element = RelicComponent(relic);
@@ -46082,7 +46126,7 @@ var getArbitrations = /* @__PURE__ */ __name((day = 3) => {
46082
46126
  currentHourIndex + 24 * day
46083
46127
  );
46084
46128
  return weekArbys.filter((a) => arbyRewards_default[a.node]).map((a) => {
46085
- const obj = regionToShort(import_warframe_public_export_plus2.ExportRegions[a.node], import_warframe_public_export_plus2.dict_zh);
46129
+ const obj = regionToShort(import_warframe_public_export_plus3.ExportRegions[a.node], import_warframe_public_export_plus3.dict_zh);
46086
46130
  return {
46087
46131
  ...obj,
46088
46132
  time: new Date(a.time * 1e3).toLocaleString("zh-cn", {
@@ -46107,10 +46151,11 @@ var generateArbitrationsOutput = /* @__PURE__ */ __name(async (puppe, arby) => {
46107
46151
  return OutputImage(imgBase64);
46108
46152
  }, "generateArbitrationsOutput");
46109
46153
  var getWeekly = /* @__PURE__ */ __name(async () => {
46110
- if (!await updateWorldState()) {
46154
+ const { raw: worldState } = await globalWorldState.get();
46155
+ if (!worldState) {
46111
46156
  return "内部错误,获取最新信息失败";
46112
46157
  }
46113
- const archon = import_warframe_public_export_plus2.dict_zh["/Lotus/Language/Narmer/" + removeSpace(worldState.archonHunt.boss)];
46158
+ const archon = import_warframe_public_export_plus3.dict_zh["/Lotus/Language/Narmer/" + removeSpace(worldState.archonHunt.boss)];
46114
46159
  const stringToDebuff = /* @__PURE__ */ __name((key, name2, prefix) => {
46115
46160
  const keyToName = zh_default[`${prefix}${key}`];
46116
46161
  if (!keyToName) {
@@ -46133,7 +46178,7 @@ var getWeekly = /* @__PURE__ */ __name(async () => {
46133
46178
  const deepArchimMissions = await Promise.all(
46134
46179
  deepArchim.missions.map(async (m) => {
46135
46180
  const receivedType = await getMissionTypeKey(m.missionType);
46136
- const type = import_warframe_public_export_plus2.dict_zh[import_warframe_public_export_plus2.ExportMissionTypes[receivedType]?.name] ?? m.missionType;
46181
+ const type = import_warframe_public_export_plus3.dict_zh[import_warframe_public_export_plus3.ExportMissionTypes[receivedType]?.name] ?? m.missionType;
46137
46182
  const diviation = stringToDebuff(
46138
46183
  m.diviation.key,
46139
46184
  m.diviation.name,
@@ -46161,7 +46206,7 @@ var getWeekly = /* @__PURE__ */ __name(async () => {
46161
46206
  const temporalArchimMissions = await Promise.all(
46162
46207
  temporalArchim.missions.map(async (m) => {
46163
46208
  const receivedType = await getMissionTypeKey(m.missionType);
46164
- const type = import_warframe_public_export_plus2.dict_zh[import_warframe_public_export_plus2.ExportMissionTypes[receivedType]?.name] ?? receivedType;
46209
+ const type = import_warframe_public_export_plus3.dict_zh[import_warframe_public_export_plus3.ExportMissionTypes[receivedType]?.name] ?? receivedType;
46165
46210
  const diviation = stringToDebuff(
46166
46211
  m.diviation.key,
46167
46212
  m.diviation.name,
@@ -46196,7 +46241,8 @@ var generateWeeklyOutput = /* @__PURE__ */ __name(async (puppe, archon, deepArch
46196
46241
  return element;
46197
46242
  }, "generateWeeklyOutput");
46198
46243
  var getRegionTime = /* @__PURE__ */ __name(async () => {
46199
- if (!await updateWorldState()) {
46244
+ const { raw: worldState } = await globalWorldState.get();
46245
+ if (!worldState) {
46200
46246
  return "内部错误,获取最新信息失败";
46201
46247
  }
46202
46248
  const cetusDay = worldState.cetusCycle.isDay ? "白天" : "黑夜";
@@ -46227,10 +46273,10 @@ var getCircuitWeek = /* @__PURE__ */ __name(() => {
46227
46273
  const EPOCH = 1734307200 * 1e3;
46228
46274
  const week = Math.trunc((Date.now() - EPOCH) / 6048e5);
46229
46275
  const incarnons = incarnonRewards[week % incarnonRewards.length].map(
46230
- (i) => import_warframe_public_export_plus2.dict_zh[i]
46276
+ (i) => import_warframe_public_export_plus3.dict_zh[i]
46231
46277
  );
46232
46278
  const warframes = warframeRewards[week % warframeRewards.length].map(
46233
- (i) => import_warframe_public_export_plus2.dict_zh[i]
46279
+ (i) => import_warframe_public_export_plus3.dict_zh[i]
46234
46280
  );
46235
46281
  return {
46236
46282
  incarnons,
@@ -46243,67 +46289,22 @@ var generateCircuitWeekOutput = /* @__PURE__ */ __name(async (puppe, data) => {
46243
46289
  return OutputImage(imgBase64);
46244
46290
  }, "generateCircuitWeekOutput");
46245
46291
  var getFissures = /* @__PURE__ */ __name(async () => {
46246
- if (!await updateWorldState()) {
46247
- return "内部错误,获取最新信息失败";
46248
- }
46249
- return fissures;
46292
+ const { fissures } = await globalWorldState.get();
46293
+ return fissures ?? "内部错误,获取最新信息失败";
46250
46294
  }, "getFissures");
46251
46295
  var getSteelPathFissures = /* @__PURE__ */ __name(async () => {
46252
- if (!await updateWorldState()) {
46253
- return "内部错误,获取最新信息失败";
46254
- }
46255
- return spFissures;
46296
+ const { spFissures } = await globalWorldState.get();
46297
+ return spFissures ?? "内部错误,获取最新信息失败";
46256
46298
  }, "getSteelPathFissures");
46257
46299
  var getRailjackFissures = /* @__PURE__ */ __name(async () => {
46258
- if (!await updateWorldState()) {
46259
- return "内部错误,获取最新信息失败";
46260
- }
46261
- return rjFissures;
46300
+ const { rjFissures } = await globalWorldState.get();
46301
+ return rjFissures ?? "内部错误,获取最新信息失败";
46262
46302
  }, "getRailjackFissures");
46263
- var generateFissureOutput = /* @__PURE__ */ __name(async (puppe, fissures2, type) => {
46264
- const element = FissureTable(fissures2, type);
46303
+ var generateFissureOutput = /* @__PURE__ */ __name(async (puppe, fissures, type) => {
46304
+ const element = FissureTable(fissures, type);
46265
46305
  const imgBase64 = await getHtmlImageBase64(puppe, element.toString());
46266
46306
  return OutputImage(imgBase64);
46267
46307
  }, "generateFissureOutput");
46268
- var updateWorldState = /* @__PURE__ */ __name(async () => {
46269
- if (worldstateUpdating) return true;
46270
- if (worldState && worldStateLastUpdatedAt && Date.now() - worldStateLastUpdatedAt.getTime() < 12e4)
46271
- return true;
46272
- try {
46273
- worldState = await getWorldState();
46274
- worldStateLastUpdatedAt = /* @__PURE__ */ new Date();
46275
- worldstateUpdating = true;
46276
- fissures = [];
46277
- rjFissures = [];
46278
- spFissures = [];
46279
- for (const fissure of worldState.fissures) {
46280
- const nodeKey = await getSolNodeKey(fissure.nodeKey);
46281
- const obj = {
46282
- category: fissure.isStorm ? "rj-fissures" : fissure.isHard ? "sp-fissures" : "fissures",
46283
- hard: fissure.isHard,
46284
- activation: fissure.activation.getTime(),
46285
- expiry: fissure.expiry.getTime(),
46286
- node: regionToShort(import_warframe_public_export_plus2.ExportRegions[nodeKey], import_warframe_public_export_plus2.dict_zh),
46287
- tier: import_warframe_public_export_plus2.dict_zh[fissureTierName[fissure.tierNum]],
46288
- tierNum: fissureTierNumToNumber(fissure.tierNum)
46289
- };
46290
- if (fissure.isStorm) {
46291
- rjFissures.push(obj);
46292
- } else if (fissure.isHard) {
46293
- spFissures.push(obj);
46294
- } else {
46295
- fissures.push(obj);
46296
- }
46297
- }
46298
- fissures.sort((a, b) => a.tierNum - b.tierNum);
46299
- spFissures.sort((a, b) => a.tierNum - b.tierNum);
46300
- rjFissures.sort((a, b) => a.tierNum - b.tierNum);
46301
- } catch {
46302
- } finally {
46303
- worldstateUpdating = false;
46304
- return worldState && worldStateLastUpdatedAt && Date.now() - worldStateLastUpdatedAt.getTime() < 12e4;
46305
- }
46306
- }, "updateWorldState");
46307
46308
 
46308
46309
  // src/commands/wfm/wm.ts
46309
46310
  var wmCommand = /* @__PURE__ */ __name(async (action, input) => {
@@ -46331,16 +46332,11 @@ var wmrCommand = /* @__PURE__ */ __name(async (action, input) => {
46331
46332
  );
46332
46333
  }, "wmrCommand");
46333
46334
 
46334
- // src/commands/about.ts
46335
- var aboutCommand = /* @__PURE__ */ __name(async (action) => {
46336
- return "Authored by CloudeaSoft.";
46337
- }, "aboutCommand");
46338
-
46339
46335
  // src/commands/wf/arbitration.ts
46340
46336
  var arbitrationCommand = /* @__PURE__ */ __name((action, input) => {
46341
46337
  const result = getArbitrations(input);
46342
46338
  if (!result) {
46343
- return "内部错误";
46339
+ return "获取失败, 请稍后再试";
46344
46340
  }
46345
46341
  if (typeof result === "string") {
46346
46342
  return result;
@@ -46419,11 +46415,11 @@ var weeklyCommand = /* @__PURE__ */ __name(async (action) => {
46419
46415
 
46420
46416
  // src/commands/wf/relic.ts
46421
46417
  var relicCommand = /* @__PURE__ */ __name(async (action, input) => {
46422
- const result = await getRelic(action.session.app.puppeteer, input);
46418
+ const result = await getRelic(input);
46423
46419
  if (typeof result === "string") {
46424
46420
  return result;
46425
46421
  }
46426
- const relic = loadRelicData(result);
46422
+ const relic = await applyRelicData(result);
46427
46423
  return await generateRelicOutput(action.session.app.puppeteer, relic);
46428
46424
  }, "relicCommand");
46429
46425
 
@@ -46483,10 +46479,9 @@ var setupCommands = /* @__PURE__ */ __name((ctx) => {
46483
46479
  ctx.command("circuit", "本周回廊战甲及灵化之源").alias("灵化之源").alias("灵化").action(circuitCommand);
46484
46480
  ctx.command("lichc", "c系玄骸武器", { hidden: true }).action(inDevelopment);
46485
46481
  ctx.command("lichi", "i系玄骸武器", { hidden: true }).action(inDevelopment);
46486
- ctx.command("about", "关于").action(aboutCommand);
46487
46482
  }, "setupCommands");
46488
46483
  var inDevelopment = /* @__PURE__ */ __name(() => {
46489
- return "Work in progress...";
46484
+ return "功能暂未开放";
46490
46485
  }, "inDevelopment");
46491
46486
  // Annotate the CommonJS export names for ESM import in node:
46492
46487
  0 && (module.exports = {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-warframe",
3
3
  "description": "WFMToolkit",
4
- "version": "1.2.0",
4
+ "version": "1.2.2",
5
5
  "license": "GPL-3.0",
6
6
  "scripts": {
7
7
  "build": "yakumo build",